Skip to content

Commit

Permalink
V4L/DVB (3384): Separate tv & radio freqs, fix cb/freq transmit order…
Browse files Browse the repository at this point in the history
… for tuners that need this.

- Moved MSP_SET_MATRIX to v4l2-common.h
- Fix typos and integer overflows in tea5767.c
- Split old freq field into a tv_freq and a radio_freq. Prevents
  that a radio tuner is initialized with a tv frequency or vice versa.
- When switching to radio mode initialize the tuner with the last
  used radio frequency (this was already done for the TV mode).
  As a result of these changes the tuner module now remembers the
  last set radio and TV frequencies, which is what you would expect
  to happen.
- Move out of range frequencies to the closest valid frequency as per
  v4l2 API spec.
- Fix incorrect initial radio frequency (multiplier is 16000, not 16)
- Add boundary check for out of range frequencies.
- Use new flag to check if the order of the CB and freq. depends on
  the last set frequency. That is needed for some tuners or you can
  get static as a result. The flag is added for those tuners where I know
  that the datasheet indicates that this is necessary.
- For this new check use the last set div value, not the last frequency
  as radio frequencies are always much higher due to the 16000 multiplier.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
  • Loading branch information
Hans Verkuil authored and Mauro Carvalho Chehab committed Jan 15, 2006
1 parent 8f0bb9c commit 27487d4
Show file tree
Hide file tree
Showing 11 changed files with 129 additions and 82 deletions.
8 changes: 0 additions & 8 deletions drivers/media/video/msp3400.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,6 @@

/* ---------------------------------------------------------------------- */

struct msp_matrix {
int input;
int output;
};

/* ioctl for MSP_SET_MATRIX will have to be registered */
#define MSP_SET_MATRIX _IOW('m',17,struct msp_matrix)

/* This macro is allowed for *constants* only, gcc must calculate it
at compile time. Remember -- no floats in kernel mode */
#define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24)))
Expand Down
12 changes: 6 additions & 6 deletions drivers/media/video/mt20xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,8 @@ static int mt2032_init(struct i2c_client *c)
} while (xok != 1 );
t->xogc=xogc;

t->tv_freq = mt2032_set_tv_freq;
t->radio_freq = mt2032_set_radio_freq;
t->set_tv_freq = mt2032_set_tv_freq;
t->set_radio_freq = mt2032_set_radio_freq;
return(1);
}

Expand Down Expand Up @@ -481,8 +481,8 @@ static int mt2050_init(struct i2c_client *c)
i2c_master_recv(c,buf,1);

tuner_dbg("mt2050: sro is %x\n",buf[0]);
t->tv_freq = mt2050_set_tv_freq;
t->radio_freq = mt2050_set_radio_freq;
t->set_tv_freq = mt2050_set_tv_freq;
t->set_radio_freq = mt2050_set_radio_freq;
return 0;
}

Expand All @@ -494,8 +494,8 @@ int microtune_init(struct i2c_client *c)
int company_code;

memset(buf,0,sizeof(buf));
t->tv_freq = NULL;
t->radio_freq = NULL;
t->set_tv_freq = NULL;
t->set_radio_freq = NULL;
t->standby = NULL;
if (t->std & V4L2_STD_525_60) {
tuner_dbg("pinnacle ntsc\n");
Expand Down
4 changes: 2 additions & 2 deletions drivers/media/video/tda8290.c
Original file line number Diff line number Diff line change
Expand Up @@ -567,8 +567,8 @@ int tda8290_init(struct i2c_client *c)
}
tuner_info("tuner: type set to %s\n", c->name);

t->tv_freq = set_tv_freq;
t->radio_freq = set_radio_freq;
t->set_tv_freq = set_tv_freq;
t->set_radio_freq = set_radio_freq;
t->has_signal = has_signal;
t->standby = standby;
t->tda827x_lpsel = 0;
Expand Down
18 changes: 9 additions & 9 deletions drivers/media/video/tea5767.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ extern int tuner_debug;

#define TEA5767_PORT1_HIGH 0x01

/* Forth register */
/* Fourth register */
#define TEA5767_PORT2_HIGH 0x80
/* Chips stops working. Only I2C bus remains on */
#define TEA5767_STDBY 0x40
Expand All @@ -85,7 +85,7 @@ extern int tuner_debug;
/* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */
#define TEA5767_SRCH_IND 0x01

/* Fiveth register */
/* Fifth register */

