xref: /freebsd/sys/dev/iicbus/iicsmb.c (revision 0640d357f29fb1c0daaaffadd0416c5981413afd)
1 /*-
2  * Copyright (c) 1998 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  *	$Id: iicsmb.c,v 1.1.1.1 1998/09/03 20:51:50 nsouch Exp $
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/conf.h>
54 #include <sys/buf.h>
55 #include <sys/uio.h>
56 #include <sys/malloc.h>
57 
58 #include <machine/clock.h>
59 
60 #include <dev/iicbus/iiconf.h>
61 #include <dev/iicbus/iicbus.h>
62 
63 #include <dev/smbus/smbconf.h>
64 
65 #include "iicbus_if.h"
66 #include "smbus_if.h"
67 
68 struct iicsmb_softc {
69 
70 #define SMB_WAITING_ADDR	0x0
71 #define SMB_WAITING_LOW		0x1
72 #define SMB_WAITING_HIGH	0x2
73 #define SMB_DONE		0x3
74 	int state;
75 
76 	u_char devaddr;			/* slave device address */
77 
78 	char low;			/* low byte received first */
79 	char high;			/* high byte */
80 
81 	device_t smbus;
82 };
83 
84 static int iicsmb_probe(device_t);
85 static int iicsmb_attach(device_t);
86 static void iicsmb_print_child(device_t, device_t);
87 
88 static void iicsmb_intr(device_t dev, int event, char *buf);
89 static int iicsmb_callback(device_t dev, int index, caddr_t data);
90 static int iicsmb_quick(device_t dev, u_char slave, int how);
91 static int iicsmb_sendb(device_t dev, u_char slave, char byte);
92 static int iicsmb_recvb(device_t dev, u_char slave, char *byte);
93 static int iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
94 static int iicsmb_writew(device_t dev, u_char slave, char cmd, short word);
95 static int iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
96 static int iicsmb_readw(device_t dev, u_char slave, char cmd, short *word);
97 static int iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
98 static int iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
99 static int iicsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf);
100 
101 static devclass_t iicsmb_devclass;
102 
103 static device_method_t iicsmb_methods[] = {
104 	/* device interface */
105 	DEVMETHOD(device_probe,		iicsmb_probe),
106 	DEVMETHOD(device_attach,	iicsmb_attach),
107 
108 	/* bus interface */
109 	DEVMETHOD(bus_print_child,	iicsmb_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 	DRIVER_TYPE_MISC,
134 	sizeof(struct iicsmb_softc),
135 };
136 
137 static int
138 iicsmb_probe(device_t dev)
139 {
140 	struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
141 
142 	sc->smbus = smbus_alloc_bus(dev);
143 
144 	if (!sc->smbus)
145 		return (EINVAL);	/* XXX don't know what to return else */
146 
147 	return (0);
148 }
149 
150 static int
151 iicsmb_attach(device_t dev)
152 {
153 	struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
154 
155 	/* probe and attach the smbus */
156 	device_probe_and_attach(sc->smbus);
157 
158 	return (0);
159 }
160 
161 static void
162 iicsmb_print_child(device_t bus, device_t dev)
163 {
164 	printf(" on %s%d", device_get_name(bus), device_get_unit(bus));
165 
166 	return;
167 }
168 
169 /*
170  * iicsmb_intr()
171  *
172  * iicbus interrupt handler
173  */
174 static void
175 iicsmb_intr(device_t dev, int event, char *buf)
176 {
177 	struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
178 
179 	switch (event) {
180 	case INTR_GENERAL:
181 	case INTR_START:
182 		sc->state = SMB_WAITING_ADDR;
183 		break;
184 
185 	case INTR_STOP:
186 		/* call smbus intr handler */
187 		smbus_intr(sc->smbus, sc->devaddr,
188 				sc->low, sc->high, SMB_ENOERR);
189 		break;
190 
191 	case INTR_RECEIVE:
192 		switch (sc->state) {
193 		case SMB_DONE:
194 			/* XXX too much data, discard */
195 			printf("%s: too much data from 0x%x\n", __FUNCTION__,
196 				sc->devaddr & 0xff);
197 			goto end;
198 
199 		case SMB_WAITING_ADDR:
200 			sc->devaddr = (u_char)*buf;
201 			sc->state = SMB_WAITING_LOW;
202 			break;
203 
204 		case SMB_WAITING_LOW:
205 			sc->low = *buf;
206 			sc->state = SMB_WAITING_HIGH;
207 			break;
208 
209 		case SMB_WAITING_HIGH:
210 			sc->high = *buf;
211 			sc->state = SMB_DONE;
212 			break;
213 		}
214 end:
215 		break;
216 
217 	case INTR_TRANSMIT:
218 	case INTR_NOACK:
219 		break;
220 
221 	case INTR_ERROR:
222 		switch (*buf) {
223 		case IIC_EBUSERR:
224 			smbus_intr(sc->smbus, sc->devaddr, 0, 0, SMB_EBUSERR);
225 			break;
226 
227 		default:
228 			printf("%s unknown error 0x%x!\n", __FUNCTION__,
229 								(int)*buf);
230 			break;
231 		}
232 		break;
233 
234 	default:
235 		panic("%s: unknown event (%d)!", __FUNCTION__, event);
236 	}
237 
238 	return;
239 }
240 
241 static int
242 iicsmb_callback(device_t dev, int index, caddr_t data)
243 {
244 	device_t parent = device_get_parent(dev);
245 	int error = 0;
246 	int how;
247 
248 	switch (index) {
249 	case SMB_REQUEST_BUS:
250 		/* request underlying iicbus */
251 		how = *(int *)data;
252 		error = iicbus_request_bus(parent, dev, how);
253 		break;
254 
255 	case SMB_RELEASE_BUS:
256 		/* release underlying iicbus */
257 		error = iicbus_release_bus(parent, dev);
258 		break;
259 
260 	default:
261 		error = EINVAL;
262 	}
263 
264 	return (error);
265 }
266 
267 static int
268 iicsmb_quick(device_t dev, u_char slave, int how)
269 {
270 	device_t parent = device_get_parent(dev);
271 	int error;
272 
273 	switch (how) {
274 	case SMB_QWRITE:
275 		error = iicbus_start(parent, slave & ~LSB, 0);
276 		break;
277 
278 	case SMB_QREAD:
279 		error = iicbus_start(parent, slave | LSB, 0);
280 		break;
281 
282 	default:
283 		error = EINVAL;
284 		break;
285 	}
286 
287 	if (!error)
288 		error = iicbus_stop(parent);
289 
290 	return (error);
291 }
292 
293 static int
294 iicsmb_sendb(device_t dev, u_char slave, char byte)
295 {
296 	device_t parent = device_get_parent(dev);
297 	int error, sent;
298 
299 	error = iicbus_start(parent, slave & ~LSB, 0);
300 
301 	if (!error) {
302 		error = iicbus_write(parent, &byte, 1, &sent, 0);
303 
304 		iicbus_stop(parent);
305 	}
306 
307 	return (error);
308 }
309 
310 static int
311 iicsmb_recvb(device_t dev, u_char slave, char *byte)
312 {
313 	device_t parent = device_get_parent(dev);
314 	int error, read;
315 
316 	error = iicbus_start(parent, slave | LSB, 0);
317 
318 	if (!error) {
319 		error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, 0);
320 
321 		iicbus_stop(parent);
322 	}
323 
324 	return (error);
325 }
326 
327 static int
328 iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
329 {
330 	device_t parent = device_get_parent(dev);
331 	int error, sent;
332 
333 	error = iicbus_start(parent, slave & ~LSB, 0);
334 
335 	if (!error) {
336 		if (!(error = iicbus_write(parent, &cmd, 1, &sent, 0)))
337 			error = iicbus_write(parent, &byte, 1, &sent, 0);
338 
339 		iicbus_stop(parent);
340 	}
341 
342 	return (error);
343 }
344 
345 static int
346 iicsmb_writew(device_t dev, u_char slave, char cmd, short word)
347 {
348 	device_t parent = device_get_parent(dev);
349 	int error, sent;
350 
351 	char low = (char)(word & 0xff);
352 	char high = (char)((word & 0xff00) >> 8);
353 
354 	error = iicbus_start(parent, slave & ~LSB, 0);
355 
356 	if (!error) {
357 		if (!(error = iicbus_write(parent, &cmd, 1, &sent, 0)))
358 		  if (!(error = iicbus_write(parent, &low, 1, &sent, 0)))
359 		    error = iicbus_write(parent, &high, 1, &sent, 0);
360 
361 		iicbus_stop(parent);
362 	}
363 
364 	return (error);
365 }
366 
367 static int
368 iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
369 {
370 	device_t parent = device_get_parent(dev);
371 	int error, sent, read;
372 
373 	if ((error = iicbus_start(parent, slave & ~LSB, 0)))
374 		return (error);
375 
376 	if ((error = iicbus_write(parent, &cmd, 1, &sent, 0)))
377 		goto error;
378 
379 	if ((error = iicbus_repeated_start(parent, slave | LSB, 0)))
380 		goto error;
381 
382 	if ((error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, 0)))
383 		goto error;
384 
385 error:
386 	iicbus_stop(parent);
387 	return (error);
388 }
389 
390 #define BUF2SHORT(low,high) \
391 	((short)(((high) & 0xff) << 8) | (short)((low) & 0xff))
392 
393 static int
394 iicsmb_readw(device_t dev, u_char slave, char cmd, short *word)
395 {
396 	device_t parent = device_get_parent(dev);
397 	int error, sent, read;
398 	char buf[2];
399 
400 	if ((error = iicbus_start(parent, slave & ~LSB, 0)))
401 		return (error);
402 
403 	if ((error = iicbus_write(parent, &cmd, 1, &sent, 0)))
404 		goto error;
405 
406 	if ((error = iicbus_repeated_start(parent, slave | LSB, 0)))
407 		goto error;
408 
409 	if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, 0)))
410 		goto error;
411 
412 	/* first, receive low, then high byte */
413 	*word = BUF2SHORT(buf[0], buf[1]);
414 
415 error:
416 	iicbus_stop(parent);
417 	return (error);
418 }
419 
420 static int
421 iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
422 {
423 	device_t parent = device_get_parent(dev);
424 	int error, sent, read;
425 	char buf[2];
426 
427 	if ((error = iicbus_start(parent, slave & ~LSB, 0)))
428 		return (error);
429 
430 	if ((error = iicbus_write(parent, &cmd, 1, &sent, 0)))
431 		goto error;
432 
433 	/* first, send low, then high byte */
434 	buf[0] = (char)(sdata & 0xff);
435 	buf[1] = (char)((sdata & 0xff00) >> 8);
436 
437 	if ((error = iicbus_write(parent, buf, 2, &sent, 0)))
438 		goto error;
439 
440 	if ((error = iicbus_repeated_start(parent, slave | LSB, 0)))
441 		goto error;
442 
443 	if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, 0)))
444 		goto error;
445 
446 	/* first, receive low, then high byte */
447 	*rdata = BUF2SHORT(buf[0], buf[1]);
448 
449 error:
450 	iicbus_stop(parent);
451 	return (error);
452 }
453 
454 static int
455 iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
456 {
457 	device_t parent = device_get_parent(dev);
458 	int error, sent;
459 
460 	if ((error = iicbus_start(parent, slave & ~LSB, 0)))
461 		goto error;
462 
463 	if ((error = iicbus_write(parent, &cmd, 1, &sent, 0)))
464 		goto error;
465 
466 	if ((error = iicbus_write(parent, buf, (int)count, &sent, 0)))
467 		goto error;
468 
469 	if ((error = iicbus_stop(parent)))
470 		goto error;
471 
472 error:
473 	return (error);
474 }
475 
476 static int
477 iicsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
478 {
479 	device_t parent = device_get_parent(dev);
480 	int error, sent, read;
481 
482 	if ((error = iicbus_start(parent, slave & ~LSB, 0)))
483 		return (error);
484 
485 	if ((error = iicbus_write(parent, &cmd, 1, &sent, 0)))
486 		goto error;
487 
488 	if ((error = iicbus_repeated_start(parent, slave | LSB, 0)))
489 		goto error;
490 
491 	if ((error = iicbus_read(parent, buf, (int)count, &read,
492 							IIC_LAST_READ, 0)))
493 		goto error;
494 
495 error:
496 	iicbus_stop(parent);
497 	return (error);
498 }
499 
500 DRIVER_MODULE(iicsmb, iicbus, iicsmb_driver, iicsmb_devclass, 0, 0);
501