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