1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  PCA9543A SMBus Switch  driver		File: dev_smbus_switch.c
5    *
6    *  This module contains a CFE driver for a PCA9543A SMBus Switch.
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    *  Constants
53    ********************************************************************* */
54
55/*
56 * Register bits
57 */
58
59#define SWITCH_CHAN0		0x01		/* Channel 0 */
60#define SWITCH_CHAN1		0x02		/* Channel 1 */
61
62/*
63 * Register numbers
64 */
65
66
67/*  *********************************************************************
68    *  Forward declarations
69    ********************************************************************* */
70
71static void switch_probe(cfe_driver_t *drv,
72			      unsigned long probe_a, unsigned long probe_b,
73			      void *probe_ptr);
74
75static int switch_open(cfe_devctx_t *ctx);
76static int switch_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
77static int switch_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
78static int switch_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
79static int switch_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
80static int switch_close(cfe_devctx_t *ctx);
81
82
83/*  *********************************************************************
84    *  Device dispatch
85    ********************************************************************* */
86
87const static cfe_devdisp_t switch_dispatch = {
88  switch_open,
89  switch_read,
90  switch_inpstat,
91  switch_write,
92  switch_ioctl,
93  switch_close,
94  NULL,
95  NULL
96};
97
98const cfe_driver_t smbus_switch = {
99  "SMBUS SWITCH",
100  "switch",
101  CFE_DEV_OTHER,
102  &switch_dispatch,
103  switch_probe
104};
105
106
107/*  *********************************************************************
108    *  Structures
109    ********************************************************************* */
110typedef struct switch_s {
111  cfe_smbus_channel_t *smbus_channel;
112} switch_t;
113
114/*  *********************************************************************
115    *  smbus_readbyte(chan,slaveaddr,devaddr)
116    *
117    *  Read a byte from the chip.
118    *
119    *  Input parameters:
120    *  	   chan - SMBus channel
121    *  	   slaveaddr -  SMBus slave address
122    *  	   devaddr - byte within the at24c02 device to read
123    *
124    *  Return value:
125    *  	   0 if ok
126    *  	   else -1
127    ********************************************************************* */
128
129static int smbus_readbyte(cfe_smbus_channel_t *chan,int slaveaddr,int devaddr)
130{
131    uint8_t buf[1];
132    int err;
133
134    /*
135     * Start the command
136     */
137
138    buf[0] = devaddr;
139    err = SMBUS_WRITE(chan,slaveaddr,buf,1);
140    if (err < 0) return err;
141
142    /*
143     * Read the data byte
144     */
145
146    err = SMBUS_READ(chan,slaveaddr,buf,1);
147    if (err < 0) return err;
148
149    return buf[0];
150}
151
152/*  *********************************************************************
153    *  smbus_writebyte(chan,slaveaddr,devaddr,b)
154    *
155    *  write a byte from the chip.
156    *
157    *  Input parameters:
158    *  	   chan - SMBus channel
159    *  	   slaveaddr -  SMBus slave address
160    *  	   devaddr - byte within the at24c02 device to read
161    *      b - byte to write
162    *
163    *  Return value:
164    *  	   0 if ok
165    *  	   else -1
166    ********************************************************************* */
167
168static int smbus_writebyte(cfe_smbus_channel_t *chan,int slaveaddr,int devaddr,int b)
169{
170    uint8_t buf[2];
171    int err;
172    int64_t timer;
173
174    /*
175     * Write the data to the controller
176     */
177
178    buf[0] = devaddr;
179    buf[1] = b;
180
181    err = SMBUS_WRITE(chan,slaveaddr,buf,2);
182
183    /*
184     * Pound on the device with a current address read
185     * to poll for the write complete
186     */
187
188    TIMER_SET(timer,50);
189    err = -1;
190
191    while (!TIMER_EXPIRED(timer)) {
192	POLL();
193
194	err = SMBUS_READ(chan,slaveaddr,buf,1);
195	if (err == 0) break;
196	}
197
198    return err;
199}
200
201/*  *********************************************************************
202    *  switch_probe(drv,a,b,ptr)
203    *
204    *  Probe routine for this driver.  This routine creates the
205    *  local device context and attaches it to the driver list
206    *  within CFE.
207    *
208    *  Input parameters:
209    *  	   drv - driver handle
210    *  	   a,b - probe hints (longs)
211    *  	   ptr - probe hint (pointer)
212    *
213    *  Return value:
214    *  	   nothing
215    ********************************************************************* */
216
217static void switch_probe(cfe_driver_t *drv,
218				     unsigned long probe_a, unsigned long probe_b,
219				     void *probe_ptr)
220{
221    switch_t *softc;
222    char descr[80];
223
224    softc = (switch_t *) KMALLOC(sizeof(switch_t),0);
225
226    /*
227     * Probe_a is the SMBus channel number
228     * Probe_b is the SMBus device address
229     * Probe_ptr is unused.
230     */
231
232    softc->smbus_channel = SMBUS_CHANNEL((int)probe_a);
233
234    xsprintf(descr,"%s on SMBus channel %d dev 0x%02X",
235	     drv->drv_description,probe_a,probe_b);
236    cfe_attach(drv,softc,NULL,descr);
237
238}
239
240/*  *********************************************************************
241    *  switch_open(ctx)
242    *
243    *  Open this device.  For the M41T81, we do a quick test
244    *  read to be sure the device is out there.
245    *
246    *  Input parameters:
247    *  	   ctx - device context (can obtain our softc here)
248    *
249    *  Return value:
250    *  	   0 if ok
251    *  	   else error code
252    ********************************************************************* */
253
254static int switch_open(cfe_devctx_t *ctx)
255{
256    switch_t *softc = ctx->dev_softc;
257    int b = -1;
258
259    b = smbus_readbyte(softc->smbus_channel,
260		       0,
261		       0);
262    b = smbus_writebyte(softc->smbus_channel,
263			0,
264			0,
265			0x01);
266
267    return (b < 0) ? -1 : 0;
268}
269
270/*  *********************************************************************
271    *  switch_read(ctx,buffer)
272    *
273    *  Read from switch.
274    *
275    *  Input parameters:
276    *  	   ctx - device context (can obtain our softc here)
277    *  	   buffer - buffer descriptor (target buffer, length, offset)
278    *
279    *  Return value:
280    *  	   number of bytes read
281    *  	   -1 if an error occured
282    ********************************************************************* */
283
284static int switch_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
285{
286    return 0;
287}
288
289/*  *********************************************************************
290    *  switch_write(ctx,buffer)
291    *
292    *  Write to switch.
293    *
294    *  Input parameters:
295    *  	   ctx - device context (can obtain our softc here)
296    *  	   buffer - buffer descriptor (target buffer, length, offset)
297    *
298    *  Return value:
299    *  	   number of bytes written
300    *  	   -1 if an error occured
301    ********************************************************************* */
302
303static int switch_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
304{
305    return 0;
306}
307
308/*  *********************************************************************
309    *  switch_inpstat(ctx,inpstat)
310    *
311    *  Test input (read) status for the device
312    *
313    *  Input parameters:
314    *  	   ctx - device context (can obtain our softc here)
315    *  	   inpstat - input status descriptor to receive value
316    *
317    *  Return value:
318    *  	   0 if ok
319    *  	   -1 if an error occured
320    ********************************************************************* */
321
322static int switch_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
323{
324    inpstat->inp_status = 1;
325
326    return 0;
327}
328
329/*  *********************************************************************
330    *  switch_ioctl(ctx,buffer)
331    *
332    *  Perform miscellaneous I/O control operations on the device.
333    *
334    *  Input parameters:
335    *  	   ctx - device context (can obtain our softc here)
336    *  	   buffer - buffer descriptor (target buffer, length, offset)
337    *
338    *  Return value:
339    *  	   number of bytes read
340    *  	   -1 if an error occured
341    ********************************************************************* */
342
343static int switch_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
344{
345  return 0;
346}
347
348/*  *********************************************************************
349    *  switch_close(ctx,buffer)
350    *
351    *  Close the device.
352    *
353    *  Input parameters:
354    *  	   ctx - device context (can obtain our softc here)
355    *
356    *  Return value:
357    *  	   0 if ok
358    *  	   -1 if an error occured
359    ********************************************************************* */
360
361static int switch_close(cfe_devctx_t *ctx)
362{
363    return 0;
364}
365
366
367
368
369
370
371
372
373