Commit eae63ae0 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

[media] si470x: add control event support and more v4l2 compliancy fixes

Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Acked-by: default avatarTobias Lorenz <tobias.lorenz@gmx.net>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 4967d53d
...@@ -262,7 +262,7 @@ static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq) ...@@ -262,7 +262,7 @@ static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
*/ */
int si470x_set_freq(struct si470x_device *radio, unsigned int freq) int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
{ {
unsigned int spacing, band_bottom; unsigned int spacing, band_bottom, band_top;
unsigned short chan; unsigned short chan;
/* Spacing (kHz) */ /* Spacing (kHz) */
...@@ -278,19 +278,26 @@ int si470x_set_freq(struct si470x_device *radio, unsigned int freq) ...@@ -278,19 +278,26 @@ int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
spacing = 0.050 * FREQ_MUL; break; spacing = 0.050 * FREQ_MUL; break;
}; };
/* Bottom of Band (MHz) */ /* Bottom/Top of Band (MHz) */
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) { switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
/* 0: 87.5 - 108 MHz (USA, Europe) */ /* 0: 87.5 - 108 MHz (USA, Europe) */
case 0: case 0:
band_bottom = 87.5 * FREQ_MUL; break; band_bottom = 87.5 * FREQ_MUL;
band_top = 108 * FREQ_MUL;
break;
/* 1: 76 - 108 MHz (Japan wide band) */ /* 1: 76 - 108 MHz (Japan wide band) */
default: default:
band_bottom = 76 * FREQ_MUL; break; band_bottom = 76 * FREQ_MUL;
band_top = 108 * FREQ_MUL;
break;
/* 2: 76 - 90 MHz (Japan) */ /* 2: 76 - 90 MHz (Japan) */
case 2: case 2:
band_bottom = 76 * FREQ_MUL; break; band_bottom = 76 * FREQ_MUL;
band_top = 90 * FREQ_MUL;
break;
}; };
freq = clamp(freq, band_bottom, band_top);
/* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */ /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
chan = (freq - band_bottom) / spacing; chan = (freq - band_bottom) / spacing;
...@@ -515,17 +522,19 @@ static unsigned int si470x_fops_poll(struct file *file, ...@@ -515,17 +522,19 @@ static unsigned int si470x_fops_poll(struct file *file,
struct poll_table_struct *pts) struct poll_table_struct *pts)
{ {
struct si470x_device *radio = video_drvdata(file); struct si470x_device *radio = video_drvdata(file);
int retval = 0; unsigned long req_events = poll_requested_events(pts);
int retval = v4l2_ctrl_poll(file, pts);
if (req_events & (POLLIN | POLLRDNORM)) {
/* switch on rds reception */ /* switch on rds reception */
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
si470x_rds_on(radio); si470x_rds_on(radio);
poll_wait(file, &radio->read_queue, pts); poll_wait(file, &radio->read_queue, pts);
if (radio->rd_index != radio->wr_index) if (radio->rd_index != radio->wr_index)
retval = POLLIN | POLLRDNORM; retval |= POLLIN | POLLRDNORM;
}
return retval; return retval;
} }
...@@ -637,6 +646,8 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, ...@@ -637,6 +646,8 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI); tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI);
/* the ideal factor is 0xffff/75 = 873,8 */ /* the ideal factor is 0xffff/75 = 873,8 */
tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10); tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10);
if (tuner->signal > 0xffff)
tuner->signal = 0xffff;
/* automatic frequency control: -1: freq to low, 1 freq to high */ /* automatic frequency control: -1: freq to low, 1 freq to high */
/* AFCRL does only indicate that freq. differs, not if too low/high */ /* AFCRL does only indicate that freq. differs, not if too low/high */
...@@ -660,7 +671,7 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv, ...@@ -660,7 +671,7 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
int retval = 0; int retval = 0;
if (tuner->index != 0) if (tuner->index != 0)
goto done; return -EINVAL;
/* mono/stereo selector */ /* mono/stereo selector */
switch (tuner->audmode) { switch (tuner->audmode) {
...@@ -668,15 +679,13 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv, ...@@ -668,15 +679,13 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */ radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */
break; break;
case V4L2_TUNER_MODE_STEREO: case V4L2_TUNER_MODE_STEREO:
default:
radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */ radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
break; break;
default:
goto done;
} }
retval = si470x_set_register(radio, POWERCFG); retval = si470x_set_register(radio, POWERCFG);
done:
if (retval < 0) if (retval < 0)
dev_warn(&radio->videodev.dev, dev_warn(&radio->videodev.dev,
"set tuner failed with %d\n", retval); "set tuner failed with %d\n", retval);
...@@ -770,6 +779,8 @@ static const struct v4l2_ioctl_ops si470x_ioctl_ops = { ...@@ -770,6 +779,8 @@ static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
.vidioc_g_frequency = si470x_vidioc_g_frequency, .vidioc_g_frequency = si470x_vidioc_g_frequency,
.vidioc_s_frequency = si470x_vidioc_s_frequency, .vidioc_s_frequency = si470x_vidioc_s_frequency,
.vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek, .vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
}; };
......
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