120835280SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0
220835280SMauro Carvalho Chehab // ir-sanyo-decoder.c - handle SANYO IR Pulse/Space protocol
320835280SMauro Carvalho Chehab //
420835280SMauro Carvalho Chehab // Copyright (C) 2011 by Mauro Carvalho Chehab
520835280SMauro Carvalho Chehab //
620835280SMauro Carvalho Chehab // This protocol uses the NEC protocol timings. However, data is formatted as:
720835280SMauro Carvalho Chehab //	13 bits Custom Code
820835280SMauro Carvalho Chehab //	13 bits NOT(Custom Code)
920835280SMauro Carvalho Chehab //	8 bits Key data
1020835280SMauro Carvalho Chehab //	8 bits NOT(Key data)
1120835280SMauro Carvalho Chehab //
1220835280SMauro Carvalho Chehab // According with LIRC, this protocol is used on Sanyo, Aiwa and Chinon
1320835280SMauro Carvalho Chehab // Information for this protocol is available at the Sanyo LC7461 datasheet.
14b32e7243SMauro Carvalho Chehab 
152e962f4eSHans Verkuil #include <linux/module.h>
16b32e7243SMauro Carvalho Chehab #include <linux/bitrev.h>
17b32e7243SMauro Carvalho Chehab #include "rc-core-priv.h"
18b32e7243SMauro Carvalho Chehab 
19b32e7243SMauro Carvalho Chehab #define SANYO_NBITS		(13+13+8+8)
20528222d8SSean Young #define SANYO_UNIT		563  /* us */
21b32e7243SMauro Carvalho Chehab #define SANYO_HEADER_PULSE	(16  * SANYO_UNIT)
22b32e7243SMauro Carvalho Chehab #define SANYO_HEADER_SPACE	(8   * SANYO_UNIT)
23b32e7243SMauro Carvalho Chehab #define SANYO_BIT_PULSE		(1   * SANYO_UNIT)
24b32e7243SMauro Carvalho Chehab #define SANYO_BIT_0_SPACE	(1   * SANYO_UNIT)
25b32e7243SMauro Carvalho Chehab #define SANYO_BIT_1_SPACE	(3   * SANYO_UNIT)
26b32e7243SMauro Carvalho Chehab #define SANYO_REPEAT_SPACE	(150 * SANYO_UNIT)
27b32e7243SMauro Carvalho Chehab #define	SANYO_TRAILER_PULSE	(1   * SANYO_UNIT)
28b32e7243SMauro Carvalho Chehab #define	SANYO_TRAILER_SPACE	(10  * SANYO_UNIT)	/* in fact, 42 */
29b32e7243SMauro Carvalho Chehab 
30b32e7243SMauro Carvalho Chehab enum sanyo_state {
31b32e7243SMauro Carvalho Chehab 	STATE_INACTIVE,
32b32e7243SMauro Carvalho Chehab 	STATE_HEADER_SPACE,
33b32e7243SMauro Carvalho Chehab 	STATE_BIT_PULSE,
34b32e7243SMauro Carvalho Chehab 	STATE_BIT_SPACE,
35b32e7243SMauro Carvalho Chehab 	STATE_TRAILER_PULSE,
36b32e7243SMauro Carvalho Chehab 	STATE_TRAILER_SPACE,
37b32e7243SMauro Carvalho Chehab };
38b32e7243SMauro Carvalho Chehab 
39b32e7243SMauro Carvalho Chehab /**
40b32e7243SMauro Carvalho Chehab  * ir_sanyo_decode() - Decode one SANYO pulse or space
41b32e7243SMauro Carvalho Chehab  * @dev:	the struct rc_dev descriptor of the device
421855e988SMauro Carvalho Chehab  * @ev:		the struct ir_raw_event descriptor of the pulse/space
43b32e7243SMauro Carvalho Chehab  *
44b32e7243SMauro Carvalho Chehab  * This function returns -EINVAL if the pulse violates the state machine
45b32e7243SMauro Carvalho Chehab  */
ir_sanyo_decode(struct rc_dev * dev,struct ir_raw_event ev)46b32e7243SMauro Carvalho Chehab static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
47b32e7243SMauro Carvalho Chehab {
48b32e7243SMauro Carvalho Chehab 	struct sanyo_dec *data = &dev->raw->sanyo;
49b32e7243SMauro Carvalho Chehab 	u32 scancode;
502bfc04d6SSean Young 	u16 address;
512bfc04d6SSean Young 	u8 command, not_command;
52b32e7243SMauro Carvalho Chehab 
53b32e7243SMauro Carvalho Chehab 	if (!is_timing_event(ev)) {
54*950170d6SSean Young 		if (ev.overflow) {
55*950170d6SSean Young 			dev_dbg(&dev->dev, "SANYO event overflow received. reset to state 0\n");
56b32e7243SMauro Carvalho Chehab 			data->state = STATE_INACTIVE;
57b32e7243SMauro Carvalho Chehab 		}
58b32e7243SMauro Carvalho Chehab 		return 0;
59b32e7243SMauro Carvalho Chehab 	}
60b32e7243SMauro Carvalho Chehab 
6150078a90SSean Young 	dev_dbg(&dev->dev, "SANYO decode started at state %d (%uus %s)\n",
62528222d8SSean Young 		data->state, ev.duration, TO_STR(ev.pulse));
63b32e7243SMauro Carvalho Chehab 
64b32e7243SMauro Carvalho Chehab 	switch (data->state) {
65b32e7243SMauro Carvalho Chehab 
66b32e7243SMauro Carvalho Chehab 	case STATE_INACTIVE:
67b32e7243SMauro Carvalho Chehab 		if (!ev.pulse)
68b32e7243SMauro Carvalho Chehab 			break;
69b32e7243SMauro Carvalho Chehab 
70b32e7243SMauro Carvalho Chehab 		if (eq_margin(ev.duration, SANYO_HEADER_PULSE, SANYO_UNIT / 2)) {
71b32e7243SMauro Carvalho Chehab 			data->count = 0;
72b32e7243SMauro Carvalho Chehab 			data->state = STATE_HEADER_SPACE;
73b32e7243SMauro Carvalho Chehab 			return 0;
74b32e7243SMauro Carvalho Chehab 		}
75b32e7243SMauro Carvalho Chehab 		break;
76b32e7243SMauro Carvalho Chehab 
77b32e7243SMauro Carvalho Chehab 
78b32e7243SMauro Carvalho Chehab 	case STATE_HEADER_SPACE:
79b32e7243SMauro Carvalho Chehab 		if (ev.pulse)
80b32e7243SMauro Carvalho Chehab 			break;
81b32e7243SMauro Carvalho Chehab 
82b32e7243SMauro Carvalho Chehab 		if (eq_margin(ev.duration, SANYO_HEADER_SPACE, SANYO_UNIT / 2)) {
83b32e7243SMauro Carvalho Chehab 			data->state = STATE_BIT_PULSE;
84b32e7243SMauro Carvalho Chehab 			return 0;
85b32e7243SMauro Carvalho Chehab 		}
86b32e7243SMauro Carvalho Chehab 
87b32e7243SMauro Carvalho Chehab 		break;
88b32e7243SMauro Carvalho Chehab 
89b32e7243SMauro Carvalho Chehab 	case STATE_BIT_PULSE:
90b32e7243SMauro Carvalho Chehab 		if (!ev.pulse)
91b32e7243SMauro Carvalho Chehab 			break;
92b32e7243SMauro Carvalho Chehab 
93b32e7243SMauro Carvalho Chehab 		if (!eq_margin(ev.duration, SANYO_BIT_PULSE, SANYO_UNIT / 2))
94b32e7243SMauro Carvalho Chehab 			break;
95b32e7243SMauro Carvalho Chehab 
96b32e7243SMauro Carvalho Chehab 		data->state = STATE_BIT_SPACE;
97b32e7243SMauro Carvalho Chehab 		return 0;
98b32e7243SMauro Carvalho Chehab 
99b32e7243SMauro Carvalho Chehab 	case STATE_BIT_SPACE:
100b32e7243SMauro Carvalho Chehab 		if (ev.pulse)
101b32e7243SMauro Carvalho Chehab 			break;
102b32e7243SMauro Carvalho Chehab 
103b32e7243SMauro Carvalho Chehab 		if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) {
104b32e7243SMauro Carvalho Chehab 			rc_repeat(dev);
10550078a90SSean Young 			dev_dbg(&dev->dev, "SANYO repeat last key\n");
106b32e7243SMauro Carvalho Chehab 			data->state = STATE_INACTIVE;
107b32e7243SMauro Carvalho Chehab 			return 0;
108b32e7243SMauro Carvalho Chehab 		}
109b32e7243SMauro Carvalho Chehab 
110b32e7243SMauro Carvalho Chehab 		data->bits <<= 1;
111b32e7243SMauro Carvalho Chehab 		if (eq_margin(ev.duration, SANYO_BIT_1_SPACE, SANYO_UNIT / 2))
112b32e7243SMauro Carvalho Chehab 			data->bits |= 1;
113b32e7243SMauro Carvalho Chehab 		else if (!eq_margin(ev.duration, SANYO_BIT_0_SPACE, SANYO_UNIT / 2))
114b32e7243SMauro Carvalho Chehab 			break;
115b32e7243SMauro Carvalho Chehab 		data->count++;
116b32e7243SMauro Carvalho Chehab 
117b32e7243SMauro Carvalho Chehab 		if (data->count == SANYO_NBITS)
118b32e7243SMauro Carvalho Chehab 			data->state = STATE_TRAILER_PULSE;
119b32e7243SMauro Carvalho Chehab 		else
120b32e7243SMauro Carvalho Chehab 			data->state = STATE_BIT_PULSE;
121b32e7243SMauro Carvalho Chehab 
122b32e7243SMauro Carvalho Chehab 		return 0;
123b32e7243SMauro Carvalho Chehab 
124b32e7243SMauro Carvalho Chehab 	case STATE_TRAILER_PULSE:
125b32e7243SMauro Carvalho Chehab 		if (!ev.pulse)
126b32e7243SMauro Carvalho Chehab 			break;
127b32e7243SMauro Carvalho Chehab 
128b32e7243SMauro Carvalho Chehab 		if (!eq_margin(ev.duration, SANYO_TRAILER_PULSE, SANYO_UNIT / 2))
129b32e7243SMauro Carvalho Chehab 			break;
130b32e7243SMauro Carvalho Chehab 
131b32e7243SMauro Carvalho Chehab 		data->state = STATE_TRAILER_SPACE;
132b32e7243SMauro Carvalho Chehab 		return 0;
133b32e7243SMauro Carvalho Chehab 
134b32e7243SMauro Carvalho Chehab 	case STATE_TRAILER_SPACE:
135b32e7243SMauro Carvalho Chehab 		if (ev.pulse)
136b32e7243SMauro Carvalho Chehab 			break;
137b32e7243SMauro Carvalho Chehab 
138b32e7243SMauro Carvalho Chehab 		if (!geq_margin(ev.duration, SANYO_TRAILER_SPACE, SANYO_UNIT / 2))
139b32e7243SMauro Carvalho Chehab 			break;
140b32e7243SMauro Carvalho Chehab 
141b32e7243SMauro Carvalho Chehab 		address     = bitrev16((data->bits >> 29) & 0x1fff) >> 3;
1425becbc58SHans Verkuil 		/* not_address = bitrev16((data->bits >> 16) & 0x1fff) >> 3; */
143b32e7243SMauro Carvalho Chehab 		command	    = bitrev8((data->bits >>  8) & 0xff);
144b32e7243SMauro Carvalho Chehab 		not_command = bitrev8((data->bits >>  0) & 0xff);
145b32e7243SMauro Carvalho Chehab 
146b32e7243SMauro Carvalho Chehab 		if ((command ^ not_command) != 0xff) {
14750078a90SSean Young 			dev_dbg(&dev->dev, "SANYO checksum error: received 0x%08llx\n",
148b32e7243SMauro Carvalho Chehab 				data->bits);
149b32e7243SMauro Carvalho Chehab 			data->state = STATE_INACTIVE;
150b32e7243SMauro Carvalho Chehab 			return 0;
151b32e7243SMauro Carvalho Chehab 		}
152b32e7243SMauro Carvalho Chehab 
153b32e7243SMauro Carvalho Chehab 		scancode = address << 8 | command;
15450078a90SSean Young 		dev_dbg(&dev->dev, "SANYO scancode: 0x%06x\n", scancode);
1556d741bfeSSean Young 		rc_keydown(dev, RC_PROTO_SANYO, scancode, 0);
156b32e7243SMauro Carvalho Chehab 		data->state = STATE_INACTIVE;
157b32e7243SMauro Carvalho Chehab 		return 0;
158b32e7243SMauro Carvalho Chehab 	}
159b32e7243SMauro Carvalho Chehab 
16050078a90SSean Young 	dev_dbg(&dev->dev, "SANYO decode failed at count %d state %d (%uus %s)\n",
161528222d8SSean Young 		data->count, data->state, ev.duration, TO_STR(ev.pulse));
162b32e7243SMauro Carvalho Chehab 	data->state = STATE_INACTIVE;
163b32e7243SMauro Carvalho Chehab 	return -EINVAL;
164b32e7243SMauro Carvalho Chehab }
165b32e7243SMauro Carvalho Chehab 
166cb981257SSean Young static const struct ir_raw_timings_pd ir_sanyo_timings = {
167cb981257SSean Young 	.header_pulse  = SANYO_HEADER_PULSE,
168cb981257SSean Young 	.header_space  = SANYO_HEADER_SPACE,
169cb981257SSean Young 	.bit_pulse     = SANYO_BIT_PULSE,
170cb981257SSean Young 	.bit_space[0]  = SANYO_BIT_0_SPACE,
171cb981257SSean Young 	.bit_space[1]  = SANYO_BIT_1_SPACE,
172cb981257SSean Young 	.trailer_pulse = SANYO_TRAILER_PULSE,
173cb981257SSean Young 	.trailer_space = SANYO_TRAILER_SPACE,
174cb981257SSean Young 	.msb_first     = 1,
175cb981257SSean Young };
176cb981257SSean Young 
177cb981257SSean Young /**
178cb981257SSean Young  * ir_sanyo_encode() - Encode a scancode as a stream of raw events
179cb981257SSean Young  *
180cb981257SSean Young  * @protocol:	protocol to encode
181cb981257SSean Young  * @scancode:	scancode to encode
182cb981257SSean Young  * @events:	array of raw ir events to write into
183cb981257SSean Young  * @max:	maximum size of @events
184cb981257SSean Young  *
185cb981257SSean Young  * Returns:	The number of events written.
186cb981257SSean Young  *		-ENOBUFS if there isn't enough space in the array to fit the
187cb981257SSean Young  *		encoding. In this case all @max events will have been written.
188cb981257SSean Young  */
ir_sanyo_encode(enum rc_proto protocol,u32 scancode,struct ir_raw_event * events,unsigned int max)1896d741bfeSSean Young static int ir_sanyo_encode(enum rc_proto protocol, u32 scancode,
190cb981257SSean Young 			   struct ir_raw_event *events, unsigned int max)
191cb981257SSean Young {
192cb981257SSean Young 	struct ir_raw_event *e = events;
193cb981257SSean Young 	int ret;
194cb981257SSean Young 	u64 raw;
195cb981257SSean Young 
196cb981257SSean Young 	raw = ((u64)(bitrev16(scancode >> 8) & 0xfff8) << (8 + 8 + 13 - 3)) |
197cb981257SSean Young 	      ((u64)(bitrev16(~scancode >> 8) & 0xfff8) << (8 + 8 +  0 - 3)) |
198cb981257SSean Young 	      ((bitrev8(scancode) & 0xff) << 8) |
199cb981257SSean Young 	      (bitrev8(~scancode) & 0xff);
200cb981257SSean Young 
201cb981257SSean Young 	ret = ir_raw_gen_pd(&e, max, &ir_sanyo_timings, SANYO_NBITS, raw);
202cb981257SSean Young 	if (ret < 0)
203cb981257SSean Young 		return ret;
204cb981257SSean Young 
205cb981257SSean Young 	return e - events;
206cb981257SSean Young }
207cb981257SSean Young 
208b32e7243SMauro Carvalho Chehab static struct ir_raw_handler sanyo_handler = {
2096d741bfeSSean Young 	.protocols	= RC_PROTO_BIT_SANYO,
210b32e7243SMauro Carvalho Chehab 	.decode		= ir_sanyo_decode,
211cb981257SSean Young 	.encode		= ir_sanyo_encode,
212cdfaa01cSSean Young 	.carrier	= 38000,
213a86d6df8SSean Young 	.min_timeout	= SANYO_TRAILER_SPACE,
214b32e7243SMauro Carvalho Chehab };
215b32e7243SMauro Carvalho Chehab 
ir_sanyo_decode_init(void)216b32e7243SMauro Carvalho Chehab static int __init ir_sanyo_decode_init(void)
217b32e7243SMauro Carvalho Chehab {
218b32e7243SMauro Carvalho Chehab 	ir_raw_handler_register(&sanyo_handler);
219b32e7243SMauro Carvalho Chehab 
220b32e7243SMauro Carvalho Chehab 	printk(KERN_INFO "IR SANYO protocol handler initialized\n");
221b32e7243SMauro Carvalho Chehab 	return 0;
222b32e7243SMauro Carvalho Chehab }
223b32e7243SMauro Carvalho Chehab 
ir_sanyo_decode_exit(void)224b32e7243SMauro Carvalho Chehab static void __exit ir_sanyo_decode_exit(void)
225b32e7243SMauro Carvalho Chehab {
226b32e7243SMauro Carvalho Chehab 	ir_raw_handler_unregister(&sanyo_handler);
227b32e7243SMauro Carvalho Chehab }
228b32e7243SMauro Carvalho Chehab 
229b32e7243SMauro Carvalho Chehab module_init(ir_sanyo_decode_init);
230b32e7243SMauro Carvalho Chehab module_exit(ir_sanyo_decode_exit);
231b32e7243SMauro Carvalho Chehab 
23220835280SMauro Carvalho Chehab MODULE_LICENSE("GPL v2");
23337e59f87SMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab");
234b32e7243SMauro Carvalho Chehab MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
235b32e7243SMauro Carvalho Chehab MODULE_DESCRIPTION("SANYO IR protocol decoder");
236