diff options
Diffstat (limited to 'target/linux/brcm2708/patches-4.9/950-0045-lirc-added-support-for-RaspberryPi-GPIO.patch')
-rw-r--r-- | target/linux/brcm2708/patches-4.9/950-0045-lirc-added-support-for-RaspberryPi-GPIO.patch | 855 |
1 files changed, 0 insertions, 855 deletions
diff --git a/target/linux/brcm2708/patches-4.9/950-0045-lirc-added-support-for-RaspberryPi-GPIO.patch b/target/linux/brcm2708/patches-4.9/950-0045-lirc-added-support-for-RaspberryPi-GPIO.patch deleted file mode 100644 index 0cbc1c45a4..0000000000 --- a/target/linux/brcm2708/patches-4.9/950-0045-lirc-added-support-for-RaspberryPi-GPIO.patch +++ /dev/null @@ -1,855 +0,0 @@ -From 277c109833c1d78543bec0723ab42f4c79937df9 Mon Sep 17 00:00:00 2001 -From: Aron Szabo <aron@aron.ws> -Date: Sat, 16 Jun 2012 12:15:55 +0200 -Subject: [PATCH] lirc: added support for RaspberryPi GPIO - -lirc_rpi: Use read_current_timer to determine transmitter delay. Thanks to jjmz and others -See: https://github.com/raspberrypi/linux/issues/525 - -lirc: Remove restriction on gpio pins that can be used with lirc - -Compute Module, for example could use different pins - -lirc_rpi: Add parameter to specify input pin pull - -Depending on the connected IR circuitry it might be desirable to change the -gpios internal pull from it pull-down default behaviour. Add a module -parameter to allow the user to set it explicitly. - -Signed-off-by: Julian Scheel <julian@jusst.de> - -lirc-rpi: Use the higher-level irq control functions - -This module used to access the irq_chip methods of the -gpio controller directly, rather than going through the -standard enable_irq/irq_set_irq_type functions. This -caused problems on pinctrl-bcm2835 which only implements -the irq_enable/disable methods and not irq_unmask/mask. - -lirc-rpi: Correct the interrupt usage - -1) Correct the use of enable_irq (i.e. don't call it so often) -2) Correct the shutdown sequence. -3) Avoid a bcm2708_gpio driver quirk by setting the irq flags earlier - -lirc-rpi: use getnstimeofday instead of read_current_timer - -read_current_timer isn't guaranteed to return values in -microseconds, and indeed it doesn't on a Pi2. - -Issue: linux#827 - -lirc-rpi: Add device tree support, and a suitable overlay - -The overlay supports DT parameters that match the old module -parameters, except that gpio_in_pull should be set using the -strings "up", "down" or "off". - -lirc-rpi: Also support pinctrl-bcm2835 in non-DT mode - -fix auto-sense in lirc_rpi driver - -On a Raspberry Pi 2, the lirc_rpi driver might receive spurious -interrupts and change it's low-active / high-active setting. -When this happens, the IR remote control stops working. - -This patch disables this auto-detection if the 'sense' parameter -was set in the device tree, making the driver robust to such -spurious interrupts. ---- - drivers/staging/media/lirc/Kconfig | 6 + - drivers/staging/media/lirc/Makefile | 1 + - drivers/staging/media/lirc/lirc_rpi.c | 734 ++++++++++++++++++++++++++++++++++ - include/linux/platform_data/bcm2708.h | 23 ++ - 4 files changed, 764 insertions(+) - create mode 100644 drivers/staging/media/lirc/lirc_rpi.c - create mode 100644 include/linux/platform_data/bcm2708.h - ---- a/drivers/staging/media/lirc/Kconfig -+++ b/drivers/staging/media/lirc/Kconfig -@@ -32,6 +32,12 @@ config LIRC_PARALLEL - help - Driver for Homebrew Parallel Port Receivers - -+config LIRC_RPI -+ tristate "Homebrew GPIO Port Receiver/Transmitter for the RaspberryPi" -+ depends on LIRC -+ help -+ Driver for Homebrew GPIO Port Receiver/Transmitter for the RaspberryPi -+ - config LIRC_SASEM - tristate "Sasem USB IR Remote" - depends on LIRC && USB ---- a/drivers/staging/media/lirc/Makefile -+++ b/drivers/staging/media/lirc/Makefile -@@ -6,6 +6,7 @@ - obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o - obj-$(CONFIG_LIRC_IMON) += lirc_imon.o - obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o -+obj-$(CONFIG_LIRC_RPI) += lirc_rpi.o - obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o - obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o - obj-$(CONFIG_LIRC_SIR) += lirc_sir.o ---- /dev/null -+++ b/drivers/staging/media/lirc/lirc_rpi.c -@@ -0,0 +1,734 @@ -+/* -+ * lirc_rpi.c -+ * -+ * lirc_rpi - Device driver that records pulse- and pause-lengths -+ * (space-lengths) (just like the lirc_serial driver does) -+ * between GPIO interrupt events on the Raspberry Pi. -+ * Lots of code has been taken from the lirc_serial module, -+ * so I would like say thanks to the authors. -+ * -+ * Copyright (C) 2012 Aron Robert Szabo <aron@reon.hu>, -+ * Michael Bishop <cleverca22@gmail.com> -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include <linux/module.h> -+#include <linux/errno.h> -+#include <linux/interrupt.h> -+#include <linux/sched.h> -+#include <linux/kernel.h> -+#include <linux/time.h> -+#include <linux/timex.h> -+#include <linux/timekeeping.h> -+#include <linux/string.h> -+#include <linux/delay.h> -+#include <linux/platform_device.h> -+#include <linux/irq.h> -+#include <linux/spinlock.h> -+#include <media/lirc.h> -+#include <media/lirc_dev.h> -+#include <linux/gpio.h> -+#include <linux/of_platform.h> -+#include <linux/platform_data/bcm2708.h> -+ -+#define LIRC_DRIVER_NAME "lirc_rpi" -+#define RBUF_LEN 256 -+#define LIRC_TRANSMITTER_LATENCY 50 -+ -+#ifndef MAX_UDELAY_MS -+#define MAX_UDELAY_US 5000 -+#else -+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) -+#endif -+ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ -+ fmt, ## args); \ -+ } while (0) -+ -+/* module parameters */ -+ -+/* set the default GPIO input pin */ -+static int gpio_in_pin = 18; -+/* set the default pull behaviour for input pin */ -+static int gpio_in_pull = BCM2708_PULL_DOWN; -+/* set the default GPIO output pin */ -+static int gpio_out_pin = 17; -+/* enable debugging messages */ -+static bool debug; -+/* -1 = auto, 0 = active high, 1 = active low */ -+static int sense = -1; -+/* use softcarrier by default */ -+static bool softcarrier = 1; -+/* 0 = do not invert output, 1 = invert output */ -+static bool invert = 0; -+ -+struct gpio_chip *gpiochip; -+static int irq_num; -+static int auto_sense = 1; -+ -+/* forward declarations */ -+static long send_pulse(unsigned long length); -+static void send_space(long length); -+static void lirc_rpi_exit(void); -+ -+static struct platform_device *lirc_rpi_dev; -+static struct timeval lasttv = { 0, 0 }; -+static struct lirc_buffer rbuf; -+static spinlock_t lock; -+ -+/* initialized/set in init_timing_params() */ -+static unsigned int freq = 38000; -+static unsigned int duty_cycle = 50; -+static unsigned long period; -+static unsigned long pulse_width; -+static unsigned long space_width; -+ -+static void safe_udelay(unsigned long usecs) -+{ -+ while (usecs > MAX_UDELAY_US) { -+ udelay(MAX_UDELAY_US); -+ usecs -= MAX_UDELAY_US; -+ } -+ udelay(usecs); -+} -+ -+static unsigned long read_current_us(void) -+{ -+ struct timespec now; -+ getnstimeofday(&now); -+ return (now.tv_sec * 1000000) + (now.tv_nsec/1000); -+} -+ -+static int init_timing_params(unsigned int new_duty_cycle, -+ unsigned int new_freq) -+{ -+ if (1000 * 1000000L / new_freq * new_duty_cycle / 100 <= -+ LIRC_TRANSMITTER_LATENCY) -+ return -EINVAL; -+ if (1000 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <= -+ LIRC_TRANSMITTER_LATENCY) -+ return -EINVAL; -+ duty_cycle = new_duty_cycle; -+ freq = new_freq; -+ period = 1000 * 1000000L / freq; -+ pulse_width = period * duty_cycle / 100; -+ space_width = period - pulse_width; -+ dprintk("in init_timing_params, freq=%d pulse=%ld, " -+ "space=%ld\n", freq, pulse_width, space_width); -+ return 0; -+} -+ -+static long send_pulse_softcarrier(unsigned long length) -+{ -+ int flag; -+ unsigned long actual, target; -+ unsigned long actual_us, initial_us, target_us; -+ -+ length *= 1000; -+ -+ actual = 0; target = 0; flag = 0; -+ actual_us = read_current_us(); -+ -+ while (actual < length) { -+ if (flag) { -+ gpiochip->set(gpiochip, gpio_out_pin, invert); -+ target += space_width; -+ } else { -+ gpiochip->set(gpiochip, gpio_out_pin, !invert); -+ target += pulse_width; -+ } -+ initial_us = actual_us; -+ target_us = actual_us + (target - actual) / 1000; -+ /* -+ * Note - we've checked in ioctl that the pulse/space -+ * widths are big enough so that d is > 0 -+ */ -+ if ((int)(target_us - actual_us) > 0) -+ udelay(target_us - actual_us); -+ actual_us = read_current_us(); -+ actual += (actual_us - initial_us) * 1000; -+ flag = !flag; -+ } -+ return (actual-length) / 1000; -+} -+ -+static long send_pulse(unsigned long length) -+{ -+ if (length <= 0) -+ return 0; -+ -+ if (softcarrier) { -+ return send_pulse_softcarrier(length); -+ } else { -+ gpiochip->set(gpiochip, gpio_out_pin, !invert); -+ safe_udelay(length); -+ return 0; -+ } -+} -+ -+static void send_space(long length) -+{ -+ gpiochip->set(gpiochip, gpio_out_pin, invert); -+ if (length <= 0) -+ return; -+ safe_udelay(length); -+} -+ -+static void rbwrite(int l) -+{ -+ if (lirc_buffer_full(&rbuf)) { -+ /* no new signals will be accepted */ -+ dprintk("Buffer overrun\n"); -+ return; -+ } -+ lirc_buffer_write(&rbuf, (void *)&l); -+} -+ -+static void frbwrite(int l) -+{ -+ /* simple noise filter */ -+ static int pulse, space; -+ static unsigned int ptr; -+ -+ if (ptr > 0 && (l & PULSE_BIT)) { -+ pulse += l & PULSE_MASK; -+ if (pulse > 250) { -+ rbwrite(space); -+ rbwrite(pulse | PULSE_BIT); -+ ptr = 0; -+ pulse = 0; -+ } -+ return; -+ } -+ if (!(l & PULSE_BIT)) { -+ if (ptr == 0) { -+ if (l > 20000) { -+ space = l; -+ ptr++; -+ return; -+ } -+ } else { -+ if (l > 20000) { -+ space += pulse; -+ if (space > PULSE_MASK) -+ space = PULSE_MASK; -+ space += l; -+ if (space > PULSE_MASK) -+ space = PULSE_MASK; -+ pulse = 0; -+ return; -+ } -+ rbwrite(space); -+ rbwrite(pulse | PULSE_BIT); -+ ptr = 0; -+ pulse = 0; -+ } -+ } -+ rbwrite(l); -+} -+ -+static irqreturn_t irq_handler(int i, void *blah, struct pt_regs *regs) -+{ -+ struct timeval tv; -+ long deltv; -+ int data; -+ int signal; -+ -+ /* use the GPIO signal level */ -+ signal = gpiochip->get(gpiochip, gpio_in_pin); -+ -+ if (sense != -1) { -+ /* get current time */ -+ do_gettimeofday(&tv); -+ -+ /* calc time since last interrupt in microseconds */ -+ deltv = tv.tv_sec-lasttv.tv_sec; -+ if (tv.tv_sec < lasttv.tv_sec || -+ (tv.tv_sec == lasttv.tv_sec && -+ tv.tv_usec < lasttv.tv_usec)) { -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": AIEEEE: your clock just jumped backwards\n"); -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": %d %d %lx %lx %lx %lx\n", signal, sense, -+ tv.tv_sec, lasttv.tv_sec, -+ tv.tv_usec, lasttv.tv_usec); -+ data = PULSE_MASK; -+ } else if (deltv > 15) { -+ data = PULSE_MASK; /* really long time */ -+ if (!(signal^sense)) { -+ /* sanity check */ -+ printk(KERN_DEBUG LIRC_DRIVER_NAME -+ ": AIEEEE: %d %d %lx %lx %lx %lx\n", -+ signal, sense, tv.tv_sec, lasttv.tv_sec, -+ tv.tv_usec, lasttv.tv_usec); -+ /* -+ * detecting pulse while this -+ * MUST be a space! -+ */ -+ if (auto_sense) { -+ sense = sense ? 0 : 1; -+ } -+ } -+ } else { -+ data = (int) (deltv*1000000 + -+ (tv.tv_usec - lasttv.tv_usec)); -+ } -+ frbwrite(signal^sense ? data : (data|PULSE_BIT)); -+ lasttv = tv; -+ wake_up_interruptible(&rbuf.wait_poll); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static int is_right_chip(struct gpio_chip *chip, void *data) -+{ -+ dprintk("is_right_chip %s %d\n", chip->label, strcmp(data, chip->label)); -+ -+ if (strcmp(data, chip->label) == 0) -+ return 1; -+ return 0; -+} -+ -+static inline int read_bool_property(const struct device_node *np, -+ const char *propname, -+ bool *out_value) -+{ -+ u32 value = 0; -+ int err = of_property_read_u32(np, propname, &value); -+ if (err == 0) -+ *out_value = (value != 0); -+ return err; -+} -+ -+static void read_pin_settings(struct device_node *node) -+{ -+ u32 pin; -+ int index; -+ -+ for (index = 0; -+ of_property_read_u32_index( -+ node, -+ "brcm,pins", -+ index, -+ &pin) == 0; -+ index++) { -+ u32 function; -+ int err; -+ err = of_property_read_u32_index( -+ node, -+ "brcm,function", -+ index, -+ &function); -+ if (err == 0) { -+ if (function == 1) /* Output */ -+ gpio_out_pin = pin; -+ else if (function == 0) /* Input */ -+ gpio_in_pin = pin; -+ } -+ } -+} -+ -+static int init_port(void) -+{ -+ int i, nlow, nhigh; -+ struct device_node *node; -+ -+ node = lirc_rpi_dev->dev.of_node; -+ -+ gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip); -+ -+ /* -+ * Because of the lack of a setpull function, only support -+ * pinctrl-bcm2835 if using device tree. -+ */ -+ if (!gpiochip && node) -+ gpiochip = gpiochip_find("pinctrl-bcm2835", is_right_chip); -+ -+ if (!gpiochip) { -+ pr_err(LIRC_DRIVER_NAME ": gpio chip not found!\n"); -+ return -ENODEV; -+ } -+ -+ if (node) { -+ struct device_node *pins_node; -+ -+ pins_node = of_parse_phandle(node, "pinctrl-0", 0); -+ if (!pins_node) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": pinctrl settings not found!\n"); -+ return -EINVAL; -+ } -+ -+ read_pin_settings(pins_node); -+ -+ of_property_read_u32(node, "rpi,sense", &sense); -+ -+ read_bool_property(node, "rpi,softcarrier", &softcarrier); -+ -+ read_bool_property(node, "rpi,invert", &invert); -+ -+ read_bool_property(node, "rpi,debug", &debug); -+ -+ } else { -+ return -EINVAL; -+ } -+ -+ gpiochip->set(gpiochip, gpio_out_pin, invert); -+ -+ irq_num = gpiochip->to_irq(gpiochip, gpio_in_pin); -+ dprintk("to_irq %d\n", irq_num); -+ -+ /* if pin is high, then this must be an active low receiver. */ -+ if (sense == -1) { -+ /* wait 1/2 sec for the power supply */ -+ msleep(500); -+ -+ /* -+ * probe 9 times every 0.04s, collect "votes" for -+ * active high/low -+ */ -+ nlow = 0; -+ nhigh = 0; -+ for (i = 0; i < 9; i++) { -+ if (gpiochip->get(gpiochip, gpio_in_pin)) -+ nlow++; -+ else -+ nhigh++; -+ msleep(40); -+ } -+ sense = (nlow >= nhigh ? 1 : 0); -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": auto-detected active %s receiver on GPIO pin %d\n", -+ sense ? "low" : "high", gpio_in_pin); -+ } else { -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": manually using active %s receiver on GPIO pin %d\n", -+ sense ? "low" : "high", gpio_in_pin); -+ auto_sense = 0; -+ } -+ -+ return 0; -+} -+ -+// called when the character device is opened -+static int set_use_inc(void *data) -+{ -+ int result; -+ -+ /* initialize timestamp */ -+ do_gettimeofday(&lasttv); -+ -+ result = request_irq(irq_num, -+ (irq_handler_t) irq_handler, -+ IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING, -+ LIRC_DRIVER_NAME, (void*) 0); -+ -+ switch (result) { -+ case -EBUSY: -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": IRQ %d is busy\n", -+ irq_num); -+ return -EBUSY; -+ case -EINVAL: -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": Bad irq number or handler\n"); -+ return -EINVAL; -+ default: -+ dprintk("Interrupt %d obtained\n", -+ irq_num); -+ break; -+ }; -+ -+ /* initialize pulse/space widths */ -+ init_timing_params(duty_cycle, freq); -+ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+ /* GPIO Pin Falling/Rising Edge Detect Disable */ -+ irq_set_irq_type(irq_num, 0); -+ disable_irq(irq_num); -+ -+ free_irq(irq_num, (void *) 0); -+ -+ dprintk(KERN_INFO LIRC_DRIVER_NAME -+ ": freed IRQ %d\n", irq_num); -+} -+ -+static ssize_t lirc_write(struct file *file, const char *buf, -+ size_t n, loff_t *ppos) -+{ -+ int i, count; -+ unsigned long flags; -+ long delta = 0; -+ int *wbuf; -+ -+ count = n / sizeof(int); -+ if (n % sizeof(int) || count % 2 == 0) -+ return -EINVAL; -+ wbuf = memdup_user(buf, n); -+ if (IS_ERR(wbuf)) -+ return PTR_ERR(wbuf); -+ spin_lock_irqsave(&lock, flags); -+ -+ for (i = 0; i < count; i++) { -+ if (i%2) -+ send_space(wbuf[i] - delta); -+ else -+ delta = send_pulse(wbuf[i]); -+ } -+ gpiochip->set(gpiochip, gpio_out_pin, invert); -+ -+ spin_unlock_irqrestore(&lock, flags); -+ kfree(wbuf); -+ return n; -+} -+ -+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -+{ -+ int result; -+ __u32 value; -+ -+ switch (cmd) { -+ case LIRC_GET_SEND_MODE: -+ return -ENOIOCTLCMD; -+ break; -+ -+ case LIRC_SET_SEND_MODE: -+ result = get_user(value, (__u32 *) arg); -+ if (result) -+ return result; -+ /* only LIRC_MODE_PULSE supported */ -+ if (value != LIRC_MODE_PULSE) -+ return -ENOSYS; -+ break; -+ -+ case LIRC_GET_LENGTH: -+ return -ENOSYS; -+ break; -+ -+ case LIRC_SET_SEND_DUTY_CYCLE: -+ dprintk("SET_SEND_DUTY_CYCLE\n"); -+ result = get_user(value, (__u32 *) arg); -+ if (result) -+ return result; -+ if (value <= 0 || value > 100) -+ return -EINVAL; -+ return init_timing_params(value, freq); -+ break; -+ -+ case LIRC_SET_SEND_CARRIER: -+ dprintk("SET_SEND_CARRIER\n"); -+ result = get_user(value, (__u32 *) arg); -+ if (result) -+ return result; -+ if (value > 500000 || value < 20000) -+ return -EINVAL; -+ return init_timing_params(duty_cycle, value); -+ break; -+ -+ default: -+ return lirc_dev_fop_ioctl(filep, cmd, arg); -+ } -+ return 0; -+} -+ -+static const struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .write = lirc_write, -+ .unlocked_ioctl = lirc_ioctl, -+ .read = lirc_dev_fop_read, -+ .poll = lirc_dev_fop_poll, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+ .llseek = no_llseek, -+}; -+ -+static struct lirc_driver driver = { -+ .name = LIRC_DRIVER_NAME, -+ .minor = -1, -+ .code_length = 1, -+ .sample_rate = 0, -+ .data = NULL, -+ .add_to_buf = NULL, -+ .rbuf = &rbuf, -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .fops = &lirc_fops, -+ .dev = NULL, -+ .owner = THIS_MODULE, -+}; -+ -+static const struct of_device_id lirc_rpi_of_match[] = { -+ { .compatible = "rpi,lirc-rpi", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, lirc_rpi_of_match); -+ -+static struct platform_driver lirc_rpi_driver = { -+ .driver = { -+ .name = LIRC_DRIVER_NAME, -+ .owner = THIS_MODULE, -+ .of_match_table = of_match_ptr(lirc_rpi_of_match), -+ }, -+}; -+ -+static int __init lirc_rpi_init(void) -+{ -+ struct device_node *node; -+ int result; -+ -+ /* Init read buffer. */ -+ result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN); -+ if (result < 0) -+ return -ENOMEM; -+ -+ result = platform_driver_register(&lirc_rpi_driver); -+ if (result) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": lirc register returned %d\n", result); -+ goto exit_buffer_free; -+ } -+ -+ node = of_find_compatible_node(NULL, NULL, -+ lirc_rpi_of_match[0].compatible); -+ -+ if (node) { -+ /* DT-enabled */ -+ lirc_rpi_dev = of_find_device_by_node(node); -+ WARN_ON(lirc_rpi_dev->dev.of_node != node); -+ of_node_put(node); -+ } -+ else { -+ lirc_rpi_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0); -+ if (!lirc_rpi_dev) { -+ result = -ENOMEM; -+ goto exit_driver_unregister; -+ } -+ -+ result = platform_device_add(lirc_rpi_dev); -+ if (result) -+ goto exit_device_put; -+ } -+ -+ return 0; -+ -+ exit_device_put: -+ platform_device_put(lirc_rpi_dev); -+ -+ exit_driver_unregister: -+ platform_driver_unregister(&lirc_rpi_driver); -+ -+ exit_buffer_free: -+ lirc_buffer_free(&rbuf); -+ -+ return result; -+} -+ -+static void lirc_rpi_exit(void) -+{ -+ if (!lirc_rpi_dev->dev.of_node) -+ platform_device_unregister(lirc_rpi_dev); -+ platform_driver_unregister(&lirc_rpi_driver); -+ lirc_buffer_free(&rbuf); -+} -+ -+static int __init lirc_rpi_init_module(void) -+{ -+ int result; -+ -+ result = lirc_rpi_init(); -+ if (result) -+ return result; -+ -+ result = init_port(); -+ if (result < 0) -+ goto exit_rpi; -+ -+ driver.features = LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SET_SEND_CARRIER | -+ LIRC_CAN_SEND_PULSE | -+ LIRC_CAN_REC_MODE2; -+ -+ driver.dev = &lirc_rpi_dev->dev; -+ driver.minor = lirc_register_driver(&driver); -+ -+ if (driver.minor < 0) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": device registration failed with %d\n", result); -+ result = -EIO; -+ goto exit_rpi; -+ } -+ -+ printk(KERN_INFO LIRC_DRIVER_NAME ": driver registered!\n"); -+ -+ return 0; -+ -+ exit_rpi: -+ lirc_rpi_exit(); -+ -+ return result; -+} -+ -+static void __exit lirc_rpi_exit_module(void) -+{ -+ lirc_unregister_driver(driver.minor); -+ -+ gpio_free(gpio_out_pin); -+ gpio_free(gpio_in_pin); -+ -+ lirc_rpi_exit(); -+ -+ printk(KERN_INFO LIRC_DRIVER_NAME ": cleaned up module\n"); -+} -+ -+module_init(lirc_rpi_init_module); -+module_exit(lirc_rpi_exit_module); -+ -+MODULE_DESCRIPTION("Infra-red receiver and blaster driver for Raspberry Pi GPIO."); -+MODULE_AUTHOR("Aron Robert Szabo <aron@reon.hu>"); -+MODULE_AUTHOR("Michael Bishop <cleverca22@gmail.com>"); -+MODULE_LICENSE("GPL"); -+ -+module_param(gpio_out_pin, int, S_IRUGO); -+MODULE_PARM_DESC(gpio_out_pin, "GPIO output/transmitter pin number of the BCM" -+ " processor. (default 17"); -+ -+module_param(gpio_in_pin, int, S_IRUGO); -+MODULE_PARM_DESC(gpio_in_pin, "GPIO input pin number of the BCM processor." -+ " (default 18"); -+ -+module_param(gpio_in_pull, int, S_IRUGO); -+MODULE_PARM_DESC(gpio_in_pull, "GPIO input pin pull configuration." -+ " (0 = off, 1 = up, 2 = down, default down)"); -+ -+module_param(sense, int, S_IRUGO); -+MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit" -+ " (0 = active high, 1 = active low )"); -+ -+module_param(softcarrier, bool, S_IRUGO); -+MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)"); -+ -+module_param(invert, bool, S_IRUGO); -+MODULE_PARM_DESC(invert, "Invert output (0 = off, 1 = on, default off"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); ---- /dev/null -+++ b/include/linux/platform_data/bcm2708.h -@@ -0,0 +1,23 @@ -+/* -+ * include/linux/platform_data/bcm2708.h -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * (C) 2014 Julian Scheel <julian@jusst.de> -+ * -+ */ -+#ifndef __BCM2708_H_ -+#define __BCM2708_H_ -+ -+typedef enum { -+ BCM2708_PULL_OFF, -+ BCM2708_PULL_UP, -+ BCM2708_PULL_DOWN -+} bcm2708_gpio_pull_t; -+ -+extern int bcm2708_gpio_setpull(struct gpio_chip *gc, unsigned offset, -+ bcm2708_gpio_pull_t value); -+ -+#endif |