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