1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  Xicor RTC/EEPROM driver		File: dev_smbus_x1240eeprom.c
5    *
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
9    *  storage.
10    *
11    *  Author:  Mitch Lichtenberg
12    *
13    *********************************************************************
14    *
15    *  Copyright 2000,2001,2002,2003
16    *  Broadcom Corporation. All rights reserved.
17    *
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.
24    *
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.
28    *
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.
34    *
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    ********************************************************************* */
49
50
51#include "cfe.h"
52#include "cfe_smbus.h"
53
54
55/*  *********************************************************************
56    *  Xicor X1241 RTC constants
57    ********************************************************************* */
58
59/*
60 * Register bits
61 */
62
63#define X1241REG_SR_BAT	0x80		/* currently on battery power */
64#define X1241REG_SR_RWEL 0x04		/* r/w latch is enabled, can write RTC */
65#define X1241REG_SR_WEL 0x02		/* r/w latch is unlocked, can enable r/w now */
66#define X1241REG_SR_RTCF 0x01		/* clock failed */
67#define X1241REG_BL_BP2 0x80		/* block protect 2 */
68#define X1241REG_BL_BP1 0x40		/* block protect 1 */
69#define X1241REG_BL_BP0 0x20		/* block protect 0 */
70#define X1241REG_BL_WD1	0x10
71#define X1241REG_BL_WD0	0x08
72#define X1241REG_HR_MIL 0x80		/* military time format */
73
74/*
75 * Register numbers
76 */
77
78#define X1241REG_BL	0x10		/* block protect bits */
79#define X1241REG_INT	0x11		/*  */
80#define X1241REG_SC	0x30		/* Seconds */
81#define X1241REG_MN	0x31		/* Minutes */
82#define X1241REG_HR	0x32		/* Hours */
83#define X1241REG_DT	0x33		/* Day of month */
84#define X1241REG_MO	0x34		/* Month */
85#define X1241REG_YR	0x35		/* Year */
86#define X1241REG_DW	0x36		/* Day of Week */
87#define X1241REG_Y2K	0x37		/* Year 2K */
88#define X1241REG_SR	0x3F		/* Status register */
89
90#define X1241_CCR_ADDRESS	0x6F
91#define X1241_ARRAY_ADDRESS	0x57
92
93#define X1241_EEPROM_SIZE 2048
94
95/*  *********************************************************************
96    *  Forward Declarations
97    ********************************************************************* */
98
99static void sb1250_x1240eeprom_probe(cfe_driver_t *drv,
100				     unsigned long probe_a, unsigned long probe_b,
101				     void *probe_ptr);
102
103
104static int sb1250_x1240eeprom_open(cfe_devctx_t *ctx);
105static int sb1250_x1240eeprom_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
106static int sb1250_x1240eeprom_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
107static int sb1250_x1240eeprom_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
108static int sb1250_x1240eeprom_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
109static int sb1250_x1240eeprom_close(cfe_devctx_t *ctx);
110
111/*  *********************************************************************
112    *  Dispatch tables
113    ********************************************************************* */
114
115const static cfe_devdisp_t sb1250_x1240eeprom_dispatch = {
116    sb1250_x1240eeprom_open,
117    sb1250_x1240eeprom_read,
118    sb1250_x1240eeprom_inpstat,
119    sb1250_x1240eeprom_write,
120    sb1250_x1240eeprom_ioctl,
121    sb1250_x1240eeprom_close,
122    NULL,
123    NULL
124};
125
126const cfe_driver_t smbus_x1240eeprom = {
127    "Xicor X1241 EEPROM",
128    "eeprom",
129    CFE_DEV_NVRAM,
130    &sb1250_x1240eeprom_dispatch,
131    sb1250_x1240eeprom_probe
132};
133
134typedef struct sb1250_x1240eeprom_s {
135    cfe_smbus_channel_t *smbus_channel;
136    int env_offset;
137    int env_size;
138} sb1250_x1240eeprom_t;
139
140
141
142
143/*  *********************************************************************
144    *  smbus_readrtc(chan,slaveaddr,devaddr)
145    *
146    *  Read a byte from the chip.  The 'slaveaddr' parameter determines
147    *  whether we're reading from the RTC section or the EEPROM section.
148    *
149    *  Input parameters:
150    *  	   chan - SMBus channel
151    *  	   slaveaddr -  SMBus slave address
152    *  	   devaddr - byte with in the X1240 device to read
153    *
154    *  Return value:
155    *  	   0 if ok
156    *  	   else -1
157    ********************************************************************* */
158
159static int smbus_readrtc(cfe_smbus_channel_t *chan,int slaveaddr,int devaddr)
160{
161    uint8_t buf[2];
162    int err;
163
164    /*
165     * Write the device address to the controller. There are two
166     * parts, the high part goes in the "CMD" field, and the
167     * low part is the data field.
168     */
169
170    buf[0] = (devaddr >> 8) & 0x07;
171    buf[1] = (devaddr & 0xFF);
172
173    err = SMBUS_WRITE(chan,slaveaddr,buf,2);
174    if (err < 0) return err;
175
176    /*
177     * Read the data byte
178     */
179
180    err = SMBUS_READ(chan,slaveaddr,buf,1);
181    if (err < 0) return err;
182
183    return (buf[0]);
184}
185
186/*  *********************************************************************
187    *  smbus_writertc(chan,slaveaddr,devaddr,b)
188    *
189    *  write a byte from the chip.  The 'slaveaddr' parameter determines
190    *  whethe we're writing to the RTC section or the EEPROM section.
191    *
192    *  Input parameters:
193    *  	   chan - SMBus channel
194    *  	   slaveaddr -  SMBus slave address
195    *  	   devaddr - byte with in the X1240 device to read
196    *      b - byte to write
197    *
198    *  Return value:
199    *  	   0 if ok
200    *  	   else -1
201    ********************************************************************* */
202
203
204static int smbus_writertc(cfe_smbus_channel_t *chan,int slaveaddr,int devaddr,int b)
205{
206    uint8_t buf[3];
207    int err;
208    int64_t timer;
209
210
211    /*
212     * Write the data to the controller
213     */
214
215
216    buf[0] = (devaddr >> 8) & 0x07;
217    buf[1] = (devaddr & 0xFF);
218    buf[2] = b;
219
220    err = SMBUS_WRITE(chan,slaveaddr,buf,3);
221    if (err < 0) return err;
222
223    /*
224     * Pound on the device with a current address read
225     * to poll for the write complete
226     */
227
228    TIMER_SET(timer,50);
229    err = -1;
230
231    while (!TIMER_EXPIRED(timer)) {
232	POLL();
233
234	err = SMBUS_READ(chan,slaveaddr,buf,1);
235	if (err == 0) break;
236	}
237
238    return err;
239}
240
241
242/*  *********************************************************************
243    *  sb1250_x1240eeprom_probe(drv,a,b,ptr)
244    *
245    *  Probe routine for this driver.  This routine creates the
246    *  local device context and attaches it to the driver list
247    *  within CFE.
248    *
249    *  Input parameters:
250    *  	   drv - driver handle
251    *  	   a,b - probe hints (longs)
252    *  	   ptr - probe hint (pointer)
253    *
254    *  Return value:
255    *  	   nothing
256    ********************************************************************* */
257
258static void sb1250_x1240eeprom_probe(cfe_driver_t *drv,
259				     unsigned long probe_a, unsigned long probe_b,
260				     void *probe_ptr)
261{
262    sb1250_x1240eeprom_t *softc;
263    char descr[80];
264
265    softc = (sb1250_x1240eeprom_t *) KMALLOC(sizeof(sb1250_x1240eeprom_t),0);
266
267    /*
268     * Probe_a is the SMBus channel number
269     * Probe_b is the SMBus device offset
270     * Probe_ptr is unused.
271     */
272
273    softc->smbus_channel = SMBUS_CHANNEL((int)probe_a);
274    softc->env_offset  = 0;
275    softc->env_size = X1241_EEPROM_SIZE;
276
277    xsprintf(descr,"%s on SMBus channel %d dev 0x%02X",
278	     drv->drv_description,probe_a,X1241_ARRAY_ADDRESS);
279    cfe_attach(drv,softc,NULL,descr);
280}
281
282
283
284/*  *********************************************************************
285    *  sb1250_x1240eeprom_open(ctx)
286    *
287    *  Open this device.  For the X1240, we do a quick test
288    *  read to be sure the device is out there.
289    *
290    *  Input parameters:
291    *  	   ctx - device context (can obtain our softc here)
292    *
293    *  Return value:
294    *  	   0 if ok
295    *  	   else error code
296    ********************************************************************* */
297
298static int sb1250_x1240eeprom_open(cfe_devctx_t *ctx)
299{
300    sb1250_x1240eeprom_t *softc = ctx->dev_softc;
301    int b;
302    int64_t timer;
303
304    /*
305     * Try to read byte 0 from the device.  If it does not
306     * respond, fail the open.  We may need to do this for
307     * up to 300ms in case the X1240 is busy wiggling its
308     * RESET line.
309     */
310
311    TIMER_SET(timer,300);
312    while (!TIMER_EXPIRED(timer)) {
313	POLL();
314	b = smbus_readrtc(softc->smbus_channel,
315			  X1241_ARRAY_ADDRESS,
316			  0);
317	if (b >= 0) break;		/* read is ok */
318	}
319
320    /*
321     * See if the watchdog is enabled.  If it is, turn it off.
322     */
323
324    b = smbus_readrtc(softc->smbus_channel,
325		      X1241_CCR_ADDRESS,
326		      X1241REG_BL);
327
328    if (b != (X1241REG_BL_WD1 | X1241REG_BL_WD0)) {
329
330	smbus_writertc(softc->smbus_channel,
331		       X1241_CCR_ADDRESS,
332		       X1241REG_SR,
333		       X1241REG_SR_WEL);
334
335	smbus_writertc(softc->smbus_channel,
336		       X1241_CCR_ADDRESS,
337		       X1241REG_SR,
338		       X1241REG_SR_WEL | X1241REG_SR_RWEL);
339
340	smbus_writertc(softc->smbus_channel,
341		       X1241_CCR_ADDRESS,
342		       X1241REG_BL,
343		       (X1241REG_BL_WD1 | X1241REG_BL_WD0));
344
345	smbus_writertc(softc->smbus_channel,
346		       X1241_CCR_ADDRESS,
347		       X1241REG_SR,
348		       0);
349	}
350
351
352
353    return (b < 0) ? -1 : 0;
354}
355
356/*  *********************************************************************
357    *  sb1250_x1240eeprom_read(ctx,buffer)
358    *
359    *  Read bytes from the device.
360    *
361    *  Input parameters:
362    *  	   ctx - device context (can obtain our softc here)
363    *  	   buffer - buffer descriptor (target buffer, length, offset)
364    *
365    *  Return value:
366    *  	   number of bytes read
367    *  	   -1 if an error occured
368    ********************************************************************* */
369
370static int sb1250_x1240eeprom_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
371{
372    sb1250_x1240eeprom_t *softc = ctx->dev_softc;
373    hsaddr_t bptr;
374    int blen;
375    int idx;
376    int b = 0;
377
378    bptr = buffer->buf_ptr;
379    blen = buffer->buf_length;
380
381    if ((buffer->buf_offset + blen) > X1241_EEPROM_SIZE) return -1;
382
383    idx = (int) buffer->buf_offset;
384
385    while (blen > 0) {
386	b = smbus_readrtc(softc->smbus_channel,
387			  X1241_ARRAY_ADDRESS,
388			  idx);
389	if (b < 0) break;
390	hs_write8(bptr,(unsigned char)b);
391	bptr++;
392	blen--;
393	idx++;
394	}
395
396    buffer->buf_retlen = bptr - buffer->buf_ptr;
397    return (b < 0) ? -1 : 0;
398}
399
400/*  *********************************************************************
401    *  sb1250_x1240eeprom_inpstat(ctx,inpstat)
402    *
403    *  Test input (read) status for the device
404    *
405    *  Input parameters:
406    *  	   ctx - device context (can obtain our softc here)
407    *  	   inpstat - input status descriptor to receive value
408    *
409    *  Return value:
410    *  	   0 if ok
411    *  	   -1 if an error occured
412    ********************************************************************* */
413
414static int sb1250_x1240eeprom_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
415{
416    inpstat->inp_status = 1;
417
418    return 0;
419}
420
421/*  *********************************************************************
422    *  sb1250_x1240eeprom_write(ctx,buffer)
423    *
424    *  Write bytes from the device.
425    *
426    *  Input parameters:
427    *  	   ctx - device context (can obtain our softc here)
428    *  	   buffer - buffer descriptor (target buffer, length, offset)
429    *
430    *  Return value:
431    *  	   number of bytes read
432    *  	   -1 if an error occured
433    ********************************************************************* */
434
435static int sb1250_x1240eeprom_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
436{
437    sb1250_x1240eeprom_t *softc = ctx->dev_softc;
438    hsaddr_t bptr;
439    int blen;
440    int idx;
441    int b = 0;
442
443    bptr = buffer->buf_ptr;
444    blen = buffer->buf_length;
445
446    if ((buffer->buf_offset + blen) > X1241_EEPROM_SIZE) return -1;
447
448    idx = (int) buffer->buf_offset;
449
450    smbus_writertc(softc->smbus_channel,
451		   X1241_CCR_ADDRESS,
452		   X1241REG_SR,
453		   X1241REG_SR_WEL);
454
455
456    while (blen > 0) {
457	b = hs_read8(bptr);
458	bptr++;
459	b = smbus_writertc(softc->smbus_channel,
460			   X1241_ARRAY_ADDRESS,
461			   idx,
462			   b);
463	if (b < 0) break;
464	blen--;
465	idx++;
466	}
467
468    smbus_writertc(softc->smbus_channel,
469		   X1241_CCR_ADDRESS,
470		   X1241REG_SR,
471		   0);
472
473    buffer->buf_retlen = bptr - buffer->buf_ptr;
474    return (b < 0) ? -1 : 0;
475}
476
477/*  *********************************************************************
478    *  sb1250_x1240eeprom_ioctl(ctx,buffer)
479    *
480    *  Perform miscellaneous I/O control operations on the device.
481    *
482    *  Input parameters:
483    *  	   ctx - device context (can obtain our softc here)
484    *  	   buffer - buffer descriptor (target buffer, length, offset)
485    *
486    *  Return value:
487    *  	   number of bytes read
488    *  	   -1 if an error occured
489    ********************************************************************* */
490
491static int sb1250_x1240eeprom_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
492{
493    sb1250_x1240eeprom_t *softc = ctx->dev_softc;
494    nvram_info_t info;
495
496    switch ((int)buffer->buf_ioctlcmd) {
497	case IOCTL_NVRAM_GETINFO:
498	    if (buffer->buf_length != sizeof(nvram_info_t)) return -1;
499	    info.nvram_offset = softc->env_offset;
500	    info.nvram_size =   softc->env_size;
501	    info.nvram_eraseflg = FALSE;
502	    buffer->buf_retlen = sizeof(nvram_info_t);
503	    hs_memcpy_to_hs(buffer->buf_ptr,&info,sizeof(info));
504	    return 0;
505	default:
506	    return -1;
507	}
508}
509
510/*  *********************************************************************
511    *  sb1250_x1240eeprom_close(ctx,buffer)
512    *
513    *  Close the device.
514    *
515    *  Input parameters:
516    *  	   ctx - device context (can obtain our softc here)
517    *
518    *  Return value:
519    *  	   0 if ok
520    *  	   -1 if an error occured
521    ********************************************************************* */
522
523static int sb1250_x1240eeprom_close(cfe_devctx_t *ctx)
524{
525    return 0;
526}
527
528
529