Beispiel #1
0
static int rtl28xxu_identify_state(struct dvb_usb_device *d, const char **name)
{
	struct rtl28xxu_dev *dev = d_to_priv(d);
	int ret;
	struct rtl28xxu_req req_demod_i2c = {0x0020, CMD_I2C_DA_RD, 0, NULL};

	dev_dbg(&d->intf->dev, "\n");

	/*
	 * Detect chip type using I2C command that is not supported
	 * by old RTL2831U.
	 */
	ret = rtl28xxu_ctrl_msg(d, &req_demod_i2c);
	if (ret == -EPIPE) {
		dev->chip_id = CHIP_ID_RTL2831U;
	} else if (ret == 0) {
		dev->chip_id = CHIP_ID_RTL2832U;
	} else {
		dev_err(&d->intf->dev, "chip type detection failed %d\n", ret);
		goto err;
	}
	dev_dbg(&d->intf->dev, "chip_id=%u\n", dev->chip_id);

	return WARM;
err:
	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
	return ret;
}
Beispiel #2
0
static int rtl28xx_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
{
	struct rtl28xxu_req req;

	if (reg < 0x3000)
		req.index = CMD_USB_WR;
	else if (reg < 0x4000)
		req.index = CMD_SYS_WR;
	else
		req.index = CMD_IR_WR;

	req.value = reg;
	req.size = len;
	req.data = val;

	return rtl28xxu_ctrl_msg(d, &req);
}
Beispiel #3
0
static int rtl2832u_read_config(struct dvb_usb_device *d)
{
	struct rtl28xxu_priv *priv = d_to_priv(d);
	int ret;
	u8 buf[2];
	/* open RTL2832U/RTL2832 I2C gate */
	struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"};
	/* close RTL2832U/RTL2832 I2C gate */
	struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"};
	/* tuner probes */
	struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf};
	struct rtl28xxu_req req_fc0013 = {0x00c6, CMD_I2C_RD, 1, buf};
	struct rtl28xxu_req req_mt2266 = {0x00c0, CMD_I2C_RD, 1, buf};
	struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};
	struct rtl28xxu_req req_mt2063 = {0x00c0, CMD_I2C_RD, 1, buf};
	struct rtl28xxu_req req_max3543 = {0x00c0, CMD_I2C_RD, 1, buf};
	struct rtl28xxu_req req_tua9001 = {0x7ec0, CMD_I2C_RD, 2, buf};
	struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf};
	struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf};
	struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf};
	struct rtl28xxu_req req_r820t = {0x0034, CMD_I2C_RD, 1, buf};

	dev_dbg(&d->udev->dev, "%s:\n", __func__);

	/* enable GPIO3 and GPIO6 as output */
	ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x40);
	if (ret)
		goto err;

	ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x48, 0x48);
	if (ret)
		goto err;

	/*
	 * Probe used tuner. We need to know used tuner before demod attach
	 * since there is some demod params needed to set according to tuner.
	 */

	/* open demod I2C gate */
	ret = rtl28xxu_ctrl_msg(d, &req_gate_open);
	if (ret)
		goto err;

	priv->tuner_name = "NONE";

	/* check FC0012 ID register; reg=00 val=a1 */
	ret = rtl28xxu_ctrl_msg(d, &req_fc0012);
	if (ret == 0 && buf[0] == 0xa1) {
		priv->tuner = TUNER_RTL2832_FC0012;
		priv->tuner_name = "FC0012";
		goto found;
	}

	/* check FC0013 ID register; reg=00 val=a3 */
	ret = rtl28xxu_ctrl_msg(d, &req_fc0013);
	if (ret == 0 && buf[0] == 0xa3) {
		priv->tuner = TUNER_RTL2832_FC0013;
		priv->tuner_name = "FC0013";
		goto found;
	}

	/* check MT2266 ID register; reg=00 val=85 */
	ret = rtl28xxu_ctrl_msg(d, &req_mt2266);
	if (ret == 0 && buf[0] == 0x85) {
		priv->tuner = TUNER_RTL2832_MT2266;
		priv->tuner_name = "MT2266";
		goto found;
	}

	/* check FC2580 ID register; reg=01 val=56 */
	ret = rtl28xxu_ctrl_msg(d, &req_fc2580);
	if (ret == 0 && buf[0] == 0x56) {
		priv->tuner = TUNER_RTL2832_FC2580;
		priv->tuner_name = "FC2580";
		goto found;
	}

	/* check MT2063 ID register; reg=00 val=9e || 9c */
	ret = rtl28xxu_ctrl_msg(d, &req_mt2063);
	if (ret == 0 && (buf[0] == 0x9e || buf[0] == 0x9c)) {
		priv->tuner = TUNER_RTL2832_MT2063;
		priv->tuner_name = "MT2063";
		goto found;
	}

	/* check MAX3543 ID register; reg=00 val=38 */
	ret = rtl28xxu_ctrl_msg(d, &req_max3543);
	if (ret == 0 && buf[0] == 0x38) {
		priv->tuner = TUNER_RTL2832_MAX3543;
		priv->tuner_name = "MAX3543";
		goto found;
	}

	/* check TUA9001 ID register; reg=7e val=2328 */
	ret = rtl28xxu_ctrl_msg(d, &req_tua9001);
	if (ret == 0 && buf[0] == 0x23 && buf[1] == 0x28) {
		priv->tuner = TUNER_RTL2832_TUA9001;
		priv->tuner_name = "TUA9001";
		goto found;
	}

	/* check MXL5007R ID register; reg=d9 val=14 */
	ret = rtl28xxu_ctrl_msg(d, &req_mxl5007t);
	if (ret == 0 && buf[0] == 0x14) {
		priv->tuner = TUNER_RTL2832_MXL5007T;
		priv->tuner_name = "MXL5007T";
		goto found;
	}

	/* check E4000 ID register; reg=02 val=40 */
	ret = rtl28xxu_ctrl_msg(d, &req_e4000);
	if (ret == 0 && buf[0] == 0x40) {
		priv->tuner = TUNER_RTL2832_E4000;
		priv->tuner_name = "E4000";
		goto found;
	}

	/* check TDA18272 ID register; reg=00 val=c760  */
	ret = rtl28xxu_ctrl_msg(d, &req_tda18272);
	if (ret == 0 && (buf[0] == 0xc7 || buf[1] == 0x60)) {
		priv->tuner = TUNER_RTL2832_TDA18272;
		priv->tuner_name = "TDA18272";
		goto found;
	}

	/* check R820T ID register; reg=00 val=69 */
	ret = rtl28xxu_ctrl_msg(d, &req_r820t);
	if (ret == 0 && buf[0] == 0x69) {
		priv->tuner = TUNER_RTL2832_R820T;
		priv->tuner_name = "R820T";
		goto found;
	}

