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 int iio_interrupt_trigger_probe(struct platform_device *pdev) 29 { 30 struct iio_interrupt_trigger_info *trig_info; 31 struct iio_trigger *trig; 32 unsigned long irqflags; 33 struct resource *irq_res; 34 int irq, ret = 0; 35 36 irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 37 38 if (irq_res == NULL) 39 return -ENODEV; 40 41 irqflags = (irq_res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED; 42 43 irq = irq_res->start; 44 45 trig = iio_trigger_alloc(NULL, "irqtrig%d", irq); 46 if (!trig) { 47 ret = -ENOMEM; 48 goto error_ret; 49 } 50 51 trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL); 52 if (!trig_info) { 53 ret = -ENOMEM; 54 goto error_free_trigger; 55 } 56 iio_trigger_set_drvdata(trig, trig_info); 57 trig_info->irq = irq; 58 ret = request_irq(irq, iio_interrupt_trigger_poll, 59 irqflags, trig->name, trig); 60 if (ret) { 61 dev_err(&pdev->dev, 62 "request IRQ-%d failed", irq); 63 goto error_free_trig_info; 64 } 65 66 ret = iio_trigger_register(trig); 67 if (ret) 68 goto error_release_irq; 69 platform_set_drvdata(pdev, trig); 70 71 return 0; 72 73 /* First clean up the partly allocated trigger */ 74 error_release_irq: 75 free_irq(irq, trig); 76 error_free_trig_info: 77 kfree(trig_info); 78 error_free_trigger: 79 iio_trigger_free(trig); 80 error_ret: 81 return ret; 82 } 83 84 static int iio_interrupt_trigger_remove(struct platform_device *pdev) 85 { 86 struct iio_trigger *trig; 87 struct iio_interrupt_trigger_info *trig_info; 88 89 trig = platform_get_drvdata(pdev); 90 trig_info = iio_trigger_get_drvdata(trig); 91 iio_trigger_unregister(trig); 92 free_irq(trig_info->irq, trig); 93 kfree(trig_info); 94 iio_trigger_free(trig); 95 96 return 0; 97 } 98 99 static struct platform_driver iio_interrupt_trigger_driver = { 100 .probe = iio_interrupt_trigger_probe, 101 .remove = iio_interrupt_trigger_remove, 102 .driver = { 103 .name = "iio_interrupt_trigger", 104 }, 105 }; 106 107 module_platform_driver(iio_interrupt_trigger_driver); 108 109 MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); 110 MODULE_DESCRIPTION("Interrupt trigger for the iio subsystem"); 111 MODULE_LICENSE("GPL v2"); 112