xref: /freebsd/sys/dev/iicbus/iic.c (revision abd87254)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 1998, 2001 Nicolas Souchu
5  * Copyright (c) 2023 Juniper Networks, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 #include <sys/param.h>
31 #include <sys/abi_compat.h>
32 #include <sys/bus.h>
33 #include <sys/conf.h>
34 #include <sys/fcntl.h>
35 #include <sys/lock.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/module.h>
39 #include <sys/sx.h>
40 #include <sys/systm.h>
41 #include <sys/uio.h>
42 #include <sys/errno.h>
43 
44 #include <dev/iicbus/iiconf.h>
45 #include <dev/iicbus/iicbus.h>
46 #include <dev/iicbus/iic.h>
47 
48 #include "iicbus_if.h"
49 
50 struct iic_softc {
51 	device_t sc_dev;
52 	struct cdev *sc_devnode;
53 };
54 
55 struct iic_cdevpriv {
56 	struct sx lock;
57 	struct iic_softc *sc;
58 	bool started;
59 	uint8_t addr;
60 };
61 
62 #ifdef COMPAT_FREEBSD32
63 struct iic_msg32 {
64 	uint16_t slave;
65 	uint16_t flags;
66 	uint16_t len;
67 	uint32_t buf;
68 };
69 
70 struct iiccmd32 {
71 	u_char slave;
72 	uint32_t count;
73 	uint32_t last;
74 	uint32_t buf;
75 };
76 
77 struct iic_rdwr_data32 {
78 	uint32_t msgs;
79 	uint32_t nmsgs;
80 };
81 
82 #define	I2CWRITE32	_IOW('i', 4, struct iiccmd32)
83 #define	I2CREAD32	_IOW('i', 5, struct iiccmd32)
84 #define	I2CRDWR32	_IOW('i', 6, struct iic_rdwr_data32)
85 #endif
86 
87 #define	IIC_LOCK(cdp)			sx_xlock(&(cdp)->lock)
88 #define	IIC_UNLOCK(cdp)			sx_xunlock(&(cdp)->lock)
89 
90 static MALLOC_DEFINE(M_IIC, "iic", "I2C device data");
91 
92 static int iic_probe(device_t);
93 static int iic_attach(device_t);
94 static int iic_detach(device_t);
95 static void iic_identify(driver_t *driver, device_t parent);
96 static void iicdtor(void *data);
97 static int iicuio_move(struct iic_cdevpriv *priv, struct uio *uio, int last);
98 static int iicuio(struct cdev *dev, struct uio *uio, int ioflag);
99 static int iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags, bool compat32);
100 
101 static device_method_t iic_methods[] = {
102 	/* device interface */
103 	DEVMETHOD(device_identify,	iic_identify),
104 	DEVMETHOD(device_probe,		iic_probe),
105 	DEVMETHOD(device_attach,	iic_attach),
106 	DEVMETHOD(device_detach,	iic_detach),
107 
108 	/* iicbus interface */
109 	DEVMETHOD(iicbus_intr,		iicbus_generic_intr),
110 
111 	{ 0, 0 }
112 };
113 
114 static driver_t iic_driver = {
115 	"iic",
116 	iic_methods,
117 	sizeof(struct iic_softc),
118 };
119 
120 static	d_open_t	iicopen;
121 static	d_ioctl_t	iicioctl;
122 
123 static struct cdevsw iic_cdevsw = {
124 	.d_version =	D_VERSION,
125 	.d_open =	iicopen,
126 	.d_read =	iicuio,
127 	.d_write =	iicuio,
128 	.d_ioctl =	iicioctl,
129 	.d_name =	"iic",
130 };
131 
132 static void
133 iic_identify(driver_t *driver, device_t parent)
134 {
135 
136 	if (device_find_child(parent, "iic", -1) == NULL)
137 		BUS_ADD_CHILD(parent, 0, "iic", -1);
138 }
139 
140 static int
141 iic_probe(device_t dev)
142 {
143 	if (iicbus_get_addr(dev) > 0)
144 		return (ENXIO);
145 
146 	device_set_desc(dev, "I2C generic I/O");
147 
148 	return (0);
149 }
150 
151 static int
152 iic_attach(device_t dev)
153 {
154 	struct iic_softc *sc;
155 
156 	sc = device_get_softc(dev);
157 	sc->sc_dev = dev;
158 	sc->sc_devnode = make_dev(&iic_cdevsw, device_get_unit(dev),
159 			UID_ROOT, GID_WHEEL,
160 			0600, "iic%d", device_get_unit(dev));
161 	if (sc->sc_devnode == NULL) {
162 		device_printf(dev, "failed to create character device\n");
163 		return (ENXIO);
164 	}
165 	sc->sc_devnode->si_drv1 = sc;
166 
167 	return (0);
168 }
169 
170 static int
171 iic_detach(device_t dev)
172 {
173 	struct iic_softc *sc;
174 
175 	sc = device_get_softc(dev);
176 
177 	if (sc->sc_devnode)
178 		destroy_dev(sc->sc_devnode);
179 
180 	return (0);
181 }
182 
183 static int
184 iicopen(struct cdev *dev, int flags, int fmt, struct thread *td)
185 {
186 	struct iic_cdevpriv *priv;
187 	int error;
188 
189 	priv = malloc(sizeof(*priv), M_IIC, M_WAITOK | M_ZERO);
190 
191 	sx_init(&priv->lock, "iic");
192 	priv->sc = dev->si_drv1;
193 
194 	error = devfs_set_cdevpriv(priv, iicdtor);
195 	if (error != 0)
196 		free(priv, M_IIC);
197 
198 	return (error);
199 }
200 
201 static void
202 iicdtor(void *data)
203 {
204 	device_t iicdev, parent;
205 	struct iic_cdevpriv *priv;
206 
207 	priv = data;
208 	KASSERT(priv != NULL, ("iic cdevpriv should not be NULL!"));
209 
210 	iicdev = priv->sc->sc_dev;
211 	parent = device_get_parent(iicdev);
212 
213 	if (priv->started) {
214 		iicbus_stop(parent);
215 		iicbus_reset(parent, IIC_UNKNOWN, 0, NULL);
216 		iicbus_release_bus(parent, iicdev);
217 	}
218 
219 	sx_destroy(&priv->lock);
220 	free(priv, M_IIC);
221 }
222 
223 static int
224 iicuio_move(struct iic_cdevpriv *priv, struct uio *uio, int last)
225 {
226 	device_t parent;
227 	int error, num_bytes, transferred_bytes, written_bytes;
228 	char buffer[128];
229 
230 	parent = device_get_parent(priv->sc->sc_dev);
231 	error = 0;
232 
233 	/*
234 	 * We can only transfer up to sizeof(buffer) bytes in 1 shot, so loop until
235 	 * everything has been transferred.
236 	*/
237 	while ((error == 0) && (uio->uio_resid > 0)) {
238 
239 		num_bytes = MIN(uio->uio_resid, sizeof(buffer));
240 		transferred_bytes = 0;
241 
242 		if (uio->uio_rw == UIO_WRITE) {
243 			error = uiomove(buffer, num_bytes, uio);
244 
245 			while ((error == 0) && (transferred_bytes < num_bytes)) {
246 				written_bytes = 0;
247 				error = iicbus_write(parent, &buffer[transferred_bytes],
248 				    num_bytes - transferred_bytes, &written_bytes, 0);
249 				transferred_bytes += written_bytes;
250 			}
251 
252 		} else if (uio->uio_rw == UIO_READ) {
253 			error = iicbus_read(parent, buffer,
254 			    num_bytes, &transferred_bytes,
255 			    ((uio->uio_resid <= sizeof(buffer)) ? last : 0), 0);
256 			if (error == 0)
257 				error = uiomove(buffer, transferred_bytes, uio);
258 		}
259 	}
260 
261 	return (error);
262 }
263 
264 static int
265 iicuio(struct cdev *dev, struct uio *uio, int ioflag)
266 {
267 	device_t parent;
268 	struct iic_cdevpriv *priv;
269 	int error;
270 	uint8_t addr;
271 
272 	priv = NULL;
273 	error = devfs_get_cdevpriv((void**)&priv);
274 
275 	if (error != 0)
276 		return (error);
277 	KASSERT(priv != NULL, ("iic cdevpriv should not be NULL!"));
278 
279 	IIC_LOCK(priv);
280 	if (priv->started || (priv->addr == 0)) {
281 		IIC_UNLOCK(priv);
282 		return (ENXIO);
283 	}
284 	parent = device_get_parent(priv->sc->sc_dev);
285 
286 	error = iicbus_request_bus(parent, priv->sc->sc_dev,
287 	    (ioflag & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR));
288 	if (error != 0) {
289 		IIC_UNLOCK(priv);
290 		return (error);
291 	}
292 
293 	if (uio->uio_rw == UIO_READ)
294 		addr = priv->addr | LSB;
295 	else
296 		addr = priv->addr & ~LSB;
297 
298 	error = iicbus_start(parent, addr, 0);
299 	if (error != 0)
300 	{
301 		iicbus_release_bus(parent, priv->sc->sc_dev);
302 		IIC_UNLOCK(priv);
303 		return (error);
304 	}
305 
306 	error = iicuio_move(priv, uio, IIC_LAST_READ);
307 
308 	iicbus_stop(parent);
309 	iicbus_release_bus(parent, priv->sc->sc_dev);
310 	IIC_UNLOCK(priv);
311 	return (error);
312 }
313 
314 #ifdef COMPAT_FREEBSD32
315 static int
316 iic_copyinmsgs32(struct iic_rdwr_data *d, struct iic_msg *buf)
317 {
318 	struct iic_msg32 msg32;
319 	struct iic_msg32 *m32;
320 	int error, i;
321 
322 	m32 = (struct iic_msg32 *)d->msgs;
323 	for (i = 0; i < d->nmsgs; i++) {
324 		error = copyin(&m32[i], &msg32, sizeof(msg32));
325 		if (error != 0)
326 			return (error);
327 		CP(msg32, buf[i], slave);
328 		CP(msg32, buf[i], flags);
329 		CP(msg32, buf[i], len);
330 		PTRIN_CP(msg32, buf[i], buf);
331 	}
332 	return (0);
333 }
334 #endif
335 
336 static int
337 iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags,
338     bool compat32 __unused)
339 {
340 #ifdef COMPAT_FREEBSD32
341 	struct iic_rdwr_data dswab;
342 	struct iic_rdwr_data32 *d32;
343 #endif
344 	struct iic_msg *buf, *m;
345 	void **usrbufs;
346 	device_t iicdev, parent;
347 	int error;
348 	uint32_t i;
349 
350 	iicdev = priv->sc->sc_dev;
351 	parent = device_get_parent(iicdev);
352 	error = 0;
353 #ifdef COMPAT_FREEBSD32
354 	if (compat32) {
355 		d32 = (struct iic_rdwr_data32 *)d;
356 		PTRIN_CP(*d32, dswab, msgs);
357 		CP(*d32, dswab, nmsgs);
358 		d = &dswab;
359 	}
360 #endif
361 
362 	if (d->nmsgs > IIC_RDRW_MAX_MSGS)
363 		return (EINVAL);
364 
365 	buf = malloc(sizeof(*d->msgs) * d->nmsgs, M_IIC, M_WAITOK);
366 
367 #ifdef COMPAT_FREEBSD32
368 	if (compat32)
369 		error = iic_copyinmsgs32(d, buf);
370 	else
371 #endif
372 	error = copyin(d->msgs, buf, sizeof(*d->msgs) * d->nmsgs);
373 	if (error != 0) {
374 		free(buf, M_IIC);
375 		return (error);
376 	}
377 
378 	/* Alloc kernel buffers for userland data, copyin write data */
379 	usrbufs = malloc(sizeof(void *) * d->nmsgs, M_IIC, M_WAITOK | M_ZERO);
380 
381 	for (i = 0; i < d->nmsgs; i++) {
382 		m = &(buf[i]);
383 		usrbufs[i] = m->buf;
384 
385 		/*
386 		 * At least init the buffer to NULL so we can safely free() it later.
387 		 * If the copyin() to buf failed, don't try to malloc bogus m->len.
388 		 */
389 		m->buf = NULL;
390 		if (error != 0)
391 			continue;
392 
393 		/* m->len is uint16_t, so allocation size is capped at 64K. */
394 		m->buf = malloc(m->len, M_IIC, M_WAITOK);
395 		if (!(m->flags & IIC_M_RD))
396 			error = copyin(usrbufs[i], m->buf, m->len);
397 	}
398 
399 	if (error == 0)
400 		error = iicbus_request_bus(parent, iicdev,
401 		    (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR));
402 
403 	if (error == 0) {
404 		error = iicbus_transfer(iicdev, buf, d->nmsgs);
405 		iicbus_release_bus(parent, iicdev);
406 	}
407 
408 	/* Copyout all read segments, free up kernel buffers */
409 	for (i = 0; i < d->nmsgs; i++) {
410 		m = &(buf[i]);
411 		if ((error == 0) && (m->flags & IIC_M_RD))
412 			error = copyout(m->buf, usrbufs[i], m->len);
413 		free(m->buf, M_IIC);
414 	}
415 
416 	free(usrbufs, M_IIC);
417 	free(buf, M_IIC);
418 	return (error);
419 }
420 
421 static int
422 iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td)
423 {
424 #ifdef COMPAT_FREEBSD32
425 	struct iiccmd iicswab;
426 #endif
427 	device_t parent, iicdev;
428 	struct iiccmd *s;
429 #ifdef COMPAT_FREEBSD32
430 	struct iiccmd32 *s32;
431 #endif
432 	struct uio ubuf;
433 	struct iovec uvec;
434 	struct iic_cdevpriv *priv;
435 	int error;
436 	bool compat32;
437 
438 	s = (struct iiccmd *)data;
439 #ifdef COMPAT_FREEBSD32
440 	s32 = (struct iiccmd32 *)data;
441 #endif
442 	error = devfs_get_cdevpriv((void**)&priv);
443 	if (error != 0)
444 		return (error);
445 
446 	KASSERT(priv != NULL, ("iic cdevpriv should not be NULL!"));
447 
448 	iicdev = priv->sc->sc_dev;
449 	parent = device_get_parent(iicdev);
450 	IIC_LOCK(priv);
451 
452 #ifdef COMPAT_FREEBSD32
453 	switch (cmd) {
454 	case I2CWRITE32:
455 	case I2CREAD32:
456 		CP(*s32, iicswab, slave);
457 		CP(*s32, iicswab, count);
458 		CP(*s32, iicswab, last);
459 		PTRIN_CP(*s32, iicswab, buf);
460 		s = &iicswab;
461 		break;
462 	default:
463 		break;
464 	}
465 #endif
466 
467 	switch (cmd) {
468 	case I2CSTART:
469 		if (priv->started) {
470 			error = EINVAL;
471 			break;
472 		}
473 		error = iicbus_request_bus(parent, iicdev,
474 		    (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR));
475 
476 		if (error == 0)
477 			error = iicbus_start(parent, s->slave, 0);
478 
479 		if (error == 0) {
480 			priv->addr = s->slave;
481 			priv->started = true;
482 		} else
483 			iicbus_release_bus(parent, iicdev);
484 
485 		break;
486 
487 	case I2CSTOP:
488 		if (priv->started) {
489 			error = iicbus_stop(parent);
490 			iicbus_release_bus(parent, iicdev);
491 			priv->started = false;
492 		}
493 
494 		break;
495 
496 	case I2CRSTCARD:
497 		/*
498 		 * Bus should be owned before we reset it.
499 		 * We allow the bus to be already owned as the result of an in-progress
500 		 * sequence; however, bus reset will always be followed by release
501 		 * (a new start is presumably needed for I/O anyway). */
502 		if (!priv->started)
503 			error = iicbus_request_bus(parent, iicdev,
504 			    (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR));
505 
506 		if (error == 0) {
507 			error = iicbus_reset(parent, IIC_UNKNOWN, 0, NULL);
508 			/*
509 			 * Ignore IIC_ENOADDR as it only means we have a master-only
510 			 * controller.
511 			 */
512 			if (error == IIC_ENOADDR)
513 				error = 0;
514 
515 			iicbus_release_bus(parent, iicdev);
516 			priv->started = false;
517 		}
518 		break;
519 
520 	case I2CWRITE:
521 #ifdef COMPAT_FREEBSD32
522 	case I2CWRITE32:
523 #endif
524 		if (!priv->started) {
525 			error = EINVAL;
526 			break;
527 		}
528 		uvec.iov_base = s->buf;
529 		uvec.iov_len = s->count;
530 		ubuf.uio_iov = &uvec;
531 		ubuf.uio_iovcnt = 1;
532 		ubuf.uio_segflg = UIO_USERSPACE;
533 		ubuf.uio_td = td;
534 		ubuf.uio_resid = s->count;
535 		ubuf.uio_offset = 0;
536 		ubuf.uio_rw = UIO_WRITE;
537 		error = iicuio_move(priv, &ubuf, 0);
538 		break;
539 
540 	case I2CREAD:
541 #ifdef COMPAT_FREEBSD32
542 	case I2CREAD32:
543 #endif
544 		if (!priv->started) {
545 			error = EINVAL;
546 			break;
547 		}
548 		uvec.iov_base = s->buf;
549 		uvec.iov_len = s->count;
550 		ubuf.uio_iov = &uvec;
551 		ubuf.uio_iovcnt = 1;
552 		ubuf.uio_segflg = UIO_USERSPACE;
553 		ubuf.uio_td = td;
554 		ubuf.uio_resid = s->count;
555 		ubuf.uio_offset = 0;
556 		ubuf.uio_rw = UIO_READ;
557 		error = iicuio_move(priv, &ubuf, s->last);
558 		break;
559 
560 #ifdef COMPAT_FREEBSD32
561 	case I2CRDWR32:
562 #endif
563 	case I2CRDWR:
564 		/*
565 		 * The rdwr list should be a self-contained set of
566 		 * transactions.  Fail if another transaction is in progress.
567                  */
568 		if (priv->started) {
569 			error = EINVAL;
570 			break;
571 		}
572 
573 #ifdef COMPAT_FREEBSD32
574 		compat32 = (cmd == I2CRDWR32);
575 #else
576 		compat32 = false;
577 #endif
578 		error = iicrdwr(priv, (struct iic_rdwr_data *)data, flags,
579 		    compat32);
580 
581 		break;
582 
583 	case I2CRPTSTART:
584 		if (!priv->started) {
585 			error = EINVAL;
586 			break;
587 		}
588 		error = iicbus_repeated_start(parent, s->slave, 0);
589 		break;
590 
591 	case I2CSADDR:
592 		priv->addr = *((uint8_t*)data);
593 		break;
594 
595 	default:
596 		error = ENOTTY;
597 	}
598 
599 	IIC_UNLOCK(priv);
600 	return (error);
601 }
602 
603 DRIVER_MODULE(iic, iicbus, iic_driver, 0, 0);
604 MODULE_DEPEND(iic, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
605 MODULE_VERSION(iic, 1);
606