1e72b21abSJames Hogan /*
2e72b21abSJames Hogan  * ImgTec IR Decoder setup for Sony (SIRC) protocol.
3e72b21abSJames Hogan  *
4e72b21abSJames Hogan  * Copyright 2012-2014 Imagination Technologies Ltd.
52ac6f630SJames Hogan  *
62ac6f630SJames Hogan  * This program is free software; you can redistribute it and/or modify
72ac6f630SJames Hogan  * it under the terms of the GNU General Public License as published by the
82ac6f630SJames Hogan  * Free Software Foundation; either version 2 of the License, or (at your
92ac6f630SJames Hogan  * option) any later version.
10e72b21abSJames Hogan  */
11e72b21abSJames Hogan 
12e72b21abSJames Hogan #include "img-ir-hw.h"
13e72b21abSJames Hogan 
14e72b21abSJames Hogan /* Convert Sony data to a scancode */
15ab93ce06SSifan Naeem static int img_ir_sony_scancode(int len, u64 raw, u64 enabled_protocols,
16ab93ce06SSifan Naeem 				struct img_ir_scancode_req *request)
17e72b21abSJames Hogan {
18e72b21abSJames Hogan 	unsigned int dev, subdev, func;
19e72b21abSJames Hogan 
20e72b21abSJames Hogan 	switch (len) {
21e72b21abSJames Hogan 	case 12:
226d741bfeSSean Young 		if (!(enabled_protocols & RC_PROTO_BIT_SONY12))
23e72b21abSJames Hogan 			return -EINVAL;
24e72b21abSJames Hogan 		func   = raw & 0x7f;	/* first 7 bits */
25e72b21abSJames Hogan 		raw    >>= 7;
26e72b21abSJames Hogan 		dev    = raw & 0x1f;	/* next 5 bits */
27e72b21abSJames Hogan 		subdev = 0;
286d741bfeSSean Young 		request->protocol = RC_PROTO_SONY12;
29e72b21abSJames Hogan 		break;
30e72b21abSJames Hogan 	case 15:
316d741bfeSSean Young 		if (!(enabled_protocols & RC_PROTO_BIT_SONY15))
32e72b21abSJames Hogan 			return -EINVAL;
33e72b21abSJames Hogan 		func   = raw & 0x7f;	/* first 7 bits */
34e72b21abSJames Hogan 		raw    >>= 7;
35e72b21abSJames Hogan 		dev    = raw & 0xff;	/* next 8 bits */
36e72b21abSJames Hogan 		subdev = 0;
376d741bfeSSean Young 		request->protocol = RC_PROTO_SONY15;
38e72b21abSJames Hogan 		break;
39e72b21abSJames Hogan 	case 20:
406d741bfeSSean Young 		if (!(enabled_protocols & RC_PROTO_BIT_SONY20))
41e72b21abSJames Hogan 			return -EINVAL;
42e72b21abSJames Hogan 		func   = raw & 0x7f;	/* first 7 bits */
43e72b21abSJames Hogan 		raw    >>= 7;
44e72b21abSJames Hogan 		dev    = raw & 0x1f;	/* next 5 bits */
45e72b21abSJames Hogan 		raw    >>= 5;
46e72b21abSJames Hogan 		subdev = raw & 0xff;	/* next 8 bits */
476d741bfeSSean Young 		request->protocol = RC_PROTO_SONY20;
48e72b21abSJames Hogan 		break;
49e72b21abSJames Hogan 	default:
50e72b21abSJames Hogan 		return -EINVAL;
51e72b21abSJames Hogan 	}
52ab93ce06SSifan Naeem 	request->scancode = dev << 16 | subdev << 8 | func;
53e72b21abSJames Hogan 	return IMG_IR_SCANCODE;
54e72b21abSJames Hogan }
55e72b21abSJames Hogan 
56e72b21abSJames Hogan /* Convert NEC scancode to NEC data filter */
57e72b21abSJames Hogan static int img_ir_sony_filter(const struct rc_scancode_filter *in,
58e72b21abSJames Hogan 			      struct img_ir_filter *out, u64 protocols)
59e72b21abSJames Hogan {
60e72b21abSJames Hogan 	unsigned int dev, subdev, func;
61e72b21abSJames Hogan 	unsigned int dev_m, subdev_m, func_m;
62e72b21abSJames Hogan 	unsigned int len = 0;
63e72b21abSJames Hogan 
64e72b21abSJames Hogan 	dev      = (in->data >> 16) & 0xff;
65e72b21abSJames Hogan 	dev_m    = (in->mask >> 16) & 0xff;
66e72b21abSJames Hogan 	subdev   = (in->data >> 8)  & 0xff;
67e72b21abSJames Hogan 	subdev_m = (in->mask >> 8)  & 0xff;
68e72b21abSJames Hogan 	func     = (in->data >> 0)  & 0x7f;
69e72b21abSJames Hogan 	func_m   = (in->mask >> 0)  & 0x7f;
70e72b21abSJames Hogan 
716d741bfeSSean Young 	protocols &= RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 |
726d741bfeSSean Young 							RC_PROTO_BIT_SONY20;
730751d33cSSean Young 
740751d33cSSean Young 	/*
750751d33cSSean Young 	 * If only one bit is set, we were requested to do an exact
760751d33cSSean Young 	 * protocol. This should be the case for wakeup filters; for
770751d33cSSean Young 	 * normal filters, guess the protocol from the scancode.
780751d33cSSean Young 	 */
790751d33cSSean Young 	if (!is_power_of_2(protocols)) {
800751d33cSSean Young 		if (subdev & subdev_m)
816d741bfeSSean Young 			protocols = RC_PROTO_BIT_SONY20;
820751d33cSSean Young 		else if (dev & dev_m & 0xe0)
836d741bfeSSean Young 			protocols = RC_PROTO_BIT_SONY15;
840751d33cSSean Young 		else
856d741bfeSSean Young 			protocols = RC_PROTO_BIT_SONY12;
860751d33cSSean Young 	}
870751d33cSSean Young 
886d741bfeSSean Young 	if (protocols == RC_PROTO_BIT_SONY20) {
89e72b21abSJames Hogan 		/* can't encode subdev and higher device bits */
90e72b21abSJames Hogan 		if (dev & dev_m & 0xe0)
91e72b21abSJames Hogan 			return -EINVAL;
92e72b21abSJames Hogan 		len = 20;
93e72b21abSJames Hogan 		dev_m &= 0x1f;
946d741bfeSSean Young 	} else if (protocols == RC_PROTO_BIT_SONY15) {
95e72b21abSJames Hogan 		len = 15;
96e72b21abSJames Hogan 		subdev_m = 0;
97e72b21abSJames Hogan 	} else {
98e72b21abSJames Hogan 		/*
99e72b21abSJames Hogan 		 * The hardware mask cannot distinguish high device bits and low
100e72b21abSJames Hogan 		 * extended bits, so logically AND those bits of the masks
101e72b21abSJames Hogan 		 * together.
102e72b21abSJames Hogan 		 */
103e72b21abSJames Hogan 		subdev_m &= (dev_m >> 5) | 0xf8;
104e72b21abSJames Hogan 		dev_m &= 0x1f;
105e72b21abSJames Hogan 	}
106e72b21abSJames Hogan 
107e72b21abSJames Hogan 	/* ensure there aren't any bits straying between fields */
108e72b21abSJames Hogan 	dev &= dev_m;
109e72b21abSJames Hogan 	subdev &= subdev_m;
110e72b21abSJames Hogan 
111e72b21abSJames Hogan 	/* write the hardware filter */
112e72b21abSJames Hogan 	out->data = func          |
113e72b21abSJames Hogan 		    dev      << 7 |
114e72b21abSJames Hogan 		    subdev   << 15;
115e72b21abSJames Hogan 	out->mask = func_m        |
116e72b21abSJames Hogan 		    dev_m    << 7 |
117e72b21abSJames Hogan 		    subdev_m << 15;
118e72b21abSJames Hogan 
119e72b21abSJames Hogan 	if (len) {
120e72b21abSJames Hogan 		out->minlen = len;
121e72b21abSJames Hogan 		out->maxlen = len;
122e72b21abSJames Hogan 	}
123e72b21abSJames Hogan 	return 0;
124e72b21abSJames Hogan }
125e72b21abSJames Hogan 
126e72b21abSJames Hogan /*
127e72b21abSJames Hogan  * Sony SIRC decoder
128e72b21abSJames Hogan  * See also http://www.sbprojects.com/knowledge/ir/sirc.php
129e72b21abSJames Hogan  *          http://picprojects.org.uk/projects/sirc/sonysirc.pdf
130e72b21abSJames Hogan  */
131e72b21abSJames Hogan struct img_ir_decoder img_ir_sony = {
1326d741bfeSSean Young 	.type = RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 | RC_PROTO_BIT_SONY20,
133e72b21abSJames Hogan 	.control = {
134e72b21abSJames Hogan 		.decoden = 1,
135e72b21abSJames Hogan 		.code_type = IMG_IR_CODETYPE_PULSELEN,
136e72b21abSJames Hogan 	},
137e72b21abSJames Hogan 	/* main timings */
138e72b21abSJames Hogan 	.unit = 600000, /* 600 us */
139e72b21abSJames Hogan 	.timings = {
140e72b21abSJames Hogan 		/* leader symbol */
141e72b21abSJames Hogan 		.ldr = {
142e72b21abSJames Hogan 			.pulse = { 4	/* 2.4 ms */ },
143e72b21abSJames Hogan 			.space = { 1	/* 600 us */ },
144e72b21abSJames Hogan 		},
145e72b21abSJames Hogan 		/* 0 symbol */
146e72b21abSJames Hogan 		.s00 = {
147e72b21abSJames Hogan 			.pulse = { 1	/* 600 us */ },
148e72b21abSJames Hogan 			.space = { 1	/* 600 us */ },
149e72b21abSJames Hogan 		},
150e72b21abSJames Hogan 		/* 1 symbol */
151e72b21abSJames Hogan 		.s01 = {
152e72b21abSJames Hogan 			.pulse = { 2	/* 1.2 ms */ },
153e72b21abSJames Hogan 			.space = { 1	/* 600 us */ },
154e72b21abSJames Hogan 		},
155e72b21abSJames Hogan 		/* free time */
156e72b21abSJames Hogan 		.ft = {
157e72b21abSJames Hogan 			.minlen = 12,
158e72b21abSJames Hogan 			.maxlen = 20,
159e72b21abSJames Hogan 			.ft_min = 10,	/* 6 ms */
160e72b21abSJames Hogan 		},
161e72b21abSJames Hogan 	},
162e72b21abSJames Hogan 	/* scancode logic */
163e72b21abSJames Hogan 	.scancode = img_ir_sony_scancode,
164e72b21abSJames Hogan 	.filter = img_ir_sony_filter,
165e72b21abSJames Hogan };
166