iicbb.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1998, 2001 Nicolas Souchu
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/11/sys/dev/iicbus/iicbb.c 330897 2018-03-14 03:19:51Z eadler $");
31
32/*
33 * Generic I2C bit-banging code
34 *
35 * Example:
36 *
37 *	iicbus
38 *	 /  \
39 *    iicbb pcf
40 *     |  \
41 *   bti2c lpbb
42 *
43 * From Linux I2C generic interface
44 * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
45 *
46 */
47
48#include "opt_platform.h"
49
50#include <sys/param.h>
51#include <sys/kernel.h>
52#include <sys/systm.h>
53#include <sys/module.h>
54#include <sys/bus.h>
55#include <sys/uio.h>
56
57#ifdef FDT
58#include <dev/ofw/ofw_bus.h>
59#include <dev/ofw/ofw_bus_subr.h>
60#include <dev/fdt/fdt_common.h>
61#endif
62
63#include <dev/iicbus/iiconf.h>
64#include <dev/iicbus/iicbus.h>
65
66#include <dev/smbus/smbconf.h>
67
68#include "iicbus_if.h"
69#include "iicbb_if.h"
70
71struct iicbb_softc {
72	device_t iicbus;
73	int udelay;		/* signal toggle delay in usec */
74};
75
76static int iicbb_attach(device_t);
77static void iicbb_child_detached(device_t, device_t);
78static int iicbb_detach(device_t);
79static int iicbb_print_child(device_t, device_t);
80static int iicbb_probe(device_t);
81
82static int iicbb_callback(device_t, int, caddr_t);
83static int iicbb_start(device_t, u_char, int);
84static int iicbb_stop(device_t);
85static int iicbb_write(device_t, const char *, int, int *, int);
86static int iicbb_read(device_t, char *, int, int *, int, int);
87static int iicbb_reset(device_t, u_char, u_char, u_char *);
88static int iicbb_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs);
89#ifdef FDT
90static phandle_t iicbb_get_node(device_t, device_t);
91#endif
92
93static device_method_t iicbb_methods[] = {
94	/* device interface */
95	DEVMETHOD(device_probe,		iicbb_probe),
96	DEVMETHOD(device_attach,	iicbb_attach),
97	DEVMETHOD(device_detach,	iicbb_detach),
98
99	/* bus interface */
100	DEVMETHOD(bus_child_detached,	iicbb_child_detached),
101	DEVMETHOD(bus_print_child,	iicbb_print_child),
102
103	/* iicbus interface */
104	DEVMETHOD(iicbus_callback,	iicbb_callback),
105	DEVMETHOD(iicbus_start,		iicbb_start),
106	DEVMETHOD(iicbus_repeated_start, iicbb_start),
107	DEVMETHOD(iicbus_stop,		iicbb_stop),
108	DEVMETHOD(iicbus_write,		iicbb_write),
109	DEVMETHOD(iicbus_read,		iicbb_read),
110	DEVMETHOD(iicbus_reset,		iicbb_reset),
111	DEVMETHOD(iicbus_transfer,	iicbb_transfer),
112
113#ifdef FDT
114	/* ofw_bus interface */
115	DEVMETHOD(ofw_bus_get_node,	iicbb_get_node),
116#endif
117
118	{ 0, 0 }
119};
120
121driver_t iicbb_driver = {
122	"iicbb",
123	iicbb_methods,
124	sizeof(struct iicbb_softc),
125};
126
127devclass_t iicbb_devclass;
128
129static int
130iicbb_probe(device_t dev)
131{
132	device_set_desc(dev, "I2C bit-banging driver");
133
134	return (0);
135}
136
137static int
138iicbb_attach(device_t dev)
139{
140	struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev);
141
142	sc->iicbus = device_add_child(dev, "iicbus", -1);
143	if (!sc->iicbus)
144		return (ENXIO);
145	sc->udelay = 10;		/* 10 uS default */
146	bus_generic_attach(dev);
147
148	return (0);
149}
150
151static int
152iicbb_detach(device_t dev)
153{
154
155	bus_generic_detach(dev);
156	device_delete_children(dev);
157
158	return (0);
159}
160
161#ifdef FDT
162static phandle_t
163iicbb_get_node(device_t bus, device_t dev)
164{
165
166	/* We only have one child, the I2C bus, which needs our own node. */
167	return (ofw_bus_get_node(bus));
168}
169#endif
170
171static void
172iicbb_child_detached( device_t dev, device_t child )
173{
174	struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev);
175
176	if (child == sc->iicbus)
177		sc->iicbus = NULL;
178}
179
180static int
181iicbb_print_child(device_t bus, device_t dev)
182{
183	int error;
184	int retval = 0;
185	u_char oldaddr;
186
187	retval += bus_print_child_header(bus, dev);
188	/* retrieve the interface I2C address */
189	error = IICBB_RESET(device_get_parent(bus), IIC_FASTEST, 0, &oldaddr);
190	if (error == IIC_ENOADDR) {
191		retval += printf(" on %s master-only\n",
192				 device_get_nameunit(bus));
193	} else {
194		/* restore the address */
195		IICBB_RESET(device_get_parent(bus), IIC_FASTEST, oldaddr, NULL);
196
197		retval += printf(" on %s addr 0x%x\n",
198				 device_get_nameunit(bus), oldaddr & 0xff);
199	}
200
201	return (retval);
202}
203
204#define I2C_SETSDA(sc,dev,val) do {			\
205	IICBB_SETSDA(device_get_parent(dev), val);	\
206	DELAY(sc->udelay);				\
207	} while (0)
208
209#define I2C_SETSCL(dev,val) do {			\
210	iicbb_setscl(dev, val, 100);			\
211	} while (0)
212
213#define I2C_SET(sc,dev,ctrl,data) do {			\
214	I2C_SETSCL(dev, ctrl);				\
215	I2C_SETSDA(sc, dev, data);			\
216	} while (0)
217
218#define I2C_GETSDA(dev) (IICBB_GETSDA(device_get_parent(dev)))
219
220#define I2C_GETSCL(dev) (IICBB_GETSCL(device_get_parent(dev)))
221
222static int i2c_debug = 0;
223#define I2C_DEBUG(x)	do {					\
224				if (i2c_debug) (x);		\
225			} while (0)
226
227#define I2C_LOG(format,args...)	do {				\
228					printf(format, args);	\
229				} while (0)
230
231static void
232iicbb_setscl(device_t dev, int val, int timeout)
233{
234	struct iicbb_softc *sc = device_get_softc(dev);
235	int k = 0;
236
237	IICBB_SETSCL(device_get_parent(dev), val);
238	DELAY(sc->udelay);
239
240	while (val && !I2C_GETSCL(dev) && k++ < timeout) {
241		IICBB_SETSCL(device_get_parent(dev), val);
242		DELAY(sc->udelay);
243	}
244
245	return;
246}
247
248static void
249iicbb_one(device_t dev, int timeout)
250{
251	struct iicbb_softc *sc = device_get_softc(dev);
252
253	I2C_SET(sc,dev,0,1);
254	I2C_SET(sc,dev,1,1);
255	I2C_SET(sc,dev,0,1);
256	return;
257}
258
259static void
260iicbb_zero(device_t dev, int timeout)
261{
262	struct iicbb_softc *sc = device_get_softc(dev);
263
264	I2C_SET(sc,dev,0,0);
265	I2C_SET(sc,dev,1,0);
266	I2C_SET(sc,dev,0,0);
267	return;
268}
269
270/*
271 * Waiting for ACKNOWLEDGE.
272 *
273 * When a chip is being addressed or has received data it will issue an
274 * ACKNOWLEDGE pulse. Therefore the MASTER must release the DATA line
275 * (set it to high level) and then release the CLOCK line.
276 * Now it must wait for the SLAVE to pull the DATA line low.
277 * Actually on the bus this looks like a START condition so nothing happens
278 * because of the fact that the IC's that have not been addressed are doing
279 * nothing.
280 *
281 * When the SLAVE has pulled this line low the MASTER will take the CLOCK
282 * line low and then the SLAVE will release the SDA (data) line.
283 */
284static int
285iicbb_ack(device_t dev, int timeout)
286{
287	struct iicbb_softc *sc = device_get_softc(dev);
288	int noack;
289	int k = 0;
290
291	I2C_SET(sc,dev,0,1);
292	I2C_SET(sc,dev,1,1);
293	do {
294		noack = I2C_GETSDA(dev);
295		if (!noack)
296			break;
297		DELAY(1);
298		k++;
299	} while (k < timeout);
300
301	I2C_SET(sc,dev,0,1);
302	I2C_DEBUG(printf("%c ",noack?'-':'+'));
303
304	return (noack);
305}
306
307static void
308iicbb_sendbyte(device_t dev, u_char data, int timeout)
309{
310	int i;
311
312	for (i=7; i>=0; i--) {
313		if (data&(1<<i)) {
314			iicbb_one(dev, timeout);
315		} else {
316			iicbb_zero(dev, timeout);
317		}
318	}
319	I2C_DEBUG(printf("w%02x",(int)data));
320	return;
321}
322
323static u_char
324iicbb_readbyte(device_t dev, int last, int timeout)
325{
326	struct iicbb_softc *sc = device_get_softc(dev);
327	int i;
328	unsigned char data=0;
329
330	I2C_SET(sc,dev,0,1);
331	for (i=7; i>=0; i--)
332	{
333		I2C_SET(sc,dev,1,1);
334		if (I2C_GETSDA(dev))
335			data |= (1<<i);
336		I2C_SET(sc,dev,0,1);
337	}
338	if (last) {
339		iicbb_one(dev, timeout);
340	} else {
341		iicbb_zero(dev, timeout);
342	}
343	I2C_DEBUG(printf("r%02x%c ",(int)data,last?'-':'+'));
344	return data;
345}
346
347static int
348iicbb_callback(device_t dev, int index, caddr_t data)
349{
350	return (IICBB_CALLBACK(device_get_parent(dev), index, data));
351}
352
353static int
354iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
355{
356	return (IICBB_RESET(device_get_parent(dev), speed, addr, oldaddr));
357}
358
359static int
360iicbb_start(device_t dev, u_char slave, int timeout)
361{
362	struct iicbb_softc *sc = device_get_softc(dev);
363	int error;
364
365	I2C_DEBUG(printf("<"));
366
367	I2C_SET(sc,dev,1,1);
368	I2C_SET(sc,dev,1,0);
369	I2C_SET(sc,dev,0,0);
370
371	/* send address */
372	iicbb_sendbyte(dev, slave, timeout);
373
374	/* check for ack */
375	if (iicbb_ack(dev, timeout)) {
376		error = IIC_ENOACK;
377		goto error;
378	}
379
380	return(0);
381
382error:
383	iicbb_stop(dev);
384	return (error);
385}
386
387static int
388iicbb_stop(device_t dev)
389{
390	struct iicbb_softc *sc = device_get_softc(dev);
391
392	I2C_SET(sc,dev,0,0);
393	I2C_SET(sc,dev,1,0);
394	I2C_SET(sc,dev,1,1);
395	I2C_DEBUG(printf(">"));
396	I2C_DEBUG(printf("\n"));
397	return (0);
398}
399
400static int
401iicbb_write(device_t dev, const char *buf, int len, int *sent, int timeout)
402{
403	int bytes, error = 0;
404
405	bytes = 0;
406	while (len) {
407		/* send byte */
408		iicbb_sendbyte(dev,(u_char)*buf++, timeout);
409
410		/* check for ack */
411		if (iicbb_ack(dev, timeout)) {
412			error = IIC_ENOACK;
413			goto error;
414		}
415		bytes ++;
416		len --;
417	}
418
419error:
420	*sent = bytes;
421	return (error);
422}
423
424static int
425iicbb_read(device_t dev, char * buf, int len, int *read, int last, int delay)
426{
427	int bytes;
428
429	bytes = 0;
430	while (len) {
431		/* XXX should insert delay here */
432		*buf++ = (char)iicbb_readbyte(dev, (len == 1) ? last : 0, delay);
433
434		bytes ++;
435		len --;
436	}
437
438	*read = bytes;
439	return (0);
440}
441
442static int
443iicbb_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
444{
445	int error;
446
447	error = IICBB_PRE_XFER(device_get_parent(dev));
448	if (error)
449		return (error);
450
451	error = iicbus_transfer_gen(dev, msgs, nmsgs);
452
453	IICBB_POST_XFER(device_get_parent(dev));
454	return (error);
455}
456
457DRIVER_MODULE(iicbus, iicbb, iicbus_driver, iicbus_devclass, 0, 0);
458
459MODULE_DEPEND(iicbb, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
460MODULE_VERSION(iicbb, IICBB_MODVER);
461