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 18 struct iio_interrupt_trigger_info { 19 unsigned int irq; 20 }; 21 22 static irqreturn_t iio_interrupt_trigger_poll(int irq, void *private) 23 { 24 iio_trigger_poll(private); 25 return IRQ_HANDLED; 26 } 27 28 static const struct iio_trigger_ops iio_interrupt_trigger_ops = { 29 }; 30 31 static 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(NULL, "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 */ 78 error_release_irq: 79 free_irq(irq, trig); 80 error_free_trig_info: 81 kfree(trig_info); 82 error_free_trigger: 83 iio_trigger_free(trig); 84 error_ret: 85 return ret; 86 } 87 88 static 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 103 static 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 111 module_platform_driver(iio_interrupt_trigger_driver); 112 113 MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); 114 MODULE_DESCRIPTION("Interrupt trigger for the iio subsystem"); 115 MODULE_LICENSE("GPL v2"); 116