1 From 96fbef3b8f8ab61f7f32d52b54d7993117a5fdbc 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 015/114] lirc: added support for RaspberryPi GPIO
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
9 lirc: Remove restriction on gpio pins that can be used with lirc
11 Compute Module, for example could use different pins
13 lirc_rpi: Add parameter to specify input pin pull
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.
19 Signed-off-by: Julian Scheel <julian@jusst.de>
21 lirc-rpi: Use the higher-level irq control functions
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.
29 lirc-rpi: Correct the interrupt usage
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
35 drivers/staging/media/lirc/Kconfig | 6 +
36 drivers/staging/media/lirc/Makefile | 1 +
37 drivers/staging/media/lirc/lirc_rpi.c | 659 ++++++++++++++++++++++++++++++++++
38 3 files changed, 666 insertions(+)
39 create mode 100644 drivers/staging/media/lirc/lirc_rpi.c
41 diff --git a/drivers/staging/media/lirc/Kconfig b/drivers/staging/media/lirc/Kconfig
42 index e60a59f..6b7ff70 100644
43 --- a/drivers/staging/media/lirc/Kconfig
44 +++ b/drivers/staging/media/lirc/Kconfig
45 @@ -38,6 +38,12 @@ config LIRC_PARALLEL
47 Driver for Homebrew Parallel Port Receivers
50 + tristate "Homebrew GPIO Port Receiver/Transmitter for the RaspberryPi"
53 + Driver for Homebrew GPIO Port Receiver/Transmitter for the RaspberryPi
56 tristate "Sasem USB IR Remote"
57 depends on LIRC && USB
58 diff --git a/drivers/staging/media/lirc/Makefile b/drivers/staging/media/lirc/Makefile
59 index b90fcab..2b227fd 100644
60 --- a/drivers/staging/media/lirc/Makefile
61 +++ b/drivers/staging/media/lirc/Makefile
62 @@ -7,6 +7,7 @@ obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o
63 obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o
64 obj-$(CONFIG_LIRC_IMON) += lirc_imon.o
65 obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o
66 +obj-$(CONFIG_LIRC_RPI) += lirc_rpi.o
67 obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o
68 obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o
69 obj-$(CONFIG_LIRC_SIR) += lirc_sir.o
70 diff --git a/drivers/staging/media/lirc/lirc_rpi.c b/drivers/staging/media/lirc/lirc_rpi.c
72 index 0000000..c688364
74 +++ b/drivers/staging/media/lirc/lirc_rpi.c
79 + * lirc_rpi - Device driver that records pulse- and pause-lengths
80 + * (space-lengths) (just like the lirc_serial driver does)
81 + * between GPIO interrupt events on the Raspberry Pi.
82 + * Lots of code has been taken from the lirc_serial module,
83 + * so I would like say thanks to the authors.
85 + * Copyright (C) 2012 Aron Robert Szabo <aron@reon.hu>,
86 + * Michael Bishop <cleverca22@gmail.com>
87 + * This program is free software; you can redistribute it and/or modify
88 + * it under the terms of the GNU General Public License as published by
89 + * the Free Software Foundation; either version 2 of the License, or
90 + * (at your option) any later version.
92 + * This program is distributed in the hope that it will be useful,
93 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
94 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
95 + * GNU General Public License for more details.
97 + * You should have received a copy of the GNU General Public License
98 + * along with this program; if not, write to the Free Software
99 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
102 +#include <linux/module.h>
103 +#include <linux/errno.h>
104 +#include <linux/interrupt.h>
105 +#include <linux/sched.h>
106 +#include <linux/kernel.h>
107 +#include <linux/time.h>
108 +#include <linux/timex.h>
109 +#include <linux/string.h>
110 +#include <linux/delay.h>
111 +#include <linux/platform_device.h>
112 +#include <linux/irq.h>
113 +#include <linux/spinlock.h>
114 +#include <media/lirc.h>
115 +#include <media/lirc_dev.h>
116 +#include <mach/gpio.h>
117 +#include <linux/gpio.h>
119 +#include <linux/platform_data/bcm2708.h>
121 +#define LIRC_DRIVER_NAME "lirc_rpi"
122 +#define RBUF_LEN 256
123 +#define LIRC_TRANSMITTER_LATENCY 50
125 +#ifndef MAX_UDELAY_MS
126 +#define MAX_UDELAY_US 5000
128 +#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
131 +#define dprintk(fmt, args...) \
134 + printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \
138 +/* module parameters */
140 +/* set the default GPIO input pin */
141 +static int gpio_in_pin = 18;
142 +/* set the default pull behaviour for input pin */
143 +static int gpio_in_pull = BCM2708_PULL_DOWN;
144 +/* set the default GPIO output pin */
145 +static int gpio_out_pin = 17;
146 +/* enable debugging messages */
148 +/* -1 = auto, 0 = active high, 1 = active low */
149 +static int sense = -1;
150 +/* use softcarrier by default */
151 +static bool softcarrier = 1;
152 +/* 0 = do not invert output, 1 = invert output */
153 +static bool invert = 0;
155 +struct gpio_chip *gpiochip;
158 +/* forward declarations */
159 +static long send_pulse(unsigned long length);
160 +static void send_space(long length);
161 +static void lirc_rpi_exit(void);
163 +static struct platform_device *lirc_rpi_dev;
164 +static struct timeval lasttv = { 0, 0 };
165 +static struct lirc_buffer rbuf;
166 +static spinlock_t lock;
168 +/* initialized/set in init_timing_params() */
169 +static unsigned int freq = 38000;
170 +static unsigned int duty_cycle = 50;
171 +static unsigned long period;
172 +static unsigned long pulse_width;
173 +static unsigned long space_width;
175 +static void safe_udelay(unsigned long usecs)
177 + while (usecs > MAX_UDELAY_US) {
178 + udelay(MAX_UDELAY_US);
179 + usecs -= MAX_UDELAY_US;
184 +static int init_timing_params(unsigned int new_duty_cycle,
185 + unsigned int new_freq)
187 + if (1000 * 1000000L / new_freq * new_duty_cycle / 100 <=
188 + LIRC_TRANSMITTER_LATENCY)
190 + if (1000 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <=
191 + LIRC_TRANSMITTER_LATENCY)
193 + duty_cycle = new_duty_cycle;
195 + period = 1000 * 1000000L / freq;
196 + pulse_width = period * duty_cycle / 100;
197 + space_width = period - pulse_width;
198 + dprintk("in init_timing_params, freq=%d pulse=%ld, "
199 + "space=%ld\n", freq, pulse_width, space_width);
203 +static long send_pulse_softcarrier(unsigned long length)
206 + unsigned long actual, target;
207 + unsigned long actual_us, initial_us, target_us;
211 + actual = 0; target = 0; flag = 0;
212 + read_current_timer(&actual_us);
214 + while (actual < length) {
216 + gpiochip->set(gpiochip, gpio_out_pin, invert);
217 + target += space_width;
219 + gpiochip->set(gpiochip, gpio_out_pin, !invert);
220 + target += pulse_width;
222 + initial_us = actual_us;
223 + target_us = actual_us + (target - actual) / 1000;
225 + * Note - we've checked in ioctl that the pulse/space
226 + * widths are big enough so that d is > 0
228 + if ((int)(target_us - actual_us) > 0)
229 + udelay(target_us - actual_us);
230 + read_current_timer(&actual_us);
231 + actual += (actual_us - initial_us) * 1000;
234 + return (actual-length) / 1000;
237 +static long send_pulse(unsigned long length)
243 + return send_pulse_softcarrier(length);
245 + gpiochip->set(gpiochip, gpio_out_pin, !invert);
246 + safe_udelay(length);
251 +static void send_space(long length)
253 + gpiochip->set(gpiochip, gpio_out_pin, invert);
256 + safe_udelay(length);
259 +static void rbwrite(int l)
261 + if (lirc_buffer_full(&rbuf)) {
262 + /* no new signals will be accepted */
263 + dprintk("Buffer overrun\n");
266 + lirc_buffer_write(&rbuf, (void *)&l);
269 +static void frbwrite(int l)
271 + /* simple noise filter */
272 + static int pulse, space;
273 + static unsigned int ptr;
275 + if (ptr > 0 && (l & PULSE_BIT)) {
276 + pulse += l & PULSE_MASK;
279 + rbwrite(pulse | PULSE_BIT);
285 + if (!(l & PULSE_BIT)) {
295 + if (space > PULSE_MASK)
296 + space = PULSE_MASK;
298 + if (space > PULSE_MASK)
299 + space = PULSE_MASK;
304 + rbwrite(pulse | PULSE_BIT);
312 +static irqreturn_t irq_handler(int i, void *blah, struct pt_regs *regs)
319 + /* use the GPIO signal level */
320 + signal = gpiochip->get(gpiochip, gpio_in_pin);
323 + /* get current time */
324 + do_gettimeofday(&tv);
326 + /* calc time since last interrupt in microseconds */
327 + deltv = tv.tv_sec-lasttv.tv_sec;
328 + if (tv.tv_sec < lasttv.tv_sec ||
329 + (tv.tv_sec == lasttv.tv_sec &&
330 + tv.tv_usec < lasttv.tv_usec)) {
331 + printk(KERN_WARNING LIRC_DRIVER_NAME
332 + ": AIEEEE: your clock just jumped backwards\n");
333 + printk(KERN_WARNING LIRC_DRIVER_NAME
334 + ": %d %d %lx %lx %lx %lx\n", signal, sense,
335 + tv.tv_sec, lasttv.tv_sec,
336 + tv.tv_usec, lasttv.tv_usec);
338 + } else if (deltv > 15) {
339 + data = PULSE_MASK; /* really long time */
340 + if (!(signal^sense)) {
342 + printk(KERN_WARNING LIRC_DRIVER_NAME
343 + ": AIEEEE: %d %d %lx %lx %lx %lx\n",
344 + signal, sense, tv.tv_sec, lasttv.tv_sec,
345 + tv.tv_usec, lasttv.tv_usec);
347 + * detecting pulse while this
350 + sense = sense ? 0 : 1;
353 + data = (int) (deltv*1000000 +
354 + (tv.tv_usec - lasttv.tv_usec));
356 + frbwrite(signal^sense ? data : (data|PULSE_BIT));
358 + wake_up_interruptible(&rbuf.wait_poll);
361 + return IRQ_HANDLED;
364 +static int is_right_chip(struct gpio_chip *chip, void *data)
366 + dprintk("is_right_chip %s %d\n", chip->label, strcmp(data, chip->label));
368 + if (strcmp(data, chip->label) == 0)
373 +static int init_port(void)
375 + int i, nlow, nhigh, ret;
377 + gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip);
382 + if (gpio_request(gpio_out_pin, LIRC_DRIVER_NAME " ir/out")) {
383 + printk(KERN_ALERT LIRC_DRIVER_NAME
384 + ": cant claim gpio pin %d\n", gpio_out_pin);
386 + goto exit_init_port;
389 + if (gpio_request(gpio_in_pin, LIRC_DRIVER_NAME " ir/in")) {
390 + printk(KERN_ALERT LIRC_DRIVER_NAME
391 + ": cant claim gpio pin %d\n", gpio_in_pin);
393 + goto exit_gpio_free_out_pin;
396 + bcm2708_gpio_setpull(gpiochip, gpio_in_pin, gpio_in_pull);
397 + gpiochip->direction_input(gpiochip, gpio_in_pin);
398 + gpiochip->direction_output(gpiochip, gpio_out_pin, 1);
399 + gpiochip->set(gpiochip, gpio_out_pin, invert);
401 + irq_num = gpiochip->to_irq(gpiochip, gpio_in_pin);
402 + dprintk("to_irq %d\n", irq_num);
404 + /* if pin is high, then this must be an active low receiver. */
406 + /* wait 1/2 sec for the power supply */
410 + * probe 9 times every 0.04s, collect "votes" for
415 + for (i = 0; i < 9; i++) {
416 + if (gpiochip->get(gpiochip, gpio_in_pin))
422 + sense = (nlow >= nhigh ? 1 : 0);
423 + printk(KERN_INFO LIRC_DRIVER_NAME
424 + ": auto-detected active %s receiver on GPIO pin %d\n",
425 + sense ? "low" : "high", gpio_in_pin);
427 + printk(KERN_INFO LIRC_DRIVER_NAME
428 + ": manually using active %s receiver on GPIO pin %d\n",
429 + sense ? "low" : "high", gpio_in_pin);
434 + exit_gpio_free_out_pin:
435 + gpio_free(gpio_out_pin);
441 +// called when the character device is opened
442 +static int set_use_inc(void *data)
446 + /* initialize timestamp */
447 + do_gettimeofday(&lasttv);
449 + result = request_irq(irq_num,
450 + (irq_handler_t) irq_handler,
451 + IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING,
452 + LIRC_DRIVER_NAME, (void*) 0);
456 + printk(KERN_ERR LIRC_DRIVER_NAME
457 + ": IRQ %d is busy\n",
461 + printk(KERN_ERR LIRC_DRIVER_NAME
462 + ": Bad irq number or handler\n");
465 + dprintk("Interrupt %d obtained\n",
470 + /* initialize pulse/space widths */
471 + init_timing_params(duty_cycle, freq);
476 +static void set_use_dec(void *data)
478 + /* GPIO Pin Falling/Rising Edge Detect Disable */
479 + irq_set_irq_type(irq_num, 0);
480 + disable_irq(irq_num);
482 + free_irq(irq_num, (void *) 0);
484 + dprintk(KERN_INFO LIRC_DRIVER_NAME
485 + ": freed IRQ %d\n", irq_num);
488 +static ssize_t lirc_write(struct file *file, const char *buf,
489 + size_t n, loff_t *ppos)
492 + unsigned long flags;
496 + count = n / sizeof(int);
497 + if (n % sizeof(int) || count % 2 == 0)
499 + wbuf = memdup_user(buf, n);
501 + return PTR_ERR(wbuf);
502 + spin_lock_irqsave(&lock, flags);
504 + for (i = 0; i < count; i++) {
506 + send_space(wbuf[i] - delta);
508 + delta = send_pulse(wbuf[i]);
510 + gpiochip->set(gpiochip, gpio_out_pin, invert);
512 + spin_unlock_irqrestore(&lock, flags);
517 +static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
523 + case LIRC_GET_SEND_MODE:
524 + return -ENOIOCTLCMD;
527 + case LIRC_SET_SEND_MODE:
528 + result = get_user(value, (__u32 *) arg);
531 + /* only LIRC_MODE_PULSE supported */
532 + if (value != LIRC_MODE_PULSE)
536 + case LIRC_GET_LENGTH:
540 + case LIRC_SET_SEND_DUTY_CYCLE:
541 + dprintk("SET_SEND_DUTY_CYCLE\n");
542 + result = get_user(value, (__u32 *) arg);
545 + if (value <= 0 || value > 100)
547 + return init_timing_params(value, freq);
550 + case LIRC_SET_SEND_CARRIER:
551 + dprintk("SET_SEND_CARRIER\n");
552 + result = get_user(value, (__u32 *) arg);
555 + if (value > 500000 || value < 20000)
557 + return init_timing_params(duty_cycle, value);
561 + return lirc_dev_fop_ioctl(filep, cmd, arg);
566 +static const struct file_operations lirc_fops = {
567 + .owner = THIS_MODULE,
568 + .write = lirc_write,
569 + .unlocked_ioctl = lirc_ioctl,
570 + .read = lirc_dev_fop_read,
571 + .poll = lirc_dev_fop_poll,
572 + .open = lirc_dev_fop_open,
573 + .release = lirc_dev_fop_close,
574 + .llseek = no_llseek,
577 +static struct lirc_driver driver = {
578 + .name = LIRC_DRIVER_NAME,
583 + .add_to_buf = NULL,
585 + .set_use_inc = set_use_inc,
586 + .set_use_dec = set_use_dec,
587 + .fops = &lirc_fops,
589 + .owner = THIS_MODULE,
592 +static struct platform_driver lirc_rpi_driver = {
594 + .name = LIRC_DRIVER_NAME,
595 + .owner = THIS_MODULE,
599 +static int __init lirc_rpi_init(void)
603 + /* Init read buffer. */
604 + result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN);
608 + result = platform_driver_register(&lirc_rpi_driver);
610 + printk(KERN_ERR LIRC_DRIVER_NAME
611 + ": lirc register returned %d\n", result);
612 + goto exit_buffer_free;
615 + lirc_rpi_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0);
616 + if (!lirc_rpi_dev) {
618 + goto exit_driver_unregister;
621 + result = platform_device_add(lirc_rpi_dev);
623 + goto exit_device_put;
628 + platform_device_put(lirc_rpi_dev);
630 + exit_driver_unregister:
631 + platform_driver_unregister(&lirc_rpi_driver);
634 + lirc_buffer_free(&rbuf);
639 +static void lirc_rpi_exit(void)
641 + if (!lirc_rpi_dev->dev.of_node)
642 + platform_device_unregister(lirc_rpi_dev);
643 + platform_driver_unregister(&lirc_rpi_driver);
644 + lirc_buffer_free(&rbuf);
647 +static int __init lirc_rpi_init_module(void)
651 + result = lirc_rpi_init();
655 + if (gpio_in_pin >= BCM2708_NR_GPIOS || gpio_out_pin >= BCM2708_NR_GPIOS) {
657 + printk(KERN_ERR LIRC_DRIVER_NAME
658 + ": invalid GPIO pin(s) specified!\n");
662 + result = init_port();
666 + driver.features = LIRC_CAN_SET_SEND_DUTY_CYCLE |
667 + LIRC_CAN_SET_SEND_CARRIER |
668 + LIRC_CAN_SEND_PULSE |
669 + LIRC_CAN_REC_MODE2;
671 + driver.dev = &lirc_rpi_dev->dev;
672 + driver.minor = lirc_register_driver(&driver);
674 + if (driver.minor < 0) {
675 + printk(KERN_ERR LIRC_DRIVER_NAME
676 + ": device registration failed with %d\n", result);
681 + printk(KERN_INFO LIRC_DRIVER_NAME ": driver registered!\n");
691 +static void __exit lirc_rpi_exit_module(void)
693 + lirc_unregister_driver(driver.minor);
695 + gpio_free(gpio_out_pin);
696 + gpio_free(gpio_in_pin);
700 + printk(KERN_INFO LIRC_DRIVER_NAME ": cleaned up module\n");
703 +module_init(lirc_rpi_init_module);
704 +module_exit(lirc_rpi_exit_module);
706 +MODULE_DESCRIPTION("Infra-red receiver and blaster driver for Raspberry Pi GPIO.");
707 +MODULE_AUTHOR("Aron Robert Szabo <aron@reon.hu>");
708 +MODULE_AUTHOR("Michael Bishop <cleverca22@gmail.com>");
709 +MODULE_LICENSE("GPL");
711 +module_param(gpio_out_pin, int, S_IRUGO);
712 +MODULE_PARM_DESC(gpio_out_pin, "GPIO output/transmitter pin number of the BCM"
713 + " processor. (default 17");
715 +module_param(gpio_in_pin, int, S_IRUGO);
716 +MODULE_PARM_DESC(gpio_in_pin, "GPIO input pin number of the BCM processor."
719 +module_param(gpio_in_pull, int, S_IRUGO);
720 +MODULE_PARM_DESC(gpio_in_pull, "GPIO input pin pull configuration."
721 + " (0 = off, 1 = up, 2 = down, default down)");
723 +module_param(sense, int, S_IRUGO);
724 +MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit"
725 + " (0 = active high, 1 = active low )");
727 +module_param(softcarrier, bool, S_IRUGO);
728 +MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)");
730 +module_param(invert, bool, S_IRUGO);
731 +MODULE_PARM_DESC(invert, "Invert output (0 = off, 1 = on, default off");
733 +module_param(debug, bool, S_IRUGO | S_IWUSR);
734 +MODULE_PARM_DESC(debug, "Enable debugging messages");