Merge branch 'for-linus' of git://git.kernel.dk/linux-block
[pandora-kernel.git] / drivers / staging / iio / trigger / iio-trig-gpio.c
1 /*
2  * Industrial I/O - gpio based trigger support
3  *
4  * Copyright (c) 2008 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  * Currently this is more of a functioning proof of concept than a full
11  * fledged trigger driver.
12  *
13  * TODO:
14  *
15  * Add board config elements to allow specification of startup settings.
16  */
17
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <linux/interrupt.h>
22 #include <linux/gpio.h>
23 #include <linux/slab.h>
24
25 #include "../iio.h"
26 #include "../trigger.h"
27
28 static LIST_HEAD(iio_gpio_trigger_list);
29 static DEFINE_MUTEX(iio_gpio_trigger_list_lock);
30
31 struct iio_gpio_trigger_info {
32         struct mutex in_use;
33         unsigned int irq;
34 };
35 /*
36  * Need to reference count these triggers and only enable gpio interrupts
37  * as appropriate.
38  */
39
40 /* So what functionality do we want in here?... */
41 /* set high / low as interrupt type? */
42
43 static irqreturn_t iio_gpio_trigger_poll(int irq, void *private)
44 {
45         /* Timestamp not currently provided */
46         iio_trigger_poll(private, 0);
47         return IRQ_HANDLED;
48 }
49
50 static int iio_gpio_trigger_probe(struct platform_device *pdev)
51 {
52         struct iio_gpio_trigger_info *trig_info;
53         struct iio_trigger *trig, *trig2;
54         unsigned long irqflags;
55         struct resource *irq_res;
56         int irq, ret = 0, irq_res_cnt = 0;
57
58         do {
59                 irq_res = platform_get_resource(pdev,
60                                 IORESOURCE_IRQ, irq_res_cnt);
61
62                 if (irq_res == NULL) {
63                         if (irq_res_cnt == 0)
64                                 dev_err(&pdev->dev, "No GPIO IRQs specified");
65                         break;
66                 }
67                 irqflags = (irq_res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED;
68
69                 for (irq = irq_res->start; irq <= irq_res->end; irq++) {
70
71                         trig = iio_allocate_trigger("irqtrig%d", irq);
72                         if (!trig) {
73                                 ret = -ENOMEM;
74                                 goto error_free_completed_registrations;
75                         }
76
77                         trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL);
78                         if (!trig_info) {
79                                 ret = -ENOMEM;
80                                 goto error_put_trigger;
81                         }
82                         trig->private_data = trig_info;
83                         trig_info->irq = irq;
84                         trig->owner = THIS_MODULE;
85                         ret = request_irq(irq, iio_gpio_trigger_poll,
86                                           irqflags, trig->name, trig);
87                         if (ret) {
88                                 dev_err(&pdev->dev,
89                                         "request IRQ-%d failed", irq);
90                                 goto error_free_trig_info;
91                         }
92
93                         ret = iio_trigger_register(trig);
94                         if (ret)
95                                 goto error_release_irq;
96
97                         list_add_tail(&trig->alloc_list,
98                                         &iio_gpio_trigger_list);
99                 }
100
101                 irq_res_cnt++;
102         } while (irq_res != NULL);
103
104
105         return 0;
106
107 /* First clean up the partly allocated trigger */
108 error_release_irq:
109         free_irq(irq, trig);
110 error_free_trig_info:
111         kfree(trig_info);
112 error_put_trigger:
113         iio_put_trigger(trig);
114 error_free_completed_registrations:
115         /* The rest should have been added to the iio_gpio_trigger_list */
116         list_for_each_entry_safe(trig,
117                                  trig2,
118                                  &iio_gpio_trigger_list,
119                                  alloc_list) {
120                 trig_info = trig->private_data;
121                 free_irq(gpio_to_irq(trig_info->irq), trig);
122                 kfree(trig_info);
123                 iio_trigger_unregister(trig);
124         }
125
126         return ret;
127 }
128
129 static int iio_gpio_trigger_remove(struct platform_device *pdev)
130 {
131         struct iio_trigger *trig, *trig2;
132         struct iio_gpio_trigger_info *trig_info;
133
134         mutex_lock(&iio_gpio_trigger_list_lock);
135         list_for_each_entry_safe(trig,
136                                  trig2,
137                                  &iio_gpio_trigger_list,
138                                  alloc_list) {
139                 trig_info = trig->private_data;
140                 iio_trigger_unregister(trig);
141                 free_irq(trig_info->irq, trig);
142                 kfree(trig_info);
143                 iio_put_trigger(trig);
144         }
145         mutex_unlock(&iio_gpio_trigger_list_lock);
146
147         return 0;
148 }
149
150 static struct platform_driver iio_gpio_trigger_driver = {
151         .probe = iio_gpio_trigger_probe,
152         .remove = iio_gpio_trigger_remove,
153         .driver = {
154                 .name = "iio_gpio_trigger",
155                 .owner = THIS_MODULE,
156         },
157 };
158
159 static int __init iio_gpio_trig_init(void)
160 {
161         return platform_driver_register(&iio_gpio_trigger_driver);
162 }
163 module_init(iio_gpio_trig_init);
164
165 static void __exit iio_gpio_trig_exit(void)
166 {
167         platform_driver_unregister(&iio_gpio_trigger_driver);
168 }
169 module_exit(iio_gpio_trig_exit);
170
171 MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
172 MODULE_DESCRIPTION("Example gpio trigger for the iio subsystem");
173 MODULE_LICENSE("GPL v2");