summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.c355
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.h42
2 files changed, 156 insertions, 241 deletions
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
index 3af869c5497d..6c5b2944ecb2 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -32,6 +32,7 @@
#include <media/v4l2-event.h>
#include <media/videobuf2-vmalloc.h>
+#include <linux/platform_device.h>
#include <linux/jiffies.h>
#include <linux/math64.h>
@@ -112,7 +113,7 @@ struct rtl2832_sdr_dev {
#define URB_BUF (1 << 2)
unsigned long flags;
- const struct rtl2832_config *cfg;
+ struct platform_device *pdev;
struct dvb_frontend *fe;
struct dvb_usb_device *d;
struct i2c_adapter *i2c;
@@ -160,110 +161,29 @@ struct rtl2832_sdr_dev {
unsigned long jiffies_next;
};
-/* write multiple hardware registers */
-static int rtl2832_sdr_wr(struct rtl2832_sdr_dev *dev, u8 reg, const u8 *val,
- int len)
-{
- int ret;
-#define MAX_WR_LEN 24
-#define MAX_WR_XFER_LEN (MAX_WR_LEN + 1)
- u8 buf[MAX_WR_XFER_LEN];
- struct i2c_msg msg[1] = {
- {
- .addr = dev->cfg->i2c_addr,
- .flags = 0,
- .len = 1 + len,
- .buf = buf,
- }
- };
-
- if (WARN_ON(len > MAX_WR_LEN))
- return -EINVAL;
-
- buf[0] = reg;
- memcpy(&buf[1], val, len);
-
- ret = i2c_transfer(dev->i2c, msg, 1);
- if (ret == 1) {
- ret = 0;
- } else {
- dev_err(&dev->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_dev *dev, u8 reg, u8 *val, int len)
-{
- int ret;
- struct i2c_msg msg[2] = {
- {
- .addr = dev->cfg->i2c_addr,
- .flags = 0,
- .len = 1,
- .buf = &reg,
- }, {
- .addr = dev->cfg->i2c_addr,
- .flags = I2C_M_RD,
- .len = len,
- .buf = val,
- }
- };
-
- ret = i2c_transfer(dev->i2c, msg, 2);
- if (ret == 2) {
- ret = 0;
- } else {
- dev_err(&dev->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_dev *dev, 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 != dev->bank) {
- ret = rtl2832_sdr_wr(dev, 0x00, &bank, 1);
- if (ret)
- return ret;
+ struct platform_device *pdev = dev->pdev;
+ struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+ struct i2c_client *client = pdata->i2c_client;
- dev->bank = bank;
- }
-
- return rtl2832_sdr_wr(dev, reg2, val, len);
+ return pdata->bulk_write(client, reg, val, len);
}
+#if 0
/* read multiple registers */
static int rtl2832_sdr_rd_regs(struct rtl2832_sdr_dev *dev, u16 reg, u8 *val,
int len)
{
- int ret;
- u8 reg2 = (reg >> 0) & 0xff;
- u8 bank = (reg >> 8) & 0xff;
-
- /* switch bank if needed */
- if (bank != dev->bank) {
- ret = rtl2832_sdr_wr(dev, 0x00, &bank, 1);
- if (ret)
- return ret;
+ struct platform_device *pdev = dev->pdev;
+ struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+ struct i2c_client *client = pdata->i2c_client;
- dev->bank = bank;
- }
-
- return rtl2832_sdr_rd(dev, reg2, val, len);
+ return pdata->bulk_read(client, reg, val, len);
}
+#endif
/* write single register */
static int rtl2832_sdr_wr_reg(struct rtl2832_sdr_dev *dev, u16 reg, u8 val)
@@ -271,59 +191,16 @@ static int rtl2832_sdr_wr_reg(struct rtl2832_sdr_dev *dev, u16 reg, u8 val)
return rtl2832_sdr_wr_regs(dev, reg, &val, 1);
}
-#if 0
-/* read single register */
-static int rtl2832_sdr_rd_reg(struct rtl2832_sdr_dev *dev, u16 reg, u8 *val)
-{
- return rtl2832_sdr_rd_regs(dev, reg, val, 1);
-}
-#endif
-
/* write single register with mask */
static int rtl2832_sdr_wr_reg_mask(struct rtl2832_sdr_dev *dev, 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(dev, reg, &tmp, 1);
- if (ret)
- return ret;
-
- val &= mask;
- tmp &= ~mask;
- val |= tmp;
- }
-
- return rtl2832_sdr_wr_regs(dev, reg, &val, 1);
-}
-
-#if 0
-/* read single register with mask */
-static int rtl2832_sdr_rd_reg_mask(struct rtl2832_sdr_dev *dev, u16 reg,
- u8 *val, u8 mask)
-{
- int ret, i;
- u8 tmp;
-
- ret = rtl2832_sdr_rd_regs(dev, 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;
+ struct platform_device *pdev = dev->pdev;
+ struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+ struct i2c_client *client = pdata->i2c_client;
- return 0;
+ return pdata->update_bits(client, reg, mask, val);
}
-#endif
/* Private functions */
static struct rtl2832_sdr_frame_buf *rtl2832_sdr_get_next_fill_buf(
@@ -584,28 +461,6 @@ static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_dev *dev)
spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
}
-/* The user yanked out the cable... */
-static void rtl2832_sdr_release_sec(struct dvb_frontend *fe)
-{
- struct rtl2832_sdr_dev *dev = fe->sec_priv;
-
- dev_dbg(&dev->udev->dev, "\n");
-
- mutex_lock(&dev->vb_queue_lock);
- mutex_lock(&dev->v4l2_lock);
- /* No need to keep the urbs around after disconnection */
- dev->udev = NULL;
-
- v4l2_device_disconnect(&dev->v4l2_dev);
- video_unregister_device(&dev->vdev);
- mutex_unlock(&dev->v4l2_lock);
- mutex_unlock(&dev->vb_queue_lock);
-
- v4l2_device_put(&dev->v4l2_dev);
-
- fe->sec_priv = NULL;
-}
-
static int rtl2832_sdr_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
@@ -672,6 +527,8 @@ static void rtl2832_sdr_buf_queue(struct vb2_buffer *vb)
static int rtl2832_sdr_set_adc(struct rtl2832_sdr_dev *dev)
{
+ struct platform_device *pdev = dev->pdev;
+ struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
struct dvb_frontend *fe = dev->fe;
int ret;
unsigned int f_sr, f_if;
@@ -707,9 +564,9 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_dev *dev)
goto err;
/* program IF */
- u64tmp = f_if % dev->cfg->xtal;
+ u64tmp = f_if % pdata->clk;
u64tmp *= 0x400000;
- u64tmp = div_u64(u64tmp, dev->cfg->xtal);
+ u64tmp = div_u64(u64tmp, pdata->clk);
u64tmp = -u64tmp;
u32tmp = u64tmp & 0x3fffff;
@@ -746,7 +603,7 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_dev *dev)
goto err;
/* program sampling rate (resampling down) */
- u32tmp = div_u64(dev->cfg->xtal * 0x400000ULL, f_sr * 4U);
+ u32tmp = div_u64(pdata->clk * 0x400000ULL, f_sr * 4U);
u32tmp <<= 2;
buf[0] = (u32tmp >> 24) & 0xff;
buf[1] = (u32tmp >> 16) & 0xff;
@@ -787,8 +644,8 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_dev *dev)
goto err;
/* used RF tuner based settings */
- switch (dev->cfg->tuner) {
- case RTL2832_TUNER_E4000:
+ switch (pdata->tuner) {
+ case RTL2832_SDR_TUNER_E4000:
ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x5a", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x5a", 1);
@@ -824,8 +681,8 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_dev *dev)
ret = rtl2832_sdr_wr_regs(dev, 0x00d, "\x85", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x013, "\x02", 1);
break;
- case RTL2832_TUNER_FC0012:
- case RTL2832_TUNER_FC0013:
+ case RTL2832_SDR_TUNER_FC0012:
+ case RTL2832_SDR_TUNER_FC0013:
ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x5a", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x5a", 1);
@@ -856,7 +713,8 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_dev *dev)
ret = rtl2832_sdr_wr_regs(dev, 0x1e6, "\x02", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1d7, "\x09", 1);
break;
- case RTL2832_TUNER_R820T:
+ case RTL2832_SDR_TUNER_R820T:
+ case RTL2832_SDR_TUNER_R828D:
ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x5a", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x115, "\x01", 1);
@@ -1401,34 +1259,46 @@ static void rtl2832_sdr_video_release(struct v4l2_device *v)
{
struct rtl2832_sdr_dev *dev =
container_of(v, struct rtl2832_sdr_dev, v4l2_dev);
+ struct platform_device *pdev = dev->pdev;
+
+ dev_dbg(&pdev->dev, "\n");
v4l2_ctrl_handler_free(&dev->hdl);
v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
}
-struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c, const struct rtl2832_config *cfg,
- struct v4l2_subdev *sd)
+/* Platform driver interface */
+static int rtl2832_sdr_probe(struct platform_device *pdev)
{
- int ret;
struct rtl2832_sdr_dev *dev;
+ struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
const struct v4l2_ctrl_ops *ops = &rtl2832_sdr_ctrl_ops;
- struct dvb_usb_device *d = i2c_get_adapdata(i2c);
+ struct v4l2_subdev *subdev;
+ int ret;
- dev = kzalloc(sizeof(struct rtl2832_sdr_dev), GFP_KERNEL);
+ dev_dbg(&pdev->dev, "\n");
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "Cannot proceed without platform data\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
- dev_err(&d->udev->dev,
- "Could not allocate memory for rtl2832_sdr_dev\n");
- return NULL;
+ dev_err(&pdev->dev,
+ "Could not allocate memory for rtl2832_sdr_dev\n");
+ ret = -ENOMEM;
+ goto err;
}
/* setup the state */
- dev->fe = fe;
- dev->d = d;
- dev->udev = d->udev;
- dev->i2c = i2c;
- dev->cfg = cfg;
+ subdev = pdata->v4l2_subdev;
+ dev->pdev = pdev;
+ dev->fe = pdata->dvb_frontend;
+ dev->d = pdata->dvb_usb_device;
+ dev->udev = pdata->dvb_usb_device->udev;
+ dev->i2c = pdata->i2c_client->adapter;
dev->f_adc = bands_adc[0].rangelow;
dev->f_tuner = bands_fm[0].rangelow;
dev->pixelformat = formats[0].pixelformat;
@@ -1452,50 +1322,49 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
ret = vb2_queue_init(&dev->vb_queue);
if (ret) {
- dev_err(&dev->udev->dev, "Could not initialize vb2 queue\n");
- goto err_free_mem;
+ dev_err(&pdev->dev, "Could not initialize vb2 queue\n");
+ goto err_kfree;
}
/* Register controls */
- switch (dev->cfg->tuner) {
- case RTL2832_TUNER_E4000:
+ switch (pdata->tuner) {
+ case RTL2832_SDR_TUNER_E4000:
v4l2_ctrl_handler_init(&dev->hdl, 9);
- if (sd)
- v4l2_ctrl_add_handler(&dev->hdl, sd->ctrl_handler, NULL);
+ if (subdev)
+ v4l2_ctrl_add_handler(&dev->hdl, subdev->ctrl_handler, NULL);
break;
- case RTL2832_TUNER_R820T:
+ case RTL2832_SDR_TUNER_R820T:
+ case RTL2832_SDR_TUNER_R828D:
v4l2_ctrl_handler_init(&dev->hdl, 2);
dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, ops,
- V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
- 0, 1, 1, 1);
+ V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
+ 0, 1, 1, 1);
dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, ops,
- V4L2_CID_RF_TUNER_BANDWIDTH,
- 0, 8000000, 100000, 0);
+ V4L2_CID_RF_TUNER_BANDWIDTH,
+ 0, 8000000, 100000, 0);
v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
break;
- case RTL2832_TUNER_FC0012:
- case RTL2832_TUNER_FC0013:
+ case RTL2832_SDR_TUNER_FC0012:
+ case RTL2832_SDR_TUNER_FC0013:
v4l2_ctrl_handler_init(&dev->hdl, 2);
dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, ops,
- V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
- 0, 1, 1, 1);
+ V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
+ 0, 1, 1, 1);
dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, ops,
- V4L2_CID_RF_TUNER_BANDWIDTH,
- 6000000, 8000000, 1000000,
- 6000000);
+ V4L2_CID_RF_TUNER_BANDWIDTH,
+ 6000000, 8000000, 1000000,
+ 6000000);
v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
break;
default:
v4l2_ctrl_handler_init(&dev->hdl, 0);
- dev_notice(&dev->udev->dev, "%s: Unsupported tuner\n",
- KBUILD_MODNAME);
- goto err_free_controls;
+ dev_err(&pdev->dev, "Unsupported tuner\n");
+ goto err_v4l2_ctrl_handler_free;
}
-
if (dev->hdl.error) {
ret = dev->hdl.error;
- dev_err(&dev->udev->dev, "Could not initialize controls\n");
- goto err_free_controls;
+ dev_err(&pdev->dev, "Could not initialize controls\n");
+ goto err_v4l2_ctrl_handler_free;
}
/* Init video_device structure */
@@ -1508,9 +1377,8 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
dev->v4l2_dev.release = rtl2832_sdr_video_release;
ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
if (ret) {
- dev_err(&dev->udev->dev,
- "Failed to register v4l2-device (%d)\n", ret);
- goto err_free_controls;
+ dev_err(&pdev->dev, "Failed to register v4l2-device %d\n", ret);
+ goto err_v4l2_ctrl_handler_free;
}
dev->v4l2_dev.ctrl_handler = &dev->hdl;
@@ -1520,33 +1388,56 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
ret = video_register_device(&dev->vdev, VFL_TYPE_SDR, -1);
if (ret) {
- dev_err(&dev->udev->dev,
- "Failed to register as video device (%d)\n",
- ret);
- goto err_unregister_v4l2_dev;
+ dev_err(&pdev->dev, "Failed to register as video device %d\n",
+ ret);
+ goto err_v4l2_device_unregister;
}
- dev_info(&dev->udev->dev, "Registered as %s\n",
- video_device_node_name(&dev->vdev));
-
- fe->sec_priv = dev;
- fe->ops.release_sec = rtl2832_sdr_release_sec;
-
- dev_info(&dev->i2c->dev, "%s: Realtek RTL2832 SDR attached\n",
- KBUILD_MODNAME);
- dev_notice(&dev->udev->dev,
- "%s: SDR API is still slightly experimental and functionality changes may follow\n",
- KBUILD_MODNAME);
- return fe;
-
-err_unregister_v4l2_dev:
+ dev_info(&pdev->dev, "Registered as %s\n",
+ video_device_node_name(&dev->vdev));
+ dev_info(&pdev->dev, "Realtek RTL2832 SDR attached\n");
+ dev_notice(&pdev->dev,
+ "SDR API is still slightly experimental and functionality changes may follow\n");
+ platform_set_drvdata(pdev, dev);
+ return 0;
+err_v4l2_device_unregister:
v4l2_device_unregister(&dev->v4l2_dev);
-err_free_controls:
+err_v4l2_ctrl_handler_free:
v4l2_ctrl_handler_free(&dev->hdl);
-err_free_mem:
+err_kfree:
kfree(dev);
- return NULL;
+err:
+ return ret;
}
-EXPORT_SYMBOL(rtl2832_sdr_attach);
+
+static int rtl2832_sdr_remove(struct platform_device *pdev)
+{
+ struct rtl2832_sdr_dev *dev = platform_get_drvdata(pdev);
+
+ dev_dbg(&pdev->dev, "\n");
+
+ mutex_lock(&dev->vb_queue_lock);
+ mutex_lock(&dev->v4l2_lock);
+ /* No need to keep the urbs around after disconnection */
+ dev->udev = NULL;
+ v4l2_device_disconnect(&dev->v4l2_dev);
+ video_unregister_device(&dev->vdev);
+ mutex_unlock(&dev->v4l2_lock);
+ mutex_unlock(&dev->vb_queue_lock);
+
+ v4l2_device_put(&dev->v4l2_dev);
+
+ return 0;
+}
+
+static struct platform_driver rtl2832_sdr_driver = {
+ .driver = {
+ .name = "rtl2832_sdr",
+ .owner = THIS_MODULE,
+ },
+ .probe = rtl2832_sdr_probe,
+ .remove = rtl2832_sdr_remove,
+};
+module_platform_driver(rtl2832_sdr_driver);
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_DESCRIPTION("Realtek RTL2832 SDR driver");
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.h b/drivers/media/dvb-frontends/rtl2832_sdr.h
index b865fadf184f..5efe609abd20 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.h
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.h
@@ -32,23 +32,47 @@
#define RTL2832_SDR_H
#include <linux/kconfig.h>
+#include <linux/i2c.h>
#include <media/v4l2-subdev.h>
-
-/* for config struct */
+#include "dvb_frontend.h"
#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
+struct rtl2832_sdr_platform_data {
+ /*
+ * Clock frequency.
+ * Hz
+ * 4000000, 16000000, 25000000, 28800000
+ */
+ u32 clk;
+
+ /*
+ * Tuner.
+ * XXX: This list must be kept sync with dvb_usb_rtl28xxu USB IF driver.
+ */
+#define RTL2832_SDR_TUNER_TUA9001 0x24
+#define RTL2832_SDR_TUNER_FC0012 0x26
+#define RTL2832_SDR_TUNER_E4000 0x27
+#define RTL2832_SDR_TUNER_FC0013 0x29
+#define RTL2832_SDR_TUNER_R820T 0x2a
+#define RTL2832_SDR_TUNER_R828D 0x2b
+ u8 tuner;
+
+ struct i2c_client *i2c_client;
+ int (*bulk_read)(struct i2c_client *, unsigned int, void *, size_t);
+ int (*bulk_write)(struct i2c_client *, unsigned int, const void *, size_t);
+ int (*update_bits)(struct i2c_client *, unsigned int, unsigned int, unsigned int);
+ struct dvb_frontend *dvb_frontend;
+ struct v4l2_subdev *v4l2_subdev;
+ struct dvb_usb_device *dvb_usb_device;
+};
+
+
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__);
+ dev_warn(&i2c->dev, "%s: driver disabled!\n", __func__);
return NULL;
}
-#endif
#endif /* RTL2832_SDR_H */