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