1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  DS17887-3 RTC  driver		File: dev_sb1250_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 (mpl@broadcom.com)
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#include "lib_types.h"
49#include "lib_malloc.h"
50#include "lib_printf.h"
51#include "cfe_iocb.h"
52#include "cfe_device.h"
53#include "cfe_ioctl.h"
54
55#include "lib_physio.h"
56
57
58/*  *********************************************************************
59    *  Constants
60    ********************************************************************* */
61
62/*
63 * Register bits
64 */
65
66#define DS17887REGA_UIP		0x80		/* Update-in-progress */
67#define DS17887REGA_DV2		0x40		/* Countdown chain */
68#define DS17887REGA_DV1		0x20		/* Oscillator enable */
69#define DS17887REGA_DV0		0x10		/* Bank Select */
70#define DS17887REGA_RS3		0x08		/* Rate-selection bits */
71#define DS17887REGA_RS2		0x04
72#define DS17887REGA_RS1		0x02
73#define DS17887REGA_RS0		0x01
74
75#define DS17887REGB_SET		0x80		/* Set bit */
76#define DS17887REGB_PIE		0x40		/* Periodic Interrupt Enable */
77#define DS17887REGB_AIE		0x20		/* Alarm Interrupt Enable */
78#define DS17887REGB_UIE		0x10		/* Update-ended Interrupt Enable */
79#define DS17887REGB_SQWE	0x08		/* Square-wave Enable */
80#define DS17887REGB_DM		0x04		/* Data Mode (binary) */
81#define DS17887REGB_24		0x02		/* 24-hour mode control bit */
82#define DS17887REGB_DSE		0x01		/* Daylight Savings Enable */
83
84#define DS17887REGC_IRQF	0x80		/* Interrupt request flag */
85#define DS17887REGC_PF 		0x40		/* Periodic interrupt flag */
86#define DS17887REGC_AF		0x20		/* Alarm interrupt flag */
87#define DS17887REGC_UF		0x10		/* Update ended interrupt flag */
88
89#define DS17887REGD_VRT		0x80		/* Valid RAM and time */
90
91/*
92 * Register numbers
93 */
94
95#define DS17887REG_SC		0x00		/* seconds */
96#define DS17887REG_SCA		0x01		/* seconds alarm */
97#define DS17887REG_MN		0x02		/* minutes */
98#define DS17887REG_MNA		0x03		/* minutes alarm */
99#define DS17887REG_HR		0x04		/* hours */
100#define DS17887REG_HRA		0x05		/* hours alarm */
101#define DS17887REG_DW		0x06		/* day of week */
102#define DS17887REG_DM		0x07		/* day of month */
103#define DS17887REG_MO		0x08		/* month */
104#define DS17887REG_YR		0x09		/* year */
105#define DS17887REG_A		0x0A		/* register A */
106#define DS17887REG_B		0x0B		/* register B */
107#define DS17887REG_C		0x0C		/* register C */
108#define DS17887REG_D		0x0D		/* register D */
109
110#define DS17887REG_CE		0x48		/* century (bank 1 only) */
111
112#define BCD(x) (((x) % 10) + (((x) / 10) << 4))
113#define SET_TIME	0x00
114#define SET_DATE	0x01
115
116#define WRITECSR(p,v) phys_write8((p),(v))
117#define READCSR(p) phys_read8((p))
118
119/*  *********************************************************************
120    *  Forward declarations
121    ********************************************************************* */
122
123static void ds17887_clock_probe(cfe_driver_t *drv,
124			      unsigned long probe_a, unsigned long probe_b,
125			      void *probe_ptr);
126
127static int ds17887_clock_open(cfe_devctx_t *ctx);
128static int ds17887_clock_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
129static int ds17887_clock_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
130static int ds17887_clock_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
131static int ds17887_clock_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
132static int ds17887_clock_close(cfe_devctx_t *ctx);
133
134
135/*  *********************************************************************
136    *  Device dispatch
137    ********************************************************************* */
138
139const static cfe_devdisp_t ds17887_clock_dispatch = {
140  ds17887_clock_open,
141  ds17887_clock_read,
142  ds17887_clock_inpstat,
143  ds17887_clock_write,
144  ds17887_clock_ioctl,
145  ds17887_clock_close,
146  NULL,
147  NULL
148};
149
150const cfe_driver_t ds17887_clock = {
151  "DS17887 RTC",
152  "clock",
153  CFE_DEV_CLOCK,
154  &ds17887_clock_dispatch,
155  ds17887_clock_probe
156};
157
158
159/*  *********************************************************************
160    *  Structures
161    ********************************************************************* */
162typedef struct ds17887_clock_s {
163    physaddr_t clock_base;
164} ds17887_clock_t;
165
166/*  *********************************************************************
167    *  ds17887_clock_probe(drv,a,b,ptr)
168    *
169    *  Probe routine for this driver.  This routine creates the
170    *  local device context and attaches it to the driver list
171    *  within CFE.
172    *
173    *  Input parameters:
174    *  	   drv - driver handle
175    *  	   a,b - probe hints (longs)
176    *  	   ptr - probe hint (pointer)
177    *
178    *  Return value:
179    *  	   nothing
180    ********************************************************************* */
181
182static void ds17887_clock_probe(cfe_driver_t *drv,
183				     unsigned long probe_a, unsigned long probe_b,
184				     void *probe_ptr)
185{
186    ds17887_clock_t *softc;
187    char descr[80];
188
189    softc = (ds17887_clock_t *) KMALLOC(sizeof(ds17887_clock_t),0);
190
191    /*
192     * Probe_a is the clock base address
193     * Probe_b is unused.
194     * Probe_ptr is unused.
195     */
196
197    softc->clock_base = probe_a;
198
199    xsprintf(descr,"%s at 0x%X",
200	     drv->drv_description,(uint32_t)probe_a);
201    cfe_attach(drv,softc,NULL,descr);
202
203}
204
205/*  *********************************************************************
206    *  ds17887_clock_open(ctx)
207    *
208    *  Open this device.  For the DS17887, we do a quick test
209    *  read to be sure the device is out there.
210    *
211    *  Input parameters:
212    *  	   ctx - device context (can obtain our softc here)
213    *
214    *  Return value:
215    *  	   0 if ok
216    *  	   else error code
217    ********************************************************************* */
218
219static int ds17887_clock_open(cfe_devctx_t *ctx)
220{
221    ds17887_clock_t *softc = ctx->dev_softc;
222    uint8_t byte;
223    physaddr_t clockbase;
224
225    clockbase =  softc->clock_base;
226
227    /* Make sure battery is still good and RTC valid */
228    if ( !(READCSR(clockbase+DS17887REG_D) & DS17887REGD_VRT) ) {
229	      printf("Warning: Battery has failed.  Clock setting is not accurate.\n");
230	}
231
232    /* Switch to bank 1.  Mainly for century byte */
233    byte = (uint8_t) (READCSR(clockbase+DS17887REG_A) & 0xFF);
234    WRITECSR(clockbase+DS17887REG_A,DS17887REGA_DV0 | DS17887REGA_DV1 | byte);
235
236    /* Set data mode to BCD, 24-hour mode, and enable daylight savings */
237    byte = (uint8_t) (READCSR(clockbase+DS17887REG_B) & 0xFF);
238    byte &= (~DS17887REGB_DM & ~DS17887REGB_AIE);
239    WRITECSR(clockbase+DS17887REG_B, DS17887REGB_24 | DS17887REGB_DSE | byte );
240
241    return 0;
242}
243
244/*  *********************************************************************
245    *  ds17887_clock_read(ctx,buffer)
246    *
247    *  Read time/date from the RTC. Read a total of 8 bytes in this format:
248    *  hour-minute-second-month-day-year1-year2
249    *
250    *  Input parameters:
251    *  	   ctx - device context (can obtain our softc here)
252    *  	   buffer - buffer descriptor (target buffer, length, offset)
253    *
254    *  Return value:
255    *  	   number of bytes read
256    *  	   -1 if an error occured
257    ********************************************************************* */
258
259static int ds17887_clock_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
260{
261
262    ds17887_clock_t *softc = ctx->dev_softc;
263    unsigned char *bptr;
264    physaddr_t clockbase;
265
266    clockbase = softc->clock_base;
267
268    bptr = buffer->buf_ptr;
269
270    *bptr++ =  READCSR(clockbase+DS17887REG_HR);
271    *bptr++ =  READCSR(clockbase+DS17887REG_MN);
272    *bptr++ =  READCSR(clockbase+DS17887REG_SC);
273    *bptr++ =  READCSR(clockbase+DS17887REG_MO);
274    *bptr++ =  READCSR(clockbase+DS17887REG_DM);
275    *bptr++ =  READCSR(clockbase+DS17887REG_YR);
276    *bptr++ =  READCSR(clockbase+DS17887REG_CE);
277
278    buffer->buf_retlen = 8;
279    return 0;
280}
281
282/*  *********************************************************************
283    *  ds17887_clock_write(ctx,buffer)
284    *
285    *  Write time/date to the RTC. Write in this format:
286    *  hour-minute-second-month-day-year1-year2-(time/date flag)
287    *
288    *  Input parameters:
289    *  	   ctx - device context (can obtain our softc here)
290    *  	   buffer - buffer descriptor (target buffer, length, offset)
291    *
292    *  Return value:
293    *  	   number of bytes written
294    *  	   -1 if an error occured
295    ********************************************************************* */
296
297static int ds17887_clock_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
298{
299    ds17887_clock_t *softc = ctx->dev_softc;
300    uint8_t byte;
301    unsigned char *bptr;
302    uint8_t hr,min,sec;
303    uint8_t mo,day,yr,y2k;
304    uint8_t timeDateFlag;
305    physaddr_t clockbase;
306
307    clockbase = softc->clock_base;
308
309    bptr = buffer->buf_ptr;
310
311    /* Set SET bit */
312    byte = (uint8_t) (READCSR(clockbase+DS17887REG_B) & 0xFF);
313    WRITECSR(clockbase+DS17887REG_B,DS17887REGB_SET | byte);
314
315    timeDateFlag = *(bptr + 7);
316
317    /* write time or date */
318    if(timeDateFlag == SET_TIME) {
319
320	hr = (uint8_t) *bptr;
321	WRITECSR(clockbase+DS17887REG_HR,BCD(hr));
322
323	min = (uint8_t) *(bptr+1);
324	WRITECSR(clockbase+DS17887REG_MN,BCD(min));
325
326	sec = (uint8_t) *(bptr+2);
327	WRITECSR(clockbase+DS17887REG_SC,BCD(sec));
328
329	buffer->buf_retlen = 3;
330	}
331    else if(timeDateFlag == SET_DATE) {
332
333	mo = (uint8_t) *(bptr+3);
334	WRITECSR(clockbase+DS17887REG_MO,BCD(mo));
335
336	day = (uint8_t) *(bptr+4);
337	WRITECSR(clockbase+DS17887REG_DM,BCD(day));
338
339	yr = (uint8_t) *(bptr+5);
340	WRITECSR(clockbase+DS17887REG_YR,BCD(yr));
341
342	y2k = (uint8_t) *(bptr+6);
343 	WRITECSR(clockbase+DS17887REG_CE,y2k);
344
345	buffer->buf_retlen = 4;
346	}
347    else {
348	return -1;
349	}
350
351    /* clear SET bit */
352    byte = (uint8_t) (READCSR(clockbase+DS17887REG_B) & 0xFF);
353    WRITECSR(clockbase+DS17887REG_B,~DS17887REGB_SET &  byte);
354
355  return 0;
356}
357
358/*  *********************************************************************
359    *  ds17887_clock_inpstat(ctx,inpstat)
360    *
361    *  Test input (read) status for the device
362    *
363    *  Input parameters:
364    *  	   ctx - device context (can obtain our softc here)
365    *  	   inpstat - input status descriptor to receive value
366    *
367    *  Return value:
368    *  	   0 if ok
369    *  	   -1 if an error occured
370    ********************************************************************* */
371
372static int ds17887_clock_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
373{
374    inpstat->inp_status = 1;
375
376    return 0;
377}
378
379/*  *********************************************************************
380    *  ds17887_clock_ioctl(ctx,buffer)
381    *
382    *  Perform miscellaneous I/O control operations on the device.
383    *
384    *  Input parameters:
385    *  	   ctx - device context (can obtain our softc here)
386    *  	   buffer - buffer descriptor (target buffer, length, offset)
387    *
388    *  Return value:
389    *  	   number of bytes read
390    *  	   -1 if an error occured
391    ********************************************************************* */
392
393static int ds17887_clock_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
394{
395  return 0;
396}
397
398/*  *********************************************************************
399    *  ds17887_clock_close(ctx,buffer)
400    *
401    *  Close the device.
402    *
403    *  Input parameters:
404    *  	   ctx - device context (can obtain our softc here)
405    *
406    *  Return value:
407    *  	   0 if ok
408    *  	   -1 if an error occured
409    ********************************************************************* */
410
411static int ds17887_clock_close(cfe_devctx_t *ctx)
412{
413    return 0;
414}
415
416
417
418
419
420
421
422
423