found:
	dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name);

	/* close demod I2C gate */
	ret = rtl28xxu_ctrl_msg(d, &req_gate_close);
	if (ret < 0)
		goto err;

	return 0;
err:
	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
	return ret;
}
Beispiel #4
0
static int rtl2831u_read_config(struct dvb_usb_device *d)
{
	struct rtl28xxu_priv *priv = d_to_priv(d);
	int ret;
	u8 buf[1];
	/* open RTL2831U/RTL2830 I2C gate */
	struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x08"};
	/* tuner probes */
	struct rtl28xxu_req req_mt2060 = {0x00c0, CMD_I2C_RD, 1, buf};
	struct rtl28xxu_req req_qt1010 = {0x0fc4, CMD_I2C_RD, 1, buf};

	dev_dbg(&d->udev->dev, "%s:\n", __func__);

	/*
	 * RTL2831U GPIOs
	 * =========================================================
	 * GPIO0 | tuner#0 | 0 off | 1 on  | MXL5005S (?)
	 * GPIO2 | LED     | 0 off | 1 on  |
	 * GPIO4 | tuner#1 | 0 on  | 1 off | MT2060
	 */

	/* GPIO direction */
	ret = rtl28xx_wr_reg(d, SYS_GPIO_DIR, 0x0a);
	if (ret)
		goto err;

	/* enable as output GPIO0, GPIO2, GPIO4 */
	ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_EN, 0x15);
	if (ret)
		goto err;

	/*
	 * Probe used tuner. We need to know used tuner before demod attach
	 * since there is some demod params needed to set according to tuner.
	 */

	/* demod needs some time to wake up */
	msleep(20);

	priv->tuner_name = "NONE";

	/* open demod I2C gate */
	ret = rtl28xxu_ctrl_msg(d, &req_gate_open);
	if (ret)
		goto err;

	/* check QT1010 ID(?) register; reg=0f val=2c */
	ret = rtl28xxu_ctrl_msg(d, &req_qt1010);
	if (ret == 0 && buf[0] == 0x2c) {
		priv->tuner = TUNER_RTL2830_QT1010;
		priv->tuner_name = "QT1010";
		goto found;
	}

	/* open demod I2C gate */
	ret = rtl28xxu_ctrl_msg(d, &req_gate_open);
	if (ret)
		goto err;

	/* check MT2060 ID register; reg=00 val=63 */
	ret = rtl28xxu_ctrl_msg(d, &req_mt2060);
	if (ret == 0 && buf[0] == 0x63) {
		priv->tuner = TUNER_RTL2830_MT2060;
		priv->tuner_name = "MT2060";
		goto found;
	}

	/* assume MXL5005S */
	priv->tuner = TUNER_RTL2830_MXL5005S;
	priv->tuner_name = "MXL5005S";
	goto found;

