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

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

[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
Loading
Loading
Loading
Loading
+65 −18
Original line number Diff line number Diff line
@@ -134,11 +134,29 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
{
	int ret;
	struct dvb_usb_device *d = i2c_get_adapdata(adap);
	struct rtl28xxu_priv *priv = d->priv;
	struct rtl28xxu_req req;

	/*
	 * 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.
	 * 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)
@@ -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) &&
		(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;
			goto err_unlock;
		}
		if (msg[0].addr == 0x10) {
			/* integrated demod */
			req.value = (msg[0].buf[1] << 8) | (msg[0].addr << 1);
			req.index = CMD_DEMOD_RD | msg[0].buf[0];
		} else if (msg[0].addr == 0x10) {
			/* method 1 - integrated demod */
			req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
			req.index = CMD_DEMOD_RD | priv->page;
			req.size = msg[1].len;
			req.data = &msg[1].buf[0];
			ret = rtl28xxu_ctrl_msg(d, &req);
		} else {
			/* real I2C */
		} else if (msg[0].len < 2) {
			/* method 2 - old I2C */
			req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
			req.index = CMD_I2C_RD;
			req.size = msg[1].len;
			req.data = &msg[1].buf[0];
			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)) {
		if (msg[0].len > 22) {
			/* TODO: check msg[0].len max */
			ret = -EOPNOTSUPP;
			goto err_unlock;
		}
		if (msg[0].addr == 0x10) {
			/* integrated demod */
			req.value = (msg[0].buf[1] << 8) | (msg[0].addr << 1);
			req.index = CMD_DEMOD_WR | msg[0].buf[0];
			req.size = msg[0].len-2;
			req.data = &msg[0].buf[2];
			ret = rtl28xxu_ctrl_msg(d, &req);
		} else if (msg[0].addr == 0x10) {
			/* method 1 - integrated demod */
			if (msg[0].buf[0] == 0x00) {
				/* save demod page for later demod access */
				priv->page = msg[0].buf[1];
				ret = 0;
			} else {
			/* real I2C */
				req.value = (msg[0].buf[0] << 8) |
					(msg[0].addr << 1);
				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.index = CMD_I2C_WR;
			req.size = msg[0].len-1;
			req.data = &msg[0].buf[1];
			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 {
		ret = -EINVAL;
+11 −6
Original line number Diff line number Diff line
@@ -53,21 +53,26 @@
#define USB    (0x01 << 8)
#define SYS    (0x02 << 8)
#define I2C    (0x03 << 8)
#define I2C_DA (0x06 << 8)

#define CMD_WR_FLAG   0x10
#define CMD_DEMOD_RD  (DEMOD)
#define CMD_DEMOD_WR  (DEMOD | CMD_WR_FLAG)
#define CMD_USB_RD    (USB)
#define CMD_USB_WR    (USB | CMD_WR_FLAG)
#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_I2C_RD    (I2C)
#define CMD_I2C_WR    (I2C | CMD_WR_FLAG)
#define CMD_IR_RD     (CMD_SYS_RD | 0x01)
#define CMD_IR_WR     (CMD_SYS_WR | 0x01)
#define CMD_I2C_DA_RD (I2C_DA)
#define CMD_I2C_DA_WR (I2C_DA | CMD_WR_FLAG)

struct rtl28xxu_priv {
	u8 chip_id;
	u8 tuner;
	u8 page; /* integrated demod active register page */
	bool rc_active;
};