Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f39fac3e authored by Antti Palosaari's avatar Antti Palosaari Committed by Mauro Carvalho Chehab
Browse files

[media] rtl28xxu: reimplement rtl2832u remote controller



Thanks to Rodrigo for original implementation!

Signed-off-by: default avatarAntti Palosaari <crope@iki.fi>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 1e41413f
Loading
Loading
Loading
Loading
+56 −96
Original line number Diff line number Diff line
@@ -1114,17 +1114,6 @@ static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff)
		if (ret)
			goto err;
	} else {
		/* demod_ctl_1 */
		ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val);
		if (ret)
			goto err;

		val |= 0x0c;

		ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val);
		if (ret)
			goto err;

		/* set output values */
		ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
		if (ret)
@@ -1249,72 +1238,44 @@ static int rtl2831u_get_rc_config(struct dvb_usb_device *d,
#if IS_ENABLED(CONFIG_RC_CORE)
static int rtl2832u_rc_query(struct dvb_usb_device *d)
{
#define TICSAT38KHZTONS(x) ((x) * (1000000000/38000))
	int ret, i;
	int ret, i, len;
	struct rtl28xxu_priv *priv = d->priv;
	struct ir_raw_event ev;
	u8 buf[128];
	int len;
	struct ir_raw_event ev; //encode single ir event (pulse or space)
	struct rtl28xxu_xreg_val rc_sys_init_tab[] = {
		{ SYS_DEMOD_CTL1,   OP_AND, 0xfb },
		{ SYS_DEMOD_CTL1,   OP_AND, 0xf7 },
		{ USB_CTRL,         OP_OR , 0x20 },
		{ SYS_SYS1,         OP_AND, 0xf7 },
		{ SYS_GPIO_OUT_EN,  OP_OR , 0x08 },
		{ SYS_GPIO_OUT_VAL, OP_OR , 0x08 },
	}; // system hard init
	struct rtl28xxu_reg_val rc_init_tab[] = {
		{ IR_RX_CTRL,             0x20 },
		{ IR_RX_BUF_CTRL,         0x80 },
		{ IR_RX_IF,               0xff },
		{ IR_RX_IE,               0xff },
		{ IR_MAX_DURATION0,       0xd0 },
		{ IR_MAX_DURATION1,       0x07 },
		{ IR_IDLE_LEN0,           0xc0 },
		{ IR_IDLE_LEN1,           0x00 },
		{ IR_GLITCH_LEN,          0x03 },
		{ IR_RX_CLK,              0x09 },
		{ IR_RX_CFG,              0x1c },
		{ IR_MAX_H_TOL_LEN,       0x1e },
		{ IR_MAX_L_TOL_LEN,       0x1e },
		{ IR_RX_CTRL,             0x80 },
	}; // hard init
	struct rtl28xxu_reg_val rc_reinit_tab[] = {
		{ IR_RX_CTRL,     0x20 },
		{ IR_RX_BUF_CTRL, 0x80 },
		{ IR_RX_IF,       0xff },
		{ IR_RX_IE,       0xff },
		{ IR_RX_CTRL,     0x80 },
	}; // reinit IR
	struct rtl28xxu_reg_val rc_clear_tab[] = {
		{ IR_RX_IF,       0x03 },
		{ IR_RX_BUF_CTRL, 0x80 },
		{ IR_RX_CTRL,     0x80 },
	}; // clear reception
	static const struct rtl28xxu_reg_val_mask refresh_tab[] = {
		{IR_RX_IF,               0x03, 0xff},
		{IR_RX_BUF_CTRL,         0x80, 0xff},
		{IR_RX_CTRL,             0x80, 0xff},
	};

	/* init remote controller */
	if (!priv->rc_active) {
		for (i = 0; i < ARRAY_SIZE(rc_sys_init_tab); i++) {
			ret = rtl28xx_rd_reg(d, rc_sys_init_tab[i].reg, &buf[0]);
			if (ret)
				goto err;
			if (rc_sys_init_tab[i].op == OP_AND) {
				buf[0] &= rc_sys_init_tab[i].mask;
			}
			else {//OP_OR
				buf[0] |= rc_sys_init_tab[i].mask;
			}
			ret = rtl28xx_wr_reg(d, rc_sys_init_tab[i].reg,
					buf[0]);
			if (ret)
				goto err;
		}
		for (i = 0; i < ARRAY_SIZE(rc_init_tab); i++) {
			ret = rtl28xx_wr_reg(d, rc_init_tab[i].reg,
					rc_init_tab[i].val);
		static const struct rtl28xxu_reg_val_mask init_tab[] = {
			{SYS_DEMOD_CTL1,         0x00, 0x04},
			{SYS_DEMOD_CTL1,         0x00, 0x08},
			{USB_CTRL,               0x20, 0x20},
			{SYS_GPIO_DIR,           0x00, 0x08},
			{SYS_GPIO_OUT_EN,        0x08, 0x08},
			{SYS_GPIO_OUT_VAL,       0x08, 0x08},
			{IR_MAX_DURATION0,       0xd0, 0xff},
			{IR_MAX_DURATION1,       0x07, 0xff},
			{IR_IDLE_LEN0,           0xc0, 0xff},
			{IR_IDLE_LEN1,           0x00, 0xff},
			{IR_GLITCH_LEN,          0x03, 0xff},
			{IR_RX_CLK,              0x09, 0xff},
			{IR_RX_CFG,              0x1c, 0xff},
			{IR_MAX_H_TOL_LEN,       0x1e, 0xff},
			{IR_MAX_L_TOL_LEN,       0x1e, 0xff},
			{IR_RX_CTRL,             0x80, 0xff},
		};

		for (i = 0; i < ARRAY_SIZE(init_tab); i++) {
			ret = rtl28xx_wr_reg_mask(d, init_tab[i].reg,
					init_tab[i].val, init_tab[i].mask);
			if (ret)
				goto err;
		}

		priv->rc_active = true;
	}

@@ -1323,57 +1284,56 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
		goto err;

	if (buf[0] != 0x83)
		goto err;
		goto exit;

	ret = rtl28xx_rd_reg(d, IR_RX_BC, &buf[0]);
	if (ret)
		goto err;

	len = buf[0];
	ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len);

	/* pass raw IR to Kernel IR decoder */
	init_ir_raw_event(&ev);
	ir_raw_event_reset(d->rc_dev);
	ev.pulse=1;
	for(i=0; true; ++i) { // conver count to time
		if (i >= len || !(buf[i] & 0x80) != !(ev.pulse)) {//end or transition pulse/space: flush
			ir_raw_event_store(d->rc_dev, &ev);
			ev.duration = 0;
		}
		if (i >= len)
			break;
		ev.pulse = buf[i] >> 7;
		ev.duration += TICSAT38KHZTONS(((u32)(buf[i] & 0x7F)) << 1);
	}
	ir_raw_event_handle(d->rc_dev);
	/* read raw code from hw */
	ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len);
	if (ret)
		goto err;

	for (i = 0; i < ARRAY_SIZE(rc_clear_tab); i++) {
		ret = rtl28xx_wr_reg(d, rc_clear_tab[i].reg,
				rc_clear_tab[i].val);
	/* let hw receive new code */
	for (i = 0; i < ARRAY_SIZE(refresh_tab); i++) {
		ret = rtl28xx_wr_reg_mask(d, refresh_tab[i].reg,
				refresh_tab[i].val, refresh_tab[i].mask);
		if (ret)
			goto err;
	}

	/* pass data to Kernel IR decoder */
	init_ir_raw_event(&ev);

	for (i = 0; i < len; i++) {
		ev.pulse = buf[i] >> 7;
		ev.duration = 50800 * (buf[i] & 0x7f);
		ir_raw_event_store_with_filter(d->rc_dev, &ev);
	}

	/* 'flush' ir_raw_event_store_with_filter() */
	ir_raw_event_set_idle(d->rc_dev, true);
	ir_raw_event_handle(d->rc_dev);
exit:
	return ret;
err:
	for (i = 0; i < ARRAY_SIZE(rc_reinit_tab); i++) {
		ret = rtl28xx_wr_reg(d, rc_reinit_tab[i].reg,
				rc_reinit_tab[i].val);
	}
	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
	return ret;
#undef TICSAT38KHZTONS
}

static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
		struct dvb_usb_rc *rc)
{
	/* load empty to enable rc */
	if (!rc->map_name)
		rc->map_name = RC_MAP_EMPTY;
	rc->allowed_protos = RC_BIT_ALL;
	rc->driver_type = RC_DRIVER_IR_RAW;
	rc->query = rtl2832u_rc_query;
	rc->interval = 400;
	rc->driver_type = RC_DRIVER_IR_RAW;

	return 0;
}
+2 −7
Original line number Diff line number Diff line
@@ -97,14 +97,9 @@ struct rtl28xxu_reg_val {
	u8 val;
};

enum OP{
	OP_AND	=0,
	OP_OR
};

struct rtl28xxu_xreg_val {
struct rtl28xxu_reg_val_mask {
	u16 reg;
	u8 op;
	u8 val;
	u8 mask;
};