1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * ATMEL AT24C02 EEPROM driver File: dev_sb1250_at24c02eeprom.c
6 * This module contains a CFE driver for a ATMEL AT24C02 EEPROM
8 * Author: Binh Vo (binh@broadcom.com)
10 *********************************************************************
12 * Copyright 2000,2001,2002,2003
13 * Broadcom Corporation. All rights reserved.
15 * This software is furnished under license and may be used and
16 * copied only in accordance with the following terms and
17 * conditions. Subject to these conditions, you may download,
18 * copy, install, use, modify and distribute modified or unmodified
19 * copies of this software in source and/or binary form. No title
20 * or ownership is transferred hereby.
22 * 1) Any source code used, modified or distributed must reproduce
23 * and retain this copyright notice and list of conditions
24 * as they appear in the source file.
26 * 2) No right is granted to use any trade name, trademark, or
27 * logo of Broadcom Corporation. The "Broadcom Corporation"
28 * name may not be used to endorse or promote products derived
29 * from this software without the prior written permission of
30 * Broadcom Corporation.
32 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
33 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
34 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
35 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
36 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
37 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
40 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
42 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
43 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
44 * THE POSSIBILITY OF SUCH DAMAGE.
45 ********************************************************************* */
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 /* *********************************************************************
64 * Forward Declarations
65 ********************************************************************* */
67 static void sb1250_at24c02eeprom_probe(cfe_driver_t
*drv
,
68 unsigned long probe_a
, unsigned long probe_b
,
72 static int sb1250_at24c02eeprom_open(cfe_devctx_t
*ctx
);
73 static int sb1250_at24c02eeprom_read(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
);
74 static int sb1250_at24c02eeprom_inpstat(cfe_devctx_t
*ctx
,iocb_inpstat_t
*inpstat
);
75 static int sb1250_at24c02eeprom_write(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
);
76 static int sb1250_at24c02eeprom_ioctl(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
);
77 static int sb1250_at24c02eeprom_close(cfe_devctx_t
*ctx
);
79 /* *********************************************************************
81 ********************************************************************* */
83 #define AT24C02_EEPROM_SIZE 256
85 const static cfe_devdisp_t sb1250_at24c02eeprom_dispatch
= {
86 sb1250_at24c02eeprom_open
,
87 sb1250_at24c02eeprom_read
,
88 sb1250_at24c02eeprom_inpstat
,
89 sb1250_at24c02eeprom_write
,
90 sb1250_at24c02eeprom_ioctl
,
91 sb1250_at24c02eeprom_close
,
96 const cfe_driver_t sb1250_at24c02eeprom
= {
97 "ATMEL AT24C02 SPD EEPROM",
100 &sb1250_at24c02eeprom_dispatch
,
101 sb1250_at24c02eeprom_probe
104 typedef struct sb1250_at24c02eeprom_s
{
109 unsigned char data
[AT24C02_EEPROM_SIZE
];
110 } sb1250_at24c02eeprom_t
;
113 /* *********************************************************************
116 * Initialize the specified SMBus channel
119 * chan - channel # (0 or 1)
123 ********************************************************************* */
125 static void smbus_init(int chan
)
129 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_FREQ
));
131 SBWRITECSR(reg
,K_SMB_FREQ_100KHZ
);
133 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_CONTROL
));
135 SBWRITECSR(reg
,0); /* not in direct mode, no interrupts, will poll */
139 /* *********************************************************************
140 * smbus_waitready(chan)
142 * Wait until the SMBus channel is ready. We simply poll
143 * the busy bit until it clears.
146 * chan - channel (0 or 1)
150 ********************************************************************* */
151 static int smbus_waitready(int chan
)
156 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_STATUS
));
159 status
= SBREADCSR(reg
);
160 if (status
& M_SMB_BUSY
) continue;
164 if (status
& M_SMB_ERROR
) {
166 SBWRITECSR(reg
,(status
& M_SMB_ERROR
));
172 /* *********************************************************************
173 * smbus_readbyte(chan,slaveaddr,devaddr)
175 * Read a byte from the chip.
178 * chan - SMBus channel
179 * slaveaddr - SMBus slave address
180 * devaddr - byte within the at24c02 device to read
185 ********************************************************************* */
187 static int smbus_readbyte(int chan
,int slaveaddr
,int devaddr
)
193 * Make sure the bus is idle (probably should
197 if (smbus_waitready(chan
) < 0) return -1;
200 * Write the device address to smb_cmd field of command register
203 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_CMD
));
204 SBWRITECSR(reg
,devaddr
);
210 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_START
));
211 SBWRITECSR(reg
,V_SMB_TT(K_SMB_TT_WR1BYTE
) | slaveaddr
);
217 err
= smbus_waitready(chan
);
218 if (err
< 0) return err
;
224 SBWRITECSR(reg
,V_SMB_TT(K_SMB_TT_RD1BYTE
) | slaveaddr
);
226 err
= smbus_waitready(chan
);
227 if (err
< 0) return err
;
229 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_DATA
));
230 err
= SBREADCSR(reg
);
235 /* *********************************************************************
236 * smbus_writebyte(chan,slaveaddr,devaddr,b)
238 * write a byte from the chip.
241 * chan - SMBus channel
242 * slaveaddr - SMBus slave address
243 * devaddr - byte within the at24c02 device to read
249 ********************************************************************* */
251 static int smbus_writebyte(int chan
,int slaveaddr
,int devaddr
,int b
)
258 * Make sure the bus is idle (probably should
262 if (smbus_waitready(chan
) < 0) return -1;
265 * Write the device address to the controller. There are two
266 * parts, the high part goes in the "CMD" field, and the
267 * low part is the data field.
270 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_CMD
));
271 SBWRITECSR(reg
,devaddr
);
274 * Write the data to the controller
277 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_DATA
));
281 * Start the command. Keep pounding on the device until it
282 * submits or the timer expires, whichever comes first. The
283 * datasheet says writes can take up to 10ms, so we'll give it 500.
286 reg
= PHYS_TO_K1(A_SMB_REGISTER(chan
,R_SMB_START
));
287 SBWRITECSR(reg
,V_SMB_TT(K_SMB_TT_WR2BYTE
) | slaveaddr
);
290 * Wait till the SMBus interface is done
293 err
= smbus_waitready(chan
);
294 if (err
< 0) return err
;
297 * Pound on the device with a current address read
298 * to poll for the write complete
304 while (!TIMER_EXPIRED(timer
)) {
307 SBWRITECSR(reg
,V_SMB_TT(K_SMB_TT_RD1BYTE
) | slaveaddr
);
309 err
= smbus_waitready(chan
);
316 /* *********************************************************************
317 * sb1250_at24c02eeprom_probe(drv,a,b,ptr)
319 * Probe routine for this driver. This routine creates the
320 * local device context and attaches it to the driver list
324 * drv - driver handle
325 * a,b - probe hints (longs)
326 * ptr - probe hint (pointer)
330 ********************************************************************* */
332 static void sb1250_at24c02eeprom_probe(cfe_driver_t
*drv
,
333 unsigned long probe_a
, unsigned long probe_b
,
336 sb1250_at24c02eeprom_t
*softc
;
339 softc
= (sb1250_at24c02eeprom_t
*) KMALLOC(sizeof(sb1250_at24c02eeprom_t
),0);
342 * Probe_a is the SMBus channel number
343 * Probe_b is the SMBus device offset
344 * Probe_ptr is unused.
347 softc
->smbus_channel
= (int)probe_a
;
348 softc
->smbus_address
= (int)probe_b
;
349 softc
->env_offset
= 0;
350 softc
->env_size
= AT24C02_EEPROM_SIZE
;
352 xsprintf(descr
,"%s on SMBus channel %d dev 0x%02X",
353 drv
->drv_description
,(int)probe_a
,(int)probe_b
);
354 cfe_attach(drv
,softc
,NULL
,descr
);
359 /* *********************************************************************
360 * sb1250_at24c02eeprom_open(ctx)
365 * ctx - device context (can obtain our softc here)
370 ********************************************************************* */
372 static int sb1250_at24c02eeprom_open(cfe_devctx_t
*ctx
)
374 sb1250_at24c02eeprom_t
*softc
= ctx
->dev_softc
;
377 smbus_init(softc
->smbus_channel
);
379 b
= smbus_readbyte(softc
->smbus_channel
,
380 softc
->smbus_address
,
383 return (b
< 0) ? -1 : 0;
386 /* *********************************************************************
387 * sb1250_at24c02eeprom_read(ctx,buffer)
389 * Read bytes from the device.
392 * ctx - device context (can obtain our softc here)
393 * buffer - buffer descriptor (target buffer, length, offset)
396 * number of bytes read
397 * -1 if an error occured
398 ********************************************************************* */
400 static int sb1250_at24c02eeprom_read(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
)
402 sb1250_at24c02eeprom_t
*softc
= ctx
->dev_softc
;
408 bptr
= buffer
->buf_ptr
;
409 blen
= buffer
->buf_length
;
411 if ((buffer
->buf_offset
+ blen
) > AT24C02_EEPROM_SIZE
) return -1;
413 idx
= (int) buffer
->buf_offset
;
416 b
= smbus_readbyte(softc
->smbus_channel
,
417 softc
->smbus_address
,
420 *bptr
++ = (unsigned char) b
;
425 buffer
->buf_retlen
= bptr
- buffer
->buf_ptr
;
426 return (b
< 0) ? -1 : 0;
429 /* *********************************************************************
430 * sb1250_at24c02eeprom_inpstat(ctx,inpstat)
432 * Test input (read) status for the device
435 * ctx - device context (can obtain our softc here)
436 * inpstat - input status descriptor to receive value
440 * -1 if an error occured
441 ********************************************************************* */
443 static int sb1250_at24c02eeprom_inpstat(cfe_devctx_t
*ctx
,iocb_inpstat_t
*inpstat
)
445 inpstat
->inp_status
= 1;
450 /* *********************************************************************
451 * sb1250_at24c02eeprom_write(ctx,buffer)
453 * Write bytes from the device.
456 * ctx - device context (can obtain our softc here)
457 * buffer - buffer descriptor (target buffer, length, offset)
460 * number of bytes read
461 * -1 if an error occured
462 ********************************************************************* */
464 static int sb1250_at24c02eeprom_write(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
)
466 sb1250_at24c02eeprom_t
*softc
= ctx
->dev_softc
;
472 bptr
= buffer
->buf_ptr
;
473 blen
= buffer
->buf_length
;
475 if ((buffer
->buf_offset
+ blen
) > AT24C02_EEPROM_SIZE
) return -1;
477 idx
= (int) buffer
->buf_offset
;
481 b
= smbus_writebyte(softc
->smbus_channel
,
482 softc
->smbus_address
,
490 buffer
->buf_retlen
= bptr
- buffer
->buf_ptr
;
491 return (b
< 0) ? -1 : 0;
494 /* *********************************************************************
495 * sb1250_at24c02eeprom_ioctl(ctx,buffer)
497 * Perform miscellaneous I/O control operations on the device.
500 * ctx - device context (can obtain our softc here)
501 * buffer - buffer descriptor (target buffer, length, offset)
504 * number of bytes read
505 * -1 if an error occured
506 ********************************************************************* */
508 static int sb1250_at24c02eeprom_ioctl(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
)
510 sb1250_at24c02eeprom_t
*softc
= ctx
->dev_softc
;
513 switch ((int)buffer
->buf_ioctlcmd
) {
514 case IOCTL_NVRAM_GETINFO
:
515 info
= (nvram_info_t
*) buffer
->buf_ptr
;
516 if (buffer
->buf_length
!= sizeof(nvram_info_t
)) return -1;
517 info
->nvram_offset
= softc
->env_offset
;
518 info
->nvram_size
= softc
->env_size
;
519 info
->nvram_eraseflg
= FALSE
;
520 buffer
->buf_retlen
= sizeof(nvram_info_t
);
527 /* *********************************************************************
528 * sb1250_at24c02eeprom_close(ctx,buffer)
533 * ctx - device context (can obtain our softc here)
537 * -1 if an error occured
538 ********************************************************************* */
540 static int sb1250_at24c02eeprom_close(cfe_devctx_t
*ctx
)