diff options
author | Antti Palosaari <crope@iki.fi> | 2015-03-24 00:26:55 +0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-04-03 04:24:03 +0300 |
commit | dc245a5f9b5163511e0c164c8aa47848f07b75a9 (patch) | |
tree | d0526e7d00fc06070d70ad640038949f20a087e9 /drivers/media/dvb-frontends/ts2020.c | |
parent | abd9025b95619c02f83583c9659298bc65dcdf50 (diff) | |
download | linux-dc245a5f9b5163511e0c164c8aa47848f07b75a9.tar.xz |
[media] ts2020: implement I2C client bindings
Implement I2C binding model.
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/media/dvb-frontends/ts2020.c')
-rw-r--r-- | drivers/media/dvb-frontends/ts2020.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c index 24c4712b77fe..b1d91dc46a47 100644 --- a/drivers/media/dvb-frontends/ts2020.c +++ b/drivers/media/dvb-frontends/ts2020.c @@ -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"); |