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