found:
	dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name);

	return 0;
err:
	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
	return ret;
}
Beispiel #5
0
/* I2C */
static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
	int num)
{
	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)
		return -EAGAIN;

	if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
		(msg[1].flags & I2C_M_RD)) {
		if (msg[0].len > 24 || msg[1].len > 24) {
			/* TODO: check msg[0].len max */
			ret = -EOPNOTSUPP;
			goto err_mutex_unlock;
		} 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 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_mutex_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_mutex_unlock;
		} 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 {
				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;
	}

err_mutex_unlock:
	mutex_unlock(&d->i2c_mutex);

	return ret ? ret : num;
}
static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
{
	int ret;
	struct rtl28xxu_priv *priv = adap->dev->priv;
	struct rtl2832_config *rtl2832_config;

	u8 buf[2], val;
	/* open RTL2832U/RTL2832 I2C gate */
	struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"};
	/* close RTL2832U/RTL2832 I2C gate */
	struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"};
	/* for FC0012 tuner probe */
	struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf};
	/* for FC0013 tuner probe */
	struct rtl28xxu_req req_fc0013 = {0x00c6, CMD_I2C_RD, 1, buf};
	/* for MT2266 tuner probe */
	struct rtl28xxu_req req_mt2266 = {0x00c0, CMD_I2C_RD, 1, buf};
	/* for FC2580 tuner probe */
	struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};
	/* for MT2063 tuner probe */
	struct rtl28xxu_req req_mt2063 = {0x00c0, CMD_I2C_RD, 1, buf};
	/* for MAX3543 tuner probe */
	struct rtl28xxu_req req_max3543 = {0x00c0, CMD_I2C_RD, 1, buf};
	/* for TUA9001 tuner probe */
	struct rtl28xxu_req req_tua9001 = {0x7ec0, CMD_I2C_RD, 2, buf};
	/* for MXL5007T tuner probe */
	struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf};
	/* for E4000 tuner probe */
	struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf};
	/* for TDA18272 tuner probe */
	struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf};

	deb_info("%s:\n", __func__);


	ret = rtl28xx_rd_reg(adap->dev, SYS_GPIO_DIR, &val);
	if (ret)
		goto err;

	val &= 0xbf;

	ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_DIR, val);
	if (ret)
		goto err;


	/* enable as output GPIO3 and GPIO6*/
	ret = rtl28xx_rd_reg(adap->dev, SYS_GPIO_OUT_EN, &val);
	if (ret)
		goto err;

	val |= 0x48;

	ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_OUT_EN, val);
	if (ret)
		goto err;



	/*
	 * Probe used tuner. We need to know used tuner before demod attach
	 * since there is some demod params needed to set according to tuner.
	 */

	/* open demod I2C gate */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_open);
	if (ret)
		goto err;

	priv->tuner = TUNER_NONE;

	/* check FC0012 ID register; reg=00 val=a1 */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc0012);
	if (ret == 0 && buf[0] == 0xa1) {
		priv->tuner = TUNER_RTL2832_FC0012;
		rtl2832_config = &rtl28xxu_rtl2832_fc0012_config;
		info("%s: FC0012 tuner found", __func__);
		goto found;
	}

	/* check FC0013 ID register; reg=00 val=a3 */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc0013);
	if (ret == 0 && buf[0] == 0xa3) {
		priv->tuner = TUNER_RTL2832_FC0013;
		rtl2832_config = &rtl28xxu_rtl2832_fc0013_config;
		info("%s: FC0013 tuner found", __func__);
		goto found;
	}

	/* check MT2266 ID register; reg=00 val=85 */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2266);
	if (ret == 0 && buf[0] == 0x85) {
		priv->tuner = TUNER_RTL2832_MT2266;
		/* TODO implement tuner */
		info("%s: MT2266 tuner found", __func__);
		goto unsupported;
	}

	/* check FC2580 ID register; reg=01 val=56 */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc2580);
	if (ret == 0 && buf[0] == 0x56) {
		priv->tuner = TUNER_RTL2832_FC2580;
		/* TODO implement tuner */
		info("%s: FC2580 tuner found", __func__);
		goto unsupported;
	}

	/* check MT2063 ID register; reg=00 val=9e || 9c */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2063);
	if (ret == 0 && (buf[0] == 0x9e || buf[0] == 0x9c)) {
		priv->tuner = TUNER_RTL2832_MT2063;
		/* TODO implement tuner */
		info("%s: MT2063 tuner found", __func__);
		goto unsupported;
	}

	/* check MAX3543 ID register; reg=00 val=38 */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_max3543);
	if (ret == 0 && buf[0] == 0x38) {
		priv->tuner = TUNER_RTL2832_MAX3543;
		/* TODO implement tuner */
		info("%s: MAX3534 tuner found", __func__);
		goto unsupported;
	}

	/* check TUA9001 ID register; reg=7e val=2328 */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_tua9001);
	if (ret == 0 && buf[0] == 0x23 && buf[1] == 0x28) {
		priv->tuner = TUNER_RTL2832_TUA9001;
		/* TODO implement tuner */
		info("%s: TUA9001 tuner found", __func__);
		goto unsupported;
	}

	/* check MXL5007R ID register; reg=d9 val=14 */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_mxl5007t);
	if (ret == 0 && buf[0] == 0x14) {
		priv->tuner = TUNER_RTL2832_MXL5007T;
		/* TODO implement tuner */
		info("%s: MXL5007T tuner found", __func__);
		goto unsupported;
	}

	/* check E4000 ID register; reg=02 val=40 */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_e4000);
	if (ret == 0 && buf[0] == 0x40) {
		priv->tuner = TUNER_RTL2832_E4000;
		/* TODO implement tuner */
		info("%s: E4000 tuner found", __func__);
		goto unsupported;
	}

	/* check TDA18272 ID register; reg=00 val=c760  */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_tda18272);
	if (ret == 0 && (buf[0] == 0xc7 || buf[1] == 0x60)) {
		priv->tuner = TUNER_RTL2832_TDA18272;
		/* TODO implement tuner */
		info("%s: TDA18272 tuner found", __func__);
		goto unsupported;
	}

