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 * $FreeBSD: releng/5.2/sys/dev/iicbus/iicsmb.c 118728 2003-08-10 14:28:24Z ticso $
27 *
28 */
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/kernel.h>
50 #include <sys/systm.h>
51 #include <sys/module.h>
52 #include <sys/bus.h>
53 #include <sys/uio.h>
54
55
56 #include <dev/iicbus/iiconf.h>
57 #include <dev/iicbus/iicbus.h>
58
59 #include <dev/smbus/smbconf.h>
60
61 #include "iicbus_if.h"
62 #include "smbus_if.h"
63
64 struct iicsmb_softc {
65
66 #define SMB_WAITING_ADDR 0x0
67 #define SMB_WAITING_LOW 0x1
68 #define SMB_WAITING_HIGH 0x2
69 #define SMB_DONE 0x3
70 int state;
71
72 u_char devaddr; /* slave device address */
73
74 char low; /* low byte received first */
75 char high; /* high byte */
76
77 device_t smbus;
78 };
79
80 static int iicsmb_probe(device_t);
81 static int iicsmb_attach(device_t);
82 static int iicsmb_detach(device_t);
83 static void iicsmb_identify(driver_t *driver, device_t parent);
84
85 static void iicsmb_intr(device_t dev, int event, char *buf);
86 static int iicsmb_callback(device_t dev, int index, caddr_t data);
87 static int iicsmb_quick(device_t dev, u_char slave, int how);
88 static int iicsmb_sendb(device_t dev, u_char slave, char byte);
89 static int iicsmb_recvb(device_t dev, u_char slave, char *byte);
90 static int iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
91 static int iicsmb_writew(device_t dev, u_char slave, char cmd, short word);
92 static int iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
93 static int iicsmb_readw(device_t dev, u_char slave, char cmd, short *word);
94 static int iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
95 static int iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
96 static int iicsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf);
97
98 static devclass_t iicsmb_devclass;
99
100 static device_method_t iicsmb_methods[] = {
101 /* device interface */
102 DEVMETHOD(device_identify, iicsmb_identify),
103 DEVMETHOD(device_probe, iicsmb_probe),
104 DEVMETHOD(device_attach, iicsmb_attach),
105 DEVMETHOD(device_detach, iicsmb_detach),
106
107 /* bus interface */
108 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
109 DEVMETHOD(bus_print_child, bus_generic_print_child),
110
111 /* iicbus interface */
112 DEVMETHOD(iicbus_intr, iicsmb_intr),
113
114 /* smbus interface */
115 DEVMETHOD(smbus_callback, iicsmb_callback),
116 DEVMETHOD(smbus_quick, iicsmb_quick),
117 DEVMETHOD(smbus_sendb, iicsmb_sendb),
118 DEVMETHOD(smbus_recvb, iicsmb_recvb),
119 DEVMETHOD(smbus_writeb, iicsmb_writeb),
120 DEVMETHOD(smbus_writew, iicsmb_writew),
121 DEVMETHOD(smbus_readb, iicsmb_readb),
122 DEVMETHOD(smbus_readw, iicsmb_readw),
123 DEVMETHOD(smbus_pcall, iicsmb_pcall),
124 DEVMETHOD(smbus_bwrite, iicsmb_bwrite),
125 DEVMETHOD(smbus_bread, iicsmb_bread),
126
127 { 0, 0 }
128 };
129
130 static driver_t iicsmb_driver = {
131 "iicsmb",
132 iicsmb_methods,
133 sizeof(struct iicsmb_softc),
134 };
135
136 #define IICBUS_TIMEOUT 100 /* us */
137
138 static void
139 iicsmb_identify(driver_t *driver, device_t parent)
140 {
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 (0);
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 bzero(sc, sizeof(*sc));
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 if (sc->smbus) {
173 device_delete_child(dev, sc->smbus);
174 }
175
176 return (0);
177 }
178
179 /*
180 * iicsmb_intr()
181 *
182 * iicbus interrupt handler
183 */
184 static void
185 iicsmb_intr(device_t dev, int event, char *buf)
186 {
187 struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
188
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
248 return;
249 }
250
251 static int
252 iicsmb_callback(device_t dev, int index, caddr_t data)
253 {
254 device_t parent = device_get_parent(dev);
255 int error = 0;
256 int how;
257
258 switch (index) {
259 case SMB_REQUEST_BUS:
260 /* request underlying iicbus */
261 how = *(int *)data;
262 error = iicbus_request_bus(parent, dev, how);
263 break;
264
265 case SMB_RELEASE_BUS:
266 /* release underlying iicbus */
267 error = iicbus_release_bus(parent, dev);
268 break;
269
270 default:
271 error = EINVAL;
272 }
273
274 return (error);
275 }
276
277 static int
278 iicsmb_quick(device_t dev, u_char slave, int how)
279 {
280 device_t parent = device_get_parent(dev);
281 int error;
282
283 switch (how) {
284 case SMB_QWRITE:
285 error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT);
286 break;
287
288 case SMB_QREAD:
289 error = iicbus_start(parent, slave | LSB, IICBUS_TIMEOUT);
290 break;
291
292 default:
293 error = EINVAL;
294 break;
295 }
296
297 if (!error)
298 error = iicbus_stop(parent);
299
300 return (error);
301 }
302
303 static int
304 iicsmb_sendb(device_t dev, u_char slave, char byte)
305 {
306 device_t parent = device_get_parent(dev);
307 int error, sent;
308
309 error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT);
310
311 if (!error) {
312 error = iicbus_write(parent, &byte, 1, &sent, IICBUS_TIMEOUT);
313
314 iicbus_stop(parent);
315 }
316
317 return (error);
318 }
319
320 static int
321 iicsmb_recvb(device_t dev, u_char slave, char *byte)
322 {
323 device_t parent = device_get_parent(dev);
324 int error, read;
325
326 error = iicbus_start(parent, slave | LSB, 0);
327
328 if (!error) {
329 error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, IICBUS_TIMEOUT);
330
331 iicbus_stop(parent);
332 }
333
334 return (error);
335 }
336
337 static int
338 iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
339 {
340 device_t parent = device_get_parent(dev);
341 int error, sent;
342
343 error = iicbus_start(parent, slave & ~LSB, 0);
344
345 if (!error) {
346 if (!(error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
347 error = iicbus_write(parent, &byte, 1, &sent, IICBUS_TIMEOUT);
348
349 iicbus_stop(parent);
350 }
351
352 return (error);
353 }
354
355 static int
356 iicsmb_writew(device_t dev, u_char slave, char cmd, short word)
357 {
358 device_t parent = device_get_parent(dev);
359 int error, sent;
360
361 char low = (char)(word & 0xff);
362 char high = (char)((word & 0xff00) >> 8);
363
364 error = iicbus_start(parent, slave & ~LSB, 0);
365
366 if (!error) {
367 if (!(error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
368 if (!(error = iicbus_write(parent, &low, 1, &sent, IICBUS_TIMEOUT)))
369 error = iicbus_write(parent, &high, 1, &sent, IICBUS_TIMEOUT);
370
371 iicbus_stop(parent);
372 }
373
374 return (error);
375 }
376
377 static int
378 iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
379 {
380 device_t parent = device_get_parent(dev);
381 int error, sent, read;
382
383 if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
384 return (error);
385
386 if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
387 goto error;
388
389 if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
390 goto error;
391
392 if ((error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, IICBUS_TIMEOUT)))
393 goto error;
394
395 error:
396 iicbus_stop(parent);
397 return (error);
398 }
399
400 #define BUF2SHORT(low,high) \
401 ((short)(((high) & 0xff) << 8) | (short)((low) & 0xff))
402
403 static int
404 iicsmb_readw(device_t dev, u_char slave, char cmd, short *word)
405 {
406 device_t parent = device_get_parent(dev);
407 int error, sent, read;
408 char buf[2];
409
410 if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
411 return (error);
412
413 if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
414 goto error;
415
416 if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
417 goto error;
418
419 if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, IICBUS_TIMEOUT)))
420 goto error;
421
422 /* first, receive low, then high byte */
423 *word = BUF2SHORT(buf[0], buf[1]);
424
425 error:
426 iicbus_stop(parent);
427 return (error);
428 }
429
430 static int
431 iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
432 {
433 device_t parent = device_get_parent(dev);
434 int error, sent, read;
435 char buf[2];
436
437 if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
438 return (error);
439
440 if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
441 goto error;
442
443 /* first, send low, then high byte */
444 buf[0] = (char)(sdata & 0xff);
445 buf[1] = (char)((sdata & 0xff00) >> 8);
446
447 if ((error = iicbus_write(parent, buf, 2, &sent, IICBUS_TIMEOUT)))
448 goto error;
449
450 if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
451 goto error;
452
453 if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, IICBUS_TIMEOUT)))
454 goto error;
455
456 /* first, receive low, then high byte */
457 *rdata = BUF2SHORT(buf[0], buf[1]);
458
459 error:
460 iicbus_stop(parent);
461 return (error);
462 }
463
464 static int
465 iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
466 {
467 device_t parent = device_get_parent(dev);
468 int error, sent;
469
470 if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
471 goto error;
472
473 if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
474 goto error;
475
476 if ((error = iicbus_write(parent, buf, (int)count, &sent, IICBUS_TIMEOUT)))
477 goto error;
478
479 if ((error = iicbus_stop(parent)))
480 goto error;
481
482 error:
483 return (error);
484 }
485
486 static int
487 iicsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
488 {
489 device_t parent = device_get_parent(dev);
490 int error, sent, read;
491
492 if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
493 return (error);
494
495 if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
496 goto error;
497
498 if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
499 goto error;
500
501 if ((error = iicbus_read(parent, buf, (int)count, &read,
502 IIC_LAST_READ, IICBUS_TIMEOUT)))
503 goto error;
504
505 error:
506 iicbus_stop(parent);
507 return (error);
508 }
509
510 DRIVER_MODULE(iicsmb, iicbus, iicsmb_driver, iicsmb_devclass, 0, 0);
511 MODULE_DEPEND(iicsmb, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
512 MODULE_DEPEND(iicsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
513 MODULE_VERSION(iicsmb, 1);
Cache object: 88633ce34cbbfdf54d60a1b34ba661fb
|