1/*
2 * ImgTec IR Decoder setup for NEC protocol.
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
12#include "img-ir-hw.h"
13#include <linux/bitrev.h>
14
15/* Convert NEC data to a scancode */
16static int img_ir_nec_scancode(int len, u64 raw, u64 enabled_protocols,
17			       struct img_ir_scancode_req *request)
18{
19	unsigned int addr, addr_inv, data, data_inv;
20	/* a repeat code has no data */
21	if (!len)
22		return IMG_IR_REPEATCODE;
23	if (len != 32)
24		return -EINVAL;
25	/* raw encoding: ddDDaaAA */
26	addr     = (raw >>  0) & 0xff;
27	addr_inv = (raw >>  8) & 0xff;
28	data     = (raw >> 16) & 0xff;
29	data_inv = (raw >> 24) & 0xff;
30	if ((data_inv ^ data) != 0xff) {
31		/* 32-bit NEC (used by Apple and TiVo remotes) */
32		/* scan encoding: as transmitted, MSBit = first received bit */
33		request->scancode = bitrev8(addr)     << 24 |
34				bitrev8(addr_inv) << 16 |
35				bitrev8(data)     <<  8 |
36				bitrev8(data_inv);
37	} else if ((addr_inv ^ addr) != 0xff) {
38		/* Extended NEC */
39		/* scan encoding: AAaaDD */
40		request->scancode = addr     << 16 |
41				addr_inv <<  8 |
42				data;
43	} else {
44		/* Normal NEC */
45		/* scan encoding: AADD */
46		request->scancode = addr << 8 |
47				data;
48	}
49	request->protocol = RC_TYPE_NEC;
50	return IMG_IR_SCANCODE;
51}
52
53/* Convert NEC scancode to NEC data filter */
54static int img_ir_nec_filter(const struct rc_scancode_filter *in,
55			     struct img_ir_filter *out, u64 protocols)
56{
57	unsigned int addr, addr_inv, data, data_inv;
58	unsigned int addr_m, addr_inv_m, data_m, data_inv_m;
59
60	data       = in->data & 0xff;
61	data_m     = in->mask & 0xff;
62
63	if ((in->data | in->mask) & 0xff000000) {
64		/* 32-bit NEC (used by Apple and TiVo remotes) */
65		/* scan encoding: as transmitted, MSBit = first received bit */
66		addr       = bitrev8(in->data >> 24);
67		addr_m     = bitrev8(in->mask >> 24);
68		addr_inv   = bitrev8(in->data >> 16);
69		addr_inv_m = bitrev8(in->mask >> 16);
70		data       = bitrev8(in->data >>  8);
71		data_m     = bitrev8(in->mask >>  8);
72		data_inv   = bitrev8(in->data >>  0);
73		data_inv_m = bitrev8(in->mask >>  0);
74	} else if ((in->data | in->mask) & 0x00ff0000) {
75		/* Extended NEC */
76		/* scan encoding AAaaDD */
77		addr       = (in->data >> 16) & 0xff;
78		addr_m     = (in->mask >> 16) & 0xff;
79		addr_inv   = (in->data >>  8) & 0xff;
80		addr_inv_m = (in->mask >>  8) & 0xff;
81		data_inv   = data ^ 0xff;
82		data_inv_m = data_m;
83	} else {
84		/* Normal NEC */
85		/* scan encoding: AADD */
86		addr       = (in->data >>  8) & 0xff;
87		addr_m     = (in->mask >>  8) & 0xff;
88		addr_inv   = addr ^ 0xff;
89		addr_inv_m = addr_m;
90		data_inv   = data ^ 0xff;
91		data_inv_m = data_m;
92	}
93
94	/* raw encoding: ddDDaaAA */
95	out->data = data_inv << 24 |
96		    data     << 16 |
97		    addr_inv <<  8 |
98		    addr;
99	out->mask = data_inv_m << 24 |
100		    data_m     << 16 |
101		    addr_inv_m <<  8 |
102		    addr_m;
103	return 0;
104}
105
106/*
107 * NEC decoder
108 * See also http://www.sbprojects.com/knowledge/ir/nec.php
109 *        http://wiki.altium.com/display/ADOH/NEC+Infrared+Transmission+Protocol
110 */
111struct img_ir_decoder img_ir_nec = {
112	.type = RC_BIT_NEC,
113	.control = {
114		.decoden = 1,
115		.code_type = IMG_IR_CODETYPE_PULSEDIST,
116	},
117	/* main timings */
118	.unit = 562500, /* 562.5 us */
119	.timings = {
120		/* leader symbol */
121		.ldr = {
122			.pulse = { 16	/* 9ms */ },
123			.space = { 8	/* 4.5ms */ },
124		},
125		/* 0 symbol */
126		.s00 = {
127			.pulse = { 1	/* 562.5 us */ },
128			.space = { 1	/* 562.5 us */ },
129		},
130		/* 1 symbol */
131		.s01 = {
132			.pulse = { 1	/* 562.5 us */ },
133			.space = { 3	/* 1687.5 us */ },
134		},
135		/* free time */
136		.ft = {
137			.minlen = 32,
138			.maxlen = 32,
139			.ft_min = 10,	/* 5.625 ms */
140		},
141	},
142	/* repeat codes */
143	.repeat = 108,			/* 108 ms */
144	.rtimings = {
145		/* leader symbol */
146		.ldr = {
147			.space = { 4	/* 2.25 ms */ },
148		},
149		/* free time */
150		.ft = {
151			.minlen = 0,	/* repeat code has no data */
152			.maxlen = 0,
153		},
154	},
155	/* scancode logic */
156	.scancode = img_ir_nec_scancode,
157	.filter = img_ir_nec_filter,
158};
159