1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * Xicor RTC/EEPROM driver File: dev_sb1250_x1240eeprom.c
6 * This module contains a CFE driver for a Xicor X1240 SMBus
7 * real-time-clock & EEPROM module. The only functionality
8 * we currently export is the EEPROM, for use as environment
11 * Author: Mitch Lichtenberg (mpl@broadcom.com)
13 *********************************************************************
15 * Copyright 2000,2001,2002,2003
16 * Broadcom Corporation. All rights reserved.
18 * This software is furnished under license and may be used and
19 * copied only in accordance with the following terms and
20 * conditions. Subject to these conditions, you may download,
21 * copy, install, use, modify and distribute modified or unmodified
22 * copies of this software in source and/or binary form. No title
23 * or ownership is transferred hereby.
25 * 1) Any source code used, modified or distributed must reproduce
26 * and retain this copyright notice and list of conditions
27 * as they appear in the source file.
29 * 2) No right is granted to use any trade name, trademark, or
30 * logo of Broadcom Corporation. The "Broadcom Corporation"
31 * name may not be used to endorse or promote products derived
32 * from this software without the prior written permission of
33 * Broadcom Corporation.
35 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
36 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
37 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
38 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
39 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
40 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
41 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
42 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
43 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
44 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
45 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
46 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
47 * THE POSSIBILITY OF SUCH DAMAGE.
48 ********************************************************************* */
52 #include "lib_types.h"
53 #include "lib_malloc.h"
54 #include "lib_printf.h"
57 #include "cfe_device.h"
58 #include "cfe_ioctl.h"
59 #include "cfe_timer.h"
61 #include "sb1250_defs.h"
62 #include "sb1250_regs.h"
63 #include "sb1250_smbus.h"
66 /* *********************************************************************
67 * Xicor X1241 RTC constants
68 ********************************************************************* */
74 #define X1241REG_SR_BAT 0x80 /* currently on battery power */
75 #define X1241REG_SR_RWEL 0x04 /* r/w latch is enabled, can write RTC */
76 #define X1241REG_SR_WEL 0x02 /* r/w latch is unlocked, can enable r/w now */
77 #define X1241REG_SR_RTCF 0x01 /* clock failed */
78 #define X1241REG_BL_BP2 0x80 /* block protect 2 */
79 #define X1241REG_BL_BP1 0x40 /* block protect 1 */
80 #define X1241REG_BL_BP0 0x20 /* block protect 0 */
81 #define X1241REG_BL_WD1 0x10
82 #define X1241REG_BL_WD0 0x08
83 #define X1241REG_HR_MIL 0x80 /* military time format */
89 #define X1241REG_BL 0x10 /* block protect bits */
90 #define X1241REG_INT 0x11 /* */
91 #define X1241REG_SC 0x30 /* Seconds */
92 #define X1241REG_MN 0x31 /* Minutes */
93 #define X1241REG_HR 0x32 /* Hours */
94 #define X1241REG_DT 0x33 /* Day of month */
95 #define X1241REG_MO 0x34 /* Month */
96 #define X1241REG_YR 0x35 /* Year */
97 #define X1241REG_DW 0x36 /* Day of Week */
98 #define X1241REG_Y2K 0x37 /* Year 2K */
99 #define X1241REG_SR 0x3F /* Status register */
101 #define X1241_CCR_ADDRESS 0x6F
102 #define X1241_ARRAY_ADDRESS 0x57
104 #define X1241_EEPROM_SIZE 2048
106 /* *********************************************************************
107 * Forward Declarations
108 ********************************************************************* */
110 static void sb1250_x1240eeprom_probe(cfe_driver_t
*drv
,
111 unsigned long probe_a
, unsigned long probe_b
,
115 static int sb1250_x1240eeprom_open(cfe_devctx_t
*ctx
);
116 static int sb1250_x1240eeprom_read(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
);
117 static int sb1250_x1240eeprom_inpstat(cfe_devctx_t
*ctx
,iocb_inpstat_t
*inpstat
);
118 static int sb1250_x1240eeprom_write(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
);
119 static int sb1250_x1240eeprom_ioctl(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
);
120 static int sb1250_x1240eeprom_close(cfe_devctx_t
*ctx
);
122 /* *********************************************************************
124 ********************************************************************* */
126 const static cfe_devdisp_t sb1250_x1240eeprom_dispatch
= {
127 sb1250_x1240eeprom_open
,
128 sb1250_x1240eeprom_read
,
129 sb1250_x1240eeprom_inpstat
,
130 sb1250_x1240eeprom_write
,
131 sb1250_x1240eeprom_ioctl
,
132 sb1250_x1240eeprom_close
,
137 const cfe_driver_t sb1250_x1240eeprom
= {
138 "Xicor X1241 EEPROM",
141 &sb1250_x1240eeprom_dispatch
,
142 sb1250_x1240eeprom_probe
145 typedef struct sb1250_x1240eeprom_s
{
149 unsigned char data
[X1241_EEPROM_SIZE
];
150 } sb1250_x1240eeprom_t
;
153 /* *********************************************************************
156 * Initialize the specified SMBus channel
159 * chan - channel # (0 or 1)
163 ********************************************************************* */
165 static void smbus_init(int chan
)
169 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_FREQ
));
171 SBWRITECSR(reg
,K_SMB_FREQ_100KHZ
); /* 100KHz clock */
173 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_CONTROL
));
175 SBWRITECSR(reg
,0); /* not in direct mode, no interrupts, will poll */
179 /* *********************************************************************
180 * smbus_waitready(chan)
182 * Wait until the SMBus channel is ready. We simply poll
183 * the busy bit until it clears.
186 * chan - channel (0 or 1)
190 ********************************************************************* */
191 static int smbus_waitready(int chan
)
196 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_STATUS
));
199 status
= SBREADCSR(reg
);
200 if (status
& M_SMB_BUSY
) continue;
204 if (status
& M_SMB_ERROR
) {
206 SBWRITECSR(reg
,(status
& M_SMB_ERROR
));
212 /* *********************************************************************
213 * smbus_readrtc(chan,slaveaddr,devaddr)
215 * Read a byte from the chip. The 'slaveaddr' parameter determines
216 * whether we're reading from the RTC section or the EEPROM section.
219 * chan - SMBus channel
220 * slaveaddr - SMBus slave address
221 * devaddr - byte with in the X1240 device to read
226 ********************************************************************* */
228 static int smbus_readrtc(int chan
,int slaveaddr
,int devaddr
)
234 * Make sure the bus is idle (probably should
238 if (smbus_waitready(chan
) < 0) return -1;
241 * Write the device address to the controller. There are two
242 * parts, the high part goes in the "CMD" field, and the
243 * low part is the data field.
246 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_CMD
));
247 SBWRITECSR(reg
,((devaddr
>> 8) & 0x7));
250 * Write the data to the controller
253 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_DATA
));
254 SBWRITECSR(reg
,((devaddr
& 0xFF) & 0xFF));
260 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_START
));
261 SBWRITECSR(reg
,V_SMB_TT(K_SMB_TT_WR2BYTE
) | slaveaddr
);
267 err
= smbus_waitready(chan
);
268 if (err
< 0) return err
;
274 SBWRITECSR(reg
,V_SMB_TT(K_SMB_TT_RD1BYTE
) | slaveaddr
);
276 err
= smbus_waitready(chan
);
277 if (err
< 0) return err
;
279 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_DATA
));
280 err
= SBREADCSR(reg
);
285 /* *********************************************************************
286 * smbus_writertc(chan,slaveaddr,devaddr,b)
288 * write a byte from the chip. The 'slaveaddr' parameter determines
289 * whethe we're writing to the RTC section or the EEPROM section.
292 * chan - SMBus channel
293 * slaveaddr - SMBus slave address
294 * devaddr - byte with in the X1240 device to read
300 ********************************************************************* */
303 static int smbus_writertc(int chan
,int slaveaddr
,int devaddr
,int b
)
310 * Make sure the bus is idle (probably should
314 if (smbus_waitready(chan
) < 0) return -1;
317 * Write the device address to the controller. There are two
318 * parts, the high part goes in the "CMD" field, and the
319 * low part is the data field.
322 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_CMD
));
323 SBWRITECSR(reg
,((devaddr
>> 8) & 0x7));
326 * Write the data to the controller
329 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_DATA
));
330 SBWRITECSR(reg
,((devaddr
& 0xFF) | ((b
& 0xFF) << 8)));
333 * Start the command. Keep pounding on the device until it
334 * submits or the timer expires, whichever comes first. The
335 * datasheet says writes can take up to 10ms, so we'll give it 500.
338 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_START
));
339 SBWRITECSR(reg
,V_SMB_TT(K_SMB_TT_WR3BYTE
) | slaveaddr
);
342 * Wait till the SMBus interface is done
345 err
= smbus_waitready(chan
);
346 if (err
< 0) return err
;
349 * Pound on the device with a current address read
350 * to poll for the write complete
356 while (!TIMER_EXPIRED(timer
)) {
359 SBWRITECSR(reg
,V_SMB_TT(K_SMB_TT_RD1BYTE
) | slaveaddr
);
361 err
= smbus_waitready(chan
);
369 /* *********************************************************************
370 * sb1250_x1240eeprom_probe(drv,a,b,ptr)
372 * Probe routine for this driver. This routine creates the
373 * local device context and attaches it to the driver list
377 * drv - driver handle
378 * a,b - probe hints (longs)
379 * ptr - probe hint (pointer)
383 ********************************************************************* */
385 static void sb1250_x1240eeprom_probe(cfe_driver_t
*drv
,
386 unsigned long probe_a
, unsigned long probe_b
,
389 sb1250_x1240eeprom_t
*softc
;
392 softc
= (sb1250_x1240eeprom_t
*) KMALLOC(sizeof(sb1250_x1240eeprom_t
),0);
395 * Probe_a is the SMBus channel number
396 * Probe_b is the SMBus device offset
397 * Probe_ptr is unused.
400 softc
->smbus_channel
= (int)probe_a
;
401 softc
->env_offset
= 0;
402 softc
->env_size
= X1241_EEPROM_SIZE
;
404 xsprintf(descr
,"%s on SMBus channel %d",
405 drv
->drv_description
,probe_a
);
406 cfe_attach(drv
,softc
,NULL
,descr
);
411 /* *********************************************************************
412 * sb1250_x1240eeprom_open(ctx)
414 * Open this device. For the X1240, we do a quick test
415 * read to be sure the device is out there.
418 * ctx - device context (can obtain our softc here)
423 ********************************************************************* */
425 static int sb1250_x1240eeprom_open(cfe_devctx_t
*ctx
)
427 sb1250_x1240eeprom_t
*softc
= ctx
->dev_softc
;
432 * Try to read byte 0 from the device. If it does not
433 * respond, fail the open. We may need to do this for
434 * up to 300ms in case the X1240 is busy wiggling its
438 smbus_init(softc
->smbus_channel
);
440 TIMER_SET(timer
,300);
441 while (!TIMER_EXPIRED(timer
)) {
443 b
= smbus_readrtc(softc
->smbus_channel
,
446 if (b
>= 0) break; /* read is ok */
450 * See if the watchdog is enabled. If it is, turn it off.
453 b
= smbus_readrtc(softc
->smbus_channel
,
457 if (b
!= (X1241REG_BL_WD1
| X1241REG_BL_WD0
)) {
459 smbus_writertc(softc
->smbus_channel
,
464 smbus_writertc(softc
->smbus_channel
,
467 X1241REG_SR_WEL
| X1241REG_SR_RWEL
);
469 smbus_writertc(softc
->smbus_channel
,
472 (X1241REG_BL_WD1
| X1241REG_BL_WD0
));
474 smbus_writertc(softc
->smbus_channel
,
482 return (b
< 0) ? -1 : 0;
485 /* *********************************************************************
486 * sb1250_x1240eeprom_read(ctx,buffer)
488 * Read bytes from the device.
491 * ctx - device context (can obtain our softc here)
492 * buffer - buffer descriptor (target buffer, length, offset)
495 * number of bytes read
496 * -1 if an error occured
497 ********************************************************************* */
499 static int sb1250_x1240eeprom_read(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
)
501 sb1250_x1240eeprom_t
*softc
= ctx
->dev_softc
;
507 bptr
= buffer
->buf_ptr
;
508 blen
= buffer
->buf_length
;
510 if ((buffer
->buf_offset
+ blen
) > X1241_EEPROM_SIZE
) return -1;
512 idx
= (int) buffer
->buf_offset
;
515 b
= smbus_readrtc(softc
->smbus_channel
,
519 *bptr
++ = (unsigned char) b
;
524 buffer
->buf_retlen
= bptr
- buffer
->buf_ptr
;
525 return (b
< 0) ? -1 : 0;
528 /* *********************************************************************
529 * sb1250_x1240eeprom_inpstat(ctx,inpstat)
531 * Test input (read) status for the device
534 * ctx - device context (can obtain our softc here)
535 * inpstat - input status descriptor to receive value
539 * -1 if an error occured
540 ********************************************************************* */
542 static int sb1250_x1240eeprom_inpstat(cfe_devctx_t
*ctx
,iocb_inpstat_t
*inpstat
)
544 inpstat
->inp_status
= 1;
549 /* *********************************************************************
550 * sb1250_x1240eeprom_write(ctx,buffer)
552 * Write bytes from the device.
555 * ctx - device context (can obtain our softc here)
556 * buffer - buffer descriptor (target buffer, length, offset)
559 * number of bytes read
560 * -1 if an error occured
561 ********************************************************************* */
563 static int sb1250_x1240eeprom_write(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
)
565 sb1250_x1240eeprom_t
*softc
= ctx
->dev_softc
;
571 bptr
= buffer
->buf_ptr
;
572 blen
= buffer
->buf_length
;
574 if ((buffer
->buf_offset
+ blen
) > X1241_EEPROM_SIZE
) return -1;
576 idx
= (int) buffer
->buf_offset
;
578 smbus_writertc(softc
->smbus_channel
,
586 b
= smbus_writertc(softc
->smbus_channel
,
595 smbus_writertc(softc
->smbus_channel
,
600 buffer
->buf_retlen
= bptr
- buffer
->buf_ptr
;
601 return (b
< 0) ? -1 : 0;
604 /* *********************************************************************
605 * sb1250_x1240eeprom_ioctl(ctx,buffer)
607 * Perform miscellaneous I/O control operations on the device.
610 * ctx - device context (can obtain our softc here)
611 * buffer - buffer descriptor (target buffer, length, offset)
614 * number of bytes read
615 * -1 if an error occured
616 ********************************************************************* */
618 static int sb1250_x1240eeprom_ioctl(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
)
620 sb1250_x1240eeprom_t
*softc
= ctx
->dev_softc
;
623 switch ((int)buffer
->buf_ioctlcmd
) {
624 case IOCTL_NVRAM_GETINFO
:
625 info
= (nvram_info_t
*) buffer
->buf_ptr
;
626 if (buffer
->buf_length
!= sizeof(nvram_info_t
)) return -1;
627 info
->nvram_offset
= softc
->env_offset
;
628 info
->nvram_size
= softc
->env_size
;
629 info
->nvram_eraseflg
= FALSE
;
630 buffer
->buf_retlen
= sizeof(nvram_info_t
);
637 /* *********************************************************************
638 * sb1250_x1240eeprom_close(ctx,buffer)
643 * ctx - device context (can obtain our softc here)
647 * -1 if an error occured
648 ********************************************************************* */
650 static int sb1250_x1240eeprom_close(cfe_devctx_t
*ctx
)