Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+91 −19
Original line number Diff line number Diff line
@@ -39,6 +39,10 @@ static bool rtl2832_sdr_emulated_fmt;
module_param_named(emulated_formats, rtl2832_sdr_emulated_fmt, bool, 0644);
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 BULK_BUFFER_SIZE         (128 * 512)

@@ -116,6 +120,7 @@ struct rtl2832_sdr_dev {

	struct video_device vdev;
	struct v4l2_device v4l2_dev;
	struct v4l2_subdev *v4l2_subdev;

	/* videobuf2 queue and queued buffers list */
	struct vb2_queue vb_queue;
@@ -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, 0x011, "\xf4", 1);
		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:
		dev_notice(&pdev->dev, "Unsupported tuner\n");
	}
@@ -832,8 +860,10 @@ static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_dev *dev)
	if (!test_bit(POWER_ON, &dev->flags))
		return 0;

	if (!V4L2_SUBDEV_HAS_OP(dev->v4l2_subdev, tuner, s_frequency)) {
		if (fe->ops.tuner_ops.set_params)
			fe->ops.tuner_ops.set_params(fe);
	}

	return 0;
};
@@ -891,6 +921,10 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count)

	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);
	if (ret)
		goto err;
@@ -939,6 +973,11 @@ static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq)
	rtl2832_sdr_free_stream_bufs(dev);
	rtl2832_sdr_cleanup_queued_bufs(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);

	clear_bit(POWER_ON, &dev->flags);
@@ -968,6 +1007,7 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
{
	struct rtl2832_sdr_dev *dev = video_drvdata(file);
	struct platform_device *pdev = dev->pdev;
	int ret;

	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,
		v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
		v->rangelow =   300000;
		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) {
		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;
		ret = 0;
	} else {
		return -EINVAL;
		ret = -EINVAL;
	}

	return 0;
	return ret;
}

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 platform_device *pdev = dev->pdev;
	int ret;

	dev_dbg(&pdev->dev, "\n");

	if (v->index > 1)
		return -EINVAL;
	return 0;
	if (v->index == 0) {
		ret = 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,
@@ -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 platform_device *pdev = dev->pdev;
	int ret;

	dev_dbg(&pdev->dev, "tuner=%d type=%d index=%d\n",
		band->tuner, band->type, band->index);
@@ -1017,16 +1071,20 @@ static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv,
			return -EINVAL;

		*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) {
		if (band->index >= ARRAY_SIZE(bands_fm))
			return -EINVAL;

		*band = bands_fm[band->index];
		ret = 0;
	} else {
		return -EINVAL;
		ret = -EINVAL;
	}

	return 0;
	return ret;
}

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 platform_device *pdev = dev->pdev;
	int ret  = 0;
	int ret;

	dev_dbg(&pdev->dev, "tuner=%d type=%d\n", f->tuner, f->type);

	if (f->tuner == 0) {
		f->frequency = dev->f_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) {
		f->frequency = dev->f_tuner;
		f->type = V4L2_TUNER_RF;
		ret = 0;
	} else {
		return -EINVAL;
		ret = -EINVAL;
	}

	return ret;
}

@@ -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);
		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) {
		dev->f_tuner = clamp_t(unsigned int, f->frequency,
				bands_fm[0].rangelow,
@@ -1089,7 +1155,6 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
	} else {
		ret = -EINVAL;
	}

	return ret;
}

@@ -1329,6 +1394,7 @@ static int rtl2832_sdr_probe(struct platform_device *pdev)

	/* setup the state */
	subdev = pdata->v4l2_subdev;
	dev->v4l2_subdev = pdata->v4l2_subdev;
	dev->pdev = pdev;
	dev->udev = pdata->dvb_usb_device->udev;
	dev->f_adc = bands_adc[0].rangelow;
@@ -1388,6 +1454,12 @@ static int rtl2832_sdr_probe(struct platform_device *pdev)
						   6000000);
		v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
		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:
		v4l2_ctrl_handler_init(&dev->hdl, 0);
		dev_err(&pdev->dev, "Unsupported tuner\n");
+1 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ struct rtl2832_sdr_platform_data {
	/*
	 * 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_FC0012    0x26
#define RTL2832_SDR_TUNER_E4000     0x27