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

[media] rtl28xx: reimplement I2C adapter

It is almost perfect now!
Signed-off-by: default avatarAntti Palosaari <crope@iki.fi>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent b5cbaa43
...@@ -134,11 +134,29 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ...@@ -134,11 +134,29 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
{ {
int ret; int ret;
struct dvb_usb_device *d = i2c_get_adapdata(adap); struct dvb_usb_device *d = i2c_get_adapdata(adap);
struct rtl28xxu_priv *priv = d->priv;
struct rtl28xxu_req req; struct rtl28xxu_req req;
/* /*
* It is not known which are real I2C bus xfer limits, but testing * It is not known which are real I2C bus xfer limits, but testing
* with RTL2831U + MT2060 gives max RD 24 and max WR 22 bytes. * with RTL2831U + MT2060 gives max RD 24 and max WR 22 bytes.
* TODO: find out RTL2832U lens
*/
/*
* I2C adapter logic looks rather complicated due to fact it handles
* three different access methods. Those methods are;
* 1) integrated demod access
* 2) old I2C access
* 3) new I2C access
*
* Used method is selected in order 1, 2, 3. Method 3 can handle all
* requests but there is two reasons why not use it always;
* 1) It is most expensive, usually two USB messages are needed
* 2) At least RTL2831U does not support it
*
* Method 3 is needed in case of I2C write+read (typical register read)
* where write is more than one byte.
*/ */
if (mutex_lock_interruptible(&d->i2c_mutex) < 0) if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
...@@ -146,44 +164,73 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ...@@ -146,44 +164,73 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
if (num == 2 && !(msg[0].flags & I2C_M_RD) && if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
(msg[1].flags & I2C_M_RD)) { (msg[1].flags & I2C_M_RD)) {
if (msg[0].len > 2 || msg[1].len > 24) { if (msg[0].len > 24 || msg[1].len > 24) {
/* TODO: check msg[0].len max */
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto err_unlock; goto err_unlock;
} } else if (msg[0].addr == 0x10) {
if (msg[0].addr == 0x10) { /* method 1 - integrated demod */
/* integrated demod */ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
req.value = (msg[0].buf[1] << 8) | (msg[0].addr << 1); req.index = CMD_DEMOD_RD | priv->page;
req.index = CMD_DEMOD_RD | msg[0].buf[0];
req.size = msg[1].len; req.size = msg[1].len;
req.data = &msg[1].buf[0]; req.data = &msg[1].buf[0];
ret = rtl28xxu_ctrl_msg(d, &req); ret = rtl28xxu_ctrl_msg(d, &req);
} else { } else if (msg[0].len < 2) {
/* real I2C */ /* method 2 - old I2C */
req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
req.index = CMD_I2C_RD; req.index = CMD_I2C_RD;
req.size = msg[1].len; req.size = msg[1].len;
req.data = &msg[1].buf[0]; req.data = &msg[1].buf[0];
ret = rtl28xxu_ctrl_msg(d, &req); ret = rtl28xxu_ctrl_msg(d, &req);
} else {
/* method 3 - new I2C */
req.value = (msg[0].addr << 1);
req.index = CMD_I2C_DA_WR;
req.size = msg[0].len;
req.data = msg[0].buf;
ret = rtl28xxu_ctrl_msg(d, &req);
if (ret)
goto err_unlock;
req.value = (msg[0].addr << 1);
req.index = CMD_I2C_DA_RD;
req.size = msg[1].len;
req.data = msg[1].buf;
ret = rtl28xxu_ctrl_msg(d, &req);
} }
} else if (num == 1 && !(msg[0].flags & I2C_M_RD)) { } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
if (msg[0].len > 22) { if (msg[0].len > 22) {
/* TODO: check msg[0].len max */
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto err_unlock; goto err_unlock;
} } else if (msg[0].addr == 0x10) {
if (msg[0].addr == 0x10) { /* method 1 - integrated demod */
/* integrated demod */ if (msg[0].buf[0] == 0x00) {
req.value = (msg[0].buf[1] << 8) | (msg[0].addr << 1); /* save demod page for later demod access */
req.index = CMD_DEMOD_WR | msg[0].buf[0]; priv->page = msg[0].buf[1];
req.size = msg[0].len-2; ret = 0;
req.data = &msg[0].buf[2]; } else {
ret = rtl28xxu_ctrl_msg(d, &req); req.value = (msg[0].buf[0] << 8) |
} else { (msg[0].addr << 1);
/* real I2C */ req.index = CMD_DEMOD_WR | priv->page;
req.size = msg[0].len-1;
req.data = &msg[0].buf[1];
ret = rtl28xxu_ctrl_msg(d, &req);
}
} else if (msg[0].len < 23) {
/* method 2 - old I2C */
req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
req.index = CMD_I2C_WR; req.index = CMD_I2C_WR;
req.size = msg[0].len-1; req.size = msg[0].len-1;
req.data = &msg[0].buf[1]; req.data = &msg[0].buf[1];
ret = rtl28xxu_ctrl_msg(d, &req); ret = rtl28xxu_ctrl_msg(d, &req);
} else {
/* method 3 - new I2C */
req.value = (msg[0].addr << 1);
req.index = CMD_I2C_DA_WR;
req.size = msg[0].len;
req.data = msg[0].buf;
ret = rtl28xxu_ctrl_msg(d, &req);
} }
} else { } else {
ret = -EINVAL; ret = -EINVAL;
......
...@@ -49,25 +49,30 @@ ...@@ -49,25 +49,30 @@
* USB commands * USB commands
* (usb_control_msg() index parameter) * (usb_control_msg() index parameter)
*/ */
#define DEMOD (0x00 << 8) #define DEMOD (0x00 << 8)
#define USB (0x01 << 8) #define USB (0x01 << 8)
#define SYS (0x02 << 8) #define SYS (0x02 << 8)
#define I2C (0x03 << 8) #define I2C (0x03 << 8)
#define I2C_DA (0x06 << 8)
#define CMD_WR_FLAG 0x10 #define CMD_WR_FLAG 0x10
#define CMD_DEMOD_RD (DEMOD) #define CMD_DEMOD_RD (DEMOD)
#define CMD_DEMOD_WR (DEMOD | CMD_WR_FLAG) #define CMD_DEMOD_WR (DEMOD | CMD_WR_FLAG)
#define CMD_USB_RD (USB) #define CMD_USB_RD (USB)
#define CMD_USB_WR (USB | CMD_WR_FLAG) #define CMD_USB_WR (USB | CMD_WR_FLAG)
#define CMD_SYS_RD (SYS) #define CMD_SYS_RD (SYS)
#define CMD_IR_RD (CMD_SYS_RD | 0x01)
#define CMD_IR_WR (CMD_SYS_WR | 0x01)
#define CMD_SYS_WR (SYS | CMD_WR_FLAG) #define CMD_SYS_WR (SYS | CMD_WR_FLAG)
#define CMD_I2C_RD (I2C) #define CMD_I2C_RD (I2C)
#define CMD_I2C_WR (I2C | CMD_WR_FLAG) #define CMD_I2C_WR (I2C | CMD_WR_FLAG)
#define CMD_IR_RD (CMD_SYS_RD | 0x01) #define CMD_I2C_DA_RD (I2C_DA)
#define CMD_IR_WR (CMD_SYS_WR | 0x01) #define CMD_I2C_DA_WR (I2C_DA | CMD_WR_FLAG)
struct rtl28xxu_priv { struct rtl28xxu_priv {
u8 chip_id; u8 chip_id;
u8 tuner; u8 tuner;
u8 page; /* integrated demod active register page */
bool rc_active; bool rc_active;
}; };
......
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