Module: xenomai-3
Branch: wip/gpio
Commit: 2bba7740be7ce51755b6b7a3dd0a1fae3a79476d
URL:    
http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=2bba7740be7ce51755b6b7a3dd0a1fae3a79476d

Author: Philippe Gerum <r...@xenomai.org>
Date:   Wed May 25 10:54:22 2016 +0200

drivers/gpio: introduce real-time GPIO support

---

 configure.ac                       |    1 +
 include/rtdm/Makefile.am           |    1 +
 include/rtdm/gpio.h                |   24 +++
 include/rtdm/uapi/Makefile.am      |    1 +
 include/rtdm/uapi/gpio.h           |   28 +++
 include/rtdm/uapi/rtdm.h           |    1 +
 kernel/drivers/Kconfig             |    1 +
 kernel/drivers/Makefile            |    2 +-
 kernel/drivers/gpio/Kconfig        |   25 +++
 kernel/drivers/gpio/Makefile       |    7 +
 kernel/drivers/gpio/gpio-bcm2708.c |   39 ++++
 kernel/drivers/gpio/gpio-core.c    |  349 ++++++++++++++++++++++++++++++++++++
 kernel/drivers/gpio/gpio-core.h    |   48 +++++
 kernel/drivers/gpio/gpio-mxc.c     |   67 +++++++
 14 files changed, 593 insertions(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index 8bbeeef..88022a6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -878,6 +878,7 @@ AC_CONFIG_FILES([ \
        testsuite/Makefile \
        testsuite/latency/Makefile \
        testsuite/switchtest/Makefile \
+       testsuite/gpiotest/Makefile \
        testsuite/smokey/Makefile \
        testsuite/smokey/arith/Makefile \
        testsuite/smokey/sched-quota/Makefile \
diff --git a/include/rtdm/Makefile.am b/include/rtdm/Makefile.am
index a4e6ff8..ad2c342 100644
--- a/include/rtdm/Makefile.am
+++ b/include/rtdm/Makefile.am
@@ -4,6 +4,7 @@ includesub_HEADERS =    \
        analogy.h       \
        autotune.h      \
        can.h           \
+       gpio.h          \
        ipc.h           \
        rtdm.h          \
        serial.h        \
diff --git a/include/rtdm/gpio.h b/include/rtdm/gpio.h
new file mode 100644
index 0000000..c61f229
--- /dev/null
+++ b/include/rtdm/gpio.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 Philippe Gerum <r...@xenomai.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+ */
+#ifndef _RTDM_GPIO_H
+#define _RTDM_GPIO_H
+
+#include <rtdm/rtdm.h>
+#include <rtdm/uapi/gpio.h>
+
+#endif /* !_RTDM_GPIO_H */
diff --git a/include/rtdm/uapi/Makefile.am b/include/rtdm/uapi/Makefile.am
index 7cff6c2..d53f10c 100644
--- a/include/rtdm/uapi/Makefile.am
+++ b/include/rtdm/uapi/Makefile.am
@@ -4,6 +4,7 @@ includesub_HEADERS =    \
        analogy.h       \
        autotune.h      \
        can.h           \
+       gpio.h          \
        ipc.h           \
        rtdm.h          \
        serial.h        \
diff --git a/include/rtdm/uapi/gpio.h b/include/rtdm/uapi/gpio.h
new file mode 100644
index 0000000..b0d4899
--- /dev/null
+++ b/include/rtdm/uapi/gpio.h
@@ -0,0 +1,28 @@
+/**
+ * @note Copyright (C) 2016 Philippe Gerum <r...@xenomai.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef _RTDM_UAPI_GPIO_H
+#define _RTDM_UAPI_GPIO_H
+
+#include <linux/types.h>
+
+#define GPIO_RTIOC_DIR_OUT             _IOW(RTDM_CLASS_GPIO, 0, int)
+#define GPIO_RTIOC_DIR_IN              _IO(RTDM_CLASS_GPIO, 1)
+#define GPIO_RTIOC_IRQEN               _IO(RTDM_CLASS_GPIO, 2)
+#define GPIO_RTIOC_IRQDIS              _IO(RTDM_CLASS_GPIO, 3)
+
+#endif /* !_RTDM_UAPI_GPIO_H */
diff --git a/include/rtdm/uapi/rtdm.h b/include/rtdm/uapi/rtdm.h
index eed3b36..c49378c 100644
--- a/include/rtdm/uapi/rtdm.h
+++ b/include/rtdm/uapi/rtdm.h
@@ -79,6 +79,7 @@ typedef int64_t nanosecs_rel_t;
 #define RTDM_CLASS_COBALT              8
 #define RTDM_CLASS_UDD                 9
 #define RTDM_CLASS_MEMORY              10
+#define RTDM_CLASS_GPIO                        11
 /*
 #define RTDM_CLASS_USB                 ?
 #define RTDM_CLASS_FIREWIRE            ?
diff --git a/kernel/drivers/Kconfig b/kernel/drivers/Kconfig
index a8b4c26..cbb6222 100644
--- a/kernel/drivers/Kconfig
+++ b/kernel/drivers/Kconfig
@@ -28,5 +28,6 @@ source "drivers/xenomai/net/Kconfig"
 source "drivers/xenomai/analogy/Kconfig"
 source "drivers/xenomai/ipc/Kconfig"
 source "drivers/xenomai/udd/Kconfig"
+source "drivers/xenomai/gpio/Kconfig"
 
 endmenu
diff --git a/kernel/drivers/Makefile b/kernel/drivers/Makefile
index 4d80f68..c9cb567 100644
--- a/kernel/drivers/Makefile
+++ b/kernel/drivers/Makefile
@@ -1 +1 @@
-obj-$(CONFIG_XENOMAI) += autotune/ serial/ testing/ can/ net/ analogy/ ipc/ 
udd/
+obj-$(CONFIG_XENOMAI) += autotune/ serial/ testing/ can/ net/ analogy/ ipc/ 
udd/ gpio/
diff --git a/kernel/drivers/gpio/Kconfig b/kernel/drivers/gpio/Kconfig
new file mode 100644
index 0000000..001c1bc
--- /dev/null
+++ b/kernel/drivers/gpio/Kconfig
@@ -0,0 +1,25 @@
+menu "Real-time GPIO drivers"
+
+config XENO_DRIVERS_GPIO
+       bool
+       depends on GPIOLIB
+
+config XENO_DRIVERS_GPIO_BCM2708
+       depends on MACH_BCM2708
+       select XENO_DRIVERS_GPIO
+       bool "Support for BCM2708 GPIOs"
+       help
+
+       Suitable for the GPIO controller present on Broadcom's BCM2708
+       chip family.
+
+config XENO_DRIVERS_GPIO_MXC
+       depends on GPIO_MXC
+       select XENO_DRIVERS_GPIO
+       bool "Support for MXC GPIOs"
+       help
+
+       Suitable for the GPIO controller available with
+       Freescale/NXP's MXC architecture.
+
+endmenu
diff --git a/kernel/drivers/gpio/Makefile b/kernel/drivers/gpio/Makefile
new file mode 100644
index 0000000..5d194a1
--- /dev/null
+++ b/kernel/drivers/gpio/Makefile
@@ -0,0 +1,7 @@
+
+obj-$(CONFIG_XENO_DRIVERS_GPIO) += xeno_gpio.o
+
+xeno_gpio-y := gpio-core.o
+
+xeno_gpio-$(CONFIG_XENO_DRIVERS_GPIO_BCM2708) += gpio-bcm2708.o
+xeno_gpio-$(CONFIG_XENO_DRIVERS_GPIO_MXC) += gpio-mxc.o
diff --git a/kernel/drivers/gpio/gpio-bcm2708.c 
b/kernel/drivers/gpio/gpio-bcm2708.c
new file mode 100644
index 0000000..2b5b6ac
--- /dev/null
+++ b/kernel/drivers/gpio/gpio-bcm2708.c
@@ -0,0 +1,39 @@
+/**
+ * @note Copyright (C) 2016 Philippe Gerum <r...@xenomai.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/module.h>
+#include "gpio-core.h"
+
+#define RTDM_SUBCLASS_BCM2708  1
+
+static struct rtdm_gpio_chip bcm2708_gpio_chip;
+
+static int __init bcm2708_gpio_init(void)
+{
+       return rtdm_gpiochip_add_by_name(&bcm2708_gpio_chip, "bcm2708_gpio",
+                                        RTDM_SUBCLASS_BCM2708);
+}
+
+static void __exit bcm2708_gpio_exit(void)
+{
+       rtdm_gpiochip_remove(&bcm2708_gpio_chip);
+}
+
+module_init(bcm2708_gpio_init);
+module_exit(bcm2708_gpio_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/kernel/drivers/gpio/gpio-core.c b/kernel/drivers/gpio/gpio-core.c
new file mode 100644
index 0000000..4f707b8
--- /dev/null
+++ b/kernel/drivers/gpio/gpio-core.c
@@ -0,0 +1,349 @@
+/**
+ * @note Copyright (C) 2016 Philippe Gerum <r...@xenomai.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of_platform.h>
+#include "gpio-core.h"
+
+struct rtdm_gpio_pin {
+       struct rtdm_device dev;
+       struct list_head next;
+       rtdm_irq_t irqh;
+       rtdm_event_t event;
+       char *name;
+       struct gpio_desc *desc;
+};
+
+static int gpio_pin_interrupt(rtdm_irq_t *irqh)
+{
+       struct rtdm_gpio_pin *pin;
+
+       pin = rtdm_irq_get_arg(irqh, struct rtdm_gpio_pin);
+
+       rtdm_event_signal(&pin->event);
+
+       return RTDM_IRQ_HANDLED;
+}
+
+static int request_gpio_irq(unsigned int gpio, struct rtdm_gpio_pin *pin)
+{
+       unsigned int irq;
+       int ret;
+
+       ret = gpio_request(gpio, pin->name);
+       if (ret) {
+               if (ret != -EPROBE_DEFER)
+                       printk(XENO_ERR "cannot request GPIO%d\n", gpio);
+               return ret;
+       }
+
+       ret = gpio_direction_input(gpio);
+       if (ret) {
+               printk(XENO_ERR "cannot set GPIO%d as input\n", gpio);
+               goto fail;
+       }
+
+       gpio_export(gpio, true);
+
+       rtdm_event_clear(&pin->event);
+       irq = gpio_to_irq(gpio);
+       ret = rtdm_irq_request(&pin->irqh, irq, gpio_pin_interrupt,
+                              0, pin->name, pin);
+       if (ret) {
+               printk(XENO_ERR "cannot request GPIO%d interrupt\n", gpio);
+               goto fail;
+       }
+
+       rtdm_irq_enable(&pin->irqh);
+
+       return 0;
+fail:
+       gpio_free(gpio);
+
+       return ret;
+}
+
+static void release_gpio_irq(unsigned int gpio, struct rtdm_gpio_pin *pin)
+{
+       rtdm_irq_free(&pin->irqh);
+       gpio_free(gpio);
+}
+
+static int gpio_pin_ioctl_nrt(struct rtdm_fd *fd,
+                             unsigned int request, void *arg)
+{
+       struct rtdm_device *dev = rtdm_fd_device(fd);
+       unsigned int gpio = rtdm_fd_minor(fd);
+       struct rtdm_gpio_pin *pin;
+       int ret = 0, val;
+       
+       pin = container_of(dev, struct rtdm_gpio_pin, dev);
+
+       switch (request) {
+       case GPIO_RTIOC_DIR_OUT:
+               ret = rtdm_safe_copy_from_user(fd, &val, arg, sizeof(val));
+               if (ret)
+                       return ret;
+               ret = gpio_direction_output(gpio, val);
+               break;
+       case GPIO_RTIOC_DIR_IN:
+               ret = gpio_direction_input(gpio);
+               break;
+       case GPIO_RTIOC_IRQEN:
+               ret = request_gpio_irq(gpio, pin);
+               break;
+       case GPIO_RTIOC_IRQDIS:
+               release_gpio_irq(gpio, pin);
+               break;
+       default:
+               return -EINVAL;
+       }
+       
+       return ret;
+}
+
+static ssize_t gpio_pin_read_rt(struct rtdm_fd *fd,
+                               void __user *buf, size_t len)
+{
+       struct rtdm_device *dev = rtdm_fd_device(fd);
+       struct rtdm_gpio_pin *pin;
+       int value, ret;
+
+       if (len < sizeof(value))
+               return -EINVAL;
+
+       pin = container_of(dev, struct rtdm_gpio_pin, dev);
+       value = gpiod_get_raw_value(pin->desc);
+       ret = rtdm_safe_copy_to_user(fd, buf, &value, sizeof(value));
+       
+       return ret ?: sizeof(value);
+}
+
+static ssize_t gpio_pin_write_rt(struct rtdm_fd *fd,
+                                const void __user *buf, size_t len)
+{
+       struct rtdm_device *dev = rtdm_fd_device(fd);
+       struct rtdm_gpio_pin *pin;
+       int value, ret;
+
+       if (len < sizeof(value))
+               return -EINVAL;
+
+       ret = rtdm_safe_copy_from_user(fd, &value, buf, sizeof(value));
+       if (ret)
+               return ret;
+
+       pin = container_of(dev, struct rtdm_gpio_pin, dev);
+       gpiod_set_raw_value(pin->desc, value);
+
+       return sizeof(value);
+}
+
+static int gpio_pin_select(struct rtdm_fd *fd, struct xnselector *selector,
+                          unsigned int type, unsigned int index)
+{
+       struct rtdm_device *dev = rtdm_fd_device(fd);
+       struct rtdm_gpio_pin *pin;
+
+       pin = container_of(dev, struct rtdm_gpio_pin, dev);
+
+       return rtdm_event_select(&pin->event, selector, type, index);
+}
+
+static void delete_pin_devices(struct rtdm_gpio_chip *rgc)
+{
+       struct rtdm_gpio_pin *pin, *n;
+       struct rtdm_device *dev;
+
+       list_for_each_entry_safe(pin, n, &rgc->pins, next) {
+               list_del(&pin->next);
+               dev = &pin->dev;
+               rtdm_dev_unregister(dev);
+               rtdm_event_destroy(&pin->event);
+               kfree(dev->label);
+               kfree(pin->name);
+               kfree(pin);
+       }
+}
+
+static int create_pin_devices(struct rtdm_gpio_chip *rgc)
+{
+       struct gpio_chip *gc = rgc->gc;
+       struct rtdm_gpio_pin *pin;
+       struct rtdm_device *dev;
+       int n, ret;
+
+       for (n = gc->base; n < gc->base + gc->ngpio - 1; n++) {
+               ret = -ENOMEM;
+               pin = kzalloc(sizeof(*pin), GFP_KERNEL);
+               if (pin == NULL)
+                       goto fail;
+               pin->name = kasprintf(GFP_KERNEL, "gpio%d", n);
+               if (pin->name == NULL)
+                       goto fail_name;
+               pin->desc = gpio_to_desc(n);
+               if (pin->desc == NULL) {
+                       ret = -ENODEV;
+                       goto fail_desc;
+               }
+               dev = &pin->dev;
+               dev->driver = &rgc->driver;
+               dev->label = kasprintf(GFP_KERNEL, "%s/gpio%%d", gc->label);
+               if (dev->label == NULL)
+                       goto fail_label;
+               dev->minor = n;
+               dev->device_data = rgc;
+               ret = rtdm_dev_register(dev);
+               if (ret)
+                       goto fail_register;
+               rtdm_event_init(&pin->event, 0);
+               list_add_tail(&pin->next, &rgc->pins);
+       }
+
+       return 0;
+
+fail_register:
+       kfree(dev->label);
+fail_desc:
+fail_label:
+       kfree(pin->name);
+fail_name:
+       kfree(pin);
+fail:
+       delete_pin_devices(rgc);
+
+       return ret;
+}
+
+static char *gpio_pin_devnode(struct device *dev, umode_t *mode)
+{
+       return kasprintf(GFP_KERNEL, "rtdm/%s/%s",
+                        dev->class->name,
+                        dev_name(dev));
+}
+
+int rtdm_gpiochip_add(struct rtdm_gpio_chip *rgc,
+                     struct gpio_chip *gc, int gpio_subclass)
+{
+       int ret;
+
+       if (!realtime_core_enabled())
+               return 0;
+
+       rgc->devclass = class_create(gc->owner, gc->label);
+       if (IS_ERR(rgc->devclass)) {
+               printk(XENO_ERR "cannot create sysfs class\n");
+               return PTR_ERR(rgc->devclass);
+       }
+       rgc->devclass->devnode = gpio_pin_devnode;
+
+       rgc->driver.profile_info = (struct rtdm_profile_info)
+               RTDM_PROFILE_INFO(rtdm_gpio_chip,
+                                 RTDM_CLASS_GPIO,
+                                 gpio_subclass,
+                                 0);
+       rgc->driver.device_flags = RTDM_NAMED_DEVICE|RTDM_FIXED_MINOR;
+       rgc->driver.base_minor = gc->base;
+       rgc->driver.device_count = gc->ngpio;
+       rgc->driver.context_size = 0;
+       rgc->driver.ops = (struct rtdm_fd_ops){
+               .ioctl_nrt      =       gpio_pin_ioctl_nrt,
+               .read_rt        =       gpio_pin_read_rt,
+               .write_rt       =       gpio_pin_write_rt,
+               .select         =       gpio_pin_select,
+       };
+       
+       rtdm_drv_set_sysclass(&rgc->driver, rgc->devclass);
+
+       rgc->gc = gc;
+       INIT_LIST_HEAD(&rgc->pins);
+
+       ret = create_pin_devices(rgc);
+       if (ret)
+               class_destroy(rgc->devclass);
+       
+       return ret;
+}
+EXPORT_SYMBOL_GPL(rtdm_gpiochip_add);
+
+void rtdm_gpiochip_remove(struct rtdm_gpio_chip *rgc)
+{
+       if (!realtime_core_enabled())
+               return;
+
+       delete_pin_devices(rgc);
+       class_destroy(rgc->devclass);
+}
+EXPORT_SYMBOL_GPL(rtdm_gpiochip_remove);
+
+static int gpiochip_match_name(struct gpio_chip *chip, void *data)
+{
+       const char *name = data;
+
+       return !strcmp(chip->label, name);
+}
+
+static struct gpio_chip *find_chip_by_name(const char *name)
+{
+       return gpiochip_find((void *)name, gpiochip_match_name);
+}
+
+int rtdm_gpiochip_add_by_name(struct rtdm_gpio_chip *rgc,
+                             const char *label, int gpio_subclass)
+{
+       struct gpio_chip *gc = find_chip_by_name(label);
+
+       if (gc == NULL)
+               return -EPROBE_DEFER;
+
+       return rtdm_gpiochip_add(rgc, gc, gpio_subclass);
+}
+EXPORT_SYMBOL_GPL(rtdm_gpiochip_add_by_name);
+
+int rtdm_gpiochip_scan_of(struct device_node *from, const char *compat,
+                         int (*match)(struct gpio_chip *gc))
+{
+       struct device_node *np = from;
+       struct platform_device *pdev;
+       int ret = -EPROBE_DEFER;
+       struct gpio_chip *gc;
+
+       for (;;) {
+               np = of_find_compatible_node(np, NULL, compat);
+               if (np == NULL)
+                       break;
+               pdev = of_find_device_by_node(np);
+               of_node_put(np);
+               if (pdev == NULL)
+                       return -ENODEV;
+               gc = find_chip_by_name(dev_name(&pdev->dev));
+               if (gc) {
+                       ret = match(gc);
+                       if (ret)
+                               break;
+               }
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(rtdm_gpiochip_scan_of);
diff --git a/kernel/drivers/gpio/gpio-core.h b/kernel/drivers/gpio/gpio-core.h
new file mode 100644
index 0000000..3fa7867
--- /dev/null
+++ b/kernel/drivers/gpio/gpio-core.h
@@ -0,0 +1,48 @@
+/**
+ * @note Copyright (C) 2016 Philippe Gerum <r...@xenomai.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef _RTDM_GPIO_CORE_H
+#define _RTDM_GPIO_CORE_H
+
+#include <linux/list.h>
+#include <rtdm/driver.h>
+#include <rtdm/uapi/gpio.h>
+
+struct class;
+struct device_node;
+
+struct rtdm_gpio_chip {
+       struct gpio_chip *gc;
+       struct rtdm_driver driver;
+       struct class *devclass;
+       struct list_head pins;
+       struct list_head next;
+};
+
+int rtdm_gpiochip_add(struct rtdm_gpio_chip *rgc,
+                     struct gpio_chip *gc,
+                     int gpio_subclass);
+
+void rtdm_gpiochip_remove(struct rtdm_gpio_chip *rgc);
+
+int rtdm_gpiochip_add_by_name(struct rtdm_gpio_chip *rgc,
+                             const char *label, int gpio_subclass);
+
+int rtdm_gpiochip_scan_of(struct device_node *from, const char *compat,
+                         int (*match)(struct gpio_chip *gc));
+
+#endif /* !_RTDM_GPIO_CORE_H */
diff --git a/kernel/drivers/gpio/gpio-mxc.c b/kernel/drivers/gpio/gpio-mxc.c
new file mode 100644
index 0000000..808cd54
--- /dev/null
+++ b/kernel/drivers/gpio/gpio-mxc.c
@@ -0,0 +1,67 @@
+/**
+ * @note Copyright (C) 2016 Philippe Gerum <r...@xenomai.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include "gpio-core.h"
+
+#define RTDM_SUBCLASS_MXC  2
+
+static LIST_HEAD(mxc_gpio_chips);
+
+static int match_gpio_chip(struct gpio_chip *gc)
+{
+       struct rtdm_gpio_chip *rgc;
+       int ret;
+       
+       rgc = kzalloc(sizeof(*rgc), GFP_KERNEL);
+       if (rgc == NULL)
+               return -ENOMEM;
+
+       ret = rtdm_gpiochip_add(rgc, gc, RTDM_SUBCLASS_MXC);
+       if (ret) {
+               kfree(rgc);
+               return ret;
+       }
+
+       list_add(&rgc->next, &mxc_gpio_chips);
+
+       return 0;
+}
+
+static int __init mxc_gpio_init(void)
+{
+       return rtdm_gpiochip_scan_of(NULL, "fsl,imx6q-gpio", match_gpio_chip);
+}
+
+static void __exit mxc_gpio_exit(void)
+{
+       struct rtdm_gpio_chip *rgc, *n;
+
+       list_for_each_entry_safe(rgc, n, &mxc_gpio_chips, next) {
+               list_del(&rgc->next);
+               rtdm_gpiochip_remove(rgc);
+               kfree(rgc);
+       }
+}
+
+module_init(mxc_gpio_init);
+module_exit(mxc_gpio_exit);
+
+MODULE_LICENSE("GPL");


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
https://xenomai.org/mailman/listinfo/xenomai-git

Reply via email to