diff options
author | Jonathan Cameron <jic23@cam.ac.uk> | 2009-08-18 18:06:31 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-09-15 12:02:25 -0700 |
commit | 930bae8667c100d727360c0fa0df0378af9097ea (patch) | |
tree | 32f4ac6ac1a813c633a88e5837034c029bb0e52b /drivers | |
parent | 7f3a1fb998e11a45d14556cc17f72d4f8aa89732 (diff) |
Staging: IIO: Proof of concept gpio trigger
Simple example of how a gpio trigger driver would work.
Things to be added include interupt type control (high, low).
Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/iio/trigger/Kconfig | 6 | ||||
-rw-r--r-- | drivers/staging/iio/trigger/Makefile | 2 | ||||
-rw-r--r-- | drivers/staging/iio/trigger/iio-trig-gpio.c | 202 |
3 files changed, 209 insertions, 1 deletions
diff --git a/drivers/staging/iio/trigger/Kconfig b/drivers/staging/iio/trigger/Kconfig index 05ed139e153..fdd9301271a 100644 --- a/drivers/staging/iio/trigger/Kconfig +++ b/drivers/staging/iio/trigger/Kconfig @@ -12,4 +12,10 @@ config IIO_PERIODIC_RTC_TRIGGER Provides support for using periodic capable real time clocks as IIO triggers. +config IIO_GPIO_TRIGGER + tristate "GPIO trigger" + depends on GENERIC_GPIO + help + Provides support for using GPIO pins as IIO triggers. + endif # IIO_TRIGGER diff --git a/drivers/staging/iio/trigger/Makefile b/drivers/staging/iio/trigger/Makefile index 4ae55b9abae..e5f96d2fe64 100644 --- a/drivers/staging/iio/trigger/Makefile +++ b/drivers/staging/iio/trigger/Makefile @@ -2,4 +2,4 @@ # Makefile for triggers not associated with iio-devices # obj-$(CONFIG_IIO_PERIODIC_RTC_TRIGGER) += iio-trig-periodic-rtc.o - +obj-$(CONFIG_IIO_GPIO_TRIGGER) += iio-trig-gpio.o
\ No newline at end of file diff --git a/drivers/staging/iio/trigger/iio-trig-gpio.c b/drivers/staging/iio/trigger/iio-trig-gpio.c new file mode 100644 index 00000000000..0b3b43ebee6 --- /dev/null +++ b/drivers/staging/iio/trigger/iio-trig-gpio.c @@ -0,0 +1,202 @@ +/* + * Industrial I/O - gpio based trigger support + * + * Copyright (c) 2008 Jonathan Cameron + * + * 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. + * + * Currently this is more of a functioning proof of concept that a fully + * fledged trigger driver. + * + * TODO: + * + * Add board config elements to allow specification of startup settings. + * Add configuration settings (irq type etc) + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/gpio.h> + +#include "../iio.h" +#include "../trigger.h" + +LIST_HEAD(iio_gpio_trigger_list); +DEFINE_MUTEX(iio_gpio_trigger_list_lock); + +struct iio_gpio_trigger_info { + struct mutex in_use; + int gpio; +}; +/* + * Need to reference count these triggers and only enable gpio interrupts + * as appropriate. + */ + +/* So what functionality do we want in here?... */ +/* set high / low as interrupt type? */ + +static irqreturn_t iio_gpio_trigger_poll(int irq, void *private) +{ + iio_trigger_poll(private); + return IRQ_HANDLED; +} + +DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); + +static struct attribute *iio_gpio_trigger_attrs[] = { + &dev_attr_name.attr, + NULL, +}; + +static const struct attribute_group iio_gpio_trigger_attr_group = { + .attrs = iio_gpio_trigger_attrs, +}; + +static int iio_gpio_trigger_probe(struct platform_device *dev) +{ + int *pdata = dev->dev.platform_data; + struct iio_gpio_trigger_info *trig_info; + struct iio_trigger *trig, *trig2; + int i, irq, ret = 0; + if (!pdata) { + printk(KERN_ERR "No IIO gpio trigger platform data found\n"); + goto error_ret; + } + for (i = 0;; i++) { + if (!gpio_is_valid(pdata[i])) + break; + trig = iio_allocate_trigger(); + if (!trig) { + ret = -ENOMEM; + goto error_free_completed_registrations; + } + + trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL); + if (!trig_info) { + ret = -ENOMEM; + goto error_put_trigger; + } + trig->control_attrs = &iio_gpio_trigger_attr_group; + trig->private_data = trig_info; + trig_info->gpio = pdata[i]; + trig->owner = THIS_MODULE; + trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); + if (!trig->name) { + ret = -ENOMEM; + goto error_free_trig_info; + } + snprintf((char *)trig->name, + IIO_TRIGGER_NAME_LENGTH, + "gpiotrig%d", + pdata[i]); + ret = gpio_request(trig_info->gpio, trig->name); + if (ret) + goto error_free_name; + + ret = gpio_direction_input(trig_info->gpio); + if (ret) + goto error_release_gpio; + + irq = gpio_to_irq(trig_info->gpio); + if (irq < 0) { + ret = irq; + goto error_release_gpio; + } + + ret = request_irq(irq, iio_gpio_trigger_poll, + IRQF_TRIGGER_RISING, + trig->name, + trig); + if (ret) + goto error_release_gpio; + + ret = iio_trigger_register(trig); + if (ret) + goto error_release_irq; + + list_add_tail(&trig->alloc_list, &iio_gpio_trigger_list); + + } + return 0; + +/* First clean up the partly allocated trigger */ +error_release_irq: + free_irq(irq, trig); +error_release_gpio: + gpio_free(trig_info->gpio); +error_free_name: + kfree(trig->name); +error_free_trig_info: + kfree(trig_info); +error_put_trigger: + iio_put_trigger(trig); +error_free_completed_registrations: + /* The rest should have been added to the iio_gpio_trigger_list */ + list_for_each_entry_safe(trig, + trig2, + &iio_gpio_trigger_list, + alloc_list) { + trig_info = trig->private_data; + free_irq(gpio_to_irq(trig_info->gpio), trig); + gpio_free(trig_info->gpio); + kfree(trig->name); + kfree(trig_info); + iio_trigger_unregister(trig); + } + +error_ret: + return ret; +} + +static int iio_gpio_trigger_remove(struct platform_device *dev) +{ + struct iio_trigger *trig, *trig2; + struct iio_gpio_trigger_info *trig_info; + + mutex_lock(&iio_gpio_trigger_list_lock); + list_for_each_entry_safe(trig, + trig2, + &iio_gpio_trigger_list, + alloc_list) { + trig_info = trig->private_data; + iio_trigger_unregister(trig); + free_irq(gpio_to_irq(trig_info->gpio), trig); + gpio_free(trig_info->gpio); + kfree(trig->name); + kfree(trig_info); + iio_put_trigger(trig); + } + mutex_unlock(&iio_gpio_trigger_list_lock); + + return 0; +} + +static struct platform_driver iio_gpio_trigger_driver = { + .probe = iio_gpio_trigger_probe, + .remove = iio_gpio_trigger_remove, + .driver = { + .name = "iio_gpio_trigger", + .owner = THIS_MODULE, + }, +}; + +static int __init iio_gpio_trig_init(void) +{ + return platform_driver_register(&iio_gpio_trigger_driver); +} +module_init(iio_gpio_trig_init); + +static void __exit iio_gpio_trig_exit(void) +{ + platform_driver_unregister(&iio_gpio_trigger_driver); +} +module_exit(iio_gpio_trig_exit); + +MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); +MODULE_DESCRIPTION("Example gpio trigger for the iio subsystem"); +MODULE_LICENSE("GPL v2"); |