xref: /freebsd/sys/dev/iicbus/iicbb.c (revision 6e8394b8baa7d5d9153ab90de6824bcd19b3b4e1)
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: iicbb.c,v 1.3 1999/01/28 15:50:24 roger Exp $
27  *
28  */
29 
30 /*
31  * Generic I2C bit-banging code
32  *
33  * Example:
34  *
35  *	iicbus
36  *	 /  \
37  *    iicbb pcf
38  *     |  \
39  *   bti2c lpbb
40  *
41  * From Linux I2C generic interface
42  * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
43  *
44  * TODO: port Peter's generic bit-banging code <dufault@hda.com>
45  */
46 
47 #include <sys/param.h>
48 #include <sys/kernel.h>
49 #include <sys/systm.h>
50 #include <sys/module.h>
51 #include <sys/bus.h>
52 #include <sys/conf.h>
53 #include <sys/buf.h>
54 #include <sys/uio.h>
55 #include <sys/malloc.h>
56 
57 #include <machine/clock.h>
58 
59 #include <dev/iicbus/iiconf.h>
60 #include <dev/iicbus/iicbus.h>
61 
62 #include <dev/smbus/smbconf.h>
63 
64 #include "iicbus_if.h"
65 #include "iicbb_if.h"
66 
67 struct iicbb_softc {
68 	int dummy;
69 };
70 
71 static int iicbb_probe(device_t);
72 static int iicbb_attach(device_t);
73 static void iicbb_print_child(device_t, device_t);
74 
75 static int iicbb_callback(device_t, int, caddr_t);
76 static int iicbb_start(device_t, u_char, int);
77 static int iicbb_stop(device_t);
78 static int iicbb_write(device_t, char *, int, int *, int);
79 static int iicbb_read(device_t, char *, int, int *, int, int);
80 static int iicbb_reset(device_t, u_char, u_char, u_char *);
81 
82 static device_method_t iicbb_methods[] = {
83 	/* device interface */
84 	DEVMETHOD(device_probe,		iicbb_probe),
85 	DEVMETHOD(device_attach,	iicbb_attach),
86 
87 	/* bus interface */
88 	DEVMETHOD(bus_print_child,	iicbb_print_child),
89 
90 	/* iicbus interface */
91 	DEVMETHOD(iicbus_callback,	iicbb_callback),
92 	DEVMETHOD(iicbus_start,		iicbb_start),
93 	DEVMETHOD(iicbus_repeated_start, iicbb_start),
94 	DEVMETHOD(iicbus_stop,		iicbb_stop),
95 	DEVMETHOD(iicbus_write,		iicbb_write),
96 	DEVMETHOD(iicbus_read,		iicbb_read),
97 	DEVMETHOD(iicbus_reset,		iicbb_reset),
98 
99 	{ 0, 0 }
100 };
101 
102 static driver_t iicbb_driver = {
103 	"iicbb",
104 	iicbb_methods,
105 	sizeof(struct iicbb_softc),
106 };
107 
108 static devclass_t iicbb_devclass;
109 
110 static int iicbb_probe(device_t dev)
111 {
112 	device_set_desc(dev, "I2C generic bit-banging driver");
113 
114 	return (0);
115 }
116 
117 static int iicbb_attach(device_t dev)
118 {
119 	return (0);
120 }
121 
122 static void
123 iicbb_print_child(device_t bus, device_t dev)
124 {
125 	int error;
126 	u_char oldaddr;
127 
128 	/* retrieve the interface I2C address */
129 	error = IICBB_RESET(device_get_parent(bus), IIC_FASTEST, 0, &oldaddr);
130 	if (error == IIC_ENOADDR) {
131 		printf(" on %s%d master-only", device_get_name(bus),
132 			device_get_unit(bus));
133 
134 	} else {
135 		/* restore the address */
136 		IICBB_RESET(device_get_parent(bus), IIC_FASTEST, oldaddr, NULL);
137 
138 		printf(" on %s%d addr 0x%x", device_get_name(bus),
139 			device_get_unit(bus), oldaddr & 0xff);
140 	}
141 
142 	return;
143 }
144 
145 #define I2C_SET(dev,ctrl,data) \
146 	IICBB_SETLINES(device_get_parent(dev), ctrl, data)
147 
148 #define I2C_GET(dev) (IICBB_GETDATALINE(device_get_parent(dev)))
149 
150 static int i2c_debug = 0;
151 #define I2C_DEBUG(x) if (i2c_debug) (x)
152 
153 static void iicbb_one(device_t dev)
154 {
155 	I2C_SET(dev,0,1);
156 	I2C_SET(dev,1,1);
157 	I2C_SET(dev,0,1);
158 	return;
159 }
160 
161 static void iicbb_zero(device_t dev)
162 {
163 	I2C_SET(dev,0,0);
164 	I2C_SET(dev,1,0);
165 	I2C_SET(dev,0,0);
166 	return;
167 }
168 
169 /*
170  * Waiting for ACKNOWLEDGE.
171  *
172  * When a chip is being addressed or has received data it will issue an
173  * ACKNOWLEDGE pulse. Therefore the MASTER must release the DATA line
174  * (set it to high level) and then release the CLOCK line.
175  * Now it must wait for the SLAVE to pull the DATA line low.
176  * Actually on the bus this looks like a START condition so nothing happens
177  * because of the fact that the IC's that have not been addressed are doing
178  * nothing.
179  *
180  * When the SLAVE has pulled this line low the MASTER will take the CLOCK
181  * line low and then the SLAVE will release the SDA (data) line.
182  */
183 static int iicbb_ack(device_t dev, int timeout)
184 {
185 	int noack;
186 	int k = timeout/10;
187 
188 	I2C_SET(dev,0,1);
189 	I2C_SET(dev,1,1);
190 
191 	do {
192 		noack = I2C_GET(dev);
193 		if (!noack)
194 			break;
195 		DELAY(10);		/* XXX wait 10us */
196 	} while (k--);
197 
198 	I2C_SET(dev,0,1);
199 	I2C_DEBUG(printf("%c ",noack?'-':'+'));
200 
201 	return (noack);
202 }
203 
204 static void iicbb_sendbyte(device_t dev, u_char data)
205 {
206 	int i;
207 
208 	I2C_SET(dev,0,0);
209 	for (i=7; i>=0; i--)
210 		(data&(1<<i)) ? iicbb_one(dev) : iicbb_zero(dev);
211 	I2C_DEBUG(printf("w%02x",(int)data));
212 	return;
213 }
214 
215 static u_char iicbb_readbyte(device_t dev, int last)
216 {
217 	int i;
218 	unsigned char data=0;
219 
220 	I2C_SET(dev,0,1);
221 	for (i=7; i>=0; i--)
222 	{
223 		I2C_SET(dev,1,1);
224 		if (I2C_GET(dev))
225 			data |= (1<<i);
226 		I2C_SET(dev,0,1);
227 	}
228 	last ? iicbb_one(dev) : iicbb_zero(dev);
229 	I2C_DEBUG(printf("r%02x%c ",(int)data,last?'-':'+'));
230 	return data;
231 }
232 
233 static int iicbb_callback(device_t dev, int index, caddr_t data)
234 {
235 	return (IICBB_CALLBACK(device_get_parent(dev), index, data));
236 }
237 
238 static int iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
239 {
240 	return (IICBB_RESET(device_get_parent(dev), speed, addr, oldaddr));
241 }
242 
243 static int iicbb_start(device_t dev, u_char slave, int timeout)
244 {
245 	int error;
246 
247 	I2C_DEBUG(printf("<"));
248 
249 	I2C_SET(dev,0,1);
250 	I2C_SET(dev,1,1);
251 	I2C_SET(dev,1,0);
252 	I2C_SET(dev,0,0);
253 
254 	/* send address */
255 	iicbb_sendbyte(dev, slave);
256 
257 	/* check for ack */
258 	if (iicbb_ack(dev, timeout)) {
259 		error = IIC_ENOACK;
260 		goto error;
261 	}
262 
263 	return(0);
264 
265 error:
266 	iicbb_stop(dev);
267 	return (error);
268 }
269 
270 static int iicbb_stop(device_t dev)
271 {
272 	I2C_SET(dev,0,0);
273 	I2C_SET(dev,1,0);
274 	I2C_SET(dev,1,1);
275 	I2C_DEBUG(printf(">"));
276 	return (0);
277 }
278 
279 static int iicbb_write(device_t dev, char * buf, int len, int *sent,
280 			int timeout)
281 {
282 	int bytes, error = 0;
283 
284 	bytes = 0;
285 	while (len) {
286 		/* send byte */
287 		iicbb_sendbyte(dev,(u_char)*buf++);
288 
289 		/* check for ack */
290 		if (iicbb_ack(dev, timeout)) {
291 			error = IIC_ENOACK;
292 			goto error;
293 		}
294 		bytes ++;
295 		len --;
296 	}
297 
298 error:
299 	*sent = bytes;
300 	return (error);
301 }
302 
303 static int iicbb_read(device_t dev, char * buf, int len, int *read,
304 			int last, int delay)
305 {
306 	int bytes;
307 
308 	bytes = 0;
309 	while (len) {
310 		/* XXX should insert delay here */
311 		*buf++ = (char)iicbb_readbyte(dev, (len == 1) ? last : 0);
312 
313 		bytes ++;
314 		len --;
315 	}
316 
317 	*read = bytes;
318 	return (0);
319 }
320 
321 DRIVER_MODULE(iicbb, bti2c, iicbb_driver, iicbb_devclass, 0, 0);
322 DRIVER_MODULE(iicbb, lpbb, iicbb_driver, iicbb_devclass, 0, 0);
323