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