1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * M41T81 RTC driver File: dev_sb1250_m41t81clock.c
6 * This module contains a CFE driver for a M41T81 SMBus
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 ********************************************************************* */
49 #include "lib_types.h"
50 #include "lib_malloc.h"
51 #include "lib_printf.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 /* *********************************************************************
65 ********************************************************************* */
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 */
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
,
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 /* *********************************************************************
147 ********************************************************************* */
149 const static cfe_devdisp_t m41t81_clock_dispatch
= {
152 m41t81_clock_inpstat
,
160 const cfe_driver_t m41t81_clock
= {
164 &m41t81_clock_dispatch
,
169 /* *********************************************************************
171 ********************************************************************* */
172 typedef struct m41t81_clock_s
{
176 /* *********************************************************************
177 * time_smbus_init(chan)
179 * Initialize the specified SMBus channel for the temp sensor
182 * chan - channel # (0 or 1)
186 ********************************************************************* */
188 static void time_smbus_init(int chan
)
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.
209 * chan - channel (0 or 1)
213 ********************************************************************* */
214 static int time_waitready(int chan
)
219 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_STATUS
));
222 status
= SBREADCSR(reg
);
223 if (status
& M_SMB_BUSY
) continue;
227 if (status
& M_SMB_ERROR
) {
229 SBWRITECSR(reg
,(status
& M_SMB_ERROR
));
235 /* *********************************************************************
236 * time_readrtc(chan,slaveaddr,devaddr)
238 * Read a byte from the chip.
241 * chan - SMBus channel
242 * slaveaddr - SMBus slave address
243 * devaddr - byte with in the M41T81 device to read
248 ********************************************************************* */
250 static int time_readrtc(int chan
,int slaveaddr
,int devaddr
)
256 * Make sure the bus is idle (probably should
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));
269 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_START
));
270 SBWRITECSR(reg
,V_SMB_TT(K_SMB_TT_WR1BYTE
) | slaveaddr
);
276 err
= time_waitready(chan
);
277 if (err
< 0) return err
;
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
);
294 /* *********************************************************************
295 * time_writertc(chan,slaveaddr,devaddr,b)
297 * write a byte from the chip.
300 * chan - SMBus channel
301 * slaveaddr - SMBus slave address
302 * devaddr - byte with in the X1240 device to read
308 ********************************************************************* */
310 static int time_writertc(int chan
,int slaveaddr
,int devaddr
,int b
)
317 * Make sure the bus is idle (probably should
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
359 while (!TIMER_EXPIRED(timer
)) {
362 SBWRITECSR(reg
,V_SMB_TT(K_SMB_TT_RD1BYTE
) | slaveaddr
);
364 err
= time_waitready(chan
);
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
380 * drv - driver handle
381 * a,b - probe hints (longs)
382 * ptr - probe hint (pointer)
386 ********************************************************************* */
388 static void m41t81_clock_probe(cfe_driver_t
*drv
,
389 unsigned long probe_a
, unsigned long probe_b
,
392 m41t81_clock_t
*softc
;
396 softc
= (m41t81_clock_t
*) KMALLOC(sizeof(m41t81_clock_t
),0);
399 * Probe_a is the SMBus channel number
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.
428 * ctx - device context (can obtain our softc here)
433 ********************************************************************* */
435 static int m41t81_clock_open(cfe_devctx_t
*ctx
)
437 m41t81_clock_t
*softc
= ctx
->dev_softc
;
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
448 time_smbus_init(chan
);
450 TIMER_SET(timer
,300);
451 while (!TIMER_EXPIRED(timer
)) {
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
467 * ctx - device context (can obtain our softc here)
468 * buffer - buffer descriptor (target buffer, length, offset)
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
;
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
;
508 *bptr
= 0x20; /*Year 20xx*/
511 *bptr
= 0x19; /*Year 19xx*/
514 buffer
->buf_retlen
= 8;
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)
525 * ctx - device context (can obtain our softc here)
526 * buffer - buffer descriptor (target buffer, length, offset)
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
;
538 uint8_t mo
,day
,yr
,y2k
;
539 uint8_t timeDateFlag
;
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
;
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"
580 temp
= (uint8_t) time_readrtc(chan
,M41T81_CCR_ADDRESS
,M41T81REG_HR
);
582 temp
&= ~M41T81REG_HR_CB
;
584 else if (y2k
== 0x20) {
585 temp
|= M41T81REG_HR_CB
;
590 time_writertc(chan
,M41T81_CCR_ADDRESS
,M41T81REG_HR
, temp
);
592 buffer
->buf_retlen
= 3;
601 /* *********************************************************************
602 * m41t81_clock_inpstat(ctx,inpstat)
604 * Test input (read) status for the device
607 * ctx - device context (can obtain our softc here)
608 * inpstat - input status descriptor to receive value
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;
622 /* *********************************************************************
623 * m41t81_clock_ioctl(ctx,buffer)
625 * Perform miscellaneous I/O control operations on the device.
628 * ctx - device context (can obtain our softc here)
629 * buffer - buffer descriptor (target buffer, length, offset)
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
)
641 /* *********************************************************************
642 * m41t81_clock_close(ctx,buffer)
647 * ctx - device context (can obtain our softc here)
651 * -1 if an error occured
652 ********************************************************************* */
654 static int m41t81_clock_close(cfe_devctx_t
*ctx
)