]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - sys/dev/iicbus/iicsmb.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.git] / sys / dev / iicbus / iicsmb.c
1 /*-
2  * Copyright (c) 1998, 2001 Nicolas Souchu
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 /*
31  * I2C to SMB bridge
32  *
33  * Example:
34  *
35  *     smb bttv
36  *       \ /
37  *      smbus
38  *       /  \
39  *    iicsmb bti2c
40  *       |
41  *     iicbus
42  *     /  |  \
43  *  iicbb pcf ...
44  *    |
45  *  lpbb
46  */
47
48 #include <sys/param.h>
49 #include <sys/bus.h>
50 #include <sys/kernel.h>
51 #include <sys/lock.h>
52 #include <sys/module.h>
53 #include <sys/mutex.h>
54 #include <sys/systm.h>
55 #include <sys/uio.h>
56
57 #include <dev/iicbus/iiconf.h>
58 #include <dev/iicbus/iicbus.h>
59
60 #include <dev/smbus/smbconf.h>
61
62 #include "iicbus_if.h"
63 #include "smbus_if.h"
64
65 struct iicsmb_softc {
66
67 #define SMB_WAITING_ADDR        0x0
68 #define SMB_WAITING_LOW         0x1
69 #define SMB_WAITING_HIGH        0x2
70 #define SMB_DONE                0x3
71         int state;
72
73         u_char devaddr;                 /* slave device address */
74
75         char low;                       /* low byte received first */
76         char high;                      /* high byte */
77
78         struct mtx lock;
79         device_t smbus;
80 };
81
82 static int iicsmb_probe(device_t);
83 static int iicsmb_attach(device_t);
84 static int iicsmb_detach(device_t);
85 static void iicsmb_identify(driver_t *driver, device_t parent);
86
87 static int iicsmb_intr(device_t dev, int event, char *buf);
88 static int iicsmb_callback(device_t dev, int index, void *data);
89 static int iicsmb_quick(device_t dev, u_char slave, int how);
90 static int iicsmb_sendb(device_t dev, u_char slave, char byte);
91 static int iicsmb_recvb(device_t dev, u_char slave, char *byte);
92 static int iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
93 static int iicsmb_writew(device_t dev, u_char slave, char cmd, short word);
94 static int iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
95 static int iicsmb_readw(device_t dev, u_char slave, char cmd, short *word);
96 static int iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
97 static int iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
98 static int iicsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf);
99
100 static devclass_t iicsmb_devclass;
101
102 static device_method_t iicsmb_methods[] = {
103         /* device interface */
104         DEVMETHOD(device_identify,      iicsmb_identify),
105         DEVMETHOD(device_probe,         iicsmb_probe),
106         DEVMETHOD(device_attach,        iicsmb_attach),
107         DEVMETHOD(device_detach,        iicsmb_detach),
108
109         /* iicbus interface */
110         DEVMETHOD(iicbus_intr,          iicsmb_intr),
111
112         /* smbus interface */
113         DEVMETHOD(smbus_callback,       iicsmb_callback),
114         DEVMETHOD(smbus_quick,          iicsmb_quick),
115         DEVMETHOD(smbus_sendb,          iicsmb_sendb),
116         DEVMETHOD(smbus_recvb,          iicsmb_recvb),
117         DEVMETHOD(smbus_writeb,         iicsmb_writeb),
118         DEVMETHOD(smbus_writew,         iicsmb_writew),
119         DEVMETHOD(smbus_readb,          iicsmb_readb),
120         DEVMETHOD(smbus_readw,          iicsmb_readw),
121         DEVMETHOD(smbus_pcall,          iicsmb_pcall),
122         DEVMETHOD(smbus_bwrite,         iicsmb_bwrite),
123         DEVMETHOD(smbus_bread,          iicsmb_bread),
124
125         DEVMETHOD_END
126 };
127
128 static driver_t iicsmb_driver = {
129         "iicsmb",
130         iicsmb_methods,
131         sizeof(struct iicsmb_softc),
132 };
133
134 #define IICBUS_TIMEOUT  100     /* us */
135
136 static void
137 iicsmb_identify(driver_t *driver, device_t parent)
138 {
139
140         if (device_find_child(parent, "iicsmb", -1) == NULL)
141                 BUS_ADD_CHILD(parent, 0, "iicsmb", -1);
142 }
143
144 static int
145 iicsmb_probe(device_t dev)
146 {
147         device_set_desc(dev, "SMBus over I2C bridge");
148         return (BUS_PROBE_NOWILDCARD);
149 }
150
151 static int
152 iicsmb_attach(device_t dev)
153 {
154         struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
155
156         mtx_init(&sc->lock, "iicsmb", NULL, MTX_DEF);
157
158         sc->smbus = device_add_child(dev, "smbus", -1);
159
160         /* probe and attach the smbus */
161         bus_generic_attach(dev);
162
163         return (0);
164 }
165
166 static int
167 iicsmb_detach(device_t dev)
168 {
169         struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
170
171         bus_generic_detach(dev);
172         device_delete_children(dev);
173         mtx_destroy(&sc->lock);
174
175         return (0);
176 }
177
178 /*
179  * iicsmb_intr()
180  *
181  * iicbus interrupt handler
182  */
183 static int
184 iicsmb_intr(device_t dev, int event, char *buf)
185 {
186         struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
187
188         mtx_lock(&sc->lock);
189         switch (event) {
190         case INTR_GENERAL:
191         case INTR_START:
192                 sc->state = SMB_WAITING_ADDR;
193                 break;
194
195         case INTR_STOP:
196                 /* call smbus intr handler */
197                 smbus_intr(sc->smbus, sc->devaddr,
198                                 sc->low, sc->high, SMB_ENOERR);
199                 break;
200
201         case INTR_RECEIVE:
202                 switch (sc->state) {
203                 case SMB_DONE:
204                         /* XXX too much data, discard */
205                         printf("%s: too much data from 0x%x\n", __func__,
206                                 sc->devaddr & 0xff);
207                         goto end;
208
209                 case SMB_WAITING_ADDR:
210                         sc->devaddr = (u_char)*buf;
211                         sc->state = SMB_WAITING_LOW;
212                         break;
213
214                 case SMB_WAITING_LOW:
215                         sc->low = *buf;
216                         sc->state = SMB_WAITING_HIGH;
217                         break;
218
219                 case SMB_WAITING_HIGH:
220                         sc->high = *buf;
221                         sc->state = SMB_DONE;
222                         break;
223                 }
224 end:
225                 break;
226
227         case INTR_TRANSMIT:
228         case INTR_NOACK:
229                 break;
230
231         case INTR_ERROR:
232                 switch (*buf) {
233                 case IIC_EBUSERR:
234                         smbus_intr(sc->smbus, sc->devaddr, 0, 0, SMB_EBUSERR);
235                         break;
236
237                 default:
238                         printf("%s unknown error 0x%x!\n", __func__,
239                                                                 (int)*buf);
240                         break;
241                 }
242                 break;
243
244         default:
245                 panic("%s: unknown event (%d)!", __func__, event);
246         }
247         mtx_unlock(&sc->lock);
248
249         return (0);
250 }
251
252 static int
253 iicsmb_callback(device_t dev, int index, void *data)
254 {
255         device_t parent = device_get_parent(dev);
256         int error = 0;
257         int how;
258
259         switch (index) {
260         case SMB_REQUEST_BUS:
261                 /* request underlying iicbus */
262                 how = *(int *)data;
263                 error = iicbus_request_bus(parent, dev, how);
264                 break;
265
266         case SMB_RELEASE_BUS:
267                 /* release underlying iicbus */
268                 error = iicbus_release_bus(parent, dev);
269                 break;
270
271         default:
272                 error = EINVAL;
273         }
274
275         return (error);
276 }
277
278 static int
279 iicsmb_quick(device_t dev, u_char slave, int how)
280 {
281         device_t parent = device_get_parent(dev);
282         int error;
283
284         switch (how) {
285         case SMB_QWRITE:
286                 error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT);
287                 break;
288
289         case SMB_QREAD:
290                 error = iicbus_start(parent, slave | LSB, IICBUS_TIMEOUT);
291                 break;
292
293         default:
294                 error = EINVAL;
295                 break;
296         }
297
298         if (!error)
299                 error = iicbus_stop(parent);
300                 
301         return (error);
302 }
303
304 static int
305 iicsmb_sendb(device_t dev, u_char slave, char byte)
306 {
307         device_t parent = device_get_parent(dev);
308         int error, sent;
309
310         error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT);
311
312         if (!error) {
313                 error = iicbus_write(parent, &byte, 1, &sent, IICBUS_TIMEOUT);
314
315                 iicbus_stop(parent);
316         }
317
318         return (error);
319 }
320
321 static int
322 iicsmb_recvb(device_t dev, u_char slave, char *byte)
323 {
324         device_t parent = device_get_parent(dev);
325         int error, read;
326
327         error = iicbus_start(parent, slave | LSB, 0);
328
329         if (!error) {
330                 error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, IICBUS_TIMEOUT);
331
332                 iicbus_stop(parent);
333         }
334
335         return (error);
336 }
337
338 static int
339 iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
340 {
341         device_t parent = device_get_parent(dev);
342         int error, sent;
343
344         error = iicbus_start(parent, slave & ~LSB, 0);
345
346         if (!error) {
347                 if (!(error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
348                         error = iicbus_write(parent, &byte, 1, &sent, IICBUS_TIMEOUT);
349
350                 iicbus_stop(parent);
351         }
352
353         return (error);
354 }
355
356 static int
357 iicsmb_writew(device_t dev, u_char slave, char cmd, short word)
358 {
359         device_t parent = device_get_parent(dev);
360         int error, sent;
361
362         char low = (char)(word & 0xff);
363         char high = (char)((word & 0xff00) >> 8);
364
365         error = iicbus_start(parent, slave & ~LSB, 0);
366
367         if (!error) {
368                 if (!(error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
369                   if (!(error = iicbus_write(parent, &low, 1, &sent, IICBUS_TIMEOUT)))
370                     error = iicbus_write(parent, &high, 1, &sent, IICBUS_TIMEOUT);
371
372                 iicbus_stop(parent);
373         }
374
375         return (error);
376 }
377
378 static int
379 iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
380 {
381         device_t parent = device_get_parent(dev);
382         int error, sent, read;
383
384         if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
385                 return (error);
386
387         if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
388                 goto error;
389
390         if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
391                 goto error;
392
393         if ((error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, IICBUS_TIMEOUT)))
394                 goto error;
395
396 error:
397         iicbus_stop(parent);
398         return (error);
399 }
400
401 #define BUF2SHORT(low,high) \
402         ((short)(((high) & 0xff) << 8) | (short)((low) & 0xff))
403
404 static int
405 iicsmb_readw(device_t dev, u_char slave, char cmd, short *word)
406 {
407         device_t parent = device_get_parent(dev);
408         int error, sent, read;
409         char buf[2];
410
411         if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
412                 return (error);
413
414         if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
415                 goto error;
416
417         if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
418                 goto error;
419
420         if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, IICBUS_TIMEOUT)))
421                 goto error;
422
423         /* first, receive low, then high byte */
424         *word = BUF2SHORT(buf[0], buf[1]);
425
426 error:
427         iicbus_stop(parent);
428         return (error);
429 }
430
431 static int
432 iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
433 {
434         device_t parent = device_get_parent(dev);
435         int error, sent, read;
436         char buf[2];
437
438         if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
439                 return (error);
440
441         if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
442                 goto error;
443
444         /* first, send low, then high byte */
445         buf[0] = (char)(sdata & 0xff);
446         buf[1] = (char)((sdata & 0xff00) >> 8);
447
448         if ((error = iicbus_write(parent, buf, 2, &sent, IICBUS_TIMEOUT)))
449                 goto error;
450
451         if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
452                 goto error;
453
454         if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, IICBUS_TIMEOUT)))
455                 goto error;
456
457         /* first, receive low, then high byte */
458         *rdata = BUF2SHORT(buf[0], buf[1]);
459
460 error:
461         iicbus_stop(parent);
462         return (error);
463 }
464
465 static int
466 iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
467 {
468         device_t parent = device_get_parent(dev);
469         int error, sent;
470
471         if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
472                 goto error;
473
474         if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
475                 goto error;
476
477         if ((error = iicbus_write(parent, buf, (int)count, &sent, IICBUS_TIMEOUT)))
478                 goto error;
479
480         if ((error = iicbus_stop(parent)))
481                 goto error;
482
483 error:
484         return (error);
485 }
486
487 static int
488 iicsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
489 {
490         device_t parent = device_get_parent(dev);
491         int error, sent, read;
492
493         if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
494                 return (error);
495
496         if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
497                 goto error;
498
499         if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
500                 goto error;
501
502         if ((error = iicbus_read(parent, buf, (int)*count, &read,
503                                                 IIC_LAST_READ, IICBUS_TIMEOUT)))
504                 goto error;
505         *count = read;
506
507 error:
508         iicbus_stop(parent);
509         return (error);
510 }
511
512 DRIVER_MODULE(iicsmb, iicbus, iicsmb_driver, iicsmb_devclass, 0, 0);
513 DRIVER_MODULE(smbus, iicsmb, smbus_driver, smbus_devclass, 0, 0);
514 MODULE_DEPEND(iicsmb, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
515 MODULE_DEPEND(iicsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
516 MODULE_VERSION(iicsmb, 1);