/* By activating, it will use Xtal at 13 MHz as reference for divider */
#define TEA5767_PLLREF_ENABLE 0x80
Expand All @@ -109,13 +109,13 @@ extern int tuner_debug;
#define TEA5767_STEREO_MASK 0x80
#define TEA5767_IF_CNTR_MASK 0x7f

/* Four register */
/* Fourth register */
#define TEA5767_ADC_LEVEL_MASK 0xf0

/* should be 0 */
#define TEA5767_CHIP_ID_MASK 0x0f

/* Fiveth register */
/* Fifth register */
/* Reserved for future extensions */
#define TEA5767_RESERVED_MASK 0xff

Expand Down Expand Up @@ -220,19 +220,19 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq)
tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n");
buffer[2] |= TEA5767_HIGH_LO_INJECT;
buffer[4] |= TEA5767_PLLREF_ENABLE;
div = (frq * 4000 / 16 + 700000 + 225000 + 25000) / 50000;
div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000;
break;
case TEA5767_LOW_LO_13MHz:
tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 13 MHz\n");

buffer[4] |= TEA5767_PLLREF_ENABLE;
div = (frq * 4000 / 16 - 700000 - 225000 + 25000) / 50000;
div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000;
break;
case TEA5767_LOW_LO_32768:
tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n");
buffer[3] |= TEA5767_XTAL_32768;
/* const 700=4000*175 Khz - to adjust freq to right value */
div = ((frq * 4000 / 16 - 700000 - 225000) + 16384) >> 15;
div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15;
break;
case TEA5767_HIGH_LO_32768:
default:
Expand Down Expand Up @@ -350,8 +350,8 @@ int tea5767_tuner_init(struct i2c_client *c)
tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio");
strlcpy(c->name, "tea5767", sizeof(c->name));

t->tv_freq = set_tv_freq;
t->radio_freq = set_radio_freq;
t->set_tv_freq = set_tv_freq;
t->set_radio_freq = set_radio_freq;
t->has_signal = tea5767_signal;
t->is_stereo = tea5767_stereo;
t->standby = tea5767_standby;
Expand Down
85 changes: 52 additions & 33 deletions drivers/media/video/tuner-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,16 +82,22 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
tuner_warn ("tuner type not set\n");
return;
}
if (NULL == t->tv_freq) {
if (NULL == t->set_tv_freq) {
tuner_warn ("Tuner has no way to set tv freq\n");
return;
}
if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
freq / 16, freq % 16 * 100 / 16, tv_range[0],
tv_range[1]);
/* V4L2 spec: if the freq is not possible then the closest
possible value should be selected */
if (freq < tv_range[0] * 16)
freq = tv_range[0] * 16;
else
freq = tv_range[1] * 16;
}
t->tv_freq(c, freq);
t->set_tv_freq(c, freq);
}

static void set_radio_freq(struct i2c_client *c, unsigned int freq)
Expand All @@ -102,18 +108,23 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
tuner_warn ("tuner type not set\n");
return;
}
if (NULL == t->radio_freq) {
if (NULL == t->set_radio_freq) {
tuner_warn ("tuner has no way to set radio frequency\n");
return;
}
if (freq <= radio_range[0] * 16000 || freq >= radio_range[1] * 16000) {
if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
freq / 16000, freq % 16000 * 100 / 16000,
radio_range[0], radio_range[1]);
/* V4L2 spec: if the freq is not possible then the closest
possible value should be selected */
if (freq < radio_range[0] * 16000)
freq = radio_range[0] * 16000;
else
freq = radio_range[1] * 16000;
}

t->radio_freq(c, freq);
return;
t->set_radio_freq(c, freq);
}

static void set_freq(struct i2c_client *c, unsigned long freq)
Expand All @@ -125,15 +136,16 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
tuner_dbg("radio freq set to %lu.%02lu\n",
freq / 16000, freq % 16000 * 100 / 16000);
set_radio_freq(c, freq);
t->radio_freq = freq;
break;
case V4L2_TUNER_ANALOG_TV:
case V4L2_TUNER_DIGITAL_TV:
tuner_dbg("tv freq set to %lu.%02lu\n",
freq / 16, freq % 16 * 100 / 16);
set_tv_freq(c, freq);
t->tv_freq = freq;
break;
}
t->freq = freq;
}

