1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  ATMEL AT24C02 EEPROM driver 	File: dev_smbus_at24c02.c
5    *
6    *  This module contains a CFE driver for a ATMEL AT24C02 EEPROM
7    *
8    *  Author:  Binh Vo
9    *
10    *********************************************************************
11    *
12    *  Copyright 2000,2001,2002,2003
13    *  Broadcom Corporation. All rights reserved.
14    *
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.
21    *
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.
25    *
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.
31    *
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    ********************************************************************* */
46
47#include "cfe.h"
48#include "cfe_smbus.h"
49
50
51/*  *********************************************************************
52    *  Forward Declarations
53    ********************************************************************* */
54
55static void sb1250_at24c02eeprom_probe(cfe_driver_t *drv,
56				     unsigned long probe_a, unsigned long probe_b,
57				     void *probe_ptr);
58
59
60static int sb1250_at24c02eeprom_open(cfe_devctx_t *ctx);
61static int sb1250_at24c02eeprom_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
62static int sb1250_at24c02eeprom_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
63static int sb1250_at24c02eeprom_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
64static int sb1250_at24c02eeprom_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
65static int sb1250_at24c02eeprom_close(cfe_devctx_t *ctx);
66
67/*  *********************************************************************
68    *  Dispatch tables
69    ********************************************************************* */
70
71#define AT24C02_EEPROM_SIZE	256
72
73const static cfe_devdisp_t sb1250_at24c02eeprom_dispatch = {
74    sb1250_at24c02eeprom_open,
75    sb1250_at24c02eeprom_read,
76    sb1250_at24c02eeprom_inpstat,
77    sb1250_at24c02eeprom_write,
78    sb1250_at24c02eeprom_ioctl,
79    sb1250_at24c02eeprom_close,
80    NULL,
81    NULL
82};
83
84const cfe_driver_t smbus_at24c02 = {
85    "ATMEL AT24C02 SPD EEPROM",
86    "eeprom",
87    CFE_DEV_NVRAM,
88    &sb1250_at24c02eeprom_dispatch,
89    sb1250_at24c02eeprom_probe
90};
91
92typedef struct sb1250_at24c02eeprom_s {
93    cfe_smbus_channel_t *smbus_channel;
94    int smbus_address;
95    int env_offset;
96    int env_size;
97} sb1250_at24c02eeprom_t;
98
99
100/*  *********************************************************************
101    *  smbus_readbyte(chan,slaveaddr,devaddr)
102    *
103    *  Read a byte from the chip.
104    *
105    *  Input parameters:
106    *  	   chan - SMBus channel
107    *  	   slaveaddr -  SMBus slave address
108    *  	   devaddr - byte within the at24c02 device to read
109    *
110    *  Return value:
111    *  	   0 if ok
112    *  	   else -1
113    ********************************************************************* */
114
115static int smbus_readbyte(cfe_smbus_channel_t *chan,int slaveaddr,int devaddr)
116{
117    uint8_t buf[1];
118    int err;
119
120    /*
121     * Start the command
122     */
123
124    buf[0] = devaddr;
125    err = SMBUS_WRITE(chan,slaveaddr,buf,1);
126    if (err < 0) return err;
127
128    /*
129     * Read the data byte
130     */
131
132    err = SMBUS_READ(chan,slaveaddr,buf,1);
133    if (err < 0) return err;
134
135    return buf[0];
136}
137
138/*  *********************************************************************
139    *  smbus_writebyte(chan,slaveaddr,devaddr,b)
140    *
141    *  write a byte from the chip.
142    *
143    *  Input parameters:
144    *  	   chan - SMBus channel
145    *  	   slaveaddr -  SMBus slave address
146    *  	   devaddr - byte within the at24c02 device to read
147    *      b - byte to write
148    *
149    *  Return value:
150    *  	   0 if ok
151    *  	   else -1
152    ********************************************************************* */
153
154static int smbus_writebyte(cfe_smbus_channel_t *chan,int slaveaddr,int devaddr,int b)
155{
156    uint8_t buf[2];
157    int err;
158    int64_t timer;
159
160    /*
161     * Write the data to the controller
162     */
163
164    buf[0] = devaddr;
165    buf[1] = b;
166
167    err = SMBUS_WRITE(chan,slaveaddr,buf,2);
168
169    /*
170     * Pound on the device with a current address read
171     * to poll for the write complete
172     */
173
174    TIMER_SET(timer,50);
175    err = -1;
176
177    while (!TIMER_EXPIRED(timer)) {
178	POLL();
179
180	err = SMBUS_READ(chan,slaveaddr,buf,1);
181	if (err == 0) break;
182	}
183
184    return err;
185}
186
187/*  *********************************************************************
188    *  sb1250_at24c02eeprom_probe(drv,a,b,ptr)
189    *
190    *  Probe routine for this driver.  This routine creates the
191    *  local device context and attaches it to the driver list
192    *  within CFE.
193    *
194    *  Input parameters:
195    *  	   drv - driver handle
196    *  	   a,b - probe hints (longs)
197    *  	   ptr - probe hint (pointer)
198    *
199    *  Return value:
200    *  	   nothing
201    ********************************************************************* */
202
203static void sb1250_at24c02eeprom_probe(cfe_driver_t *drv,
204				     unsigned long probe_a, unsigned long probe_b,
205				     void *probe_ptr)
206{
207    sb1250_at24c02eeprom_t *softc;
208    char descr[80];
209
210    softc = (sb1250_at24c02eeprom_t *) KMALLOC(sizeof(sb1250_at24c02eeprom_t),0);
211
212    /*
213     * Probe_a is the SMBus channel number
214     * Probe_b is the SMBus device offset
215     * Probe_ptr is unused.
216     */
217
218    softc->smbus_channel = SMBUS_CHANNEL((int)probe_a);
219    softc->smbus_address = (int)probe_b;
220    softc->env_offset  = 0;
221    softc->env_size = AT24C02_EEPROM_SIZE;
222
223    xsprintf(descr,"%s on SMBus channel %d dev 0x%02X",
224	     drv->drv_description,(int)probe_a,(int)probe_b);
225    cfe_attach(drv,softc,NULL,descr);
226}
227
228
229
230/*  *********************************************************************
231    *  sb1250_at24c02eeprom_open(ctx)
232    *
233    *  Open this device.
234    *
235    *  Input parameters:
236    *  	   ctx - device context (can obtain our softc here)
237    *
238    *  Return value:
239    *  	   0 if ok
240    *  	   else error code
241    ********************************************************************* */
242
243static int sb1250_at24c02eeprom_open(cfe_devctx_t *ctx)
244{
245    sb1250_at24c02eeprom_t *softc = ctx->dev_softc;
246    int b;
247
248    b = smbus_readbyte(softc->smbus_channel,
249		       softc->smbus_address,
250		       0);
251
252    return (b < 0) ? -1 : 0;
253}
254
255/*  *********************************************************************
256    *  sb1250_at24c02eeprom_read(ctx,buffer)
257    *
258    *  Read bytes from the device.
259    *
260    *  Input parameters:
261    *  	   ctx - device context (can obtain our softc here)
262    *  	   buffer - buffer descriptor (target buffer, length, offset)
263    *
264    *  Return value:
265    *  	   number of bytes read
266    *  	   -1 if an error occured
267    ********************************************************************* */
268
269static int sb1250_at24c02eeprom_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
270{
271    sb1250_at24c02eeprom_t *softc = ctx->dev_softc;
272    hsaddr_t bptr;
273    int blen;
274    int idx;
275    int b = 0;
276
277    bptr = buffer->buf_ptr;
278    blen = buffer->buf_length;
279
280    if ((buffer->buf_offset + blen) > AT24C02_EEPROM_SIZE) return -1;
281
282    idx = (int) buffer->buf_offset;
283
284    while (blen > 0) {
285	b = smbus_readbyte(softc->smbus_channel,
286			  softc->smbus_address,
287			  idx);
288	if (b < 0) break;
289	hs_write8(bptr,(unsigned char)b);
290	bptr++;
291	blen--;
292	idx++;
293	}
294
295    buffer->buf_retlen = bptr - buffer->buf_ptr;
296    return (b < 0) ? -1 : 0;
297}
298
299/*  *********************************************************************
300    *  sb1250_at24c02eeprom_inpstat(ctx,inpstat)
301    *
302    *  Test input (read) status for the device
303    *
304    *  Input parameters:
305    *  	   ctx - device context (can obtain our softc here)
306    *  	   inpstat - input status descriptor to receive value
307    *
308    *  Return value:
309    *  	   0 if ok
310    *  	   -1 if an error occured
311    ********************************************************************* */
312
313static int sb1250_at24c02eeprom_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
314{
315    inpstat->inp_status = 1;
316
317    return 0;
318}
319
320/*  *********************************************************************
321    *  sb1250_at24c02eeprom_write(ctx,buffer)
322    *
323    *  Write bytes from the device.
324    *
325    *  Input parameters:
326    *  	   ctx - device context (can obtain our softc here)
327    *  	   buffer - buffer descriptor (target buffer, length, offset)
328    *
329    *  Return value:
330    *  	   number of bytes read
331    *  	   -1 if an error occured
332    ********************************************************************* */
333
334static int sb1250_at24c02eeprom_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
335{
336    sb1250_at24c02eeprom_t *softc = ctx->dev_softc;
337    hsaddr_t bptr;
338    int blen;
339    int idx;
340    int b = 0;
341
342    bptr = buffer->buf_ptr;
343    blen = buffer->buf_length;
344
345    if ((buffer->buf_offset + blen) > AT24C02_EEPROM_SIZE) return -1;
346
347    idx = (int) buffer->buf_offset;
348
349    while (blen > 0) {
350	b = hs_read8(bptr);
351	bptr++;
352	b = smbus_writebyte(softc->smbus_channel,
353			   softc->smbus_address,
354			   idx,
355			   b);
356	if (b < 0) break;
357	blen--;
358	idx++;
359	}
360
361    buffer->buf_retlen = bptr - buffer->buf_ptr;
362    return (b < 0) ? -1 : 0;
363}
364
365/*  *********************************************************************
366    *  sb1250_at24c02eeprom_ioctl(ctx,buffer)
367    *
368    *  Perform miscellaneous I/O control operations on the device.
369    *
370    *  Input parameters:
371    *  	   ctx - device context (can obtain our softc here)
372    *  	   buffer - buffer descriptor (target buffer, length, offset)
373    *
374    *  Return value:
375    *  	   number of bytes read
376    *  	   -1 if an error occured
377    ********************************************************************* */
378
379static int sb1250_at24c02eeprom_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
380{
381    sb1250_at24c02eeprom_t *softc = ctx->dev_softc;
382    nvram_info_t info;
383
384    switch ((int)buffer->buf_ioctlcmd) {
385	case IOCTL_NVRAM_GETINFO:
386	    if (buffer->buf_length != sizeof(nvram_info_t)) return -1;
387	    info.nvram_offset = softc->env_offset;
388	    info.nvram_size =   softc->env_size;
389	    info.nvram_eraseflg = FALSE;
390	    buffer->buf_retlen = sizeof(nvram_info_t);
391	    hs_memcpy_to_hs(buffer->buf_ptr,&info,sizeof(info));
392	    return 0;
393	default:
394	    return -1;
395	}
396}
397
398/*  *********************************************************************
399    *  sb1250_at24c02eeprom_close(ctx,buffer)
400    *
401    *  Close the device.
402    *
403    *  Input parameters:
404    *  	   ctx - device context (can obtain our softc here)
405    *
406    *  Return value:
407    *  	   0 if ok
408    *  	   -1 if an error occured
409    ********************************************************************* */
410
411static int sb1250_at24c02eeprom_close(cfe_devctx_t *ctx)
412{
413    return 0;
414}
415
416
417