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 <linux/platform_data/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        struct timer_list flush_timer;
  34};
  35
  36#ifdef CONFIG_OF
  37/*
  38 * Translate OpenFirmware node properties into platform_data
  39 */
  40static int gpio_ir_recv_get_devtree_pdata(struct device *dev,
  41                                  struct gpio_ir_recv_platform_data *pdata)
  42{
  43        struct device_node *np = dev->of_node;
  44        enum of_gpio_flags flags;
  45        int gpio;
  46
  47        gpio = of_get_gpio_flags(np, 0, &flags);
  48        if (gpio < 0) {
  49                if (gpio != -EPROBE_DEFER)
  50                        dev_err(dev, "Failed to get gpio flags (%d)\n", gpio);
  51                return gpio;
  52        }
  53
  54        pdata->gpio_nr = gpio;
  55        pdata->active_low = (flags & OF_GPIO_ACTIVE_LOW);
  56        /* probe() takes care of map_name == NULL or allowed_protos == 0 */
  57        pdata->map_name = of_get_property(np, "linux,rc-map-name", NULL);
  58        pdata->allowed_protos = 0;
  59
  60        return 0;
  61}
  62
  63static const struct of_device_id gpio_ir_recv_of_match[] = {
  64        { .compatible = "gpio-ir-receiver", },
  65        { },
  66};
  67MODULE_DEVICE_TABLE(of, gpio_ir_recv_of_match);
  68
  69#else /* !CONFIG_OF */
  70
  71#define gpio_ir_recv_get_devtree_pdata(dev, pdata)      (-ENOSYS)
  72
  73#endif
  74
  75static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
  76{
  77        struct gpio_rc_dev *gpio_dev = dev_id;
  78        int gval;
  79        int rc = 0;
  80        enum raw_event_type type = IR_SPACE;
  81
  82        gval = gpio_get_value(gpio_dev->gpio_nr);
  83
  84        if (gval < 0)
  85                goto err_get_value;
  86
  87        if (gpio_dev->active_low)
  88                gval = !gval;
  89
  90        if (gval == 1)
  91                type = IR_PULSE;
  92
  93        rc = ir_raw_event_store_edge(gpio_dev->rcdev, type);
  94        if (rc < 0)
  95                goto err_get_value;
  96
  97        mod_timer(&gpio_dev->flush_timer,
  98                  jiffies + nsecs_to_jiffies(gpio_dev->rcdev->timeout));
  99
 100        ir_raw_event_handle(gpio_dev->rcdev);
 101
 102err_get_value:
 103        return IRQ_HANDLED;
 104}
 105
 106static void flush_timer(unsigned long arg)
 107{
 108        struct gpio_rc_dev *gpio_dev = (struct gpio_rc_dev *)arg;
 109        DEFINE_IR_RAW_EVENT(ev);
 110
 111        ev.timeout = true;
 112        ev.duration = gpio_dev->rcdev->timeout;
 113        ir_raw_event_store(gpio_dev->rcdev, &ev);
 114        ir_raw_event_handle(gpio_dev->rcdev);
 115}
 116
 117static int gpio_ir_recv_probe(struct platform_device *pdev)
 118{
 119        struct gpio_rc_dev *gpio_dev;
 120        struct rc_dev *rcdev;
 121        const struct gpio_ir_recv_platform_data *pdata =
 122                                        pdev->dev.platform_data;
 123        int rc;
 124
 125        if (pdev->dev.of_node) {
 126                struct gpio_ir_recv_platform_data *dtpdata =
 127                        devm_kzalloc(&pdev->dev, sizeof(*dtpdata), GFP_KERNEL);
 128                if (!dtpdata)
 129                        return -ENOMEM;
 130                rc = gpio_ir_recv_get_devtree_pdata(&pdev->dev, dtpdata);
 131                if (rc)
 132                        return rc;
 133                pdata = dtpdata;
 134        }
 135
 136        if (!pdata)
 137                return -EINVAL;
 138
 139        if (pdata->gpio_nr < 0)
 140                return -EINVAL;
 141
 142        gpio_dev = kzalloc(sizeof(struct gpio_rc_dev), GFP_KERNEL);
 143        if (!gpio_dev)
 144                return -ENOMEM;
 145
 146        rcdev = rc_allocate_device();
 147        if (!rcdev) {
 148                rc = -ENOMEM;
 149                goto err_allocate_device;
 150        }
 151
 152        rcdev->priv = gpio_dev;
 153        rcdev->driver_type = RC_DRIVER_IR_RAW;
 154        rcdev->input_name = GPIO_IR_DEVICE_NAME;
 155        rcdev->input_phys = GPIO_IR_DEVICE_NAME "/input0";
 156        rcdev->input_id.bustype = BUS_HOST;
 157        rcdev->input_id.vendor = 0x0001;
 158        rcdev->input_id.product = 0x0001;
 159        rcdev->input_id.version = 0x0100;
 160        rcdev->dev.parent = &pdev->dev;
 161        rcdev->driver_name = GPIO_IR_DRIVER_NAME;
 162        rcdev->min_timeout = 0;
 163        rcdev->timeout = IR_DEFAULT_TIMEOUT;
 164        rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
 165        if (pdata->allowed_protos)
 166                rcdev->allowed_protocols = pdata->allowed_protos;
 167        else
 168                rcdev->allowed_protocols = RC_BIT_ALL;
 169        rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY;
 170
 171        gpio_dev->rcdev = rcdev;
 172        gpio_dev->gpio_nr = pdata->gpio_nr;
 173        gpio_dev->active_low = pdata->active_low;
 174
 175        setup_timer(&gpio_dev->flush_timer, flush_timer,
 176                    (unsigned long)gpio_dev);
 177
 178        rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv");
 179        if (rc < 0)
 180                goto err_gpio_request;
 181        rc  = gpio_direction_input(pdata->gpio_nr);
 182        if (rc < 0)
 183                goto err_gpio_direction_input;
 184
 185        rc = rc_register_device(rcdev);
 186        if (rc < 0) {
 187                dev_err(&pdev->dev, "failed to register rc device\n");
 188                goto err_register_rc_device;
 189        }
 190
 191        platform_set_drvdata(pdev, gpio_dev);
 192
 193        rc = request_any_context_irq(gpio_to_irq(pdata->gpio_nr),
 194                                gpio_ir_recv_irq,
 195                        IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
 196                                        "gpio-ir-recv-irq", gpio_dev);
 197        if (rc < 0)
 198                goto err_request_irq;
 199
 200        return 0;
 201
 202err_request_irq:
 203        rc_unregister_device(rcdev);
 204        rcdev = NULL;
 205err_register_rc_device:
 206err_gpio_direction_input:
 207        gpio_free(pdata->gpio_nr);
 208err_gpio_request:
 209        rc_free_device(rcdev);
 210err_allocate_device:
 211        kfree(gpio_dev);
 212        return rc;
 213}
 214
 215static int gpio_ir_recv_remove(struct platform_device *pdev)
 216{
 217        struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
 218
 219        free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
 220        del_timer_sync(&gpio_dev->flush_timer);
 221        rc_unregister_device(gpio_dev->rcdev);
 222        gpio_free(gpio_dev->gpio_nr);
 223        kfree(gpio_dev);
 224        return 0;
 225}
 226
 227#ifdef CONFIG_PM
 228static int gpio_ir_recv_suspend(struct device *dev)
 229{
 230        struct platform_device *pdev = to_platform_device(dev);
 231        struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
 232
 233        if (device_may_wakeup(dev))
 234                enable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
 235        else
 236                disable_irq(gpio_to_irq(gpio_dev->gpio_nr));
 237
 238        return 0;
 239}
 240
 241static int gpio_ir_recv_resume(struct device *dev)
 242{
 243        struct platform_device *pdev = to_platform_device(dev);
 244        struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
 245
 246        if (device_may_wakeup(dev))
 247                disable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
 248        else
 249                enable_irq(gpio_to_irq(gpio_dev->gpio_nr));
 250
 251        return 0;
 252}
 253
 254static const struct dev_pm_ops gpio_ir_recv_pm_ops = {
 255        .suspend        = gpio_ir_recv_suspend,
 256        .resume         = gpio_ir_recv_resume,
 257};
 258#endif
 259
 260static struct platform_driver gpio_ir_recv_driver = {
 261        .probe  = gpio_ir_recv_probe,
 262        .remove = gpio_ir_recv_remove,
 263        .driver = {
 264                .name   = GPIO_IR_DRIVER_NAME,
 265                .of_match_table = of_match_ptr(gpio_ir_recv_of_match),
 266#ifdef CONFIG_PM
 267                .pm     = &gpio_ir_recv_pm_ops,
 268#endif
 269        },
 270};
 271module_platform_driver(gpio_ir_recv_driver);
 272
 273MODULE_DESCRIPTION("GPIO IR Receiver driver");
 274MODULE_LICENSE("GPL v2");
 275