2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Alex Hornung <ahornung@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
35 * Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org>
36 * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org>
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.
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.
51 * XXX: consumer_detach stuff.
52 * XXX: userland stuff.
55 #include <sys/param.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>
65 #include <sys/queue.h>
68 #include <dev/misc/gpio/gpio.h>
69 #include <sys/devfs.h>
73 struct devfs_bitmap unit_bitmap;
74 LIST_ENTRY(gpio_driver) link;
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_DECLARE_CLONE_BITMAP(gpio);
80 static struct lock gpio_lock;
83 gpio_consumer_register(struct gpio_consumer *gcp)
85 lockmgr(&gpio_lock, LK_EXCLUSIVE);
86 LIST_INSERT_HEAD(&gpio_conslist, gcp, link);
87 lockmgr(&gpio_lock, LK_RELEASE);
91 gpio_consumer_unregister(struct gpio_consumer *gcp)
93 lockmgr(&gpio_lock, LK_EXCLUSIVE);
94 LIST_REMOVE(gcp, link);
95 lockmgr(&gpio_lock, LK_RELEASE);
99 gpio_consumer_attach(const char *consumer, void *arg, struct gpio *gp,
100 int pin, u_int32_t mask)
102 struct gpio_consumer *gcp;
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);
112 LIST_FOREACH(gcp, &gpio_conslist, link) {
113 if (strcmp(gcp->consumer_name, consumer) != 0)
116 if (gcp->consumer_attach)
117 error = gcp->consumer_attach(gp, arg, pin, mask);
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);
125 kprintf("gpio: Attached consumer %s to gpio %s%d pin %d\n",
126 consumer, gp->driver_name, gp->driver_unit, pin);
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);
134 /* If we acquired the lock, we also get rid of it */
136 lockmgr(&gpio_lock, LK_RELEASE);
141 gpio_consumer_detach(const char *consumer, struct gpio *gp,
144 struct gpio_consumer *gcp;
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);
154 LIST_FOREACH(gcp, &gpio_conslist, link) {
155 if (strcmp(gcp->consumer_name, consumer) != 0)
158 if (gcp->consumer_detach)
159 error = gcp->consumer_detach(gp, NULL, pin);
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);
167 kprintf("gpio: Detached consumer %s from gpio %s%d pin %d\n",
168 consumer, gp->driver_name, gp->driver_unit, pin);
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);
176 /* If we acquired the lock, we also get rid of it */
178 lockmgr(&gpio_lock, LK_RELEASE);
182 struct gpio_mapping *
183 gpio_map(struct gpio *gp, int *map, int offset, u_int32_t mask)
185 struct gpio_mapping *gmp;
189 npins = gpio_npins(mask);
190 if (npins > gp->npins)
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);
201 gmp = kmalloc(sizeof(struct gpio_mapping), M_TEMP, M_WAITOK);
205 gmp->map_alloced = 0;
207 gmp->map = kmalloc(sizeof(int) * npins, M_TEMP, M_WAITOK);
208 gmp->map_alloced = 1;
211 for (npins = 0, i = 0; i < 32; i++)
212 if (mask & (1 << i)) {
214 if (pin < 0 || pin >= gp->npins ||
215 gp->pins[pin].pin_mapped || gp->pins[pin].pin_opened) {
217 kfree(gmp->map, M_TEMP);
219 /* If we acquired the lock, we also get rid of it */
221 lockmgr(&gpio_lock, LK_RELEASE);
224 gp->pins[pin].pin_mapped = 1;
225 gmp->map[npins++] = pin;
229 /* If we acquired the lock, we also get rid of it */
231 lockmgr(&gpio_lock, LK_RELEASE);
237 gpio_unmap(struct gpio_mapping *gmp)
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);
248 for (i = 0; i < gmp->size; i++) {
250 gmp->gp->pins[pin].pin_mapped = 0;
253 if (gmp->map_alloced)
254 kfree(gmp->map, M_TEMP);
257 /* If we acquired the lock, we also get rid of it */
259 lockmgr(&gpio_lock, LK_RELEASE);
263 gpio_npins(u_int32_t mask)
267 for (npins = 0, i = 0; i < 32; i++)
275 gpio_pin_read(struct gpio *gp, struct gpio_mapping *map, int pin)
277 return gp->pin_read(gp->arg, map->map[pin]);
281 gpio_pin_write(struct gpio *gp, struct gpio_mapping *map, int pin, int data)
283 gp->pin_write(gp->arg, map->map[pin], data);
287 gpio_pin_ctl(struct gpio *gp, struct gpio_mapping *map, int pin, int flags)
289 gp->pin_ctl(gp->arg, map->map[pin], flags);
293 gpio_pin_caps(struct gpio *gp, struct gpio_mapping *map, int pin)
295 return (gp->pins[map->map[pin]].pin_caps);
299 gpio_open(struct dev_open_args *ap)
304 dev = ap->a_head.a_dev;
307 if (pin->pin_opened || pin->pin_mapped)
316 gpio_close(struct dev_close_args *ap)
321 dev = ap->a_head.a_dev;
331 gpio_write(struct dev_write_args *ap)
339 dev = ap->a_head.a_dev;
343 if (ap->a_uio->uio_resid > sizeof(int))
346 error = uiomove((void *)&data, ap->a_uio->uio_resid, ap->a_uio);
350 if (data != GPIO_PIN_LOW && data != GPIO_PIN_HIGH)
353 gp->pin_write(gp->arg, pin->pin_num, data);
354 pin->pin_state = data;
360 gpio_read(struct dev_read_args *ap)
368 dev = ap->a_head.a_dev;
372 if (ap->a_uio->uio_resid < sizeof(char))
375 data = gp->pin_read(gp->arg, pin->pin_num);
377 error = uiomove((void *)&data,
378 (ap->a_uio->uio_resid > sizeof(int))?(sizeof(int)):(ap->a_uio->uio_resid),
385 gpio_ioctl(struct dev_ioctl_args *ap)
387 struct gpio_pin_set_args *gpsa;
392 dev = ap->a_head.a_dev;
393 gpsa = (struct gpio_pin_set_args *)ap->a_data;
399 if (pin->pin_opened || pin->pin_mapped)
402 gpsa->caps = pin->pin_caps;
403 gpsa->flags = pin->pin_flags;
405 if ((gpsa->flags & pin->pin_caps) != gpsa->flags)
408 if (gpsa->flags > 0) {
409 gp->pin_ctl(gp->arg, pin->pin_num, gpsa->flags);
410 pin->pin_flags = gpsa->flags | GPIO_PIN_SET;
425 gpio_master_ioctl(struct dev_ioctl_args *ap)
427 struct gpio_pin_set_args *gpsa;
428 struct gpio_info *gpi;
429 struct gpio_attach_args *gpaa;
435 dev = ap->a_head.a_dev;
440 gpi = (struct gpio_info *)ap->a_data;
441 gpi->npins = gp->npins;
442 if (gpi->pins != NULL) {
443 error = copyout(gp->pins, gpi->pins,
444 sizeof(struct gpio_pin)*gp->npins);
449 gpaa = (struct gpio_attach_args *)ap->a_data;
450 error = gpio_consumer_attach(gpaa->consumer_name,
451 (gpaa->arg_type == GPIO_TYPE_INT)?
452 ((void *)gpaa->consumer_arg.lint):
453 (gpaa->consumer_arg.string),
454 gp, gpaa->pin_offset, gpaa->pin_mask);
458 gpaa = (struct gpio_attach_args *)ap->a_data;
459 error = gpio_consumer_detach(gpaa->consumer_name, gp,
464 gpsa = (struct gpio_pin_set_args *)ap->a_data;
465 if (gpsa->pin < 0 || gpsa->pin >= gp->npins)
468 pin = &gp->pins[gpsa->pin];
470 if (pin->pin_opened || pin->pin_mapped)
473 gpsa->caps = pin->pin_caps;
474 gpsa->flags = pin->pin_flags;
476 if ((gpsa->flags & pin->pin_caps) != gpsa->flags)
479 if (gpsa->flags > 0) {
480 gp->pin_ctl(gp->arg, gpsa->pin, gpsa->flags);
481 pin->pin_flags = gpsa->flags | GPIO_PIN_SET;
486 gpsa = (struct gpio_pin_set_args *)ap->a_data;
497 static struct dev_ops gpio_ops = {
500 .d_close = gpio_close,
501 .d_write = gpio_write,
503 .d_ioctl = gpio_ioctl,
506 static struct dev_ops gpio_master_ops = {
508 .d_ioctl = gpio_master_ioctl,
512 gpio_register(struct gpio *gp)
514 struct gpio_driver *gpd;
515 int i, unit, master_unit = -1;
517 KKASSERT(gp->npins > 0);
520 lockmgr(&gpio_lock, LK_EXCLUSIVE);
521 LIST_FOREACH(gpd, &gpio_driverlist, link) {
522 if (strcmp(gpd->name, gp->driver_name) != 0)
525 master_unit = devfs_clone_bitmap_get(&gpd->unit_bitmap, 0);
528 if (master_unit == -1) {
529 gpd = kmalloc(sizeof(struct gpio_driver),
530 M_TEMP, M_WAITOK | M_ZERO);
531 gpd->name = kstrdup(gp->driver_name, M_TEMP);
532 devfs_clone_bitmap_init(&gpd->unit_bitmap);
533 master_unit = devfs_clone_bitmap_get(&gpd->unit_bitmap, 0);
534 LIST_INSERT_HEAD(&gpio_driverlist, gpd, link);
536 lockmgr(&gpio_lock, LK_RELEASE);
538 gp->driver_unit = master_unit;
539 kprintf("gpio: GPIO driver %s%d registered, npins = %d\n",
540 gp->driver_name, master_unit, gp->npins);
542 unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(gpio), 0);
543 gp->master_dev = make_dev(&gpio_master_ops, unit, UID_ROOT, GID_WHEEL, 0600,
544 "gpio/%s%d/master", gp->driver_name, master_unit);
545 gp->master_dev->si_drv1 = gp;
547 for (i = 0; i < gp->npins; i++) {
548 unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(gpio), 0);
549 gp->pins[i].dev = make_dev(&gpio_ops, unit, UID_ROOT, GID_WHEEL, 0600,
550 "gpio/%s%d/%d", gp->driver_name, master_unit, gp->pins[i].pin_num);
551 gp->pins[i].dev->si_drv1 = gp;
552 gp->pins[i].dev->si_drv2 = &gp->pins[i];
557 gpio_unregister(struct gpio *gp)
559 struct gpio_driver *gpd;
562 KKASSERT(gp->npins > 0);
565 for (i = 0; i < gp->npins; i++) {
566 devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(gpio),
567 minor(gp->pins[i].dev));
568 destroy_dev(gp->pins[i].dev);
571 destroy_dev(gp->master_dev);
573 lockmgr(&gpio_lock, LK_EXCLUSIVE);
574 LIST_FOREACH(gpd, &gpio_driverlist, link) {
575 if (strcmp(gpd->name, gp->driver_name) != 0)
578 devfs_clone_bitmap_put(&gpd->unit_bitmap, gp->driver_unit);
579 LIST_REMOVE(gpd, link);
582 lockmgr(&gpio_lock, LK_RELEASE);
584 kprintf("gpio: GPIO driver %s%d unregistered\n",
585 gp->driver_name, gp->driver_unit);
589 gpio_drvinit(void *unused)
591 lockinit(&gpio_lock, "gpio_lock", 0, 0);
592 devfs_clone_bitmap_init(&DEVFS_CLONE_BITMAP(gpio));
595 SYSINIT(gpio, SI_SUB_PRE_DRIVERS, SI_ORDER_FIRST, gpio_drvinit, NULL);