unsupported:
	/* close demod I2C gate */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
	if (ret)
		goto err;

	/* tuner not found */
	deb_info("No compatible tuner found");
	ret = -ENODEV;
	return ret;

found:
	/* close demod I2C gate */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
	if (ret)
		goto err;

	/* attach demodulator */
	adap->fe_adap[0].fe = dvb_attach(rtl2832_attach, rtl2832_config,
		&adap->dev->i2c_adap);
		if (adap->fe_adap[0].fe == NULL) {
			ret = -ENODEV;
			goto err;
		}

	/* set fe callbacks */
	adap->fe_adap[0].fe->callback = rtl2832u_frontend_callback;

	return ret;

err:
	deb_info("%s: failed=%d\n", __func__, ret);
	return ret;
}
static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
{
	int ret;
	struct rtl28xxu_priv *priv = adap->dev->priv;
	u8 buf[1];
	struct rtl2830_config *rtl2830_config;
	/* open RTL2831U/RTL2830 I2C gate */
	struct rtl28xxu_req req_gate = { 0x0120, 0x0011, 0x0001, "\x08" };
	/* for MT2060 tuner probe */
	struct rtl28xxu_req req_mt2060 = { 0x00c0, CMD_I2C_RD, 1, buf };
	/* for QT1010 tuner probe */
	struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf };

	deb_info("%s:\n", __func__);

	/*
	 * RTL2831U GPIOs
	 * =========================================================
	 * GPIO0 | tuner#0 | 0 off | 1 on  | MXL5005S (?)
	 * GPIO2 | LED     | 0 off | 1 on  |
	 * GPIO4 | tuner#1 | 0 on  | 1 off | MT2060
	 */

	/* GPIO direction */
	ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
	if (ret)
		goto err;

	/* enable as output GPIO0, GPIO2, GPIO4 */
	ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
	if (ret)
		goto err;

	/*
	 * Probe used tuner. We need to know used tuner before demod attach
	 * since there is some demod params needed to set according to tuner.
	 */

	/* demod needs some time to wake up */
	msleep(20);

	/* open demod I2C gate */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate);
	if (ret)
		goto err;

	/* check QT1010 ID(?) register; reg=0f val=2c */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_qt1010);
	if (ret == 0 && buf[0] == 0x2c) {
		priv->tuner = TUNER_RTL2830_QT1010;
		rtl2830_config = &rtl28xxu_rtl2830_qt1010_config;
		deb_info("%s: QT1010\n", __func__);
		goto found;
	} else {
		deb_info("%s: QT1010 probe failed=%d - %02x\n",
			__func__, ret, buf[0]);
	}

	/* open demod I2C gate */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate);
	if (ret)
		goto err;

	/* check MT2060 ID register; reg=00 val=63 */
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2060);
	if (ret == 0 && buf[0] == 0x63) {
		priv->tuner = TUNER_RTL2830_MT2060;
		rtl2830_config = &rtl28xxu_rtl2830_mt2060_config;
		deb_info("%s: MT2060\n", __func__);
		goto found;
	} else {
		deb_info("%s: MT2060 probe failed=%d - %02x\n",
			__func__, ret, buf[0]);
	}

	/* assume MXL5005S */
	ret = 0;
	priv->tuner = TUNER_RTL2830_MXL5005S;
	rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config;
	deb_info("%s: MXL5005S\n", __func__);
	goto found;

