On Thu, 20 Sep 2007 18:00:53 +0200, Matteo Croce <technoboy85@xxxxxxxxx> wrote: > Char device to access GPIO pins > > Signed-off-by: Matteo Croce <technoboy85@xxxxxxxxx> > Signed-off-by: Nicolas Thill <nico@xxxxxxxxxxx> This driver is almost platform independent. The only platform-specific part is its name and AR7_GPIO_MAX. It would be great if this driver was really "generic" and could be used with any GPIO API providers. I think there were some discussions about userspace API for GPIO on LKML, but cannot remember the detail. David, give us a comment please? > diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig > index b391776..b98aedf 100644 > --- a/drivers/char/Kconfig > +++ b/drivers/char/Kconfig > @@ -928,6 +928,15 @@ config MWAVE > To compile this driver as a module, choose M here: the > module will be called mwave. > > +config AR7_GPIO > + tristate "TI AR7 GPIO Support" > + depends on AR7 > + help > + Give userspace access to the GPIO pins on the Texas Instruments AR7 > + processors. > + > + If compiled as a module, it will be called ar7_gpio. > + > config SCx200_GPIO > tristate "NatSemi SCx200 GPIO Support" > depends on SCx200 > diff --git a/drivers/char/Makefile b/drivers/char/Makefile > index d68ddbe..804319e 100644 > --- a/drivers/char/Makefile > +++ b/drivers/char/Makefile > @@ -89,6 +89,7 @@ obj-$(CONFIG_COBALT_LCD) += lcd.o > obj-$(CONFIG_PPDEV) += ppdev.o > obj-$(CONFIG_NWBUTTON) += nwbutton.o > obj-$(CONFIG_NWFLASH) += nwflash.o > +obj-$(CONFIG_AR7_GPIO) += ar7_gpio.o > obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o > obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o > obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o > diff --git a/drivers/char/ar7_gpio.c b/drivers/char/ar7_gpio.c > new file mode 100644 > index 0000000..d57a23e > --- /dev/null > +++ b/drivers/char/ar7_gpio.c > @@ -0,0 +1,158 @@ > +/* > + * Copyright (C) 2007 Nicolas Thill <nico@xxxxxxxxxxx> > + * > + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#include <linux/device.h> > +#include <linux/fs.h> > +#include <linux/module.h> > +#include <linux/errno.h> > +#include <linux/kernel.h> > +#include <linux/init.h> > +#include <linux/platform_device.h> > +#include <linux/uaccess.h> > +#include <linux/io.h> > +#include <linux/types.h> > +#include <linux/cdev.h> > +#include <gpio.h> This should be "#include <asm/gpio.h>". > + > +#define DRVNAME "ar7_gpio" > +#define LONGNAME "TI AR7 GPIOs Driver" > + > +MODULE_AUTHOR("Nicolas Thill <nico@xxxxxxxxxxx>"); > +MODULE_DESCRIPTION(LONGNAME); > +MODULE_LICENSE("GPL"); > + > +static int ar7_gpio_major; > + > +static ssize_t ar7_gpio_write(struct file *file, const char __user *buf, > + size_t len, loff_t *ppos) > +{ > + int pin = iminor(file->f_dentry->d_inode); > + size_t i; > + > + for (i = 0; i < len; ++i) { > + char c; > + if (get_user(c, buf + i)) > + return -EFAULT; > + switch (c) { > + case '0': > + gpio_set_value(pin, 0); > + break; > + case '1': > + gpio_set_value(pin, 1); > + break; > + case 'd': > + case 'D': > + ar7_gpio_disable(pin); > + break; > + case 'e': > + case 'E': > + ar7_gpio_enable(pin); > + break; > + case 'i': > + case 'I': > + case '<': > + gpio_direction_input(pin); > + break; > + case 'o': > + case 'O': > + case '>': > + gpio_direction_output(pin); > + break; > + default: > + return -EINVAL; > + } > + } > + > + return len; > +} > + > +static ssize_t ar7_gpio_read(struct file *file, char __user *buf, > + size_t len, loff_t *ppos) > +{ > + int pin = iminor(file->f_dentry->d_inode); > + int value; > + > + value = gpio_get_value(pin); > + if (put_user(value ? '1' : '0', buf)) > + return -EFAULT; > + > + return 1; > +} > + > +static int ar7_gpio_open(struct inode *inode, struct file *file) > +{ > + int m = iminor(inode); > + > + if (m >= AR7_GPIO_MAX) > + return -EINVAL; > + > + return nonseekable_open(inode, file); > +} > + > +static int ar7_gpio_release(struct inode *inode, struct file *file) > +{ > + return 0; > +} > + > +static const struct file_operations ar7_gpio_fops = { > + .owner = THIS_MODULE, > + .write = ar7_gpio_write, > + .read = ar7_gpio_read, > + .open = ar7_gpio_open, > + .release = ar7_gpio_release, > + .llseek = no_llseek, > +}; > + > +static struct platform_device *ar7_gpio_device; > + > +static int __init ar7_gpio_init(void) > +{ > + int rc; > + > + ar7_gpio_device = platform_device_alloc(DRVNAME, -1); > + if (!ar7_gpio_device) > + return -ENOMEM; > + > + rc = platform_device_add(ar7_gpio_device); > + if (rc < 0) > + goto out_put; > + > + rc = register_chrdev(ar7_gpio_major, DRVNAME, &ar7_gpio_fops); > + if (rc < 0) > + goto out_put; > + > + ar7_gpio_major = rc; > + > + rc = 0; > + > + goto out; > + > +out_put: > + platform_device_put(ar7_gpio_device); > +out: > + return rc; > +} > + > +static void __exit ar7_gpio_exit(void) > +{ > + unregister_chrdev(ar7_gpio_major, DRVNAME); > + platform_device_unregister(ar7_gpio_device); > +} > + > +module_init(ar7_gpio_init); > +module_exit(ar7_gpio_exit); --- Atsushi Nemoto