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

[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
...@@ -1114,17 +1114,6 @@ static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff) ...@@ -1114,17 +1114,6 @@ static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff)
if (ret) if (ret)
goto err; goto err;
} else { } 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 */ /* set output values */
ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val); ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
if (ret) if (ret)
...@@ -1249,72 +1238,44 @@ static int rtl2831u_get_rc_config(struct dvb_usb_device *d, ...@@ -1249,72 +1238,44 @@ static int rtl2831u_get_rc_config(struct dvb_usb_device *d,
#if IS_ENABLED(CONFIG_RC_CORE) #if IS_ENABLED(CONFIG_RC_CORE)
static int rtl2832u_rc_query(struct dvb_usb_device *d) static int rtl2832u_rc_query(struct dvb_usb_device *d)
{ {
#define TICSAT38KHZTONS(x) ((x) * (1000000000/38000)) int ret, i, len;
int ret, i;
struct rtl28xxu_priv *priv = d->priv; struct rtl28xxu_priv *priv = d->priv;
struct ir_raw_event ev;
u8 buf[128]; u8 buf[128];
int len; static const struct rtl28xxu_reg_val_mask refresh_tab[] = {
struct ir_raw_event ev; //encode single ir event (pulse or space) {IR_RX_IF, 0x03, 0xff},
struct rtl28xxu_xreg_val rc_sys_init_tab[] = { {IR_RX_BUF_CTRL, 0x80, 0xff},
{ SYS_DEMOD_CTL1, OP_AND, 0xfb }, {IR_RX_CTRL, 0x80, 0xff},
{ 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
/* init remote controller */ /* init remote controller */
if (!priv->rc_active) { if (!priv->rc_active) {
for (i = 0; i < ARRAY_SIZE(rc_sys_init_tab); i++) { static const struct rtl28xxu_reg_val_mask init_tab[] = {
ret = rtl28xx_rd_reg(d, rc_sys_init_tab[i].reg, &buf[0]); {SYS_DEMOD_CTL1, 0x00, 0x04},
if (ret) {SYS_DEMOD_CTL1, 0x00, 0x08},
goto err; {USB_CTRL, 0x20, 0x20},
if (rc_sys_init_tab[i].op == OP_AND) { {SYS_GPIO_DIR, 0x00, 0x08},
buf[0] &= rc_sys_init_tab[i].mask; {SYS_GPIO_OUT_EN, 0x08, 0x08},
} {SYS_GPIO_OUT_VAL, 0x08, 0x08},
else {//OP_OR {IR_MAX_DURATION0, 0xd0, 0xff},
buf[0] |= rc_sys_init_tab[i].mask; {IR_MAX_DURATION1, 0x07, 0xff},
} {IR_IDLE_LEN0, 0xc0, 0xff},
ret = rtl28xx_wr_reg(d, rc_sys_init_tab[i].reg, {IR_IDLE_LEN1, 0x00, 0xff},
buf[0]); {IR_GLITCH_LEN, 0x03, 0xff},
if (ret) {IR_RX_CLK, 0x09, 0xff},
goto err; {IR_RX_CFG, 0x1c, 0xff},
} {IR_MAX_H_TOL_LEN, 0x1e, 0xff},
for (i = 0; i < ARRAY_SIZE(rc_init_tab); i++) { {IR_MAX_L_TOL_LEN, 0x1e, 0xff},
ret = rtl28xx_wr_reg(d, rc_init_tab[i].reg, {IR_RX_CTRL, 0x80, 0xff},
rc_init_tab[i].val); };
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) if (ret)
goto err; goto err;
} }
priv->rc_active = true; priv->rc_active = true;
} }
...@@ -1323,57 +1284,56 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d) ...@@ -1323,57 +1284,56 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
goto err; goto err;
if (buf[0] != 0x83) if (buf[0] != 0x83)
goto err; goto exit;
ret = rtl28xx_rd_reg(d, IR_RX_BC, &buf[0]); ret = rtl28xx_rd_reg(d, IR_RX_BC, &buf[0]);
if (ret) if (ret)
goto err; goto err;
len = buf[0]; len = buf[0];
ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len);
/* pass raw IR to Kernel IR decoder */ /* read raw code from hw */
init_ir_raw_event(&ev); ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len);
ir_raw_event_reset(d->rc_dev); if (ret)
ev.pulse=1; goto err;
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);
for (i = 0; i < ARRAY_SIZE(rc_clear_tab); i++) { /* let hw receive new code */
ret = rtl28xx_wr_reg(d, rc_clear_tab[i].reg, for (i = 0; i < ARRAY_SIZE(refresh_tab); i++) {
rc_clear_tab[i].val); ret = rtl28xx_wr_reg_mask(d, refresh_tab[i].reg,
refresh_tab[i].val, refresh_tab[i].mask);
if (ret) if (ret)
goto err; 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; return ret;
err: 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); dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
return ret; return ret;
#undef TICSAT38KHZTONS
} }
static int rtl2832u_get_rc_config(struct dvb_usb_device *d, static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
struct dvb_usb_rc *rc) struct dvb_usb_rc *rc)
{ {
rc->map_name = RC_MAP_EMPTY; /* load empty to enable rc */
if (!rc->map_name)
rc->map_name = RC_MAP_EMPTY;
rc->allowed_protos = RC_BIT_ALL; rc->allowed_protos = RC_BIT_ALL;
rc->driver_type = RC_DRIVER_IR_RAW;
rc->query = rtl2832u_rc_query; rc->query = rtl2832u_rc_query;
rc->interval = 400; rc->interval = 400;
rc->driver_type = RC_DRIVER_IR_RAW;
return 0; return 0;
} }
......
...@@ -97,14 +97,9 @@ struct rtl28xxu_reg_val { ...@@ -97,14 +97,9 @@ struct rtl28xxu_reg_val {
u8 val; u8 val;
}; };
enum OP{ struct rtl28xxu_reg_val_mask {
OP_AND =0,
OP_OR
};
struct rtl28xxu_xreg_val {
u16 reg; u16 reg;
u8 op; u8 val;
u8 mask; u8 mask;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment