[media] tea575x: fix HW seek
Fix HW seek in TEA575x to work properly: - a delay must be present after search start and before first register read or the seek does weird things - when the search stops, the new frequency is not available immediately, we must wait until it appears in the register (fortunately, we can clear the frequency bits when starting the search as it starts at the frequency currently set, not from the value written) - sometimes, seek remains on the current frequency (or moves only a little), so repeat it until it moves by at least 50 kHz Signed-off-by: Ondrej Zary <linux@rainbow-software.org> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
d4ecc83b79
commit
bc2b395c03
|
@ -89,7 +89,7 @@ static void snd_tea575x_write(struct snd_tea575x *tea, unsigned int val)
|
||||||
tea->ops->set_pins(tea, 0);
|
tea->ops->set_pins(tea, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int snd_tea575x_read(struct snd_tea575x *tea)
|
static u32 snd_tea575x_read(struct snd_tea575x *tea)
|
||||||
{
|
{
|
||||||
u16 l, rdata;
|
u16 l, rdata;
|
||||||
u32 data = 0;
|
u32 data = 0;
|
||||||
|
@ -120,6 +120,25 @@ static unsigned int snd_tea575x_read(struct snd_tea575x *tea)
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 snd_tea575x_get_freq(struct snd_tea575x *tea)
|
||||||
|
{
|
||||||
|
u32 freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK;
|
||||||
|
|
||||||
|
if (freq == 0)
|
||||||
|
return freq;
|
||||||
|
|
||||||
|
/* freq *= 12.5 */
|
||||||
|
freq *= 125;
|
||||||
|
freq /= 10;
|
||||||
|
/* crystal fixup */
|
||||||
|
if (tea->tea5759)
|
||||||
|
freq += TEA575X_FMIF;
|
||||||
|
else
|
||||||
|
freq -= TEA575X_FMIF;
|
||||||
|
|
||||||
|
return clamp(freq * 16, FREQ_LO, FREQ_HI); /* from kHz */
|
||||||
|
}
|
||||||
|
|
||||||
static void snd_tea575x_set_freq(struct snd_tea575x *tea)
|
static void snd_tea575x_set_freq(struct snd_tea575x *tea)
|
||||||
{
|
{
|
||||||
u32 freq = tea->freq;
|
u32 freq = tea->freq;
|
||||||
|
@ -225,38 +244,62 @@ static int vidioc_s_hw_freq_seek(struct file *file, void *fh,
|
||||||
struct v4l2_hw_freq_seek *a)
|
struct v4l2_hw_freq_seek *a)
|
||||||
{
|
{
|
||||||
struct snd_tea575x *tea = video_drvdata(file);
|
struct snd_tea575x *tea = video_drvdata(file);
|
||||||
|
unsigned long timeout;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (tea->cannot_read_data)
|
if (tea->cannot_read_data)
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
if (a->tuner || a->wrap_around)
|
if (a->tuner || a->wrap_around)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* clear the frequency, HW will fill it in */
|
||||||
|
tea->val &= ~TEA575X_BIT_FREQ_MASK;
|
||||||
tea->val |= TEA575X_BIT_SEARCH;
|
tea->val |= TEA575X_BIT_SEARCH;
|
||||||
tea->val &= ~TEA575X_BIT_UPDOWN;
|
|
||||||
if (a->seek_upward)
|
if (a->seek_upward)
|
||||||
tea->val |= TEA575X_BIT_UPDOWN;
|
tea->val |= TEA575X_BIT_UPDOWN;
|
||||||
|
else
|
||||||
|
tea->val &= ~TEA575X_BIT_UPDOWN;
|
||||||
snd_tea575x_write(tea, tea->val);
|
snd_tea575x_write(tea, tea->val);
|
||||||
|
timeout = jiffies + msecs_to_jiffies(10000);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
unsigned val = snd_tea575x_read(tea);
|
if (time_after(jiffies, timeout))
|
||||||
|
break;
|
||||||
if (!(val & TEA575X_BIT_SEARCH)) {
|
|
||||||
/* Found a frequency */
|
|
||||||
val &= TEA575X_BIT_FREQ_MASK;
|
|
||||||
val = (val * 10) / 125;
|
|
||||||
if (tea->tea5759)
|
|
||||||
val += TEA575X_FMIF;
|
|
||||||
else
|
|
||||||
val -= TEA575X_FMIF;
|
|
||||||
tea->freq = clamp(val * 16, FREQ_LO, FREQ_HI);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
|
if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
|
||||||
/* some signal arrived, stop search */
|
/* some signal arrived, stop search */
|
||||||
tea->val &= ~TEA575X_BIT_SEARCH;
|
tea->val &= ~TEA575X_BIT_SEARCH;
|
||||||
snd_tea575x_write(tea, tea->val);
|
snd_tea575x_set_freq(tea);
|
||||||
return -ERESTARTSYS;
|
return -ERESTARTSYS;
|
||||||
}
|
}
|
||||||
|
if (!(snd_tea575x_read(tea) & TEA575X_BIT_SEARCH)) {
|
||||||
|
u32 freq;
|
||||||
|
|
||||||
|
/* Found a frequency, wait until it can be read */
|
||||||
|
for (i = 0; i < 100; i++) {
|
||||||
|
msleep(10);
|
||||||
|
freq = snd_tea575x_get_freq(tea);
|
||||||
|
if (freq) /* available */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (freq == 0) /* shouldn't happen */
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
* if we moved by less than 50 kHz, or in the wrong
|
||||||
|
* direction, continue seeking
|
||||||
|
*/
|
||||||
|
if (abs(tea->freq - freq) < 16 * 50 ||
|
||||||
|
(a->seek_upward && freq < tea->freq) ||
|
||||||
|
(!a->seek_upward && freq > tea->freq)) {
|
||||||
|
snd_tea575x_write(tea, tea->val);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tea->freq = freq;
|
||||||
|
tea->val &= ~TEA575X_BIT_SEARCH;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
tea->val &= ~TEA575X_BIT_SEARCH;
|
||||||
|
snd_tea575x_set_freq(tea);
|
||||||
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl)
|
static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||||
|
@ -320,7 +363,7 @@ int snd_tea575x_init(struct snd_tea575x *tea)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40;
|
tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_5_28;
|
||||||
tea->freq = 90500 * 16; /* 90.5Mhz default */
|
tea->freq = 90500 * 16; /* 90.5Mhz default */
|
||||||
snd_tea575x_set_freq(tea);
|
snd_tea575x_set_freq(tea);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue