diff options
Diffstat (limited to 'drivers/iio/trigger/iio-trig-interrupt.c')
| -rw-r--r-- | drivers/iio/trigger/iio-trig-interrupt.c | 121 | 
1 files changed, 121 insertions, 0 deletions
diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c new file mode 100644 index 00000000000..02577ec54c6 --- /dev/null +++ b/drivers/iio/trigger/iio-trig-interrupt.c @@ -0,0 +1,121 @@ +/* + * Industrial I/O - generic interrupt based trigger support + * + * Copyright (c) 2008-2013 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. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/slab.h> + +#include <linux/iio/iio.h> +#include <linux/iio/trigger.h> + + +struct iio_interrupt_trigger_info { +	unsigned int irq; +}; + +static irqreturn_t iio_interrupt_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_interrupt_trigger_ops = { +	.owner = THIS_MODULE, +}; + +static int iio_interrupt_trigger_probe(struct platform_device *pdev) +{ +	struct iio_interrupt_trigger_info *trig_info; +	struct iio_trigger *trig; +	unsigned long irqflags; +	struct resource *irq_res; +	int irq, ret = 0; + +	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + +	if (irq_res == NULL) +		return -ENODEV; + +	irqflags = (irq_res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED; + +	irq = irq_res->start; + +	trig = iio_trigger_alloc("irqtrig%d", irq); +	if (!trig) { +		ret = -ENOMEM; +		goto error_ret; +	} + +	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_interrupt_trigger_ops; +	ret = request_irq(irq, iio_interrupt_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; +	platform_set_drvdata(pdev, trig); + +	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_ret: +	return ret; +} + +static int iio_interrupt_trigger_remove(struct platform_device *pdev) +{ +	struct iio_trigger *trig; +	struct iio_interrupt_trigger_info *trig_info; + +	trig = platform_get_drvdata(pdev); +	trig_info = iio_trigger_get_drvdata(trig); +	iio_trigger_unregister(trig); +	free_irq(trig_info->irq, trig); +	kfree(trig_info); +	iio_trigger_put(trig); + +	return 0; +} + +static struct platform_driver iio_interrupt_trigger_driver = { +	.probe = iio_interrupt_trigger_probe, +	.remove = iio_interrupt_trigger_remove, +	.driver = { +		.name = "iio_interrupt_trigger", +		.owner = THIS_MODULE, +	}, +}; + +module_platform_driver(iio_interrupt_trigger_driver); + +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); +MODULE_DESCRIPTION("Interrupt trigger for the iio subsystem"); +MODULE_LICENSE("GPL v2");  | 
