xref: /freebsd/sys/dev/iicbus/iicsmb.c (revision f7c4bd95ba735bd6a5454b4953945a99cefbb80c)
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$
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/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 	device_t smbus;
79 };
80 
81 static int iicsmb_probe(device_t);
82 static int iicsmb_attach(device_t);
83 static int iicsmb_detach(device_t);
84 static void iicsmb_identify(driver_t *driver, device_t parent);
85 
86 static void iicsmb_intr(device_t dev, int event, char *buf);
87 static int iicsmb_callback(device_t dev, int index, void *data);
88 static int iicsmb_quick(device_t dev, u_char slave, int how);
89 static int iicsmb_sendb(device_t dev, u_char slave, char byte);
90 static int iicsmb_recvb(device_t dev, u_char slave, char *byte);
91 static int iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
92 static int iicsmb_writew(device_t dev, u_char slave, char cmd, short word);
93 static int iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
94 static int iicsmb_readw(device_t dev, u_char slave, char cmd, short *word);
95 static int iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
96 static int iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
97 static int iicsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf);
98 
99 static devclass_t iicsmb_devclass;
100 
101 static device_method_t iicsmb_methods[] = {
102 	/* device interface */
103 	DEVMETHOD(device_identify,	iicsmb_identify),
104 	DEVMETHOD(device_probe,		iicsmb_probe),
105 	DEVMETHOD(device_attach,	iicsmb_attach),
106 	DEVMETHOD(device_detach,	iicsmb_detach),
107 
108 	/* bus interface */
109 	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
110 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
111 
112 	/* iicbus interface */
113 	DEVMETHOD(iicbus_intr,		iicsmb_intr),
114 
115 	/* smbus interface */
116 	DEVMETHOD(smbus_callback,	iicsmb_callback),
117 	DEVMETHOD(smbus_quick,		iicsmb_quick),
118 	DEVMETHOD(smbus_sendb,		iicsmb_sendb),
119 	DEVMETHOD(smbus_recvb,		iicsmb_recvb),
120 	DEVMETHOD(smbus_writeb,		iicsmb_writeb),
121 	DEVMETHOD(smbus_writew,		iicsmb_writew),
122 	DEVMETHOD(smbus_readb,		iicsmb_readb),
123 	DEVMETHOD(smbus_readw,		iicsmb_readw),
124 	DEVMETHOD(smbus_pcall,		iicsmb_pcall),
125 	DEVMETHOD(smbus_bwrite,		iicsmb_bwrite),
126 	DEVMETHOD(smbus_bread,		iicsmb_bread),
127 
128 	{ 0, 0 }
129 };
130 
131 static driver_t iicsmb_driver = {
132 	"iicsmb",
133 	iicsmb_methods,
134 	sizeof(struct iicsmb_softc),
135 };
136 
137 #define IICBUS_TIMEOUT	100	/* us */
138 
139 static void
140 iicsmb_identify(driver_t *driver, device_t parent)
141 {
142 	BUS_ADD_CHILD(parent, 0, "iicsmb", -1);
143 }
144 
145 static int
146 iicsmb_probe(device_t dev)
147 {
148 	device_set_desc(dev, "SMBus over I2C bridge");
149 	return (0);
150 }
151 
152 static int
153 iicsmb_attach(device_t dev)
154 {
155 	struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
156 
157 	sc->smbus = device_add_child(dev, "smbus", -1);
158 
159 	/* probe and attach the smbus */
160 	bus_generic_attach(dev);
161 
162 	return (0);
163 }
164 
165 static int
166 iicsmb_detach(device_t dev)
167 {
168 	struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
169 
170 	bus_generic_detach(dev);
171 	if (sc->smbus) {
172 		device_delete_child(dev, sc->smbus);
173 	}
174 
175 	return (0);
176 }
177 
178 /*
179  * iicsmb_intr()
180  *
181  * iicbus interrupt handler
182  */
183 static void
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 	switch (event) {
189 	case INTR_GENERAL:
190 	case INTR_START:
191 		sc->state = SMB_WAITING_ADDR;
192 		break;
193 
194 	case INTR_STOP:
195 		/* call smbus intr handler */
196 		smbus_intr(sc->smbus, sc->devaddr,
197 				sc->low, sc->high, SMB_ENOERR);
198 		break;
199 
200 	case INTR_RECEIVE:
201 		switch (sc->state) {
202 		case SMB_DONE:
203 			/* XXX too much data, discard */
204 			printf("%s: too much data from 0x%x\n", __func__,
205 				sc->devaddr & 0xff);
206 			goto end;
207 
208 		case SMB_WAITING_ADDR:
209 			sc->devaddr = (u_char)*buf;
210 			sc->state = SMB_WAITING_LOW;
211 			break;
212 
213 		case SMB_WAITING_LOW:
214 			sc->low = *buf;
215 			sc->state = SMB_WAITING_HIGH;
216 			break;
217 
218 		case SMB_WAITING_HIGH:
219 			sc->high = *buf;
220 			sc->state = SMB_DONE;
221 			break;
222 		}
223 end:
224 		break;
225 
226 	case INTR_TRANSMIT:
227 	case INTR_NOACK:
228 		break;
229 
230 	case INTR_ERROR:
231 		switch (*buf) {
232 		case IIC_EBUSERR:
233 			smbus_intr(sc->smbus, sc->devaddr, 0, 0, SMB_EBUSERR);
234 			break;
235 
236 		default:
237 			printf("%s unknown error 0x%x!\n", __func__,
238 								(int)*buf);
239 			break;
240 		}
241 		break;
242 
243 	default:
244 		panic("%s: unknown event (%d)!", __func__, event);
245 	}
246 
247 	return;
248 }
249 
250 static int
251 iicsmb_callback(device_t dev, int index, void *data)
252 {
253 	device_t parent = device_get_parent(dev);
254 	int error = 0;
255 	int how;
256 
257 	switch (index) {
258 	case SMB_REQUEST_BUS:
259 		/* request underlying iicbus */
260 		how = *(int *)data;
261 		mtx_lock(&Giant);
262 		error = iicbus_request_bus(parent, dev, how);
263 		mtx_unlock(&Giant);
264 		break;
265 
266 	case SMB_RELEASE_BUS:
267 		/* release underlying iicbus */
268 		mtx_lock(&Giant);
269 		error = iicbus_release_bus(parent, dev);
270 		mtx_unlock(&Giant);
271 		break;
272 
273 	default:
274 		error = EINVAL;
275 	}
276 
277 	return (error);
278 }
279 
280 static int
281 iicsmb_quick(device_t dev, u_char slave, int how)
282 {
283 	device_t parent = device_get_parent(dev);
284 	int error;
285 
286 	mtx_lock(&Giant);
287 	switch (how) {
288 	case SMB_QWRITE:
289 		error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT);
290 		break;
291 
292 	case SMB_QREAD:
293 		error = iicbus_start(parent, slave | LSB, IICBUS_TIMEOUT);
294 		break;
295 
296 	default:
297 		error = EINVAL;
298 		break;
299 	}
300 
301 	if (!error)
302 		error = iicbus_stop(parent);
303 	mtx_unlock(&Giant);
304 
305 	return (error);
306 }
307 
308 static int
309 iicsmb_sendb(device_t dev, u_char slave, char byte)
310 {
311 	device_t parent = device_get_parent(dev);
312 	int error, sent;
313 
314 	mtx_lock(&Giant);
315 	error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT);
316 
317 	if (!error) {
318 		error = iicbus_write(parent, &byte, 1, &sent, IICBUS_TIMEOUT);
319 
320 		iicbus_stop(parent);
321 	}
322 	mtx_unlock(&Giant);
323 
324 	return (error);
325 }
326 
327 static int
328 iicsmb_recvb(device_t dev, u_char slave, char *byte)
329 {
330 	device_t parent = device_get_parent(dev);
331 	int error, read;
332 
333 	mtx_lock(&Giant);
334 	error = iicbus_start(parent, slave | LSB, 0);
335 
336 	if (!error) {
337 		error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, IICBUS_TIMEOUT);
338 
339 		iicbus_stop(parent);
340 	}
341 	mtx_unlock(&Giant);
342 
343 	return (error);
344 }
345 
346 static int
347 iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
348 {
349 	device_t parent = device_get_parent(dev);
350 	int error, sent;
351 
352 	mtx_lock(&Giant);
353 	error = iicbus_start(parent, slave & ~LSB, 0);
354 
355 	if (!error) {
356 		if (!(error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
357 			error = iicbus_write(parent, &byte, 1, &sent, IICBUS_TIMEOUT);
358 
359 		iicbus_stop(parent);
360 	}
361 	mtx_unlock(&Giant);
362 
363 	return (error);
364 }
365 
366 static int
367 iicsmb_writew(device_t dev, u_char slave, char cmd, short word)
368 {
369 	device_t parent = device_get_parent(dev);
370 	int error, sent;
371 
372 	char low = (char)(word & 0xff);
373 	char high = (char)((word & 0xff00) >> 8);
374 
375 	mtx_lock(&Giant);
376 	error = iicbus_start(parent, slave & ~LSB, 0);
377 
378 	if (!error) {
379 		if (!(error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
380 		  if (!(error = iicbus_write(parent, &low, 1, &sent, IICBUS_TIMEOUT)))
381 		    error = iicbus_write(parent, &high, 1, &sent, IICBUS_TIMEOUT);
382 
383 		iicbus_stop(parent);
384 	}
385 	mtx_unlock(&Giant);
386 
387 	return (error);
388 }
389 
390 static int
391 iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
392 {
393 	device_t parent = device_get_parent(dev);
394 	int error, sent, read;
395 
396 	mtx_lock(&Giant);
397 	if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT))) {
398 		mtx_unlock(&Giant);
399 		return (error);
400 	}
401 
402 	if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
403 		goto error;
404 
405 	if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
406 		goto error;
407 
408 	if ((error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, IICBUS_TIMEOUT)))
409 		goto error;
410 
411 error:
412 	iicbus_stop(parent);
413 	mtx_unlock(&Giant);
414 	return (error);
415 }
416 
417 #define BUF2SHORT(low,high) \
418 	((short)(((high) & 0xff) << 8) | (short)((low) & 0xff))
419 
420 static int
421 iicsmb_readw(device_t dev, u_char slave, char cmd, short *word)
422 {
423 	device_t parent = device_get_parent(dev);
424 	int error, sent, read;
425 	char buf[2];
426 
427 	mtx_lock(&Giant);
428 	if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT))) {
429 		mtx_unlock(&Giant);
430 		return (error);
431 	}
432 
433 	if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
434 		goto error;
435 
436 	if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
437 		goto error;
438 
439 	if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, IICBUS_TIMEOUT)))
440 		goto error;
441 
442 	/* first, receive low, then high byte */
443 	*word = BUF2SHORT(buf[0], buf[1]);
444 
445 error:
446 	iicbus_stop(parent);
447 	mtx_unlock(&Giant);
448 	return (error);
449 }
450 
451 static int
452 iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
453 {
454 	device_t parent = device_get_parent(dev);
455 	int error, sent, read;
456 	char buf[2];
457 
458 	mtx_lock(&Giant);
459 	if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT))) {
460 		mtx_unlock(&Giant);
461 		return (error);
462 	}
463 
464 	if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
465 		goto error;
466 
467 	/* first, send low, then high byte */
468 	buf[0] = (char)(sdata & 0xff);
469 	buf[1] = (char)((sdata & 0xff00) >> 8);
470 
471 	if ((error = iicbus_write(parent, buf, 2, &sent, IICBUS_TIMEOUT)))
472 		goto error;
473 
474 	if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
475 		goto error;
476 
477 	if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, IICBUS_TIMEOUT)))
478 		goto error;
479 
480 	/* first, receive low, then high byte */
481 	*rdata = BUF2SHORT(buf[0], buf[1]);
482 
483 error:
484 	iicbus_stop(parent);
485 	mtx_unlock(&Giant);
486 	return (error);
487 }
488 
489 static int
490 iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
491 {
492 	device_t parent = device_get_parent(dev);
493 	int error, sent;
494 
495 	mtx_lock(&Giant);
496 	if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT)))
497 		goto error;
498 
499 	if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
500 		goto error;
501 
502 	if ((error = iicbus_write(parent, buf, (int)count, &sent, IICBUS_TIMEOUT)))
503 		goto error;
504 
505 	if ((error = iicbus_stop(parent)))
506 		goto error;
507 
508 error:
509 	mtx_unlock(&Giant);
510 	return (error);
511 }
512 
513 static int
514 iicsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
515 {
516 	device_t parent = device_get_parent(dev);
517 	int error, sent, read;
518 
519 	mtx_lock(&Giant);
520 	if ((error = iicbus_start(parent, slave & ~LSB, IICBUS_TIMEOUT))) {
521 		mtx_unlock(&Giant);
522 		return (error);
523 	}
524 
525 	if ((error = iicbus_write(parent, &cmd, 1, &sent, IICBUS_TIMEOUT)))
526 		goto error;
527 
528 	if ((error = iicbus_repeated_start(parent, slave | LSB, IICBUS_TIMEOUT)))
529 		goto error;
530 
531 	if ((error = iicbus_read(parent, buf, (int)*count, &read,
532 						IIC_LAST_READ, IICBUS_TIMEOUT)))
533 		goto error;
534 	*count = read;
535 
536 error:
537 	iicbus_stop(parent);
538 	mtx_unlock(&Giant);
539 	return (error);
540 }
541 
542 DRIVER_MODULE(iicsmb, iicbus, iicsmb_driver, iicsmb_devclass, 0, 0);
543 DRIVER_MODULE(smbus, iicsmb, smbus_driver, smbus_devclass, 0, 0);
544 MODULE_DEPEND(iicsmb, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
545 MODULE_DEPEND(iicsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
546 MODULE_VERSION(iicsmb, 1);
547