xref: /linux/drivers/media/rc/img-ir/img-ir-raw.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
1 /*
2  * ImgTec IR Raw Decoder found in PowerDown Controller.
3  *
4  * Copyright 2010-2014 Imagination Technologies Ltd.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; either version 2 of the License, or (at your
9  * option) any later version.
10  *
11  * This ties into the input subsystem using the RC-core in raw mode. Raw IR
12  * signal edges are reported and decoded by generic software decoders.
13  */
14 
15 #include <linux/spinlock.h>
16 #include <media/rc-core.h>
17 #include "img-ir.h"
18 
19 #define ECHO_TIMEOUT_MS 150	/* ms between echos */
20 
21 /* must be called with priv->lock held */
22 static void img_ir_refresh_raw(struct img_ir_priv *priv, u32 irq_status)
23 {
24 	struct img_ir_priv_raw *raw = &priv->raw;
25 	struct rc_dev *rc_dev = priv->raw.rdev;
26 	int multiple;
27 	u32 ir_status;
28 
29 	/* find whether both rise and fall was detected */
30 	multiple = ((irq_status & IMG_IR_IRQ_EDGE) == IMG_IR_IRQ_EDGE);
31 	/*
32 	 * If so, we need to see if the level has actually changed.
33 	 * If it's just noise that we didn't have time to process,
34 	 * there's no point reporting it.
35 	 */
36 	ir_status = img_ir_read(priv, IMG_IR_STATUS) & IMG_IR_IRRXD;
37 	if (multiple && ir_status == raw->last_status)
38 		return;
39 	raw->last_status = ir_status;
40 
41 	/* report the edge to the IR raw decoders */
42 	if (ir_status) /* low */
43 		ir_raw_event_store_edge(rc_dev, IR_SPACE);
44 	else /* high */
45 		ir_raw_event_store_edge(rc_dev, IR_PULSE);
46 	ir_raw_event_handle(rc_dev);
47 }
48 
49 /* called with priv->lock held */
50 void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status)
51 {
52 	struct img_ir_priv_raw *raw = &priv->raw;
53 
54 	/* check not removing */
55 	if (!raw->rdev)
56 		return;
57 
58 	img_ir_refresh_raw(priv, irq_status);
59 
60 	/* start / push back the echo timer */
61 	mod_timer(&raw->timer, jiffies + msecs_to_jiffies(ECHO_TIMEOUT_MS));
62 }
63 
64 /*
65  * Echo timer callback function.
66  * The raw decoders expect to get a final sample even if there are no edges, in
67  * order to be assured of the final space. If there are no edges for a certain
68  * time we use this timer to emit a final sample to satisfy them.
69  */
70 static void img_ir_echo_timer(unsigned long arg)
71 {
72 	struct img_ir_priv *priv = (struct img_ir_priv *)arg;
73 
74 	spin_lock_irq(&priv->lock);
75 
76 	/* check not removing */
77 	if (priv->raw.rdev)
78 		/*
79 		 * It's safe to pass irq_status=0 since it's only used to check
80 		 * for double edges.
81 		 */
82 		img_ir_refresh_raw(priv, 0);
83 
84 	spin_unlock_irq(&priv->lock);
85 }
86 
87 void img_ir_setup_raw(struct img_ir_priv *priv)
88 {
89 	u32 irq_en;
90 
91 	if (!priv->raw.rdev)
92 		return;
93 
94 	/* clear and enable edge interrupts */
95 	spin_lock_irq(&priv->lock);
96 	irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
97 	irq_en |= IMG_IR_IRQ_EDGE;
98 	img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE);
99 	img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en);
100 	spin_unlock_irq(&priv->lock);
101 }
102 
103 int img_ir_probe_raw(struct img_ir_priv *priv)
104 {
105 	struct img_ir_priv_raw *raw = &priv->raw;
106 	struct rc_dev *rdev;
107 	int error;
108 
109 	/* Set up the echo timer */
110 	setup_timer(&raw->timer, img_ir_echo_timer, (unsigned long)priv);
111 
112 	/* Allocate raw decoder */
113 	raw->rdev = rdev = rc_allocate_device();
114 	if (!rdev) {
115 		dev_err(priv->dev, "cannot allocate raw input device\n");
116 		return -ENOMEM;
117 	}
118 	rdev->priv = priv;
119 	rdev->map_name = RC_MAP_EMPTY;
120 	rdev->input_name = "IMG Infrared Decoder Raw";
121 	rdev->driver_type = RC_DRIVER_IR_RAW;
122 
123 	/* Register raw decoder */
124 	error = rc_register_device(rdev);
125 	if (error) {
126 		dev_err(priv->dev, "failed to register raw IR input device\n");
127 		rc_free_device(rdev);
128 		raw->rdev = NULL;
129 		return error;
130 	}
131 
132 	return 0;
133 }
134 
135 void img_ir_remove_raw(struct img_ir_priv *priv)
136 {
137 	struct img_ir_priv_raw *raw = &priv->raw;
138 	struct rc_dev *rdev = raw->rdev;
139 	u32 irq_en;
140 
141 	if (!rdev)
142 		return;
143 
144 	/* switch off and disable raw (edge) interrupts */
145 	spin_lock_irq(&priv->lock);
146 	raw->rdev = NULL;
147 	irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
148 	irq_en &= ~IMG_IR_IRQ_EDGE;
149 	img_ir_write(priv, IMG_IR_IRQ_ENABLE, irq_en);
150 	img_ir_write(priv, IMG_IR_IRQ_CLEAR, IMG_IR_IRQ_EDGE);
151 	spin_unlock_irq(&priv->lock);
152 
153 	rc_unregister_device(rdev);
154 
155 	del_timer_sync(&raw->timer);
156 }
157