blob: 33f37ed87ad2909e5b53e1a4083c99e46d70d68d [file] [log] [blame]
Kyle Swenson8d8f6542021-03-15 11:02:55 -06001/*
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 */
22static 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 */
50void 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 */
70static 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
87void 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
103int 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
135void 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}