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 */
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}
157