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

[media] rtl2832_sdr: add support for fc2580 tuner

Add initial support for fc2580 tuner based devices.
Tuner is controlled via V4L2 subdevice API.
Passes v4l2-compliance tests.
Signed-off-by: default avatarAntti Palosaari <crope@iki.fi>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent 252fad1c
...@@ -39,6 +39,10 @@ static bool rtl2832_sdr_emulated_fmt; ...@@ -39,6 +39,10 @@ static bool rtl2832_sdr_emulated_fmt;
module_param_named(emulated_formats, rtl2832_sdr_emulated_fmt, bool, 0644); module_param_named(emulated_formats, rtl2832_sdr_emulated_fmt, bool, 0644);
MODULE_PARM_DESC(emulated_formats, "enable emulated formats (disappears in future)"); MODULE_PARM_DESC(emulated_formats, "enable emulated formats (disappears in future)");
/* Original macro does not contain enough null pointer checks for our need */
#define V4L2_SUBDEV_HAS_OP(sd, o, f) \
((sd) && (sd)->ops && (sd)->ops->o && (sd)->ops->o->f)
#define MAX_BULK_BUFS (10) #define MAX_BULK_BUFS (10)
#define BULK_BUFFER_SIZE (128 * 512) #define BULK_BUFFER_SIZE (128 * 512)
...@@ -116,6 +120,7 @@ struct rtl2832_sdr_dev { ...@@ -116,6 +120,7 @@ struct rtl2832_sdr_dev {
struct video_device vdev; struct video_device vdev;
struct v4l2_device v4l2_dev; struct v4l2_device v4l2_dev;
struct v4l2_subdev *v4l2_subdev;
/* videobuf2 queue and queued buffers list */ /* videobuf2 queue and queued buffers list */
struct vb2_queue vb_queue; struct vb2_queue vb_queue;
...@@ -742,6 +747,29 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_dev *dev) ...@@ -742,6 +747,29 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_dev *dev)
ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1); ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xf4", 1); ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xf4", 1);
break; break;
case RTL2832_SDR_TUNER_FC2580:
ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x39", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x5a", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1c7, "\x2c", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x104, "\xcc", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x105, "\xbe", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1c8, "\x16", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x106, "\x35", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1c9, "\x21", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1ca, "\x21", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1cb, "\x00", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x107, "\x40", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1cd, "\x10", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1ce, "\x10", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x108, "\x80", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x109, "\x7f", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x10a, "\x9c", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x10b, "\x7f", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xe9\xf4", 2);
break;
default: default:
dev_notice(&pdev->dev, "Unsupported tuner\n"); dev_notice(&pdev->dev, "Unsupported tuner\n");
} }
...@@ -832,8 +860,10 @@ static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_dev *dev) ...@@ -832,8 +860,10 @@ static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_dev *dev)
if (!test_bit(POWER_ON, &dev->flags)) if (!test_bit(POWER_ON, &dev->flags))
return 0; return 0;
if (!V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, tuner, s_frequency)) {
if (fe->ops.tuner_ops.set_params) if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe); fe->ops.tuner_ops.set_params(fe);
}
return 0; return 0;
}; };
...@@ -891,6 +921,10 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count) ...@@ -891,6 +921,10 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count)
set_bit(POWER_ON, &dev->flags); set_bit(POWER_ON, &dev->flags);
/* wake-up tuner */
if (V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, core, s_power))
ret = v4l2_subdev_call(dev->v4l2_subdev, core, s_power, 1);
else
ret = rtl2832_sdr_set_tuner(dev); ret = rtl2832_sdr_set_tuner(dev);
if (ret) if (ret)
goto err; goto err;
...@@ -939,6 +973,11 @@ static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq) ...@@ -939,6 +973,11 @@ static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq)
rtl2832_sdr_free_stream_bufs(dev); rtl2832_sdr_free_stream_bufs(dev);
rtl2832_sdr_cleanup_queued_bufs(dev); rtl2832_sdr_cleanup_queued_bufs(dev);
rtl2832_sdr_unset_adc(dev); rtl2832_sdr_unset_adc(dev);
/* sleep tuner */
if (V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, core, s_power))
v4l2_subdev_call(dev->v4l2_subdev, core, s_power, 0);
else
rtl2832_sdr_unset_tuner(dev); rtl2832_sdr_unset_tuner(dev);
clear_bit(POWER_ON, &dev->flags); clear_bit(POWER_ON, &dev->flags);
...@@ -968,6 +1007,7 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv, ...@@ -968,6 +1007,7 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
{ {
struct rtl2832_sdr_dev *dev = video_drvdata(file); struct rtl2832_sdr_dev *dev = video_drvdata(file);
struct platform_device *pdev = dev->pdev; struct platform_device *pdev = dev->pdev;
int ret;
dev_dbg(&pdev->dev, "index=%d type=%d\n", v->index, v->type); dev_dbg(&pdev->dev, "index=%d type=%d\n", v->index, v->type);
...@@ -977,17 +1017,21 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv, ...@@ -977,17 +1017,21 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
v->rangelow = 300000; v->rangelow = 300000;
v->rangehigh = 3200000; v->rangehigh = 3200000;
ret = 0;
} else if (v->index == 1 &&
V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, tuner, g_tuner)) {
ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, g_tuner, v);
} else if (v->index == 1) { } else if (v->index == 1) {
strlcpy(v->name, "RF: <unknown>", sizeof(v->name)); strlcpy(v->name, "RF: <unknown>", sizeof(v->name));
v->type = V4L2_TUNER_RF; v->type = V4L2_TUNER_RF;
v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
v->rangelow = 50000000; v->rangelow = 50000000;
v->rangehigh = 2000000000; v->rangehigh = 2000000000;
ret = 0;
} else { } else {
return -EINVAL; ret = -EINVAL;
} }
return ret;
return 0;
} }
static int rtl2832_sdr_s_tuner(struct file *file, void *priv, static int rtl2832_sdr_s_tuner(struct file *file, void *priv,
...@@ -995,12 +1039,21 @@ static int rtl2832_sdr_s_tuner(struct file *file, void *priv, ...@@ -995,12 +1039,21 @@ static int rtl2832_sdr_s_tuner(struct file *file, void *priv,
{ {
struct rtl2832_sdr_dev *dev = video_drvdata(file); struct rtl2832_sdr_dev *dev = video_drvdata(file);
struct platform_device *pdev = dev->pdev; struct platform_device *pdev = dev->pdev;
int ret;
dev_dbg(&pdev->dev, "\n"); dev_dbg(&pdev->dev, "\n");
if (v->index > 1) if (v->index == 0) {
return -EINVAL; ret = 0;
return 0; } else if (v->index == 1 &&
V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, tuner, s_tuner)) {
ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, s_tuner, v);
} else if (v->index == 1) {
ret = 0;
} else {
ret = -EINVAL;
}
return ret;
} }
static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv, static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv,
...@@ -1008,6 +1061,7 @@ static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv, ...@@ -1008,6 +1061,7 @@ static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv,
{ {
struct rtl2832_sdr_dev *dev = video_drvdata(file); struct rtl2832_sdr_dev *dev = video_drvdata(file);
struct platform_device *pdev = dev->pdev; struct platform_device *pdev = dev->pdev;
int ret;
dev_dbg(&pdev->dev, "tuner=%d type=%d index=%d\n", dev_dbg(&pdev->dev, "tuner=%d type=%d index=%d\n",
band->tuner, band->type, band->index); band->tuner, band->type, band->index);
...@@ -1017,16 +1071,20 @@ static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv, ...@@ -1017,16 +1071,20 @@ static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv,
return -EINVAL; return -EINVAL;
*band = bands_adc[band->index]; *band = bands_adc[band->index];
ret = 0;
} else if (band->tuner == 1 &&
V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, tuner, enum_freq_bands)) {
ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, enum_freq_bands, band);
} else if (band->tuner == 1) { } else if (band->tuner == 1) {
if (band->index >= ARRAY_SIZE(bands_fm)) if (band->index >= ARRAY_SIZE(bands_fm))
return -EINVAL; return -EINVAL;
*band = bands_fm[band->index]; *band = bands_fm[band->index];
ret = 0;
} else { } else {
return -EINVAL; ret = -EINVAL;
} }
return ret;
return 0;
} }
static int rtl2832_sdr_g_frequency(struct file *file, void *priv, static int rtl2832_sdr_g_frequency(struct file *file, void *priv,
...@@ -1034,20 +1092,25 @@ static int rtl2832_sdr_g_frequency(struct file *file, void *priv, ...@@ -1034,20 +1092,25 @@ static int rtl2832_sdr_g_frequency(struct file *file, void *priv,
{ {
struct rtl2832_sdr_dev *dev = video_drvdata(file); struct rtl2832_sdr_dev *dev = video_drvdata(file);
struct platform_device *pdev = dev->pdev; struct platform_device *pdev = dev->pdev;
int ret = 0; int ret;
dev_dbg(&pdev->dev, "tuner=%d type=%d\n", f->tuner, f->type); dev_dbg(&pdev->dev, "tuner=%d type=%d\n", f->tuner, f->type);
if (f->tuner == 0) { if (f->tuner == 0) {
f->frequency = dev->f_adc; f->frequency = dev->f_adc;
f->type = V4L2_TUNER_ADC; f->type = V4L2_TUNER_ADC;
ret = 0;
} else if (f->tuner == 1 &&
V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, tuner, g_frequency)) {
f->type = V4L2_TUNER_RF;
ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, g_frequency, f);
} else if (f->tuner == 1) { } else if (f->tuner == 1) {
f->frequency = dev->f_tuner; f->frequency = dev->f_tuner;
f->type = V4L2_TUNER_RF; f->type = V4L2_TUNER_RF;
ret = 0;
} else { } else {
return -EINVAL; ret = -EINVAL;
} }
return ret; return ret;
} }
...@@ -1079,6 +1142,9 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv, ...@@ -1079,6 +1142,9 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
dev_dbg(&pdev->dev, "ADC frequency=%u Hz\n", dev->f_adc); dev_dbg(&pdev->dev, "ADC frequency=%u Hz\n", dev->f_adc);
ret = rtl2832_sdr_set_adc(dev); ret = rtl2832_sdr_set_adc(dev);
} else if (f->tuner == 1 &&
V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, tuner, s_frequency)) {
ret = v4l2_subdev_call(dev->v4l2_subdev, tuner, s_frequency, f);
} else if (f->tuner == 1) { } else if (f->tuner == 1) {
dev->f_tuner = clamp_t(unsigned int, f->frequency, dev->f_tuner = clamp_t(unsigned int, f->frequency,
bands_fm[0].rangelow, bands_fm[0].rangelow,
...@@ -1089,7 +1155,6 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv, ...@@ -1089,7 +1155,6 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
} else { } else {
ret = -EINVAL; ret = -EINVAL;
} }
return ret; return ret;
} }
...@@ -1329,6 +1394,7 @@ static int rtl2832_sdr_probe(struct platform_device *pdev) ...@@ -1329,6 +1394,7 @@ static int rtl2832_sdr_probe(struct platform_device *pdev)
/* setup the state */ /* setup the state */
subdev = pdata->v4l2_subdev; subdev = pdata->v4l2_subdev;
dev->v4l2_subdev = pdata->v4l2_subdev;
dev->pdev = pdev; dev->pdev = pdev;
dev->udev = pdata->dvb_usb_device->udev; dev->udev = pdata->dvb_usb_device->udev;
dev->f_adc = bands_adc[0].rangelow; dev->f_adc = bands_adc[0].rangelow;
...@@ -1388,6 +1454,12 @@ static int rtl2832_sdr_probe(struct platform_device *pdev) ...@@ -1388,6 +1454,12 @@ static int rtl2832_sdr_probe(struct platform_device *pdev)
6000000); 6000000);
v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false); v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
break; break;
case RTL2832_SDR_TUNER_FC2580:
v4l2_ctrl_handler_init(&dev->hdl, 2);
if (subdev)
v4l2_ctrl_add_handler(&dev->hdl, subdev->ctrl_handler,
NULL);
break;
default: default:
v4l2_ctrl_handler_init(&dev->hdl, 0); v4l2_ctrl_handler_init(&dev->hdl, 0);
dev_err(&pdev->dev, "Unsupported tuner\n"); dev_err(&pdev->dev, "Unsupported tuner\n");
......
...@@ -47,6 +47,7 @@ struct rtl2832_sdr_platform_data { ...@@ -47,6 +47,7 @@ struct rtl2832_sdr_platform_data {
/* /*
* XXX: This list must be kept sync with dvb_usb_rtl28xxu USB IF driver. * XXX: This list must be kept sync with dvb_usb_rtl28xxu USB IF driver.
*/ */
#define RTL2832_SDR_TUNER_FC2580 0x21
#define RTL2832_SDR_TUNER_TUA9001 0x24 #define RTL2832_SDR_TUNER_TUA9001 0x24
#define RTL2832_SDR_TUNER_FC0012 0x26 #define RTL2832_SDR_TUNER_FC0012 0x26
#define RTL2832_SDR_TUNER_E4000 0x27 #define RTL2832_SDR_TUNER_E4000 0x27
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment