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

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

[media] anysee: convert tda18212 tuner to I2C client



Used tda18212 tuner is implemented as I2C driver. Implement I2C
client to anysee and use it for tda18212.

Signed-off-by: default avatarAntti Palosaari <crope@iki.fi>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent 3ab779c0
Loading
Loading
Loading
Loading
+149 −36
Original line number Diff line number Diff line
@@ -332,7 +332,6 @@ static struct tda10023_config anysee_tda10023_tda18212_config = {
};

static struct tda18212_config anysee_tda18212_config = {
	.i2c_address = (0xc0 >> 1),
	.if_dvbt_6 = 4150,
	.if_dvbt_7 = 4150,
	.if_dvbt_8 = 4150,
@@ -340,7 +339,6 @@ static struct tda18212_config anysee_tda18212_config = {
};

static struct tda18212_config anysee_tda18212_config2 = {
	.i2c_address = 0x60 /* (0xc0 >> 1) */,
	.if_dvbt_6 = 3550,
	.if_dvbt_7 = 3700,
	.if_dvbt_8 = 4150,
@@ -632,6 +630,92 @@ static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff)
	return ret;
}

static int anysee_add_i2c_dev(struct dvb_usb_device *d, char *type, u8 addr,
		void *platform_data)
{
	int ret, num;
	struct anysee_state *state = d_to_priv(d);
	struct i2c_client *client;
	struct i2c_adapter *adapter = &d->i2c_adap;
	struct i2c_board_info board_info = {
		.addr = addr,
		.platform_data = platform_data,
	};

	strlcpy(board_info.type, type, I2C_NAME_SIZE);

	/* find first free client */
	for (num = 0; num < ANYSEE_I2C_CLIENT_MAX; num++) {
		if (state->i2c_client[num] == NULL)
			break;
	}

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

	if (num == ANYSEE_I2C_CLIENT_MAX) {
		dev_err(&d->udev->dev, "%s: I2C client out of index\n",
				KBUILD_MODNAME);
		ret = -ENODEV;
		goto err;
	}

	request_module(board_info.type);

	/* register I2C device */
	client = i2c_new_device(adapter, &board_info);
	if (client == NULL || client->dev.driver == NULL) {
		ret = -ENODEV;
		goto err;
	}

	/* increase I2C driver usage count */
	if (!try_module_get(client->dev.driver->owner)) {
		i2c_unregister_device(client);
		ret = -ENODEV;
		goto err;
	}

	state->i2c_client[num] = client;
	return 0;
err:
	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
	return ret;
}

static void anysee_del_i2c_dev(struct dvb_usb_device *d)
{
	int num;
	struct anysee_state *state = d_to_priv(d);
	struct i2c_client *client;

	/* find last used client */
	num = ANYSEE_I2C_CLIENT_MAX;
	while (num--) {
		if (state->i2c_client[num] != NULL)
			break;
	}

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

	if (num == -1) {
		dev_err(&d->udev->dev, "%s: I2C client out of index\n",
				KBUILD_MODNAME);
		goto err;
	}

	client = state->i2c_client[num];

	/* decrease I2C driver usage count */
	module_put(client->dev.driver->owner);

	/* unregister I2C device */
	i2c_unregister_device(client);

	state->i2c_client[num] = NULL;
err:
	dev_dbg(&d->udev->dev, "%s: failed\n", __func__);
}