found:
	/* attach demodulator */
	adap->fe_adap[0].fe = dvb_attach(rtl2830_attach, rtl2830_config,
		&adap->dev->i2c_adap);
	if (adap->fe_adap[0].fe == NULL) {
		ret = -ENODEV;
		goto err;
	}

	return ret;
err:
	deb_info("%s: failed=%d\n", __func__, ret);
	return ret;
}
static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
{
	int ret;
	struct rtl28xxu_priv *priv = adap->dev->priv;
	u8 buf[1];
	
	struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"};
	
	struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"};
	
	struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};

	deb_info("%s:\n", __func__);

	
	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
	if (ret)
		goto err;

	
	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
	if (ret)
		goto err;

	ret = rtl2831_wr_reg(adap->dev, SYS_DEMOD_CTL, 0xe8);
	if (ret)
		goto err;


	
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_open);
	if (ret)
		goto err;

	
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc2580);
	if (ret == 0 && buf[0] == 0x56) {
		priv->tuner = TUNER_RTL2832_FC2580;
		deb_info("%s: FC2580\n", __func__);
		goto found;
	} else {
		deb_info("%s: FC2580 probe failed=%d - %02x\n",
			__func__, ret, buf[0]);
	}

	
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
	if (ret)
		goto err;

	
	ret = -ENODEV;
	goto err;

