xref: /dragonfly/sys/dev/misc/gpio/gpio.c (revision dda92f98)
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/malloc.h>
62 #include <sys/ctype.h>
63 #include <sys/sbuf.h>
64 #include <sys/queue.h>
65 #include <sys/uio.h>
66 #include <sys/lock.h>
67 #include <dev/misc/gpio/gpio.h>
68 #include <sys/devfs.h>
69 
70 struct gpio_driver {
71 	char	*name;
72 	struct devfs_bitmap	unit_bitmap;
73 	LIST_ENTRY(gpio_driver)	link;
74 };
75 
76 static LIST_HEAD(, gpio_consumer) gpio_conslist = LIST_HEAD_INITIALIZER(&gpio_conslist);
77 static LIST_HEAD(, gpio_driver) gpio_driverlist = LIST_HEAD_INITIALIZER(&gpio_driverlist);
78 DEVFS_DEFINE_CLONE_BITMAP(gpio);
79 static struct lock gpio_lock;
80 static struct lock gpiodev_lock;
81 
82 void
83 gpio_consumer_register(struct gpio_consumer *gcp)
84 {
85 	lockmgr(&gpio_lock, LK_EXCLUSIVE);
86 	LIST_INSERT_HEAD(&gpio_conslist, gcp, link);
87 	lockmgr(&gpio_lock, LK_RELEASE);
88 }
89 
90 void
91 gpio_consumer_unregister(struct gpio_consumer *gcp)
92 {
93 	lockmgr(&gpio_lock, LK_EXCLUSIVE);
94 	LIST_REMOVE(gcp, link);
95 	lockmgr(&gpio_lock, LK_RELEASE);
96 }
97 
98 int
99 gpio_consumer_attach(const char *consumer, void *arg, struct gpio *gp,
100 	    int pin, u_int32_t mask)
101 {
102 	struct gpio_consumer *gcp;
103 	int error = -1;
104 	int locked = 0;
105 
106 	/* Check if it is locked already. if not, we acquire the lock */
107 	if ((lockstatus(&gpio_lock, curthread)) != LK_EXCLUSIVE) {
108 		lockmgr(&gpio_lock, LK_EXCLUSIVE);
109 		locked = 1;
110 	}
111 
112 	LIST_FOREACH(gcp, &gpio_conslist, link) {
113 		if (strcmp(gcp->consumer_name, consumer) != 0)
114 			continue;
115 
116 		if (gcp->consumer_attach)
117 			error = gcp->consumer_attach(gp, arg, pin, mask);
118 		if (error) {
119 			kprintf("gpio: Attach of consumer %s to gpio %s%d pin %d failed "
120 			    "(consumer error %d)\n", consumer, gp->driver_name,
121 			    gp->driver_unit, pin, error);
122 			goto end;
123 		}
124 
125 		kprintf("gpio: Attached consumer %s to gpio %s%d pin %d\n",
126 		    consumer, gp->driver_name, gp->driver_unit, pin);
127 		goto end;
128 	}
129 
130 	kprintf("gpio: Attach of consumer %s to gpio %s%d pin %d failed "
131 	    "(unknown consumer)\n", consumer, gp->driver_name, gp->driver_unit, pin);
132 
133 end:
134 	/* If we acquired the lock, we also get rid of it */
135 	if (locked)
136 		lockmgr(&gpio_lock, LK_RELEASE);
137 	return error;
138 }
139 
140 int
141 gpio_consumer_detach(const char *consumer, struct gpio *gp,
142 		int pin)
143 {
144 	struct gpio_consumer *gcp;
145 	int error = -1;
146 	int locked = 0;
147 
148 	/* Check if it is locked already. if not, we acquire the lock */
149 	if ((lockstatus(&gpio_lock, curthread)) != LK_EXCLUSIVE) {
150 		lockmgr(&gpio_lock, LK_EXCLUSIVE);
151 		locked = 1;
152 	}
153 
154 	LIST_FOREACH(gcp, &gpio_conslist, link) {
155 		if (strcmp(gcp->consumer_name, consumer) != 0)
156 			continue;
157 
158 		if (gcp->consumer_detach)
159 			error = gcp->consumer_detach(gp, NULL, pin);
160 		if (error) {
161 			kprintf("gpio: Detach of consumer %s from gpio %s%d pin %d failed "
162 			    "(consumer error %d)\n", consumer, gp->driver_name,
163 			    gp->driver_unit, pin, error);
164 			goto end;
165 		}
166 
167 		kprintf("gpio: Detached consumer %s from gpio %s%d pin %d\n",
168 		    consumer, gp->driver_name, gp->driver_unit, pin);
169 		goto end;
170 	}
171 
172 	kprintf("gpio: Detach of consumer %s from gpio %s%d pin %d failed "
173 	    "(unknown consumer)\n", consumer, gp->driver_name, gp->driver_unit, pin);
174 
175 end:
176 	/* If we acquired the lock, we also get rid of it */
177 	if (locked)
178 		lockmgr(&gpio_lock, LK_RELEASE);
179 	return error;
180 }
181 
182 struct gpio_mapping *
183 gpio_map(struct gpio *gp, int *map, int offset, u_int32_t mask)
184 {
185 	struct gpio_mapping *gmp;
186 	int npins, pin, i;
187 	int locked = 0;
188 
189 	npins = gpio_npins(mask);
190 	if (npins > gp->npins)
191 		return NULL;
192 	if (npins == 0)
193 		return NULL;
194 
195 	/* Check if it is locked already. if not, we acquire the lock */
196 	if ((lockstatus(&gpio_lock, curthread)) != LK_EXCLUSIVE) {
197 		lockmgr(&gpio_lock, LK_EXCLUSIVE);
198 		locked = 1;
199 	}
200 
201 	gmp = kmalloc(sizeof(struct gpio_mapping), M_TEMP, M_WAITOK);
202 	gmp->gp = gp;
203 	if (map) {
204 		gmp->map = map;
205 		gmp->map_alloced = 0;
206 	} else {
207 		gmp->map = kmalloc(sizeof(int) * npins, M_TEMP, M_WAITOK);
208 		gmp->map_alloced = 1;
209 	}
210 
211 	for (npins = 0, i = 0; i < 32; i++)
212 		if (mask & (1 << i)) {
213 			pin = offset + i;
214 			if (pin < 0 || pin >= gp->npins ||
215 				gp->pins[pin].pin_mapped || gp->pins[pin].pin_opened) {
216 				if (map == NULL)
217 					kfree(gmp->map, M_TEMP);
218 				kfree(gmp, M_TEMP);
219 				/* If we acquired the lock, we also get rid of it */
220 				if (locked)
221 					lockmgr(&gpio_lock, LK_RELEASE);
222 				return NULL;
223 			}
224 			gp->pins[pin].pin_mapped = 1;
225 			gmp->map[npins++] = pin;
226 		}
227 	gmp->size = npins;
228 
229 	/* If we acquired the lock, we also get rid of it */
230 	if (locked)
231 		lockmgr(&gpio_lock, LK_RELEASE);
232 
233 	return gmp;
234 }
235 
236 void
237 gpio_unmap(struct gpio_mapping *gmp)
238 {
239 	int pin, i;
240 	int locked = 0;
241 
242 	/* Check if it is locked already. if not, we acquire the lock */
243 	if ((lockstatus(&gpio_lock, curthread)) != LK_EXCLUSIVE) {
244 		lockmgr(&gpio_lock, LK_EXCLUSIVE);
245 		locked = 1;
246 	}
247 
248 	for (i = 0; i < gmp->size; i++) {
249 		pin = gmp->map[i];
250 		gmp->gp->pins[pin].pin_mapped = 0;
251 	}
252 
253 	if (gmp->map_alloced)
254 		kfree(gmp->map, M_TEMP);
255 	kfree(gmp, M_TEMP);
256 
257 	/* If we acquired the lock, we also get rid of it */
258 	if (locked)
259 		lockmgr(&gpio_lock, LK_RELEASE);
260 }
261 
262 int
263 gpio_npins(u_int32_t mask)
264 {
265 	int npins, i;
266 
267 	for (npins = 0, i = 0; i < 32; i++)
268 		if (mask & (1 << i))
269 			npins++;
270 
271 	return (npins);
272 }
273 
274 int
275 gpio_pin_read(struct gpio *gp, struct gpio_mapping *map, int pin)
276 {
277 	return gp->pin_read(gp->arg, map->map[pin]);
278 }
279 
280 void
281 gpio_pin_write(struct gpio *gp, struct gpio_mapping *map, int pin, int data)
282 {
283 	gp->pin_write(gp->arg, map->map[pin], data);
284 }
285 
286 void
287 gpio_pin_ctl(struct gpio *gp, struct gpio_mapping *map, int pin, int flags)
288 {
289 	gp->pin_ctl(gp->arg, map->map[pin], flags);
290 }
291 
292 int
293 gpio_pin_caps(struct gpio *gp, struct gpio_mapping *map, int pin)
294 {
295 	return (gp->pins[map->map[pin]].pin_caps);
296 }
297 
298 static int
299 gpio_open(struct dev_open_args *ap)
300 {
301 	gpio_pin_t	*pin;
302 	cdev_t	dev;
303 
304 	lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
305 	dev = ap->a_head.a_dev;
306 	pin = dev->si_drv2;
307 
308 	if (pin->pin_opened || pin->pin_mapped) {
309 		lockmgr(&gpiodev_lock, LK_RELEASE);
310 		return EBUSY;
311 	}
312 
313 	pin->pin_opened = 1;
314 	lockmgr(&gpiodev_lock, LK_RELEASE);
315 
316 	return 0;
317 }
318 
319 static int
320 gpio_close(struct dev_close_args *ap)
321 {
322 	gpio_pin_t	*pin;
323 	cdev_t	dev;
324 
325 	lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
326 	dev = ap->a_head.a_dev;
327 	pin = dev->si_drv2;
328 
329 	if (pin->pin_opened)
330 		pin->pin_opened = 0;
331 	lockmgr(&gpiodev_lock, LK_RELEASE);
332 
333 	return 0;
334 }
335 
336 static int
337 gpio_write(struct dev_write_args *ap)
338 {
339 	struct gpio	*gp;
340 	gpio_pin_t	*pin;
341 	cdev_t		dev;
342 	int		error;
343 	int		data = 0;
344 
345 	dev = ap->a_head.a_dev;
346 	gp = dev->si_drv1;
347 	pin = dev->si_drv2;
348 
349 	if (ap->a_uio->uio_resid > sizeof(int))
350 		return EINVAL;
351 
352 	error = uiomove((void *)&data, ap->a_uio->uio_resid, ap->a_uio);
353 	if (error)
354 		return error;
355 
356 	if (data != GPIO_PIN_LOW && data != GPIO_PIN_HIGH)
357 		return EINVAL;
358 
359 	lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
360 	gp->pin_write(gp->arg, pin->pin_num, data);
361 	pin->pin_state = data;
362 	lockmgr(&gpiodev_lock, LK_RELEASE);
363 
364 	return 0;
365 }
366 
367 static int
368 gpio_read(struct dev_read_args *ap)
369 {
370 	struct gpio	*gp;
371 	gpio_pin_t	*pin;
372 	cdev_t		dev;
373 	int		error;
374 	int		data = 0;
375 
376 	dev = ap->a_head.a_dev;
377 	gp = dev->si_drv1;
378 	pin = dev->si_drv2;
379 
380 	if (ap->a_uio->uio_resid < sizeof(char))
381 		return EINVAL;
382 
383 	lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
384 	data = gp->pin_read(gp->arg, pin->pin_num);
385 	lockmgr(&gpiodev_lock, LK_RELEASE);
386 
387 	error = uiomove((void *)&data,
388 	    (ap->a_uio->uio_resid > sizeof(int))?(sizeof(int)):(ap->a_uio->uio_resid),
389 		ap->a_uio);
390 
391 	return error;
392 }
393 
394 static int
395 gpio_ioctl(struct dev_ioctl_args *ap)
396 {
397 	struct gpio_pin_set_args *gpsa;
398 	struct gpio	*gp;
399 	gpio_pin_t	*pin;
400 	cdev_t		dev;
401 	int		error;
402 
403 	dev = ap->a_head.a_dev;
404 	gpsa = (struct gpio_pin_set_args *)ap->a_data;
405 	gp = dev->si_drv1;
406 	pin = dev->si_drv2;
407 	error = 0;
408 
409 	lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
410 
411 	switch(ap->a_cmd) {
412 	case GPIOPINSET:
413 		if (pin->pin_opened || pin->pin_mapped) {
414 			error = EBUSY;
415 			break;
416 		}
417 
418 		gpsa->caps = pin->pin_caps;
419 		gpsa->flags = pin->pin_flags;
420 
421 		if ((gpsa->flags & pin->pin_caps) != gpsa->flags) {
422 			error = ENODEV;
423 			break;
424 		}
425 
426 		if (gpsa->flags > 0) {
427 			gp->pin_ctl(gp->arg, pin->pin_num, gpsa->flags);
428 			pin->pin_flags = gpsa->flags | GPIO_PIN_SET;
429 		}
430 		break;
431 
432 	case GPIOPINUNSET:
433 		error = EINVAL;
434 		break;
435 
436 	default:
437 		error = EINVAL;
438 		break;
439 	}
440 	lockmgr(&gpiodev_lock, LK_RELEASE);
441 
442 	return error;
443 }
444 
445 static int
446 gpio_master_ioctl(struct dev_ioctl_args *ap)
447 {
448 	struct gpio_pin_set_args *gpsa;
449 	struct gpio_info	*gpi;
450 	struct gpio_attach_args	*gpaa;
451 	struct gpio	*gp;
452 	cdev_t		dev;
453 	gpio_pin_t	*pin;
454 	int		error = 0;
455 
456 	dev = ap->a_head.a_dev;
457 	gp = dev->si_drv1;
458 
459 	lockmgr(&gpiodev_lock, LK_EXCLUSIVE);
460 
461 	switch(ap->a_cmd) {
462 	case GPIOINFO:
463 		gpi = (struct gpio_info *)ap->a_data;
464 		gpi->npins = gp->npins;
465 		if (gpi->pins != NULL) {
466 			error = copyout(gp->pins, gpi->pins,
467 			    sizeof(struct gpio_pin)*gp->npins);
468 		}
469 		break;
470 
471 	case GPIOATTACH:
472 		gpaa = (struct gpio_attach_args *)ap->a_data;
473 		error = gpio_consumer_attach(gpaa->consumer_name,
474 		    (gpaa->arg_type == GPIO_TYPE_INT)?
475 		    ((void *)gpaa->consumer_arg.lint):
476 		    (gpaa->consumer_arg.string),
477 		    gp, gpaa->pin_offset, gpaa->pin_mask);
478 		break;
479 
480 	case GPIODETACH:
481 		gpaa = (struct gpio_attach_args *)ap->a_data;
482 		error = gpio_consumer_detach(gpaa->consumer_name, gp,
483 		    gpaa->pin_offset);
484 		break;
485 
486 	case GPIOPINSET:
487 		gpsa = (struct gpio_pin_set_args *)ap->a_data;
488 		if (gpsa->pin < 0 || gpsa->pin >= gp->npins) {
489 			error = EINVAL;
490 			break;
491 		}
492 
493 		pin = &gp->pins[gpsa->pin];
494 
495 		if (pin->pin_opened || pin->pin_mapped) {
496 			error = EBUSY;
497 			break;
498 		}
499 
500 		gpsa->caps = pin->pin_caps;
501 		gpsa->flags = pin->pin_flags;
502 
503 		if ((gpsa->flags & pin->pin_caps) != gpsa->flags) {
504 			error = ENODEV;
505 			break;
506 		}
507 
508 		if (gpsa->flags > 0) {
509 			gp->pin_ctl(gp->arg, gpsa->pin, gpsa->flags);
510 			pin->pin_flags = gpsa->flags | GPIO_PIN_SET;
511 		}
512 		break;
513 
514 	case GPIOPINUNSET:
515 		gpsa = (struct gpio_pin_set_args *)ap->a_data;
516 		error = EINVAL;
517 		break;
518 
519 	default:
520 		error = EINVAL;
521 		break;
522 	}
523 	lockmgr(&gpiodev_lock, LK_RELEASE);
524 
525 	return error;
526 }
527 
528 static struct dev_ops gpio_ops = {
529 	{ "gpio", 0, D_MPSAFE },
530 	.d_open  =	gpio_open,
531 	.d_close =	gpio_close,
532 	.d_write = 	gpio_write,
533 	.d_read  =	gpio_read,
534 	.d_ioctl =	gpio_ioctl,
535 };
536 
537 static struct dev_ops gpio_master_ops = {
538 	{ "gpio", 0, D_MPSAFE },
539 	.d_ioctl =	gpio_master_ioctl,
540 };
541 
542 void
543 gpio_register(struct gpio *gp)
544 {
545 	struct gpio_driver *gpd;
546 	int i, unit, master_unit = -1;
547 
548 	KKASSERT(gp->npins > 0);
549 	KKASSERT(gp->pins);
550 
551 	lockmgr(&gpio_lock, LK_EXCLUSIVE);
552 	LIST_FOREACH(gpd, &gpio_driverlist, link) {
553 		if (strcmp(gpd->name, gp->driver_name) != 0)
554 			continue;
555 
556 		master_unit = devfs_clone_bitmap_get(&gpd->unit_bitmap, 0);
557 		break;
558 	}
559 	if (master_unit == -1) {
560 		gpd = kmalloc(sizeof(struct gpio_driver),
561 		    M_TEMP, M_WAITOK | M_ZERO);
562 		gpd->name = kstrdup(gp->driver_name, M_TEMP);
563 		devfs_clone_bitmap_init(&gpd->unit_bitmap);
564 		master_unit = devfs_clone_bitmap_get(&gpd->unit_bitmap, 0);
565 		LIST_INSERT_HEAD(&gpio_driverlist, gpd, link);
566 	}
567 	lockmgr(&gpio_lock, LK_RELEASE);
568 
569 	gp->driver_unit = master_unit;
570 	kprintf("gpio: GPIO driver %s%d registered, npins = %d\n",
571 	    gp->driver_name, master_unit, gp->npins);
572 
573 	unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(gpio), 0);
574 	gp->master_dev = make_dev(&gpio_master_ops, unit, UID_ROOT, GID_WHEEL, 0600,
575 	    "gpio/%s%d/master", gp->driver_name, master_unit);
576 	gp->master_dev->si_drv1 = gp;
577 
578 	for (i = 0; i < gp->npins; i++) {
579 		unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(gpio), 0);
580 		gp->pins[i].dev = make_dev(&gpio_ops, unit, UID_ROOT, GID_WHEEL, 0600,
581 		    "gpio/%s%d/%d", gp->driver_name, master_unit, gp->pins[i].pin_num);
582 		gp->pins[i].dev->si_drv1 = gp;
583 		gp->pins[i].dev->si_drv2 = &gp->pins[i];
584 	}
585 }
586 
587 void
588 gpio_unregister(struct gpio *gp)
589 {
590 	struct gpio_driver *gpd;
591 	int i;
592 
593 	KKASSERT(gp->npins > 0);
594 	KKASSERT(gp->pins);
595 
596 	for (i = 0; i < gp->npins; i++) {
597 		devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(gpio),
598 		    minor(gp->pins[i].dev));
599 		destroy_dev(gp->pins[i].dev);
600 	}
601 
602 	destroy_dev(gp->master_dev);
603 
604 	lockmgr(&gpio_lock, LK_EXCLUSIVE);
605 	LIST_FOREACH(gpd, &gpio_driverlist, link) {
606 		if (strcmp(gpd->name, gp->driver_name) != 0)
607 			continue;
608 
609 		devfs_clone_bitmap_put(&gpd->unit_bitmap, gp->driver_unit);
610 		LIST_REMOVE(gpd, link);
611 		break;
612 	}
613 	lockmgr(&gpio_lock, LK_RELEASE);
614 
615 	kprintf("gpio: GPIO driver %s%d unregistered\n",
616 	    gp->driver_name, gp->driver_unit);
617 }
618 
619 static void
620 gpio_drvinit(void *unused)
621 {
622 	lockinit(&gpio_lock, "gpio_lock", 0, 0);
623 	lockinit(&gpiodev_lock, "gpiodev_lock", 0, 0);
624 	devfs_clone_bitmap_init(&DEVFS_CLONE_BITMAP(gpio));
625 }
626 
627 SYSINIT(gpio, SI_SUB_PRE_DRIVERS, SI_ORDER_FIRST, gpio_drvinit, NULL);
628