parent
2d61e4c580
commit
be2adce709
@ -1,35 +0,0 @@ |
||||
/*
|
||||
* Definitions for the GPIO buttons interface driver |
||||
* |
||||
* Copyright (C) 2007,2008 Gabor Juhos <juhosg at openwrt.org> |
||||
* |
||||
* This file was based on: /include/linux/gpio_keys.h |
||||
* The original gpio_keys.h seems not to have a license. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef _GPIO_BUTTONS_H_ |
||||
#define _GPIO_BUTTONS_H_ |
||||
|
||||
struct gpio_button { |
||||
int gpio; /* GPIO line number */ |
||||
int active_low; |
||||
char *desc; /* button description */ |
||||
int type; /* input event type (EV_KEY, EV_SW) */ |
||||
int code; /* input event code (KEY_*, SW_*) */ |
||||
int count; |
||||
int threshold; /* count threshold */ |
||||
}; |
||||
|
||||
struct gpio_buttons_platform_data { |
||||
struct gpio_button *buttons; |
||||
int nbuttons; /* number of buttons */ |
||||
int poll_interval; /* polling interval */ |
||||
}; |
||||
|
||||
#endif /* _GPIO_BUTTONS_H_ */ |
||||
|
@ -1,11 +0,0 @@ |
||||
#ifndef _GPIODEV_H__ |
||||
#define _GPIODEV_H__ |
||||
|
||||
#define IOC_GPIODEV_MAGIC 'B' |
||||
#define GPIO_GET _IO(IOC_GPIODEV_MAGIC, 10) |
||||
#define GPIO_SET _IO(IOC_GPIODEV_MAGIC, 11) |
||||
#define GPIO_CLEAR _IO(IOC_GPIODEV_MAGIC, 12) |
||||
#define GPIO_DIR_IN _IO(IOC_GPIODEV_MAGIC, 13) |
||||
#define GPIO_DIR_OUT _IO(IOC_GPIODEV_MAGIC, 14) |
||||
|
||||
#endif |
@ -1,201 +0,0 @@ |
||||
/*
|
||||
* character device wrapper for generic gpio layer |
||||
* |
||||
* 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, MA02111-1307USA |
||||
* |
||||
* Feedback, Bugs... blogic@openwrt.org |
||||
* |
||||
*/ |
||||
|
||||
#include <linux/module.h> |
||||
#include <linux/errno.h> |
||||
#include <linux/init.h> |
||||
#include <asm/uaccess.h> |
||||
#include <asm/io.h> |
||||
#include <asm/gpio.h> |
||||
#include <asm/atomic.h> |
||||
#include <linux/init.h> |
||||
#include <linux/genhd.h> |
||||
#include <linux/device.h> |
||||
#include <linux/platform_device.h> |
||||
#include <linux/gpio_dev.h> |
||||
|
||||
#define DRVNAME "gpiodev" |
||||
#define DEVNAME "gpio" |
||||
|
||||
static int dev_major; |
||||
static unsigned int gpio_access_mask; |
||||
static struct class *gpiodev_class; |
||||
|
||||
/* Counter is 1, if the device is not opened and zero (or less) if opened. */ |
||||
static atomic_t gpio_open_cnt = ATOMIC_INIT(1); |
||||
|
||||
static int |
||||
gpio_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) |
||||
{ |
||||
int retval = 0; |
||||
|
||||
if (((1 << arg) & gpio_access_mask) != (1 << arg)) |
||||
{ |
||||
retval = -EINVAL; |
||||
goto out; |
||||
} |
||||
|
||||
switch (cmd) |
||||
{ |
||||
case GPIO_GET: |
||||
retval = gpio_get_value(arg); |
||||
break; |
||||
|
||||
case GPIO_SET: |
||||
gpio_set_value(arg, 1); |
||||
break; |
||||
|
||||
case GPIO_CLEAR: |
||||
gpio_set_value(arg, 0); |
||||
break; |
||||
|
||||
case GPIO_DIR_IN: |
||||
gpio_direction_input(arg); |
||||
break; |
||||
|
||||
case GPIO_DIR_OUT: |
||||
gpio_direction_output(arg, 0); |
||||
break; |
||||
|
||||
default: |
||||
retval = -EINVAL; |
||||
break; |
||||
} |
||||
|
||||
out: |
||||
return retval; |
||||
} |
||||
|
||||
static int |
||||
gpio_open(struct inode *inode, struct file *file) |
||||
{ |
||||
int result = 0; |
||||
unsigned int dev_minor = MINOR(inode->i_rdev); |
||||
|
||||
if (dev_minor != 0) |
||||
{ |
||||
printk(KERN_ERR DRVNAME ": trying to access unknown minor device -> %d\n", dev_minor); |
||||
result = -ENODEV; |
||||
goto out; |
||||
} |
||||
|
||||
/* FIXME: We should really allow multiple applications to open the device
|
||||
* at the same time, as long as the apps access different IO pins. |
||||
* The generic gpio-registration functions can be used for that. |
||||
* Two new IOCTLs have to be introduced for that. Need to check userspace |
||||
* compatibility first. --mb */ |
||||
if (!atomic_dec_and_test(&gpio_open_cnt)) { |
||||
atomic_inc(&gpio_open_cnt); |
||||
printk(KERN_ERR DRVNAME ": Device with minor ID %d already in use\n", dev_minor); |
||||
result = -EBUSY; |
||||
goto out; |
||||
} |
||||
|
||||
out: |
||||
return result; |
||||
} |
||||
|
||||
static int |
||||
gpio_close(struct inode * inode, struct file * file) |
||||
{ |
||||
smp_mb__before_atomic_inc(); |
||||
atomic_inc(&gpio_open_cnt); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
struct file_operations gpio_fops = { |
||||
ioctl: gpio_ioctl, |
||||
open: gpio_open, |
||||
release: gpio_close |
||||
}; |
||||
|
||||
static int |
||||
gpio_probe(struct platform_device *dev) |
||||
{ |
||||
int result = 0; |
||||
|
||||
dev_major = register_chrdev(0, DEVNAME, &gpio_fops); |
||||
if (!dev_major) |
||||
{ |
||||
printk(KERN_ERR DRVNAME ": Error whilst opening %s \n", DEVNAME); |
||||
result = -ENODEV; |
||||
goto out; |
||||
} |
||||
|
||||
gpiodev_class = class_create(THIS_MODULE, DRVNAME); |
||||
device_create(gpiodev_class, NULL, MKDEV(dev_major, 0), dev, DEVNAME); |
||||
|
||||
printk(KERN_INFO DRVNAME ": gpio device registered with major %d\n", dev_major); |
||||
|
||||
if (dev->num_resources != 1) |
||||
{ |
||||
printk(KERN_ERR DRVNAME ": device may only have 1 resource\n"); |
||||
result = -ENODEV; |
||||
goto out; |
||||
} |
||||
|
||||
gpio_access_mask = dev->resource[0].start; |
||||
|
||||
printk(KERN_INFO DRVNAME ": gpio platform device registered with access mask %08X\n", gpio_access_mask); |
||||
out: |
||||
return result; |
||||
} |
||||
|
||||
static int |
||||
gpio_remove(struct platform_device *dev) |
||||
{ |
||||
unregister_chrdev(dev_major, DEVNAME); |
||||
return 0; |
||||
} |
||||
|
||||
static struct |
||||
platform_driver gpio_driver = { |
||||
.probe = gpio_probe, |
||||
.remove = gpio_remove, |
||||
.driver = { |
||||
.name = "GPIODEV", |
||||
.owner = THIS_MODULE, |
||||
}, |
||||
}; |
||||
|
||||
static int __init |
||||
gpio_mod_init(void) |
||||
{ |
||||
int ret = platform_driver_register(&gpio_driver); |
||||
if (ret) |
||||
printk(KERN_INFO DRVNAME ": Error registering platfom driver!"); |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
static void __exit |
||||
gpio_mod_exit(void) |
||||
{ |
||||
platform_driver_unregister(&gpio_driver); |
||||
} |
||||
|
||||
module_init (gpio_mod_init); |
||||
module_exit (gpio_mod_exit); |
||||
|
||||
MODULE_LICENSE("GPL"); |
||||
MODULE_AUTHOR("John Crispin / OpenWrt"); |
||||
MODULE_DESCRIPTION("Character device for for generic gpio api"); |
@ -1,209 +0,0 @@ |
||||
/*
|
||||
* Driver for buttons on GPIO lines not capable of generating interrupts |
||||
* |
||||
* Copyright (C) 2007,2008 Gabor Juhos <juhosg at openwrt.org> |
||||
* |
||||
* This file was based on: /drivers/input/misc/cobalt_btns.c |
||||
* Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> |
||||
* |
||||
* also was based on: /drivers/input/keyboard/gpio_keys.c |
||||
* Copyright 2005 Phil Blundell |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
* |
||||
*/ |
||||
|
||||
#include <linux/kernel.h> |
||||
#include <linux/module.h> |
||||
#include <linux/init.h> |
||||
|
||||
#include <linux/input.h> |
||||
#include <linux/input-polldev.h> |
||||
#include <linux/ioport.h> |
||||
#include <linux/platform_device.h> |
||||
|
||||
#include <linux/gpio_buttons.h> |
||||
|
||||
#include <asm/gpio.h> |
||||
|
||||
#define DRV_NAME "gpio-buttons" |
||||
#define DRV_VERSION "0.1.1" |
||||
#define PFX DRV_NAME ": " |
||||
|
||||
struct gpio_buttons_dev { |
||||
struct input_polled_dev *poll_dev; |
||||
struct gpio_buttons_platform_data *pdata; |
||||
}; |
||||
|
||||
static void gpio_buttons_poll(struct input_polled_dev *dev) |
||||
{ |
||||
struct gpio_buttons_dev *bdev = dev->private; |
||||
struct gpio_buttons_platform_data *pdata = bdev->pdata; |
||||
struct input_dev *input = dev->input; |
||||
int i; |
||||
|
||||
for (i = 0; i < bdev->pdata->nbuttons; i++) { |
||||
struct gpio_button *button = &pdata->buttons[i]; |
||||
unsigned int type = button->type ?: EV_KEY; |
||||
int state; |
||||
|
||||
state = gpio_get_value(button->gpio) ? 1 : 0; |
||||
state ^= button->active_low; |
||||
|
||||
if (state) { |
||||
button->count++; |
||||
} else { |
||||
if (button->count >= button->threshold) { |
||||
input_event(input, type, button->code, 1); |
||||
input_sync(input); |
||||
} |
||||
button->count = 0; |
||||
} |
||||
|
||||
if (button->count == button->threshold) { |
||||
input_event(input, type, button->code, 0); |
||||
input_sync(input); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static int __devinit gpio_buttons_probe(struct platform_device *pdev) |
||||
{ |
||||
struct gpio_buttons_platform_data *pdata = pdev->dev.platform_data; |
||||
struct gpio_buttons_dev *bdev; |
||||
struct input_polled_dev *poll_dev; |
||||
struct input_dev *input; |
||||
int error, i; |
||||
|
||||
|
||||
if (!pdata) |
||||
return -ENXIO; |
||||
|
||||
bdev = kzalloc(sizeof(*bdev), GFP_KERNEL); |
||||
if (!bdev) { |
||||
printk(KERN_ERR DRV_NAME "no memory for device\n"); |
||||
return -ENOMEM; |
||||
} |
||||
|
||||
poll_dev = input_allocate_polled_device(); |
||||
if (!poll_dev) { |
||||
printk(KERN_ERR DRV_NAME "no memory for polled device\n"); |
||||
error = -ENOMEM; |
||||
goto err_free_bdev; |
||||
} |
||||
|
||||
poll_dev->private = bdev; |
||||
poll_dev->poll = gpio_buttons_poll; |
||||
poll_dev->poll_interval = pdata->poll_interval; |
||||
|
||||
input = poll_dev->input; |
||||
|
||||
input->evbit[0] = BIT(EV_KEY); |
||||
input->name = pdev->name; |
||||
input->phys = "gpio-buttons/input0"; |
||||
input->dev.parent = &pdev->dev; |
||||
|
||||
input->id.bustype = BUS_HOST; |
||||
input->id.vendor = 0x0001; |
||||
input->id.product = 0x0001; |
||||
input->id.version = 0x0100; |
||||
|
||||
for (i = 0; i < pdata->nbuttons; i++) { |
||||
struct gpio_button *button = &pdata->buttons[i]; |
||||
unsigned int gpio = button->gpio; |
||||
unsigned int type = button->type ?: EV_KEY; |
||||
|
||||
error = gpio_request(gpio, button->desc ? |
||||
button->desc : DRV_NAME); |
||||
if (error) { |
||||
printk(KERN_ERR PFX "unable to claim gpio %u, " |
||||
"error %d\n", gpio, error); |
||||
goto err_free_gpio; |
||||
} |
||||
|
||||
error = gpio_direction_input(gpio); |
||||
if (error) { |
||||
printk(KERN_ERR PFX "unable to set direction on " |
||||
"gpio %u, error %d\n", gpio, error); |
||||
goto err_free_gpio; |
||||
} |
||||
|
||||
input_set_capability(input, type, button->code); |
||||
button->count = 0; |
||||
} |
||||
|
||||
bdev->poll_dev = poll_dev; |
||||
bdev->pdata = pdata; |
||||
platform_set_drvdata(pdev, bdev); |
||||
|
||||
error = input_register_polled_device(poll_dev); |
||||
if (error) { |
||||
printk(KERN_ERR PFX "unable to register polled device, " |
||||
"error %d\n", error); |
||||
goto err_free_gpio; |
||||
} |
||||
|
||||
return 0; |
||||
|
||||
err_free_gpio: |
||||
for (i = i - 1; i >= 0; i--) |
||||
gpio_free(pdata->buttons[i].gpio); |
||||
|
||||
input_free_polled_device(poll_dev); |
||||
|
||||
err_free_bdev: |
||||
kfree(bdev); |
||||
|
||||
platform_set_drvdata(pdev, NULL); |
||||
return error; |
||||
} |
||||
|
||||
static int __devexit gpio_buttons_remove(struct platform_device *pdev) |
||||
{ |
||||
struct gpio_buttons_dev *bdev = platform_get_drvdata(pdev); |
||||
struct gpio_buttons_platform_data *pdata = bdev->pdata; |
||||
int i; |
||||
|
||||
input_unregister_polled_device(bdev->poll_dev); |
||||
|
||||
for (i = 0; i < pdata->nbuttons; i++) |
||||
gpio_free(pdata->buttons[i].gpio); |
||||
|
||||
input_free_polled_device(bdev->poll_dev); |
||||
|
||||
kfree(bdev); |
||||
platform_set_drvdata(pdev, NULL); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static struct platform_driver gpio_buttons_driver = { |
||||
.probe = gpio_buttons_probe, |
||||
.remove = __devexit_p(gpio_buttons_remove), |
||||
.driver = { |
||||
.name = DRV_NAME, |
||||
.owner = THIS_MODULE, |
||||
}, |
||||
}; |
||||
|
||||
static int __init gpio_buttons_init(void) |
||||
{ |
||||
printk(KERN_INFO DRV_NAME " driver version " DRV_VERSION "\n"); |
||||
return platform_driver_register(&gpio_buttons_driver); |
||||
} |
||||
|
||||
static void __exit gpio_buttons_exit(void) |
||||
{ |
||||
platform_driver_unregister(&gpio_buttons_driver); |
||||
} |
||||
|
||||
module_init(gpio_buttons_init); |
||||
module_exit(gpio_buttons_exit); |
||||
|
||||
MODULE_LICENSE("GPL"); |
||||
MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>"); |
||||
MODULE_VERSION(DRV_VERSION); |
||||
MODULE_DESCRIPTION("Polled buttons driver for CPU GPIOs"); |
||||
|
@ -1,35 +0,0 @@ |
||||
/*
|
||||
* Definitions for the GPIO buttons interface driver |
||||
* |
||||
* Copyright (C) 2007,2008 Gabor Juhos <juhosg at openwrt.org> |
||||
* |
||||
* This file was based on: /include/linux/gpio_keys.h |
||||
* The original gpio_keys.h seems not to have a license. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef _GPIO_BUTTONS_H_ |
||||
#define _GPIO_BUTTONS_H_ |
||||
|
||||
struct gpio_button { |
||||
int gpio; /* GPIO line number */ |
||||
int active_low; |
||||
char *desc; /* button description */ |
||||
int type; /* input event type (EV_KEY, EV_SW) */ |
||||
int code; /* input event code (KEY_*, SW_*) */ |
||||
int count; |
||||
int threshold; /* count threshold */ |
||||
}; |
||||
|
||||
struct gpio_buttons_platform_data { |
||||
struct gpio_button *buttons; |
||||
int nbuttons; /* number of buttons */ |
||||
int poll_interval; /* polling interval */ |
||||
}; |
||||
|
||||
#endif /* _GPIO_BUTTONS_H_ */ |
||||
|
@ -1,11 +0,0 @@ |
||||
#ifndef _GPIODEV_H__ |
||||
#define _GPIODEV_H__ |
||||
|
||||
#define IOC_GPIODEV_MAGIC 'B' |
||||
#define GPIO_GET _IO(IOC_GPIODEV_MAGIC, 10) |
||||
#define GPIO_SET _IO(IOC_GPIODEV_MAGIC, 11) |
||||
#define GPIO_CLEAR _IO(IOC_GPIODEV_MAGIC, 12) |
||||
#define GPIO_DIR_IN _IO(IOC_GPIODEV_MAGIC, 13) |
||||
#define GPIO_DIR_OUT _IO(IOC_GPIODEV_MAGIC, 14) |
||||
|
||||
#endif |
Loading…
Reference in new issue