1 /*
2  * ImgTec IR Decoder setup for Sony (SIRC) protocol.
3  *
4  * Copyright 2012-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 
14 /* Convert Sony data to a scancode */
15 static int img_ir_sony_scancode(int len, u64 raw, int *scancode, u64 protocols)
16 {
17 	unsigned int dev, subdev, func;
18 
19 	switch (len) {
20 	case 12:
21 		if (!(protocols & RC_BIT_SONY12))
22 			return -EINVAL;
23 		func   = raw & 0x7f;	/* first 7 bits */
24 		raw    >>= 7;
25 		dev    = raw & 0x1f;	/* next 5 bits */
26 		subdev = 0;
27 		break;
28 	case 15:
29 		if (!(protocols & RC_BIT_SONY15))
30 			return -EINVAL;
31 		func   = raw & 0x7f;	/* first 7 bits */
32 		raw    >>= 7;
33 		dev    = raw & 0xff;	/* next 8 bits */
34 		subdev = 0;
35 		break;
36 	case 20:
37 		if (!(protocols & RC_BIT_SONY20))
38 			return -EINVAL;
39 		func   = raw & 0x7f;	/* first 7 bits */
40 		raw    >>= 7;
41 		dev    = raw & 0x1f;	/* next 5 bits */
42 		raw    >>= 5;
43 		subdev = raw & 0xff;	/* next 8 bits */
44 		break;
45 	default:
46 		return -EINVAL;
47 	}
48 	*scancode = dev << 16 | subdev << 8 | func;
49 	return IMG_IR_SCANCODE;
50 }
51 
52 /* Convert NEC scancode to NEC data filter */
53 static int img_ir_sony_filter(const struct rc_scancode_filter *in,
54 			      struct img_ir_filter *out, u64 protocols)
55 {
56 	unsigned int dev, subdev, func;
57 	unsigned int dev_m, subdev_m, func_m;
58 	unsigned int len = 0;
59 
60 	dev      = (in->data >> 16) & 0xff;
61 	dev_m    = (in->mask >> 16) & 0xff;
62 	subdev   = (in->data >> 8)  & 0xff;
63 	subdev_m = (in->mask >> 8)  & 0xff;
64 	func     = (in->data >> 0)  & 0x7f;
65 	func_m   = (in->mask >> 0)  & 0x7f;
66 
67 	if (subdev & subdev_m) {
68 		/* can't encode subdev and higher device bits */
69 		if (dev & dev_m & 0xe0)
70 			return -EINVAL;
71 		/* subdevice (extended) bits only in 20 bit encoding */
72 		if (!(protocols & RC_BIT_SONY20))
73 			return -EINVAL;
74 		len = 20;
75 		dev_m &= 0x1f;
76 	} else if (dev & dev_m & 0xe0) {
77 		/* upper device bits only in 15 bit encoding */
78 		if (!(protocols & RC_BIT_SONY15))
79 			return -EINVAL;
80 		len = 15;
81 		subdev_m = 0;
82 	} else {
83 		/*
84 		 * The hardware mask cannot distinguish high device bits and low
85 		 * extended bits, so logically AND those bits of the masks
86 		 * together.
87 		 */
88 		subdev_m &= (dev_m >> 5) | 0xf8;
89 		dev_m &= 0x1f;
90 	}
91 
92 	/* ensure there aren't any bits straying between fields */
93 	dev &= dev_m;
94 	subdev &= subdev_m;
95 
96 	/* write the hardware filter */
97 	out->data = func          |
98 		    dev      << 7 |
99 		    subdev   << 15;
100 	out->mask = func_m        |
101 		    dev_m    << 7 |
102 		    subdev_m << 15;
103 
104 	if (len) {
105 		out->minlen = len;
106 		out->maxlen = len;
107 	}
108 	return 0;
109 }
110 
111 /*
112  * Sony SIRC decoder
113  * See also http://www.sbprojects.com/knowledge/ir/sirc.php
114  *          http://picprojects.org.uk/projects/sirc/sonysirc.pdf
115  */
116 struct img_ir_decoder img_ir_sony = {
117 	.type = RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20,
118 	.control = {
119 		.decoden = 1,
120 		.code_type = IMG_IR_CODETYPE_PULSELEN,
121 	},
122 	/* main timings */
123 	.unit = 600000, /* 600 us */
124 	.timings = {
125 		/* leader symbol */
126 		.ldr = {
127 			.pulse = { 4	/* 2.4 ms */ },
128 			.space = { 1	/* 600 us */ },
129 		},
130 		/* 0 symbol */
131 		.s00 = {
132 			.pulse = { 1	/* 600 us */ },
133 			.space = { 1	/* 600 us */ },
134 		},
135 		/* 1 symbol */
136 		.s01 = {
137 			.pulse = { 2	/* 1.2 ms */ },
138 			.space = { 1	/* 600 us */ },
139 		},
140 		/* free time */
141 		.ft = {
142 			.minlen = 12,
143 			.maxlen = 20,
144 			.ft_min = 10,	/* 6 ms */
145 		},
146 	},
147 	/* scancode logic */
148 	.scancode = img_ir_sony_scancode,
149 	.filter = img_ir_sony_filter,
150 };
151