* [PATCH 01/17] e4000: convert DVB tuner to I2C driver model
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
2014-03-14 0:14 ` [PATCH 02/17] e4000: implement controls via v4l2 control framework Antti Palosaari
` (15 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media
Cc: Hans Verkuil, Mauro Carvalho Chehab, Antti Palosaari,
Jean Delvare
Driver conversion from proprietary DVB tuner model to more
general I2C driver model.
Cc: Jean Delvare <khali@linux-fr.org>
Cc: Mauro Carvalho Chehab <m.chehab@samsung.com>
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/media/tuners/e4000.c | 115 ++++++++++++++++++++------------
drivers/media/tuners/e4000.h | 21 ++----
drivers/media/tuners/e4000_priv.h | 5 +-
drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 56 +++++++++++++---
drivers/media/usb/dvb-usb-v2/rtl28xxu.h | 1 +
5 files changed, 126 insertions(+), 72 deletions(-)
diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c
index 40c1da7..0153169 100644
--- a/drivers/media/tuners/e4000.c
+++ b/drivers/media/tuners/e4000.c
@@ -31,7 +31,7 @@ static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
u8 buf[MAX_XFER_SIZE];
struct i2c_msg msg[1] = {
{
- .addr = priv->cfg->i2c_addr,
+ .addr = priv->client->addr,
.flags = 0,
.len = 1 + len,
.buf = buf,
@@ -39,7 +39,7 @@ static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
};
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",
KBUILD_MODNAME, reg, len);
return -EINVAL;
@@ -48,11 +48,11 @@ static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
buf[0] = reg;
memcpy(&buf[1], val, len);
- ret = i2c_transfer(priv->i2c, msg, 1);
+ ret = i2c_transfer(priv->client->adapter, msg, 1);
if (ret == 1) {
ret = 0;
} else {
- dev_warn(&priv->i2c->dev,
+ dev_warn(&priv->client->dev,
"%s: i2c wr failed=%d reg=%02x len=%d\n",
KBUILD_MODNAME, ret, reg, len);
ret = -EREMOTEIO;
@@ -67,12 +67,12 @@ static int e4000_rd_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
u8 buf[MAX_XFER_SIZE];
struct i2c_msg msg[2] = {
{
- .addr = priv->cfg->i2c_addr,
+ .addr = priv->client->addr,
.flags = 0,
.len = 1,
.buf = ®,
}, {
- .addr = priv->cfg->i2c_addr,
+ .addr = priv->client->addr,
.flags = I2C_M_RD,
.len = len,
.buf = buf,
@@ -80,18 +80,18 @@ static int e4000_rd_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
};
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",
KBUILD_MODNAME, reg, len);
return -EINVAL;
}
- ret = i2c_transfer(priv->i2c, msg, 2);
+ ret = i2c_transfer(priv->client->adapter, msg, 2);
if (ret == 2) {
memcpy(val, buf, len);
ret = 0;
} else {
- dev_warn(&priv->i2c->dev,
+ dev_warn(&priv->client->dev,
"%s: i2c rd failed=%d reg=%02x len=%d\n",
KBUILD_MODNAME, ret, reg, len);
ret = -EREMOTEIO;
@@ -117,7 +117,7 @@ static int e4000_init(struct dvb_frontend *fe)
struct e4000_priv *priv = fe->tuner_priv;
int ret;
- dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
+ dev_dbg(&priv->client->dev, "%s:\n", __func__);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
@@ -186,7 +186,7 @@ err:
if (fe->ops.i2c_gate_ctrl)
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;
}
@@ -195,7 +195,7 @@ static int e4000_sleep(struct dvb_frontend *fe)
struct e4000_priv *priv = fe->tuner_priv;
int ret;
- dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
+ dev_dbg(&priv->client->dev, "%s:\n", __func__);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
@@ -212,7 +212,7 @@ err:
if (fe->ops.i2c_gate_ctrl)
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;
}
@@ -224,7 +224,7 @@ static int e4000_set_params(struct dvb_frontend *fe)
unsigned int f_vco;
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",
__func__, c->delivery_system, c->frequency,
c->bandwidth_hz);
@@ -253,14 +253,15 @@ static int e4000_set_params(struct dvb_frontend *fe)
* or more.
*/
f_vco = c->frequency * e4000_pll_lut[i].mul;
- sigma_delta = div_u64(0x10000ULL * (f_vco % priv->cfg->clock), priv->cfg->clock);
- buf[0] = f_vco / priv->cfg->clock;
+ sigma_delta = div_u64(0x10000ULL * (f_vco % priv->clock), priv->clock);
+ buf[0] = f_vco / priv->clock;
buf[1] = (sigma_delta >> 0) & 0xff;
buf[2] = (sigma_delta >> 8) & 0xff;
buf[3] = 0x00;
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);
ret = e4000_wr_regs(priv, 0x09, buf, 5);
@@ -369,7 +370,7 @@ err:
if (fe->ops.i2c_gate_ctrl)
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;
}
@@ -377,24 +378,13 @@ static int e4000_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
{
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 */
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 = {
.info = {
.name = "Elonics E4000",
@@ -402,8 +392,6 @@ static const struct dvb_tuner_ops e4000_tuner_ops = {
.frequency_max = 862000000,
},
- .release = e4000_release,
-
.init = e4000_init,
.sleep = e4000_sleep,
.set_params = e4000_set_params,
@@ -411,9 +399,11 @@ static const struct dvb_tuner_ops e4000_tuner_ops = {
.get_if_frequency = e4000_get_if_frequency,
};
-struct dvb_frontend *e4000_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c, const struct e4000_config *cfg)
+static int e4000_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
+ struct e4000_config *cfg = client->dev.platform_data;
+ struct dvb_frontend *fe = cfg->fe;
struct e4000_priv *priv;
int ret;
u8 chip_id;
@@ -424,29 +414,33 @@ struct dvb_frontend *e4000_attach(struct dvb_frontend *fe,
priv = kzalloc(sizeof(struct e4000_priv), GFP_KERNEL);
if (!priv) {
ret = -ENOMEM;
- dev_err(&i2c->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+ dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
goto err;
}
- priv->cfg = cfg;
- priv->i2c = i2c;
+ priv->clock = cfg->clock;
+ priv->client = client;
+ priv->fe = cfg->fe;
/* check if the tuner is there */
ret = e4000_rd_reg(priv, 0x02, &chip_id);
if (ret < 0)
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;
+ }
/* put sleep as chip seems to be in normal mode by default */
ret = e4000_wr_reg(priv, 0x00, 0x00);
if (ret < 0)
goto err;
- dev_info(&priv->i2c->dev,
+ dev_info(&priv->client->dev,
"%s: Elonics E4000 successfully identified\n",
KBUILD_MODNAME);
@@ -457,16 +451,49 @@ struct dvb_frontend *e4000_attach(struct dvb_frontend *fe,
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
- return fe;
+ i2c_set_clientdata(client, priv);
+
+ return 0;
err:
if (fe->ops.i2c_gate_ctrl)
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);
- 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_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/tuners/e4000.h b/drivers/media/tuners/e4000.h
index 25ee7c0..e74b8b2 100644
--- a/drivers/media/tuners/e4000.h
+++ b/drivers/media/tuners/e4000.h
@@ -24,12 +24,15 @@
#include <linux/kconfig.h>
#include "dvb_frontend.h"
+/*
+ * I2C address
+ * 0x64, 0x65, 0x66, 0x67
+ */
struct e4000_config {
/*
- * I2C address
- * 0x64, 0x65, 0x66, 0x67
+ * frontend
*/
- u8 i2c_addr;
+ struct dvb_frontend *fe;
/*
* clock
@@ -37,16 +40,4 @@ struct e4000_config {
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
diff --git a/drivers/media/tuners/e4000_priv.h b/drivers/media/tuners/e4000_priv.h
index a385505..8f45a30 100644
--- a/drivers/media/tuners/e4000_priv.h
+++ b/drivers/media/tuners/e4000_priv.h
@@ -24,8 +24,9 @@
#include "e4000.h"
struct e4000_priv {
- const struct e4000_config *cfg;
- struct i2c_adapter *i2c;
+ struct i2c_client *client;
+ u32 clock;
+ struct dvb_frontend *fe;
};
struct e4000_pll {
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index e9294dc..ae07740 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -852,11 +852,6 @@ err:
return ret;
}
-static const struct e4000_config rtl2832u_e4000_config = {
- .i2c_addr = 0x64,
- .clock = 28800000,
-};
-
static const struct fc2580_config rtl2832u_fc2580_config = {
.i2c_addr = 0x56,
.clock = 16384000,
@@ -890,10 +885,14 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
int ret;
struct dvb_usb_device *d = adap_to_d(adap);
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__);
+ memset(&info, 0, sizeof(struct i2c_board_info));
+
switch (priv->tuner) {
case TUNER_RTL2832_FC0012:
fe = dvb_attach(fc0012_attach, adap->fe[0],
@@ -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.tuner_ops.get_rf_strength;
return 0;
- case TUNER_RTL2832_E4000:
- fe = dvb_attach(e4000_attach, adap->fe[0], &d->i2c_adap,
- &rtl2832u_e4000_config);
+ case TUNER_RTL2832_E4000: {
+ struct e4000_config 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;
case TUNER_RTL2832_FC2580:
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)
adap->fe[0]->ops.tuner_ops.get_rf_strength;
break;
default:
- fe = NULL;
dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME,
priv->tuner);
}
- if (fe == NULL) {
+ if (fe == NULL && priv->client == NULL) {
ret = -ENODEV;
goto err;
}
@@ -1014,6 +1031,22 @@ err:
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)
{
int ret;
@@ -1376,6 +1409,7 @@ static const struct dvb_usb_device_properties rtl2832u_props = {
.frontend_attach = rtl2832u_frontend_attach,
.tuner_attach = rtl2832u_tuner_attach,
.init = rtl28xxu_init,
+ .exit = rtl28xxu_exit,
.get_rc_config = rtl2832u_get_rc_config,
.num_adapters = 1,
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
index 2142bcb..367aca1 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
@@ -56,6 +56,7 @@ struct rtl28xxu_priv {
char *tuner_name;
u8 page; /* integrated demod active register page */
bool rc_active;
+ struct i2c_client *client;
};
enum rtl28xxu_chip_id {
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 02/17] e4000: implement controls via v4l2 control framework
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
2014-03-14 0:14 ` [PATCH 01/17] e4000: convert DVB tuner to I2C driver model Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
2014-03-14 0:14 ` [PATCH 03/17] e4000: fix PLL calc to allow higher frequencies Antti Palosaari
` (14 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Mauro Carvalho Chehab, Antti Palosaari
Implement gain and bandwidth controls using v4l2 control framework.
Cc: Mauro Carvalho Chehab <m.chehab@samsung.com>
Cc: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/media/tuners/Kconfig | 2 +-
drivers/media/tuners/e4000.c | 217 +++++++++++++++++++++++++++++++++++++-
drivers/media/tuners/e4000_priv.h | 77 ++++++++++++++
3 files changed, 291 insertions(+), 5 deletions(-)
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
index ba2e365..3b95392 100644
--- a/drivers/media/tuners/Kconfig
+++ b/drivers/media/tuners/Kconfig
@@ -203,7 +203,7 @@ config MEDIA_TUNER_TDA18212
config MEDIA_TUNER_E4000
tristate "Elonics E4000 silicon tuner"
- depends on MEDIA_SUPPORT && I2C
+ depends on MEDIA_SUPPORT && I2C && VIDEO_V4L2
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Elonics E4000 silicon tuner driver.
diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c
index 0153169..3a03b02 100644
--- a/drivers/media/tuners/e4000.c
+++ b/drivers/media/tuners/e4000.c
@@ -385,6 +385,178 @@ static int e4000_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
return 0;
}
+static int e4000_set_lna_gain(struct dvb_frontend *fe)
+{
+ struct e4000_priv *priv = fe->tuner_priv;
+ int ret;
+ u8 u8tmp;
+ dev_dbg(&priv->client->dev, "%s: lna auto=%d->%d val=%d->%d\n",
+ __func__, priv->lna_gain_auto->cur.val,
+ priv->lna_gain_auto->val, priv->lna_gain->cur.val,
+ priv->lna_gain->val);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (priv->lna_gain_auto->val && priv->if_gain_auto->cur.val)
+ u8tmp = 0x17;
+ else if (priv->lna_gain_auto->val)
+ u8tmp = 0x19;
+ else if (priv->if_gain_auto->cur.val)
+ u8tmp = 0x16;
+ else
+ u8tmp = 0x10;
+
+ ret = e4000_wr_reg(priv, 0x1a, u8tmp);
+ if (ret)
+ goto err;
+
+ if (priv->lna_gain_auto->val == false) {
+ ret = e4000_wr_reg(priv, 0x14, priv->lna_gain->val);
+ if (ret)
+ goto err;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return 0;
+err:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int e4000_set_mixer_gain(struct dvb_frontend *fe)
+{
+ struct e4000_priv *priv = fe->tuner_priv;
+ int ret;
+ u8 u8tmp;
+ dev_dbg(&priv->client->dev, "%s: mixer auto=%d->%d val=%d->%d\n",
+ __func__, priv->mixer_gain_auto->cur.val,
+ priv->mixer_gain_auto->val, priv->mixer_gain->cur.val,
+ priv->mixer_gain->val);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (priv->mixer_gain_auto->val)
+ u8tmp = 0x15;
+ else
+ u8tmp = 0x14;
+
+ ret = e4000_wr_reg(priv, 0x20, u8tmp);
+ if (ret)
+ goto err;
+
+ if (priv->mixer_gain_auto->val == false) {
+ ret = e4000_wr_reg(priv, 0x15, priv->mixer_gain->val);
+ if (ret)
+ goto err;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return 0;
+err:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int e4000_set_if_gain(struct dvb_frontend *fe)
+{
+ struct e4000_priv *priv = fe->tuner_priv;
+ int ret;
+ u8 buf[2];
+ u8 u8tmp;
+ dev_dbg(&priv->client->dev, "%s: if auto=%d->%d val=%d->%d\n",
+ __func__, priv->if_gain_auto->cur.val,
+ priv->if_gain_auto->val, priv->if_gain->cur.val,
+ priv->if_gain->val);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (priv->if_gain_auto->val && priv->lna_gain_auto->cur.val)
+ u8tmp = 0x17;
+ else if (priv->lna_gain_auto->cur.val)
+ u8tmp = 0x19;
+ else if (priv->if_gain_auto->val)
+ u8tmp = 0x16;
+ else
+ u8tmp = 0x10;
+
+ ret = e4000_wr_reg(priv, 0x1a, u8tmp);
+ if (ret)
+ goto err;
+
+ if (priv->if_gain_auto->val == false) {
+ buf[0] = e4000_if_gain_lut[priv->if_gain->val].reg16_val;
+ buf[1] = e4000_if_gain_lut[priv->if_gain->val].reg17_val;
+ ret = e4000_wr_regs(priv, 0x16, buf, 2);
+ if (ret)
+ goto err;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return 0;
+err:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int e4000_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct e4000_priv *priv =
+ container_of(ctrl->handler, struct e4000_priv, hdl);
+ struct dvb_frontend *fe = priv->fe;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ dev_dbg(&priv->client->dev,
+ "%s: id=%d name=%s val=%d min=%d max=%d step=%d\n",
+ __func__, ctrl->id, ctrl->name, ctrl->val,
+ ctrl->minimum, ctrl->maximum, ctrl->step);
+
+ switch (ctrl->id) {
+ case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
+ case V4L2_CID_RF_TUNER_BANDWIDTH:
+ c->bandwidth_hz = priv->bandwidth->val;
+ ret = e4000_set_params(priv->fe);
+ break;
+ case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO:
+ case V4L2_CID_RF_TUNER_LNA_GAIN:
+ ret = e4000_set_lna_gain(priv->fe);
+ break;
+ case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO:
+ case V4L2_CID_RF_TUNER_MIXER_GAIN:
+ ret = e4000_set_mixer_gain(priv->fe);
+ break;
+ case V4L2_CID_RF_TUNER_IF_GAIN_AUTO:
+ case V4L2_CID_RF_TUNER_IF_GAIN:
+ ret = e4000_set_if_gain(priv->fe);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops e4000_ctrl_ops = {
+ .s_ctrl = e4000_s_ctrl,
+};
+
static const struct dvb_tuner_ops e4000_tuner_ops = {
.info = {
.name = "Elonics E4000",
@@ -399,6 +571,10 @@ static const struct dvb_tuner_ops e4000_tuner_ops = {
.get_if_frequency = e4000_get_if_frequency,
};
+/*
+ * Use V4L2 subdev to carry V4L2 control handler, even we don't implement
+ * subdev itself, just to avoid reinventing the wheel.
+ */
static int e4000_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -440,6 +616,37 @@ static int e4000_probe(struct i2c_client *client,
if (ret < 0)
goto err;
+ /* Register controls */
+ v4l2_ctrl_handler_init(&priv->hdl, 8);
+ priv->bandwidth_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
+ priv->bandwidth = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_BANDWIDTH, 4300000, 11000000, 100000, 4300000);
+ v4l2_ctrl_auto_cluster(2, &priv->bandwidth_auto, 0, false);
+ priv->lna_gain_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_LNA_GAIN_AUTO, 0, 1, 1, 1);
+ priv->lna_gain = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_LNA_GAIN, 0, 15, 1, 10);
+ v4l2_ctrl_auto_cluster(2, &priv->lna_gain_auto, 0, false);
+ priv->mixer_gain_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO, 0, 1, 1, 1);
+ priv->mixer_gain = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_MIXER_GAIN, 0, 1, 1, 1);
+ v4l2_ctrl_auto_cluster(2, &priv->mixer_gain_auto, 0, false);
+ priv->if_gain_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_IF_GAIN_AUTO, 0, 1, 1, 1);
+ priv->if_gain = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_IF_GAIN, 0, 54, 1, 0);
+ v4l2_ctrl_auto_cluster(2, &priv->if_gain_auto, 0, false);
+ if (priv->hdl.error) {
+ ret = priv->hdl.error;
+ dev_err(&priv->client->dev, "Could not initialize controls\n");
+ v4l2_ctrl_handler_free(&priv->hdl);
+ goto err;
+ }
+
+ priv->sd.ctrl_handler = &priv->hdl;
+
dev_info(&priv->client->dev,
"%s: Elonics E4000 successfully identified\n",
KBUILD_MODNAME);
@@ -448,11 +655,12 @@ static int e4000_probe(struct i2c_client *client,
memcpy(&fe->ops.tuner_ops, &e4000_tuner_ops,
sizeof(struct dvb_tuner_ops));
+ v4l2_set_subdevdata(&priv->sd, client);
+ i2c_set_clientdata(client, &priv->sd);
+
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
- i2c_set_clientdata(client, priv);
-
return 0;
err:
if (fe->ops.i2c_gate_ctrl)
@@ -465,11 +673,12 @@ err:
static int e4000_remove(struct i2c_client *client)
{
- struct e4000_priv *priv = i2c_get_clientdata(client);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct e4000_priv *priv = container_of(sd, struct e4000_priv, sd);
struct dvb_frontend *fe = priv->fe;
dev_dbg(&client->dev, "%s:\n", __func__);
-
+ v4l2_ctrl_handler_free(&priv->hdl);
memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
fe->tuner_priv = NULL;
kfree(priv);
diff --git a/drivers/media/tuners/e4000_priv.h b/drivers/media/tuners/e4000_priv.h
index 8f45a30..e2ad54f 100644
--- a/drivers/media/tuners/e4000_priv.h
+++ b/drivers/media/tuners/e4000_priv.h
@@ -22,11 +22,25 @@
#define E4000_PRIV_H
#include "e4000.h"
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
struct e4000_priv {
struct i2c_client *client;
u32 clock;
struct dvb_frontend *fe;
+ struct v4l2_subdev sd;
+
+ /* Controls */
+ struct v4l2_ctrl_handler hdl;
+ struct v4l2_ctrl *bandwidth_auto;
+ struct v4l2_ctrl *bandwidth;
+ struct v4l2_ctrl *lna_gain_auto;
+ struct v4l2_ctrl *lna_gain;
+ struct v4l2_ctrl *mixer_gain_auto;
+ struct v4l2_ctrl *mixer_gain;
+ struct v4l2_ctrl *if_gain_auto;
+ struct v4l2_ctrl *if_gain;
};
struct e4000_pll {
@@ -145,4 +159,67 @@ static const struct e4000_if_filter e4000_if_filter_lut[] = {
{ 0xffffffff, 0x00, 0x20 },
};
+struct e4000_if_gain {
+ u8 reg16_val;
+ u8 reg17_val;
+};
+
+static const struct e4000_if_gain e4000_if_gain_lut[] = {
+ {0x00, 0x00},
+ {0x20, 0x00},
+ {0x40, 0x00},
+ {0x02, 0x00},
+ {0x22, 0x00},
+ {0x42, 0x00},
+ {0x04, 0x00},
+ {0x24, 0x00},
+ {0x44, 0x00},
+ {0x01, 0x00},
+ {0x21, 0x00},
+ {0x41, 0x00},
+ {0x03, 0x00},
+ {0x23, 0x00},
+ {0x43, 0x00},
+ {0x05, 0x00},
+ {0x25, 0x00},
+ {0x45, 0x00},
+ {0x07, 0x00},
+ {0x27, 0x00},
+ {0x47, 0x00},
+ {0x0f, 0x00},
+ {0x2f, 0x00},
+ {0x4f, 0x00},
+ {0x17, 0x00},
+ {0x37, 0x00},
+ {0x57, 0x00},
+ {0x1f, 0x00},
+ {0x3f, 0x00},
+ {0x5f, 0x00},
+ {0x1f, 0x01},
+ {0x3f, 0x01},
+ {0x5f, 0x01},
+ {0x1f, 0x02},
+ {0x3f, 0x02},
+ {0x5f, 0x02},
+ {0x1f, 0x03},
+ {0x3f, 0x03},
+ {0x5f, 0x03},
+ {0x1f, 0x04},
+ {0x3f, 0x04},
+ {0x5f, 0x04},
+ {0x1f, 0x0c},
+ {0x3f, 0x0c},
+ {0x5f, 0x0c},
+ {0x1f, 0x14},
+ {0x3f, 0x14},
+ {0x5f, 0x14},
+ {0x1f, 0x1c},
+ {0x3f, 0x1c},
+ {0x5f, 0x1c},
+ {0x1f, 0x24},
+ {0x3f, 0x24},
+ {0x5f, 0x24},
+ {0x7f, 0x24},
+};
+
#endif
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 03/17] e4000: fix PLL calc to allow higher frequencies
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
2014-03-14 0:14 ` [PATCH 01/17] e4000: convert DVB tuner to I2C driver model Antti Palosaari
2014-03-14 0:14 ` [PATCH 02/17] e4000: implement controls via v4l2 control framework Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
2014-03-14 0:14 ` [PATCH 04/17] e4000: implement PLL lock v4l control Antti Palosaari
` (13 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Mauro Carvalho Chehab, Antti Palosaari
There was 32-bit overflow on VCO frequency calculation which blocks
tuning to 1073 - 1104 MHz. Use 64 bit number in order to avoid VCO
frequency overflow.
After that fix device in question tunes to following range:
60 - 1104 MHz
1250 - 2207 MHz
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/media/tuners/e4000.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c
index 3a03b02..ae52a1f 100644
--- a/drivers/media/tuners/e4000.c
+++ b/drivers/media/tuners/e4000.c
@@ -221,11 +221,11 @@ static int e4000_set_params(struct dvb_frontend *fe)
struct e4000_priv *priv = fe->tuner_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i, sigma_delta;
- unsigned int f_vco;
+ u64 f_vco;
u8 buf[5], i_data[4], q_data[4];
dev_dbg(&priv->client->dev,
- "%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n",
+ "%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n",
__func__, c->delivery_system, c->frequency,
c->bandwidth_hz);
@@ -248,20 +248,16 @@ static int e4000_set_params(struct dvb_frontend *fe)
goto err;
}
- /*
- * Note: Currently f_vco overflows when c->frequency is 1 073 741 824 Hz
- * or more.
- */
- f_vco = c->frequency * e4000_pll_lut[i].mul;
+ f_vco = 1ull * c->frequency * e4000_pll_lut[i].mul;
sigma_delta = div_u64(0x10000ULL * (f_vco % priv->clock), priv->clock);
- buf[0] = f_vco / priv->clock;
+ buf[0] = div_u64(f_vco, priv->clock);
buf[1] = (sigma_delta >> 0) & 0xff;
buf[2] = (sigma_delta >> 8) & 0xff;
buf[3] = 0x00;
buf[4] = e4000_pll_lut[i].div;
dev_dbg(&priv->client->dev,
- "%s: f_vco=%u pll div=%d sigma_delta=%04x\n",
+ "%s: f_vco=%llu pll div=%d sigma_delta=%04x\n",
__func__, f_vco, buf[0], sigma_delta);
ret = e4000_wr_regs(priv, 0x09, buf, 5);
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 04/17] e4000: implement PLL lock v4l control
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
` (2 preceding siblings ...)
2014-03-14 0:14 ` [PATCH 03/17] e4000: fix PLL calc to allow higher frequencies Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
2014-03-14 0:14 ` [PATCH 05/17] rtl2832_sdr: Realtek RTL2832 SDR driver module Antti Palosaari
` (12 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Mauro Carvalho Chehab, Antti Palosaari
Implement PLL lock control to get PLL lock flag status from tuner
synthesizer.
Cc: Mauro Carvalho Chehab <m.chehab@samsung.com>
Cc: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/media/tuners/e4000.c | 53 ++++++++++++++++++++++++++++++++++++++-
drivers/media/tuners/e4000_priv.h | 2 ++
2 files changed, 54 insertions(+), 1 deletion(-)
diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c
index ae52a1f..ed2f635 100644
--- a/drivers/media/tuners/e4000.c
+++ b/drivers/media/tuners/e4000.c
@@ -181,6 +181,8 @@ static int e4000_init(struct dvb_frontend *fe)
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
+ priv->active = true;
+
return 0;
err:
if (fe->ops.i2c_gate_ctrl)
@@ -197,6 +199,8 @@ static int e4000_sleep(struct dvb_frontend *fe)
dev_dbg(&priv->client->dev, "%s:\n", __func__);
+ priv->active = false;
+
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
@@ -512,6 +516,50 @@ err:
return ret;
}
+static int e4000_pll_lock(struct dvb_frontend *fe)
+{
+ struct e4000_priv *priv = fe->tuner_priv;
+ int ret;
+ u8 u8tmp;
+
+ if (priv->active == false)
+ return 0;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = e4000_rd_reg(priv, 0x07, &u8tmp);
+ if (ret)
+ goto err;
+
+ priv->pll_lock->val = (u8tmp & 0x01);
+err:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ if (ret)
+ dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct e4000_priv *priv =
+ container_of(ctrl->handler, struct e4000_priv, hdl);
+ int ret;
+
+ switch (ctrl->id) {
+ case V4L2_CID_RF_TUNER_PLL_LOCK:
+ ret = e4000_pll_lock(priv->fe);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
static int e4000_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct e4000_priv *priv =
@@ -550,6 +598,7 @@ static int e4000_s_ctrl(struct v4l2_ctrl *ctrl)
}
static const struct v4l2_ctrl_ops e4000_ctrl_ops = {
+ .g_volatile_ctrl = e4000_g_volatile_ctrl,
.s_ctrl = e4000_s_ctrl,
};
@@ -613,7 +662,7 @@ static int e4000_probe(struct i2c_client *client,
goto err;
/* Register controls */
- v4l2_ctrl_handler_init(&priv->hdl, 8);
+ v4l2_ctrl_handler_init(&priv->hdl, 9);
priv->bandwidth_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
priv->bandwidth = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
@@ -634,6 +683,8 @@ static int e4000_probe(struct i2c_client *client,
priv->if_gain = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
V4L2_CID_RF_TUNER_IF_GAIN, 0, 54, 1, 0);
v4l2_ctrl_auto_cluster(2, &priv->if_gain_auto, 0, false);
+ priv->pll_lock = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ V4L2_CID_RF_TUNER_PLL_LOCK, 0, 1, 1, 0);
if (priv->hdl.error) {
ret = priv->hdl.error;
dev_err(&priv->client->dev, "Could not initialize controls\n");
diff --git a/drivers/media/tuners/e4000_priv.h b/drivers/media/tuners/e4000_priv.h
index e2ad54f..3ddd980 100644
--- a/drivers/media/tuners/e4000_priv.h
+++ b/drivers/media/tuners/e4000_priv.h
@@ -30,6 +30,7 @@ struct e4000_priv {
u32 clock;
struct dvb_frontend *fe;
struct v4l2_subdev sd;
+ bool active;
/* Controls */
struct v4l2_ctrl_handler hdl;
@@ -41,6 +42,7 @@ struct e4000_priv {
struct v4l2_ctrl *mixer_gain;
struct v4l2_ctrl *if_gain_auto;
struct v4l2_ctrl *if_gain;
+ struct v4l2_ctrl *pll_lock;
};
struct e4000_pll {
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 05/17] rtl2832_sdr: Realtek RTL2832 SDR driver module
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
` (3 preceding siblings ...)
2014-03-14 0:14 ` [PATCH 04/17] e4000: implement PLL lock v4l control Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
2014-03-14 0:14 ` [PATCH 06/17] rtl2832_sdr: expose e4000 controls to user Antti Palosaari
` (11 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Mauro Carvalho Chehab, Antti Palosaari
Implement SDR driver for Realtek RTL2832U chip as a DVB extension
module. SDR module is attached by DVB USB RTL28XXU driver as a DVB
SEC (satellite equipment controller) module. Abusing unused SEC here
has no harm as that is DVB-T only frontend.
SDR functionality is provided by RTL2832 DVB-T demodulator. I suspect
it is originally planned for DAB and FM, but it could be abused general
SDR, due to modern silicon tuners that has wide frequency range and a
lot of configurable parameters (filters, gains, ...).
http://thread.gmane.org/gmane.linux.drivers.video-input-infrastructure/44461
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/staging/media/Kconfig | 2 +
drivers/staging/media/Makefile | 2 +
drivers/staging/media/rtl2832u_sdr/Kconfig | 7 +
drivers/staging/media/rtl2832u_sdr/Makefile | 6 +
drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c | 1471 ++++++++++++++++++++++
drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.h | 54 +
6 files changed, 1542 insertions(+)
create mode 100644 drivers/staging/media/rtl2832u_sdr/Kconfig
create mode 100644 drivers/staging/media/rtl2832u_sdr/Makefile
create mode 100644 drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
create mode 100644 drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.h
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index 22b0c9d..a9f2e63 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -41,6 +41,8 @@ source "drivers/staging/media/solo6x10/Kconfig"
source "drivers/staging/media/omap4iss/Kconfig"
+source "drivers/staging/media/rtl2832u_sdr/Kconfig"
+
# Keep LIRC at the end, as it has sub-menus
source "drivers/staging/media/lirc/Kconfig"
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index bedc62a..8e2c5d2 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -11,3 +11,5 @@ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/
obj-$(CONFIG_USB_SN9C102) += sn9c102/
obj-$(CONFIG_VIDEO_OMAP2) += omap24xx/
obj-$(CONFIG_VIDEO_TCM825X) += omap24xx/
+obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832u_sdr/
+
diff --git a/drivers/staging/media/rtl2832u_sdr/Kconfig b/drivers/staging/media/rtl2832u_sdr/Kconfig
new file mode 100644
index 0000000..3ede5fe
--- /dev/null
+++ b/drivers/staging/media/rtl2832u_sdr/Kconfig
@@ -0,0 +1,7 @@
+config DVB_RTL2832_SDR
+ tristate "Realtek RTL2832 SDR"
+ depends on USB && DVB_CORE && I2C && VIDEO_V4L2 && DVB_USB_RTL28XXU
+ select DVB_RTL2832
+ select VIDEOBUF2_VMALLOC
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+
diff --git a/drivers/staging/media/rtl2832u_sdr/Makefile b/drivers/staging/media/rtl2832u_sdr/Makefile
new file mode 100644
index 0000000..7e00a0d
--- /dev/null
+++ b/drivers/staging/media/rtl2832u_sdr/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832_sdr.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/usb/dvb-usb-v2
diff --git a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
new file mode 100644
index 0000000..86fffcf
--- /dev/null
+++ b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
@@ -0,0 +1,1471 @@
+/*
+ * Realtek RTL2832U SDR driver
+ *
+ * Copyright (C) 2013 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * GNU Radio plugin "gr-kernel" for device usage will be on:
+ * http://git.linuxtv.org/anttip/gr-kernel.git
+ *
+ */
+
+#include "dvb_frontend.h"
+#include "rtl2832_sdr.h"
+#include "dvb_usb.h"
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include <linux/jiffies.h>
+#include <linux/math64.h>
+
+#define MAX_BULK_BUFS (10)
+#define BULK_BUFFER_SIZE (128 * 512)
+
+static const struct v4l2_frequency_band bands_adc[] = {
+ {
+ .tuner = 0,
+ .type = V4L2_TUNER_ADC,
+ .index = 0,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 300000,
+ .rangehigh = 300000,
+ },
+ {
+ .tuner = 0,
+ .type = V4L2_TUNER_ADC,
+ .index = 1,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 900001,
+ .rangehigh = 2800000,
+ },
+ {
+ .tuner = 0,
+ .type = V4L2_TUNER_ADC,
+ .index = 2,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 3200000,
+ .rangehigh = 3200000,
+ },
+};
+
+static const struct v4l2_frequency_band bands_fm[] = {
+ {
+ .tuner = 1,
+ .type = V4L2_TUNER_RF,
+ .index = 0,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 50000000,
+ .rangehigh = 2000000000,
+ },
+};
+
+/* stream formats */
+struct rtl2832_sdr_format {
+ char *name;
+ u32 pixelformat;
+};
+
+static struct rtl2832_sdr_format formats[] = {
+ {
+ .name = "IQ U8",
+ .pixelformat = V4L2_SDR_FMT_CU8,
+ }, {
+ .name = "IQ U16LE (emulated)",
+ .pixelformat = V4L2_SDR_FMT_CU16LE,
+ },
+};
+
+static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats);
+
+/* intermediate buffers with raw data from the USB device */
+struct rtl2832_sdr_frame_buf {
+ struct vb2_buffer vb; /* common v4l buffer stuff -- must be first */
+ struct list_head list;
+};
+
+struct rtl2832_sdr_state {
+#define POWER_ON (1 << 1)
+#define URB_BUF (1 << 2)
+ unsigned long flags;
+
+ const struct rtl2832_config *cfg;
+ struct dvb_frontend *fe;
+ struct dvb_usb_device *d;
+ struct i2c_adapter *i2c;
+ u8 bank;
+
+ struct video_device vdev;
+ struct v4l2_device v4l2_dev;
+
+ /* videobuf2 queue and queued buffers list */
+ struct vb2_queue vb_queue;
+ struct list_head queued_bufs;
+ spinlock_t queued_bufs_lock; /* Protects queued_bufs */
+
+ /* Note if taking both locks v4l2_lock must always be locked first! */
+ struct mutex v4l2_lock; /* Protects everything else */
+ struct mutex vb_queue_lock; /* Protects vb_queue and capt_file */
+
+ /* Pointer to our usb_device, will be NULL after unplug */
+ struct usb_device *udev; /* Both mutexes most be hold when setting! */
+
+ unsigned int vb_full; /* vb is full and packets dropped */
+
+ struct urb *urb_list[MAX_BULK_BUFS];
+ int buf_num;
+ unsigned long buf_size;
+ u8 *buf_list[MAX_BULK_BUFS];
+ dma_addr_t dma_addr[MAX_BULK_BUFS];
+ int urbs_initialized;
+ int urbs_submitted;
+
+ unsigned int f_adc, f_tuner;
+ u32 pixelformat;
+
+ /* Controls */
+ struct v4l2_ctrl_handler hdl;
+ struct v4l2_ctrl *bandwidth_auto;
+ struct v4l2_ctrl *bandwidth;
+
+ /* for sample rate calc */
+ unsigned int sample;
+ unsigned int sample_measured;
+ unsigned long jiffies_next;
+};
+
+/* write multiple hardware registers */
+static int rtl2832_sdr_wr(struct rtl2832_sdr_state *s, u8 reg, const u8 *val,
+ int len)
+{
+ int ret;
+ u8 buf[1 + len];
+ struct i2c_msg msg[1] = {
+ {
+ .addr = s->cfg->i2c_addr,
+ .flags = 0,
+ .len = 1 + len,
+ .buf = buf,
+ }
+ };
+
+ buf[0] = reg;
+ memcpy(&buf[1], val, len);
+
+ ret = i2c_transfer(s->i2c, msg, 1);
+ if (ret == 1) {
+ ret = 0;
+ } else {
+ dev_err(&s->i2c->dev,
+ "%s: I2C wr failed=%d reg=%02x len=%d\n",
+ KBUILD_MODNAME, ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+ return ret;
+}
+
+/* read multiple hardware registers */
+static int rtl2832_sdr_rd(struct rtl2832_sdr_state *s, u8 reg, u8 *val, int len)
+{
+ int ret;
+ struct i2c_msg msg[2] = {
+ {
+ .addr = s->cfg->i2c_addr,
+ .flags = 0,
+ .len = 1,
+ .buf = ®,
+ }, {
+ .addr = s->cfg->i2c_addr,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = val,
+ }
+ };
+
+ ret = i2c_transfer(s->i2c, msg, 2);
+ if (ret == 2) {
+ ret = 0;
+ } else {
+ dev_err(&s->i2c->dev,
+ "%s: I2C rd failed=%d reg=%02x len=%d\n",
+ KBUILD_MODNAME, ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+ return ret;
+}
+
+/* write multiple registers */
+static int rtl2832_sdr_wr_regs(struct rtl2832_sdr_state *s, u16 reg,
+ const u8 *val, int len)
+{
+ int ret;
+ u8 reg2 = (reg >> 0) & 0xff;
+ u8 bank = (reg >> 8) & 0xff;
+
+ /* switch bank if needed */
+ if (bank != s->bank) {
+ ret = rtl2832_sdr_wr(s, 0x00, &bank, 1);
+ if (ret)
+ return ret;
+
+ s->bank = bank;
+ }
+
+ return rtl2832_sdr_wr(s, reg2, val, len);
+}
+
+/* read multiple registers */
+static int rtl2832_sdr_rd_regs(struct rtl2832_sdr_state *s, u16 reg, u8 *val,
+ int len)
+{
+ int ret;
+ u8 reg2 = (reg >> 0) & 0xff;
+ u8 bank = (reg >> 8) & 0xff;
+
+ /* switch bank if needed */
+ if (bank != s->bank) {
+ ret = rtl2832_sdr_wr(s, 0x00, &bank, 1);
+ if (ret)
+ return ret;
+
+ s->bank = bank;
+ }
+
+ return rtl2832_sdr_rd(s, reg2, val, len);
+}
+
+/* write single register */
+static int rtl2832_sdr_wr_reg(struct rtl2832_sdr_state *s, u16 reg, u8 val)
+{
+ return rtl2832_sdr_wr_regs(s, reg, &val, 1);
+}
+
+#if 0
+/* read single register */
+static int rtl2832_sdr_rd_reg(struct rtl2832_sdr_state *s, u16 reg, u8 *val)
+{
+ return rtl2832_sdr_rd_regs(s, reg, val, 1);
+}
+#endif
+
+/* write single register with mask */
+static int rtl2832_sdr_wr_reg_mask(struct rtl2832_sdr_state *s, u16 reg,
+ u8 val, u8 mask)
+{
+ int ret;
+ u8 tmp;
+
+ /* no need for read if whole reg is written */
+ if (mask != 0xff) {
+ ret = rtl2832_sdr_rd_regs(s, reg, &tmp, 1);
+ if (ret)
+ return ret;
+
+ val &= mask;
+ tmp &= ~mask;
+ val |= tmp;
+ }
+
+ return rtl2832_sdr_wr_regs(s, reg, &val, 1);
+}
+
+#if 0
+/* read single register with mask */
+static int rtl2832_sdr_rd_reg_mask(struct rtl2832_sdr_state *s, u16 reg,
+ u8 *val, u8 mask)
+{
+ int ret, i;
+ u8 tmp;
+
+ ret = rtl2832_sdr_rd_regs(s, reg, &tmp, 1);
+ if (ret)
+ return ret;
+
+ tmp &= mask;
+
+ /* find position of the first bit */
+ for (i = 0; i < 8; i++) {
+ if ((mask >> i) & 0x01)
+ break;
+ }
+ *val = tmp >> i;
+
+ return 0;
+}
+#endif
+
+/* Private functions */
+static struct rtl2832_sdr_frame_buf *rtl2832_sdr_get_next_fill_buf(
+ struct rtl2832_sdr_state *s)
+{
+ unsigned long flags = 0;
+ struct rtl2832_sdr_frame_buf *buf = NULL;
+
+ spin_lock_irqsave(&s->queued_bufs_lock, flags);
+ if (list_empty(&s->queued_bufs))
+ goto leave;
+
+ buf = list_entry(s->queued_bufs.next,
+ struct rtl2832_sdr_frame_buf, list);
+ list_del(&buf->list);
+leave:
+ spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
+ return buf;
+}
+
+static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s,
+ void *dst, const u8 *src, unsigned int src_len)
+{
+ unsigned int dst_len;
+
+ if (s->pixelformat == V4L2_SDR_FMT_CU8) {
+ /* native stream, no need to convert */
+ memcpy(dst, src, src_len);
+ dst_len = src_len;
+ } else if (s->pixelformat == V4L2_SDR_FMT_CU16LE) {
+ /* convert u8 to u16 */
+ unsigned int i;
+ u16 *u16dst = dst;
+ for (i = 0; i < src_len; i++)
+ *u16dst++ = (src[i] << 8) | (src[i] >> 0);
+ dst_len = 2 * src_len;
+ } else {
+ dst_len = 0;
+ }
+
+ /* calculate samping rate and output it in 10 seconds intervals */
+ if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
+#define MSECS 10000UL
+ unsigned int samples = s->sample - s->sample_measured;
+ s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
+ s->sample_measured = s->sample;
+ dev_dbg(&s->udev->dev,
+ "slen=%d samples=%u msecs=%lu sampling rate=%lu\n",
+ src_len, samples, MSECS,
+ samples * 1000UL / MSECS);
+ }
+
+ /* total number of I+Q pairs */
+ s->sample += src_len / 2;
+
+ return dst_len;
+}
+
+/*
+ * This gets called for the bulk stream pipe. This is done in interrupt
+ * time, so it has to be fast, not crash, and not stall. Neat.
+ */
+static void rtl2832_sdr_urb_complete(struct urb *urb)
+{
+ struct rtl2832_sdr_state *s = urb->context;
+ struct rtl2832_sdr_frame_buf *fbuf;
+
+ dev_dbg_ratelimited(&s->udev->dev,
+ "%s: status=%d length=%d/%d errors=%d\n",
+ __func__, urb->status, urb->actual_length,
+ urb->transfer_buffer_length, urb->error_count);
+
+ switch (urb->status) {
+ case 0: /* success */
+ case -ETIMEDOUT: /* NAK */
+ break;
+ case -ECONNRESET: /* kill */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default: /* error */
+ dev_err_ratelimited(&s->udev->dev, "urb failed=%d\n",
+ urb->status);
+ break;
+ }
+
+ if (likely(urb->actual_length > 0)) {
+ void *ptr;
+ unsigned int len;
+ /* get free framebuffer */
+ fbuf = rtl2832_sdr_get_next_fill_buf(s);
+ if (unlikely(fbuf == NULL)) {
+ s->vb_full++;
+ dev_notice_ratelimited(&s->udev->dev,
+ "videobuf is full, %d packets dropped\n",
+ s->vb_full);
+ goto skip;
+ }
+
+ /* fill framebuffer */
+ ptr = vb2_plane_vaddr(&fbuf->vb, 0);
+ len = rtl2832_sdr_convert_stream(s, ptr, urb->transfer_buffer,
+ urb->actual_length);
+ vb2_set_plane_payload(&fbuf->vb, 0, len);
+ vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
+ }
+skip:
+ usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int rtl2832_sdr_kill_urbs(struct rtl2832_sdr_state *s)
+{
+ int i;
+
+ for (i = s->urbs_submitted - 1; i >= 0; i--) {
+ dev_dbg(&s->udev->dev, "%s: kill urb=%d\n", __func__, i);
+ /* stop the URB */
+ usb_kill_urb(s->urb_list[i]);
+ }
+ s->urbs_submitted = 0;
+
+ return 0;
+}
+
+static int rtl2832_sdr_submit_urbs(struct rtl2832_sdr_state *s)
+{
+ int i, ret;
+
+ for (i = 0; i < s->urbs_initialized; i++) {
+ dev_dbg(&s->udev->dev, "%s: submit urb=%d\n", __func__, i);
+ ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC);
+ if (ret) {
+ dev_err(&s->udev->dev,
+ "Could not submit urb no. %d - get them all back\n",
+ i);
+ rtl2832_sdr_kill_urbs(s);
+ return ret;
+ }
+ s->urbs_submitted++;
+ }
+
+ return 0;
+}
+
+static int rtl2832_sdr_free_stream_bufs(struct rtl2832_sdr_state *s)
+{
+ if (s->flags & USB_STATE_URB_BUF) {
+ while (s->buf_num) {
+ s->buf_num--;
+ dev_dbg(&s->udev->dev, "%s: free buf=%d\n",
+ __func__, s->buf_num);
+ usb_free_coherent(s->udev, s->buf_size,
+ s->buf_list[s->buf_num],
+ s->dma_addr[s->buf_num]);
+ }
+ }
+ s->flags &= ~USB_STATE_URB_BUF;
+
+ return 0;
+}
+
+static int rtl2832_sdr_alloc_stream_bufs(struct rtl2832_sdr_state *s)
+{
+ s->buf_num = 0;
+ s->buf_size = BULK_BUFFER_SIZE;
+
+ dev_dbg(&s->udev->dev,
+ "%s: all in all I will use %u bytes for streaming\n",
+ __func__, MAX_BULK_BUFS * BULK_BUFFER_SIZE);
+
+ for (s->buf_num = 0; s->buf_num < MAX_BULK_BUFS; s->buf_num++) {
+ s->buf_list[s->buf_num] = usb_alloc_coherent(s->udev,
+ BULK_BUFFER_SIZE, GFP_ATOMIC,
+ &s->dma_addr[s->buf_num]);
+ if (!s->buf_list[s->buf_num]) {
+ dev_dbg(&s->udev->dev, "%s: alloc buf=%d failed\n",
+ __func__, s->buf_num);
+ rtl2832_sdr_free_stream_bufs(s);
+ return -ENOMEM;
+ }
+
+ dev_dbg(&s->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n",
+ __func__, s->buf_num,
+ s->buf_list[s->buf_num],
+ (long long)s->dma_addr[s->buf_num]);
+ s->flags |= USB_STATE_URB_BUF;
+ }
+
+ return 0;
+}
+
+static int rtl2832_sdr_free_urbs(struct rtl2832_sdr_state *s)
+{
+ int i;
+
+ rtl2832_sdr_kill_urbs(s);
+
+ for (i = s->urbs_initialized - 1; i >= 0; i--) {
+ if (s->urb_list[i]) {
+ dev_dbg(&s->udev->dev, "%s: free urb=%d\n",
+ __func__, i);
+ /* free the URBs */
+ usb_free_urb(s->urb_list[i]);
+ }
+ }
+ s->urbs_initialized = 0;
+
+ return 0;
+}
+
+static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_state *s)
+{
+ int i, j;
+
+ /* allocate the URBs */
+ for (i = 0; i < MAX_BULK_BUFS; i++) {
+ dev_dbg(&s->udev->dev, "%s: alloc urb=%d\n", __func__, i);
+ s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!s->urb_list[i]) {
+ dev_dbg(&s->udev->dev, "%s: failed\n", __func__);
+ for (j = 0; j < i; j++)
+ usb_free_urb(s->urb_list[j]);
+ return -ENOMEM;
+ }
+ usb_fill_bulk_urb(s->urb_list[i],
+ s->udev,
+ usb_rcvbulkpipe(s->udev, 0x81),
+ s->buf_list[i],
+ BULK_BUFFER_SIZE,
+ rtl2832_sdr_urb_complete, s);
+
+ s->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+ s->urb_list[i]->transfer_dma = s->dma_addr[i];
+ s->urbs_initialized++;
+ }
+
+ return 0;
+}
+
+/* Must be called with vb_queue_lock hold */
+static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_state *s)
+{
+ unsigned long flags = 0;
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ spin_lock_irqsave(&s->queued_bufs_lock, flags);
+ while (!list_empty(&s->queued_bufs)) {
+ struct rtl2832_sdr_frame_buf *buf;
+ buf = list_entry(s->queued_bufs.next,
+ struct rtl2832_sdr_frame_buf, list);
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+ spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
+}
+
+/* The user yanked out the cable... */
+static void rtl2832_sdr_release_sec(struct dvb_frontend *fe)
+{
+ struct rtl2832_sdr_state *s = fe->sec_priv;
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ mutex_lock(&s->vb_queue_lock);
+ mutex_lock(&s->v4l2_lock);
+ /* No need to keep the urbs around after disconnection */
+ s->udev = NULL;
+
+ v4l2_device_disconnect(&s->v4l2_dev);
+ video_unregister_device(&s->vdev);
+ mutex_unlock(&s->v4l2_lock);
+ mutex_unlock(&s->vb_queue_lock);
+
+ v4l2_device_put(&s->v4l2_dev);
+
+ fe->sec_priv = NULL;
+}
+
+static int rtl2832_sdr_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct rtl2832_sdr_state *s = video_drvdata(file);
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+ strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
+ usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info));
+ cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+/* Videobuf2 operations */
+static int rtl2832_sdr_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt, unsigned int *nbuffers,
+ unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
+ dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers);
+
+ /* Absolute min and max number of buffers available for mmap() */
+ *nbuffers = clamp_t(unsigned int, *nbuffers, 8, 32);
+ *nplanes = 1;
+ /* 2 = max 16-bit sample returned */
+ sizes[0] = PAGE_ALIGN(BULK_BUFFER_SIZE * 2);
+ dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n",
+ __func__, *nbuffers, sizes[0]);
+ return 0;
+}
+
+static int rtl2832_sdr_buf_prepare(struct vb2_buffer *vb)
+{
+ struct rtl2832_sdr_state *s = vb2_get_drv_priv(vb->vb2_queue);
+
+ /* Don't allow queing new buffers after device disconnection */
+ if (!s->udev)
+ return -ENODEV;
+
+ return 0;
+}
+
+static void rtl2832_sdr_buf_queue(struct vb2_buffer *vb)
+{
+ struct rtl2832_sdr_state *s = vb2_get_drv_priv(vb->vb2_queue);
+ struct rtl2832_sdr_frame_buf *buf =
+ container_of(vb, struct rtl2832_sdr_frame_buf, vb);
+ unsigned long flags = 0;
+
+ /* Check the device has not disconnected between prep and queuing */
+ if (!s->udev) {
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ return;
+ }
+
+ spin_lock_irqsave(&s->queued_bufs_lock, flags);
+ list_add_tail(&buf->list, &s->queued_bufs);
+ spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
+}
+
+static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s)
+{
+ struct dvb_frontend *fe = s->fe;
+ int ret;
+ unsigned int f_sr, f_if;
+ u8 buf[4], u8tmp1, u8tmp2;
+ u64 u64tmp;
+ u32 u32tmp;
+ dev_dbg(&s->udev->dev, "%s: f_adc=%u\n", __func__, s->f_adc);
+
+ if (!test_bit(POWER_ON, &s->flags))
+ return 0;
+
+ if (s->f_adc == 0)
+ return 0;
+
+ f_sr = s->f_adc;
+
+ ret = rtl2832_sdr_wr_regs(s, 0x13e, "\x00\x00", 2);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_sdr_wr_regs(s, 0x115, "\x00\x00\x00\x00", 4);
+ if (ret)
+ goto err;
+
+ /* get IF from tuner */
+ if (fe->ops.tuner_ops.get_if_frequency)
+ ret = fe->ops.tuner_ops.get_if_frequency(fe, &f_if);
+ else
+ ret = -EINVAL;
+
+ if (ret)
+ goto err;
+
+ /* program IF */
+ u64tmp = f_if % s->cfg->xtal;
+ u64tmp *= 0x400000;
+ u64tmp = div_u64(u64tmp, s->cfg->xtal);
+ u64tmp = -u64tmp;
+ u32tmp = u64tmp & 0x3fffff;
+
+ dev_dbg(&s->udev->dev, "%s: f_if=%u if_ctl=%08x\n",
+ __func__, f_if, u32tmp);
+
+ buf[0] = (u32tmp >> 16) & 0xff;
+ buf[1] = (u32tmp >> 8) & 0xff;
+ buf[2] = (u32tmp >> 0) & 0xff;
+
+ ret = rtl2832_sdr_wr_regs(s, 0x119, buf, 3);
+ if (ret)
+ goto err;
+
+ /* BB / IF mode */
+ /* POR: 0x1b1=0x1f, 0x008=0x0d, 0x006=0x80 */
+ if (f_if) {
+ u8tmp1 = 0x1a; /* disable Zero-IF */
+ u8tmp2 = 0x8d; /* enable ADC I */
+ } else {
+ u8tmp1 = 0x1b; /* enable Zero-IF, DC, IQ */
+ u8tmp2 = 0xcd; /* enable ADC I, ADC Q */
+ }
+
+ ret = rtl2832_sdr_wr_reg(s, 0x1b1, u8tmp1);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_sdr_wr_reg(s, 0x008, u8tmp2);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_sdr_wr_reg(s, 0x006, 0x80);
+ if (ret)
+ goto err;
+
+ /* program sampling rate (resampling down) */
+ u32tmp = div_u64(s->cfg->xtal * 0x400000ULL, f_sr * 4U);
+ u32tmp <<= 2;
+ buf[0] = (u32tmp >> 24) & 0xff;
+ buf[1] = (u32tmp >> 16) & 0xff;
+ buf[2] = (u32tmp >> 8) & 0xff;
+ buf[3] = (u32tmp >> 0) & 0xff;
+ ret = rtl2832_sdr_wr_regs(s, 0x19f, buf, 4);
+ if (ret)
+ goto err;
+
+ /* low-pass filter */
+ ret = rtl2832_sdr_wr_regs(s, 0x11c,
+ "\xca\xdc\xd7\xd8\xe0\xf2\x0e\x35\x06\x50\x9c\x0d\x71\x11\x14\x71\x74\x19\x41\xa5",
+ 20);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_sdr_wr_regs(s, 0x017, "\x11\x10", 2);
+ if (ret)
+ goto err;
+
+ /* mode */
+ ret = rtl2832_sdr_wr_regs(s, 0x019, "\x05", 1);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_sdr_wr_regs(s, 0x01a, "\x1b\x16\x0d\x06\x01\xff", 6);
+ if (ret)
+ goto err;
+
+ /* FSM */
+ ret = rtl2832_sdr_wr_regs(s, 0x192, "\x00\xf0\x0f", 3);
+ if (ret)
+ goto err;
+
+ /* PID filter */
+ ret = rtl2832_sdr_wr_regs(s, 0x061, "\x60", 1);
+ if (ret)
+ goto err;
+
+ /* used RF tuner based settings */
+ switch (s->cfg->tuner) {
+ case RTL2832_TUNER_E4000:
+ ret = rtl2832_sdr_wr_regs(s, 0x112, "\x5a", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x102, "\x40", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x103, "\x5a", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1c7, "\x30", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x104, "\xd0", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x105, "\xbe", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1c8, "\x18", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x106, "\x35", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1c9, "\x21", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1ca, "\x21", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1cb, "\x00", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x107, "\x40", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1cd, "\x10", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1ce, "\x10", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x108, "\x80", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x109, "\x7f", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x10a, "\x80", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x10b, "\x7f", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x011, "\xd4", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1e5, "\xf0", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1d9, "\x00", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1db, "\x00", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1dd, "\x14", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1de, "\xec", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1d8, "\x0c", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1e6, "\x02", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1d7, "\x09", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x00d, "\x83", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x010, "\x49", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x00d, "\x87", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x00d, "\x85", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x013, "\x02", 1);
+ break;
+ case RTL2832_TUNER_FC0012:
+ case RTL2832_TUNER_FC0013:
+ ret = rtl2832_sdr_wr_regs(s, 0x112, "\x5a", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x102, "\x40", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x103, "\x5a", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1c7, "\x2c", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x104, "\xcc", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x105, "\xbe", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1c8, "\x16", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x106, "\x35", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1c9, "\x21", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1ca, "\x21", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1cb, "\x00", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x107, "\x40", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1cd, "\x10", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1ce, "\x10", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x108, "\x80", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x109, "\x7f", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x10a, "\x80", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x10b, "\x7f", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x011, "\xe9\xbf", 2);
+ ret = rtl2832_sdr_wr_regs(s, 0x1e5, "\xf0", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1d9, "\x00", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1db, "\x00", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1dd, "\x11", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1de, "\xef", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1d8, "\x0c", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1e6, "\x02", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1d7, "\x09", 1);
+ break;
+ case RTL2832_TUNER_R820T:
+ ret = rtl2832_sdr_wr_regs(s, 0x112, "\x5a", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x102, "\x40", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x115, "\x01", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x103, "\x80", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1c7, "\x24", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x104, "\xcc", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x105, "\xbe", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1c8, "\x14", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x106, "\x35", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1c9, "\x21", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1ca, "\x21", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1cb, "\x00", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x107, "\x40", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1cd, "\x10", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x1ce, "\x10", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x108, "\x80", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x109, "\x7f", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x10a, "\x80", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x10b, "\x7f", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
+ ret = rtl2832_sdr_wr_regs(s, 0x011, "\xf4", 1);
+ break;
+ default:
+ dev_notice(&s->udev->dev, "Unsupported tuner\n");
+ }
+
+ /* software reset */
+ ret = rtl2832_sdr_wr_reg_mask(s, 0x101, 0x04, 0x04);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_sdr_wr_reg_mask(s, 0x101, 0x00, 0x04);
+ if (ret)
+ goto err;
+err:
+ return ret;
+};
+
+static void rtl2832_sdr_unset_adc(struct rtl2832_sdr_state *s)
+{
+ int ret;
+
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ /* PID filter */
+ ret = rtl2832_sdr_wr_regs(s, 0x061, "\xe0", 1);
+ if (ret)
+ goto err;
+
+ /* mode */
+ ret = rtl2832_sdr_wr_regs(s, 0x019, "\x20", 1);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_sdr_wr_regs(s, 0x017, "\x11\x10", 2);
+ if (ret)
+ goto err;
+
+ /* FSM */
+ ret = rtl2832_sdr_wr_regs(s, 0x192, "\x00\x0f\xff", 3);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_sdr_wr_regs(s, 0x13e, "\x40\x00", 2);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_sdr_wr_regs(s, 0x115, "\x06\x3f\xce\xcc", 4);
+ if (ret)
+ goto err;
+err:
+ return;
+};
+
+static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s)
+{
+ struct dvb_frontend *fe = s->fe;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct v4l2_ctrl *bandwidth_auto;
+ struct v4l2_ctrl *bandwidth;
+
+ /*
+ * tuner RF (Hz)
+ */
+ if (s->f_tuner == 0)
+ return 0;
+
+ /*
+ * bandwidth (Hz)
+ */
+ bandwidth_auto = v4l2_ctrl_find(&s->hdl, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO);
+ bandwidth = v4l2_ctrl_find(&s->hdl, V4L2_CID_RF_TUNER_BANDWIDTH);
+ if (v4l2_ctrl_g_ctrl(bandwidth_auto)) {
+ c->bandwidth_hz = s->f_adc;
+ v4l2_ctrl_s_ctrl(bandwidth, s->f_adc);
+ } else {
+ c->bandwidth_hz = v4l2_ctrl_g_ctrl(bandwidth);
+ }
+
+ c->frequency = s->f_tuner;
+ c->delivery_system = SYS_DVBT;
+
+ dev_dbg(&s->udev->dev, "%s: frequency=%u bandwidth=%d\n",
+ __func__, c->frequency, c->bandwidth_hz);
+
+ if (!test_bit(POWER_ON, &s->flags))
+ return 0;
+
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe);
+
+ return 0;
+};
+
+static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_state *s)
+{
+ struct dvb_frontend *fe = s->fe;
+
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ if (fe->ops.tuner_ops.init)
+ fe->ops.tuner_ops.init(fe);
+
+ return 0;
+};
+
+static void rtl2832_sdr_unset_tuner(struct rtl2832_sdr_state *s)
+{
+ struct dvb_frontend *fe = s->fe;
+
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ if (fe->ops.tuner_ops.sleep)
+ fe->ops.tuner_ops.sleep(fe);
+
+ return;
+};
+
+static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
+ int ret;
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ if (!s->udev)
+ return -ENODEV;
+
+ if (mutex_lock_interruptible(&s->v4l2_lock))
+ return -ERESTARTSYS;
+
+ if (s->d->props->power_ctrl)
+ s->d->props->power_ctrl(s->d, 1);
+
+ set_bit(POWER_ON, &s->flags);
+
+ ret = rtl2832_sdr_set_tuner(s);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_sdr_set_tuner_freq(s);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_sdr_set_adc(s);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_sdr_alloc_stream_bufs(s);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_sdr_alloc_urbs(s);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_sdr_submit_urbs(s);
+ if (ret)
+ goto err;
+
+err:
+ mutex_unlock(&s->v4l2_lock);
+
+ return ret;
+}
+
+static int rtl2832_sdr_stop_streaming(struct vb2_queue *vq)
+{
+ struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ if (mutex_lock_interruptible(&s->v4l2_lock))
+ return -ERESTARTSYS;
+
+ rtl2832_sdr_kill_urbs(s);
+ rtl2832_sdr_free_urbs(s);
+ rtl2832_sdr_free_stream_bufs(s);
+ rtl2832_sdr_cleanup_queued_bufs(s);
+ rtl2832_sdr_unset_adc(s);
+ rtl2832_sdr_unset_tuner(s);
+
+ clear_bit(POWER_ON, &s->flags);
+
+ if (s->d->props->power_ctrl)
+ s->d->props->power_ctrl(s->d, 0);
+
+ mutex_unlock(&s->v4l2_lock);
+
+ return 0;
+}
+
+static struct vb2_ops rtl2832_sdr_vb2_ops = {
+ .queue_setup = rtl2832_sdr_queue_setup,
+ .buf_prepare = rtl2832_sdr_buf_prepare,
+ .buf_queue = rtl2832_sdr_buf_queue,
+ .start_streaming = rtl2832_sdr_start_streaming,
+ .stop_streaming = rtl2832_sdr_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+{
+ struct rtl2832_sdr_state *s = video_drvdata(file);
+ dev_dbg(&s->udev->dev, "%s: index=%d type=%d\n",
+ __func__, v->index, v->type);
+
+ if (v->index == 0) {
+ strlcpy(v->name, "ADC: Realtek RTL2832", sizeof(v->name));
+ v->type = V4L2_TUNER_ADC;
+ v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+ v->rangelow = 300000;
+ v->rangehigh = 3200000;
+ } else if (v->index == 1) {
+ strlcpy(v->name, "RF: <unknown>", sizeof(v->name));
+ v->type = V4L2_TUNER_RF;
+ v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+ v->rangelow = 50000000;
+ v->rangehigh = 2000000000;
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rtl2832_sdr_s_tuner(struct file *file, void *priv,
+ const struct v4l2_tuner *v)
+{
+ struct rtl2832_sdr_state *s = video_drvdata(file);
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ return 0;
+}
+
+static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv,
+ struct v4l2_frequency_band *band)
+{
+ struct rtl2832_sdr_state *s = video_drvdata(file);
+ dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n",
+ __func__, band->tuner, band->type, band->index);
+
+ if (band->tuner == 0) {
+ if (band->index >= ARRAY_SIZE(bands_adc))
+ return -EINVAL;
+
+ *band = bands_adc[band->index];
+ } else if (band->tuner == 1) {
+ if (band->index >= ARRAY_SIZE(bands_fm))
+ return -EINVAL;
+
+ *band = bands_fm[band->index];
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rtl2832_sdr_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct rtl2832_sdr_state *s = video_drvdata(file);
+ int ret = 0;
+ dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n",
+ __func__, f->tuner, f->type);
+
+ if (f->tuner == 0)
+ f->frequency = s->f_adc;
+ else if (f->tuner == 1)
+ f->frequency = s->f_tuner;
+ else
+ return -EINVAL;
+
+ return ret;
+}
+
+static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
+ const struct v4l2_frequency *f)
+{
+ struct rtl2832_sdr_state *s = video_drvdata(file);
+ int ret, band;
+
+ dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n",
+ __func__, f->tuner, f->type, f->frequency);
+
+ /* ADC band midpoints */
+ #define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2)
+ #define BAND_ADC_1 ((bands_adc[1].rangehigh + bands_adc[2].rangelow) / 2)
+
+ if (f->tuner == 0 && f->type == V4L2_TUNER_ADC) {
+ if (f->frequency < BAND_ADC_0)
+ band = 0;
+ else if (f->frequency < BAND_ADC_1)
+ band = 1;
+ else
+ band = 2;
+
+ s->f_adc = clamp_t(unsigned int, f->frequency,
+ bands_adc[band].rangelow,
+ bands_adc[band].rangehigh);
+
+ dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n",
+ __func__, s->f_adc);
+ ret = rtl2832_sdr_set_adc(s);
+ } else if (f->tuner == 1) {
+ s->f_tuner = f->frequency;
+ dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n",
+ __func__, f->frequency);
+
+ ret = rtl2832_sdr_set_tuner_freq(s);
+ } else {
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct rtl2832_sdr_state *s = video_drvdata(file);
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ if (f->index >= NUM_FORMATS)
+ return -EINVAL;
+
+ strlcpy(f->description, formats[f->index].name, sizeof(f->description));
+ f->pixelformat = formats[f->index].pixelformat;
+
+ return 0;
+}
+
+static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct rtl2832_sdr_state *s = video_drvdata(file);
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ f->fmt.sdr.pixelformat = s->pixelformat;
+
+ return 0;
+}
+
+static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct rtl2832_sdr_state *s = video_drvdata(file);
+ struct vb2_queue *q = &s->vb_queue;
+ int i;
+ dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+ (char *)&f->fmt.sdr.pixelformat);
+
+ if (vb2_is_busy(q))
+ return -EBUSY;
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
+ s->pixelformat = f->fmt.sdr.pixelformat;
+ return 0;
+ }
+ }
+
+ f->fmt.sdr.pixelformat = formats[0].pixelformat;
+ s->pixelformat = formats[0].pixelformat;
+
+ return 0;
+}
+
+static int rtl2832_sdr_try_fmt_sdr_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct rtl2832_sdr_state *s = video_drvdata(file);
+ int i;
+ dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+ (char *)&f->fmt.sdr.pixelformat);
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].pixelformat == f->fmt.sdr.pixelformat)
+ return 0;
+ }
+
+ f->fmt.sdr.pixelformat = formats[0].pixelformat;
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops rtl2832_sdr_ioctl_ops = {
+ .vidioc_querycap = rtl2832_sdr_querycap,
+
+ .vidioc_enum_fmt_sdr_cap = rtl2832_sdr_enum_fmt_sdr_cap,
+ .vidioc_g_fmt_sdr_cap = rtl2832_sdr_g_fmt_sdr_cap,
+ .vidioc_s_fmt_sdr_cap = rtl2832_sdr_s_fmt_sdr_cap,
+ .vidioc_try_fmt_sdr_cap = rtl2832_sdr_try_fmt_sdr_cap,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+
+ .vidioc_g_tuner = rtl2832_sdr_g_tuner,
+ .vidioc_s_tuner = rtl2832_sdr_s_tuner,
+
+ .vidioc_enum_freq_bands = rtl2832_sdr_enum_freq_bands,
+ .vidioc_g_frequency = rtl2832_sdr_g_frequency,
+ .vidioc_s_frequency = rtl2832_sdr_s_frequency,
+
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+};
+
+static const struct v4l2_file_operations rtl2832_sdr_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static struct video_device rtl2832_sdr_template = {
+ .name = "Realtek RTL2832 SDR",
+ .release = video_device_release_empty,
+ .fops = &rtl2832_sdr_fops,
+ .ioctl_ops = &rtl2832_sdr_ioctl_ops,
+};
+
+static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct rtl2832_sdr_state *s =
+ container_of(ctrl->handler, struct rtl2832_sdr_state,
+ hdl);
+ struct dvb_frontend *fe = s->fe;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ dev_dbg(&s->udev->dev,
+ "%s: id=%d name=%s val=%d min=%d max=%d step=%d\n",
+ __func__, ctrl->id, ctrl->name, ctrl->val,
+ ctrl->minimum, ctrl->maximum, ctrl->step);
+
+ switch (ctrl->id) {
+ case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
+ case V4L2_CID_RF_TUNER_BANDWIDTH:
+ if (s->bandwidth_auto->val)
+ s->bandwidth->val = s->f_adc;
+
+ c->bandwidth_hz = s->bandwidth->val;
+
+ if (!test_bit(POWER_ON, &s->flags))
+ return 0;
+
+ if (fe->ops.tuner_ops.set_params)
+ ret = fe->ops.tuner_ops.set_params(fe);
+ else
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops rtl2832_sdr_ctrl_ops = {
+ .s_ctrl = rtl2832_sdr_s_ctrl,
+};
+
+static void rtl2832_sdr_video_release(struct v4l2_device *v)
+{
+ struct rtl2832_sdr_state *s =
+ container_of(v, struct rtl2832_sdr_state, v4l2_dev);
+
+ v4l2_ctrl_handler_free(&s->hdl);
+ v4l2_device_unregister(&s->v4l2_dev);
+ kfree(s);
+}
+
+struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, const struct rtl2832_config *cfg,
+ struct v4l2_subdev *sd)
+{
+ int ret;
+ struct rtl2832_sdr_state *s;
+ const struct v4l2_ctrl_ops *ops = &rtl2832_sdr_ctrl_ops;
+ struct dvb_usb_device *d = i2c_get_adapdata(i2c);
+
+ s = kzalloc(sizeof(struct rtl2832_sdr_state), GFP_KERNEL);
+ if (s == NULL) {
+ dev_err(&d->udev->dev,
+ "Could not allocate memory for rtl2832_sdr_state\n");
+ return NULL;
+ }
+
+ /* setup the state */
+ s->fe = fe;
+ s->d = d;
+ s->udev = d->udev;
+ s->i2c = i2c;
+ s->cfg = cfg;
+ s->f_adc = bands_adc[0].rangelow;
+ s->pixelformat = V4L2_SDR_FMT_CU8;
+
+ mutex_init(&s->v4l2_lock);
+ mutex_init(&s->vb_queue_lock);
+ spin_lock_init(&s->queued_bufs_lock);
+ INIT_LIST_HEAD(&s->queued_bufs);
+
+ /* Init videobuf2 queue structure */
+ s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
+ s->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+ s->vb_queue.drv_priv = s;
+ s->vb_queue.buf_struct_size = sizeof(struct rtl2832_sdr_frame_buf);
+ s->vb_queue.ops = &rtl2832_sdr_vb2_ops;
+ s->vb_queue.mem_ops = &vb2_vmalloc_memops;
+ s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ ret = vb2_queue_init(&s->vb_queue);
+ if (ret) {
+ dev_err(&s->udev->dev, "Could not initialize vb2 queue\n");
+ goto err_free_mem;
+ }
+
+ /* Register controls */
+ switch (s->cfg->tuner) {
+ case RTL2832_TUNER_E4000:
+ v4l2_ctrl_handler_init(&s->hdl, 2);
+ s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
+ s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH, 4300000, 11000000, 100000, 4300000);
+ v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false);
+ break;
+ case RTL2832_TUNER_R820T:
+ v4l2_ctrl_handler_init(&s->hdl, 2);
+ s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
+ s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH, 0, 8000000, 100000, 0);
+ v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false);
+ break;
+ case RTL2832_TUNER_FC0012:
+ case RTL2832_TUNER_FC0013:
+ v4l2_ctrl_handler_init(&s->hdl, 2);
+ s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
+ s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH, 6000000, 8000000, 1000000, 6000000);
+ v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false);
+ break;
+ default:
+ v4l2_ctrl_handler_init(&s->hdl, 0);
+ dev_notice(&s->udev->dev, "%s: Unsupported tuner\n",
+ KBUILD_MODNAME);
+ goto err_free_controls;
+ }
+
+ if (s->hdl.error) {
+ ret = s->hdl.error;
+ dev_err(&s->udev->dev, "Could not initialize controls\n");
+ goto err_free_controls;
+ }
+
+ /* Init video_device structure */
+ s->vdev = rtl2832_sdr_template;
+ s->vdev.queue = &s->vb_queue;
+ s->vdev.queue->lock = &s->vb_queue_lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev.flags);
+ video_set_drvdata(&s->vdev, s);
+
+ /* Register the v4l2_device structure */
+ s->v4l2_dev.release = rtl2832_sdr_video_release;
+ ret = v4l2_device_register(&s->udev->dev, &s->v4l2_dev);
+ if (ret) {
+ dev_err(&s->udev->dev,
+ "Failed to register v4l2-device (%d)\n", ret);
+ goto err_free_controls;
+ }
+
+ s->v4l2_dev.ctrl_handler = &s->hdl;
+ s->vdev.v4l2_dev = &s->v4l2_dev;
+ s->vdev.lock = &s->v4l2_lock;
+ s->vdev.vfl_dir = VFL_DIR_RX;
+
+ ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
+ if (ret) {
+ dev_err(&s->udev->dev,
+ "Failed to register as video device (%d)\n",
+ ret);
+ goto err_unregister_v4l2_dev;
+ }
+ dev_info(&s->udev->dev, "Registered as %s\n",
+ video_device_node_name(&s->vdev));
+
+ fe->sec_priv = s;
+ fe->ops.release_sec = rtl2832_sdr_release_sec;
+
+ dev_info(&s->i2c->dev, "%s: Realtek RTL2832 SDR attached\n",
+ KBUILD_MODNAME);
+ return fe;
+
+err_unregister_v4l2_dev:
+ v4l2_device_unregister(&s->v4l2_dev);
+err_free_controls:
+ v4l2_ctrl_handler_free(&s->hdl);
+err_free_mem:
+ kfree(s);
+ return NULL;
+}
+EXPORT_SYMBOL(rtl2832_sdr_attach);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Realtek RTL2832 SDR driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.h b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.h
new file mode 100644
index 0000000..b865fad
--- /dev/null
+++ b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.h
@@ -0,0 +1,54 @@
+/*
+ * Realtek RTL2832U SDR driver
+ *
+ * Copyright (C) 2013 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * GNU Radio plugin "gr-kernel" for device usage will be on:
+ * http://git.linuxtv.org/anttip/gr-kernel.git
+ *
+ * TODO:
+ * Help is very highly welcome for these + all the others you could imagine:
+ * - move controls to V4L2 API
+ * - use libv4l2 for stream format conversions
+ * - gr-kernel: switch to v4l2_mmap (current read eats a lot of cpu)
+ * - SDRSharp support
+ */
+
+#ifndef RTL2832_SDR_H
+#define RTL2832_SDR_H
+
+#include <linux/kconfig.h>
+#include <media/v4l2-subdev.h>
+
+/* for config struct */
+#include "rtl2832.h"
+
+#if IS_ENABLED(CONFIG_DVB_RTL2832_SDR)
+extern struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, const struct rtl2832_config *cfg,
+ struct v4l2_subdev *sd);
+#else
+static inline struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, const struct rtl2832_config *cfg,
+ struct v4l2_subdev *sd)
+{
+ dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif /* RTL2832_SDR_H */
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 06/17] rtl2832_sdr: expose e4000 controls to user
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
` (4 preceding siblings ...)
2014-03-14 0:14 ` [PATCH 05/17] rtl2832_sdr: Realtek RTL2832 SDR driver module Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
2014-03-14 0:14 ` [PATCH 07/17] rtl28xxu: constify demod config structs Antti Palosaari
` (10 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Mauro Carvalho Chehab, Antti Palosaari
E4000 tuner driver provides now some controls. Expose those to
userland.
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
index 86fffcf..7e20576 100644
--- a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
+++ b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
@@ -1387,10 +1387,9 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
/* Register controls */
switch (s->cfg->tuner) {
case RTL2832_TUNER_E4000:
- v4l2_ctrl_handler_init(&s->hdl, 2);
- s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
- s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH, 4300000, 11000000, 100000, 4300000);
- v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false);
+ v4l2_ctrl_handler_init(&s->hdl, 9);
+ if (sd)
+ v4l2_ctrl_add_handler(&s->hdl, sd->ctrl_handler, NULL);
break;
case RTL2832_TUNER_R820T:
v4l2_ctrl_handler_init(&s->hdl, 2);
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 07/17] rtl28xxu: constify demod config structs
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
` (5 preceding siblings ...)
2014-03-14 0:14 ` [PATCH 06/17] rtl2832_sdr: expose e4000 controls to user Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
2014-03-14 0:14 ` [PATCH 08/17] rtl28xxu: attach SDR extension module Antti Palosaari
` (9 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Mauro Carvalho Chehab, Antti Palosaari
Optimize a little bit from data to text.
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index ae07740..db98f1c 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -516,7 +516,7 @@ err:
return ret;
}
-static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
+static const struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.ts_mode = 0,
@@ -527,7 +527,7 @@ static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
};
-static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
+static const struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.ts_mode = 0,
@@ -537,7 +537,7 @@ static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
.agc_targ_val = 0x2d,
};
-static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = {
+static const struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.ts_mode = 0,
@@ -551,7 +551,7 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dvb_usb_device *d = adap_to_d(adap);
struct rtl28xxu_priv *priv = d_to_priv(d);
- struct rtl2830_config *rtl2830_config;
+ const struct rtl2830_config *rtl2830_config;
int ret;
dev_dbg(&d->udev->dev, "%s:\n", __func__);
@@ -586,31 +586,31 @@ err:
return ret;
}
-static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.tuner = TUNER_RTL2832_FC0012
};
-static struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.tuner = TUNER_RTL2832_FC0013
};
-static struct rtl2832_config rtl28xxu_rtl2832_tua9001_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_tua9001_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.tuner = TUNER_RTL2832_TUA9001,
};
-static struct rtl2832_config rtl28xxu_rtl2832_e4000_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_e4000_config = {
.i2c_addr = 0x10, /* 0x20 */
.xtal = 28800000,
.tuner = TUNER_RTL2832_E4000,
};
-static struct rtl2832_config rtl28xxu_rtl2832_r820t_config = {
+static const struct rtl2832_config rtl28xxu_rtl2832_r820t_config = {
.i2c_addr = 0x10,
.xtal = 28800000,
.tuner = TUNER_RTL2832_R820T,
@@ -734,7 +734,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
int ret;
struct dvb_usb_device *d = adap_to_d(adap);
struct rtl28xxu_priv *priv = d_to_priv(d);
- struct rtl2832_config *rtl2832_config;
+ const struct rtl2832_config *rtl2832_config;
dev_dbg(&d->udev->dev, "%s:\n", __func__);
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 08/17] rtl28xxu: attach SDR extension module
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
` (6 preceding siblings ...)
2014-03-14 0:14 ` [PATCH 07/17] rtl28xxu: constify demod config structs Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
2014-03-14 0:14 ` [PATCH 09/17] rtl28xxu: fix switch-case style issue Antti Palosaari
` (8 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Mauro Carvalho Chehab, Antti Palosaari
With that extension module it supports SDR.
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/media/usb/dvb-usb-v2/Makefile | 1 +
drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 20 ++++++++++++++++++++
2 files changed, 21 insertions(+)
diff --git a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile
index bc38f03..7407b83 100644
--- a/drivers/media/usb/dvb-usb-v2/Makefile
+++ b/drivers/media/usb/dvb-usb-v2/Makefile
@@ -41,3 +41,4 @@ ccflags-y += -I$(srctree)/drivers/media/dvb-core
ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
ccflags-y += -I$(srctree)/drivers/media/tuners
ccflags-y += -I$(srctree)/drivers/media/common
+ccflags-y += -I$(srctree)/drivers/staging/media/rtl2832u_sdr
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index db98f1c..61b420c 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -24,6 +24,7 @@
#include "rtl2830.h"
#include "rtl2832.h"
+#include "rtl2832_sdr.h"
#include "qt1010.h"
#include "mt2060.h"
@@ -902,6 +903,10 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
* that to the tuner driver */
adap->fe[0]->ops.read_signal_strength =
adap->fe[0]->ops.tuner_ops.get_rf_strength;
+
+ /* attach SDR */
+ dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
+ &rtl28xxu_rtl2832_fc0012_config, NULL);
return 0;
break;
case TUNER_RTL2832_FC0013:
@@ -911,8 +916,13 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
/* fc0013 also supports signal strength reading */
adap->fe[0]->ops.read_signal_strength =
adap->fe[0]->ops.tuner_ops.get_rf_strength;
+
+ /* attach SDR */
+ dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
+ &rtl28xxu_rtl2832_fc0013_config, NULL);
return 0;
case TUNER_RTL2832_E4000: {
+ struct v4l2_subdev *sd;
struct e4000_config e4000_config = {
.fe = adap->fe[0],
.clock = 28800000,
@@ -933,6 +943,12 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
}
priv->client = client;
+ sd = i2c_get_clientdata(client);
+
+ /* attach SDR */
+ dvb_attach(rtl2832_sdr_attach, adap->fe[0],
+ &d->i2c_adap,
+ &rtl28xxu_rtl2832_e4000_config, sd);
}
break;
case TUNER_RTL2832_FC2580:
@@ -959,6 +975,10 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
/* Use tuner to get the signal strength */
adap->fe[0]->ops.read_signal_strength =
adap->fe[0]->ops.tuner_ops.get_rf_strength;
+
+ /* attach SDR */
+ dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
+ &rtl28xxu_rtl2832_r820t_config, NULL);
break;
case TUNER_RTL2832_R828D:
/* power off mn88472 demod on GPIO0 */
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 09/17] rtl28xxu: fix switch-case style issue
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
` (7 preceding siblings ...)
2014-03-14 0:14 ` [PATCH 08/17] rtl28xxu: attach SDR extension module Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
2014-03-14 0:14 ` [PATCH 10/17] rtl28xxu: use muxed RTL2832 I2C adapters for E4000 and RTL2832_SDR Antti Palosaari
` (7 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Mauro Carvalho Chehab, Antti Palosaari
Use break, not return, for every case.
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index 61b420c..f51949e 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -907,7 +907,6 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
/* attach SDR */
dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
&rtl28xxu_rtl2832_fc0012_config, NULL);
- return 0;
break;
case TUNER_RTL2832_FC0013:
fe = dvb_attach(fc0013_attach, adap->fe[0],
@@ -920,7 +919,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
/* attach SDR */
dvb_attach(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
&rtl28xxu_rtl2832_fc0013_config, NULL);
- return 0;
+ break;
case TUNER_RTL2832_E4000: {
struct v4l2_subdev *sd;
struct e4000_config e4000_config = {
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 10/17] rtl28xxu: use muxed RTL2832 I2C adapters for E4000 and RTL2832_SDR
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
` (8 preceding siblings ...)
2014-03-14 0:14 ` [PATCH 09/17] rtl28xxu: fix switch-case style issue Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
2014-03-14 0:14 ` [PATCH 11/17] rtl28xxu: depends on I2C_MUX Antti Palosaari
` (6 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Mauro Carvalho Chehab, Antti Palosaari
RTL2832 driver provides muxed I2C adapters for tuner bus I2C gate
control. Pass those adapters to rtl2832_sdr and e4000 modules in order
to get rid of proprietary DVB .i2c_gate_ctrl() callback use.
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 10 ++++++++--
drivers/media/usb/dvb-usb-v2/rtl28xxu.h | 1 +
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index f51949e..c83c16c 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -774,6 +774,9 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
goto err;
}
+ /* RTL2832 I2C repeater */
+ priv->demod_i2c_adapter = rtl2832_get_i2c_adapter(adap->fe[0]);
+
/* set fe callback */
adap->fe[0]->callback = rtl2832u_frontend_callback;
@@ -922,6 +925,8 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
break;
case TUNER_RTL2832_E4000: {
struct v4l2_subdev *sd;
+ struct i2c_adapter *i2c_adap_internal =
+ rtl2832_get_private_i2c_adapter(adap->fe[0]);
struct e4000_config e4000_config = {
.fe = adap->fe[0],
.clock = 28800000,
@@ -932,7 +937,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
info.platform_data = &e4000_config;
request_module(info.type);
- client = i2c_new_device(&d->i2c_adap, &info);
+ client = i2c_new_device(priv->demod_i2c_adapter, &info);
if (client == NULL || client->dev.driver == NULL)
break;
@@ -943,10 +948,11 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
priv->client = client;
sd = i2c_get_clientdata(client);
+ i2c_set_adapdata(i2c_adap_internal, d);
/* attach SDR */
dvb_attach(rtl2832_sdr_attach, adap->fe[0],
- &d->i2c_adap,
+ i2c_adap_internal,
&rtl28xxu_rtl2832_e4000_config, sd);
}
break;
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
index 367aca1..a26cab1 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
@@ -55,6 +55,7 @@ struct rtl28xxu_priv {
u8 tuner;
char *tuner_name;
u8 page; /* integrated demod active register page */
+ struct i2c_adapter *demod_i2c_adapter;
bool rc_active;
struct i2c_client *client;
};
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 11/17] rtl28xxu: depends on I2C_MUX
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
` (9 preceding siblings ...)
2014-03-14 0:14 ` [PATCH 10/17] rtl28xxu: use muxed RTL2832 I2C adapters for E4000 and RTL2832_SDR Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
2014-03-24 18:08 ` How to build I2C_MUX in media_build as rtl28xxu depends on it ? Jan Hoogenraad
2014-03-14 0:14 ` [PATCH 12/17] e4000: get rid of DVB i2c_gate_ctrl() Antti Palosaari
` (5 subsequent siblings)
16 siblings, 1 reply; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Mauro Carvalho Chehab, Antti Palosaari
We need depend on I2C_MUX as rtl2832 demod used requires it.
All error/warnings:
warning: (DVB_USB_RTL28XXU) selects DVB_RTL2832 which has unmet direct dependencies (MEDIA_SUPPORT && DVB_CORE && I2C && I2C_MUX)
ERROR: "i2c_add_mux_adapter" [drivers/media/dvb-frontends/rtl2832.ko] undefined!
ERROR: "i2c_del_mux_adapter" [drivers/media/dvb-frontends/rtl2832.ko] undefined!
Reported-by: kbuild test robot <fengguang.wu@intel.com>
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/media/usb/dvb-usb-v2/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
index bfb7378..037e519 100644
--- a/drivers/media/usb/dvb-usb-v2/Kconfig
+++ b/drivers/media/usb/dvb-usb-v2/Kconfig
@@ -126,7 +126,7 @@ config DVB_USB_MXL111SF
config DVB_USB_RTL28XXU
tristate "Realtek RTL28xxU DVB USB support"
- depends on DVB_USB_V2
+ depends on DVB_USB_V2 && I2C_MUX
select DVB_RTL2830
select DVB_RTL2832
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* How to build I2C_MUX in media_build as rtl28xxu depends on it ?
2014-03-14 0:14 ` [PATCH 11/17] rtl28xxu: depends on I2C_MUX Antti Palosaari
@ 2014-03-24 18:08 ` Jan Hoogenraad
2014-03-24 19:31 ` Antti Palosaari
0 siblings, 1 reply; 20+ messages in thread
From: Jan Hoogenraad @ 2014-03-24 18:08 UTC (permalink / raw)
To: Antti Palosaari, linux-media; +Cc: Hans Verkuil
After recent changes, I cannot build rtl28xxu on systems with linux
2.6.32 or 3.2.0.
rtl28xxu is one of the few drivers depending on I2C_MUX.
Kconfig.kern lists I2C_MUX (correctly) as not in the kernel of the system.
I don't know if it is possible to load a new module for that.
Who can help me with this ?
Antti Palosaari wrote:
> We need depend on I2C_MUX as rtl2832 demod used requires it.
>
> All error/warnings:
> warning: (DVB_USB_RTL28XXU) selects DVB_RTL2832 which has unmet direct dependencies (MEDIA_SUPPORT && DVB_CORE && I2C && I2C_MUX)
> ERROR: "i2c_add_mux_adapter" [drivers/media/dvb-frontends/rtl2832.ko] undefined!
> ERROR: "i2c_del_mux_adapter" [drivers/media/dvb-frontends/rtl2832.ko] undefined!
>
> Reported-by: kbuild test robot <fengguang.wu@intel.com>
> Signed-off-by: Antti Palosaari <crope@iki.fi>
> ---
> drivers/media/usb/dvb-usb-v2/Kconfig | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
> index bfb7378..037e519 100644
> --- a/drivers/media/usb/dvb-usb-v2/Kconfig
> +++ b/drivers/media/usb/dvb-usb-v2/Kconfig
> @@ -126,7 +126,7 @@ config DVB_USB_MXL111SF
>
> config DVB_USB_RTL28XXU
> tristate "Realtek RTL28xxU DVB USB support"
> - depends on DVB_USB_V2
> + depends on DVB_USB_V2 && I2C_MUX
> select DVB_RTL2830
> select DVB_RTL2832
> select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
--
Jan Hoogenraad
Hoogenraad Interface Services
Postbus 2717
3500 GS Utrecht
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 12/17] e4000: get rid of DVB i2c_gate_ctrl()
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
` (10 preceding siblings ...)
2014-03-14 0:14 ` [PATCH 11/17] rtl28xxu: depends on I2C_MUX Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
2014-03-14 0:14 ` [PATCH 13/17] e4000: convert to Regmap API Antti Palosaari
` (4 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Mauro Carvalho Chehab, Antti Palosaari
Gate control is now implemented by rtl2832 I2C adapter so we do not
need proprietary DVB i2c_gate_ctrl() anymore.
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/media/tuners/e4000.c | 103 +++++++++----------------------------------
1 file changed, 21 insertions(+), 82 deletions(-)
diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c
index ed2f635..29f73f6 100644
--- a/drivers/media/tuners/e4000.c
+++ b/drivers/media/tuners/e4000.c
@@ -119,9 +119,6 @@ static int e4000_init(struct dvb_frontend *fe)
dev_dbg(&priv->client->dev, "%s:\n", __func__);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
/* dummy I2C to ensure I2C wakes up */
ret = e4000_wr_reg(priv, 0x02, 0x40);
@@ -178,17 +175,11 @@ static int e4000_init(struct dvb_frontend *fe)
if (ret < 0)
goto err;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
priv->active = true;
-
- return 0;
err:
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
+ if (ret)
+ dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
- dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
@@ -201,22 +192,13 @@ static int e4000_sleep(struct dvb_frontend *fe)
priv->active = false;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
ret = e4000_wr_reg(priv, 0x00, 0x00);
if (ret < 0)
goto err;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
- return 0;
err:
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
+ if (ret)
+ dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
- dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
@@ -233,9 +215,6 @@ static int e4000_set_params(struct dvb_frontend *fe)
__func__, c->delivery_system, c->frequency,
c->bandwidth_hz);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
/* gain control manual */
ret = e4000_wr_reg(priv, 0x1a, 0x00);
if (ret < 0)
@@ -361,16 +340,10 @@ static int e4000_set_params(struct dvb_frontend *fe)
ret = e4000_wr_reg(priv, 0x1a, 0x17);
if (ret < 0)
goto err;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
- return 0;
err:
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
+ if (ret)
+ dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
- dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
@@ -390,14 +363,12 @@ static int e4000_set_lna_gain(struct dvb_frontend *fe)
struct e4000_priv *priv = fe->tuner_priv;
int ret;
u8 u8tmp;
+
dev_dbg(&priv->client->dev, "%s: lna auto=%d->%d val=%d->%d\n",
__func__, priv->lna_gain_auto->cur.val,
priv->lna_gain_auto->val, priv->lna_gain->cur.val,
priv->lna_gain->val);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
if (priv->lna_gain_auto->val && priv->if_gain_auto->cur.val)
u8tmp = 0x17;
else if (priv->lna_gain_auto->val)
@@ -416,16 +387,10 @@ static int e4000_set_lna_gain(struct dvb_frontend *fe)
if (ret)
goto err;
}
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
- return 0;
err:
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
+ if (ret)
+ dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
- dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
@@ -434,14 +399,12 @@ static int e4000_set_mixer_gain(struct dvb_frontend *fe)
struct e4000_priv *priv = fe->tuner_priv;
int ret;
u8 u8tmp;
+
dev_dbg(&priv->client->dev, "%s: mixer auto=%d->%d val=%d->%d\n",
__func__, priv->mixer_gain_auto->cur.val,
priv->mixer_gain_auto->val, priv->mixer_gain->cur.val,
priv->mixer_gain->val);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
if (priv->mixer_gain_auto->val)
u8tmp = 0x15;
else
@@ -456,16 +419,10 @@ static int e4000_set_mixer_gain(struct dvb_frontend *fe)
if (ret)
goto err;
}
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
- return 0;
err:
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
+ if (ret)
+ dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
- dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
@@ -475,14 +432,12 @@ static int e4000_set_if_gain(struct dvb_frontend *fe)
int ret;
u8 buf[2];
u8 u8tmp;
+
dev_dbg(&priv->client->dev, "%s: if auto=%d->%d val=%d->%d\n",
__func__, priv->if_gain_auto->cur.val,
priv->if_gain_auto->val, priv->if_gain->cur.val,
priv->if_gain->val);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
if (priv->if_gain_auto->val && priv->lna_gain_auto->cur.val)
u8tmp = 0x17;
else if (priv->lna_gain_auto->cur.val)
@@ -503,16 +458,10 @@ static int e4000_set_if_gain(struct dvb_frontend *fe)
if (ret)
goto err;
}
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
- return 0;
err:
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
+ if (ret)
+ dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
- dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
@@ -525,18 +474,12 @@ static int e4000_pll_lock(struct dvb_frontend *fe)
if (priv->active == false)
return 0;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
ret = e4000_rd_reg(priv, 0x07, &u8tmp);
if (ret)
goto err;
priv->pll_lock->val = (u8tmp & 0x01);
err:
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
if (ret)
dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
@@ -567,6 +510,7 @@ static int e4000_s_ctrl(struct v4l2_ctrl *ctrl)
struct dvb_frontend *fe = priv->fe;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
+
dev_dbg(&priv->client->dev,
"%s: id=%d name=%s val=%d min=%d max=%d step=%d\n",
__func__, ctrl->id, ctrl->name, ctrl->val,
@@ -629,9 +573,6 @@ static int e4000_probe(struct i2c_client *client,
int ret;
u8 chip_id;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
priv = kzalloc(sizeof(struct e4000_priv), GFP_KERNEL);
if (!priv) {
ret = -ENOMEM;
@@ -705,16 +646,13 @@ static int e4000_probe(struct i2c_client *client,
v4l2_set_subdevdata(&priv->sd, client);
i2c_set_clientdata(client, &priv->sd);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
return 0;
err:
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
+ if (ret) {
+ dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
+ kfree(priv);
+ }
- dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
- kfree(priv);
return ret;
}
@@ -725,6 +663,7 @@ static int e4000_remove(struct i2c_client *client)
struct dvb_frontend *fe = priv->fe;
dev_dbg(&client->dev, "%s:\n", __func__);
+
v4l2_ctrl_handler_free(&priv->hdl);
memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
fe->tuner_priv = NULL;
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 13/17] e4000: convert to Regmap API
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
` (11 preceding siblings ...)
2014-03-14 0:14 ` [PATCH 12/17] e4000: get rid of DVB i2c_gate_ctrl() Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
2014-03-14 0:14 ` [PATCH 14/17] e4000: rename some variables Antti Palosaari
` (3 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Mauro Carvalho Chehab, Antti Palosaari
That comes possible after driver was converted to kernel I2C model
(I2C binding & proper I2C client with no gate control hack). All
nasty low level I2C routines are now covered by regmap.
Cc: Mauro Carvalho Chehab <m.chehab@samsung.com>
Cc: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/media/tuners/Kconfig | 1 +
drivers/media/tuners/e4000.c | 212 ++++++++++++--------------------------
drivers/media/tuners/e4000_priv.h | 2 +
3 files changed, 68 insertions(+), 147 deletions(-)
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
index 3b95392..85c0d96 100644
--- a/drivers/media/tuners/Kconfig
+++ b/drivers/media/tuners/Kconfig
@@ -204,6 +204,7 @@ config MEDIA_TUNER_TDA18212
config MEDIA_TUNER_E4000
tristate "Elonics E4000 silicon tuner"
depends on MEDIA_SUPPORT && I2C && VIDEO_V4L2
+ select REGMAP_I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Elonics E4000 silicon tuner driver.
diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c
index 29f73f6..f382b90 100644
--- a/drivers/media/tuners/e4000.c
+++ b/drivers/media/tuners/e4000.c
@@ -21,97 +21,6 @@
#include "e4000_priv.h"
#include <linux/math64.h>
-/* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE 64
-
-/* write multiple registers */
-static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
-{
- int ret;
- u8 buf[MAX_XFER_SIZE];
- struct i2c_msg msg[1] = {
- {
- .addr = priv->client->addr,
- .flags = 0,
- .len = 1 + len,
- .buf = buf,
- }
- };
-
- if (1 + len > sizeof(buf)) {
- dev_warn(&priv->client->dev,
- "%s: i2c wr reg=%04x: len=%d is too big!\n",
- KBUILD_MODNAME, reg, len);
- return -EINVAL;
- }
-
- buf[0] = reg;
- memcpy(&buf[1], val, len);
-
- ret = i2c_transfer(priv->client->adapter, msg, 1);
- if (ret == 1) {
- ret = 0;
- } else {
- dev_warn(&priv->client->dev,
- "%s: i2c wr failed=%d reg=%02x len=%d\n",
- KBUILD_MODNAME, ret, reg, len);
- ret = -EREMOTEIO;
- }
- return ret;
-}
-
-/* read multiple registers */
-static int e4000_rd_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
-{
- int ret;
- u8 buf[MAX_XFER_SIZE];
- struct i2c_msg msg[2] = {
- {
- .addr = priv->client->addr,
- .flags = 0,
- .len = 1,
- .buf = ®,
- }, {
- .addr = priv->client->addr,
- .flags = I2C_M_RD,
- .len = len,
- .buf = buf,
- }
- };
-
- if (len > sizeof(buf)) {
- dev_warn(&priv->client->dev,
- "%s: i2c rd reg=%04x: len=%d is too big!\n",
- KBUILD_MODNAME, reg, len);
- return -EINVAL;
- }
-
- ret = i2c_transfer(priv->client->adapter, msg, 2);
- if (ret == 2) {
- memcpy(val, buf, len);
- ret = 0;
- } else {
- dev_warn(&priv->client->dev,
- "%s: i2c rd failed=%d reg=%02x len=%d\n",
- KBUILD_MODNAME, ret, reg, len);
- ret = -EREMOTEIO;
- }
-
- return ret;
-}
-
-/* write single register */
-static int e4000_wr_reg(struct e4000_priv *priv, u8 reg, u8 val)
-{
- return e4000_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-static int e4000_rd_reg(struct e4000_priv *priv, u8 reg, u8 *val)
-{
- return e4000_rd_regs(priv, reg, val, 1);
-}
-
static int e4000_init(struct dvb_frontend *fe)
{
struct e4000_priv *priv = fe->tuner_priv;
@@ -120,58 +29,58 @@ static int e4000_init(struct dvb_frontend *fe)
dev_dbg(&priv->client->dev, "%s:\n", __func__);
/* dummy I2C to ensure I2C wakes up */
- ret = e4000_wr_reg(priv, 0x02, 0x40);
+ ret = regmap_write(priv->regmap, 0x02, 0x40);
/* reset */
- ret = e4000_wr_reg(priv, 0x00, 0x01);
+ ret = regmap_write(priv->regmap, 0x00, 0x01);
if (ret < 0)
goto err;
/* disable output clock */
- ret = e4000_wr_reg(priv, 0x06, 0x00);
+ ret = regmap_write(priv->regmap, 0x06, 0x00);
if (ret < 0)
goto err;
- ret = e4000_wr_reg(priv, 0x7a, 0x96);
+ ret = regmap_write(priv->regmap, 0x7a, 0x96);
if (ret < 0)
goto err;
/* configure gains */
- ret = e4000_wr_regs(priv, 0x7e, "\x01\xfe", 2);
+ ret = regmap_bulk_write(priv->regmap, 0x7e, "\x01\xfe", 2);
if (ret < 0)
goto err;
- ret = e4000_wr_reg(priv, 0x82, 0x00);
+ ret = regmap_write(priv->regmap, 0x82, 0x00);
if (ret < 0)
goto err;
- ret = e4000_wr_reg(priv, 0x24, 0x05);
+ ret = regmap_write(priv->regmap, 0x24, 0x05);
if (ret < 0)
goto err;
- ret = e4000_wr_regs(priv, 0x87, "\x20\x01", 2);
+ ret = regmap_bulk_write(priv->regmap, 0x87, "\x20\x01", 2);
if (ret < 0)
goto err;
- ret = e4000_wr_regs(priv, 0x9f, "\x7f\x07", 2);
+ ret = regmap_bulk_write(priv->regmap, 0x9f, "\x7f\x07", 2);
if (ret < 0)
goto err;
/* DC offset control */
- ret = e4000_wr_reg(priv, 0x2d, 0x1f);
+ ret = regmap_write(priv->regmap, 0x2d, 0x1f);
if (ret < 0)
goto err;
- ret = e4000_wr_regs(priv, 0x70, "\x01\x01", 2);
+ ret = regmap_bulk_write(priv->regmap, 0x70, "\x01\x01", 2);
if (ret < 0)
goto err;
/* gain control */
- ret = e4000_wr_reg(priv, 0x1a, 0x17);
+ ret = regmap_write(priv->regmap, 0x1a, 0x17);
if (ret < 0)
goto err;
- ret = e4000_wr_reg(priv, 0x1f, 0x1a);
+ ret = regmap_write(priv->regmap, 0x1f, 0x1a);
if (ret < 0)
goto err;
@@ -192,7 +101,7 @@ static int e4000_sleep(struct dvb_frontend *fe)
priv->active = false;
- ret = e4000_wr_reg(priv, 0x00, 0x00);
+ ret = regmap_write(priv->regmap, 0x00, 0x00);
if (ret < 0)
goto err;
err:
@@ -216,7 +125,7 @@ static int e4000_set_params(struct dvb_frontend *fe)
c->bandwidth_hz);
/* gain control manual */
- ret = e4000_wr_reg(priv, 0x1a, 0x00);
+ ret = regmap_write(priv->regmap, 0x1a, 0x00);
if (ret < 0)
goto err;
@@ -243,7 +152,7 @@ static int e4000_set_params(struct dvb_frontend *fe)
"%s: f_vco=%llu pll div=%d sigma_delta=%04x\n",
__func__, f_vco, buf[0], sigma_delta);
- ret = e4000_wr_regs(priv, 0x09, buf, 5);
+ ret = regmap_bulk_write(priv->regmap, 0x09, buf, 5);
if (ret < 0)
goto err;
@@ -258,7 +167,7 @@ static int e4000_set_params(struct dvb_frontend *fe)
goto err;
}
- ret = e4000_wr_reg(priv, 0x10, e400_lna_filter_lut[i].val);
+ ret = regmap_write(priv->regmap, 0x10, e400_lna_filter_lut[i].val);
if (ret < 0)
goto err;
@@ -276,7 +185,7 @@ static int e4000_set_params(struct dvb_frontend *fe)
buf[0] = e4000_if_filter_lut[i].reg11_val;
buf[1] = e4000_if_filter_lut[i].reg12_val;
- ret = e4000_wr_regs(priv, 0x11, buf, 2);
+ ret = regmap_bulk_write(priv->regmap, 0x11, buf, 2);
if (ret < 0)
goto err;
@@ -291,33 +200,33 @@ static int e4000_set_params(struct dvb_frontend *fe)
goto err;
}
- ret = e4000_wr_reg(priv, 0x07, e4000_band_lut[i].reg07_val);
+ ret = regmap_write(priv->regmap, 0x07, e4000_band_lut[i].reg07_val);
if (ret < 0)
goto err;
- ret = e4000_wr_reg(priv, 0x78, e4000_band_lut[i].reg78_val);
+ ret = regmap_write(priv->regmap, 0x78, e4000_band_lut[i].reg78_val);
if (ret < 0)
goto err;
/* DC offset */
for (i = 0; i < 4; i++) {
if (i == 0)
- ret = e4000_wr_regs(priv, 0x15, "\x00\x7e\x24", 3);
+ ret = regmap_bulk_write(priv->regmap, 0x15, "\x00\x7e\x24", 3);
else if (i == 1)
- ret = e4000_wr_regs(priv, 0x15, "\x00\x7f", 2);
+ ret = regmap_bulk_write(priv->regmap, 0x15, "\x00\x7f", 2);
else if (i == 2)
- ret = e4000_wr_regs(priv, 0x15, "\x01", 1);
+ ret = regmap_bulk_write(priv->regmap, 0x15, "\x01", 1);
else
- ret = e4000_wr_regs(priv, 0x16, "\x7e", 1);
+ ret = regmap_bulk_write(priv->regmap, 0x16, "\x7e", 1);
if (ret < 0)
goto err;
- ret = e4000_wr_reg(priv, 0x29, 0x01);
+ ret = regmap_write(priv->regmap, 0x29, 0x01);
if (ret < 0)
goto err;
- ret = e4000_rd_regs(priv, 0x2a, buf, 3);
+ ret = regmap_bulk_read(priv->regmap, 0x2a, buf, 3);
if (ret < 0)
goto err;
@@ -328,16 +237,16 @@ static int e4000_set_params(struct dvb_frontend *fe)
swap(q_data[2], q_data[3]);
swap(i_data[2], i_data[3]);
- ret = e4000_wr_regs(priv, 0x50, q_data, 4);
+ ret = regmap_bulk_write(priv->regmap, 0x50, q_data, 4);
if (ret < 0)
goto err;
- ret = e4000_wr_regs(priv, 0x60, i_data, 4);
+ ret = regmap_bulk_write(priv->regmap, 0x60, i_data, 4);
if (ret < 0)
goto err;
/* gain control auto */
- ret = e4000_wr_reg(priv, 0x1a, 0x17);
+ ret = regmap_write(priv->regmap, 0x1a, 0x17);
if (ret < 0)
goto err;
err:
@@ -378,12 +287,12 @@ static int e4000_set_lna_gain(struct dvb_frontend *fe)
else
u8tmp = 0x10;
- ret = e4000_wr_reg(priv, 0x1a, u8tmp);
+ ret = regmap_write(priv->regmap, 0x1a, u8tmp);
if (ret)
goto err;
if (priv->lna_gain_auto->val == false) {
- ret = e4000_wr_reg(priv, 0x14, priv->lna_gain->val);
+ ret = regmap_write(priv->regmap, 0x14, priv->lna_gain->val);
if (ret)
goto err;
}
@@ -410,12 +319,12 @@ static int e4000_set_mixer_gain(struct dvb_frontend *fe)
else
u8tmp = 0x14;
- ret = e4000_wr_reg(priv, 0x20, u8tmp);
+ ret = regmap_write(priv->regmap, 0x20, u8tmp);
if (ret)
goto err;
if (priv->mixer_gain_auto->val == false) {
- ret = e4000_wr_reg(priv, 0x15, priv->mixer_gain->val);
+ ret = regmap_write(priv->regmap, 0x15, priv->mixer_gain->val);
if (ret)
goto err;
}
@@ -447,14 +356,14 @@ static int e4000_set_if_gain(struct dvb_frontend *fe)
else
u8tmp = 0x10;
- ret = e4000_wr_reg(priv, 0x1a, u8tmp);
+ ret = regmap_write(priv->regmap, 0x1a, u8tmp);
if (ret)
goto err;
if (priv->if_gain_auto->val == false) {
buf[0] = e4000_if_gain_lut[priv->if_gain->val].reg16_val;
buf[1] = e4000_if_gain_lut[priv->if_gain->val].reg17_val;
- ret = e4000_wr_regs(priv, 0x16, buf, 2);
+ ret = regmap_bulk_write(priv->regmap, 0x16, buf, 2);
if (ret)
goto err;
}
@@ -469,16 +378,13 @@ static int e4000_pll_lock(struct dvb_frontend *fe)
{
struct e4000_priv *priv = fe->tuner_priv;
int ret;
- u8 u8tmp;
+ unsigned int utmp;
- if (priv->active == false)
- return 0;
-
- ret = e4000_rd_reg(priv, 0x07, &u8tmp);
- if (ret)
+ ret = regmap_read(priv->regmap, 0x07, &utmp);
+ if (ret < 0)
goto err;
- priv->pll_lock->val = (u8tmp & 0x01);
+ priv->pll_lock->val = (utmp & 0x01);
err:
if (ret)
dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
@@ -488,15 +394,19 @@ err:
static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
- struct e4000_priv *priv =
- container_of(ctrl->handler, struct e4000_priv, hdl);
+ struct e4000_priv *priv = container_of(ctrl->handler, struct e4000_priv, hdl);
int ret;
+ if (priv->active == false)
+ return 0;
+
switch (ctrl->id) {
case V4L2_CID_RF_TUNER_PLL_LOCK:
ret = e4000_pll_lock(priv->fe);
break;
default:
+ dev_dbg(&priv->client->dev, "%s: unknown ctrl: id=%d name=%s\n",
+ __func__, ctrl->id, ctrl->name);
ret = -EINVAL;
}
@@ -505,16 +415,13 @@ static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
static int e4000_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct e4000_priv *priv =
- container_of(ctrl->handler, struct e4000_priv, hdl);
+ struct e4000_priv *priv = container_of(ctrl->handler, struct e4000_priv, hdl);
struct dvb_frontend *fe = priv->fe;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
- dev_dbg(&priv->client->dev,
- "%s: id=%d name=%s val=%d min=%d max=%d step=%d\n",
- __func__, ctrl->id, ctrl->name, ctrl->val,
- ctrl->minimum, ctrl->maximum, ctrl->step);
+ if (priv->active == false)
+ return 0;
switch (ctrl->id) {
case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
@@ -535,6 +442,8 @@ static int e4000_s_ctrl(struct v4l2_ctrl *ctrl)
ret = e4000_set_if_gain(priv->fe);
break;
default:
+ dev_dbg(&priv->client->dev, "%s: unknown ctrl: id=%d name=%s\n",
+ __func__, ctrl->id, ctrl->name);
ret = -EINVAL;
}
@@ -571,7 +480,12 @@ static int e4000_probe(struct i2c_client *client,
struct dvb_frontend *fe = cfg->fe;
struct e4000_priv *priv;
int ret;
- u8 chip_id;
+ unsigned int utmp;
+ static const struct regmap_config regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xff,
+ };
priv = kzalloc(sizeof(struct e4000_priv), GFP_KERNEL);
if (!priv) {
@@ -583,22 +497,26 @@ static int e4000_probe(struct i2c_client *client,
priv->clock = cfg->clock;
priv->client = client;
priv->fe = cfg->fe;
+ priv->regmap = devm_regmap_init_i2c(client, ®map_config);
+ if (IS_ERR(priv->regmap)) {
+ ret = PTR_ERR(priv->regmap);
+ goto err;
+ }
/* check if the tuner is there */
- ret = e4000_rd_reg(priv, 0x02, &chip_id);
+ ret = regmap_read(priv->regmap, 0x02, &utmp);
if (ret < 0)
goto err;
- dev_dbg(&priv->client->dev,
- "%s: chip_id=%02x\n", __func__, chip_id);
+ dev_dbg(&priv->client->dev, "%s: chip id=%02x\n", __func__, utmp);
- if (chip_id != 0x40) {
+ if (utmp != 0x40) {
ret = -ENODEV;
goto err;
}
/* put sleep as chip seems to be in normal mode by default */
- ret = e4000_wr_reg(priv, 0x00, 0x00);
+ ret = regmap_write(priv->regmap, 0x00, 0x00);
if (ret < 0)
goto err;
diff --git a/drivers/media/tuners/e4000_priv.h b/drivers/media/tuners/e4000_priv.h
index 3ddd980..e772b00 100644
--- a/drivers/media/tuners/e4000_priv.h
+++ b/drivers/media/tuners/e4000_priv.h
@@ -24,9 +24,11 @@
#include "e4000.h"
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
+#include <linux/regmap.h>
struct e4000_priv {
struct i2c_client *client;
+ struct regmap *regmap;
u32 clock;
struct dvb_frontend *fe;
struct v4l2_subdev sd;
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 14/17] e4000: rename some variables
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
` (12 preceding siblings ...)
2014-03-14 0:14 ` [PATCH 13/17] e4000: convert to Regmap API Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
2014-03-14 0:14 ` [PATCH 15/17] rtl2832_sdr: fixing v4l2-compliance issues Antti Palosaari
` (2 subsequent siblings)
16 siblings, 0 replies; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Mauro Carvalho Chehab, Antti Palosaari
Rename some variables.
Change error status checks from (ret < 0) to (ret).
No actual functionality changes.
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/media/tuners/e4000.c | 332 +++++++++++++++++++-------------------
drivers/media/tuners/e4000_priv.h | 2 +-
2 files changed, 167 insertions(+), 167 deletions(-)
diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c
index f382b90..3b52550 100644
--- a/drivers/media/tuners/e4000.c
+++ b/drivers/media/tuners/e4000.c
@@ -23,110 +23,110 @@
static int e4000_init(struct dvb_frontend *fe)
{
- struct e4000_priv *priv = fe->tuner_priv;
+ struct e4000 *s = fe->tuner_priv;
int ret;
- dev_dbg(&priv->client->dev, "%s:\n", __func__);
+ dev_dbg(&s->client->dev, "%s:\n", __func__);
/* dummy I2C to ensure I2C wakes up */
- ret = regmap_write(priv->regmap, 0x02, 0x40);
+ ret = regmap_write(s->regmap, 0x02, 0x40);
/* reset */
- ret = regmap_write(priv->regmap, 0x00, 0x01);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x00, 0x01);
+ if (ret)
goto err;
/* disable output clock */
- ret = regmap_write(priv->regmap, 0x06, 0x00);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x06, 0x00);
+ if (ret)
goto err;
- ret = regmap_write(priv->regmap, 0x7a, 0x96);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x7a, 0x96);
+ if (ret)
goto err;
/* configure gains */
- ret = regmap_bulk_write(priv->regmap, 0x7e, "\x01\xfe", 2);
- if (ret < 0)
+ ret = regmap_bulk_write(s->regmap, 0x7e, "\x01\xfe", 2);
+ if (ret)
goto err;
- ret = regmap_write(priv->regmap, 0x82, 0x00);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x82, 0x00);
+ if (ret)
goto err;
- ret = regmap_write(priv->regmap, 0x24, 0x05);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x24, 0x05);
+ if (ret)
goto err;
- ret = regmap_bulk_write(priv->regmap, 0x87, "\x20\x01", 2);
- if (ret < 0)
+ ret = regmap_bulk_write(s->regmap, 0x87, "\x20\x01", 2);
+ if (ret)
goto err;
- ret = regmap_bulk_write(priv->regmap, 0x9f, "\x7f\x07", 2);
- if (ret < 0)
+ ret = regmap_bulk_write(s->regmap, 0x9f, "\x7f\x07", 2);
+ if (ret)
goto err;
/* DC offset control */
- ret = regmap_write(priv->regmap, 0x2d, 0x1f);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x2d, 0x1f);
+ if (ret)
goto err;
- ret = regmap_bulk_write(priv->regmap, 0x70, "\x01\x01", 2);
- if (ret < 0)
+ ret = regmap_bulk_write(s->regmap, 0x70, "\x01\x01", 2);
+ if (ret)
goto err;
/* gain control */
- ret = regmap_write(priv->regmap, 0x1a, 0x17);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x1a, 0x17);
+ if (ret)
goto err;
- ret = regmap_write(priv->regmap, 0x1f, 0x1a);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x1f, 0x1a);
+ if (ret)
goto err;
- priv->active = true;
+ s->active = true;
err:
if (ret)
- dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
static int e4000_sleep(struct dvb_frontend *fe)
{
- struct e4000_priv *priv = fe->tuner_priv;
+ struct e4000 *s = fe->tuner_priv;
int ret;
- dev_dbg(&priv->client->dev, "%s:\n", __func__);
+ dev_dbg(&s->client->dev, "%s:\n", __func__);
- priv->active = false;
+ s->active = false;
- ret = regmap_write(priv->regmap, 0x00, 0x00);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x00, 0x00);
+ if (ret)
goto err;
err:
if (ret)
- dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
static int e4000_set_params(struct dvb_frontend *fe)
{
- struct e4000_priv *priv = fe->tuner_priv;
+ struct e4000 *s = fe->tuner_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i, sigma_delta;
u64 f_vco;
u8 buf[5], i_data[4], q_data[4];
- dev_dbg(&priv->client->dev,
+ dev_dbg(&s->client->dev,
"%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n",
__func__, c->delivery_system, c->frequency,
c->bandwidth_hz);
/* gain control manual */
- ret = regmap_write(priv->regmap, 0x1a, 0x00);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x1a, 0x00);
+ if (ret)
goto err;
/* PLL */
@@ -141,19 +141,19 @@ static int e4000_set_params(struct dvb_frontend *fe)
}
f_vco = 1ull * c->frequency * e4000_pll_lut[i].mul;
- sigma_delta = div_u64(0x10000ULL * (f_vco % priv->clock), priv->clock);
- buf[0] = div_u64(f_vco, priv->clock);
+ sigma_delta = div_u64(0x10000ULL * (f_vco % s->clock), s->clock);
+ buf[0] = div_u64(f_vco, s->clock);
buf[1] = (sigma_delta >> 0) & 0xff;
buf[2] = (sigma_delta >> 8) & 0xff;
buf[3] = 0x00;
buf[4] = e4000_pll_lut[i].div;
- dev_dbg(&priv->client->dev,
+ dev_dbg(&s->client->dev,
"%s: f_vco=%llu pll div=%d sigma_delta=%04x\n",
__func__, f_vco, buf[0], sigma_delta);
- ret = regmap_bulk_write(priv->regmap, 0x09, buf, 5);
- if (ret < 0)
+ ret = regmap_bulk_write(s->regmap, 0x09, buf, 5);
+ if (ret)
goto err;
/* LNA filter (RF filter) */
@@ -167,8 +167,8 @@ static int e4000_set_params(struct dvb_frontend *fe)
goto err;
}
- ret = regmap_write(priv->regmap, 0x10, e400_lna_filter_lut[i].val);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x10, e400_lna_filter_lut[i].val);
+ if (ret)
goto err;
/* IF filters */
@@ -185,8 +185,8 @@ static int e4000_set_params(struct dvb_frontend *fe)
buf[0] = e4000_if_filter_lut[i].reg11_val;
buf[1] = e4000_if_filter_lut[i].reg12_val;
- ret = regmap_bulk_write(priv->regmap, 0x11, buf, 2);
- if (ret < 0)
+ ret = regmap_bulk_write(s->regmap, 0x11, buf, 2);
+ if (ret)
goto err;
/* frequency band */
@@ -200,34 +200,34 @@ static int e4000_set_params(struct dvb_frontend *fe)
goto err;
}
- ret = regmap_write(priv->regmap, 0x07, e4000_band_lut[i].reg07_val);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x07, e4000_band_lut[i].reg07_val);
+ if (ret)
goto err;
- ret = regmap_write(priv->regmap, 0x78, e4000_band_lut[i].reg78_val);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x78, e4000_band_lut[i].reg78_val);
+ if (ret)
goto err;
/* DC offset */
for (i = 0; i < 4; i++) {
if (i == 0)
- ret = regmap_bulk_write(priv->regmap, 0x15, "\x00\x7e\x24", 3);
+ ret = regmap_bulk_write(s->regmap, 0x15, "\x00\x7e\x24", 3);
else if (i == 1)
- ret = regmap_bulk_write(priv->regmap, 0x15, "\x00\x7f", 2);
+ ret = regmap_bulk_write(s->regmap, 0x15, "\x00\x7f", 2);
else if (i == 2)
- ret = regmap_bulk_write(priv->regmap, 0x15, "\x01", 1);
+ ret = regmap_bulk_write(s->regmap, 0x15, "\x01", 1);
else
- ret = regmap_bulk_write(priv->regmap, 0x16, "\x7e", 1);
+ ret = regmap_bulk_write(s->regmap, 0x16, "\x7e", 1);
- if (ret < 0)
+ if (ret)
goto err;
- ret = regmap_write(priv->regmap, 0x29, 0x01);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x29, 0x01);
+ if (ret)
goto err;
- ret = regmap_bulk_read(priv->regmap, 0x2a, buf, 3);
- if (ret < 0)
+ ret = regmap_bulk_read(s->regmap, 0x2a, buf, 3);
+ if (ret)
goto err;
i_data[i] = (((buf[2] >> 0) & 0x3) << 6) | (buf[0] & 0x3f);
@@ -237,30 +237,30 @@ static int e4000_set_params(struct dvb_frontend *fe)
swap(q_data[2], q_data[3]);
swap(i_data[2], i_data[3]);
- ret = regmap_bulk_write(priv->regmap, 0x50, q_data, 4);
- if (ret < 0)
+ ret = regmap_bulk_write(s->regmap, 0x50, q_data, 4);
+ if (ret)
goto err;
- ret = regmap_bulk_write(priv->regmap, 0x60, i_data, 4);
- if (ret < 0)
+ ret = regmap_bulk_write(s->regmap, 0x60, i_data, 4);
+ if (ret)
goto err;
/* gain control auto */
- ret = regmap_write(priv->regmap, 0x1a, 0x17);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x1a, 0x17);
+ if (ret)
goto err;
err:
if (ret)
- dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
static int e4000_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
{
- struct e4000_priv *priv = fe->tuner_priv;
+ struct e4000 *s = fe->tuner_priv;
- dev_dbg(&priv->client->dev, "%s:\n", __func__);
+ dev_dbg(&s->client->dev, "%s:\n", __func__);
*frequency = 0; /* Zero-IF */
@@ -269,143 +269,143 @@ static int e4000_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
static int e4000_set_lna_gain(struct dvb_frontend *fe)
{
- struct e4000_priv *priv = fe->tuner_priv;
+ struct e4000 *s = fe->tuner_priv;
int ret;
u8 u8tmp;
- dev_dbg(&priv->client->dev, "%s: lna auto=%d->%d val=%d->%d\n",
- __func__, priv->lna_gain_auto->cur.val,
- priv->lna_gain_auto->val, priv->lna_gain->cur.val,
- priv->lna_gain->val);
+ dev_dbg(&s->client->dev, "%s: lna auto=%d->%d val=%d->%d\n",
+ __func__, s->lna_gain_auto->cur.val,
+ s->lna_gain_auto->val, s->lna_gain->cur.val,
+ s->lna_gain->val);
- if (priv->lna_gain_auto->val && priv->if_gain_auto->cur.val)
+ if (s->lna_gain_auto->val && s->if_gain_auto->cur.val)
u8tmp = 0x17;
- else if (priv->lna_gain_auto->val)
+ else if (s->lna_gain_auto->val)
u8tmp = 0x19;
- else if (priv->if_gain_auto->cur.val)
+ else if (s->if_gain_auto->cur.val)
u8tmp = 0x16;
else
u8tmp = 0x10;
- ret = regmap_write(priv->regmap, 0x1a, u8tmp);
+ ret = regmap_write(s->regmap, 0x1a, u8tmp);
if (ret)
goto err;
- if (priv->lna_gain_auto->val == false) {
- ret = regmap_write(priv->regmap, 0x14, priv->lna_gain->val);
+ if (s->lna_gain_auto->val == false) {
+ ret = regmap_write(s->regmap, 0x14, s->lna_gain->val);
if (ret)
goto err;
}
err:
if (ret)
- dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
static int e4000_set_mixer_gain(struct dvb_frontend *fe)
{
- struct e4000_priv *priv = fe->tuner_priv;
+ struct e4000 *s = fe->tuner_priv;
int ret;
u8 u8tmp;
- dev_dbg(&priv->client->dev, "%s: mixer auto=%d->%d val=%d->%d\n",
- __func__, priv->mixer_gain_auto->cur.val,
- priv->mixer_gain_auto->val, priv->mixer_gain->cur.val,
- priv->mixer_gain->val);
+ dev_dbg(&s->client->dev, "%s: mixer auto=%d->%d val=%d->%d\n",
+ __func__, s->mixer_gain_auto->cur.val,
+ s->mixer_gain_auto->val, s->mixer_gain->cur.val,
+ s->mixer_gain->val);
- if (priv->mixer_gain_auto->val)
+ if (s->mixer_gain_auto->val)
u8tmp = 0x15;
else
u8tmp = 0x14;
- ret = regmap_write(priv->regmap, 0x20, u8tmp);
+ ret = regmap_write(s->regmap, 0x20, u8tmp);
if (ret)
goto err;
- if (priv->mixer_gain_auto->val == false) {
- ret = regmap_write(priv->regmap, 0x15, priv->mixer_gain->val);
+ if (s->mixer_gain_auto->val == false) {
+ ret = regmap_write(s->regmap, 0x15, s->mixer_gain->val);
if (ret)
goto err;
}
err:
if (ret)
- dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
static int e4000_set_if_gain(struct dvb_frontend *fe)
{
- struct e4000_priv *priv = fe->tuner_priv;
+ struct e4000 *s = fe->tuner_priv;
int ret;
u8 buf[2];
u8 u8tmp;
- dev_dbg(&priv->client->dev, "%s: if auto=%d->%d val=%d->%d\n",
- __func__, priv->if_gain_auto->cur.val,
- priv->if_gain_auto->val, priv->if_gain->cur.val,
- priv->if_gain->val);
+ dev_dbg(&s->client->dev, "%s: if auto=%d->%d val=%d->%d\n",
+ __func__, s->if_gain_auto->cur.val,
+ s->if_gain_auto->val, s->if_gain->cur.val,
+ s->if_gain->val);
- if (priv->if_gain_auto->val && priv->lna_gain_auto->cur.val)
+ if (s->if_gain_auto->val && s->lna_gain_auto->cur.val)
u8tmp = 0x17;
- else if (priv->lna_gain_auto->cur.val)
+ else if (s->lna_gain_auto->cur.val)
u8tmp = 0x19;
- else if (priv->if_gain_auto->val)
+ else if (s->if_gain_auto->val)
u8tmp = 0x16;
else
u8tmp = 0x10;
- ret = regmap_write(priv->regmap, 0x1a, u8tmp);
+ ret = regmap_write(s->regmap, 0x1a, u8tmp);
if (ret)
goto err;
- if (priv->if_gain_auto->val == false) {
- buf[0] = e4000_if_gain_lut[priv->if_gain->val].reg16_val;
- buf[1] = e4000_if_gain_lut[priv->if_gain->val].reg17_val;
- ret = regmap_bulk_write(priv->regmap, 0x16, buf, 2);
+ if (s->if_gain_auto->val == false) {
+ buf[0] = e4000_if_gain_lut[s->if_gain->val].reg16_val;
+ buf[1] = e4000_if_gain_lut[s->if_gain->val].reg17_val;
+ ret = regmap_bulk_write(s->regmap, 0x16, buf, 2);
if (ret)
goto err;
}
err:
if (ret)
- dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
static int e4000_pll_lock(struct dvb_frontend *fe)
{
- struct e4000_priv *priv = fe->tuner_priv;
+ struct e4000 *s = fe->tuner_priv;
int ret;
unsigned int utmp;
- ret = regmap_read(priv->regmap, 0x07, &utmp);
- if (ret < 0)
+ ret = regmap_read(s->regmap, 0x07, &utmp);
+ if (ret)
goto err;
- priv->pll_lock->val = (utmp & 0x01);
+ s->pll_lock->val = (utmp & 0x01);
err:
if (ret)
- dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
- struct e4000_priv *priv = container_of(ctrl->handler, struct e4000_priv, hdl);
+ struct e4000 *s = container_of(ctrl->handler, struct e4000, hdl);
int ret;
- if (priv->active == false)
+ if (s->active == false)
return 0;
switch (ctrl->id) {
case V4L2_CID_RF_TUNER_PLL_LOCK:
- ret = e4000_pll_lock(priv->fe);
+ ret = e4000_pll_lock(s->fe);
break;
default:
- dev_dbg(&priv->client->dev, "%s: unknown ctrl: id=%d name=%s\n",
+ dev_dbg(&s->client->dev, "%s: unknown ctrl: id=%d name=%s\n",
__func__, ctrl->id, ctrl->name);
ret = -EINVAL;
}
@@ -415,34 +415,34 @@ static int e4000_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
static int e4000_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct e4000_priv *priv = container_of(ctrl->handler, struct e4000_priv, hdl);
- struct dvb_frontend *fe = priv->fe;
+ struct e4000 *s = container_of(ctrl->handler, struct e4000, hdl);
+ struct dvb_frontend *fe = s->fe;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
- if (priv->active == false)
+ if (s->active == false)
return 0;
switch (ctrl->id) {
case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
case V4L2_CID_RF_TUNER_BANDWIDTH:
- c->bandwidth_hz = priv->bandwidth->val;
- ret = e4000_set_params(priv->fe);
+ c->bandwidth_hz = s->bandwidth->val;
+ ret = e4000_set_params(s->fe);
break;
case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO:
case V4L2_CID_RF_TUNER_LNA_GAIN:
- ret = e4000_set_lna_gain(priv->fe);
+ ret = e4000_set_lna_gain(s->fe);
break;
case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO:
case V4L2_CID_RF_TUNER_MIXER_GAIN:
- ret = e4000_set_mixer_gain(priv->fe);
+ ret = e4000_set_mixer_gain(s->fe);
break;
case V4L2_CID_RF_TUNER_IF_GAIN_AUTO:
case V4L2_CID_RF_TUNER_IF_GAIN:
- ret = e4000_set_if_gain(priv->fe);
+ ret = e4000_set_if_gain(s->fe);
break;
default:
- dev_dbg(&priv->client->dev, "%s: unknown ctrl: id=%d name=%s\n",
+ dev_dbg(&s->client->dev, "%s: unknown ctrl: id=%d name=%s\n",
__func__, ctrl->id, ctrl->name);
ret = -EINVAL;
}
@@ -478,7 +478,7 @@ static int e4000_probe(struct i2c_client *client,
{
struct e4000_config *cfg = client->dev.platform_data;
struct dvb_frontend *fe = cfg->fe;
- struct e4000_priv *priv;
+ struct e4000 *s;
int ret;
unsigned int utmp;
static const struct regmap_config regmap_config = {
@@ -487,28 +487,28 @@ static int e4000_probe(struct i2c_client *client,
.max_register = 0xff,
};
- priv = kzalloc(sizeof(struct e4000_priv), GFP_KERNEL);
- if (!priv) {
+ s = kzalloc(sizeof(struct e4000), GFP_KERNEL);
+ if (!s) {
ret = -ENOMEM;
dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
goto err;
}
- priv->clock = cfg->clock;
- priv->client = client;
- priv->fe = cfg->fe;
- priv->regmap = devm_regmap_init_i2c(client, ®map_config);
- if (IS_ERR(priv->regmap)) {
- ret = PTR_ERR(priv->regmap);
+ s->clock = cfg->clock;
+ s->client = client;
+ s->fe = cfg->fe;
+ s->regmap = devm_regmap_init_i2c(client, ®map_config);
+ if (IS_ERR(s->regmap)) {
+ ret = PTR_ERR(s->regmap);
goto err;
}
/* check if the tuner is there */
- ret = regmap_read(priv->regmap, 0x02, &utmp);
- if (ret < 0)
+ ret = regmap_read(s->regmap, 0x02, &utmp);
+ if (ret)
goto err;
- dev_dbg(&priv->client->dev, "%s: chip id=%02x\n", __func__, utmp);
+ dev_dbg(&s->client->dev, "%s: chip id=%02x\n", __func__, utmp);
if (utmp != 0x40) {
ret = -ENODEV;
@@ -516,59 +516,59 @@ static int e4000_probe(struct i2c_client *client,
}
/* put sleep as chip seems to be in normal mode by default */
- ret = regmap_write(priv->regmap, 0x00, 0x00);
- if (ret < 0)
+ ret = regmap_write(s->regmap, 0x00, 0x00);
+ if (ret)
goto err;
/* Register controls */
- v4l2_ctrl_handler_init(&priv->hdl, 9);
- priv->bandwidth_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ v4l2_ctrl_handler_init(&s->hdl, 9);
+ s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
- priv->bandwidth = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ s->bandwidth = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
V4L2_CID_RF_TUNER_BANDWIDTH, 4300000, 11000000, 100000, 4300000);
- v4l2_ctrl_auto_cluster(2, &priv->bandwidth_auto, 0, false);
- priv->lna_gain_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false);
+ s->lna_gain_auto = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
V4L2_CID_RF_TUNER_LNA_GAIN_AUTO, 0, 1, 1, 1);
- priv->lna_gain = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ s->lna_gain = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
V4L2_CID_RF_TUNER_LNA_GAIN, 0, 15, 1, 10);
- v4l2_ctrl_auto_cluster(2, &priv->lna_gain_auto, 0, false);
- priv->mixer_gain_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ v4l2_ctrl_auto_cluster(2, &s->lna_gain_auto, 0, false);
+ s->mixer_gain_auto = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO, 0, 1, 1, 1);
- priv->mixer_gain = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ s->mixer_gain = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
V4L2_CID_RF_TUNER_MIXER_GAIN, 0, 1, 1, 1);
- v4l2_ctrl_auto_cluster(2, &priv->mixer_gain_auto, 0, false);
- priv->if_gain_auto = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ v4l2_ctrl_auto_cluster(2, &s->mixer_gain_auto, 0, false);
+ s->if_gain_auto = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
V4L2_CID_RF_TUNER_IF_GAIN_AUTO, 0, 1, 1, 1);
- priv->if_gain = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ s->if_gain = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
V4L2_CID_RF_TUNER_IF_GAIN, 0, 54, 1, 0);
- v4l2_ctrl_auto_cluster(2, &priv->if_gain_auto, 0, false);
- priv->pll_lock = v4l2_ctrl_new_std(&priv->hdl, &e4000_ctrl_ops,
+ v4l2_ctrl_auto_cluster(2, &s->if_gain_auto, 0, false);
+ s->pll_lock = v4l2_ctrl_new_std(&s->hdl, &e4000_ctrl_ops,
V4L2_CID_RF_TUNER_PLL_LOCK, 0, 1, 1, 0);
- if (priv->hdl.error) {
- ret = priv->hdl.error;
- dev_err(&priv->client->dev, "Could not initialize controls\n");
- v4l2_ctrl_handler_free(&priv->hdl);
+ if (s->hdl.error) {
+ ret = s->hdl.error;
+ dev_err(&s->client->dev, "Could not initialize controls\n");
+ v4l2_ctrl_handler_free(&s->hdl);
goto err;
}
- priv->sd.ctrl_handler = &priv->hdl;
+ s->sd.ctrl_handler = &s->hdl;
- dev_info(&priv->client->dev,
+ dev_info(&s->client->dev,
"%s: Elonics E4000 successfully identified\n",
KBUILD_MODNAME);
- fe->tuner_priv = priv;
+ fe->tuner_priv = s;
memcpy(&fe->ops.tuner_ops, &e4000_tuner_ops,
sizeof(struct dvb_tuner_ops));
- v4l2_set_subdevdata(&priv->sd, client);
- i2c_set_clientdata(client, &priv->sd);
+ v4l2_set_subdevdata(&s->sd, client);
+ i2c_set_clientdata(client, &s->sd);
return 0;
err:
if (ret) {
dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
- kfree(priv);
+ kfree(s);
}
return ret;
@@ -577,15 +577,15 @@ err:
static int e4000_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct e4000_priv *priv = container_of(sd, struct e4000_priv, sd);
- struct dvb_frontend *fe = priv->fe;
+ struct e4000 *s = container_of(sd, struct e4000, sd);
+ struct dvb_frontend *fe = s->fe;
dev_dbg(&client->dev, "%s:\n", __func__);
- v4l2_ctrl_handler_free(&priv->hdl);
+ v4l2_ctrl_handler_free(&s->hdl);
memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
fe->tuner_priv = NULL;
- kfree(priv);
+ kfree(s);
return 0;
}
diff --git a/drivers/media/tuners/e4000_priv.h b/drivers/media/tuners/e4000_priv.h
index e772b00..cb00704 100644
--- a/drivers/media/tuners/e4000_priv.h
+++ b/drivers/media/tuners/e4000_priv.h
@@ -26,7 +26,7 @@
#include <media/v4l2-subdev.h>
#include <linux/regmap.h>
-struct e4000_priv {
+struct e4000 {
struct i2c_client *client;
struct regmap *regmap;
u32 clock;
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 15/17] rtl2832_sdr: fixing v4l2-compliance issues
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
` (13 preceding siblings ...)
2014-03-14 0:14 ` [PATCH 14/17] e4000: rename some variables Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
2014-03-14 0:14 ` [PATCH 16/17] rtl2832_sdr: clamp bandwidth to nearest legal value in automode Antti Palosaari
2014-03-14 0:14 ` [PATCH 17/17] MAINTAINERS: add rtl2832_sdr driver Antti Palosaari
16 siblings, 0 replies; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media
Cc: Hans Verkuil, Mauro Carvalho Chehab, Hans Verkuil,
Antti Palosaari
From: Hans Verkuil <hverkuil@xs4all.nl>
Fix rtl2832_sdr driver v4l2-compliance issues.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c | 29 +++++++++++++++++++-----
1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
index 7e20576..141fc8b 100644
--- a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
+++ b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
@@ -118,6 +118,7 @@ struct rtl2832_sdr_state {
struct vb2_queue vb_queue;
struct list_head queued_bufs;
spinlock_t queued_bufs_lock; /* Protects queued_bufs */
+ unsigned sequence; /* buffer sequence counter */
/* Note if taking both locks v4l2_lock must always be locked first! */
struct mutex v4l2_lock; /* Protects everything else */
@@ -413,6 +414,8 @@ static void rtl2832_sdr_urb_complete(struct urb *urb)
len = rtl2832_sdr_convert_stream(s, ptr, urb->transfer_buffer,
urb->actual_length);
vb2_set_plane_payload(&fbuf->vb, 0, len);
+ v4l2_get_timestamp(&fbuf->vb.v4l2_buf.timestamp);
+ fbuf->vb.v4l2_buf.sequence = s->sequence++;
vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
}
skip:
@@ -609,8 +612,9 @@ static int rtl2832_sdr_queue_setup(struct vb2_queue *vq,
struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers);
- /* Absolute min and max number of buffers available for mmap() */
- *nbuffers = clamp_t(unsigned int, *nbuffers, 8, 32);
+ /* Need at least 8 buffers */
+ if (vq->num_buffers + *nbuffers < 8)
+ *nbuffers = 8 - vq->num_buffers;
*nplanes = 1;
/* 2 = max 16-bit sample returned */
sizes[0] = PAGE_ALIGN(BULK_BUFFER_SIZE * 2);
@@ -1011,6 +1015,8 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count)
if (ret)
goto err;
+ s->sequence = 0;
+
ret = rtl2832_sdr_submit_urbs(s);
if (ret)
goto err;
@@ -1088,6 +1094,8 @@ static int rtl2832_sdr_s_tuner(struct file *file, void *priv,
struct rtl2832_sdr_state *s = video_drvdata(file);
dev_dbg(&s->udev->dev, "%s:\n", __func__);
+ if (v->index > 1)
+ return -EINVAL;
return 0;
}
@@ -1123,12 +1131,15 @@ static int rtl2832_sdr_g_frequency(struct file *file, void *priv,
dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n",
__func__, f->tuner, f->type);
- if (f->tuner == 0)
+ if (f->tuner == 0) {
f->frequency = s->f_adc;
- else if (f->tuner == 1)
+ f->type = V4L2_TUNER_ADC;
+ } else if (f->tuner == 1) {
f->frequency = s->f_tuner;
- else
+ f->type = V4L2_TUNER_RF;
+ } else {
return -EINVAL;
+ }
return ret;
}
@@ -1162,7 +1173,9 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
__func__, s->f_adc);
ret = rtl2832_sdr_set_adc(s);
} else if (f->tuner == 1) {
- s->f_tuner = f->frequency;
+ s->f_tuner = clamp_t(unsigned int, f->frequency,
+ bands_fm[0].rangelow,
+ bands_fm[0].rangehigh);
dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n",
__func__, f->frequency);
@@ -1196,6 +1209,7 @@ static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv,
dev_dbg(&s->udev->dev, "%s:\n", __func__);
f->fmt.sdr.pixelformat = s->pixelformat;
+ memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
return 0;
}
@@ -1212,6 +1226,7 @@ static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv,
if (vb2_is_busy(q))
return -EBUSY;
+ memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
for (i = 0; i < NUM_FORMATS; i++) {
if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
s->pixelformat = f->fmt.sdr.pixelformat;
@@ -1233,6 +1248,7 @@ static int rtl2832_sdr_try_fmt_sdr_cap(struct file *file, void *priv,
dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
(char *)&f->fmt.sdr.pixelformat);
+ memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
for (i = 0; i < NUM_FORMATS; i++) {
if (formats[i].pixelformat == f->fmt.sdr.pixelformat)
return 0;
@@ -1363,6 +1379,7 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
s->i2c = i2c;
s->cfg = cfg;
s->f_adc = bands_adc[0].rangelow;
+ s->f_tuner = bands_fm[0].rangelow;
s->pixelformat = V4L2_SDR_FMT_CU8;
mutex_init(&s->v4l2_lock);
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 16/17] rtl2832_sdr: clamp bandwidth to nearest legal value in automode
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
` (14 preceding siblings ...)
2014-03-14 0:14 ` [PATCH 15/17] rtl2832_sdr: fixing v4l2-compliance issues Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
2014-03-14 0:14 ` [PATCH 17/17] MAINTAINERS: add rtl2832_sdr driver Antti Palosaari
16 siblings, 0 replies; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Mauro Carvalho Chehab, Antti Palosaari
Clamp bandwidth to nearest legal value in automode in order to pass
v4l2-compliance test.
Reported-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
index 141fc8b..b09f7d8 100644
--- a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
+++ b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
@@ -1322,8 +1322,16 @@ static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
case V4L2_CID_RF_TUNER_BANDWIDTH:
- if (s->bandwidth_auto->val)
- s->bandwidth->val = s->f_adc;
+ /* TODO: these controls should be moved to tuner drivers */
+ if (s->bandwidth_auto->val) {
+ /* Round towards the closest legal value */
+ s32 val = s->f_adc + s->bandwidth->step / 2;
+ u32 offset;
+ val = clamp(val, s->bandwidth->minimum, s->bandwidth->maximum);
+ offset = val - s->bandwidth->minimum;
+ offset = s->bandwidth->step * (offset / s->bandwidth->step);
+ s->bandwidth->val = s->bandwidth->minimum + offset;
+ }
c->bandwidth_hz = s->bandwidth->val;
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH 17/17] MAINTAINERS: add rtl2832_sdr driver
2014-03-14 0:14 [PATCH 00/17] SDR API - rtl2832_sdr driver Antti Palosaari
` (15 preceding siblings ...)
2014-03-14 0:14 ` [PATCH 16/17] rtl2832_sdr: clamp bandwidth to nearest legal value in automode Antti Palosaari
@ 2014-03-14 0:14 ` Antti Palosaari
16 siblings, 0 replies; 20+ messages in thread
From: Antti Palosaari @ 2014-03-14 0:14 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Mauro Carvalho Chehab, Antti Palosaari
Realtek RTL2832 SDR driver. Currently in staging as SDR API is not
ready.
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
MAINTAINERS | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 3718c32..94c9cff 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7351,6 +7351,16 @@ T: git git://linuxtv.org/anttip/media_tree.git
S: Maintained
F: drivers/media/dvb-frontends/rtl2832*
+RTL2832_SDR MEDIA DRIVER
+M: Antti Palosaari <crope@iki.fi>
+L: linux-media@vger.kernel.org
+W: http://linuxtv.org/
+W: http://palosaari.fi/linux/
+Q: http://patchwork.linuxtv.org/project/linux-media/list/
+T: git git://linuxtv.org/anttip/media_tree.git
+S: Maintained
+F: drivers/staging/media/rtl2832u_sdr/rtl2832_sdr*
+
RTL8180 WIRELESS DRIVER
M: "John W. Linville" <linville@tuxdriver.com>
L: linux-wireless@vger.kernel.org
--
1.8.5.3
^ permalink raw reply related [flat|nested] 20+ messages in thread