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

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

[media] ts2020: implement I2C client bindings



Implement I2C binding model.

Signed-off-by: default avatarAntti Palosaari <crope@iki.fi>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent abd9025b
Loading
Loading
Loading
Loading
+161 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#define FREQ_OFFSET_LOW_SYM_RATE 3000

struct ts2020_priv {
	struct dvb_frontend *fe;
	/* i2c details */
	int i2c_address;
	struct i2c_adapter *i2c;
@@ -428,6 +429,7 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe,
	priv->clk_out = config->clk_out;
	priv->clk_out_div = config->clk_out_div;
	priv->frequency_div = config->frequency_div;
	priv->fe = fe;
	fe->tuner_priv = priv;

	if (!priv->frequency_div)
@@ -463,6 +465,165 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe,
}
EXPORT_SYMBOL(ts2020_attach);

static int ts2020_probe(struct i2c_client *client,
		const struct i2c_device_id *id)
{
	struct ts2020_config *pdata = client->dev.platform_data;
	struct dvb_frontend *fe = pdata->fe;
	struct ts2020_priv *dev;
	int ret;
	u8 u8tmp;
	unsigned int utmp;
	char *chip_str;

	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (!dev) {
		ret = -ENOMEM;
		goto err;
	}

	dev->i2c = client->adapter;
	dev->i2c_address = client->addr;
	dev->clk_out = pdata->clk_out;
	dev->clk_out_div = pdata->clk_out_div;
	dev->frequency_div = pdata->frequency_div;
	dev->fe = fe;
	fe->tuner_priv = dev;

	/* check if the tuner is there */
	ret = ts2020_readreg(fe, 0x00);
	if (ret < 0)
		goto err;
	utmp = ret;

	if ((utmp & 0x03) == 0x00) {
		ret = ts2020_writereg(fe, 0x00, 0x01);
		if (ret)
			goto err;

		usleep_range(2000, 50000);
	}

	ret = ts2020_writereg(fe, 0x00, 0x03);
	if (ret)
		goto err;

	usleep_range(2000, 50000);

	ret = ts2020_readreg(fe, 0x00);
	if (ret < 0)
		goto err;
	utmp = ret;

	dev_dbg(&client->dev, "chip_id=%02x\n", utmp);

	switch (utmp) {
	case 0x01:
	case 0x41:
	case 0x81:
		dev->tuner = TS2020_M88TS2020;
		chip_str = "TS2020";
		if (!dev->frequency_div)
			dev->frequency_div = 1060000;
		break;
	case 0xc3:
	case 0x83:
		dev->tuner = TS2020_M88TS2022;
		chip_str = "TS2022";
		if (!dev->frequency_div)
			dev->frequency_div = 1103000;
		break;
	default:
		ret = -ENODEV;
		goto err;
	}

	if (dev->tuner == TS2020_M88TS2022) {
		switch (dev->clk_out) {
		case TS2020_CLK_OUT_DISABLED:
			u8tmp = 0x60;
			break;
		case TS2020_CLK_OUT_ENABLED:
			u8tmp = 0x70;
			ret = ts2020_writereg(fe, 0x05, dev->clk_out_div);
			if (ret)
				goto err;
			break;
		case TS2020_CLK_OUT_ENABLED_XTALOUT:
			u8tmp = 0x6c;
			break;
		default:
			ret = -EINVAL;
			goto err;
		}

		ret = ts2020_writereg(fe, 0x42, u8tmp);
		if (ret)
			goto err;

		if (dev->loop_through)
			u8tmp = 0xec;
		else
			u8tmp = 0x6c;

		ret = ts2020_writereg(fe, 0x62, u8tmp);
		if (ret)
			goto err;
	}

	/* sleep */
	ret = ts2020_writereg(fe, 0x00, 0x00);
	if (ret)
		goto err;

	dev_info(&client->dev,
		 "Montage Technology %s successfully identified\n", chip_str);

	memcpy(&fe->ops.tuner_ops, &ts2020_tuner_ops,
			sizeof(struct dvb_tuner_ops));
	fe->ops.tuner_ops.release = NULL;

	i2c_set_clientdata(client, dev);
	return 0;
err:
	dev_dbg(&client->dev, "failed=%d\n", ret);
	kfree(dev);
	return ret;
}

static int ts2020_remove(struct i2c_client *client)
{
	struct ts2020_priv *dev = i2c_get_clientdata(client);
	struct dvb_frontend *fe = dev->fe;

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

	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
	fe->tuner_priv = NULL;
	kfree(dev);

	return 0;
}

static const struct i2c_device_id ts2020_id_table[] = {
	{"ts2020", 0},
	{"ts2022", 0},
	{}
};
MODULE_DEVICE_TABLE(i2c, ts2020_id_table);

static struct i2c_driver ts2020_driver = {
	.driver = {
		.owner	= THIS_MODULE,
		.name	= "ts2020",
	},
	.probe		= ts2020_probe,
	.remove		= ts2020_remove,
	.id_table	= ts2020_id_table,
};

module_i2c_driver(ts2020_driver);

MODULE_AUTHOR("Konstantin Dimitrov <kosio.dimitrov@gmail.com>");
MODULE_DESCRIPTION("Montage Technology TS2020 - Silicon tuner driver module");
MODULE_LICENSE("GPL");