diff options
| author | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
| commit | 8e4bff4cab0ddac6060645b0715210484d02ff40 (patch) | |
| tree | 3a5c3024371a04692a3a6d9974d001cdff8ebf84 /drivers/staging/iio/trigger/iio-trig-gpio.c | |
Diffstat (limited to 'drivers/staging/iio/trigger/iio-trig-gpio.c')
| -rw-r--r-- | drivers/staging/iio/trigger/iio-trig-gpio.c | 167 |
1 files changed, 167 insertions, 0 deletions
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 00000000..7c593d18 --- /dev/null +++ b/drivers/staging/iio/trigger/iio-trig-gpio.c @@ -0,0 +1,167 @@ +/* + * 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 than a full + * fledged trigger driver. + * + * TODO: + * + * Add board config elements to allow specification of startup settings. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <linux/slab.h> + +#include <linux/iio/iio.h> +#include <linux/iio/trigger.h> + +static LIST_HEAD(iio_gpio_trigger_list); +static DEFINE_MUTEX(iio_gpio_trigger_list_lock); + +struct iio_gpio_trigger_info { + struct mutex in_use; + unsigned int irq; +}; +/* + * 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) +{ + /* Timestamp not currently provided */ + iio_trigger_poll(private, 0); + return IRQ_HANDLED; +} + +static const struct iio_trigger_ops iio_gpio_trigger_ops = { + .owner = THIS_MODULE, +}; + +static int iio_gpio_trigger_probe(struct platform_device *pdev) +{ + struct iio_gpio_trigger_info *trig_info; + struct iio_trigger *trig, *trig2; + unsigned long irqflags; + struct resource *irq_res; + int irq, ret = 0, irq_res_cnt = 0; + + do { + irq_res = platform_get_resource(pdev, + IORESOURCE_IRQ, irq_res_cnt); + + if (irq_res == NULL) { + if (irq_res_cnt == 0) + dev_err(&pdev->dev, "No GPIO IRQs specified"); + break; + } + irqflags = (irq_res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED; + + for (irq = irq_res->start; irq <= irq_res->end; irq++) { + + trig = iio_trigger_alloc("irqtrig%d", irq); + 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; + } + iio_trigger_set_drvdata(trig, trig_info); + trig_info->irq = irq; + trig->ops = &iio_gpio_trigger_ops; + ret = request_irq(irq, iio_gpio_trigger_poll, + irqflags, trig->name, trig); + if (ret) { + dev_err(&pdev->dev, + "request IRQ-%d failed", irq); + goto error_free_trig_info; + } + + ret = iio_trigger_register(trig); + if (ret) + goto error_release_irq; + + list_add_tail(&trig->alloc_list, + &iio_gpio_trigger_list); + } + + irq_res_cnt++; + } while (irq_res != NULL); + + + return 0; + +/* First clean up the partly allocated trigger */ +error_release_irq: + free_irq(irq, trig); +error_free_trig_info: + kfree(trig_info); +error_put_trigger: + iio_trigger_put(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 = iio_trigger_get_drvdata(trig); + free_irq(gpio_to_irq(trig_info->irq), trig); + kfree(trig_info); + iio_trigger_unregister(trig); + } + + return ret; +} + +static int iio_gpio_trigger_remove(struct platform_device *pdev) +{ + 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 = iio_trigger_get_drvdata(trig); + iio_trigger_unregister(trig); + free_irq(trig_info->irq, trig); + kfree(trig_info); + iio_trigger_put(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, + }, +}; + +module_platform_driver(iio_gpio_trigger_driver); + +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); +MODULE_DESCRIPTION("Example gpio trigger for the iio subsystem"); +MODULE_LICENSE("GPL v2"); |
