Commit bbc8995f authored by Tobias Lorenz's avatar Tobias Lorenz Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (7997): si470x: hardware frequency seek support



This patch brings the following changes:
- this now finally adds hardware frequency seek support

Signed-off-by: default avatarTobias Lorenz <tobias.lorenz@gmx.net>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent ace7d4bb
Loading
Loading
Loading
Loading
+95 −2
Original line number Diff line number Diff line
@@ -101,11 +101,11 @@
 *		- unplugging fixed
 * 2008-05-07	Tobias Lorenz <tobias.lorenz@gmx.net>
 *		Version 1.0.8
 *		- hardware frequency seek support
 *		- afc indication
 *		- more safety checks, let si470x_get_freq return errno
 *
 * ToDo:
 * - add seeking support
 * - add firmware download/update support
 * - RDS support: interrupt mode, instead of polling
 * - add LED status output (check if that's not already done in firmware)
@@ -192,6 +192,11 @@ static unsigned int tune_timeout = 3000;
module_param(tune_timeout, uint, 0);
MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");

/* Seek timeout */
static unsigned int seek_timeout = 5000;
module_param(seek_timeout, uint, 0);
MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*");

/* RDS buffer blocks */
static unsigned int rds_buf = 100;
module_param(rds_buf, uint, 0);
@@ -726,6 +731,62 @@ static int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
}


/*
 * si470x_set_seek - set seek
 */
static int si470x_set_seek(struct si470x_device *radio,
		unsigned int wrap_around, unsigned int seek_upward)
{
	int retval = 0;
	unsigned long timeout;
	bool timed_out = 0;

	/* start seeking */
	radio->registers[POWERCFG] |= POWERCFG_SEEK;
	if (wrap_around == 1)
		radio->registers[POWERCFG] &= ~POWERCFG_SKMODE;
	else
		radio->registers[POWERCFG] |= POWERCFG_SKMODE;
	if (seek_upward == 1)
		radio->registers[POWERCFG] |= POWERCFG_SEEKUP;
	else
		radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP;
	retval = si470x_set_register(radio, POWERCFG);
	if (retval < 0)
		goto done;

	/* wait till seek operation has completed */
	timeout = jiffies + msecs_to_jiffies(seek_timeout);
	do {
		retval = si470x_get_register(radio, STATUSRSSI);
		if (retval < 0)
			goto stop;
		timed_out = time_after(jiffies, timeout);
	} while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
		(!timed_out));
	if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
		printk(KERN_WARNING DRIVER_NAME ": seek does not complete\n");
	if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
		printk(KERN_WARNING DRIVER_NAME
			": seek failed / band limit reached\n");
	if (timed_out)
		printk(KERN_WARNING DRIVER_NAME
			": seek timed out after %u ms\n", seek_timeout);

stop:
	/* stop seeking */
	radio->registers[POWERCFG] &= ~POWERCFG_SEEK;
	retval = si470x_set_register(radio, POWERCFG);

done:
	/* try again, if timed out */
	if ((retval == 0) && timed_out)
		retval = -EAGAIN;

	return retval;
}


/*
 * si470x_start - switch on radio
 */
@@ -1148,7 +1209,8 @@ static int si470x_vidioc_querycap(struct file *file, void *priv,
	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
	sprintf(capability->bus_info, "USB");
	capability->version = DRIVER_KERNEL_VERSION;
	capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
	capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
		V4L2_CAP_TUNER | V4L2_CAP_RADIO;

	return 0;
}
@@ -1494,6 +1556,36 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv,
}


/*
 * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek
 */
static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
		struct v4l2_hw_freq_seek *seek)
{
	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
	int retval = 0;

	/* safety checks */
	if (radio->disconnected) {
		retval = -EIO;
		goto done;
	}
	if ((seek->tuner != 0) && (seek->type != V4L2_TUNER_RADIO)) {
		retval = -EINVAL;
		goto done;
	}

	retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward);

done:
	if (retval < 0)
		printk(KERN_WARNING DRIVER_NAME
			": set hardware frequency seek failed with %d\n",
			retval);
	return retval;
}


/*
 * si470x_viddev_tamples - video device interface
 */
@@ -1514,6 +1606,7 @@ static struct video_device si470x_viddev_template = {
	.vidioc_s_tuner		= si470x_vidioc_s_tuner,
	.vidioc_g_frequency	= si470x_vidioc_g_frequency,
	.vidioc_s_frequency	= si470x_vidioc_s_frequency,
	.vidioc_s_hw_freq_seek	= si470x_vidioc_s_hw_freq_seek,
	.owner			= THIS_MODULE,
};