static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
{
	struct anysee_state *state = adap_to_priv(adap);
@@ -640,12 +724,12 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
	u8 tmp;
	struct i2c_msg msg[2] = {
		{
			.addr = anysee_tda18212_config.i2c_address,
			.addr = 0x60,
			.flags = 0,
			.len = 1,
			.buf = "\x00",
		}, {
			.addr = anysee_tda18212_config.i2c_address,
			.addr = 0x60,
			.flags = I2C_M_RD,
			.len = 1,
			.buf = &tmp,
@@ -723,9 +807,11 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
		/* probe TDA18212 */
		tmp = 0;
		ret = i2c_transfer(&d->i2c_adap, msg, 2);
		if (ret == 2 && tmp == 0xc7)
		if (ret == 2 && tmp == 0xc7) {
			dev_dbg(&d->udev->dev, "%s: TDA18212 found\n",
					__func__);
			state->has_tda18212 = true;
		}
		else
			tmp = 0;

@@ -939,21 +1025,31 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
		 * fails attach old simple PLL. */

		/* attach tuner */
		fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
				&anysee_tda18212_config);
		if (state->has_tda18212) {
			struct tda18212_config tda18212_config =
					anysee_tda18212_config;

		if (fe && adap->fe[1]) {
			/* attach tuner for 2nd FE */
			fe = dvb_attach(tda18212_attach, adap->fe[1],
					&d->i2c_adap, &anysee_tda18212_config);
			break;
		} else if (fe) {
			break;
			tda18212_config.fe = adap->fe[0];
			ret = anysee_add_i2c_dev(d, "tda18212", 0x60,
					&tda18212_config);
			if (ret)
				goto err;

			/* copy tuner ops for 2nd FE as tuner is shared */
			if (adap->fe[1]) {
				adap->fe[1]->tuner_priv =
						adap->fe[0]->tuner_priv;
				memcpy(&adap->fe[1]->ops.tuner_ops,
						&adap->fe[0]->ops.tuner_ops,
						sizeof(struct dvb_tuner_ops));
			}

			return 0;
		} else {
			/* attach tuner */
		fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1),
				&d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
			fe = dvb_attach(dvb_pll_attach, adap->fe[0],
					(0xc0 >> 1), &d->i2c_adap,
					DVB_PLL_SAMSUNG_DTOS403IH102A);

			if (fe && adap->fe[1]) {
				/* attach tuner for 2nd FE */
@@ -961,24 +1057,31 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
						(0xc0 >> 1), &d->i2c_adap,
						DVB_PLL_SAMSUNG_DTOS403IH102A);
			}
		}

		break;
	case ANYSEE_HW_508TC: /* 18 */
	case ANYSEE_HW_508PTC: /* 21 */
	{
		/* E7 TC */
		/* E7 PTC */
		struct tda18212_config tda18212_config = anysee_tda18212_config;

		/* attach tuner */
		fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
				&anysee_tda18212_config);

		if (fe) {
			/* attach tuner for 2nd FE */
			fe = dvb_attach(tda18212_attach, adap->fe[1],
					&d->i2c_adap, &anysee_tda18212_config);
		tda18212_config.fe = adap->fe[0];
		ret = anysee_add_i2c_dev(d, "tda18212", 0x60, &tda18212_config);
		if (ret)
			goto err;

		/* copy tuner ops for 2nd FE as tuner is shared */
		if (adap->fe[1]) {
			adap->fe[1]->tuner_priv = adap->fe[0]->tuner_priv;
			memcpy(&adap->fe[1]->ops.tuner_ops,
					&adap->fe[0]->ops.tuner_ops,
					sizeof(struct dvb_tuner_ops));
		}

		break;
		return 0;
	}
	case ANYSEE_HW_508S2: /* 19 */
	case ANYSEE_HW_508PS2: /* 22 */
		/* E7 S2 */
@@ -997,13 +1100,18 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
		break;

	case ANYSEE_HW_508T2C: /* 20 */
	{
		/* E7 T2C */
		struct tda18212_config tda18212_config =
				anysee_tda18212_config2;

		/* attach tuner */
		fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
				&anysee_tda18212_config2);
		tda18212_config.fe = adap->fe[0];
		ret = anysee_add_i2c_dev(d, "tda18212", 0x60, &tda18212_config);
		if (ret)
			goto err;

		break;
		return 0;
	}
	default:
		fe = NULL;
	}
@@ -1012,7 +1120,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
		ret = 0;
	else
		ret = -ENODEV;

err:
	return ret;
}

@@ -1270,6 +1378,11 @@ static int anysee_init(struct dvb_usb_device *d)

static void anysee_exit(struct dvb_usb_device *d)
{
	struct anysee_state *state = d_to_priv(d);

	if (state->i2c_client[0])
		anysee_del_i2c_dev(d);

	return anysee_ci_release(d);
}

+3 −0
Original line number Diff line number Diff line
@@ -55,8 +55,11 @@ struct anysee_state {
	u8 buf[64];
	u8 seq;
	u8 hw; /* PCB ID */
	#define ANYSEE_I2C_CLIENT_MAX 1
	struct i2c_client *i2c_client[ANYSEE_I2C_CLIENT_MAX];
	u8 fe_id:1; /* frondend ID */
	u8 has_ci:1;
	u8 has_tda18212:1;
	u8 ci_attached:1;
	struct dvb_ca_en50221 ci;
	unsigned long ci_cam_ready; /* jiffies */