BCM WL 6.30.102.9 (r366174)
[tomato.git] / release / src-rt / cfe / cfe / arch / mips / cpu / sb1250 / src / dev_sb1250_24lc128eeprom.c
blob264377cd1777320c4a0ad6d78c8aba16d3f4f02c
1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * Microchip 24lc128 EEPROM driver File: dev_sb1250_24lc128eeprom.c
5 *
6 * This module contains a CFE driver for a Microchip 24LC128 EEPROM
7 *
8 * Author: Mitch Lichtenberg (mpl@broadcom.com)
9 *
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 ********************************************************************* */
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 * Forward Declarations
65 ********************************************************************* */
67 static void sb1250_24lc128eeprom_probe(cfe_driver_t *drv,
68 unsigned long probe_a, unsigned long probe_b,
69 void *probe_ptr);
72 static int sb1250_24lc128eeprom_open(cfe_devctx_t *ctx);
73 static int sb1250_24lc128eeprom_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
74 static int sb1250_24lc128eeprom_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
75 static int sb1250_24lc128eeprom_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
76 static int sb1250_24lc128eeprom_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
77 static int sb1250_24lc128eeprom_close(cfe_devctx_t *ctx);
79 /* *********************************************************************
80 * Dispatch tables
81 ********************************************************************* */
83 #define M24LC128_EEPROM_SIZE 16384
85 const static cfe_devdisp_t sb1250_24lc128eeprom_dispatch = {
86 sb1250_24lc128eeprom_open,
87 sb1250_24lc128eeprom_read,
88 sb1250_24lc128eeprom_inpstat,
89 sb1250_24lc128eeprom_write,
90 sb1250_24lc128eeprom_ioctl,
91 sb1250_24lc128eeprom_close,
92 NULL,
93 NULL
96 const cfe_driver_t sb1250_24lc128eeprom = {
97 "Microchip 24LC128 EEPROM",
98 "eeprom",
99 CFE_DEV_NVRAM,
100 &sb1250_24lc128eeprom_dispatch,
101 sb1250_24lc128eeprom_probe
104 typedef struct sb1250_24lc128eeprom_s {
105 int smbus_channel;
106 int smbus_address;
107 int env_offset;
108 int env_size;
109 unsigned char data[M24LC128_EEPROM_SIZE];
110 } sb1250_24lc128eeprom_t;
113 /* *********************************************************************
114 * smbus_init(chan)
116 * Initialize the specified SMBus channel
118 * Input parameters:
119 * chan - channel # (0 or 1)
121 * Return value:
122 * nothing
123 ********************************************************************* */
125 static void smbus_init(int chan)
127 uintptr_t reg;
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.
145 * Input parameters:
146 * chan - channel (0 or 1)
148 * Return value:
149 * nothing
150 ********************************************************************* */
151 static int smbus_waitready(int chan)
153 uintptr_t reg;
154 uint64_t status;
156 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_STATUS));
158 for (;;) {
159 status = SBREADCSR(reg);
160 if (status & M_SMB_BUSY) continue;
161 break;
164 if (status & M_SMB_ERROR) {
166 SBWRITECSR(reg,(status & M_SMB_ERROR));
167 return -1;
169 return 0;
172 /* *********************************************************************
173 * smbus_readbyte(chan,slaveaddr,devaddr)
175 * Read a byte from the chip. The 'slaveaddr' parameter determines
176 * whether we're reading from the RTC section or the EEPROM section.
178 * Input parameters:
179 * chan - SMBus channel
180 * slaveaddr - SMBus slave address
181 * devaddr - byte with in the device to read
183 * Return value:
184 * 0 if ok
185 * else -1
186 ********************************************************************* */
188 static int smbus_readbyte(int chan,int slaveaddr,int devaddr)
190 uintptr_t reg;
191 int err;
194 * Make sure the bus is idle (probably should
195 * ignore error here)
198 if (smbus_waitready(chan) < 0) return -1;
201 * Write the device address to the controller. There are two
202 * parts, the high part goes in the "CMD" field, and the
203 * low part is the data field.
206 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_CMD));
207 SBWRITECSR(reg,((devaddr >> 8) & 0x3F));
210 * Write the data to the controller
213 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_DATA));
214 SBWRITECSR(reg,((devaddr & 0xFF) & 0xFF));
217 * Start the command
220 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_START));
221 SBWRITECSR(reg,V_SMB_TT(K_SMB_TT_WR2BYTE) | slaveaddr);
224 * Wait till done
227 err = smbus_waitready(chan);
228 if (err < 0) return err;
231 * Read the data byte
234 SBWRITECSR(reg,V_SMB_TT(K_SMB_TT_RD1BYTE) | slaveaddr);
236 err = smbus_waitready(chan);
237 if (err < 0) return err;
239 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_DATA));
240 err = SBREADCSR(reg);
242 return (err & 0xFF);
245 /* *********************************************************************
246 * smbus_writebyte(chan,slaveaddr,devaddr,b)
248 * write a byte from the chip. The 'slaveaddr' parameter determines
249 * whethe we're writing to the RTC section or the EEPROM section.
251 * Input parameters:
252 * chan - SMBus channel
253 * slaveaddr - SMBus slave address
254 * devaddr - byte with in the device to read
255 * b - byte to write
257 * Return value:
258 * 0 if ok
259 * else -1
260 ********************************************************************* */
263 static int smbus_writebyte(int chan,int slaveaddr,int devaddr,int b)
265 uintptr_t reg;
266 int err;
267 int64_t timer;
270 * Make sure the bus is idle (probably should
271 * ignore error here)
274 if (smbus_waitready(chan) < 0) return -1;
277 * Write the device address to the controller. There are two
278 * parts, the high part goes in the "CMD" field, and the
279 * low part is the data field.
282 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_CMD));
283 SBWRITECSR(reg,((devaddr >> 8) & 0x3F));
286 * Write the data to the controller
289 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_DATA));
290 SBWRITECSR(reg,((devaddr & 0xFF) | ((b & 0xFF) << 8)));
293 * Start the command. Keep pounding on the device until it
294 * submits or the timer expires, whichever comes first. The
295 * datasheet says writes can take up to 10ms, so we'll give it 500.
298 reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_START));
299 SBWRITECSR(reg,V_SMB_TT(K_SMB_TT_WR3BYTE) | slaveaddr);
302 * Wait till the SMBus interface is done
305 err = smbus_waitready(chan);
306 if (err < 0) return err;
309 * Pound on the device with a quick command (R/W=0)
310 * to poll for the write complete. See sect 7.0 of the
311 * 24LC128 manual.
314 TIMER_SET(timer,50);
315 err = -1;
317 while (!TIMER_EXPIRED(timer)) {
318 POLL();
320 SBWRITECSR(reg,V_SMB_TT(K_SMB_TT_QUICKCMD) | slaveaddr);
322 err = smbus_waitready(chan);
323 if (err == 0) break;
326 return err;
330 /* *********************************************************************
331 * sb1250_24lc128eeprom_probe(drv,a,b,ptr)
333 * Probe routine for this driver. This routine creates the
334 * local device context and attaches it to the driver list
335 * within CFE.
337 * Input parameters:
338 * drv - driver handle
339 * a,b - probe hints (longs)
340 * ptr - probe hint (pointer)
342 * Return value:
343 * nothing
344 ********************************************************************* */
346 static void sb1250_24lc128eeprom_probe(cfe_driver_t *drv,
347 unsigned long probe_a, unsigned long probe_b,
348 void *probe_ptr)
350 sb1250_24lc128eeprom_t *softc;
351 char descr[80];
353 softc = (sb1250_24lc128eeprom_t *) KMALLOC(sizeof(sb1250_24lc128eeprom_t),0);
356 * Probe_a is the SMBus channel number
357 * Probe_b is the SMBus device offset
358 * Probe_ptr is unused.
361 softc->smbus_channel = (int)probe_a;
362 softc->smbus_address = (int)probe_b;
363 softc->env_offset = 0;
364 softc->env_size = M24LC128_EEPROM_SIZE;
366 xsprintf(descr,"%s on SMBus channel %d dev 0x%02X",
367 drv->drv_description,(int)probe_a,(int)probe_b);
368 cfe_attach(drv,softc,NULL,descr);
373 /* *********************************************************************
374 * sb1250_24lc128eeprom_open(ctx)
376 * Open this device. For the X1240, we do a quick test
377 * read to be sure the device is out there.
379 * Input parameters:
380 * ctx - device context (can obtain our softc here)
382 * Return value:
383 * 0 if ok
384 * else error code
385 ********************************************************************* */
387 static int sb1250_24lc128eeprom_open(cfe_devctx_t *ctx)
389 sb1250_24lc128eeprom_t *softc = ctx->dev_softc;
390 int b;
392 smbus_init(softc->smbus_channel);
394 b = smbus_readbyte(softc->smbus_channel,
395 softc->smbus_address,
398 return (b < 0) ? -1 : 0;
401 /* *********************************************************************
402 * sb1250_24lc128eeprom_read(ctx,buffer)
404 * Read bytes from the device.
406 * Input parameters:
407 * ctx - device context (can obtain our softc here)
408 * buffer - buffer descriptor (target buffer, length, offset)
410 * Return value:
411 * number of bytes read
412 * -1 if an error occured
413 ********************************************************************* */
415 static int sb1250_24lc128eeprom_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
417 sb1250_24lc128eeprom_t *softc = ctx->dev_softc;
418 unsigned char *bptr;
419 int blen;
420 int idx;
421 int b = 0;
423 bptr = buffer->buf_ptr;
424 blen = buffer->buf_length;
426 if ((buffer->buf_offset + blen) > M24LC128_EEPROM_SIZE) return -1;
428 idx = (int) buffer->buf_offset;
430 while (blen > 0) {
431 b = smbus_readbyte(softc->smbus_channel,
432 softc->smbus_address,
433 idx);
434 if (b < 0) break;
435 *bptr++ = (unsigned char) b;
436 blen--;
437 idx++;
440 buffer->buf_retlen = bptr - buffer->buf_ptr;
441 return (b < 0) ? -1 : 0;
444 /* *********************************************************************
445 * sb1250_24lc128eeprom_inpstat(ctx,inpstat)
447 * Test input (read) status for the device
449 * Input parameters:
450 * ctx - device context (can obtain our softc here)
451 * inpstat - input status descriptor to receive value
453 * Return value:
454 * 0 if ok
455 * -1 if an error occured
456 ********************************************************************* */
458 static int sb1250_24lc128eeprom_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
460 inpstat->inp_status = 1;
462 return 0;
465 /* *********************************************************************
466 * sb1250_24lc128eeprom_write(ctx,buffer)
468 * Write bytes from the device.
470 * Input parameters:
471 * ctx - device context (can obtain our softc here)
472 * buffer - buffer descriptor (target buffer, length, offset)
474 * Return value:
475 * number of bytes read
476 * -1 if an error occured
477 ********************************************************************* */
479 static int sb1250_24lc128eeprom_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
481 sb1250_24lc128eeprom_t *softc = ctx->dev_softc;
482 unsigned char *bptr;
483 int blen;
484 int idx;
485 int b = 0;
487 bptr = buffer->buf_ptr;
488 blen = buffer->buf_length;
490 if ((buffer->buf_offset + blen) > M24LC128_EEPROM_SIZE) return -1;
492 idx = (int) buffer->buf_offset;
494 while (blen > 0) {
495 b = *bptr++;
496 b = smbus_writebyte(softc->smbus_channel,
497 softc->smbus_address,
498 idx,
500 if (b < 0) break;
501 blen--;
502 idx++;
505 buffer->buf_retlen = bptr - buffer->buf_ptr;
506 return (b < 0) ? -1 : 0;
509 /* *********************************************************************
510 * sb1250_24lc128eeprom_ioctl(ctx,buffer)
512 * Perform miscellaneous I/O control operations on the device.
514 * Input parameters:
515 * ctx - device context (can obtain our softc here)
516 * buffer - buffer descriptor (target buffer, length, offset)
518 * Return value:
519 * number of bytes read
520 * -1 if an error occured
521 ********************************************************************* */
523 static int sb1250_24lc128eeprom_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
525 sb1250_24lc128eeprom_t *softc = ctx->dev_softc;
526 nvram_info_t *info;
528 switch ((int)buffer->buf_ioctlcmd) {
529 case IOCTL_NVRAM_GETINFO:
530 info = (nvram_info_t *) buffer->buf_ptr;
531 if (buffer->buf_length != sizeof(nvram_info_t)) return -1;
532 info->nvram_offset = softc->env_offset;
533 info->nvram_size = softc->env_size;
534 info->nvram_eraseflg = FALSE;
535 buffer->buf_retlen = sizeof(nvram_info_t);
536 return 0;
537 default:
538 return -1;
542 /* *********************************************************************
543 * sb1250_24lc128eeprom_close(ctx,buffer)
545 * Close the device.
547 * Input parameters:
548 * ctx - device context (can obtain our softc here)
550 * Return value:
551 * 0 if ok
552 * -1 if an error occured
553 ********************************************************************* */
555 static int sb1250_24lc128eeprom_close(cfe_devctx_t *ctx)
557 return 0;