aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2014-02-28 18:28:53 -0500
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-03-11 14:13:00 -0400
commit3fed7dbe8b94ab45298d9e63b90c1c57a01b6d5b (patch)
treeca6f385a39c8d00472b878209232e4f8dfe80355
parent160a8f8aec4da4b68842784be3e7296e8c9860dc (diff)
[media] rc: img-ir: add raw driver
Add raw IR remote control input driver for the ImgTec Infrared decoder block's raw edge interrupts. Generic software protocol decoders are used to allow multiple protocols to be supported at a time, including those not supported by the hardware decoder. Signed-off-by: James Hogan <james.hogan@imgtec.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
-rw-r--r--drivers/media/rc/img-ir/img-ir-raw.c151
-rw-r--r--drivers/media/rc/img-ir/img-ir-raw.h60
2 files changed, 211 insertions, 0 deletions
diff --git a/drivers/media/rc/img-ir/img-ir-raw.c b/drivers/media/rc/img-ir/img-ir-raw.c
new file mode 100644
index 000000000000..cfb01d9e571a
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir-raw.c
@@ -0,0 +1,151 @@
1/*
2 * ImgTec IR Raw Decoder found in PowerDown Controller.
3 *
4 * Copyright 2010-2014 Imagination Technologies Ltd.
5 *
6 * This ties into the input subsystem using the RC-core in raw mode. Raw IR
7 * signal edges are reported and decoded by generic software decoders.
8 */
9
10#include <linux/spinlock.h>
11#include <media/rc-core.h>
12#include "img-ir.h"
13
14#define ECHO_TIMEOUT_MS 150 /* ms between echos */
15
16/* must be called with priv->lock held */
17static void img_ir_refresh_raw(struct img_ir_priv *priv, u32 irq_status)
18{
19 struct img_ir_priv_raw *raw = &priv->raw;
20 struct rc_dev *rc_dev = priv->raw.rdev;
21 int multiple;
22 u32 ir_status;
23
24 /* find whether both rise and fall was detected */
25 multiple = ((irq_status & IMG_IR_IRQ_EDGE) == IMG_IR_IRQ_EDGE);
26 /*
27 * If so, we need to see if the level has actually changed.
28 * If it's just noise that we didn't have time to process,
29 * there's no point reporting it.
30 */
31 ir_status = img_ir_read(priv, IMG_IR_STATUS) & IMG_IR_IRRXD;
32 if (multiple && ir_status == raw->last_status)
33 return;
34 raw->last_status = ir_status;
35
36 /* report the edge to the IR raw decoders */
37 if (ir_status) /* low */
38 ir_raw_event_store_edge(rc_dev, IR_SPACE);
39 else /* high */
40 ir_raw_event_store_edge(rc_dev, IR_PULSE);
41 ir_raw_event_handle(rc_dev);
42}
43
44/* called with priv->lock held */
45void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status)
46{
47 struct img_ir_priv_raw *raw = &priv->raw;
48
49 /* check not removing */
50 if (!raw->rdev)
51 return;
52
53 img_ir_refresh_raw(priv, irq_status);
54
55 /* start / push back the echo timer */
56 mod_timer(&raw->timer, jiffies + msecs_to_jiffies(ECHO_TIMEOUT_MS));
57}
58
59/*
60 * Echo timer callback function.
61 * The raw decoders expect to get a final sample even if there are no edges, in
62 * order to be assured of the final space. If there are no edges for a certain
63 * time we use this timer to emit a final sample to satisfy them.
64 */
65static void img_ir_echo_timer(unsigned long arg)
66{
67 struct img_ir_priv *priv = (struct img_ir_priv *)arg;
68
69 spin_lock_irq(&priv->lock);
70
71 /* check not removing */
72 if (priv->raw.rdev)
73 /*
74 * It's safe to pass irq_status=0 since it's only used to check
75 * for double edges.
76 */
77 img_ir_refresh_raw(priv, 0);
78
79 spin_unlock_irq(&priv->lock);
80}
81
82void img_ir_setup_raw(struct img_ir_priv *priv)
83{
84 u32 irq_en;
85
86 if (!priv->raw.rdev)
87 return;
88
89 /* clear and enable edge interrupts */
90 spin_lock_irq(&priv->lock);
91 irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
92 irq_en |= IMG_IR_IRQ_EDGE;
93 img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE);
94 img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en);
95 spin_unlock_irq(&priv->lock);
96}
97
98int img_ir_probe_raw(struct img_ir_priv *priv)
99{
100 struct img_ir_priv_raw *raw = &priv->raw;
101 struct rc_dev *rdev;
102 int error;
103
104 /* Set up the echo timer */
105 setup_timer(&raw->timer, img_ir_echo_timer, (unsigned long)priv);
106
107 /* Allocate raw decoder */
108 raw->rdev = rdev = rc_allocate_device();
109 if (!rdev) {
110 dev_err(priv->dev, "cannot allocate raw input device\n");
111 return -ENOMEM;
112 }
113 rdev->priv = priv;
114 rdev->map_name = RC_MAP_EMPTY;
115 rdev->input_name = "IMG Infrared Decoder Raw";
116 rdev->driver_type = RC_DRIVER_IR_RAW;
117
118 /* Register raw decoder */
119 error = rc_register_device(rdev);
120 if (error) {
121 dev_err(priv->dev, "failed to register raw IR input device\n");
122 rc_free_device(rdev);
123 raw->rdev = NULL;
124 return error;
125 }
126
127 return 0;
128}
129
130void img_ir_remove_raw(struct img_ir_priv *priv)
131{
132 struct img_ir_priv_raw *raw = &priv->raw;
133 struct rc_dev *rdev = raw->rdev;
134 u32 irq_en;
135
136 if (!rdev)
137 return;
138
139 /* switch off and disable raw (edge) interrupts */
140 spin_lock_irq(&priv->lock);
141 raw->rdev = NULL;
142 irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
143 irq_en &= ~IMG_IR_IRQ_EDGE;
144 img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en);
145 img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE);
146 spin_unlock_irq(&priv->lock);
147
148 rc_unregister_device(rdev);
149
150 del_timer_sync(&raw->timer);
151}
diff --git a/drivers/media/rc/img-ir/img-ir-raw.h b/drivers/media/rc/img-ir/img-ir-raw.h
new file mode 100644
index 000000000000..9802ffd51b9a
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir-raw.h
@@ -0,0 +1,60 @@
1/*
2 * ImgTec IR Raw Decoder found in PowerDown Controller.
3 *
4 * Copyright 2010-2014 Imagination Technologies Ltd.
5 */
6
7#ifndef _IMG_IR_RAW_H_
8#define _IMG_IR_RAW_H_
9
10struct img_ir_priv;
11
12#ifdef CONFIG_IR_IMG_RAW
13
14/**
15 * struct img_ir_priv_raw - Private driver data for raw decoder.
16 * @rdev: Raw remote control device
17 * @timer: Timer to echo samples to keep soft decoders happy.
18 * @last_status: Last raw status bits.
19 */
20struct img_ir_priv_raw {
21 struct rc_dev *rdev;
22 struct timer_list timer;
23 u32 last_status;
24};
25
26static inline bool img_ir_raw_enabled(struct img_ir_priv_raw *raw)
27{
28 return raw->rdev;
29};
30
31void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status);
32void img_ir_setup_raw(struct img_ir_priv *priv);
33int img_ir_probe_raw(struct img_ir_priv *priv);
34void img_ir_remove_raw(struct img_ir_priv *priv);
35
36#else
37
38struct img_ir_priv_raw {
39};
40static inline bool img_ir_raw_enabled(struct img_ir_priv_raw *raw)
41{
42 return false;
43};
44static inline void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status)
45{
46}
47static inline void img_ir_setup_raw(struct img_ir_priv *priv)
48{
49}
50static inline int img_ir_probe_raw(struct img_ir_priv *priv)
51{
52 return -ENODEV;
53}
54static inline void img_ir_remove_raw(struct img_ir_priv *priv)
55{
56}
57
58#endif /* CONFIG_IR_IMG_RAW */
59
60#endif /* _IMG_IR_RAW_H_ */