found:
	
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
	if (ret)
		goto err;

	
	

	return ret;
err:
	deb_info("%s: failed=%d\n", __func__, ret);
	return ret;
}
static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
{
	int ret;
	struct rtl28xxu_priv *priv = adap->dev->priv;
	u8 buf[1];
	struct rtl2830_config *rtl2830_config;
	
	struct rtl28xxu_req req_gate = { 0x0120, 0x0011, 0x0001, "\x08" };
	
	struct rtl28xxu_req req_mt2060 = { 0x00c0, CMD_I2C_RD, 1, buf };
	
	struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf };

	deb_info("%s:\n", __func__);


	
	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
	if (ret)
		goto err;

	
	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
	if (ret)
		goto err;


	
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate);
	if (ret)
		goto err;

	
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_qt1010);
	if (ret == 0 && buf[0] == 0x2c) {
		priv->tuner = TUNER_RTL2830_QT1010;
		rtl2830_config = &rtl28xxu_rtl2830_qt1010_config;
		deb_info("%s: QT1010\n", __func__);
		goto found;
	} else {
		deb_info("%s: QT1010 probe failed=%d - %02x\n",
			__func__, ret, buf[0]);
	}

	
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate);
	if (ret)
		goto err;

	
	ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2060);
	if (ret == 0 && buf[0] == 0x63) {
		priv->tuner = TUNER_RTL2830_MT2060;
		rtl2830_config = &rtl28xxu_rtl2830_mt2060_config;
		deb_info("%s: MT2060\n", __func__);
		goto found;
	} else {
		deb_info("%s: MT2060 probe failed=%d - %02x\n",
			__func__, ret, buf[0]);
	}

	
	ret = 0;
	priv->tuner = TUNER_RTL2830_MXL5005S;
	rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config;
	deb_info("%s: MXL5005S\n", __func__);
	goto found;

found:
	
	adap->fe_adap[0].fe = dvb_attach(rtl2830_attach, rtl2830_config,
		&adap->dev->i2c_adap);
	if (adap->fe_adap[0].fe == NULL) {
		ret = -ENODEV;
		goto err;
	}

	return ret;
err:
	deb_info("%s: failed=%d\n", __func__, ret);
	return ret;
}
static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
	int num)
{
	int ret;
	struct dvb_usb_device *d = i2c_get_adapdata(adap);
	struct rtl28xxu_priv *priv = d->priv;
	struct rtl28xxu_req req;



	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
		return -EAGAIN;

	if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
		(msg[1].flags & I2C_M_RD)) {
		if (msg[0].len > 24 || msg[1].len > 24) {
			
			ret = -EOPNOTSUPP;
			goto err_mutex_unlock;
		} else if (msg[0].addr == 0x10) {
			
			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 if (msg[0].len < 2) {
			
			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 {
			
			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_mutex_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) {
			
			ret = -EOPNOTSUPP;
			goto err_mutex_unlock;
		} else if (msg[0].addr == 0x10) {
			
			if (msg[0].buf[0] == 0x00) {
				
				priv->page = msg[0].buf[1];
				ret = 0;
			} else {
				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) {
			
			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 {
			
			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;
	}

err_mutex_unlock:
	mutex_unlock(&d->i2c_mutex);

	return ret ? ret : num;
}