static void set_type(struct i2c_client *c, unsigned int type,
Expand Down Expand Up @@ -212,7 +224,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
if (t->mode_mask == T_UNINITIALIZED)
t->mode_mask = new_mode_mask;

set_freq(c, t->freq);
set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
c->adapter->name, c->driver->driver.name, c->addr << 1, type,
t->mode_mask);
Expand Down Expand Up @@ -377,11 +389,11 @@ static void tuner_status(struct i2c_client *client)
default: p = "undefined"; break;
}
if (t->mode == V4L2_TUNER_RADIO) {
freq = t->freq / 16000;
freq_fraction = (t->freq % 16000) * 100 / 16000;
freq = t->radio_freq / 16000;
freq_fraction = (t->radio_freq % 16000) * 100 / 16000;
} else {
freq = t->freq / 16;
freq_fraction = (t->freq % 16) * 100 / 16;
freq = t->tv_freq / 16;
freq_fraction = (t->tv_freq % 16) * 100 / 16;
}
tuner_info("Tuner mode: %s\n", p);
tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
Expand Down Expand Up @@ -456,7 +468,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
t->type = TUNER_TEA5767;
t->mode_mask = T_RADIO;
t->mode = T_STANDBY;
t->freq = 87.5 * 16; /* Sets freq to FM range */
t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
default_mode_mask &= ~T_RADIO;

goto register_client;
Expand All @@ -469,7 +481,8 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
if (default_mode_mask != T_UNINITIALIZED) {
tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask);
t->mode_mask = default_mode_mask;
t->freq = 400 * 16; /* Sets freq to VHF High */
t->tv_freq = 400 * 16; /* Sets freq to VHF High */
t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
default_mode_mask = T_UNINITIALIZED;
}

Expand Down Expand Up @@ -565,16 +578,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
set_addr(client, (struct tuner_setup *)arg);
break;
case AUDC_SET_RADIO:
set_mode(client,t,V4L2_TUNER_RADIO, "AUDC_SET_RADIO");
if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
== EINVAL)
return 0;
if (t->radio_freq)
set_freq(client, t->radio_freq);
break;
case TUNER_SET_STANDBY:
{
if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
return 0;
if (t->standby)
t->standby (client);
break;
}
if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
return 0;
if (t->standby)
t->standby (client);
break;
case VIDIOCSAUDIO:
if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
return 0;
Expand All @@ -583,7 +598,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)

/* Should be implemented, since bttv calls it */
tuner_dbg("VIDIOCSAUDIO not implemented.\n");

break;
/* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a
Expand All @@ -609,8 +623,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
if (vc->norm < ARRAY_SIZE(map))
t->std = map[vc->norm];
tuner_fixup_std(t);
if (t->freq)
set_tv_freq(client, t->freq);
if (t->tv_freq)
set_tv_freq(client, t->tv_freq);
return 0;
}
case VIDIOCSFREQ:
Expand Down Expand Up @@ -684,23 +698,22 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)

t->std = *id;
tuner_fixup_std(t);
if (t->freq)
set_freq(client, t->freq);
if (t->tv_freq)
set_freq(client, t->tv_freq);
break;
}
case VIDIOC_S_FREQUENCY:
{
struct v4l2_frequency *f = arg;

t->freq = f->frequency;
switch_v4l2();
if (V4L2_TUNER_RADIO == f->type &&
V4L2_TUNER_RADIO != t->mode) {
if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
== EINVAL)
return 0;
}
set_freq(client,t->freq);
set_freq(client,f->frequency);

break;
}
Expand All @@ -712,7 +725,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
return 0;
switch_v4l2();
f->type = t->mode;
f->frequency = t->freq;
f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
t->radio_freq : t->tv_freq;
break;
}
case VIDIOC_G_TUNER:
Expand Down Expand Up @@ -763,7 +777,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)

if (V4L2_TUNER_RADIO == t->mode) {
t->audmode = tuner->audmode;
set_radio_freq(client, t->freq);
set_radio_freq(client, t->radio_freq);
}
break;
}
Expand Down Expand Up @@ -791,8 +805,13 @@ static int tuner_resume(struct device *dev)
struct tuner *t = i2c_get_clientdata (c);

tuner_dbg ("resume\n");
if (t->freq)
set_freq(c, t->freq);
if (V4L2_TUNER_RADIO == t->mode) {
if (t->radio_freq)
set_freq(c, t->radio_freq);
} else {
if (t->tv_freq)
set_freq(c, t->tv_freq);
}
return 0;
}

Expand Down
Loading

0 comments on commit 27487d4

Please sign in to comment.