162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ImgTec IR Decoder setup for Sony (SIRC) protocol.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2012-2014 Imagination Technologies Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "img-ir-hw.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci/* Convert Sony data to a scancode */
1162306a36Sopenharmony_cistatic int img_ir_sony_scancode(int len, u64 raw, u64 enabled_protocols,
1262306a36Sopenharmony_ci				struct img_ir_scancode_req *request)
1362306a36Sopenharmony_ci{
1462306a36Sopenharmony_ci	unsigned int dev, subdev, func;
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci	switch (len) {
1762306a36Sopenharmony_ci	case 12:
1862306a36Sopenharmony_ci		if (!(enabled_protocols & RC_PROTO_BIT_SONY12))
1962306a36Sopenharmony_ci			return -EINVAL;
2062306a36Sopenharmony_ci		func   = raw & 0x7f;	/* first 7 bits */
2162306a36Sopenharmony_ci		raw    >>= 7;
2262306a36Sopenharmony_ci		dev    = raw & 0x1f;	/* next 5 bits */
2362306a36Sopenharmony_ci		subdev = 0;
2462306a36Sopenharmony_ci		request->protocol = RC_PROTO_SONY12;
2562306a36Sopenharmony_ci		break;
2662306a36Sopenharmony_ci	case 15:
2762306a36Sopenharmony_ci		if (!(enabled_protocols & RC_PROTO_BIT_SONY15))
2862306a36Sopenharmony_ci			return -EINVAL;
2962306a36Sopenharmony_ci		func   = raw & 0x7f;	/* first 7 bits */
3062306a36Sopenharmony_ci		raw    >>= 7;
3162306a36Sopenharmony_ci		dev    = raw & 0xff;	/* next 8 bits */
3262306a36Sopenharmony_ci		subdev = 0;
3362306a36Sopenharmony_ci		request->protocol = RC_PROTO_SONY15;
3462306a36Sopenharmony_ci		break;
3562306a36Sopenharmony_ci	case 20:
3662306a36Sopenharmony_ci		if (!(enabled_protocols & RC_PROTO_BIT_SONY20))
3762306a36Sopenharmony_ci			return -EINVAL;
3862306a36Sopenharmony_ci		func   = raw & 0x7f;	/* first 7 bits */
3962306a36Sopenharmony_ci		raw    >>= 7;
4062306a36Sopenharmony_ci		dev    = raw & 0x1f;	/* next 5 bits */
4162306a36Sopenharmony_ci		raw    >>= 5;
4262306a36Sopenharmony_ci		subdev = raw & 0xff;	/* next 8 bits */
4362306a36Sopenharmony_ci		request->protocol = RC_PROTO_SONY20;
4462306a36Sopenharmony_ci		break;
4562306a36Sopenharmony_ci	default:
4662306a36Sopenharmony_ci		return -EINVAL;
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci	request->scancode = dev << 16 | subdev << 8 | func;
4962306a36Sopenharmony_ci	return IMG_IR_SCANCODE;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/* Convert NEC scancode to NEC data filter */
5362306a36Sopenharmony_cistatic int img_ir_sony_filter(const struct rc_scancode_filter *in,
5462306a36Sopenharmony_ci			      struct img_ir_filter *out, u64 protocols)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	unsigned int dev, subdev, func;
5762306a36Sopenharmony_ci	unsigned int dev_m, subdev_m, func_m;
5862306a36Sopenharmony_ci	unsigned int len = 0;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	dev      = (in->data >> 16) & 0xff;
6162306a36Sopenharmony_ci	dev_m    = (in->mask >> 16) & 0xff;
6262306a36Sopenharmony_ci	subdev   = (in->data >> 8)  & 0xff;
6362306a36Sopenharmony_ci	subdev_m = (in->mask >> 8)  & 0xff;
6462306a36Sopenharmony_ci	func     = (in->data >> 0)  & 0x7f;
6562306a36Sopenharmony_ci	func_m   = (in->mask >> 0)  & 0x7f;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	protocols &= RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 |
6862306a36Sopenharmony_ci							RC_PROTO_BIT_SONY20;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/*
7162306a36Sopenharmony_ci	 * If only one bit is set, we were requested to do an exact
7262306a36Sopenharmony_ci	 * protocol. This should be the case for wakeup filters; for
7362306a36Sopenharmony_ci	 * normal filters, guess the protocol from the scancode.
7462306a36Sopenharmony_ci	 */
7562306a36Sopenharmony_ci	if (!is_power_of_2(protocols)) {
7662306a36Sopenharmony_ci		if (subdev & subdev_m)
7762306a36Sopenharmony_ci			protocols = RC_PROTO_BIT_SONY20;
7862306a36Sopenharmony_ci		else if (dev & dev_m & 0xe0)
7962306a36Sopenharmony_ci			protocols = RC_PROTO_BIT_SONY15;
8062306a36Sopenharmony_ci		else
8162306a36Sopenharmony_ci			protocols = RC_PROTO_BIT_SONY12;
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if (protocols == RC_PROTO_BIT_SONY20) {
8562306a36Sopenharmony_ci		/* can't encode subdev and higher device bits */
8662306a36Sopenharmony_ci		if (dev & dev_m & 0xe0)
8762306a36Sopenharmony_ci			return -EINVAL;
8862306a36Sopenharmony_ci		len = 20;
8962306a36Sopenharmony_ci		dev_m &= 0x1f;
9062306a36Sopenharmony_ci	} else if (protocols == RC_PROTO_BIT_SONY15) {
9162306a36Sopenharmony_ci		len = 15;
9262306a36Sopenharmony_ci		subdev_m = 0;
9362306a36Sopenharmony_ci	} else {
9462306a36Sopenharmony_ci		/*
9562306a36Sopenharmony_ci		 * The hardware mask cannot distinguish high device bits and low
9662306a36Sopenharmony_ci		 * extended bits, so logically AND those bits of the masks
9762306a36Sopenharmony_ci		 * together.
9862306a36Sopenharmony_ci		 */
9962306a36Sopenharmony_ci		subdev_m &= (dev_m >> 5) | 0xf8;
10062306a36Sopenharmony_ci		dev_m &= 0x1f;
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	/* ensure there aren't any bits straying between fields */
10462306a36Sopenharmony_ci	dev &= dev_m;
10562306a36Sopenharmony_ci	subdev &= subdev_m;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	/* write the hardware filter */
10862306a36Sopenharmony_ci	out->data = func          |
10962306a36Sopenharmony_ci		    dev      << 7 |
11062306a36Sopenharmony_ci		    subdev   << 15;
11162306a36Sopenharmony_ci	out->mask = func_m        |
11262306a36Sopenharmony_ci		    dev_m    << 7 |
11362306a36Sopenharmony_ci		    subdev_m << 15;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	if (len) {
11662306a36Sopenharmony_ci		out->minlen = len;
11762306a36Sopenharmony_ci		out->maxlen = len;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci	return 0;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/*
12362306a36Sopenharmony_ci * Sony SIRC decoder
12462306a36Sopenharmony_ci * See also http://www.sbprojects.com/knowledge/ir/sirc.php
12562306a36Sopenharmony_ci *          http://picprojects.org.uk/projects/sirc/sonysirc.pdf
12662306a36Sopenharmony_ci */
12762306a36Sopenharmony_cistruct img_ir_decoder img_ir_sony = {
12862306a36Sopenharmony_ci	.type = RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 | RC_PROTO_BIT_SONY20,
12962306a36Sopenharmony_ci	.control = {
13062306a36Sopenharmony_ci		.decoden = 1,
13162306a36Sopenharmony_ci		.code_type = IMG_IR_CODETYPE_PULSELEN,
13262306a36Sopenharmony_ci	},
13362306a36Sopenharmony_ci	/* main timings */
13462306a36Sopenharmony_ci	.unit = 600000, /* 600 us */
13562306a36Sopenharmony_ci	.timings = {
13662306a36Sopenharmony_ci		/* leader symbol */
13762306a36Sopenharmony_ci		.ldr = {
13862306a36Sopenharmony_ci			.pulse = { 4	/* 2.4 ms */ },
13962306a36Sopenharmony_ci			.space = { 1	/* 600 us */ },
14062306a36Sopenharmony_ci		},
14162306a36Sopenharmony_ci		/* 0 symbol */
14262306a36Sopenharmony_ci		.s00 = {
14362306a36Sopenharmony_ci			.pulse = { 1	/* 600 us */ },
14462306a36Sopenharmony_ci			.space = { 1	/* 600 us */ },
14562306a36Sopenharmony_ci		},
14662306a36Sopenharmony_ci		/* 1 symbol */
14762306a36Sopenharmony_ci		.s01 = {
14862306a36Sopenharmony_ci			.pulse = { 2	/* 1.2 ms */ },
14962306a36Sopenharmony_ci			.space = { 1	/* 600 us */ },
15062306a36Sopenharmony_ci		},
15162306a36Sopenharmony_ci		/* free time */
15262306a36Sopenharmony_ci		.ft = {
15362306a36Sopenharmony_ci			.minlen = 12,
15462306a36Sopenharmony_ci			.maxlen = 20,
15562306a36Sopenharmony_ci			.ft_min = 10,	/* 6 ms */
15662306a36Sopenharmony_ci		},
15762306a36Sopenharmony_ci	},
15862306a36Sopenharmony_ci	/* scancode logic */
15962306a36Sopenharmony_ci	.scancode = img_ir_sony_scancode,
16062306a36Sopenharmony_ci	.filter = img_ir_sony_filter,
16162306a36Sopenharmony_ci};
162