18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * ImgTec IR Decoder setup for Sony (SIRC) protocol.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2012-2014 Imagination Technologies Ltd.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "img-ir-hw.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci/* Convert Sony data to a scancode */
118c2ecf20Sopenharmony_cistatic int img_ir_sony_scancode(int len, u64 raw, u64 enabled_protocols,
128c2ecf20Sopenharmony_ci				struct img_ir_scancode_req *request)
138c2ecf20Sopenharmony_ci{
148c2ecf20Sopenharmony_ci	unsigned int dev, subdev, func;
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci	switch (len) {
178c2ecf20Sopenharmony_ci	case 12:
188c2ecf20Sopenharmony_ci		if (!(enabled_protocols & RC_PROTO_BIT_SONY12))
198c2ecf20Sopenharmony_ci			return -EINVAL;
208c2ecf20Sopenharmony_ci		func   = raw & 0x7f;	/* first 7 bits */
218c2ecf20Sopenharmony_ci		raw    >>= 7;
228c2ecf20Sopenharmony_ci		dev    = raw & 0x1f;	/* next 5 bits */
238c2ecf20Sopenharmony_ci		subdev = 0;
248c2ecf20Sopenharmony_ci		request->protocol = RC_PROTO_SONY12;
258c2ecf20Sopenharmony_ci		break;
268c2ecf20Sopenharmony_ci	case 15:
278c2ecf20Sopenharmony_ci		if (!(enabled_protocols & RC_PROTO_BIT_SONY15))
288c2ecf20Sopenharmony_ci			return -EINVAL;
298c2ecf20Sopenharmony_ci		func   = raw & 0x7f;	/* first 7 bits */
308c2ecf20Sopenharmony_ci		raw    >>= 7;
318c2ecf20Sopenharmony_ci		dev    = raw & 0xff;	/* next 8 bits */
328c2ecf20Sopenharmony_ci		subdev = 0;
338c2ecf20Sopenharmony_ci		request->protocol = RC_PROTO_SONY15;
348c2ecf20Sopenharmony_ci		break;
358c2ecf20Sopenharmony_ci	case 20:
368c2ecf20Sopenharmony_ci		if (!(enabled_protocols & RC_PROTO_BIT_SONY20))
378c2ecf20Sopenharmony_ci			return -EINVAL;
388c2ecf20Sopenharmony_ci		func   = raw & 0x7f;	/* first 7 bits */
398c2ecf20Sopenharmony_ci		raw    >>= 7;
408c2ecf20Sopenharmony_ci		dev    = raw & 0x1f;	/* next 5 bits */
418c2ecf20Sopenharmony_ci		raw    >>= 5;
428c2ecf20Sopenharmony_ci		subdev = raw & 0xff;	/* next 8 bits */
438c2ecf20Sopenharmony_ci		request->protocol = RC_PROTO_SONY20;
448c2ecf20Sopenharmony_ci		break;
458c2ecf20Sopenharmony_ci	default:
468c2ecf20Sopenharmony_ci		return -EINVAL;
478c2ecf20Sopenharmony_ci	}
488c2ecf20Sopenharmony_ci	request->scancode = dev << 16 | subdev << 8 | func;
498c2ecf20Sopenharmony_ci	return IMG_IR_SCANCODE;
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/* Convert NEC scancode to NEC data filter */
538c2ecf20Sopenharmony_cistatic int img_ir_sony_filter(const struct rc_scancode_filter *in,
548c2ecf20Sopenharmony_ci			      struct img_ir_filter *out, u64 protocols)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	unsigned int dev, subdev, func;
578c2ecf20Sopenharmony_ci	unsigned int dev_m, subdev_m, func_m;
588c2ecf20Sopenharmony_ci	unsigned int len = 0;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	dev      = (in->data >> 16) & 0xff;
618c2ecf20Sopenharmony_ci	dev_m    = (in->mask >> 16) & 0xff;
628c2ecf20Sopenharmony_ci	subdev   = (in->data >> 8)  & 0xff;
638c2ecf20Sopenharmony_ci	subdev_m = (in->mask >> 8)  & 0xff;
648c2ecf20Sopenharmony_ci	func     = (in->data >> 0)  & 0x7f;
658c2ecf20Sopenharmony_ci	func_m   = (in->mask >> 0)  & 0x7f;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	protocols &= RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 |
688c2ecf20Sopenharmony_ci							RC_PROTO_BIT_SONY20;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	/*
718c2ecf20Sopenharmony_ci	 * If only one bit is set, we were requested to do an exact
728c2ecf20Sopenharmony_ci	 * protocol. This should be the case for wakeup filters; for
738c2ecf20Sopenharmony_ci	 * normal filters, guess the protocol from the scancode.
748c2ecf20Sopenharmony_ci	 */
758c2ecf20Sopenharmony_ci	if (!is_power_of_2(protocols)) {
768c2ecf20Sopenharmony_ci		if (subdev & subdev_m)
778c2ecf20Sopenharmony_ci			protocols = RC_PROTO_BIT_SONY20;
788c2ecf20Sopenharmony_ci		else if (dev & dev_m & 0xe0)
798c2ecf20Sopenharmony_ci			protocols = RC_PROTO_BIT_SONY15;
808c2ecf20Sopenharmony_ci		else
818c2ecf20Sopenharmony_ci			protocols = RC_PROTO_BIT_SONY12;
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	if (protocols == RC_PROTO_BIT_SONY20) {
858c2ecf20Sopenharmony_ci		/* can't encode subdev and higher device bits */
868c2ecf20Sopenharmony_ci		if (dev & dev_m & 0xe0)
878c2ecf20Sopenharmony_ci			return -EINVAL;
888c2ecf20Sopenharmony_ci		len = 20;
898c2ecf20Sopenharmony_ci		dev_m &= 0x1f;
908c2ecf20Sopenharmony_ci	} else if (protocols == RC_PROTO_BIT_SONY15) {
918c2ecf20Sopenharmony_ci		len = 15;
928c2ecf20Sopenharmony_ci		subdev_m = 0;
938c2ecf20Sopenharmony_ci	} else {
948c2ecf20Sopenharmony_ci		/*
958c2ecf20Sopenharmony_ci		 * The hardware mask cannot distinguish high device bits and low
968c2ecf20Sopenharmony_ci		 * extended bits, so logically AND those bits of the masks
978c2ecf20Sopenharmony_ci		 * together.
988c2ecf20Sopenharmony_ci		 */
998c2ecf20Sopenharmony_ci		subdev_m &= (dev_m >> 5) | 0xf8;
1008c2ecf20Sopenharmony_ci		dev_m &= 0x1f;
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	/* ensure there aren't any bits straying between fields */
1048c2ecf20Sopenharmony_ci	dev &= dev_m;
1058c2ecf20Sopenharmony_ci	subdev &= subdev_m;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	/* write the hardware filter */
1088c2ecf20Sopenharmony_ci	out->data = func          |
1098c2ecf20Sopenharmony_ci		    dev      << 7 |
1108c2ecf20Sopenharmony_ci		    subdev   << 15;
1118c2ecf20Sopenharmony_ci	out->mask = func_m        |
1128c2ecf20Sopenharmony_ci		    dev_m    << 7 |
1138c2ecf20Sopenharmony_ci		    subdev_m << 15;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (len) {
1168c2ecf20Sopenharmony_ci		out->minlen = len;
1178c2ecf20Sopenharmony_ci		out->maxlen = len;
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci	return 0;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci/*
1238c2ecf20Sopenharmony_ci * Sony SIRC decoder
1248c2ecf20Sopenharmony_ci * See also http://www.sbprojects.com/knowledge/ir/sirc.php
1258c2ecf20Sopenharmony_ci *          http://picprojects.org.uk/projects/sirc/sonysirc.pdf
1268c2ecf20Sopenharmony_ci */
1278c2ecf20Sopenharmony_cistruct img_ir_decoder img_ir_sony = {
1288c2ecf20Sopenharmony_ci	.type = RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 | RC_PROTO_BIT_SONY20,
1298c2ecf20Sopenharmony_ci	.control = {
1308c2ecf20Sopenharmony_ci		.decoden = 1,
1318c2ecf20Sopenharmony_ci		.code_type = IMG_IR_CODETYPE_PULSELEN,
1328c2ecf20Sopenharmony_ci	},
1338c2ecf20Sopenharmony_ci	/* main timings */
1348c2ecf20Sopenharmony_ci	.unit = 600000, /* 600 us */
1358c2ecf20Sopenharmony_ci	.timings = {
1368c2ecf20Sopenharmony_ci		/* leader symbol */
1378c2ecf20Sopenharmony_ci		.ldr = {
1388c2ecf20Sopenharmony_ci			.pulse = { 4	/* 2.4 ms */ },
1398c2ecf20Sopenharmony_ci			.space = { 1	/* 600 us */ },
1408c2ecf20Sopenharmony_ci		},
1418c2ecf20Sopenharmony_ci		/* 0 symbol */
1428c2ecf20Sopenharmony_ci		.s00 = {
1438c2ecf20Sopenharmony_ci			.pulse = { 1	/* 600 us */ },
1448c2ecf20Sopenharmony_ci			.space = { 1	/* 600 us */ },
1458c2ecf20Sopenharmony_ci		},
1468c2ecf20Sopenharmony_ci		/* 1 symbol */
1478c2ecf20Sopenharmony_ci		.s01 = {
1488c2ecf20Sopenharmony_ci			.pulse = { 2	/* 1.2 ms */ },
1498c2ecf20Sopenharmony_ci			.space = { 1	/* 600 us */ },
1508c2ecf20Sopenharmony_ci		},
1518c2ecf20Sopenharmony_ci		/* free time */
1528c2ecf20Sopenharmony_ci		.ft = {
1538c2ecf20Sopenharmony_ci			.minlen = 12,
1548c2ecf20Sopenharmony_ci			.maxlen = 20,
1558c2ecf20Sopenharmony_ci			.ft_min = 10,	/* 6 ms */
1568c2ecf20Sopenharmony_ci		},
1578c2ecf20Sopenharmony_ci	},
1588c2ecf20Sopenharmony_ci	/* scancode logic */
1598c2ecf20Sopenharmony_ci	.scancode = img_ir_sony_scancode,
1608c2ecf20Sopenharmony_ci	.filter = img_ir_sony_filter,
1618c2ecf20Sopenharmony_ci};
162