OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From ecc83f926bd3cf3c9e62389494f39a0939949ef3 Mon Sep 17 00:00:00 2001 |
2 | From: Aron Szabo <aron@aron.ws> |
||
3 | Date: Sat, 16 Jun 2012 12:15:55 +0200 |
||
4 | Subject: [PATCH 048/454] lirc: added support for RaspberryPi GPIO |
||
5 | |||
6 | lirc_rpi: Use read_current_timer to determine transmitter delay. Thanks to jjmz and others |
||
7 | See: https://github.com/raspberrypi/linux/issues/525 |
||
8 | |||
9 | lirc: Remove restriction on gpio pins that can be used with lirc |
||
10 | |||
11 | Compute Module, for example could use different pins |
||
12 | |||
13 | lirc_rpi: Add parameter to specify input pin pull |
||
14 | |||
15 | Depending on the connected IR circuitry it might be desirable to change the |
||
16 | gpios internal pull from it pull-down default behaviour. Add a module |
||
17 | parameter to allow the user to set it explicitly. |
||
18 | |||
19 | Signed-off-by: Julian Scheel <julian@jusst.de> |
||
20 | |||
21 | lirc-rpi: Use the higher-level irq control functions |
||
22 | |||
23 | This module used to access the irq_chip methods of the |
||
24 | gpio controller directly, rather than going through the |
||
25 | standard enable_irq/irq_set_irq_type functions. This |
||
26 | caused problems on pinctrl-bcm2835 which only implements |
||
27 | the irq_enable/disable methods and not irq_unmask/mask. |
||
28 | |||
29 | lirc-rpi: Correct the interrupt usage |
||
30 | |||
31 | 1) Correct the use of enable_irq (i.e. don't call it so often) |
||
32 | 2) Correct the shutdown sequence. |
||
33 | 3) Avoid a bcm2708_gpio driver quirk by setting the irq flags earlier |
||
34 | |||
35 | lirc-rpi: use getnstimeofday instead of read_current_timer |
||
36 | |||
37 | read_current_timer isn't guaranteed to return values in |
||
38 | microseconds, and indeed it doesn't on a Pi2. |
||
39 | |||
40 | Issue: linux#827 |
||
41 | |||
42 | lirc-rpi: Add device tree support, and a suitable overlay |
||
43 | |||
44 | The overlay supports DT parameters that match the old module |
||
45 | parameters, except that gpio_in_pull should be set using the |
||
46 | strings "up", "down" or "off". |
||
47 | |||
48 | lirc-rpi: Also support pinctrl-bcm2835 in non-DT mode |
||
49 | |||
50 | fix auto-sense in lirc_rpi driver |
||
51 | |||
52 | On a Raspberry Pi 2, the lirc_rpi driver might receive spurious |
||
53 | interrupts and change it's low-active / high-active setting. |
||
54 | When this happens, the IR remote control stops working. |
||
55 | |||
56 | This patch disables this auto-detection if the 'sense' parameter |
||
57 | was set in the device tree, making the driver robust to such |
||
58 | spurious interrupts. |
||
59 | --- |
||
60 | drivers/staging/media/lirc/Kconfig | 6 + |
||
61 | drivers/staging/media/lirc/Makefile | 1 + |
||
62 | drivers/staging/media/lirc/lirc_rpi.c | 733 ++++++++++++++++++++++++++ |
||
63 | include/linux/platform_data/bcm2708.h | 23 + |
||
64 | 4 files changed, 763 insertions(+) |
||
65 | create mode 100644 drivers/staging/media/lirc/lirc_rpi.c |
||
66 | create mode 100644 include/linux/platform_data/bcm2708.h |
||
67 | |||
68 | --- a/drivers/staging/media/lirc/Kconfig |
||
69 | +++ b/drivers/staging/media/lirc/Kconfig |
||
70 | @@ -12,6 +12,12 @@ menuconfig LIRC_STAGING |
||
71 | |||
72 | if LIRC_STAGING |
||
73 | |||
74 | +config LIRC_RPI |
||
75 | + tristate "Homebrew GPIO Port Receiver/Transmitter for the RaspberryPi" |
||
76 | + depends on LIRC |
||
77 | + help |
||
78 | + Driver for Homebrew GPIO Port Receiver/Transmitter for the RaspberryPi |
||
79 | + |
||
80 | config LIRC_ZILOG |
||
81 | tristate "Zilog/Hauppauge IR Transmitter" |
||
82 | depends on LIRC && I2C |
||
83 | --- a/drivers/staging/media/lirc/Makefile |
||
84 | +++ b/drivers/staging/media/lirc/Makefile |
||
85 | @@ -3,4 +3,5 @@ |
||
86 | |||
87 | # Each configuration option enables a list of files. |
||
88 | |||
89 | +obj-$(CONFIG_LIRC_RPI) += lirc_rpi.o |
||
90 | obj-$(CONFIG_LIRC_ZILOG) += lirc_zilog.o |
||
91 | --- /dev/null |
||
92 | +++ b/drivers/staging/media/lirc/lirc_rpi.c |
||
93 | @@ -0,0 +1,733 @@ |
||
94 | +/* |
||
95 | + * lirc_rpi.c |
||
96 | + * |
||
97 | + * lirc_rpi - Device driver that records pulse- and pause-lengths |
||
98 | + * (space-lengths) (just like the lirc_serial driver does) |
||
99 | + * between GPIO interrupt events on the Raspberry Pi. |
||
100 | + * Lots of code has been taken from the lirc_serial module, |
||
101 | + * so I would like say thanks to the authors. |
||
102 | + * |
||
103 | + * Copyright (C) 2012 Aron Robert Szabo <aron@reon.hu>, |
||
104 | + * Michael Bishop <cleverca22@gmail.com> |
||
105 | + * This program is free software; you can redistribute it and/or modify |
||
106 | + * it under the terms of the GNU General Public License as published by |
||
107 | + * the Free Software Foundation; either version 2 of the License, or |
||
108 | + * (at your option) any later version. |
||
109 | + * |
||
110 | + * This program is distributed in the hope that it will be useful, |
||
111 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
112 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
113 | + * GNU General Public License for more details. |
||
114 | + * |
||
115 | + * You should have received a copy of the GNU General Public License |
||
116 | + * along with this program; if not, write to the Free Software |
||
117 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
118 | + */ |
||
119 | + |
||
120 | +#include <linux/module.h> |
||
121 | +#include <linux/errno.h> |
||
122 | +#include <linux/interrupt.h> |
||
123 | +#include <linux/sched.h> |
||
124 | +#include <linux/kernel.h> |
||
125 | +#include <linux/time.h> |
||
126 | +#include <linux/timex.h> |
||
127 | +#include <linux/timekeeping.h> |
||
128 | +#include <linux/string.h> |
||
129 | +#include <linux/delay.h> |
||
130 | +#include <linux/platform_device.h> |
||
131 | +#include <linux/irq.h> |
||
132 | +#include <linux/spinlock.h> |
||
133 | +#include <media/lirc.h> |
||
134 | +#include <media/lirc_dev.h> |
||
135 | +#include <linux/gpio.h> |
||
136 | +#include <linux/of_platform.h> |
||
137 | +#include <linux/platform_data/bcm2708.h> |
||
138 | + |
||
139 | +#define LIRC_DRIVER_NAME "lirc_rpi" |
||
140 | +#define RBUF_LEN 256 |
||
141 | +#define LIRC_TRANSMITTER_LATENCY 50 |
||
142 | + |
||
143 | +#ifndef MAX_UDELAY_MS |
||
144 | +#define MAX_UDELAY_US 5000 |
||
145 | +#else |
||
146 | +#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) |
||
147 | +#endif |
||
148 | + |
||
149 | +#define dprintk(fmt, args...) \ |
||
150 | + do { \ |
||
151 | + if (debug) \ |
||
152 | + printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ |
||
153 | + fmt, ## args); \ |
||
154 | + } while (0) |
||
155 | + |
||
156 | +/* module parameters */ |
||
157 | + |
||
158 | +/* set the default GPIO input pin */ |
||
159 | +static int gpio_in_pin = 18; |
||
160 | +/* set the default pull behaviour for input pin */ |
||
161 | +static int gpio_in_pull = BCM2708_PULL_DOWN; |
||
162 | +/* set the default GPIO output pin */ |
||
163 | +static int gpio_out_pin = 17; |
||
164 | +/* enable debugging messages */ |
||
165 | +static bool debug; |
||
166 | +/* -1 = auto, 0 = active high, 1 = active low */ |
||
167 | +static int sense = -1; |
||
168 | +/* use softcarrier by default */ |
||
169 | +static bool softcarrier = 1; |
||
170 | +/* 0 = do not invert output, 1 = invert output */ |
||
171 | +static bool invert = 0; |
||
172 | + |
||
173 | +struct gpio_chip *gpiochip; |
||
174 | +static int irq_num; |
||
175 | +static int auto_sense = 1; |
||
176 | + |
||
177 | +/* forward declarations */ |
||
178 | +static long send_pulse(unsigned long length); |
||
179 | +static void send_space(long length); |
||
180 | +static void lirc_rpi_exit(void); |
||
181 | + |
||
182 | +static struct platform_device *lirc_rpi_dev; |
||
183 | +static struct timeval lasttv = { 0, 0 }; |
||
184 | +static struct lirc_buffer rbuf; |
||
185 | +static spinlock_t lock; |
||
186 | + |
||
187 | +/* initialized/set in init_timing_params() */ |
||
188 | +static unsigned int freq = 38000; |
||
189 | +static unsigned int duty_cycle = 50; |
||
190 | +static unsigned long period; |
||
191 | +static unsigned long pulse_width; |
||
192 | +static unsigned long space_width; |
||
193 | + |
||
194 | +static void safe_udelay(unsigned long usecs) |
||
195 | +{ |
||
196 | + while (usecs > MAX_UDELAY_US) { |
||
197 | + udelay(MAX_UDELAY_US); |
||
198 | + usecs -= MAX_UDELAY_US; |
||
199 | + } |
||
200 | + udelay(usecs); |
||
201 | +} |
||
202 | + |
||
203 | +static unsigned long read_current_us(void) |
||
204 | +{ |
||
205 | + struct timespec now; |
||
206 | + getnstimeofday(&now); |
||
207 | + return (now.tv_sec * 1000000) + (now.tv_nsec/1000); |
||
208 | +} |
||
209 | + |
||
210 | +static int init_timing_params(unsigned int new_duty_cycle, |
||
211 | + unsigned int new_freq) |
||
212 | +{ |
||
213 | + if (1000 * 1000000L / new_freq * new_duty_cycle / 100 <= |
||
214 | + LIRC_TRANSMITTER_LATENCY) |
||
215 | + return -EINVAL; |
||
216 | + if (1000 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <= |
||
217 | + LIRC_TRANSMITTER_LATENCY) |
||
218 | + return -EINVAL; |
||
219 | + duty_cycle = new_duty_cycle; |
||
220 | + freq = new_freq; |
||
221 | + period = 1000 * 1000000L / freq; |
||
222 | + pulse_width = period * duty_cycle / 100; |
||
223 | + space_width = period - pulse_width; |
||
224 | + dprintk("in init_timing_params, freq=%d pulse=%ld, " |
||
225 | + "space=%ld\n", freq, pulse_width, space_width); |
||
226 | + return 0; |
||
227 | +} |
||
228 | + |
||
229 | +static long send_pulse_softcarrier(unsigned long length) |
||
230 | +{ |
||
231 | + int flag; |
||
232 | + unsigned long actual, target; |
||
233 | + unsigned long actual_us, initial_us, target_us; |
||
234 | + |
||
235 | + length *= 1000; |
||
236 | + |
||
237 | + actual = 0; target = 0; flag = 0; |
||
238 | + actual_us = read_current_us(); |
||
239 | + |
||
240 | + while (actual < length) { |
||
241 | + if (flag) { |
||
242 | + gpiochip->set(gpiochip, gpio_out_pin, invert); |
||
243 | + target += space_width; |
||
244 | + } else { |
||
245 | + gpiochip->set(gpiochip, gpio_out_pin, !invert); |
||
246 | + target += pulse_width; |
||
247 | + } |
||
248 | + initial_us = actual_us; |
||
249 | + target_us = actual_us + (target - actual) / 1000; |
||
250 | + /* |
||
251 | + * Note - we've checked in ioctl that the pulse/space |
||
252 | + * widths are big enough so that d is > 0 |
||
253 | + */ |
||
254 | + if ((int)(target_us - actual_us) > 0) |
||
255 | + udelay(target_us - actual_us); |
||
256 | + actual_us = read_current_us(); |
||
257 | + actual += (actual_us - initial_us) * 1000; |
||
258 | + flag = !flag; |
||
259 | + } |
||
260 | + return (actual-length) / 1000; |
||
261 | +} |
||
262 | + |
||
263 | +static long send_pulse(unsigned long length) |
||
264 | +{ |
||
265 | + if (length <= 0) |
||
266 | + return 0; |
||
267 | + |
||
268 | + if (softcarrier) { |
||
269 | + return send_pulse_softcarrier(length); |
||
270 | + } else { |
||
271 | + gpiochip->set(gpiochip, gpio_out_pin, !invert); |
||
272 | + safe_udelay(length); |
||
273 | + return 0; |
||
274 | + } |
||
275 | +} |
||
276 | + |
||
277 | +static void send_space(long length) |
||
278 | +{ |
||
279 | + gpiochip->set(gpiochip, gpio_out_pin, invert); |
||
280 | + if (length <= 0) |
||
281 | + return; |
||
282 | + safe_udelay(length); |
||
283 | +} |
||
284 | + |
||
285 | +static void rbwrite(int l) |
||
286 | +{ |
||
287 | + if (lirc_buffer_full(&rbuf)) { |
||
288 | + /* no new signals will be accepted */ |
||
289 | + dprintk("Buffer overrun\n"); |
||
290 | + return; |
||
291 | + } |
||
292 | + lirc_buffer_write(&rbuf, (void *)&l); |
||
293 | +} |
||
294 | + |
||
295 | +static void frbwrite(int l) |
||
296 | +{ |
||
297 | + /* simple noise filter */ |
||
298 | + static int pulse, space; |
||
299 | + static unsigned int ptr; |
||
300 | + |
||
301 | + if (ptr > 0 && (l & PULSE_BIT)) { |
||
302 | + pulse += l & PULSE_MASK; |
||
303 | + if (pulse > 250) { |
||
304 | + rbwrite(space); |
||
305 | + rbwrite(pulse | PULSE_BIT); |
||
306 | + ptr = 0; |
||
307 | + pulse = 0; |
||
308 | + } |
||
309 | + return; |
||
310 | + } |
||
311 | + if (!(l & PULSE_BIT)) { |
||
312 | + if (ptr == 0) { |
||
313 | + if (l > 20000) { |
||
314 | + space = l; |
||
315 | + ptr++; |
||
316 | + return; |
||
317 | + } |
||
318 | + } else { |
||
319 | + if (l > 20000) { |
||
320 | + space += pulse; |
||
321 | + if (space > PULSE_MASK) |
||
322 | + space = PULSE_MASK; |
||
323 | + space += l; |
||
324 | + if (space > PULSE_MASK) |
||
325 | + space = PULSE_MASK; |
||
326 | + pulse = 0; |
||
327 | + return; |
||
328 | + } |
||
329 | + rbwrite(space); |
||
330 | + rbwrite(pulse | PULSE_BIT); |
||
331 | + ptr = 0; |
||
332 | + pulse = 0; |
||
333 | + } |
||
334 | + } |
||
335 | + rbwrite(l); |
||
336 | +} |
||
337 | + |
||
338 | +static irqreturn_t irq_handler(int i, void *blah, struct pt_regs *regs) |
||
339 | +{ |
||
340 | + struct timeval tv; |
||
341 | + long deltv; |
||
342 | + int data; |
||
343 | + int signal; |
||
344 | + |
||
345 | + /* use the GPIO signal level */ |
||
346 | + signal = gpiochip->get(gpiochip, gpio_in_pin); |
||
347 | + |
||
348 | + if (sense != -1) { |
||
349 | + /* get current time */ |
||
350 | + do_gettimeofday(&tv); |
||
351 | + |
||
352 | + /* calc time since last interrupt in microseconds */ |
||
353 | + deltv = tv.tv_sec-lasttv.tv_sec; |
||
354 | + if (tv.tv_sec < lasttv.tv_sec || |
||
355 | + (tv.tv_sec == lasttv.tv_sec && |
||
356 | + tv.tv_usec < lasttv.tv_usec)) { |
||
357 | + printk(KERN_WARNING LIRC_DRIVER_NAME |
||
358 | + ": AIEEEE: your clock just jumped backwards\n"); |
||
359 | + printk(KERN_WARNING LIRC_DRIVER_NAME |
||
360 | + ": %d %d %lx %lx %lx %lx\n", signal, sense, |
||
361 | + tv.tv_sec, lasttv.tv_sec, |
||
362 | + tv.tv_usec, lasttv.tv_usec); |
||
363 | + data = PULSE_MASK; |
||
364 | + } else if (deltv > 15) { |
||
365 | + data = PULSE_MASK; /* really long time */ |
||
366 | + if (!(signal^sense)) { |
||
367 | + /* sanity check */ |
||
368 | + printk(KERN_DEBUG LIRC_DRIVER_NAME |
||
369 | + ": AIEEEE: %d %d %lx %lx %lx %lx\n", |
||
370 | + signal, sense, tv.tv_sec, lasttv.tv_sec, |
||
371 | + tv.tv_usec, lasttv.tv_usec); |
||
372 | + /* |
||
373 | + * detecting pulse while this |
||
374 | + * MUST be a space! |
||
375 | + */ |
||
376 | + if (auto_sense) { |
||
377 | + sense = sense ? 0 : 1; |
||
378 | + } |
||
379 | + } |
||
380 | + } else { |
||
381 | + data = (int) (deltv*1000000 + |
||
382 | + (tv.tv_usec - lasttv.tv_usec)); |
||
383 | + } |
||
384 | + frbwrite(signal^sense ? data : (data|PULSE_BIT)); |
||
385 | + lasttv = tv; |
||
386 | + wake_up_interruptible(&rbuf.wait_poll); |
||
387 | + } |
||
388 | + |
||
389 | + return IRQ_HANDLED; |
||
390 | +} |
||
391 | + |
||
392 | +static int is_right_chip(struct gpio_chip *chip, void *data) |
||
393 | +{ |
||
394 | + dprintk("is_right_chip %s %d\n", chip->label, strcmp(data, chip->label)); |
||
395 | + |
||
396 | + if (strcmp(data, chip->label) == 0) |
||
397 | + return 1; |
||
398 | + return 0; |
||
399 | +} |
||
400 | + |
||
401 | +static inline int read_bool_property(const struct device_node *np, |
||
402 | + const char *propname, |
||
403 | + bool *out_value) |
||
404 | +{ |
||
405 | + u32 value = 0; |
||
406 | + int err = of_property_read_u32(np, propname, &value); |
||
407 | + if (err == 0) |
||
408 | + *out_value = (value != 0); |
||
409 | + return err; |
||
410 | +} |
||
411 | + |
||
412 | +static void read_pin_settings(struct device_node *node) |
||
413 | +{ |
||
414 | + u32 pin; |
||
415 | + int index; |
||
416 | + |
||
417 | + for (index = 0; |
||
418 | + of_property_read_u32_index( |
||
419 | + node, |
||
420 | + "brcm,pins", |
||
421 | + index, |
||
422 | + &pin) == 0; |
||
423 | + index++) { |
||
424 | + u32 function; |
||
425 | + int err; |
||
426 | + err = of_property_read_u32_index( |
||
427 | + node, |
||
428 | + "brcm,function", |
||
429 | + index, |
||
430 | + &function); |
||
431 | + if (err == 0) { |
||
432 | + if (function == 1) /* Output */ |
||
433 | + gpio_out_pin = pin; |
||
434 | + else if (function == 0) /* Input */ |
||
435 | + gpio_in_pin = pin; |
||
436 | + } |
||
437 | + } |
||
438 | +} |
||
439 | + |
||
440 | +static int init_port(void) |
||
441 | +{ |
||
442 | + int i, nlow, nhigh; |
||
443 | + struct device_node *node; |
||
444 | + |
||
445 | + node = lirc_rpi_dev->dev.of_node; |
||
446 | + |
||
447 | + gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip); |
||
448 | + |
||
449 | + /* |
||
450 | + * Because of the lack of a setpull function, only support |
||
451 | + * pinctrl-bcm2835 if using device tree. |
||
452 | + */ |
||
453 | + if (!gpiochip && node) |
||
454 | + gpiochip = gpiochip_find("pinctrl-bcm2835", is_right_chip); |
||
455 | + |
||
456 | + if (!gpiochip) { |
||
457 | + pr_err(LIRC_DRIVER_NAME ": gpio chip not found!\n"); |
||
458 | + return -ENODEV; |
||
459 | + } |
||
460 | + |
||
461 | + if (node) { |
||
462 | + struct device_node *pins_node; |
||
463 | + |
||
464 | + pins_node = of_parse_phandle(node, "pinctrl-0", 0); |
||
465 | + if (!pins_node) { |
||
466 | + printk(KERN_ERR LIRC_DRIVER_NAME |
||
467 | + ": pinctrl settings not found!\n"); |
||
468 | + return -EINVAL; |
||
469 | + } |
||
470 | + |
||
471 | + read_pin_settings(pins_node); |
||
472 | + |
||
473 | + of_property_read_u32(node, "rpi,sense", &sense); |
||
474 | + |
||
475 | + read_bool_property(node, "rpi,softcarrier", &softcarrier); |
||
476 | + |
||
477 | + read_bool_property(node, "rpi,invert", &invert); |
||
478 | + |
||
479 | + read_bool_property(node, "rpi,debug", &debug); |
||
480 | + |
||
481 | + } else { |
||
482 | + return -EINVAL; |
||
483 | + } |
||
484 | + |
||
485 | + gpiochip->set(gpiochip, gpio_out_pin, invert); |
||
486 | + |
||
487 | + irq_num = gpiochip->to_irq(gpiochip, gpio_in_pin); |
||
488 | + dprintk("to_irq %d\n", irq_num); |
||
489 | + |
||
490 | + /* if pin is high, then this must be an active low receiver. */ |
||
491 | + if (sense == -1) { |
||
492 | + /* wait 1/2 sec for the power supply */ |
||
493 | + msleep(500); |
||
494 | + |
||
495 | + /* |
||
496 | + * probe 9 times every 0.04s, collect "votes" for |
||
497 | + * active high/low |
||
498 | + */ |
||
499 | + nlow = 0; |
||
500 | + nhigh = 0; |
||
501 | + for (i = 0; i < 9; i++) { |
||
502 | + if (gpiochip->get(gpiochip, gpio_in_pin)) |
||
503 | + nlow++; |
||
504 | + else |
||
505 | + nhigh++; |
||
506 | + msleep(40); |
||
507 | + } |
||
508 | + sense = (nlow >= nhigh ? 1 : 0); |
||
509 | + printk(KERN_INFO LIRC_DRIVER_NAME |
||
510 | + ": auto-detected active %s receiver on GPIO pin %d\n", |
||
511 | + sense ? "low" : "high", gpio_in_pin); |
||
512 | + } else { |
||
513 | + printk(KERN_INFO LIRC_DRIVER_NAME |
||
514 | + ": manually using active %s receiver on GPIO pin %d\n", |
||
515 | + sense ? "low" : "high", gpio_in_pin); |
||
516 | + auto_sense = 0; |
||
517 | + } |
||
518 | + |
||
519 | + return 0; |
||
520 | +} |
||
521 | + |
||
522 | +// called when the character device is opened |
||
523 | +static int set_use_inc(void *data) |
||
524 | +{ |
||
525 | + int result; |
||
526 | + |
||
527 | + /* initialize timestamp */ |
||
528 | + do_gettimeofday(&lasttv); |
||
529 | + |
||
530 | + result = request_irq(irq_num, |
||
531 | + (irq_handler_t) irq_handler, |
||
532 | + IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING, |
||
533 | + LIRC_DRIVER_NAME, (void*) 0); |
||
534 | + |
||
535 | + switch (result) { |
||
536 | + case -EBUSY: |
||
537 | + printk(KERN_ERR LIRC_DRIVER_NAME |
||
538 | + ": IRQ %d is busy\n", |
||
539 | + irq_num); |
||
540 | + return -EBUSY; |
||
541 | + case -EINVAL: |
||
542 | + printk(KERN_ERR LIRC_DRIVER_NAME |
||
543 | + ": Bad irq number or handler\n"); |
||
544 | + return -EINVAL; |
||
545 | + default: |
||
546 | + dprintk("Interrupt %d obtained\n", |
||
547 | + irq_num); |
||
548 | + break; |
||
549 | + }; |
||
550 | + |
||
551 | + /* initialize pulse/space widths */ |
||
552 | + init_timing_params(duty_cycle, freq); |
||
553 | + |
||
554 | + return 0; |
||
555 | +} |
||
556 | + |
||
557 | +static void set_use_dec(void *data) |
||
558 | +{ |
||
559 | + /* GPIO Pin Falling/Rising Edge Detect Disable */ |
||
560 | + irq_set_irq_type(irq_num, 0); |
||
561 | + disable_irq(irq_num); |
||
562 | + |
||
563 | + free_irq(irq_num, (void *) 0); |
||
564 | + |
||
565 | + dprintk(KERN_INFO LIRC_DRIVER_NAME |
||
566 | + ": freed IRQ %d\n", irq_num); |
||
567 | +} |
||
568 | + |
||
569 | +static ssize_t lirc_write(struct file *file, const char *buf, |
||
570 | + size_t n, loff_t *ppos) |
||
571 | +{ |
||
572 | + int i, count; |
||
573 | + unsigned long flags; |
||
574 | + long delta = 0; |
||
575 | + int *wbuf; |
||
576 | + |
||
577 | + count = n / sizeof(int); |
||
578 | + if (n % sizeof(int) || count % 2 == 0) |
||
579 | + return -EINVAL; |
||
580 | + wbuf = memdup_user(buf, n); |
||
581 | + if (IS_ERR(wbuf)) |
||
582 | + return PTR_ERR(wbuf); |
||
583 | + spin_lock_irqsave(&lock, flags); |
||
584 | + |
||
585 | + for (i = 0; i < count; i++) { |
||
586 | + if (i%2) |
||
587 | + send_space(wbuf[i] - delta); |
||
588 | + else |
||
589 | + delta = send_pulse(wbuf[i]); |
||
590 | + } |
||
591 | + gpiochip->set(gpiochip, gpio_out_pin, invert); |
||
592 | + |
||
593 | + spin_unlock_irqrestore(&lock, flags); |
||
594 | + kfree(wbuf); |
||
595 | + return n; |
||
596 | +} |
||
597 | + |
||
598 | +static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) |
||
599 | +{ |
||
600 | + int result; |
||
601 | + __u32 value; |
||
602 | + |
||
603 | + switch (cmd) { |
||
604 | + case LIRC_GET_SEND_MODE: |
||
605 | + return -ENOIOCTLCMD; |
||
606 | + break; |
||
607 | + |
||
608 | + case LIRC_SET_SEND_MODE: |
||
609 | + result = get_user(value, (__u32 *) arg); |
||
610 | + if (result) |
||
611 | + return result; |
||
612 | + /* only LIRC_MODE_PULSE supported */ |
||
613 | + if (value != LIRC_MODE_PULSE) |
||
614 | + return -ENOSYS; |
||
615 | + break; |
||
616 | + |
||
617 | + case LIRC_GET_LENGTH: |
||
618 | + return -ENOSYS; |
||
619 | + break; |
||
620 | + |
||
621 | + case LIRC_SET_SEND_DUTY_CYCLE: |
||
622 | + dprintk("SET_SEND_DUTY_CYCLE\n"); |
||
623 | + result = get_user(value, (__u32 *) arg); |
||
624 | + if (result) |
||
625 | + return result; |
||
626 | + if (value <= 0 || value > 100) |
||
627 | + return -EINVAL; |
||
628 | + return init_timing_params(value, freq); |
||
629 | + break; |
||
630 | + |
||
631 | + case LIRC_SET_SEND_CARRIER: |
||
632 | + dprintk("SET_SEND_CARRIER\n"); |
||
633 | + result = get_user(value, (__u32 *) arg); |
||
634 | + if (result) |
||
635 | + return result; |
||
636 | + if (value > 500000 || value < 20000) |
||
637 | + return -EINVAL; |
||
638 | + return init_timing_params(duty_cycle, value); |
||
639 | + break; |
||
640 | + |
||
641 | + default: |
||
642 | + return lirc_dev_fop_ioctl(filep, cmd, arg); |
||
643 | + } |
||
644 | + return 0; |
||
645 | +} |
||
646 | + |
||
647 | +static const struct file_operations lirc_fops = { |
||
648 | + .owner = THIS_MODULE, |
||
649 | + .write = lirc_write, |
||
650 | + .unlocked_ioctl = lirc_ioctl, |
||
651 | + .read = lirc_dev_fop_read, |
||
652 | + .poll = lirc_dev_fop_poll, |
||
653 | + .open = lirc_dev_fop_open, |
||
654 | + .release = lirc_dev_fop_close, |
||
655 | + .llseek = no_llseek, |
||
656 | +}; |
||
657 | + |
||
658 | +static struct lirc_driver driver = { |
||
659 | + .name = LIRC_DRIVER_NAME, |
||
660 | + .minor = -1, |
||
661 | + .code_length = 1, |
||
662 | + .data = NULL, |
||
663 | + .rbuf = &rbuf, |
||
664 | + .fops = &lirc_fops, |
||
665 | + .dev = NULL, |
||
666 | + .owner = THIS_MODULE, |
||
667 | +}; |
||
668 | + |
||
669 | +static const struct of_device_id lirc_rpi_of_match[] = { |
||
670 | + { .compatible = "rpi,lirc-rpi", }, |
||
671 | + {}, |
||
672 | +}; |
||
673 | +MODULE_DEVICE_TABLE(of, lirc_rpi_of_match); |
||
674 | + |
||
675 | +static struct platform_driver lirc_rpi_driver = { |
||
676 | + .driver = { |
||
677 | + .name = LIRC_DRIVER_NAME, |
||
678 | + .owner = THIS_MODULE, |
||
679 | + .of_match_table = of_match_ptr(lirc_rpi_of_match), |
||
680 | + }, |
||
681 | +}; |
||
682 | + |
||
683 | +static int __init lirc_rpi_init(void) |
||
684 | +{ |
||
685 | + struct device_node *node; |
||
686 | + int result; |
||
687 | + |
||
688 | + /* Init read buffer. */ |
||
689 | + result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN); |
||
690 | + if (result < 0) |
||
691 | + return -ENOMEM; |
||
692 | + |
||
693 | + result = platform_driver_register(&lirc_rpi_driver); |
||
694 | + if (result) { |
||
695 | + printk(KERN_ERR LIRC_DRIVER_NAME |
||
696 | + ": lirc register returned %d\n", result); |
||
697 | + goto exit_buffer_free; |
||
698 | + } |
||
699 | + |
||
700 | + node = of_find_compatible_node(NULL, NULL, |
||
701 | + lirc_rpi_of_match[0].compatible); |
||
702 | + |
||
703 | + if (node) { |
||
704 | + /* DT-enabled */ |
||
705 | + lirc_rpi_dev = of_find_device_by_node(node); |
||
706 | + WARN_ON(lirc_rpi_dev->dev.of_node != node); |
||
707 | + of_node_put(node); |
||
708 | + } |
||
709 | + else { |
||
710 | + lirc_rpi_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0); |
||
711 | + if (!lirc_rpi_dev) { |
||
712 | + result = -ENOMEM; |
||
713 | + goto exit_driver_unregister; |
||
714 | + } |
||
715 | + |
||
716 | + result = platform_device_add(lirc_rpi_dev); |
||
717 | + if (result) |
||
718 | + goto exit_device_put; |
||
719 | + } |
||
720 | + |
||
721 | + return 0; |
||
722 | + |
||
723 | + exit_device_put: |
||
724 | + platform_device_put(lirc_rpi_dev); |
||
725 | + |
||
726 | + exit_driver_unregister: |
||
727 | + platform_driver_unregister(&lirc_rpi_driver); |
||
728 | + |
||
729 | + exit_buffer_free: |
||
730 | + lirc_buffer_free(&rbuf); |
||
731 | + |
||
732 | + return result; |
||
733 | +} |
||
734 | + |
||
735 | +static void lirc_rpi_exit(void) |
||
736 | +{ |
||
737 | + set_use_dec(NULL); |
||
738 | + if (!lirc_rpi_dev->dev.of_node) |
||
739 | + platform_device_unregister(lirc_rpi_dev); |
||
740 | + platform_driver_unregister(&lirc_rpi_driver); |
||
741 | + lirc_buffer_free(&rbuf); |
||
742 | +} |
||
743 | + |
||
744 | +static int __init lirc_rpi_init_module(void) |
||
745 | +{ |
||
746 | + int result; |
||
747 | + |
||
748 | + result = lirc_rpi_init(); |
||
749 | + if (result) |
||
750 | + return result; |
||
751 | + |
||
752 | + result = init_port(); |
||
753 | + if (result < 0) |
||
754 | + goto exit_rpi; |
||
755 | + |
||
756 | + driver.features = LIRC_CAN_SET_SEND_DUTY_CYCLE | |
||
757 | + LIRC_CAN_SET_SEND_CARRIER | |
||
758 | + LIRC_CAN_SEND_PULSE | |
||
759 | + LIRC_CAN_REC_MODE2; |
||
760 | + |
||
761 | + driver.dev = &lirc_rpi_dev->dev; |
||
762 | + driver.minor = lirc_register_driver(&driver); |
||
763 | + |
||
764 | + if (driver.minor < 0) { |
||
765 | + printk(KERN_ERR LIRC_DRIVER_NAME |
||
766 | + ": device registration failed with %d\n", result); |
||
767 | + result = -EIO; |
||
768 | + goto exit_rpi; |
||
769 | + } |
||
770 | + |
||
771 | + printk(KERN_INFO LIRC_DRIVER_NAME ": driver registered!\n"); |
||
772 | + |
||
773 | + set_use_inc(NULL); |
||
774 | + |
||
775 | + return 0; |
||
776 | + |
||
777 | + exit_rpi: |
||
778 | + lirc_rpi_exit(); |
||
779 | + |
||
780 | + return result; |
||
781 | +} |
||
782 | + |
||
783 | +static void __exit lirc_rpi_exit_module(void) |
||
784 | +{ |
||
785 | + lirc_unregister_driver(driver.minor); |
||
786 | + |
||
787 | + gpio_free(gpio_out_pin); |
||
788 | + gpio_free(gpio_in_pin); |
||
789 | + |
||
790 | + lirc_rpi_exit(); |
||
791 | + |
||
792 | + printk(KERN_INFO LIRC_DRIVER_NAME ": cleaned up module\n"); |
||
793 | +} |
||
794 | + |
||
795 | +module_init(lirc_rpi_init_module); |
||
796 | +module_exit(lirc_rpi_exit_module); |
||
797 | + |
||
798 | +MODULE_DESCRIPTION("Infra-red receiver and blaster driver for Raspberry Pi GPIO."); |
||
799 | +MODULE_AUTHOR("Aron Robert Szabo <aron@reon.hu>"); |
||
800 | +MODULE_AUTHOR("Michael Bishop <cleverca22@gmail.com>"); |
||
801 | +MODULE_LICENSE("GPL"); |
||
802 | + |
||
803 | +module_param(gpio_out_pin, int, S_IRUGO); |
||
804 | +MODULE_PARM_DESC(gpio_out_pin, "GPIO output/transmitter pin number of the BCM" |
||
805 | + " processor. (default 17"); |
||
806 | + |
||
807 | +module_param(gpio_in_pin, int, S_IRUGO); |
||
808 | +MODULE_PARM_DESC(gpio_in_pin, "GPIO input pin number of the BCM processor." |
||
809 | + " (default 18"); |
||
810 | + |
||
811 | +module_param(gpio_in_pull, int, S_IRUGO); |
||
812 | +MODULE_PARM_DESC(gpio_in_pull, "GPIO input pin pull configuration." |
||
813 | + " (0 = off, 1 = up, 2 = down, default down)"); |
||
814 | + |
||
815 | +module_param(sense, int, S_IRUGO); |
||
816 | +MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit" |
||
817 | + " (0 = active high, 1 = active low )"); |
||
818 | + |
||
819 | +module_param(softcarrier, bool, S_IRUGO); |
||
820 | +MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)"); |
||
821 | + |
||
822 | +module_param(invert, bool, S_IRUGO); |
||
823 | +MODULE_PARM_DESC(invert, "Invert output (0 = off, 1 = on, default off"); |
||
824 | + |
||
825 | +module_param(debug, bool, S_IRUGO | S_IWUSR); |
||
826 | +MODULE_PARM_DESC(debug, "Enable debugging messages"); |
||
827 | --- /dev/null |
||
828 | +++ b/include/linux/platform_data/bcm2708.h |
||
829 | @@ -0,0 +1,23 @@ |
||
830 | +/* |
||
831 | + * include/linux/platform_data/bcm2708.h |
||
832 | + * |
||
833 | + * This program is free software; you can redistribute it and/or modify |
||
834 | + * it under the terms of the GNU General Public License version 2 as |
||
835 | + * published by the Free Software Foundation. |
||
836 | + * |
||
837 | + * (C) 2014 Julian Scheel <julian@jusst.de> |
||
838 | + * |
||
839 | + */ |
||
840 | +#ifndef __BCM2708_H_ |
||
841 | +#define __BCM2708_H_ |
||
842 | + |
||
843 | +typedef enum { |
||
844 | + BCM2708_PULL_OFF, |
||
845 | + BCM2708_PULL_UP, |
||
846 | + BCM2708_PULL_DOWN |
||
847 | +} bcm2708_gpio_pull_t; |
||
848 | + |
||
849 | +extern int bcm2708_gpio_setpull(struct gpio_chip *gc, unsigned offset, |
||
850 | + bcm2708_gpio_pull_t value); |
||
851 | + |
||
852 | +#endif |