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