Commit 80c99bcd28617bd534b6f9489857235ee613c797
Committed by
Dmitry Torokhov
1 parent
ce91953782
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
Input: rotary-encoder - add DT bindings
This adds devicetree bindings to the rotary encoder driver and some documentation about how to use them. Tested on a PXA3xx platform. Signed-off-by: Daniel Mack <zonque@gmail.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Showing 2 changed files with 116 additions and 16 deletions Side-by-side Diff
Documentation/devicetree/bindings/input/rotary-encoder.txt
1 | +Rotary encoder DT bindings | |
2 | + | |
3 | +Required properties: | |
4 | +- gpios: a spec for two GPIOs to be used | |
5 | + | |
6 | +Optional properties: | |
7 | +- linux,axis: the input subsystem axis to map to this rotary encoder. | |
8 | + Defaults to 0 (ABS_X / REL_X) | |
9 | +- rotary-encoder,steps: Number of steps in a full turnaround of the | |
10 | + encoder. Only relevant for absolute axis. Defaults to 24 which is a | |
11 | + typical value for such devices. | |
12 | +- rotary-encoder,relative-axis: register a relative axis rather than an | |
13 | + absolute one. Relative axis will only generate +1/-1 events on the input | |
14 | + device, hence no steps need to be passed. | |
15 | +- rotary-encoder,rollover: Automatic rollove when the rotary value becomes | |
16 | + greater than the specified steps or smaller than 0. For absolute axis only. | |
17 | +- rotary-encoder,half-period: Makes the driver work on half-period mode. | |
18 | + | |
19 | +See Documentation/input/rotary-encoder.txt for more information. | |
20 | + | |
21 | +Example: | |
22 | + | |
23 | + rotary@0 { | |
24 | + compatible = "rotary-encoder"; | |
25 | + gpios = <&gpio 19 1>, <&gpio 20 0>; /* GPIO19 is inverted */ | |
26 | + linux,axis = <0>; /* REL_X */ | |
27 | + rotary-encoder,relative-axis; | |
28 | + }; | |
29 | + | |
30 | + rotary@1 { | |
31 | + compatible = "rotary-encoder"; | |
32 | + gpios = <&gpio 21 0>, <&gpio 22 0>; | |
33 | + linux,axis = <1>; /* ABS_Y */ | |
34 | + rotary-encoder,steps = <24>; | |
35 | + rotary-encoder,rollover; | |
36 | + }; |
drivers/input/misc/rotary_encoder.c
... | ... | @@ -24,6 +24,8 @@ |
24 | 24 | #include <linux/gpio.h> |
25 | 25 | #include <linux/rotary_encoder.h> |
26 | 26 | #include <linux/slab.h> |
27 | +#include <linux/of_platform.h> | |
28 | +#include <linux/of_gpio.h> | |
27 | 29 | |
28 | 30 | #define DRV_NAME "rotary-encoder" |
29 | 31 | |
... | ... | @@ -140,6 +142,56 @@ |
140 | 142 | return IRQ_HANDLED; |
141 | 143 | } |
142 | 144 | |
145 | +#ifdef CONFIG_OF | |
146 | +static struct of_device_id rotary_encoder_of_match[] = { | |
147 | + { .compatible = "rotary-encoder", }, | |
148 | + { }, | |
149 | +}; | |
150 | +MODULE_DEVICE_TABLE(of, rotary_encoder_of_match); | |
151 | + | |
152 | +static struct rotary_encoder_platform_data * __devinit | |
153 | +rotary_encoder_parse_dt(struct device *dev) | |
154 | +{ | |
155 | + const struct of_device_id *of_id = | |
156 | + of_match_device(rotary_encoder_of_match, dev); | |
157 | + struct device_node *np = dev->of_node; | |
158 | + struct rotary_encoder_platform_data *pdata; | |
159 | + enum of_gpio_flags flags; | |
160 | + | |
161 | + if (!of_id || !np) | |
162 | + return NULL; | |
163 | + | |
164 | + pdata = kzalloc(sizeof(struct rotary_encoder_platform_data), | |
165 | + GFP_KERNEL); | |
166 | + if (!pdata) | |
167 | + return ERR_PTR(-ENOMEM); | |
168 | + | |
169 | + of_property_read_u32(np, "rotary-encoder,steps", &pdata->steps); | |
170 | + of_property_read_u32(np, "linux,axis", &pdata->axis); | |
171 | + | |
172 | + pdata->gpio_a = of_get_gpio_flags(np, 0, &flags); | |
173 | + pdata->inverted_a = flags & OF_GPIO_ACTIVE_LOW; | |
174 | + | |
175 | + pdata->gpio_b = of_get_gpio_flags(np, 1, &flags); | |
176 | + pdata->inverted_b = flags & OF_GPIO_ACTIVE_LOW; | |
177 | + | |
178 | + pdata->relative_axis = !!of_get_property(np, | |
179 | + "rotary-encoder,relative-axis", NULL); | |
180 | + pdata->rollover = !!of_get_property(np, | |
181 | + "rotary-encoder,rollover", NULL); | |
182 | + pdata->half_period = !!of_get_property(np, | |
183 | + "rotary-encoder,half-period", NULL); | |
184 | + | |
185 | + return pdata; | |
186 | +} | |
187 | +#else | |
188 | +static inline struct rotary_encoder_platform_data * | |
189 | +rotary_encoder_parse_dt(struct device *dev) | |
190 | +{ | |
191 | + return NULL; | |
192 | +} | |
193 | +#endif | |
194 | + | |
143 | 195 | static int __devinit rotary_encoder_probe(struct platform_device *pdev) |
144 | 196 | { |
145 | 197 | struct device *dev = &pdev->dev; |
146 | 198 | |
... | ... | @@ -150,14 +202,19 @@ |
150 | 202 | int err; |
151 | 203 | |
152 | 204 | if (!pdata) { |
153 | - dev_err(&pdev->dev, "missing platform data\n"); | |
154 | - return -ENOENT; | |
205 | + pdata = rotary_encoder_parse_dt(dev); | |
206 | + if (IS_ERR(pdata)) | |
207 | + return PTR_ERR(pdata); | |
208 | + | |
209 | + if (!pdata) { | |
210 | + dev_err(dev, "missing platform data\n"); | |
211 | + return -EINVAL; | |
212 | + } | |
155 | 213 | } |
156 | 214 | |
157 | 215 | encoder = kzalloc(sizeof(struct rotary_encoder), GFP_KERNEL); |
158 | 216 | input = input_allocate_device(); |
159 | 217 | if (!encoder || !input) { |
160 | - dev_err(&pdev->dev, "failed to allocate memory for device\n"); | |
161 | 218 | err = -ENOMEM; |
162 | 219 | goto exit_free_mem; |
163 | 220 | } |
164 | 221 | |
... | ... | @@ -165,10 +222,9 @@ |
165 | 222 | encoder->input = input; |
166 | 223 | encoder->pdata = pdata; |
167 | 224 | |
168 | - /* create and register the input driver */ | |
169 | 225 | input->name = pdev->name; |
170 | 226 | input->id.bustype = BUS_HOST; |
171 | - input->dev.parent = &pdev->dev; | |
227 | + input->dev.parent = dev; | |
172 | 228 | |
173 | 229 | if (pdata->relative_axis) { |
174 | 230 | input->evbit[0] = BIT_MASK(EV_REL); |
175 | 231 | |
... | ... | @@ -179,17 +235,11 @@ |
179 | 235 | pdata->axis, 0, pdata->steps, 0, 1); |
180 | 236 | } |
181 | 237 | |
182 | - err = input_register_device(input); | |
183 | - if (err) { | |
184 | - dev_err(dev, "failed to register input device\n"); | |
185 | - goto exit_free_mem; | |
186 | - } | |
187 | - | |
188 | 238 | /* request the GPIOs */ |
189 | 239 | err = gpio_request_one(pdata->gpio_a, GPIOF_IN, dev_name(dev)); |
190 | 240 | if (err) { |
191 | 241 | dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_a); |
192 | - goto exit_unregister_input; | |
242 | + goto exit_free_mem; | |
193 | 243 | } |
194 | 244 | |
195 | 245 | err = gpio_request_one(pdata->gpio_b, GPIOF_IN, dev_name(dev)); |
196 | 246 | |
197 | 247 | |
198 | 248 | |
... | ... | @@ -225,22 +275,30 @@ |
225 | 275 | goto exit_free_irq_a; |
226 | 276 | } |
227 | 277 | |
278 | + err = input_register_device(input); | |
279 | + if (err) { | |
280 | + dev_err(dev, "failed to register input device\n"); | |
281 | + goto exit_free_irq_b; | |
282 | + } | |
283 | + | |
228 | 284 | platform_set_drvdata(pdev, encoder); |
229 | 285 | |
230 | 286 | return 0; |
231 | 287 | |
288 | +exit_free_irq_b: | |
289 | + free_irq(encoder->irq_b, encoder); | |
232 | 290 | exit_free_irq_a: |
233 | 291 | free_irq(encoder->irq_a, encoder); |
234 | 292 | exit_free_gpio_b: |
235 | 293 | gpio_free(pdata->gpio_b); |
236 | 294 | exit_free_gpio_a: |
237 | 295 | gpio_free(pdata->gpio_a); |
238 | -exit_unregister_input: | |
239 | - input_unregister_device(input); | |
240 | - input = NULL; /* so we don't try to free it */ | |
241 | 296 | exit_free_mem: |
242 | 297 | input_free_device(input); |
243 | 298 | kfree(encoder); |
299 | + if (!dev_get_platdata(&pdev->dev)) | |
300 | + kfree(pdata); | |
301 | + | |
244 | 302 | return err; |
245 | 303 | } |
246 | 304 | |
247 | 305 | |
248 | 306 | |
... | ... | @@ -253,10 +311,15 @@ |
253 | 311 | free_irq(encoder->irq_b, encoder); |
254 | 312 | gpio_free(pdata->gpio_a); |
255 | 313 | gpio_free(pdata->gpio_b); |
314 | + | |
256 | 315 | input_unregister_device(encoder->input); |
257 | - platform_set_drvdata(pdev, NULL); | |
258 | 316 | kfree(encoder); |
259 | 317 | |
318 | + if (!dev_get_platdata(&pdev->dev)) | |
319 | + kfree(pdata); | |
320 | + | |
321 | + platform_set_drvdata(pdev, NULL); | |
322 | + | |
260 | 323 | return 0; |
261 | 324 | } |
262 | 325 | |
... | ... | @@ -266,6 +329,7 @@ |
266 | 329 | .driver = { |
267 | 330 | .name = DRV_NAME, |
268 | 331 | .owner = THIS_MODULE, |
332 | + .of_match_table = of_match_ptr(rotary_encoder_of_match), | |
269 | 333 | } |
270 | 334 | }; |
271 | 335 | module_platform_driver(rotary_encoder_driver); |