Commit 28fd31f8 authored by Antti Palosaari's avatar Antti Palosaari Committed by Mauro Carvalho Chehab

[media] e4000: convert DVB tuner to I2C driver model

Driver conversion from proprietary DVB tuner model to more
general I2C driver model.

Cc: Jean Delvare <khali@linux-fr.org>
Signed-off-by: default avatarAntti Palosaari <crope@iki.fi>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent 8ea5488a
...@@ -31,7 +31,7 @@ static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len) ...@@ -31,7 +31,7 @@ static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
u8 buf[MAX_XFER_SIZE]; u8 buf[MAX_XFER_SIZE];
struct i2c_msg msg[1] = { struct i2c_msg msg[1] = {
{ {
.addr = priv->cfg->i2c_addr, .addr = priv->client->addr,
.flags = 0, .flags = 0,
.len = 1 + len, .len = 1 + len,
.buf = buf, .buf = buf,
...@@ -39,7 +39,7 @@ static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len) ...@@ -39,7 +39,7 @@ static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
}; };
if (1 + len > sizeof(buf)) { if (1 + len > sizeof(buf)) {
dev_warn(&priv->i2c->dev, dev_warn(&priv->client->dev,
"%s: i2c wr reg=%04x: len=%d is too big!\n", "%s: i2c wr reg=%04x: len=%d is too big!\n",
KBUILD_MODNAME, reg, len); KBUILD_MODNAME, reg, len);
return -EINVAL; return -EINVAL;
...@@ -48,11 +48,11 @@ static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len) ...@@ -48,11 +48,11 @@ static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
buf[0] = reg; buf[0] = reg;
memcpy(&buf[1], val, len); memcpy(&buf[1], val, len);
ret = i2c_transfer(priv->i2c, msg, 1); ret = i2c_transfer(priv->client->adapter, msg, 1);
if (ret == 1) { if (ret == 1) {
ret = 0; ret = 0;
} else { } else {
dev_warn(&priv->i2c->dev, dev_warn(&priv->client->dev,
"%s: i2c wr failed=%d reg=%02x len=%d\n", "%s: i2c wr failed=%d reg=%02x len=%d\n",
KBUILD_MODNAME, ret, reg, len); KBUILD_MODNAME, ret, reg, len);
ret = -EREMOTEIO; ret = -EREMOTEIO;
...@@ -67,12 +67,12 @@ static int e4000_rd_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len) ...@@ -67,12 +67,12 @@ static int e4000_rd_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
u8 buf[MAX_XFER_SIZE]; u8 buf[MAX_XFER_SIZE];
struct i2c_msg msg[2] = { struct i2c_msg msg[2] = {
{ {
.addr = priv->cfg->i2c_addr, .addr = priv->client->addr,
.flags = 0, .flags = 0,
.len = 1, .len = 1,
.buf = &reg, .buf = &reg,
}, { }, {
.addr = priv->cfg->i2c_addr, .addr = priv->client->addr,
.flags = I2C_M_RD, .flags = I2C_M_RD,
.len = len, .len = len,
.buf = buf, .buf = buf,
...@@ -80,18 +80,18 @@ static int e4000_rd_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len) ...@@ -80,18 +80,18 @@ static int e4000_rd_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
}; };
if (len > sizeof(buf)) { if (len > sizeof(buf)) {
dev_warn(&priv->i2c->dev, dev_warn(&priv->client->dev,
"%s: i2c rd reg=%04x: len=%d is too big!\n", "%s: i2c rd reg=%04x: len=%d is too big!\n",
KBUILD_MODNAME, reg, len); KBUILD_MODNAME, reg, len);
return -EINVAL; return -EINVAL;
} }
ret = i2c_transfer(priv->i2c, msg, 2); ret = i2c_transfer(priv->client->adapter, msg, 2);
if (ret == 2) { if (ret == 2) {
memcpy(val, buf, len); memcpy(val, buf, len);
ret = 0; ret = 0;
} else { } else {
dev_warn(&priv->i2c->dev, dev_warn(&priv->client->dev,
"%s: i2c rd failed=%d reg=%02x len=%d\n", "%s: i2c rd failed=%d reg=%02x len=%d\n",
KBUILD_MODNAME, ret, reg, len); KBUILD_MODNAME, ret, reg, len);
ret = -EREMOTEIO; ret = -EREMOTEIO;
...@@ -117,7 +117,7 @@ static int e4000_init(struct dvb_frontend *fe) ...@@ -117,7 +117,7 @@ static int e4000_init(struct dvb_frontend *fe)
struct e4000_priv *priv = fe->tuner_priv; struct e4000_priv *priv = fe->tuner_priv;
int ret; int ret;
dev_dbg(&priv->i2c->dev, "%s:\n", __func__); dev_dbg(&priv->client->dev, "%s:\n", __func__);
if (fe->ops.i2c_gate_ctrl) if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1); fe->ops.i2c_gate_ctrl(fe, 1);
...@@ -186,7 +186,7 @@ static int e4000_init(struct dvb_frontend *fe) ...@@ -186,7 +186,7 @@ static int e4000_init(struct dvb_frontend *fe)
if (fe->ops.i2c_gate_ctrl) if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0); fe->ops.i2c_gate_ctrl(fe, 0);
dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
return ret; return ret;
} }
...@@ -195,7 +195,7 @@ static int e4000_sleep(struct dvb_frontend *fe) ...@@ -195,7 +195,7 @@ static int e4000_sleep(struct dvb_frontend *fe)
struct e4000_priv *priv = fe->tuner_priv; struct e4000_priv *priv = fe->tuner_priv;
int ret; int ret;
dev_dbg(&priv->i2c->dev, "%s:\n", __func__); dev_dbg(&priv->client->dev, "%s:\n", __func__);
if (fe->ops.i2c_gate_ctrl) if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1); fe->ops.i2c_gate_ctrl(fe, 1);
...@@ -212,7 +212,7 @@ static int e4000_sleep(struct dvb_frontend *fe) ...@@ -212,7 +212,7 @@ static int e4000_sleep(struct dvb_frontend *fe)
if (fe->ops.i2c_gate_ctrl) if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0); fe->ops.i2c_gate_ctrl(fe, 0);
dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
return ret; return ret;
} }
...@@ -224,7 +224,7 @@ static int e4000_set_params(struct dvb_frontend *fe) ...@@ -224,7 +224,7 @@ static int e4000_set_params(struct dvb_frontend *fe)
unsigned int f_vco; unsigned int f_vco;
u8 buf[5], i_data[4], q_data[4]; u8 buf[5], i_data[4], q_data[4];
dev_dbg(&priv->i2c->dev, dev_dbg(&priv->client->dev,
"%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", "%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n",
__func__, c->delivery_system, c->frequency, __func__, c->delivery_system, c->frequency,
c->bandwidth_hz); c->bandwidth_hz);
...@@ -253,14 +253,15 @@ static int e4000_set_params(struct dvb_frontend *fe) ...@@ -253,14 +253,15 @@ static int e4000_set_params(struct dvb_frontend *fe)
* or more. * or more.
*/ */
f_vco = c->frequency * e4000_pll_lut[i].mul; f_vco = c->frequency * e4000_pll_lut[i].mul;
sigma_delta = div_u64(0x10000ULL * (f_vco % priv->cfg->clock), priv->cfg->clock); sigma_delta = div_u64(0x10000ULL * (f_vco % priv->clock), priv->clock);
buf[0] = f_vco / priv->cfg->clock; buf[0] = f_vco / priv->clock;
buf[1] = (sigma_delta >> 0) & 0xff; buf[1] = (sigma_delta >> 0) & 0xff;
buf[2] = (sigma_delta >> 8) & 0xff; buf[2] = (sigma_delta >> 8) & 0xff;
buf[3] = 0x00; buf[3] = 0x00;
buf[4] = e4000_pll_lut[i].div; buf[4] = e4000_pll_lut[i].div;
dev_dbg(&priv->i2c->dev, "%s: f_vco=%u pll div=%d sigma_delta=%04x\n", dev_dbg(&priv->client->dev,
"%s: f_vco=%u pll div=%d sigma_delta=%04x\n",
__func__, f_vco, buf[0], sigma_delta); __func__, f_vco, buf[0], sigma_delta);
ret = e4000_wr_regs(priv, 0x09, buf, 5); ret = e4000_wr_regs(priv, 0x09, buf, 5);
...@@ -369,7 +370,7 @@ static int e4000_set_params(struct dvb_frontend *fe) ...@@ -369,7 +370,7 @@ static int e4000_set_params(struct dvb_frontend *fe)
if (fe->ops.i2c_gate_ctrl) if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0); fe->ops.i2c_gate_ctrl(fe, 0);
dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
return ret; return ret;
} }
...@@ -377,24 +378,13 @@ static int e4000_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) ...@@ -377,24 +378,13 @@ static int e4000_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
{ {
struct e4000_priv *priv = fe->tuner_priv; struct e4000_priv *priv = fe->tuner_priv;
dev_dbg(&priv->i2c->dev, "%s:\n", __func__); dev_dbg(&priv->client->dev, "%s:\n", __func__);
*frequency = 0; /* Zero-IF */ *frequency = 0; /* Zero-IF */
return 0; return 0;
} }
static int e4000_release(struct dvb_frontend *fe)
{
struct e4000_priv *priv = fe->tuner_priv;
dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
kfree(fe->tuner_priv);
return 0;
}
static const struct dvb_tuner_ops e4000_tuner_ops = { static const struct dvb_tuner_ops e4000_tuner_ops = {
.info = { .info = {
.name = "Elonics E4000", .name = "Elonics E4000",
...@@ -402,8 +392,6 @@ static const struct dvb_tuner_ops e4000_tuner_ops = { ...@@ -402,8 +392,6 @@ static const struct dvb_tuner_ops e4000_tuner_ops = {
.frequency_max = 862000000, .frequency_max = 862000000,
}, },
.release = e4000_release,
.init = e4000_init, .init = e4000_init,
.sleep = e4000_sleep, .sleep = e4000_sleep,
.set_params = e4000_set_params, .set_params = e4000_set_params,
...@@ -411,9 +399,11 @@ static const struct dvb_tuner_ops e4000_tuner_ops = { ...@@ -411,9 +399,11 @@ static const struct dvb_tuner_ops e4000_tuner_ops = {
.get_if_frequency = e4000_get_if_frequency, .get_if_frequency = e4000_get_if_frequency,
}; };
struct dvb_frontend *e4000_attach(struct dvb_frontend *fe, static int e4000_probe(struct i2c_client *client,
struct i2c_adapter *i2c, const struct e4000_config *cfg) const struct i2c_device_id *id)
{ {
struct e4000_config *cfg = client->dev.platform_data;
struct dvb_frontend *fe = cfg->fe;
struct e4000_priv *priv; struct e4000_priv *priv;
int ret; int ret;
u8 chip_id; u8 chip_id;
...@@ -424,29 +414,33 @@ struct dvb_frontend *e4000_attach(struct dvb_frontend *fe, ...@@ -424,29 +414,33 @@ struct dvb_frontend *e4000_attach(struct dvb_frontend *fe,
priv = kzalloc(sizeof(struct e4000_priv), GFP_KERNEL); priv = kzalloc(sizeof(struct e4000_priv), GFP_KERNEL);
if (!priv) { if (!priv) {
ret = -ENOMEM; ret = -ENOMEM;
dev_err(&i2c->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
goto err; goto err;
} }
priv->cfg = cfg; priv->clock = cfg->clock;
priv->i2c = i2c; priv->client = client;
priv->fe = cfg->fe;
/* check if the tuner is there */ /* check if the tuner is there */
ret = e4000_rd_reg(priv, 0x02, &chip_id); ret = e4000_rd_reg(priv, 0x02, &chip_id);
if (ret < 0) if (ret < 0)
goto err; goto err;
dev_dbg(&priv->i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id); dev_dbg(&priv->client->dev,
"%s: chip_id=%02x\n", __func__, chip_id);
if (chip_id != 0x40) if (chip_id != 0x40) {
ret = -ENODEV;
goto err; goto err;
}
/* put sleep as chip seems to be in normal mode by default */ /* put sleep as chip seems to be in normal mode by default */
ret = e4000_wr_reg(priv, 0x00, 0x00); ret = e4000_wr_reg(priv, 0x00, 0x00);
if (ret < 0) if (ret < 0)
goto err; goto err;
dev_info(&priv->i2c->dev, dev_info(&priv->client->dev,
"%s: Elonics E4000 successfully identified\n", "%s: Elonics E4000 successfully identified\n",
KBUILD_MODNAME); KBUILD_MODNAME);
...@@ -457,16 +451,49 @@ struct dvb_frontend *e4000_attach(struct dvb_frontend *fe, ...@@ -457,16 +451,49 @@ struct dvb_frontend *e4000_attach(struct dvb_frontend *fe,
if (fe->ops.i2c_gate_ctrl) if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0); fe->ops.i2c_gate_ctrl(fe, 0);
return fe; i2c_set_clientdata(client, priv);
return 0;
err: err:
if (fe->ops.i2c_gate_ctrl) if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0); fe->ops.i2c_gate_ctrl(fe, 0);
dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
kfree(priv); kfree(priv);
return NULL; return ret;
} }
EXPORT_SYMBOL(e4000_attach);
static int e4000_remove(struct i2c_client *client)
{
struct e4000_priv *priv = i2c_get_clientdata(client);
struct dvb_frontend *fe = priv->fe;
dev_dbg(&client->dev, "%s:\n", __func__);
memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
fe->tuner_priv = NULL;
kfree(priv);
return 0;
}
static const struct i2c_device_id e4000_id[] = {
{"e4000", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, e4000_id);
static struct i2c_driver e4000_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "e4000",
},
.probe = e4000_probe,
.remove = e4000_remove,
.id_table = e4000_id,
};
module_i2c_driver(e4000_driver);
MODULE_DESCRIPTION("Elonics E4000 silicon tuner driver"); MODULE_DESCRIPTION("Elonics E4000 silicon tuner driver");
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
......
...@@ -24,12 +24,15 @@ ...@@ -24,12 +24,15 @@
#include <linux/kconfig.h> #include <linux/kconfig.h>
#include "dvb_frontend.h" #include "dvb_frontend.h"
/*
* I2C address
* 0x64, 0x65, 0x66, 0x67
*/
struct e4000_config { struct e4000_config {
/* /*
* I2C address * frontend
* 0x64, 0x65, 0x66, 0x67
*/ */
u8 i2c_addr; struct dvb_frontend *fe;
/* /*
* clock * clock
...@@ -37,16 +40,4 @@ struct e4000_config { ...@@ -37,16 +40,4 @@ struct e4000_config {
u32 clock; u32 clock;
}; };
#if IS_ENABLED(CONFIG_MEDIA_TUNER_E4000)
extern struct dvb_frontend *e4000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, const struct e4000_config *cfg);
#else
static inline struct dvb_frontend *e4000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, const struct e4000_config *cfg)
{
dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif
#endif #endif
...@@ -24,8 +24,9 @@ ...@@ -24,8 +24,9 @@
#include "e4000.h" #include "e4000.h"
struct e4000_priv { struct e4000_priv {
const struct e4000_config *cfg; struct i2c_client *client;
struct i2c_adapter *i2c; u32 clock;
struct dvb_frontend *fe;
}; };
struct e4000_pll { struct e4000_pll {
......
...@@ -852,11 +852,6 @@ static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap) ...@@ -852,11 +852,6 @@ static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap)
return ret; return ret;
} }
static const struct e4000_config rtl2832u_e4000_config = {
.i2c_addr = 0x64,
.clock = 28800000,
};
static const struct fc2580_config rtl2832u_fc2580_config = { static const struct fc2580_config rtl2832u_fc2580_config = {
.i2c_addr = 0x56, .i2c_addr = 0x56,
.clock = 16384000, .clock = 16384000,
...@@ -890,10 +885,14 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) ...@@ -890,10 +885,14 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
int ret; int ret;
struct dvb_usb_device *d = adap_to_d(adap); struct dvb_usb_device *d = adap_to_d(adap);
struct rtl28xxu_priv *priv = d_to_priv(d); struct rtl28xxu_priv *priv = d_to_priv(d);
struct dvb_frontend *fe; struct dvb_frontend *fe = NULL;
struct i2c_board_info info;
struct i2c_client *client;
dev_dbg(&d->udev->dev, "%s:\n", __func__); dev_dbg(&d->udev->dev, "%s:\n", __func__);
memset(&info, 0, sizeof(struct i2c_board_info));
switch (priv->tuner) { switch (priv->tuner) {
case TUNER_RTL2832_FC0012: case TUNER_RTL2832_FC0012:
fe = dvb_attach(fc0012_attach, adap->fe[0], fe = dvb_attach(fc0012_attach, adap->fe[0],
...@@ -913,9 +912,28 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) ...@@ -913,9 +912,28 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
adap->fe[0]->ops.read_signal_strength = adap->fe[0]->ops.read_signal_strength =
adap->fe[0]->ops.tuner_ops.get_rf_strength; adap->fe[0]->ops.tuner_ops.get_rf_strength;
return 0; return 0;
case TUNER_RTL2832_E4000: case TUNER_RTL2832_E4000: {
fe = dvb_attach(e4000_attach, adap->fe[0], &d->i2c_adap, struct e4000_config e4000_config = {
&rtl2832u_e4000_config); .fe = adap->fe[0],
.clock = 28800000,
};
strlcpy(info.type, "e4000", I2C_NAME_SIZE);
info.addr = 0x64;
info.platform_data = &e4000_config;
request_module(info.type);
client = i2c_new_device(&d->i2c_adap, &info);
if (client == NULL || client->dev.driver == NULL)
break;
if (!try_module_get(client->dev.driver->owner)) {
i2c_unregister_device(client);
break;
}
priv->client = client;
}
break; break;
case TUNER_RTL2832_FC2580: case TUNER_RTL2832_FC2580:
fe = dvb_attach(fc2580_attach, adap->fe[0], &d->i2c_adap, fe = dvb_attach(fc2580_attach, adap->fe[0], &d->i2c_adap,
...@@ -964,12 +982,11 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) ...@@ -964,12 +982,11 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
adap->fe[0]->ops.tuner_ops.get_rf_strength; adap->fe[0]->ops.tuner_ops.get_rf_strength;
break; break;
default: default:
fe = NULL;
dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME, dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME,
priv->tuner); priv->tuner);
} }
if (fe == NULL) { if (fe == NULL && priv->client == NULL) {
ret = -ENODEV; ret = -ENODEV;
goto err; goto err;
} }
...@@ -1014,6 +1031,22 @@ static int rtl28xxu_init(struct dvb_usb_device *d) ...@@ -1014,6 +1031,22 @@ static int rtl28xxu_init(struct dvb_usb_device *d)
return ret; return ret;
} }
static void rtl28xxu_exit(struct dvb_usb_device *d)
{
struct rtl28xxu_priv *priv = d->priv;
struct i2c_client *client = priv->client;
dev_dbg(&d->udev->dev, "%s:\n", __func__);
/* remove I2C tuner */
if (client) {
module_put(client->dev.driver->owner);
i2c_unregister_device(client);
}
return;
}
static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff) static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
{ {
int ret; int ret;
...@@ -1376,6 +1409,7 @@ static const struct dvb_usb_device_properties rtl2832u_props = { ...@@ -1376,6 +1409,7 @@ static const struct dvb_usb_device_properties rtl2832u_props = {
.frontend_attach = rtl2832u_frontend_attach, .frontend_attach = rtl2832u_frontend_attach,
.tuner_attach = rtl2832u_tuner_attach, .tuner_attach = rtl2832u_tuner_attach,
.init = rtl28xxu_init, .init = rtl28xxu_init,
.exit = rtl28xxu_exit,
.get_rc_config = rtl2832u_get_rc_config, .get_rc_config = rtl2832u_get_rc_config,
.num_adapters = 1, .num_adapters = 1,
......
...@@ -56,6 +56,7 @@ struct rtl28xxu_priv { ...@@ -56,6 +56,7 @@ struct rtl28xxu_priv {
char *tuner_name; char *tuner_name;
u8 page; /* integrated demod active register page */ u8 page; /* integrated demod active register page */
bool rc_active; bool rc_active;
struct i2c_client *client;
}; };
enum rtl28xxu_chip_id { enum rtl28xxu_chip_id {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment