1// SPDX-License-Identifier: GPL-2.0-only
2/* ir-sharp-decoder.c - handle Sharp IR Pulse/Space protocol
3 *
4 * Copyright (C) 2013-2014 Imagination Technologies Ltd.
5 *
6 * Based on NEC decoder:
7 * Copyright (C) 2010 by Mauro Carvalho Chehab
8 */
9
10#include <linux/bitrev.h>
11#include <linux/module.h>
12#include "rc-core-priv.h"
13
14#define SHARP_NBITS		15
15#define SHARP_UNIT		40  /* us */
16#define SHARP_BIT_PULSE		(8    * SHARP_UNIT) /* 320us */
17#define SHARP_BIT_0_PERIOD	(25   * SHARP_UNIT) /* 1ms (680us space) */
18#define SHARP_BIT_1_PERIOD	(50   * SHARP_UNIT) /* 2ms (1680us space) */
19#define SHARP_BIT_0_SPACE	(17   * SHARP_UNIT) /* 680us space */
20#define SHARP_BIT_1_SPACE	(42   * SHARP_UNIT) /* 1680us space */
21#define SHARP_ECHO_SPACE	(1000 * SHARP_UNIT) /* 40 ms */
22#define SHARP_TRAILER_SPACE	(125  * SHARP_UNIT) /* 5 ms (even longer) */
23
24enum sharp_state {
25	STATE_INACTIVE,
26	STATE_BIT_PULSE,
27	STATE_BIT_SPACE,
28	STATE_TRAILER_PULSE,
29	STATE_ECHO_SPACE,
30	STATE_TRAILER_SPACE,
31};
32
33/**
34 * ir_sharp_decode() - Decode one Sharp pulse or space
35 * @dev:	the struct rc_dev descriptor of the device
36 * @ev:		the struct ir_raw_event descriptor of the pulse/space
37 *
38 * This function returns -EINVAL if the pulse violates the state machine
39 */
40static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
41{
42	struct sharp_dec *data = &dev->raw->sharp;
43	u32 msg, echo, address, command, scancode;
44
45	if (!is_timing_event(ev)) {
46		if (ev.overflow)
47			data->state = STATE_INACTIVE;
48		return 0;
49	}
50
51	dev_dbg(&dev->dev, "Sharp decode started at state %d (%uus %s)\n",
52		data->state, ev.duration, TO_STR(ev.pulse));
53
54	switch (data->state) {
55
56	case STATE_INACTIVE:
57		if (!ev.pulse)
58			break;
59
60		if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
61			       SHARP_BIT_PULSE / 2))
62			break;
63
64		data->count = 0;
65		data->pulse_len = ev.duration;
66		data->state = STATE_BIT_SPACE;
67		return 0;
68
69	case STATE_BIT_PULSE:
70		if (!ev.pulse)
71			break;
72
73		if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
74			       SHARP_BIT_PULSE / 2))
75			break;
76
77		data->pulse_len = ev.duration;
78		data->state = STATE_BIT_SPACE;
79		return 0;
80
81	case STATE_BIT_SPACE:
82		if (ev.pulse)
83			break;
84
85		data->bits <<= 1;
86		if (eq_margin(data->pulse_len + ev.duration, SHARP_BIT_1_PERIOD,
87			      SHARP_BIT_PULSE * 2))
88			data->bits |= 1;
89		else if (!eq_margin(data->pulse_len + ev.duration,
90				    SHARP_BIT_0_PERIOD, SHARP_BIT_PULSE * 2))
91			break;
92		data->count++;
93
94		if (data->count == SHARP_NBITS ||
95		    data->count == SHARP_NBITS * 2)
96			data->state = STATE_TRAILER_PULSE;
97		else
98			data->state = STATE_BIT_PULSE;
99
100		return 0;
101
102	case STATE_TRAILER_PULSE:
103		if (!ev.pulse)
104			break;
105
106		if (!eq_margin(ev.duration, SHARP_BIT_PULSE,
107			       SHARP_BIT_PULSE / 2))
108			break;
109
110		if (data->count == SHARP_NBITS) {
111			/* exp,chk bits should be 1,0 */
112			if ((data->bits & 0x3) != 0x2 &&
113			/* DENON variant, both chk bits 0 */
114			    (data->bits & 0x3) != 0x0)
115				break;
116			data->state = STATE_ECHO_SPACE;
117		} else {
118			data->state = STATE_TRAILER_SPACE;
119		}
120		return 0;
121
122	case STATE_ECHO_SPACE:
123		if (ev.pulse)
124			break;
125
126		if (!eq_margin(ev.duration, SHARP_ECHO_SPACE,
127			       SHARP_ECHO_SPACE / 4))
128			break;
129
130		data->state = STATE_BIT_PULSE;
131
132		return 0;
133
134	case STATE_TRAILER_SPACE:
135		if (ev.pulse)
136			break;
137
138		if (!geq_margin(ev.duration, SHARP_TRAILER_SPACE,
139				SHARP_BIT_PULSE / 2))
140			break;
141
142		/* Validate - command, ext, chk should be inverted in 2nd */
143		msg = (data->bits >> 15) & 0x7fff;
144		echo = data->bits & 0x7fff;
145		if ((msg ^ echo) != 0x3ff) {
146			dev_dbg(&dev->dev,
147				"Sharp checksum error: received 0x%04x, 0x%04x\n",
148				msg, echo);
149			break;
150		}
151
152		address = bitrev8((msg >> 7) & 0xf8);
153		command = bitrev8((msg >> 2) & 0xff);
154
155		scancode = address << 8 | command;
156		dev_dbg(&dev->dev, "Sharp scancode 0x%04x\n", scancode);
157
158		rc_keydown(dev, RC_PROTO_SHARP, scancode, 0);
159		data->state = STATE_INACTIVE;
160		return 0;
161	}
162
163	dev_dbg(&dev->dev, "Sharp decode failed at count %d state %d (%uus %s)\n",
164		data->count, data->state, ev.duration, TO_STR(ev.pulse));
165	data->state = STATE_INACTIVE;
166	return -EINVAL;
167}
168
169static const struct ir_raw_timings_pd ir_sharp_timings = {
170	.header_pulse  = 0,
171	.header_space  = 0,
172	.bit_pulse     = SHARP_BIT_PULSE,
173	.bit_space[0]  = SHARP_BIT_0_SPACE,
174	.bit_space[1]  = SHARP_BIT_1_SPACE,
175	.trailer_pulse = SHARP_BIT_PULSE,
176	.trailer_space = SHARP_ECHO_SPACE,
177	.msb_first     = 1,
178};
179
180/**
181 * ir_sharp_encode() - Encode a scancode as a stream of raw events
182 *
183 * @protocol:	protocol to encode
184 * @scancode:	scancode to encode
185 * @events:	array of raw ir events to write into
186 * @max:	maximum size of @events
187 *
188 * Returns:	The number of events written.
189 *		-ENOBUFS if there isn't enough space in the array to fit the
190 *		encoding. In this case all @max events will have been written.
191 */
192static int ir_sharp_encode(enum rc_proto protocol, u32 scancode,
193			   struct ir_raw_event *events, unsigned int max)
194{
195	struct ir_raw_event *e = events;
196	int ret;
197	u32 raw;
198
199	raw = (((bitrev8(scancode >> 8) >> 3) << 8) & 0x1f00) |
200		bitrev8(scancode);
201	ret = ir_raw_gen_pd(&e, max, &ir_sharp_timings, SHARP_NBITS,
202			    (raw << 2) | 2);
203	if (ret < 0)
204		return ret;
205
206	max -= ret;
207
208	raw = (((bitrev8(scancode >> 8) >> 3) << 8) & 0x1f00) |
209		bitrev8(~scancode);
210	ret = ir_raw_gen_pd(&e, max, &ir_sharp_timings, SHARP_NBITS,
211			    (raw << 2) | 1);
212	if (ret < 0)
213		return ret;
214
215	return e - events;
216}
217
218static struct ir_raw_handler sharp_handler = {
219	.protocols	= RC_PROTO_BIT_SHARP,
220	.decode		= ir_sharp_decode,
221	.encode		= ir_sharp_encode,
222	.carrier	= 38000,
223	.min_timeout	= SHARP_ECHO_SPACE + SHARP_ECHO_SPACE / 4,
224};
225
226static int __init ir_sharp_decode_init(void)
227{
228	ir_raw_handler_register(&sharp_handler);
229
230	pr_info("IR Sharp protocol handler initialized\n");
231	return 0;
232}
233
234static void __exit ir_sharp_decode_exit(void)
235{
236	ir_raw_handler_unregister(&sharp_handler);
237}
238
239module_init(ir_sharp_decode_init);
240module_exit(ir_sharp_decode_exit);
241
242MODULE_LICENSE("GPL");
243MODULE_AUTHOR("James Hogan <jhogan@kernel.org>");
244MODULE_DESCRIPTION("Sharp IR protocol decoder");
245