xref: /dragonfly/sys/dev/misc/gpio/gpio.c (revision a4c31683)
1 /*
2  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Alex Hornung <ahornung@gmail.com>
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  *
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
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *
35  * Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org>
36  * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org>
37  *
38  * Permission to use, copy, modify, and distribute this software for any
39  * purpose with or without fee is hereby granted, provided that the above
40  * copyright notice and this permission notice appear in all copies.
41  *
42  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
43  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
44  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
45  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
46  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
47  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
48  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
49  */
50 /*
51  * XXX: consumer_detach stuff.
52  * XXX: userland stuff.
53  */
54 
55 #include <sys/param.h>
56 #include <sys/conf.h>
57 #include <sys/kernel.h>
58 #include <sys/systm.h>
59 #include <sys/limits.h>
60 #include <sys/thread.h>
61 #include <sys/thread2.h>
62 #include <sys/malloc.h>
63 #include <sys/ctype.h>
64 #include <sys/sbuf.h>
65 #include <sys/queue.h>
66 #include <sys/uio.h>
67 #include <sys/lock.h>
68 #include <dev/misc/gpio/gpio.h>
69 #include <sys/devfs.h>
70 
71 struct gpio_driver {
72 	char	*name;
73 	struct devfs_bitmap	unit_bitmap;
74 	LIST_ENTRY(gpio_driver)	link;
75 };
76 
77 static LIST_HEAD(, gpio_consumer) gpio_conslist = LIST_HEAD_INITIALIZER(&gpio_conslist);
78 static LIST_HEAD(, gpio_driver) gpio_driverlist = LIST_HEAD_INITIALIZER(&gpio_driverlist);
79 DEVFS_DEFINE_CLONE_BITMAP(gpio);
80 static struct lock gpio_lock;
81 static struct lock gpiodev_lock;
82 
83 void
84 gpio_consumer_register(struct gpio_consumer *gcp)
85 {
86 	lockmgr(&gpio_lock, LK_EXCLUSIVE);
87 	LIST_INSERT_HEAD(&gpio_conslist, gcp, link);
88 	lockmgr(&gpio_lock, LK_RELEASE);
89 }
90 
91 void
92 gpio_consumer_unregister(struct gpio_consumer *gcp)
93 {
94 	lockmgr(&gpio_lock, LK_EXCLUSIVE);
95 	LIST_REMOVE(gcp, link);
96 	lockmgr(&gpio_lock, LK_RELEASE);
97 }
98 
99 int
100 gpio_consumer_attach(const char *consumer, void *arg, struct gpio *gp,
101 	    int pin, u_int32_t mask)
102 {
103 	struct gpio_consumer *gcp;
104 	int error = -1;
105 	int locked = 0;
106 
107 	/* Check if it is locked already. if not, we acquire the lock */
108 	if ((lockstatus(&gpio_lock, curthread)) != LK_EXCLUSIVE) {
109 		lockmgr(&gpio_lock, LK_EXCLUSIVE);
110 		locked = 1;
111 	}
112 
113 	LIST_FOREACH(gcp, &gpio_conslist, link) {
114 		if (strcmp(gcp->consumer_name, consumer) != 0)
115 			continue;
116 
117 		if (gcp->consumer_attach)
118 			error = gcp->consumer_attach(gp, arg, pin, mask);
119 		if (error) {
120 			kprintf("gpio: Attach of consumer %s to gpio %s%d pin %d failed "
121 			    "(consumer error %d)\n", consumer, gp->driver_name,
122 			    gp->driver_unit, pin, error);
123 			goto end;
124 		}
125 
126 		kprintf("gpio: Attached consumer %s to gpio %s%d pin %d\n",
127 		    consumer, gp->driver_name, gp->driver_unit, pin);
128 		goto end;
129 	}
130 
131 	kprintf("gpio: Attach of consumer %s to gpio %s%d pin %d failed "
132 	    "(unknown consumer)\n", consumer, gp->driver_name, gp->driver_unit, pin);
133 
134 end:
135 	/* If we acquired the lock, we also get rid of it */
136 	if (locked)
137 		lockmgr(&gpio_lock, LK_RELEASE);
138 	return error;
139 }
140 
141 int
142 gpio_consumer_detach(const char *consumer, struct gpio *gp,
143 		int pin)
144 {
145 	struct gpio_consumer *gcp;
146 	int error = -1;
147 	int locked = 0;
148 
149 	/* Check if it is locked already. if not, we acquire the lock */
150 	if ((lockstatus(&gpio_lock, curthread)) != LK_EXCLUSIVE) {
151 		lockmgr(&gpio_lock, LK_EXCLUSIVE);
152 		locked = 1;
153 	}
154 
155 	LIST_FOREACH(gcp, &gpio_conslist, link) {
156 		if (strcmp(gcp->consumer_name, consumer) != 0)
157 			continue;
158 
159 		if (gcp->consumer_detach)
160 			error = gcp->consumer_detach(gp, NULL, pin);
161 		if (error) {
162 			kprintf("gpio: Detach of consumer %s from gpio %s%d pin %d failed "
163 			    "(consumer error %d)\n", consumer, gp->driver_name,
164 			    gp->driver_unit, pin, error);
165 			goto end;
166 		}
167 
168 		kprintf("gpio: Detached consumer %s from gpio %s%d pin %d\n",
169 		    consumer, gp->driver_name, gp->driver_unit, pin);
170 		goto end;
171 	}
172 
173 	kprintf("gpio: Detach of consumer %s from gpio %s%d pin %d failed "
174 	    "(unknown consumer)\n", consumer, gp->driver_name, gp->driver_unit, pin);
175 
176 end:
177 	/* If we acquired the lock, we also get rid of it */
178 	if (locked)
179 		lockmgr(&gpio_lock, LK_RELEASE);
180 	return error;
181 }
182 
183 struct gpio_mapping *
184 gpio_map(struct gpio *gp, int *map, int offset, u_int32_t mask)
185 {
186 	struct gpio_mapping *gmp;
187 	int npins, pin, i;
188 	int locked = 0;
189 
190 	npins = gpio_npins(mask);
191 	if (npins > gp->npins)
192 		return NULL;
193 	if (npins == 0)
194 		return NULL;
195 
196 	/* Check if it is locked already. if not, we acquire the lock */
197 	if ((lockstatus(&gpio_lock, curthread)) != LK_EXCLUSIVE) {
198 		lockmgr(&gpio_lock, LK_EXCLUSIVE);
199 		locked = 1;
200 	}
201 
202 	gmp = kmalloc(sizeof(struct gpio_mapping), M_TEMP, M_WAITOK);
203 	gmp->gp = gp;
204 	if (map) {
205 		gmp->map = map;
206 		gmp->map_alloced = 0;
207 	} else {
208 		gmp->map = kmalloc(sizeof(int) * npins, M_TEMP, M_WAITOK);
209 		gmp->map_alloced = 1;
210 	}
211 
212 	for (npins = 0, i = 0; i < 32; i++)
213 		if (mask & (1 << i)) {
214 			pin = offset + i;
215 			if (pin < 0 || pin >= gp->npins ||
216 				gp->pins[pin].pin_mapped || gp->pins[pin].pin_opened) {
217 				if (map == NULL)
218 					kfree(gmp->map, M_TEMP);
219 				kfree(gmp, M_TEMP);
220 				/* If we acquired the lock, we also get rid of it */
221 				if (locked)
222 					lockmgr(&gpio_lock, LK_RELEASE);
223 				return NULL;
224 			}
225 			gp->pins[pin].pin_mapped = 1;
226 			gmp->map[npins++] = pin;
227 		}
228 	gmp->size = npins;
229 
230 	/* If we acquired the lock, we also get rid of it */
231 	if (locked)
232 		lockmgr(&gpio_lock, LK_RELEASE);
233 
234 	return gmp;
235 }
236 
237 void
238 gpio_unmap(struct gpio_mapping *gmp)
239 {
240 	int pin, i;
241 	int locked = 0;
242 
243 	/* Check if it is locked already. if not, we acquire the lock */
244 	if ((lockstatus(&gpio_lock, curthread)) != LK_EXCLUSIVE) {
245 		lockmgr(&gpio_lock, LK_EXCLUSIVE);
246 		locked = 1;
247 	}
248 
249 	for (i = 0; i < gmp->size; i++) {
250 		pin = gmp->map[i];
251 		gmp->gp->pins[pin].pin_mapped = 0;
252 	}
253 
254 	if (gmp->map_alloced)
255 		kfree(gmp->map, M_TEMP);
256 	kfree(gmp, M_TEMP);
257 
258 	/* If we acquired the lock, we also get rid of it */
259 	if (locked)
260 		lockmgr(&gpio_lock, LK_RELEASE);
261 }
262 
263 int
264 gpio_npins(u_int32_t mask)
265 {
266 	int npins, i;
267 
268 	for (npins = 0, i = 0; i < 32; i++)
269 		if (mask & (1 << i))
270 			npins++;
271 
272 	return (npins);
273 }
274 
275 int
276 gpio_pin_read(struct gpio *gp, struct gpio_mapping *map, int pin)
277 {
278 	return gp->pin_read(gp->arg, map->map[pin]);
279 }
280 
281 void
282 gpio_pin_write(struct gpio *gp, struct gpio_mapping *map, int pin, int data)
283 {
284 	gp->pin_write(gp->arg, map->map[pin], data);
285 }
286 
287 void
288 gpio_pin_ctl(struct gpio *gp, struct gpio_mapping *map, int pin, int flags)
289 {
290 	gp->pin_ctl(gp->arg, map->map[pin], flags);
291 }
292 
293 int
294 gpio_pin_caps(struct gpio *gp, struct gpio_mapping *map, int pin)
295 {
296 	return (gp->pins[map->map[pin]].pin_caps);
297 }
298 
299 static int
300 gpio_open(struct dev_open_args *ap)
301 {
302 	gpio_pin_t	*pin;
303 	cdev_t	dev;
304 
305 	lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
306 	dev = ap->a_head.a_dev;
307 	pin = dev->si_drv2;
308 
309 	if (pin->pin_opened || pin->pin_mapped) {
310 		lockmgr(&gpiodev_lock, LK_RELEASE);
311 		return EBUSY;
312 	}
313 
314 	pin->pin_opened = 1;
315 	lockmgr(&gpiodev_lock, LK_RELEASE);
316 
317 	return 0;
318 }
319 
320 static int
321 gpio_close(struct dev_close_args *ap)
322 {
323 	gpio_pin_t	*pin;
324 	cdev_t	dev;
325 
326 	lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
327 	dev = ap->a_head.a_dev;
328 	pin = dev->si_drv2;
329 
330 	if (pin->pin_opened)
331 		pin->pin_opened = 0;
332 	lockmgr(&gpiodev_lock, LK_RELEASE);
333 
334 	return 0;
335 }
336 
337 static int
338 gpio_write(struct dev_write_args *ap)
339 {
340 	struct gpio	*gp;
341 	gpio_pin_t	*pin;
342 	cdev_t		dev;
343 	int		error;
344 	int		data = 0;
345 
346 	dev = ap->a_head.a_dev;
347 	gp = dev->si_drv1;
348 	pin = dev->si_drv2;
349 
350 	if (ap->a_uio->uio_resid > sizeof(int))
351 		return EINVAL;
352 
353 	error = uiomove((void *)&data, ap->a_uio->uio_resid, ap->a_uio);
354 	if (error)
355 		return error;
356 
357 	if (data != GPIO_PIN_LOW && data != GPIO_PIN_HIGH)
358 		return EINVAL;
359 
360 	lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
361 	gp->pin_write(gp->arg, pin->pin_num, data);
362 	pin->pin_state = data;
363 	lockmgr(&gpiodev_lock, LK_RELEASE);
364 
365 	return 0;
366 }
367 
368 static int
369 gpio_read(struct dev_read_args *ap)
370 {
371 	struct gpio	*gp;
372 	gpio_pin_t	*pin;
373 	cdev_t		dev;
374 	int		error;
375 	int		data = 0;
376 
377 	dev = ap->a_head.a_dev;
378 	gp = dev->si_drv1;
379 	pin = dev->si_drv2;
380 
381 	if (ap->a_uio->uio_resid < sizeof(char))
382 		return EINVAL;
383 
384 	lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
385 	data = gp->pin_read(gp->arg, pin->pin_num);
386 	lockmgr(&gpiodev_lock, LK_RELEASE);
387 
388 	error = uiomove((void *)&data,
389 	    (ap->a_uio->uio_resid > sizeof(int))?(sizeof(int)):(ap->a_uio->uio_resid),
390 		ap->a_uio);
391 
392 	return error;
393 }
394 
395 static int
396 gpio_ioctl(struct dev_ioctl_args *ap)
397 {
398 	struct gpio_pin_set_args *gpsa;
399 	struct gpio	*gp;
400 	gpio_pin_t	*pin;
401 	cdev_t		dev;
402 	int		error;
403 
404 	dev = ap->a_head.a_dev;
405 	gpsa = (struct gpio_pin_set_args *)ap->a_data;
406 	gp = dev->si_drv1;
407 	pin = dev->si_drv2;
408 	error = 0;
409 
410 	lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
411 
412 	switch(ap->a_cmd) {
413 	case GPIOPINSET:
414 		if (pin->pin_opened || pin->pin_mapped) {
415 			error = EBUSY;
416 			break;
417 		}
418 
419 		gpsa->caps = pin->pin_caps;
420 		gpsa->flags = pin->pin_flags;
421 
422 		if ((gpsa->flags & pin->pin_caps) != gpsa->flags) {
423 			error = ENODEV;
424 			break;
425 		}
426 
427 		if (gpsa->flags > 0) {
428 			gp->pin_ctl(gp->arg, pin->pin_num, gpsa->flags);
429 			pin->pin_flags = gpsa->flags | GPIO_PIN_SET;
430 		}
431 		break;
432 
433 	case GPIOPINUNSET:
434 		error = EINVAL;
435 		break;
436 
437 	default:
438 		error = EINVAL;
439 		break;
440 	}
441 	lockmgr(&gpiodev_lock, LK_RELEASE);
442 
443 	return error;
444 }
445 
446 static int
447 gpio_master_ioctl(struct dev_ioctl_args *ap)
448 {
449 	struct gpio_pin_set_args *gpsa;
450 	struct gpio_info	*gpi;
451 	struct gpio_attach_args	*gpaa;
452 	struct gpio	*gp;
453 	cdev_t		dev;
454 	gpio_pin_t	*pin;
455 	int		error = 0;
456 
457 	dev = ap->a_head.a_dev;
458 	gp = dev->si_drv1;
459 
460 	lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
461 
462 	switch(ap->a_cmd) {
463 	case GPIOINFO:
464 		gpi = (struct gpio_info *)ap->a_data;
465 		gpi->npins = gp->npins;
466 		if (gpi->pins != NULL) {
467 			error = copyout(gp->pins, gpi->pins,
468 			    sizeof(struct gpio_pin)*gp->npins);
469 		}
470 		break;
471 
472 	case GPIOATTACH:
473 		gpaa = (struct gpio_attach_args *)ap->a_data;
474 		error = gpio_consumer_attach(gpaa->consumer_name,
475 		    (gpaa->arg_type == GPIO_TYPE_INT)?
476 		    ((void *)gpaa->consumer_arg.lint):
477 		    (gpaa->consumer_arg.string),
478 		    gp, gpaa->pin_offset, gpaa->pin_mask);
479 		break;
480 
481 	case GPIODETACH:
482 		gpaa = (struct gpio_attach_args *)ap->a_data;
483 		error = gpio_consumer_detach(gpaa->consumer_name, gp,
484 		    gpaa->pin_offset);
485 		break;
486 
487 	case GPIOPINSET:
488 		gpsa = (struct gpio_pin_set_args *)ap->a_data;
489 		if (gpsa->pin < 0 || gpsa->pin >= gp->npins) {
490 			error = EINVAL;
491 			break;
492 		}
493 
494 		pin = &gp->pins[gpsa->pin];
495 
496 		if (pin->pin_opened || pin->pin_mapped) {
497 			error = EBUSY;
498 			break;
499 		}
500 
501 		gpsa->caps = pin->pin_caps;
502 		gpsa->flags = pin->pin_flags;
503 
504 		if ((gpsa->flags & pin->pin_caps) != gpsa->flags) {
505 			error = ENODEV;
506 			break;
507 		}
508 
509 		if (gpsa->flags > 0) {
510 			gp->pin_ctl(gp->arg, gpsa->pin, gpsa->flags);
511 			pin->pin_flags = gpsa->flags | GPIO_PIN_SET;
512 		}
513 		break;
514 
515 	case GPIOPINUNSET:
516 		gpsa = (struct gpio_pin_set_args *)ap->a_data;
517 		error = EINVAL;
518 		break;
519 
520 	default:
521 		error = EINVAL;
522 		break;
523 	}
524 	lockmgr(&gpiodev_lock, LK_RELEASE);
525 
526 	return error;
527 }
528 
529 static struct dev_ops gpio_ops = {
530 	{ "gpio", 0, D_MPSAFE },
531 	.d_open  =	gpio_open,
532 	.d_close =	gpio_close,
533 	.d_write = 	gpio_write,
534 	.d_read  =	gpio_read,
535 	.d_ioctl =	gpio_ioctl,
536 };
537 
538 static struct dev_ops gpio_master_ops = {
539 	{ "gpio", 0, D_MPSAFE },
540 	.d_ioctl =	gpio_master_ioctl,
541 };
542 
543 void
544 gpio_register(struct gpio *gp)
545 {
546 	struct gpio_driver *gpd;
547 	int i, unit, master_unit = -1;
548 
549 	KKASSERT(gp->npins > 0);
550 	KKASSERT(gp->pins);
551 
552 	lockmgr(&gpio_lock, LK_EXCLUSIVE);
553 	LIST_FOREACH(gpd, &gpio_driverlist, link) {
554 		if (strcmp(gpd->name, gp->driver_name) != 0)
555 			continue;
556 
557 		master_unit = devfs_clone_bitmap_get(&gpd->unit_bitmap, 0);
558 		break;
559 	}
560 	if (master_unit == -1) {
561 		gpd = kmalloc(sizeof(struct gpio_driver),
562 		    M_TEMP, M_WAITOK | M_ZERO);
563 		gpd->name = kstrdup(gp->driver_name, M_TEMP);
564 		devfs_clone_bitmap_init(&gpd->unit_bitmap);
565 		master_unit = devfs_clone_bitmap_get(&gpd->unit_bitmap, 0);
566 		LIST_INSERT_HEAD(&gpio_driverlist, gpd, link);
567 	}
568 	lockmgr(&gpio_lock, LK_RELEASE);
569 
570 	gp->driver_unit = master_unit;
571 	kprintf("gpio: GPIO driver %s%d registered, npins = %d\n",
572 	    gp->driver_name, master_unit, gp->npins);
573 
574 	unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(gpio), 0);
575 	gp->master_dev = make_dev(&gpio_master_ops, unit, UID_ROOT, GID_WHEEL, 0600,
576 	    "gpio/%s%d/master", gp->driver_name, master_unit);
577 	gp->master_dev->si_drv1 = gp;
578 
579 	for (i = 0; i < gp->npins; i++) {
580 		unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(gpio), 0);
581 		gp->pins[i].dev = make_dev(&gpio_ops, unit, UID_ROOT, GID_WHEEL, 0600,
582 		    "gpio/%s%d/%d", gp->driver_name, master_unit, gp->pins[i].pin_num);
583 		gp->pins[i].dev->si_drv1 = gp;
584 		gp->pins[i].dev->si_drv2 = &gp->pins[i];
585 	}
586 }
587 
588 void
589 gpio_unregister(struct gpio *gp)
590 {
591 	struct gpio_driver *gpd;
592 	int i;
593 
594 	KKASSERT(gp->npins > 0);
595 	KKASSERT(gp->pins);
596 
597 	for (i = 0; i < gp->npins; i++) {
598 		devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(gpio),
599 		    minor(gp->pins[i].dev));
600 		destroy_dev(gp->pins[i].dev);
601 	}
602 
603 	destroy_dev(gp->master_dev);
604 
605 	lockmgr(&gpio_lock, LK_EXCLUSIVE);
606 	LIST_FOREACH(gpd, &gpio_driverlist, link) {
607 		if (strcmp(gpd->name, gp->driver_name) != 0)
608 			continue;
609 
610 		devfs_clone_bitmap_put(&gpd->unit_bitmap, gp->driver_unit);
611 		LIST_REMOVE(gpd, link);
612 		break;
613 	}
614 	lockmgr(&gpio_lock, LK_RELEASE);
615 
616 	kprintf("gpio: GPIO driver %s%d unregistered\n",
617 	    gp->driver_name, gp->driver_unit);
618 }
619 
620 static void
621 gpio_drvinit(void *unused)
622 {
623 	lockinit(&gpio_lock, "gpio_lock", 0, 0);
624 	lockinit(&gpiodev_lock, "gpiodev_lock", 0, 0);
625 	devfs_clone_bitmap_init(&DEVFS_CLONE_BITMAP(gpio));
626 }
627 
628 SYSINIT(gpio, SI_SUB_PRE_DRIVERS, SI_ORDER_FIRST, gpio_drvinit, NULL);
629