1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Industrial I/O - generic interrupt based trigger support 4 * 5 * Copyright (c) 2008-2013 Jonathan Cameron 6 */ 7 8#include <linux/kernel.h> 9#include <linux/module.h> 10#include <linux/platform_device.h> 11#include <linux/interrupt.h> 12#include <linux/slab.h> 13 14#include <linux/iio/iio.h> 15#include <linux/iio/trigger.h> 16 17 18struct iio_interrupt_trigger_info { 19 unsigned int irq; 20}; 21 22static irqreturn_t iio_interrupt_trigger_poll(int irq, void *private) 23{ 24 iio_trigger_poll(private); 25 return IRQ_HANDLED; 26} 27 28static const struct iio_trigger_ops iio_interrupt_trigger_ops = { 29}; 30 31static int iio_interrupt_trigger_probe(struct platform_device *pdev) 32{ 33 struct iio_interrupt_trigger_info *trig_info; 34 struct iio_trigger *trig; 35 unsigned long irqflags; 36 struct resource *irq_res; 37 int irq, ret = 0; 38 39 irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 40 41 if (irq_res == NULL) 42 return -ENODEV; 43 44 irqflags = (irq_res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED; 45 46 irq = irq_res->start; 47 48 trig = iio_trigger_alloc("irqtrig%d", irq); 49 if (!trig) { 50 ret = -ENOMEM; 51 goto error_ret; 52 } 53 54 trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL); 55 if (!trig_info) { 56 ret = -ENOMEM; 57 goto error_free_trigger; 58 } 59 iio_trigger_set_drvdata(trig, trig_info); 60 trig_info->irq = irq; 61 trig->ops = &iio_interrupt_trigger_ops; 62 ret = request_irq(irq, iio_interrupt_trigger_poll, 63 irqflags, trig->name, trig); 64 if (ret) { 65 dev_err(&pdev->dev, 66 "request IRQ-%d failed", irq); 67 goto error_free_trig_info; 68 } 69 70 ret = iio_trigger_register(trig); 71 if (ret) 72 goto error_release_irq; 73 platform_set_drvdata(pdev, trig); 74 75 return 0; 76 77/* First clean up the partly allocated trigger */ 78error_release_irq: 79 free_irq(irq, trig); 80error_free_trig_info: 81 kfree(trig_info); 82error_free_trigger: 83 iio_trigger_free(trig); 84error_ret: 85 return ret; 86} 87 88static int iio_interrupt_trigger_remove(struct platform_device *pdev) 89{ 90 struct iio_trigger *trig; 91 struct iio_interrupt_trigger_info *trig_info; 92 93 trig = platform_get_drvdata(pdev); 94 trig_info = iio_trigger_get_drvdata(trig); 95 iio_trigger_unregister(trig); 96 free_irq(trig_info->irq, trig); 97 kfree(trig_info); 98 iio_trigger_free(trig); 99 100 return 0; 101} 102 103static struct platform_driver iio_interrupt_trigger_driver = { 104 .probe = iio_interrupt_trigger_probe, 105 .remove = iio_interrupt_trigger_remove, 106 .driver = { 107 .name = "iio_interrupt_trigger", 108 }, 109}; 110 111module_platform_driver(iio_interrupt_trigger_driver); 112 113MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); 114MODULE_DESCRIPTION("Interrupt trigger for the iio subsystem"); 115MODULE_LICENSE("GPL v2"); 116