BCM WL 6.30.102.9 (r366174)
[tomato.git] / release / src-rt / cfe / cfe / arch / mips / cpu / sb1250 / src / dev_sb1250_m41t81clock.c
blobcba1ada935ece7af5bb44eb19d0e2cc8e3370840
1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * M41T81 RTC driver File: dev_sb1250_m41t81clock.c
5 *
6 * This module contains a CFE driver for a M41T81 SMBus
7 * real-time-clock.
8 *
9 * Author: Mitch Lichtenberg (mpl@broadcom.com) and Binh Vo
11 *********************************************************************
13 * Copyright 2000,2001,2002,2003
14 * Broadcom Corporation. All rights reserved.
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.
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.
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.
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 ********************************************************************* */
48 #include "sbmips.h"
49 #include "lib_types.h"
50 #include "lib_malloc.h"
51 #include "lib_printf.h"
53 #include "cfe_iocb.h"
54 #include "cfe_device.h"
55 #include "cfe_ioctl.h"
56 #include "cfe_timer.h"
58 #include "sb1250_defs.h"
59 #include "sb1250_regs.h"
60 #include "sb1250_smbus.h"
63 /* *********************************************************************
64 * Constants
65 ********************************************************************* */
68 * Register bits
71 #define M41T81REG_SC_ST 0x80 /* stop bit */
72 #define M41T81REG_HR_CB 0x40 /* century bit */
73 #define M41T81REG_HR_CEB 0x80 /* century enable bit */
74 #define M41T81REG_CTL_S 0x20 /* sign bit */
75 #define M41T81REG_CTL_FT 0x40 /* frequency test bit */
76 #define M41T81REG_CTL_OUT 0x80 /* output level */
77 #define M41T81REG_WD_RB0 0x01 /* watchdog resolution bit 0 */
78 #define M41T81REG_WD_RB1 0x02 /* watchdog resolution bit 1 */
79 #define M41T81REG_WD_BMB0 0x04 /* watchdog multiplier bit 0 */
80 #define M41T81REG_WD_BMB1 0x08 /* watchdog multiplier bit 1 */
81 #define M41T81REG_WD_BMB2 0x10 /* watchdog multiplier bit 2 */
82 #define M41T81REG_WD_BMB3 0x20 /* watchdog multiplier bit 3 */
83 #define M41T81REG_WD_BMB4 0x40 /* watchdog multiplier bit 4 */
84 #define M41T81REG_AMO_ABE 0x20 /* alarm in "battery back-up mode" enable bit */
85 #define M41T81REG_AMO_SQWE 0x40 /* square wave enable */
86 #define M41T81REG_AMO_AFE 0x80 /* alarm flag enable flag */
87 #define M41T81REG_ADT_RPT5 0x40 /* alarm repeat mode bit 5 */
88 #define M41T81REG_ADT_RPT4 0x80 /* alarm repeat mode bit 4 */
89 #define M41T81REG_AHR_RPT3 0x80 /* alarm repeat mode bit 3 */
90 #define M41T81REG_AHR_HT 0x40 /* halt update bit */
91 #define M41T81REG_AMN_RPT2 0x80 /* alarm repeat mode bit 2 */
92 #define M41T81REG_ASC_RPT1 0x80 /* alarm repeat mode bit 1 */
93 #define M41T81REG_FLG_AF 0x40 /* alarm flag (read only) */
94 #define M41T81REG_FLG_WDF 0x80 /* watchdog flag (read only) */
95 #define M41T81REG_SQW_RS0 0x10 /* sqw frequency bit 0 */
96 #define M41T81REG_SQW_RS1 0x20 /* sqw frequency bit 1 */
97 #define M41T81REG_SQW_RS2 0x40 /* sqw frequency bit 2 */
98 #define M41T81REG_SQW_RS3 0x80 /* sqw frequency bit 3 */
102 * Register numbers
105 #define M41T81REG_TSC 0x00 /* tenths/hundredths of second */
106 #define M41T81REG_SC 0x01 /* seconds */
107 #define M41T81REG_MN 0x02 /* minute */
108 #define M41T81REG_HR 0x03 /* hour/century */
109 #define M41T81REG_DY 0x04 /* day of week */
110 #define M41T81REG_DT 0x05 /* date of month */
111 #define M41T81REG_MO 0x06 /* month */
112 #define M41T81REG_YR 0x07 /* year */
113 #define M41T81REG_CTL 0x08 /* control */
114 #define M41T81REG_WD 0x09 /* watchdog */
115 #define M41T81REG_AMO 0x0A /* alarm: month */
116 #define M41T81REG_ADT 0x0B /* alarm: date */
117 #define M41T81REG_AHR 0x0C /* alarm: hour */
118 #define M41T81REG_AMN 0x0D /* alarm: minute */
119 #define M41T81REG_ASC 0x0E /* alarm: second */
120 #define M41T81REG_FLG 0x0F /* flags */
121 #define M41T81REG_SQW 0x13 /* square wave register */
123 #define M41T81_CCR_ADDRESS 0x68
125 #define BCD(x) (((x) % 10) + (((x) / 10) << 4))
126 #define SET_TIME 0x00
127 #define SET_DATE 0x01
129 /* *********************************************************************
130 * Forward declarations
131 ********************************************************************* */
133 static void m41t81_clock_probe(cfe_driver_t *drv,
134 unsigned long probe_a, unsigned long probe_b,
135 void *probe_ptr);
137 static int m41t81_clock_open(cfe_devctx_t *ctx);
138 static int m41t81_clock_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
139 static int m41t81_clock_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
140 static int m41t81_clock_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
141 static int m41t81_clock_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
142 static int m41t81_clock_close(cfe_devctx_t *ctx);
145 /* *********************************************************************
146 * Device dispatch
147 ********************************************************************* */
149 const static cfe_devdisp_t m41t81_clock_dispatch = {
150 m41t81_clock_open,
151 m41t81_clock_read,
152 m41t81_clock_inpstat,
153 m41t81_clock_write,
154 m41t81_clock_ioctl,
155 m41t81_clock_close,
156 NULL,
157 NULL
160 const cfe_driver_t m41t81_clock = {
161 "M41T81 RTC",
162 "clock",
163 CFE_DEV_CLOCK,
164 &m41t81_clock_dispatch,
165 m41t81_clock_probe
169 /* *********************************************************************
170 * Structures
171 ********************************************************************* */
172 typedef struct m41t81_clock_s {
173 int smbus_channel;
174 } m41t81_clock_t;
176 /* *********************************************************************
177 * time_smbus_init(chan)
179 * Initialize the specified SMBus channel for the temp sensor
181 * Input parameters:
182 * chan - channel # (0 or 1)
184 * Return value:
185 * nothing
186 ********************************************************************* */
188 static void time_smbus_init(int chan)
190 uintptr_t reg;
192 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_FREQ));
194 SBWRITECSR(reg,K_SMB_FREQ_400KHZ);
196 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_CONTROL));
198 SBWRITECSR(reg,0); /* not in direct mode, no interrupts, will poll */
202 /* *********************************************************************
203 * time_waitready(chan)
205 * Wait until the SMBus channel is ready. We simply poll
206 * the busy bit until it clears.
208 * Input parameters:
209 * chan - channel (0 or 1)
211 * Return value:
212 * nothing
213 ********************************************************************* */
214 static int time_waitready(int chan)
216 uintptr_t reg;
217 uint64_t status;
219 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_STATUS));
221 for (;;) {
222 status = SBREADCSR(reg);
223 if (status & M_SMB_BUSY) continue;
224 break;
227 if (status & M_SMB_ERROR) {
229 SBWRITECSR(reg,(status & M_SMB_ERROR));
230 return -1;
232 return 0;
235 /* *********************************************************************
236 * time_readrtc(chan,slaveaddr,devaddr)
238 * Read a byte from the chip.
240 * Input parameters:
241 * chan - SMBus channel
242 * slaveaddr - SMBus slave address
243 * devaddr - byte with in the M41T81 device to read
245 * Return value:
246 * 0 if ok
247 * else -1
248 ********************************************************************* */
250 static int time_readrtc(int chan,int slaveaddr,int devaddr)
252 uintptr_t reg;
253 int err;
256 * Make sure the bus is idle (probably should
257 * ignore error here)
260 if (time_waitready(chan) < 0) return -1;
262 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_CMD));
263 SBWRITECSR(reg,((devaddr & 0xFF) & 0xFF));
266 * Start the command
269 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_START));
270 SBWRITECSR(reg,V_SMB_TT(K_SMB_TT_WR1BYTE) | slaveaddr);
273 * Wait till done
276 err = time_waitready(chan);
277 if (err < 0) return err;
280 * Read the data byte
283 SBWRITECSR(reg,V_SMB_TT(K_SMB_TT_RD1BYTE) | slaveaddr);
285 err = time_waitready(chan);
286 if (err < 0) return err;
288 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_DATA));
289 err = SBREADCSR(reg);
291 return (err & 0xFF);
294 /* *********************************************************************
295 * time_writertc(chan,slaveaddr,devaddr,b)
297 * write a byte from the chip.
299 * Input parameters:
300 * chan - SMBus channel
301 * slaveaddr - SMBus slave address
302 * devaddr - byte with in the X1240 device to read
303 * b - byte to write
305 * Return value:
306 * 0 if ok
307 * else -1
308 ********************************************************************* */
310 static int time_writertc(int chan,int slaveaddr,int devaddr,int b)
312 uintptr_t reg;
313 int err;
314 int64_t timer;
317 * Make sure the bus is idle (probably should
318 * ignore error here)
321 if (time_waitready(chan) < 0) return -1;
324 * Write the device address to the controller. There are two
325 * parts, the high part goes in the "CMD" field, and the
326 * low part is the data field.
329 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_CMD));
330 SBWRITECSR(reg,((devaddr & 0xFF) & 0xFF));
332 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_DATA));
333 SBWRITECSR(reg,((b & 0xFF) & 0xFF));
336 * Start the command. Keep pounding on the device until it
337 * submits or the timer expires, whichever comes first. The
338 * datasheet says writes can take up to 10ms, so we'll give it 500.
341 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_START));
342 SBWRITECSR(reg,V_SMB_TT(K_SMB_TT_WR2BYTE) | slaveaddr);
345 * Wait till the SMBus interface is done
348 err = time_waitready(chan);
349 if (err < 0) return err;
352 * Pound on the device with a current address read
353 * to poll for the write complete
356 TIMER_SET(timer,50);
357 err = -1;
359 while (!TIMER_EXPIRED(timer)) {
360 POLL();
362 SBWRITECSR(reg,V_SMB_TT(K_SMB_TT_RD1BYTE) | slaveaddr);
364 err = time_waitready(chan);
365 if (err == 0) break;
368 return err;
372 /* *********************************************************************
373 * m41t81_clock_probe(drv,a,b,ptr)
375 * Probe routine for this driver. This routine creates the
376 * local device context and attaches it to the driver list
377 * within CFE.
379 * Input parameters:
380 * drv - driver handle
381 * a,b - probe hints (longs)
382 * ptr - probe hint (pointer)
384 * Return value:
385 * nothing
386 ********************************************************************* */
388 static void m41t81_clock_probe(cfe_driver_t *drv,
389 unsigned long probe_a, unsigned long probe_b,
390 void *probe_ptr)
392 m41t81_clock_t *softc;
393 char descr[80];
394 uint8_t byte;
396 softc = (m41t81_clock_t *) KMALLOC(sizeof(m41t81_clock_t),0);
399 * Probe_a is the SMBus channel number
400 * Probe_b is unused.
401 * Probe_ptr is unused.
404 softc->smbus_channel = (int)probe_a;
406 xsprintf(descr,"%s on SMBus channel %d",
407 drv->drv_description,probe_a);
408 cfe_attach(drv,softc,NULL,descr);
412 * Reset HT bit to "0" to update registers with current time.
414 byte = time_readrtc(softc->smbus_channel,M41T81_CCR_ADDRESS,M41T81REG_AHR);
415 byte &= ~M41T81REG_AHR_HT;
416 time_writertc(softc->smbus_channel,M41T81_CCR_ADDRESS,M41T81REG_AHR, byte);
421 /* *********************************************************************
422 * m41t81_clock_open(ctx)
424 * Open this device. For the M41T81, we do a quick test
425 * read to be sure the device is out there.
427 * Input parameters:
428 * ctx - device context (can obtain our softc here)
430 * Return value:
431 * 0 if ok
432 * else error code
433 ********************************************************************* */
435 static int m41t81_clock_open(cfe_devctx_t *ctx)
437 m41t81_clock_t *softc = ctx->dev_softc;
438 int b = -1;
439 int64_t timer;
440 int chan = softc->smbus_channel;
443 * Try to read from the device. If it does not
444 * respond, fail the open. We may need to do this for
445 * up to 300ms.
448 time_smbus_init(chan);
450 TIMER_SET(timer,300);
451 while (!TIMER_EXPIRED(timer)) {
452 POLL();
453 b = time_readrtc(chan,M41T81_CCR_ADDRESS,0);
454 if (b >= 0) break; /* read is ok */
457 return (b < 0) ? -1 : 0;
460 /* *********************************************************************
461 * m41t81_clock_read(ctx,buffer)
463 * Read time/date from the RTC. Read a total of 8 bytes in this format:
464 * hour-minute-second-month-day-year1-year2
466 * Input parameters:
467 * ctx - device context (can obtain our softc here)
468 * buffer - buffer descriptor (target buffer, length, offset)
470 * Return value:
471 * number of bytes read
472 * -1 if an error occured
473 ********************************************************************* */
475 static int m41t81_clock_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
478 m41t81_clock_t *softc = ctx->dev_softc;
479 uint8_t byte;
480 unsigned char *bptr;
481 int chan = softc->smbus_channel;
483 bptr = buffer->buf_ptr;
485 byte = (uint8_t) time_readrtc(chan,M41T81_CCR_ADDRESS,M41T81REG_HR);
486 byte &= ~(M41T81REG_HR_CB | M41T81REG_HR_CEB);
487 *bptr++ = (unsigned char) byte;
489 byte = (uint8_t) time_readrtc(chan,M41T81_CCR_ADDRESS,M41T81REG_MN);
490 *bptr++ = (unsigned char) byte;
492 byte = (uint8_t) time_readrtc(chan,M41T81_CCR_ADDRESS,M41T81REG_SC);
493 byte &= ~(M41T81REG_SC_ST);
494 *bptr++ = (unsigned char) byte;
496 byte = (uint8_t) time_readrtc(chan,M41T81_CCR_ADDRESS,M41T81REG_MO);
497 *bptr++ = (unsigned char) byte;
499 byte = (uint8_t) time_readrtc(chan,M41T81_CCR_ADDRESS,M41T81REG_DT);
500 *bptr++ = (unsigned char) byte;
502 byte = (uint8_t) time_readrtc(chan,M41T81_CCR_ADDRESS,M41T81REG_YR);
503 *bptr++ = (unsigned char) byte;
505 byte = (uint8_t) time_readrtc(chan,M41T81_CCR_ADDRESS,M41T81REG_HR);
506 byte &= M41T81REG_HR_CB;
507 if (byte) {
508 *bptr = 0x20; /*Year 20xx*/
510 else {
511 *bptr = 0x19; /*Year 19xx*/
514 buffer->buf_retlen = 8;
515 return 0;
518 /* *********************************************************************
519 * m41t81_clock_write(ctx,buffer)
521 * Write time/date to the RTC. Write in this format:
522 * hour-minute-second-month-day-year1-year2-(time/date flag)
524 * Input parameters:
525 * ctx - device context (can obtain our softc here)
526 * buffer - buffer descriptor (target buffer, length, offset)
528 * Return value:
529 * number of bytes written
530 * -1 if an error occured
531 ********************************************************************* */
533 static int m41t81_clock_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
535 m41t81_clock_t *softc = ctx->dev_softc;
536 unsigned char *bptr;
537 uint8_t hr,min,sec;
538 uint8_t mo,day,yr,y2k;
539 uint8_t timeDateFlag;
540 uint8_t temp;
541 int chan = softc->smbus_channel;
542 bptr = buffer->buf_ptr;
543 timeDateFlag = *(bptr + 7);
545 /* write time or date */
546 if(timeDateFlag == SET_TIME) {
548 temp = time_readrtc(chan,M41T81_CCR_ADDRESS,M41T81REG_HR);
549 temp &= (M41T81REG_HR_CB | M41T81REG_HR_CEB);
550 hr = (uint8_t) *bptr;
551 hr = BCD(hr);
552 hr |= temp;
553 time_writertc(chan,M41T81_CCR_ADDRESS,M41T81REG_HR, hr);
555 min = (uint8_t) *(bptr+1);
556 time_writertc(chan,M41T81_CCR_ADDRESS,M41T81REG_MN, BCD(min) );
558 sec = (uint8_t) *(bptr+2);
559 sec &= ~M41T81REG_SC_ST;
560 time_writertc(chan,M41T81_CCR_ADDRESS,M41T81REG_SC, BCD(sec) );
562 buffer->buf_retlen = 3;
564 else if(timeDateFlag == SET_DATE) {
566 mo = (uint8_t) *(bptr+3);
567 time_writertc(chan,M41T81_CCR_ADDRESS,M41T81REG_MO, BCD(mo) );
569 day = (uint8_t) *(bptr+4);
570 time_writertc(chan,M41T81_CCR_ADDRESS,M41T81REG_DT, BCD(day) );
572 yr = (uint8_t) *(bptr+5);
573 time_writertc(chan,M41T81_CCR_ADDRESS,M41T81REG_YR, BCD(yr) );
575 y2k = (uint8_t) *(bptr+6);
576 /*M41T81 does not have a century byte, so we don't need to write y2k
577 *But we should flip the century bit (CB) to "1" for year 20xx and to "0"
578 *for year 19xx.
580 temp = (uint8_t) time_readrtc(chan,M41T81_CCR_ADDRESS,M41T81REG_HR);
581 if (y2k == 0x19) {
582 temp &= ~M41T81REG_HR_CB;
584 else if (y2k == 0x20) {
585 temp |= M41T81REG_HR_CB;
587 else {
588 return -1;
590 time_writertc(chan,M41T81_CCR_ADDRESS,M41T81REG_HR, temp );
592 buffer->buf_retlen = 3;
594 else {
595 return -1;
598 return 0;
601 /* *********************************************************************
602 * m41t81_clock_inpstat(ctx,inpstat)
604 * Test input (read) status for the device
606 * Input parameters:
607 * ctx - device context (can obtain our softc here)
608 * inpstat - input status descriptor to receive value
610 * Return value:
611 * 0 if ok
612 * -1 if an error occured
613 ********************************************************************* */
615 static int m41t81_clock_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
617 inpstat->inp_status = 1;
619 return 0;
622 /* *********************************************************************
623 * m41t81_clock_ioctl(ctx,buffer)
625 * Perform miscellaneous I/O control operations on the device.
627 * Input parameters:
628 * ctx - device context (can obtain our softc here)
629 * buffer - buffer descriptor (target buffer, length, offset)
631 * Return value:
632 * number of bytes read
633 * -1 if an error occured
634 ********************************************************************* */
636 static int m41t81_clock_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
638 return 0;
641 /* *********************************************************************
642 * m41t81_clock_close(ctx,buffer)
644 * Close the device.
646 * Input parameters:
647 * ctx - device context (can obtain our softc here)
649 * Return value:
650 * 0 if ok
651 * -1 if an error occured
652 ********************************************************************* */
654 static int m41t81_clock_close(cfe_devctx_t *ctx)
656 return 0;