]>
Commit | Line | Data |
---|---|---|
930bae86 JC |
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 that a fully | |
11 | * fledged trigger driver. | |
12 | * | |
13 | * TODO: | |
14 | * | |
15 | * Add board config elements to allow specification of startup settings. | |
16 | * Add configuration settings (irq type etc) | |
17 | */ | |
18 | ||
19 | #include <linux/kernel.h> | |
20 | #include <linux/module.h> | |
21 | #include <linux/platform_device.h> | |
22 | #include <linux/interrupt.h> | |
23 | #include <linux/gpio.h> | |
5a0e3ad6 | 24 | #include <linux/slab.h> |
930bae86 JC |
25 | |
26 | #include "../iio.h" | |
27 | #include "../trigger.h" | |
28 | ||
29 | LIST_HEAD(iio_gpio_trigger_list); | |
30 | DEFINE_MUTEX(iio_gpio_trigger_list_lock); | |
31 | ||
32 | struct iio_gpio_trigger_info { | |
33 | struct mutex in_use; | |
34 | int gpio; | |
35 | }; | |
36 | /* | |
37 | * Need to reference count these triggers and only enable gpio interrupts | |
38 | * as appropriate. | |
39 | */ | |
40 | ||
41 | /* So what functionality do we want in here?... */ | |
42 | /* set high / low as interrupt type? */ | |
43 | ||
44 | static irqreturn_t iio_gpio_trigger_poll(int irq, void *private) | |
45 | { | |
46 | iio_trigger_poll(private); | |
47 | return IRQ_HANDLED; | |
48 | } | |
49 | ||
2fdec576 | 50 | static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); |
930bae86 JC |
51 | |
52 | static struct attribute *iio_gpio_trigger_attrs[] = { | |
53 | &dev_attr_name.attr, | |
54 | NULL, | |
55 | }; | |
56 | ||
57 | static const struct attribute_group iio_gpio_trigger_attr_group = { | |
58 | .attrs = iio_gpio_trigger_attrs, | |
59 | }; | |
60 | ||
61 | static int iio_gpio_trigger_probe(struct platform_device *dev) | |
62 | { | |
63 | int *pdata = dev->dev.platform_data; | |
64 | struct iio_gpio_trigger_info *trig_info; | |
65 | struct iio_trigger *trig, *trig2; | |
66 | int i, irq, ret = 0; | |
67 | if (!pdata) { | |
68 | printk(KERN_ERR "No IIO gpio trigger platform data found\n"); | |
69 | goto error_ret; | |
70 | } | |
71 | for (i = 0;; i++) { | |
72 | if (!gpio_is_valid(pdata[i])) | |
73 | break; | |
74 | trig = iio_allocate_trigger(); | |
75 | if (!trig) { | |
76 | ret = -ENOMEM; | |
77 | goto error_free_completed_registrations; | |
78 | } | |
79 | ||
80 | trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL); | |
81 | if (!trig_info) { | |
82 | ret = -ENOMEM; | |
83 | goto error_put_trigger; | |
84 | } | |
85 | trig->control_attrs = &iio_gpio_trigger_attr_group; | |
86 | trig->private_data = trig_info; | |
87 | trig_info->gpio = pdata[i]; | |
88 | trig->owner = THIS_MODULE; | |
89 | trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL); | |
90 | if (!trig->name) { | |
91 | ret = -ENOMEM; | |
92 | goto error_free_trig_info; | |
93 | } | |
94 | snprintf((char *)trig->name, | |
95 | IIO_TRIGGER_NAME_LENGTH, | |
96 | "gpiotrig%d", | |
97 | pdata[i]); | |
98 | ret = gpio_request(trig_info->gpio, trig->name); | |
99 | if (ret) | |
100 | goto error_free_name; | |
101 | ||
102 | ret = gpio_direction_input(trig_info->gpio); | |
103 | if (ret) | |
104 | goto error_release_gpio; | |
105 | ||
106 | irq = gpio_to_irq(trig_info->gpio); | |
107 | if (irq < 0) { | |
108 | ret = irq; | |
109 | goto error_release_gpio; | |
110 | } | |
111 | ||
112 | ret = request_irq(irq, iio_gpio_trigger_poll, | |
113 | IRQF_TRIGGER_RISING, | |
114 | trig->name, | |
115 | trig); | |
116 | if (ret) | |
117 | goto error_release_gpio; | |
118 | ||
119 | ret = iio_trigger_register(trig); | |
120 | if (ret) | |
121 | goto error_release_irq; | |
122 | ||
123 | list_add_tail(&trig->alloc_list, &iio_gpio_trigger_list); | |
124 | ||
125 | } | |
126 | return 0; | |
127 | ||
128 | /* First clean up the partly allocated trigger */ | |
129 | error_release_irq: | |
130 | free_irq(irq, trig); | |
131 | error_release_gpio: | |
132 | gpio_free(trig_info->gpio); | |
133 | error_free_name: | |
134 | kfree(trig->name); | |
135 | error_free_trig_info: | |
136 | kfree(trig_info); | |
137 | error_put_trigger: | |
138 | iio_put_trigger(trig); | |
139 | error_free_completed_registrations: | |
140 | /* The rest should have been added to the iio_gpio_trigger_list */ | |
141 | list_for_each_entry_safe(trig, | |
142 | trig2, | |
143 | &iio_gpio_trigger_list, | |
144 | alloc_list) { | |
145 | trig_info = trig->private_data; | |
146 | free_irq(gpio_to_irq(trig_info->gpio), trig); | |
147 | gpio_free(trig_info->gpio); | |
148 | kfree(trig->name); | |
149 | kfree(trig_info); | |
150 | iio_trigger_unregister(trig); | |
151 | } | |
152 | ||
153 | error_ret: | |
154 | return ret; | |
155 | } | |
156 | ||
157 | static int iio_gpio_trigger_remove(struct platform_device *dev) | |
158 | { | |
159 | struct iio_trigger *trig, *trig2; | |
160 | struct iio_gpio_trigger_info *trig_info; | |
161 | ||
162 | mutex_lock(&iio_gpio_trigger_list_lock); | |
163 | list_for_each_entry_safe(trig, | |
164 | trig2, | |
165 | &iio_gpio_trigger_list, | |
166 | alloc_list) { | |
167 | trig_info = trig->private_data; | |
168 | iio_trigger_unregister(trig); | |
169 | free_irq(gpio_to_irq(trig_info->gpio), trig); | |
170 | gpio_free(trig_info->gpio); | |
171 | kfree(trig->name); | |
172 | kfree(trig_info); | |
173 | iio_put_trigger(trig); | |
174 | } | |
175 | mutex_unlock(&iio_gpio_trigger_list_lock); | |
176 | ||
177 | return 0; | |
178 | } | |
179 | ||
180 | static struct platform_driver iio_gpio_trigger_driver = { | |
181 | .probe = iio_gpio_trigger_probe, | |
182 | .remove = iio_gpio_trigger_remove, | |
183 | .driver = { | |
184 | .name = "iio_gpio_trigger", | |
185 | .owner = THIS_MODULE, | |
186 | }, | |
187 | }; | |
188 | ||
189 | static int __init iio_gpio_trig_init(void) | |
190 | { | |
191 | return platform_driver_register(&iio_gpio_trigger_driver); | |
192 | } | |
193 | module_init(iio_gpio_trig_init); | |
194 | ||
195 | static void __exit iio_gpio_trig_exit(void) | |
196 | { | |
197 | platform_driver_unregister(&iio_gpio_trigger_driver); | |
198 | } | |
199 | module_exit(iio_gpio_trig_exit); | |
200 | ||
201 | MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); | |
202 | MODULE_DESCRIPTION("Example gpio trigger for the iio subsystem"); | |
203 | MODULE_LICENSE("GPL v2"); |