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