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 */
17 static 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 */
45 void 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  */
65 static 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 
82 void 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 
98 int 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 
130 void 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 }
152