diff options
author | Ravi Kumar V <kumarrav@codeaurora.org> | 2012-02-27 23:51:40 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-03-08 09:14:10 -0500 |
commit | fd0f6851eb46512a6df2961923a0c24edc0a55b9 (patch) | |
tree | c5fc735f8fd152b9de4896d40745a3eac9f3567d /drivers | |
parent | c5f79f6a0c70a390d07bcea4d7df6219f78e0904 (diff) |
[media] rc: Add support for GPIO based IR Receiver driver
Adds GPIO based IR Receiver driver. It decodes signals using decoders
available in rc framework.
Signed-off-by: Ravi Kumar V <kumarrav@codeaurora.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/rc/Kconfig | 9 | ||||
-rw-r--r-- | drivers/media/rc/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/rc/gpio-ir-recv.c | 205 |
3 files changed, 215 insertions, 0 deletions
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 4df4affeea5f..a3fbb21350e9 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig | |||
@@ -266,4 +266,13 @@ config RC_LOOPBACK | |||
266 | To compile this driver as a module, choose M here: the module will | 266 | To compile this driver as a module, choose M here: the module will |
267 | be called rc_loopback. | 267 | be called rc_loopback. |
268 | 268 | ||
269 | config IR_GPIO_CIR | ||
270 | tristate "GPIO IR remote control" | ||
271 | depends on RC_CORE | ||
272 | ---help--- | ||
273 | Say Y if you want to use GPIO based IR Receiver. | ||
274 | |||
275 | To compile this driver as a module, choose M here: the module will | ||
276 | be called gpio-ir-recv. | ||
277 | |||
269 | endif #RC_CORE | 278 | endif #RC_CORE |
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index fb3dee2dd845..29f364f88a94 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile | |||
@@ -26,3 +26,4 @@ obj-$(CONFIG_IR_REDRAT3) += redrat3.o | |||
26 | obj-$(CONFIG_IR_STREAMZAP) += streamzap.o | 26 | obj-$(CONFIG_IR_STREAMZAP) += streamzap.o |
27 | obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o | 27 | obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o |
28 | obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o | 28 | obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o |
29 | obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o | ||
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c new file mode 100644 index 000000000000..6744479a5389 --- /dev/null +++ b/drivers/media/rc/gpio-ir-recv.c | |||
@@ -0,0 +1,205 @@ | |||
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/platform_device.h> | ||
20 | #include <linux/irq.h> | ||
21 | #include <media/rc-core.h> | ||
22 | #include <media/gpio-ir-recv.h> | ||
23 | |||
24 | #define GPIO_IR_DRIVER_NAME "gpio-rc-recv" | ||
25 | #define GPIO_IR_DEVICE_NAME "gpio_ir_recv" | ||
26 | |||
27 | struct gpio_rc_dev { | ||
28 | struct rc_dev *rcdev; | ||
29 | unsigned int gpio_nr; | ||
30 | bool active_low; | ||
31 | }; | ||
32 | |||
33 | static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id) | ||
34 | { | ||
35 | struct gpio_rc_dev *gpio_dev = dev_id; | ||
36 | unsigned int gval; | ||
37 | int rc = 0; | ||
38 | enum raw_event_type type = IR_SPACE; | ||
39 | |||
40 | gval = gpio_get_value_cansleep(gpio_dev->gpio_nr); | ||
41 | |||
42 | if (gval < 0) | ||
43 | goto err_get_value; | ||
44 | |||
45 | if (gpio_dev->active_low) | ||
46 | gval = !gval; | ||
47 | |||
48 | if (gval == 1) | ||
49 | type = IR_PULSE; | ||
50 | |||
51 | rc = ir_raw_event_store_edge(gpio_dev->rcdev, type); | ||
52 | if (rc < 0) | ||
53 | goto err_get_value; | ||
54 | |||
55 | ir_raw_event_handle(gpio_dev->rcdev); | ||
56 | |||
57 | err_get_value: | ||
58 | return IRQ_HANDLED; | ||
59 | } | ||
60 | |||
61 | static int __devinit gpio_ir_recv_probe(struct platform_device *pdev) | ||
62 | { | ||
63 | struct gpio_rc_dev *gpio_dev; | ||
64 | struct rc_dev *rcdev; | ||
65 | const struct gpio_ir_recv_platform_data *pdata = | ||
66 | pdev->dev.platform_data; | ||
67 | int rc; | ||
68 | |||
69 | if (!pdata) | ||
70 | return -EINVAL; | ||
71 | |||
72 | if (pdata->gpio_nr < 0) | ||
73 | return -EINVAL; | ||
74 | |||
75 | gpio_dev = kzalloc(sizeof(struct gpio_rc_dev), GFP_KERNEL); | ||
76 | if (!gpio_dev) | ||
77 | return -ENOMEM; | ||
78 | |||
79 | rcdev = rc_allocate_device(); | ||
80 | if (!rcdev) { | ||
81 | rc = -ENOMEM; | ||
82 | goto err_allocate_device; | ||
83 | } | ||
84 | |||
85 | rcdev->driver_type = RC_DRIVER_IR_RAW; | ||
86 | rcdev->allowed_protos = RC_TYPE_ALL; | ||
87 | rcdev->input_name = GPIO_IR_DEVICE_NAME; | ||
88 | rcdev->input_id.bustype = BUS_HOST; | ||
89 | rcdev->driver_name = GPIO_IR_DRIVER_NAME; | ||
90 | rcdev->map_name = RC_MAP_EMPTY; | ||
91 | |||
92 | gpio_dev->rcdev = rcdev; | ||
93 | gpio_dev->gpio_nr = pdata->gpio_nr; | ||
94 | gpio_dev->active_low = pdata->active_low; | ||
95 | |||
96 | rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv"); | ||
97 | if (rc < 0) | ||
98 | goto err_gpio_request; | ||
99 | rc = gpio_direction_input(pdata->gpio_nr); | ||
100 | if (rc < 0) | ||
101 | goto err_gpio_direction_input; | ||
102 | |||
103 | rc = rc_register_device(rcdev); | ||
104 | if (rc < 0) { | ||
105 | dev_err(&pdev->dev, "failed to register rc device\n"); | ||
106 | goto err_register_rc_device; | ||
107 | } | ||
108 | |||
109 | platform_set_drvdata(pdev, gpio_dev); | ||
110 | |||
111 | rc = request_any_context_irq(gpio_to_irq(pdata->gpio_nr), | ||
112 | gpio_ir_recv_irq, | ||
113 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, | ||
114 | "gpio-ir-recv-irq", gpio_dev); | ||
115 | if (rc < 0) | ||
116 | goto err_request_irq; | ||
117 | |||
118 | return 0; | ||
119 | |||
120 | err_request_irq: | ||
121 | platform_set_drvdata(pdev, NULL); | ||
122 | rc_unregister_device(rcdev); | ||
123 | err_register_rc_device: | ||
124 | err_gpio_direction_input: | ||
125 | gpio_free(pdata->gpio_nr); | ||
126 | err_gpio_request: | ||
127 | rc_free_device(rcdev); | ||
128 | rcdev = NULL; | ||
129 | err_allocate_device: | ||
130 | kfree(gpio_dev); | ||
131 | return rc; | ||
132 | } | ||
133 | |||
134 | static int __devexit gpio_ir_recv_remove(struct platform_device *pdev) | ||
135 | { | ||
136 | struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); | ||
137 | |||
138 | free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev); | ||
139 | platform_set_drvdata(pdev, NULL); | ||
140 | rc_unregister_device(gpio_dev->rcdev); | ||
141 | gpio_free(gpio_dev->gpio_nr); | ||
142 | rc_free_device(gpio_dev->rcdev); | ||
143 | kfree(gpio_dev); | ||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | #ifdef CONFIG_PM | ||
148 | static int gpio_ir_recv_suspend(struct device *dev) | ||
149 | { | ||
150 | struct platform_device *pdev = to_platform_device(dev); | ||
151 | struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); | ||
152 | |||
153 | if (device_may_wakeup(dev)) | ||
154 | enable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr)); | ||
155 | else | ||
156 | disable_irq(gpio_to_irq(gpio_dev->gpio_nr)); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static int gpio_ir_recv_resume(struct device *dev) | ||
162 | { | ||
163 | struct platform_device *pdev = to_platform_device(dev); | ||
164 | struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); | ||
165 | |||
166 | if (device_may_wakeup(dev)) | ||
167 | disable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr)); | ||
168 | else | ||
169 | enable_irq(gpio_to_irq(gpio_dev->gpio_nr)); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static const struct dev_pm_ops gpio_ir_recv_pm_ops = { | ||
175 | .suspend = gpio_ir_recv_suspend, | ||
176 | .resume = gpio_ir_recv_resume, | ||
177 | }; | ||
178 | #endif | ||
179 | |||
180 | static struct platform_driver gpio_ir_recv_driver = { | ||
181 | .probe = gpio_ir_recv_probe, | ||
182 | .remove = __devexit_p(gpio_ir_recv_remove), | ||
183 | .driver = { | ||
184 | .name = GPIO_IR_DRIVER_NAME, | ||
185 | .owner = THIS_MODULE, | ||
186 | #ifdef CONFIG_PM | ||
187 | .pm = &gpio_ir_recv_pm_ops, | ||
188 | #endif | ||
189 | }, | ||
190 | }; | ||
191 | |||
192 | static int __init gpio_ir_recv_init(void) | ||
193 | { | ||
194 | return platform_driver_register(&gpio_ir_recv_driver); | ||
195 | } | ||
196 | module_init(gpio_ir_recv_init); | ||
197 | |||
198 | static void __exit gpio_ir_recv_exit(void) | ||
199 | { | ||
200 | platform_driver_unregister(&gpio_ir_recv_driver); | ||
201 | } | ||
202 | module_exit(gpio_ir_recv_exit); | ||
203 | |||
204 | MODULE_DESCRIPTION("GPIO IR Receiver driver"); | ||
205 | MODULE_LICENSE("GPL v2"); | ||