xref: /freebsd/sys/dev/iicbus/iiconf.c (revision ca987d4641cdcd7f27e153db17c5bf064934faf5)
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 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/lock.h>
33 #include <sys/malloc.h>
34 #include <sys/module.h>
35 #include <sys/mutex.h>
36 #include <sys/bus.h>
37 
38 #include <dev/iicbus/iiconf.h>
39 #include <dev/iicbus/iicbus.h>
40 #include "iicbus_if.h"
41 
42 /*
43  * Translate IIC_Exxxxx status values to vaguely-equivelent errno values.
44  */
45 int
46 iic2errno(int iic_status)
47 {
48 	switch (iic_status) {
49 	case IIC_NOERR:         return (0);
50 	case IIC_EBUSERR:       return (EALREADY);
51 	case IIC_ENOACK:        return (EIO);
52 	case IIC_ETIMEOUT:      return (ETIMEDOUT);
53 	case IIC_EBUSBSY:       return (EWOULDBLOCK);
54 	case IIC_ESTATUS:       return (EPROTO);
55 	case IIC_EUNDERFLOW:    return (EIO);
56 	case IIC_EOVERFLOW:     return (EOVERFLOW);
57 	case IIC_ENOTSUPP:      return (EOPNOTSUPP);
58 	case IIC_ENOADDR:       return (EADDRNOTAVAIL);
59 	case IIC_ERESOURCE:     return (ENOMEM);
60 	default:                return (EIO);
61 	}
62 }
63 
64 /*
65  * iicbus_intr()
66  */
67 void
68 iicbus_intr(device_t bus, int event, char *buf)
69 {
70 	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
71 
72 	/* call owner's intr routine */
73 	if (sc->owner)
74 		IICBUS_INTR(sc->owner, event, buf);
75 
76 	return;
77 }
78 
79 static int
80 iicbus_poll(struct iicbus_softc *sc, int how)
81 {
82 	int error;
83 
84 	IICBUS_ASSERT_LOCKED(sc);
85 	switch (how) {
86 	case IIC_WAIT | IIC_INTR:
87 		error = mtx_sleep(sc, &sc->lock, IICPRI|PCATCH, "iicreq", 0);
88 		break;
89 
90 	case IIC_WAIT | IIC_NOINTR:
91 		error = mtx_sleep(sc, &sc->lock, IICPRI, "iicreq", 0);
92 		break;
93 
94 	default:
95 		return (IIC_EBUSBSY);
96 	}
97 
98 	return (error);
99 }
100 
101 /*
102  * iicbus_request_bus()
103  *
104  * Allocate the device to perform transfers.
105  *
106  * how	: IIC_WAIT or IIC_DONTWAIT
107  */
108 int
109 iicbus_request_bus(device_t bus, device_t dev, int how)
110 {
111 	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
112 	int error = 0;
113 
114 	IICBUS_LOCK(sc);
115 
116 	while (error == 0 && sc->owner != NULL && sc->owner != dev)
117 		error = iicbus_poll(sc, how);
118 
119 	if (error == 0) {
120 		++sc->owncount;
121 		if (sc->owner == NULL) {
122 			sc->owner = dev;
123 			/*
124 			 * Drop the lock around the call to the bus driver, it
125 			 * should be allowed to sleep in the IIC_WAIT case.
126 			 * Drivers might also need to grab locks that would
127 			 * cause a LOR if our lock is held.
128 			 */
129 			IICBUS_UNLOCK(sc);
130 			/* Ask the underlying layers if the request is ok */
131 			error = IICBUS_CALLBACK(device_get_parent(bus),
132 			    IIC_REQUEST_BUS, (caddr_t)&how);
133 			IICBUS_LOCK(sc);
134 
135 			if (error != 0) {
136 				sc->owner = NULL;
137 				sc->owncount = 0;
138 				wakeup_one(sc);
139 			}
140 		}
141 	}
142 
143 	IICBUS_UNLOCK(sc);
144 
145 	return (error);
146 }
147 
148 /*
149  * iicbus_release_bus()
150  *
151  * Release the device allocated with iicbus_request_dev()
152  */
153 int
154 iicbus_release_bus(device_t bus, device_t dev)
155 {
156 	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
157 
158 	IICBUS_LOCK(sc);
159 
160 	if (sc->owner != dev) {
161 		IICBUS_UNLOCK(sc);
162 		return (IIC_EBUSBSY);
163 	}
164 
165 	if (--sc->owncount == 0) {
166 		/* Drop the lock while informing the low-level driver. */
167 		IICBUS_UNLOCK(sc);
168 		IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL);
169 		IICBUS_LOCK(sc);
170 		sc->owner = NULL;
171 		wakeup_one(sc);
172 	}
173 	IICBUS_UNLOCK(sc);
174 	return (0);
175 }
176 
177 /*
178  * iicbus_started()
179  *
180  * Test if the iicbus is started by the controller
181  */
182 int
183 iicbus_started(device_t bus)
184 {
185 	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
186 
187 	return (sc->started);
188 }
189 
190 /*
191  * iicbus_start()
192  *
193  * Send start condition to the slave addressed by 'slave'
194  */
195 int
196 iicbus_start(device_t bus, u_char slave, int timeout)
197 {
198 	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
199 	int error = 0;
200 
201 	if (sc->started)
202 		return (IIC_ESTATUS); /* protocol error, bus already started */
203 
204 	if (!(error = IICBUS_START(device_get_parent(bus), slave, timeout)))
205 		sc->started = slave;
206 	else
207 		sc->started = 0;
208 
209 	return (error);
210 }
211 
212 /*
213  * iicbus_repeated_start()
214  *
215  * Send start condition to the slave addressed by 'slave'
216  */
217 int
218 iicbus_repeated_start(device_t bus, u_char slave, int timeout)
219 {
220 	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
221 	int error = 0;
222 
223 	if (!sc->started)
224 		return (IIC_ESTATUS); /* protocol error, bus not started */
225 
226 	if (!(error = IICBUS_REPEATED_START(device_get_parent(bus), slave, timeout)))
227 		sc->started = slave;
228 	else
229 		sc->started = 0;
230 
231 	return (error);
232 }
233 
234 /*
235  * iicbus_stop()
236  *
237  * Send stop condition to the bus
238  */
239 int
240 iicbus_stop(device_t bus)
241 {
242 	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
243 	int error = 0;
244 
245 	if (!sc->started)
246 		return (IIC_ESTATUS); /* protocol error, bus not started */
247 
248 	error = IICBUS_STOP(device_get_parent(bus));
249 
250 	/* refuse any further access */
251 	sc->started = 0;
252 
253 	return (error);
254 }
255 
256 /*
257  * iicbus_write()
258  *
259  * Write a block of data to the slave previously started by
260  * iicbus_start() call
261  */
262 int
263 iicbus_write(device_t bus, const char *buf, int len, int *sent, int timeout)
264 {
265 	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
266 
267 	/* a slave must have been started for writing */
268 	if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) != 0))
269 		return (IIC_ESTATUS);
270 
271 	return (IICBUS_WRITE(device_get_parent(bus), buf, len, sent, timeout));
272 }
273 
274 /*
275  * iicbus_read()
276  *
277  * Read a block of data from the slave previously started by
278  * iicbus_read() call
279  */
280 int
281 iicbus_read(device_t bus, char *buf, int len, int *read, int last, int delay)
282 {
283 	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
284 
285 	/* a slave must have been started for reading */
286 	if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) == 0))
287 		return (IIC_ESTATUS);
288 
289 	return (IICBUS_READ(device_get_parent(bus), buf, len, read, last, delay));
290 }
291 
292 /*
293  * iicbus_write_byte()
294  *
295  * Write a byte to the slave previously started by iicbus_start() call
296  */
297 int
298 iicbus_write_byte(device_t bus, char byte, int timeout)
299 {
300 	struct iicbus_softc *sc = device_get_softc(bus);
301 	char data = byte;
302 	int sent;
303 
304 	/* a slave must have been started for writing */
305 	if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) != 0))
306 		return (IIC_ESTATUS);
307 
308 	return (iicbus_write(bus, &data, 1, &sent, timeout));
309 }
310 
311 /*
312  * iicbus_read_byte()
313  *
314  * Read a byte from the slave previously started by iicbus_start() call
315  */
316 int
317 iicbus_read_byte(device_t bus, char *byte, int timeout)
318 {
319 	struct iicbus_softc *sc = device_get_softc(bus);
320 	int read;
321 
322 	/* a slave must have been started for reading */
323 	if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) == 0))
324 		return (IIC_ESTATUS);
325 
326 	return (iicbus_read(bus, byte, 1, &read, IIC_LAST_READ, timeout));
327 }
328 
329 /*
330  * iicbus_block_write()
331  *
332  * Write a block of data to slave ; start/stop protocol managed
333  */
334 int
335 iicbus_block_write(device_t bus, u_char slave, char *buf, int len, int *sent)
336 {
337 	u_char addr = slave & ~LSB;
338 	int error;
339 
340 	if ((error = iicbus_start(bus, addr, 0)))
341 		return (error);
342 
343 	error = iicbus_write(bus, buf, len, sent, 0);
344 
345 	iicbus_stop(bus);
346 
347 	return (error);
348 }
349 
350 /*
351  * iicbus_block_read()
352  *
353  * Read a block of data from slave ; start/stop protocol managed
354  */
355 int
356 iicbus_block_read(device_t bus, u_char slave, char *buf, int len, int *read)
357 {
358 	u_char addr = slave | LSB;
359 	int error;
360 
361 	if ((error = iicbus_start(bus, addr, 0)))
362 		return (error);
363 
364 	error = iicbus_read(bus, buf, len, read, IIC_LAST_READ, 0);
365 
366 	iicbus_stop(bus);
367 
368 	return (error);
369 }
370 
371 /*
372  * iicbus_transfer()
373  *
374  * Do an aribtrary number of transfers on the iicbus.  We pass these
375  * raw requests to the bridge driver.  If the bridge driver supports
376  * them directly, then it manages all the details.  If not, it can use
377  * the helper function iicbus_transfer_gen() which will do the
378  * transfers at a low level.
379  *
380  * Pointers passed in as part of iic_msg must be kernel pointers.
381  * Callers that have user addresses to manage must do so on their own.
382  */
383 int
384 iicbus_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs)
385 {
386 
387 	return (IICBUS_TRANSFER(device_get_parent(bus), msgs, nmsgs));
388 }
389 
390 int
391 iicbus_transfer_excl(device_t dev, struct iic_msg *msgs, uint32_t nmsgs,
392     int how)
393 {
394 	device_t bus;
395 	int error;
396 
397 	bus = device_get_parent(dev);
398 	error = iicbus_request_bus(bus, dev, how);
399 	if (error == 0)
400 		error = IICBUS_TRANSFER(bus, msgs, nmsgs);
401 	iicbus_release_bus(bus, dev);
402 	return (error);
403 }
404 
405 /*
406  * Generic version of iicbus_transfer that calls the appropriate
407  * routines to accomplish this.  See note above about acceptable
408  * buffer addresses.
409  */
410 int
411 iicbus_transfer_gen(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
412 {
413 	int i, error, lenread, lenwrote, nkid, rpstart, addr;
414 	device_t *children, bus;
415 	bool nostop, started;
416 
417 	if ((error = device_get_children(dev, &children, &nkid)) != 0)
418 		return (IIC_ERESOURCE);
419 	if (nkid != 1) {
420 		free(children, M_TEMP);
421 		return (IIC_ENOTSUPP);
422 	}
423 	bus = children[0];
424 	rpstart = 0;
425 	free(children, M_TEMP);
426 	nostop = iicbus_get_nostop(dev);
427 	started = false;
428 	for (i = 0, error = 0; i < nmsgs && error == 0; i++) {
429 		addr = msgs[i].slave;
430 		if (msgs[i].flags & IIC_M_RD)
431 			addr |= LSB;
432 		else
433 			addr &= ~LSB;
434 
435 		if (!(msgs[i].flags & IIC_M_NOSTART)) {
436 			if (rpstart)
437 				error = iicbus_repeated_start(bus, addr, 0);
438 			else
439 				error = iicbus_start(bus, addr, 0);
440 			if (error != 0)
441 				break;
442 			started = true;
443 		}
444 
445 		if (msgs[i].flags & IIC_M_RD)
446 			error = iicbus_read(bus, msgs[i].buf, msgs[i].len,
447 			    &lenread, IIC_LAST_READ, 0);
448 		else
449 			error = iicbus_write(bus, msgs[i].buf, msgs[i].len,
450 			    &lenwrote, 0);
451 		if (error != 0)
452 			break;
453 
454 		if ((msgs[i].flags & IIC_M_NOSTOP) != 0 ||
455 		    (nostop && i + 1 < nmsgs)) {
456 			rpstart = 1;	/* Next message gets repeated start */
457 		} else {
458 			rpstart = 0;
459 			iicbus_stop(bus);
460 		}
461 	}
462 	if (error != 0 && started)
463 		iicbus_stop(bus);
464 	return (error);
465 }
466 
467 int
468 iicdev_readfrom(device_t slavedev, uint8_t regaddr, void *buffer,
469     uint16_t buflen, int waithow)
470 {
471 	struct iic_msg msgs[2];
472 	uint8_t slaveaddr;
473 
474 	/*
475 	 * Two transfers back to back with a repeat-start between them; first we
476 	 * write the address-within-device, then we read from the device.
477 	 */
478 	slaveaddr = iicbus_get_addr(slavedev);
479 
480 	msgs[0].slave = slaveaddr;
481 	msgs[0].flags = IIC_M_WR | IIC_M_NOSTOP;
482 	msgs[0].len   = 1;
483 	msgs[0].buf   = &regaddr;
484 
485 	msgs[1].slave = slaveaddr;
486 	msgs[1].flags = IIC_M_RD;
487 	msgs[1].len   = buflen;
488 	msgs[1].buf   = buffer;
489 
490 	return (iicbus_transfer_excl(slavedev, msgs, nitems(msgs), waithow));
491 }
492 
493 int iicdev_writeto(device_t slavedev, uint8_t regaddr, void *buffer,
494     uint16_t buflen, int waithow)
495 {
496 	struct iic_msg msgs[2];
497 	uint8_t slaveaddr;
498 
499 	/*
500 	 * Two transfers back to back with no stop or start between them; first
501 	 * we write the address then we write the data to that address, all in a
502 	 * single transfer from two scattered buffers.
503 	 */
504 	slaveaddr = iicbus_get_addr(slavedev);
505 
506 	msgs[0].slave = slaveaddr;
507 	msgs[0].flags = IIC_M_WR | IIC_M_NOSTOP;
508 	msgs[0].len   = 1;
509 	msgs[0].buf   = &regaddr;
510 
511 	msgs[1].slave = slaveaddr;
512 	msgs[1].flags = IIC_M_WR | IIC_M_NOSTART;
513 	msgs[1].len   = buflen;
514 	msgs[1].buf   = buffer;
515 
516 	return (iicbus_transfer_excl(slavedev, msgs, nitems(msgs), waithow));
517 }
518