From f3c1830096661e270f11f2a33ffb7274f50c90a6 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 18 Dec 2014 16:48:32 +0000 Subject: [PATCH 068/114] 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 --- arch/arm/boot/dts/lirc-rpi-overlay.dts | 57 ++++++++++++ drivers/staging/media/lirc/lirc_rpi.c | 154 +++++++++++++++++++++++++++------ 2 files changed, 183 insertions(+), 28 deletions(-) create mode 100644 arch/arm/boot/dts/lirc-rpi-overlay.dts --- /dev/null +++ b/arch/arm/boot/dts/lirc-rpi-overlay.dts @@ -0,0 +1,57 @@ +// Definitions for lirc-rpi module +/dts-v1/; +/plugin/; + +/ { + compatible = "brcm,bcm2708"; + + fragment@0 { + target-path = "/"; + __overlay__ { + lirc_rpi: lirc_rpi { + compatible = "rpi,lirc-rpi"; + pinctrl-names = "default"; + pinctrl-0 = <&lirc_pins>; + status = "okay"; + + // Override autodetection of IR receiver circuit + // (0 = active high, 1 = active low, -1 = no override ) + rpi,sense = <0xffffffff>; + + // Software carrier + // (0 = off, 1 = on) + rpi,softcarrier = <1>; + + // Invert output + // (0 = off, 1 = on) + rpi,invert = <0>; + + // Enable debugging messages + // (0 = off, 1 = on) + rpi,debug = <0>; + }; + }; + }; + + fragment@1 { + target = <&gpio>; + __overlay__ { + lirc_pins: lirc_pins { + brcm,pins = <17 18>; + brcm,function = <1 0>; // out in + brcm,pull = <0 1>; // off down + }; + }; + }; + + __overrides__ { + gpio_out_pin = <&lirc_pins>,"brcm,pins:0"; + gpio_in_pin = <&lirc_pins>,"brcm,pins:4"; + gpio_in_pull = <&lirc_pins>,"brcm,pull:4"; + + sense = <&lirc_rpi>,"rpi,sense:0"; + softcarrier = <&lirc_rpi>,"rpi,softcarrier:0"; + invert = <&lirc_rpi>,"rpi,invert:0"; + debug = <&lirc_rpi>,"rpi,debug:0"; + }; +}; --- a/drivers/staging/media/lirc/lirc_rpi.c +++ b/drivers/staging/media/lirc/lirc_rpi.c @@ -40,6 +40,7 @@ #include #include #include +#include #include @@ -295,32 +296,117 @@ static int is_right_chip(struct gpio_chi 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, ret; + struct device_node *node; + + node = lirc_rpi_dev->dev.of_node; gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip); - if (!gpiochip) + /* + * 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"); + ret = -EINVAL; + goto exit_init_port; + } + + 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 + { + if (gpio_in_pin >= BCM2708_NR_GPIOS || + gpio_out_pin >= BCM2708_NR_GPIOS) { + ret = -EINVAL; + printk(KERN_ERR LIRC_DRIVER_NAME + ": invalid GPIO pin(s) specified!\n"); + goto exit_init_port; + } + + if (gpio_request(gpio_out_pin, LIRC_DRIVER_NAME " ir/out")) { + printk(KERN_ALERT LIRC_DRIVER_NAME + ": cant claim gpio pin %d\n", gpio_out_pin); + ret = -ENODEV; + goto exit_init_port; + } + + if (gpio_request(gpio_in_pin, LIRC_DRIVER_NAME " ir/in")) { + printk(KERN_ALERT LIRC_DRIVER_NAME + ": cant claim gpio pin %d\n", gpio_in_pin); + ret = -ENODEV; + goto exit_gpio_free_out_pin; + } + + bcm2708_gpio_setpull(gpiochip, gpio_in_pin, gpio_in_pull); + gpiochip->direction_input(gpiochip, gpio_in_pin); + gpiochip->direction_output(gpiochip, gpio_out_pin, 1); + } - if (gpio_request(gpio_out_pin, LIRC_DRIVER_NAME " ir/out")) { - printk(KERN_ALERT LIRC_DRIVER_NAME - ": cant claim gpio pin %d\n", gpio_out_pin); - ret = -ENODEV; - goto exit_init_port; - } - - if (gpio_request(gpio_in_pin, LIRC_DRIVER_NAME " ir/in")) { - printk(KERN_ALERT LIRC_DRIVER_NAME - ": cant claim gpio pin %d\n", gpio_in_pin); - ret = -ENODEV; - goto exit_gpio_free_out_pin; - } - - bcm2708_gpio_setpull(gpiochip, gpio_in_pin, gpio_in_pull); - gpiochip->direction_input(gpiochip, gpio_in_pin); - gpiochip->direction_output(gpiochip, gpio_out_pin, 1); gpiochip->set(gpiochip, gpio_out_pin, invert); irq_num = gpiochip->to_irq(gpiochip, gpio_in_pin); @@ -514,15 +600,23 @@ static struct lirc_driver driver = { .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. */ @@ -537,15 +631,26 @@ static int __init lirc_rpi_init(void) goto exit_buffer_free; } - lirc_rpi_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0); - if (!lirc_rpi_dev) { - result = -ENOMEM; - goto exit_driver_unregister; - } + node = of_find_compatible_node(NULL, NULL, + lirc_rpi_of_match[0].compatible); - result = platform_device_add(lirc_rpi_dev); - if (result) - goto exit_device_put; + 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; @@ -577,13 +682,6 @@ static int __init lirc_rpi_init_module(v if (result) return result; - if (gpio_in_pin >= BCM2708_NR_GPIOS || gpio_out_pin >= BCM2708_NR_GPIOS) { - result = -EINVAL; - printk(KERN_ERR LIRC_DRIVER_NAME - ": invalid GPIO pin(s) specified!\n"); - goto exit_rpi; - } - result = init_port(); if (result < 0) goto exit_rpi;