1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  DS17887-3 RTC  driver		File: dev_ds17887clock.c
5    *
6    *  This module contains a CFE driver for a DS17887-3 generic bus
7    *  real-time-clock.
8    *
9    *  Author:  Mitch Lichtenberg
10    *
11    *********************************************************************
12    *
13    *  Copyright 2000,2001,2002,2003
14    *  Broadcom Corporation. All rights reserved.
15    *
16    *  This software is furnished under license and may be used and
17    *  copied only in accordance with the following terms and
18    *  conditions.  Subject to these conditions, you may download,
19    *  copy, install, use, modify and distribute modified or unmodified
20    *  copies of this software in source and/or binary form.  No title
21    *  or ownership is transferred hereby.
22    *
23    *  1) Any source code used, modified or distributed must reproduce
24    *     and retain this copyright notice and list of conditions
25    *     as they appear in the source file.
26    *
27    *  2) No right is granted to use any trade name, trademark, or
28    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
29    *     name may not be used to endorse or promote products derived
30    *     from this software without the prior written permission of
31    *     Broadcom Corporation.
32    *
33    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
34    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
35    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
37    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
38    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
39    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
41    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
43    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
44    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
45    *     THE POSSIBILITY OF SUCH DAMAGE.
46    ********************************************************************* */
47
48
49#include "cfe.h"
50
51#include "lib_physio.h"
52
53
54/*  *********************************************************************
55    *  Constants
56    ********************************************************************* */
57
58/*
59 * Register bits
60 */
61
62#define DS17887REGA_UIP		0x80		/* Update-in-progress */
63#define DS17887REGA_DV2		0x40		/* Countdown chain */
64#define DS17887REGA_DV1		0x20		/* Oscillator enable */
65#define DS17887REGA_DV0		0x10		/* Bank Select */
66#define DS17887REGA_RS3		0x08		/* Rate-selection bits */
67#define DS17887REGA_RS2		0x04
68#define DS17887REGA_RS1		0x02
69#define DS17887REGA_RS0		0x01
70
71#define DS17887REGB_SET		0x80		/* Set bit */
72#define DS17887REGB_PIE		0x40		/* Periodic Interrupt Enable */
73#define DS17887REGB_AIE		0x20		/* Alarm Interrupt Enable */
74#define DS17887REGB_UIE		0x10		/* Update-ended Interrupt Enable */
75#define DS17887REGB_SQWE	0x08		/* Square-wave Enable */
76#define DS17887REGB_DM		0x04		/* Data Mode (binary) */
77#define DS17887REGB_24		0x02		/* 24-hour mode control bit */
78#define DS17887REGB_DSE		0x01		/* Daylight Savings Enable */
79
80#define DS17887REGC_IRQF	0x80		/* Interrupt request flag */
81#define DS17887REGC_PF 		0x40		/* Periodic interrupt flag */
82#define DS17887REGC_AF		0x20		/* Alarm interrupt flag */
83#define DS17887REGC_UF		0x10		/* Update ended interrupt flag */
84
85#define DS17887REGD_VRT		0x80		/* Valid RAM and time */
86
87/*
88 * Register numbers
89 */
90
91#define DS17887REG_SC		0x00		/* seconds */
92#define DS17887REG_SCA		0x01		/* seconds alarm */
93#define DS17887REG_MN		0x02		/* minutes */
94#define DS17887REG_MNA		0x03		/* minutes alarm */
95#define DS17887REG_HR		0x04		/* hours */
96#define DS17887REG_HRA		0x05		/* hours alarm */
97#define DS17887REG_DW		0x06		/* day of week */
98#define DS17887REG_DM		0x07		/* day of month */
99#define DS17887REG_MO		0x08		/* month */
100#define DS17887REG_YR		0x09		/* year */
101#define DS17887REG_A		0x0A		/* register A */
102#define DS17887REG_B		0x0B		/* register B */
103#define DS17887REG_C		0x0C		/* register C */
104#define DS17887REG_D		0x0D		/* register D */
105
106#define DS17887REG_CE		0x48		/* century (bank 1 only) */
107
108#define BCD(x) (((x) % 10) + (((x) / 10) << 4))
109#define SET_TIME	0x00
110#define SET_DATE	0x01
111
112#define WRITECSR(p,v) phys_write8((p),(v))
113#define READCSR(p) phys_read8((p))
114
115/*  *********************************************************************
116    *  Forward declarations
117    ********************************************************************* */
118
119static void ds17887_clock_probe(cfe_driver_t *drv,
120			      unsigned long probe_a, unsigned long probe_b,
121			      void *probe_ptr);
122
123static int ds17887_clock_open(cfe_devctx_t *ctx);
124static int ds17887_clock_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
125static int ds17887_clock_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
126static int ds17887_clock_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
127static int ds17887_clock_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
128static int ds17887_clock_close(cfe_devctx_t *ctx);
129
130
131/*  *********************************************************************
132    *  Device dispatch
133    ********************************************************************* */
134
135const static cfe_devdisp_t ds17887_clock_dispatch = {
136  ds17887_clock_open,
137  ds17887_clock_read,
138  ds17887_clock_inpstat,
139  ds17887_clock_write,
140  ds17887_clock_ioctl,
141  ds17887_clock_close,
142  NULL,
143  NULL
144};
145
146const cfe_driver_t ds17887_clock = {
147  "DS17887 RTC",
148  "clock",
149  CFE_DEV_CLOCK,
150  &ds17887_clock_dispatch,
151  ds17887_clock_probe
152};
153
154
155/*  *********************************************************************
156    *  Structures
157    ********************************************************************* */
158typedef struct ds17887_clock_s {
159    physaddr_t clock_base;
160} ds17887_clock_t;
161
162/*  *********************************************************************
163    *  ds17887_clock_probe(drv,a,b,ptr)
164    *
165    *  Probe routine for this driver.  This routine creates the
166    *  local device context and attaches it to the driver list
167    *  within CFE.
168    *
169    *  Input parameters:
170    *  	   drv - driver handle
171    *  	   a,b - probe hints (longs)
172    *  	   ptr - probe hint (pointer)
173    *
174    *  Return value:
175    *  	   nothing
176    ********************************************************************* */
177
178static void ds17887_clock_probe(cfe_driver_t *drv,
179				     unsigned long probe_a, unsigned long probe_b,
180				     void *probe_ptr)
181{
182    ds17887_clock_t *softc;
183    char descr[80];
184
185    softc = (ds17887_clock_t *) KMALLOC(sizeof(ds17887_clock_t),0);
186
187    /*
188     * Probe_a is the clock base address
189     * Probe_b is unused.
190     * Probe_ptr is unused.
191     */
192
193    softc->clock_base = probe_a;
194
195    xsprintf(descr,"%s at 0x%X",
196	     drv->drv_description,(uint32_t)probe_a);
197    cfe_attach(drv,softc,NULL,descr);
198
199}
200
201/*  *********************************************************************
202    *  ds17887_clock_open(ctx)
203    *
204    *  Open this device.  For the DS17887, we do a quick test
205    *  read to be sure the device is out there.
206    *
207    *  Input parameters:
208    *  	   ctx - device context (can obtain our softc here)
209    *
210    *  Return value:
211    *  	   0 if ok
212    *  	   else error code
213    ********************************************************************* */
214
215static int ds17887_clock_open(cfe_devctx_t *ctx)
216{
217    ds17887_clock_t *softc = ctx->dev_softc;
218    uint8_t byte;
219    physaddr_t clockbase;
220
221    clockbase =  softc->clock_base;
222
223    /* Make sure battery is still good and RTC valid */
224    if ( !(READCSR(clockbase+DS17887REG_D) & DS17887REGD_VRT) ) {
225	      printf("Warning: Battery has failed.  Clock setting is not accurate.\n");
226	}
227
228    /* Switch to bank 1.  Mainly for century byte */
229    byte = (uint8_t) (READCSR(clockbase+DS17887REG_A) & 0xFF);
230    WRITECSR(clockbase+DS17887REG_A,DS17887REGA_DV0 | DS17887REGA_DV1 | byte);
231
232    /* Set data mode to BCD, 24-hour mode, and enable daylight savings */
233    byte = (uint8_t) (READCSR(clockbase+DS17887REG_B) & 0xFF);
234    byte &= (~DS17887REGB_DM & ~DS17887REGB_AIE);
235    WRITECSR(clockbase+DS17887REG_B, DS17887REGB_24 | DS17887REGB_DSE | byte );
236
237    return 0;
238}
239
240/*  *********************************************************************
241    *  ds17887_clock_read(ctx,buffer)
242    *
243    *  Read time/date from the RTC. Read a total of 8 bytes in this format:
244    *  hour-minute-second-month-day-year1-year2
245    *
246    *  Input parameters:
247    *  	   ctx - device context (can obtain our softc here)
248    *  	   buffer - buffer descriptor (target buffer, length, offset)
249    *
250    *  Return value:
251    *  	   number of bytes read
252    *  	   -1 if an error occured
253    ********************************************************************* */
254
255static int ds17887_clock_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
256{
257    ds17887_clock_t *softc = ctx->dev_softc;
258    hsaddr_t bptr;
259    uint8_t b;
260    physaddr_t clockbase;
261
262    clockbase = softc->clock_base;
263
264    bptr = buffer->buf_ptr;
265
266    b = READCSR(clockbase+DS17887REG_HR); hs_write8(bptr,b); bptr++;
267    b = READCSR(clockbase+DS17887REG_MN); hs_write8(bptr,b); bptr++;
268    b = READCSR(clockbase+DS17887REG_SC); hs_write8(bptr,b); bptr++;
269    b = READCSR(clockbase+DS17887REG_MO); hs_write8(bptr,b); bptr++;
270    b = READCSR(clockbase+DS17887REG_DM); hs_write8(bptr,b); bptr++;
271    b = READCSR(clockbase+DS17887REG_YR); hs_write8(bptr,b); bptr++;
272    b = READCSR(clockbase+DS17887REG_CE); hs_write8(bptr,b); bptr++;
273
274    buffer->buf_retlen = 8;
275    return 0;
276}
277
278/*  *********************************************************************
279    *  ds17887_clock_write(ctx,buffer)
280    *
281    *  Write time/date to the RTC. Write in this format:
282    *  hour-minute-second-month-day-year1-year2-(time/date flag)
283    *
284    *  Input parameters:
285    *  	   ctx - device context (can obtain our softc here)
286    *  	   buffer - buffer descriptor (target buffer, length, offset)
287    *
288    *  Return value:
289    *  	   number of bytes written
290    *  	   -1 if an error occured
291    ********************************************************************* */
292
293static int ds17887_clock_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
294{
295    ds17887_clock_t *softc = ctx->dev_softc;
296    uint8_t byte;
297    hsaddr_t bptr;
298    uint8_t hr,min,sec;
299    uint8_t mo,day,yr,y2k;
300    uint8_t timeDateFlag;
301    physaddr_t clockbase;
302
303    clockbase = softc->clock_base;
304
305    bptr = buffer->buf_ptr;
306
307    /* Set SET bit */
308    byte = (uint8_t) (READCSR(clockbase+DS17887REG_B) & 0xFF);
309    WRITECSR(clockbase+DS17887REG_B,DS17887REGB_SET | byte);
310
311    timeDateFlag = hs_read8(bptr + 7);
312
313    /* write time or date */
314    if(timeDateFlag == SET_TIME) {
315
316	hr = (uint8_t) hs_read8(bptr);
317	WRITECSR(clockbase+DS17887REG_HR,BCD(hr));
318
319	min = (uint8_t) hs_read8(bptr+1);
320	WRITECSR(clockbase+DS17887REG_MN,BCD(min));
321
322	sec = (uint8_t) hs_read8(bptr+2);
323	WRITECSR(clockbase+DS17887REG_SC,BCD(sec));
324
325	buffer->buf_retlen = 3;
326	}
327    else if(timeDateFlag == SET_DATE) {
328
329	mo = (uint8_t) hs_read8(bptr+3);
330	WRITECSR(clockbase+DS17887REG_MO,BCD(mo));
331
332	day = (uint8_t) hs_read8(bptr+4);
333	WRITECSR(clockbase+DS17887REG_DM,BCD(day));
334
335	yr = (uint8_t) hs_read8(bptr+5);
336	WRITECSR(clockbase+DS17887REG_YR,BCD(yr));
337
338	y2k = (uint8_t) hs_read8(bptr+6);
339 	WRITECSR(clockbase+DS17887REG_CE,y2k);
340
341	buffer->buf_retlen = 4;
342	}
343    else {
344	return -1;
345	}
346
347    /* clear SET bit */
348    byte = (uint8_t) (READCSR(clockbase+DS17887REG_B) & 0xFF);
349    WRITECSR(clockbase+DS17887REG_B,~DS17887REGB_SET &  byte);
350
351  return 0;
352}
353
354/*  *********************************************************************
355    *  ds17887_clock_inpstat(ctx,inpstat)
356    *
357    *  Test input (read) status for the device
358    *
359    *  Input parameters:
360    *  	   ctx - device context (can obtain our softc here)
361    *  	   inpstat - input status descriptor to receive value
362    *
363    *  Return value:
364    *  	   0 if ok
365    *  	   -1 if an error occured
366    ********************************************************************* */
367
368static int ds17887_clock_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
369{
370    inpstat->inp_status = 1;
371
372    return 0;
373}
374
375/*  *********************************************************************
376    *  ds17887_clock_ioctl(ctx,buffer)
377    *
378    *  Perform miscellaneous I/O control operations on the device.
379    *
380    *  Input parameters:
381    *  	   ctx - device context (can obtain our softc here)
382    *  	   buffer - buffer descriptor (target buffer, length, offset)
383    *
384    *  Return value:
385    *  	   number of bytes read
386    *  	   -1 if an error occured
387    ********************************************************************* */
388
389static int ds17887_clock_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
390{
391  return 0;
392}
393
394/*  *********************************************************************
395    *  ds17887_clock_close(ctx,buffer)
396    *
397    *  Close the device.
398    *
399    *  Input parameters:
400    *  	   ctx - device context (can obtain our softc here)
401    *
402    *  Return value:
403    *  	   0 if ok
404    *  	   -1 if an error occured
405    ********************************************************************* */
406
407static int ds17887_clock_close(cfe_devctx_t *ctx)
408{
409    return 0;
410}
411
412
413
414
415
416
417
418
419