linux/drivers/media/rc/gpio-ir-recv.c
<<
>>
Prefs
   1/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
   2 *
   3 * This program is free software; you can redistribute it and/or modify
   4 * it under the terms of the GNU General Public License version 2 and
   5 * only version 2 as published by the Free Software Foundation.
   6 *
   7 * This program is distributed in the hope that it will be useful,
   8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
   9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10 * GNU General Public License for more details.
  11 */
  12
  13#include <linux/kernel.h>
  14#include <linux/init.h>
  15#include <linux/module.h>
  16#include <linux/interrupt.h>
  17#include <linux/gpio.h>
  18#include <linux/slab.h>
  19#include <linux/of.h>
  20#include <linux/of_gpio.h>
  21#include <linux/platform_device.h>
  22#include <linux/irq.h>
  23#include <media/rc-core.h>
  24#include <media/gpio-ir-recv.h>
  25
  26#define GPIO_IR_DRIVER_NAME     "gpio-rc-recv"
  27#define GPIO_IR_DEVICE_NAME     "gpio_ir_recv"
  28
  29struct gpio_rc_dev {
  30        struct rc_dev *rcdev;
  31        int gpio_nr;
  32        bool active_low;
  33};
  34
  35#ifdef CONFIG_OF
  36/*
  37 * Translate OpenFirmware node properties into platform_data
  38 */
  39static int gpio_ir_recv_get_devtree_pdata(struct device *dev,
  40                                  struct gpio_ir_recv_platform_data *pdata)
  41{
  42        struct device_node *np = dev->of_node;
  43        enum of_gpio_flags flags;
  44        int gpio;
  45
  46        gpio = of_get_gpio_flags(np, 0, &flags);
  47        if (gpio < 0) {
  48                if (gpio != -EPROBE_DEFER)
  49                        dev_err(dev, "Failed to get gpio flags (%d)\n", gpio);
  50                return gpio;
  51        }
  52
  53        pdata->gpio_nr = gpio;
  54        pdata->active_low = (flags & OF_GPIO_ACTIVE_LOW);
  55        /* probe() takes care of map_name == NULL or allowed_protos == 0 */
  56        pdata->map_name = of_get_property(np, "linux,rc-map-name", NULL);
  57        pdata->allowed_protos = 0;
  58
  59        return 0;
  60}
  61
  62static struct of_device_id gpio_ir_recv_of_match[] = {
  63        { .compatible = "gpio-ir-receiver", },
  64        { },
  65};
  66MODULE_DEVICE_TABLE(of, gpio_ir_recv_of_match);
  67
  68#else /* !CONFIG_OF */
  69
  70#define gpio_ir_recv_get_devtree_pdata(dev, pdata)      (-ENOSYS)
  71
  72#endif
  73
  74static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
  75{
  76        struct gpio_rc_dev *gpio_dev = dev_id;
  77        int gval;
  78        int rc = 0;
  79        enum raw_event_type type = IR_SPACE;
  80
  81        gval = gpio_get_value_cansleep(gpio_dev->gpio_nr);
  82
  83        if (gval < 0)
  84                goto err_get_value;
  85
  86        if (gpio_dev->active_low)
  87                gval = !gval;
  88
  89        if (gval == 1)
  90                type = IR_PULSE;
  91
  92        rc = ir_raw_event_store_edge(gpio_dev->rcdev, type);
  93        if (rc < 0)
  94                goto err_get_value;
  95
  96        ir_raw_event_handle(gpio_dev->rcdev);
  97
  98err_get_value:
  99        return IRQ_HANDLED;
 100}
 101
 102static int gpio_ir_recv_probe(struct platform_device *pdev)
 103{
 104        struct gpio_rc_dev *gpio_dev;
 105        struct rc_dev *rcdev;
 106        const struct gpio_ir_recv_platform_data *pdata =
 107                                        pdev->dev.platform_data;
 108        int rc;
 109
 110        if (pdev->dev.of_node) {
 111                struct gpio_ir_recv_platform_data *dtpdata =
 112                        devm_kzalloc(&pdev->dev, sizeof(*dtpdata), GFP_KERNEL);
 113                if (!dtpdata)
 114                        return -ENOMEM;
 115                rc = gpio_ir_recv_get_devtree_pdata(&pdev->dev, dtpdata);
 116                if (rc)
 117                        return rc;
 118                pdata = dtpdata;
 119        }
 120
 121        if (!pdata)
 122                return -EINVAL;
 123
 124        if (pdata->gpio_nr < 0)
 125                return -EINVAL;
 126
 127        gpio_dev = kzalloc(sizeof(struct gpio_rc_dev), GFP_KERNEL);
 128        if (!gpio_dev)
 129                return -ENOMEM;
 130
 131        rcdev = rc_allocate_device();
 132        if (!rcdev) {
 133                rc = -ENOMEM;
 134                goto err_allocate_device;
 135        }
 136
 137        rcdev->priv = gpio_dev;
 138        rcdev->driver_type = RC_DRIVER_IR_RAW;
 139        rcdev->input_name = GPIO_IR_DEVICE_NAME;
 140        rcdev->input_phys = GPIO_IR_DEVICE_NAME "/input0";
 141        rcdev->input_id.bustype = BUS_HOST;
 142        rcdev->input_id.vendor = 0x0001;
 143        rcdev->input_id.product = 0x0001;
 144        rcdev->input_id.version = 0x0100;
 145        rcdev->dev.parent = &pdev->dev;
 146        rcdev->driver_name = GPIO_IR_DRIVER_NAME;
 147        if (pdata->allowed_protos)
 148                rcdev->allowed_protocols = pdata->allowed_protos;
 149        else
 150                rcdev->allowed_protocols = RC_BIT_ALL;
 151        rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY;
 152
 153        gpio_dev->rcdev = rcdev;
 154        gpio_dev->gpio_nr = pdata->gpio_nr;
 155        gpio_dev->active_low = pdata->active_low;
 156
 157        rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv");
 158        if (rc < 0)
 159                goto err_gpio_request;
 160        rc  = gpio_direction_input(pdata->gpio_nr);
 161        if (rc < 0)
 162                goto err_gpio_direction_input;
 163
 164        rc = rc_register_device(rcdev);
 165        if (rc < 0) {
 166                dev_err(&pdev->dev, "failed to register rc device\n");
 167                goto err_register_rc_device;
 168        }
 169
 170        platform_set_drvdata(pdev, gpio_dev);
 171
 172        rc = request_any_context_irq(gpio_to_irq(pdata->gpio_nr),
 173                                gpio_ir_recv_irq,
 174                        IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
 175                                        "gpio-ir-recv-irq", gpio_dev);
 176        if (rc < 0)
 177                goto err_request_irq;
 178
 179        return 0;
 180
 181err_request_irq:
 182        rc_unregister_device(rcdev);
 183        rcdev = NULL;
 184err_register_rc_device:
 185err_gpio_direction_input:
 186        gpio_free(pdata->gpio_nr);
 187err_gpio_request:
 188        rc_free_device(rcdev);
 189err_allocate_device:
 190        kfree(gpio_dev);
 191        return rc;
 192}
 193
 194static int gpio_ir_recv_remove(struct platform_device *pdev)
 195{
 196        struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
 197
 198        free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
 199        rc_unregister_device(gpio_dev->rcdev);
 200        gpio_free(gpio_dev->gpio_nr);
 201        kfree(gpio_dev);
 202        return 0;
 203}
 204
 205#ifdef CONFIG_PM
 206static int gpio_ir_recv_suspend(struct device *dev)
 207{
 208        struct platform_device *pdev = to_platform_device(dev);
 209        struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
 210
 211        if (device_may_wakeup(dev))
 212                enable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
 213        else
 214                disable_irq(gpio_to_irq(gpio_dev->gpio_nr));
 215
 216        return 0;
 217}
 218
 219static int gpio_ir_recv_resume(struct device *dev)
 220{
 221        struct platform_device *pdev = to_platform_device(dev);
 222        struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
 223
 224        if (device_may_wakeup(dev))
 225                disable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
 226        else
 227                enable_irq(gpio_to_irq(gpio_dev->gpio_nr));
 228
 229        return 0;
 230}
 231
 232static const struct dev_pm_ops gpio_ir_recv_pm_ops = {
 233        .suspend        = gpio_ir_recv_suspend,
 234        .resume         = gpio_ir_recv_resume,
 235};
 236#endif
 237
 238static struct platform_driver gpio_ir_recv_driver = {
 239        .probe  = gpio_ir_recv_probe,
 240        .remove = gpio_ir_recv_remove,
 241        .driver = {
 242                .name   = GPIO_IR_DRIVER_NAME,
 243                .of_match_table = of_match_ptr(gpio_ir_recv_of_match),
 244#ifdef CONFIG_PM
 245                .pm     = &gpio_ir_recv_pm_ops,
 246#endif
 247        },
 248};
 249module_platform_driver(gpio_ir_recv_driver);
 250
 251MODULE_DESCRIPTION("GPIO IR Receiver driver");
 252MODULE_LICENSE("GPL v2");
 253