Archived
14
0
Fork 0

Merge branch 'work'

This commit is contained in:
Mauro Carvalho Chehab 2006-01-15 21:31:10 -02:00
commit 21e2379b9e
15 changed files with 212 additions and 88 deletions

View file

@ -333,7 +333,7 @@ struct dvb_pll_desc dvb_pll_tbmv30111in = {
.name = "Samsung TBMV30111IN", .name = "Samsung TBMV30111IN",
.min = 54000000, .min = 54000000,
.max = 860000000, .max = 860000000,
.count = 4, .count = 6,
.entries = { .entries = {
{ 172000000, 44000000, 166666, 0xb4, 0x01 }, { 172000000, 44000000, 166666, 0xb4, 0x01 },
{ 214000000, 44000000, 166666, 0xb4, 0x02 }, { 214000000, 44000000, 166666, 0xb4, 0x02 },

View file

@ -333,10 +333,10 @@ static snd_pcm_hardware_t snd_cx88_digital_hw = {
.channels_min = 1, .channels_min = 1,
.channels_max = 2, .channels_max = 2,
.buffer_bytes_max = (2*2048), .buffer_bytes_max = (2*2048),
.period_bytes_min = 256, .period_bytes_min = 2048,
.period_bytes_max = 2048, .period_bytes_max = 2048,
.periods_min = 2, .periods_min = 2,
.periods_max = 16, .periods_max = 2,
}; };
/* /*

View file

@ -76,6 +76,58 @@ static IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
[ 0x40 ] = KEY_ZOOM, [ 0x40 ] = KEY_ZOOM,
}; };
static IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
[ 0x3a ] = KEY_KP0,
[ 0x31 ] = KEY_KP1,
[ 0x32 ] = KEY_KP2,
[ 0x33 ] = KEY_KP3,
[ 0x34 ] = KEY_KP4,
[ 0x35 ] = KEY_KP5,
[ 0x36 ] = KEY_KP6,
[ 0x37 ] = KEY_KP7,
[ 0x38 ] = KEY_KP8,
[ 0x39 ] = KEY_KP9,
[ 0x2f ] = KEY_POWER,
[ 0x2e ] = KEY_P,
[ 0x1f ] = KEY_L,
[ 0x2b ] = KEY_I,
[ 0x2d ] = KEY_ZOOM,
[ 0x1e ] = KEY_ZOOM,
[ 0x1b ] = KEY_VOLUMEUP,
[ 0x0f ] = KEY_VOLUMEDOWN,
[ 0x17 ] = KEY_CHANNELUP,
[ 0x1c ] = KEY_CHANNELDOWN,
[ 0x25 ] = KEY_INFO,
[ 0x3c ] = KEY_MUTE,
[ 0x3d ] = KEY_LEFT,
[ 0x3b ] = KEY_RIGHT,
[ 0x3f ] = KEY_UP,
[ 0x3e ] = KEY_DOWN,
[ 0x1a ] = KEY_PAUSE,
[ 0x1d ] = KEY_MENU,
[ 0x19 ] = KEY_PLAY,
[ 0x16 ] = KEY_REWIND,
[ 0x13 ] = KEY_FORWARD,
[ 0x15 ] = KEY_PAUSE,
[ 0x0e ] = KEY_REWIND,
[ 0x0d ] = KEY_PLAY,
[ 0x0b ] = KEY_STOP,
[ 0x07 ] = KEY_FORWARD,
[ 0x27 ] = KEY_RECORD,
[ 0x26 ] = KEY_TUNER,
[ 0x29 ] = KEY_TEXT,
[ 0x2a ] = KEY_MEDIA,
[ 0x18 ] = KEY_EPG,
[ 0x27 ] = KEY_RECORD,
};
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
@ -138,6 +190,28 @@ static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1; return 1;
} }
static int get_key_pinnacle_usb(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char buf[3];
/* poll IR chip */
if (3 != i2c_master_recv(&ir->c,buf,3)) {
dprintk("read error\n");
return -EIO;
}
dprintk("key %02x\n", buf[2]&0x3f);
if (buf[0]!=0x00){
return 0;
}
*ir_key = buf[2]&0x3f;
*ir_raw = buf[2]&0x3f;
return 1;
}
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir) void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir)
{ {
@ -159,6 +233,9 @@ void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir)
snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)"); snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)");
break; break;
case (EM2820_BOARD_PINNACLE_USB_2): case (EM2820_BOARD_PINNACLE_USB_2):
ir->ir_codes = ir_codes_em_pinnacle_usb;
ir->get_key = get_key_pinnacle_usb;
snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Pinnacle PCTV)");
break; break;
case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2): case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
ir->ir_codes = ir_codes_hauppauge_new; ir->ir_codes = ir_codes_hauppauge_new;

View file

@ -1031,8 +1031,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
} }
default: default:
/* nothing */ /* unknown */
break; return -EINVAL;
} }
return 0; return 0;
} }

View file

@ -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 /* This macro is allowed for *constants* only, gcc must calculate it
at compile time. Remember -- no floats in kernel mode */ at compile time. Remember -- no floats in kernel mode */
#define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24))) #define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24)))

View file

@ -353,8 +353,8 @@ static int mt2032_init(struct i2c_client *c)
} while (xok != 1 ); } while (xok != 1 );
t->xogc=xogc; t->xogc=xogc;
t->tv_freq = mt2032_set_tv_freq; t->set_tv_freq = mt2032_set_tv_freq;
t->radio_freq = mt2032_set_radio_freq; t->set_radio_freq = mt2032_set_radio_freq;
return(1); return(1);
} }
@ -481,8 +481,8 @@ static int mt2050_init(struct i2c_client *c)
i2c_master_recv(c,buf,1); i2c_master_recv(c,buf,1);
tuner_dbg("mt2050: sro is %x\n",buf[0]); tuner_dbg("mt2050: sro is %x\n",buf[0]);
t->tv_freq = mt2050_set_tv_freq; t->set_tv_freq = mt2050_set_tv_freq;
t->radio_freq = mt2050_set_radio_freq; t->set_radio_freq = mt2050_set_radio_freq;
return 0; return 0;
} }
@ -494,8 +494,8 @@ int microtune_init(struct i2c_client *c)
int company_code; int company_code;
memset(buf,0,sizeof(buf)); memset(buf,0,sizeof(buf));
t->tv_freq = NULL; t->set_tv_freq = NULL;
t->radio_freq = NULL; t->set_radio_freq = NULL;
t->standby = NULL; t->standby = NULL;
if (t->std & V4L2_STD_525_60) { if (t->std & V4L2_STD_525_60) {
tuner_dbg("pinnacle ntsc\n"); tuner_dbg("pinnacle ntsc\n");

View file

@ -567,8 +567,8 @@ int tda8290_init(struct i2c_client *c)
} }
tuner_info("tuner: type set to %s\n", c->name); tuner_info("tuner: type set to %s\n", c->name);
t->tv_freq = set_tv_freq; t->set_tv_freq = set_tv_freq;
t->radio_freq = set_radio_freq; t->set_radio_freq = set_radio_freq;
t->has_signal = has_signal; t->has_signal = has_signal;
t->standby = standby; t->standby = standby;
t->tda827x_lpsel = 0; t->tda827x_lpsel = 0;

View file

@ -62,7 +62,7 @@ extern int tuner_debug;
#define TEA5767_PORT1_HIGH 0x01 #define TEA5767_PORT1_HIGH 0x01
/* Forth register */ /* Fourth register */
#define TEA5767_PORT2_HIGH 0x80 #define TEA5767_PORT2_HIGH 0x80
/* Chips stops working. Only I2C bus remains on */ /* Chips stops working. Only I2C bus remains on */
#define TEA5767_STDBY 0x40 #define TEA5767_STDBY 0x40
@ -85,7 +85,7 @@ extern int tuner_debug;
/* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */ /* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */
#define TEA5767_SRCH_IND 0x01 #define TEA5767_SRCH_IND 0x01
/* Fiveth register */ /* Fifth register */
/* By activating, it will use Xtal at 13 MHz as reference for divider */ /* By activating, it will use Xtal at 13 MHz as reference for divider */
#define TEA5767_PLLREF_ENABLE 0x80 #define TEA5767_PLLREF_ENABLE 0x80
@ -109,13 +109,13 @@ extern int tuner_debug;
#define TEA5767_STEREO_MASK 0x80 #define TEA5767_STEREO_MASK 0x80
#define TEA5767_IF_CNTR_MASK 0x7f #define TEA5767_IF_CNTR_MASK 0x7f
/* Four register */ /* Fourth register */
#define TEA5767_ADC_LEVEL_MASK 0xf0 #define TEA5767_ADC_LEVEL_MASK 0xf0
/* should be 0 */ /* should be 0 */
#define TEA5767_CHIP_ID_MASK 0x0f #define TEA5767_CHIP_ID_MASK 0x0f
/* Fiveth register */ /* Fifth register */
/* Reserved for future extensions */ /* Reserved for future extensions */
#define TEA5767_RESERVED_MASK 0xff #define TEA5767_RESERVED_MASK 0xff
@ -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"); tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n");
buffer[2] |= TEA5767_HIGH_LO_INJECT; buffer[2] |= TEA5767_HIGH_LO_INJECT;
buffer[4] |= TEA5767_PLLREF_ENABLE; buffer[4] |= TEA5767_PLLREF_ENABLE;
div = (frq * 4000 / 16 + 700000 + 225000 + 25000) / 50000; div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000;
break; break;
case TEA5767_LOW_LO_13MHz: case TEA5767_LOW_LO_13MHz:
tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 13 MHz\n"); tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 13 MHz\n");
buffer[4] |= TEA5767_PLLREF_ENABLE; buffer[4] |= TEA5767_PLLREF_ENABLE;
div = (frq * 4000 / 16 - 700000 - 225000 + 25000) / 50000; div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000;
break; break;
case TEA5767_LOW_LO_32768: case TEA5767_LOW_LO_32768:
tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n"); tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n");
buffer[3] |= TEA5767_XTAL_32768; buffer[3] |= TEA5767_XTAL_32768;
/* const 700=4000*175 Khz - to adjust freq to right value */ /* 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; break;
case TEA5767_HIGH_LO_32768: case TEA5767_HIGH_LO_32768:
default: default:
@ -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"); tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio");
strlcpy(c->name, "tea5767", sizeof(c->name)); strlcpy(c->name, "tea5767", sizeof(c->name));
t->tv_freq = set_tv_freq; t->set_tv_freq = set_tv_freq;
t->radio_freq = set_radio_freq; t->set_radio_freq = set_radio_freq;
t->has_signal = tea5767_signal; t->has_signal = tea5767_signal;
t->is_stereo = tea5767_stereo; t->is_stereo = tea5767_stereo;
t->standby = tea5767_standby; t->standby = tea5767_standby;

View file

@ -82,7 +82,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
tuner_warn ("tuner type not set\n"); tuner_warn ("tuner type not set\n");
return; return;
} }
if (NULL == t->tv_freq) { if (NULL == t->set_tv_freq) {
tuner_warn ("Tuner has no way to set tv freq\n"); tuner_warn ("Tuner has no way to set tv freq\n");
return; return;
} }
@ -90,8 +90,14 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n", tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
freq / 16, freq % 16 * 100 / 16, tv_range[0], freq / 16, freq % 16 * 100 / 16, tv_range[0],
tv_range[1]); 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) static void set_radio_freq(struct i2c_client *c, unsigned int freq)
@ -102,18 +108,23 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
tuner_warn ("tuner type not set\n"); tuner_warn ("tuner type not set\n");
return; return;
} }
if (NULL == t->radio_freq) { if (NULL == t->set_radio_freq) {
tuner_warn ("tuner has no way to set radio frequency\n"); tuner_warn ("tuner has no way to set radio frequency\n");
return; 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", tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
freq / 16000, freq % 16000 * 100 / 16000, freq / 16000, freq % 16000 * 100 / 16000,
radio_range[0], radio_range[1]); 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); t->set_radio_freq(c, freq);
return;
} }
static void set_freq(struct i2c_client *c, unsigned long freq) static void set_freq(struct i2c_client *c, unsigned long freq)
@ -125,15 +136,16 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
tuner_dbg("radio freq set to %lu.%02lu\n", tuner_dbg("radio freq set to %lu.%02lu\n",
freq / 16000, freq % 16000 * 100 / 16000); freq / 16000, freq % 16000 * 100 / 16000);
set_radio_freq(c, freq); set_radio_freq(c, freq);
t->radio_freq = freq;
break; break;
case V4L2_TUNER_ANALOG_TV: case V4L2_TUNER_ANALOG_TV:
case V4L2_TUNER_DIGITAL_TV: case V4L2_TUNER_DIGITAL_TV:
tuner_dbg("tv freq set to %lu.%02lu\n", tuner_dbg("tv freq set to %lu.%02lu\n",
freq / 16, freq % 16 * 100 / 16); freq / 16, freq % 16 * 100 / 16);
set_tv_freq(c, freq); set_tv_freq(c, freq);
t->tv_freq = freq;
break; break;
} }
t->freq = freq;
} }
static void set_type(struct i2c_client *c, unsigned int type, static void set_type(struct i2c_client *c, unsigned int type,
@ -212,7 +224,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
if (t->mode_mask == T_UNINITIALIZED) if (t->mode_mask == T_UNINITIALIZED)
t->mode_mask = new_mode_mask; 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", 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, c->adapter->name, c->driver->driver.name, c->addr << 1, type,
t->mode_mask); t->mode_mask);
@ -377,11 +389,11 @@ static void tuner_status(struct i2c_client *client)
default: p = "undefined"; break; default: p = "undefined"; break;
} }
if (t->mode == V4L2_TUNER_RADIO) { if (t->mode == V4L2_TUNER_RADIO) {
freq = t->freq / 16000; freq = t->radio_freq / 16000;
freq_fraction = (t->freq % 16000) * 100 / 16000; freq_fraction = (t->radio_freq % 16000) * 100 / 16000;
} else { } else {
freq = t->freq / 16; freq = t->tv_freq / 16;
freq_fraction = (t->freq % 16) * 100 / 16; freq_fraction = (t->tv_freq % 16) * 100 / 16;
} }
tuner_info("Tuner mode: %s\n", p); tuner_info("Tuner mode: %s\n", p);
tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction); tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
@ -456,7 +468,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
t->type = TUNER_TEA5767; t->type = TUNER_TEA5767;
t->mode_mask = T_RADIO; t->mode_mask = T_RADIO;
t->mode = T_STANDBY; 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; default_mode_mask &= ~T_RADIO;
goto register_client; goto register_client;
@ -469,7 +481,8 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
if (default_mode_mask != T_UNINITIALIZED) { if (default_mode_mask != T_UNINITIALIZED) {
tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask); tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask);
t->mode_mask = 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; default_mode_mask = T_UNINITIALIZED;
} }
@ -565,16 +578,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
set_addr(client, (struct tuner_setup *)arg); set_addr(client, (struct tuner_setup *)arg);
break; break;
case AUDC_SET_RADIO: 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; break;
case TUNER_SET_STANDBY: case TUNER_SET_STANDBY:
{ if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL) return 0;
return 0; if (t->standby)
if (t->standby) t->standby (client);
t->standby (client); break;
break;
}
case VIDIOCSAUDIO: case VIDIOCSAUDIO:
if (check_mode(t, "VIDIOCSAUDIO") == EINVAL) if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
return 0; return 0;
@ -583,7 +598,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
/* Should be implemented, since bttv calls it */ /* Should be implemented, since bttv calls it */
tuner_dbg("VIDIOCSAUDIO not implemented.\n"); tuner_dbg("VIDIOCSAUDIO not implemented.\n");
break; break;
/* --- v4l ioctls --- */ /* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a /* take care: bttv does userspace copying, we'll get a
@ -609,8 +623,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
if (vc->norm < ARRAY_SIZE(map)) if (vc->norm < ARRAY_SIZE(map))
t->std = map[vc->norm]; t->std = map[vc->norm];
tuner_fixup_std(t); tuner_fixup_std(t);
if (t->freq) if (t->tv_freq)
set_tv_freq(client, t->freq); set_tv_freq(client, t->tv_freq);
return 0; return 0;
} }
case VIDIOCSFREQ: case VIDIOCSFREQ:
@ -684,15 +698,14 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
t->std = *id; t->std = *id;
tuner_fixup_std(t); tuner_fixup_std(t);
if (t->freq) if (t->tv_freq)
set_freq(client, t->freq); set_freq(client, t->tv_freq);
break; break;
} }
case VIDIOC_S_FREQUENCY: case VIDIOC_S_FREQUENCY:
{ {
struct v4l2_frequency *f = arg; struct v4l2_frequency *f = arg;
t->freq = f->frequency;
switch_v4l2(); switch_v4l2();
if (V4L2_TUNER_RADIO == f->type && if (V4L2_TUNER_RADIO == f->type &&
V4L2_TUNER_RADIO != t->mode) { V4L2_TUNER_RADIO != t->mode) {
@ -700,7 +713,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
== EINVAL) == EINVAL)
return 0; return 0;
} }
set_freq(client,t->freq); set_freq(client,f->frequency);
break; break;
} }
@ -712,7 +725,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
return 0; return 0;
switch_v4l2(); switch_v4l2();
f->type = t->mode; f->type = t->mode;
f->frequency = t->freq; f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
t->radio_freq : t->tv_freq;
break; break;
} }
case VIDIOC_G_TUNER: case VIDIOC_G_TUNER:
@ -763,7 +777,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
if (V4L2_TUNER_RADIO == t->mode) { if (V4L2_TUNER_RADIO == t->mode) {
t->audmode = tuner->audmode; t->audmode = tuner->audmode;
set_radio_freq(client, t->freq); set_radio_freq(client, t->radio_freq);
} }
break; break;
} }
@ -791,8 +805,13 @@ static int tuner_resume(struct device *dev)
struct tuner *t = i2c_get_clientdata (c); struct tuner *t = i2c_get_clientdata (c);
tuner_dbg ("resume\n"); tuner_dbg ("resume\n");
if (t->freq) if (V4L2_TUNER_RADIO == t->mode) {
set_freq(c, t->freq); if (t->radio_freq)
set_freq(c, t->radio_freq);
} else {
if (t->tv_freq)
set_freq(c, t->tv_freq);
}
return 0; return 0;
} }

View file

@ -136,7 +136,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
u8 config, tuneraddr; u8 config, tuneraddr;
u16 div; u16 div;
struct tunertype *tun; struct tunertype *tun;
unsigned char buffer[4]; u8 buffer[4];
int rc, IFPCoff, i, j; int rc, IFPCoff, i, j;
tun = &tuners[t->type]; tun = &tuners[t->type];
@ -147,6 +147,11 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
continue; continue;
break; break;
} }
if (i == tun->params[j].count) {
tuner_dbg("TV frequency out of range (%d > %d)",
freq, tun->params[j].ranges[i - 1].limit);
freq = tun->params[j].ranges[--i].limit;
}
config = tun->params[j].ranges[i].cb; config = tun->params[j].ranges[i].cb;
/* i == 0 -> VHF_LO */ /* i == 0 -> VHF_LO */
/* i == 1 -> VHF_HI */ /* i == 1 -> VHF_HI */
@ -239,20 +244,6 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
break; break;
} }
/*
* Philips FI1216MK2 remark from specification :
* for channel selection involving band switching, and to ensure
* smooth tuning to the desired channel without causing
* unnecessary charge pump action, it is recommended to consider
* the difference between wanted channel frequency and the
* current channel frequency. Unnecessary charge pump action
* will result in very low tuning voltage which may drive the
* oscillator to extreme conditions.
*
* Progfou: specification says to send config data before
* frequency in case (wanted frequency < current frequency).
*/
/* IFPCoff = Video Intermediate Frequency - Vif: /* IFPCoff = Video Intermediate Frequency - Vif:
940 =16*58.75 NTSC/J (Japan) 940 =16*58.75 NTSC/J (Japan)
732 =16*45.75 M/N STD 732 =16*45.75 M/N STD
@ -284,7 +275,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
offset / 16, offset % 16 * 100 / 16, offset / 16, offset % 16 * 100 / 16,
div); div);
if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) { if (tuners[t->type].params->cb_first_if_lower_freq && div < t->last_div) {
buffer[0] = tun->params[j].config; buffer[0] = tun->params[j].config;
buffer[1] = config; buffer[1] = config;
buffer[2] = (div>>8) & 0x7f; buffer[2] = (div>>8) & 0x7f;
@ -295,6 +286,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
buffer[2] = tun->params[j].config; buffer[2] = tun->params[j].config;
buffer[3] = config; buffer[3] = config;
} }
t->last_div = div;
tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
buffer[0],buffer[1],buffer[2],buffer[3]); buffer[0],buffer[1],buffer[2],buffer[3]);
@ -337,8 +329,8 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
{ {
struct tunertype *tun; struct tunertype *tun;
struct tuner *t = i2c_get_clientdata(c); struct tuner *t = i2c_get_clientdata(c);
unsigned char buffer[4]; u8 buffer[4];
unsigned div; u16 div;
int rc, j; int rc, j;
tun = &tuners[t->type]; tun = &tuners[t->type];
@ -374,9 +366,19 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
} }
buffer[0] = (div>>8) & 0x7f; buffer[0] = (div>>8) & 0x7f;
buffer[1] = div & 0xff; buffer[1] = div & 0xff;
if (tuners[t->type].params->cb_first_if_lower_freq && div < t->last_div) {
buffer[0] = buffer[2];
buffer[1] = buffer[3];
buffer[2] = (div>>8) & 0x7f;
buffer[3] = div & 0xff;
} else {
buffer[0] = (div>>8) & 0x7f;
buffer[1] = div & 0xff;
}
tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n", tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
buffer[0],buffer[1],buffer[2],buffer[3]); buffer[0],buffer[1],buffer[2],buffer[3]);
t->last_div = div;
if (4 != (rc = i2c_master_send(c,buffer,4))) if (4 != (rc = i2c_master_send(c,buffer,4)))
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
@ -390,10 +392,10 @@ int default_tuner_init(struct i2c_client *c)
t->type, tuners[t->type].name); t->type, tuners[t->type].name);
strlcpy(c->name, tuners[t->type].name, sizeof(c->name)); strlcpy(c->name, tuners[t->type].name, sizeof(c->name));
t->tv_freq = default_set_tv_freq; t->set_tv_freq = default_set_tv_freq;
t->radio_freq = default_set_radio_freq; t->set_radio_freq = default_set_radio_freq;
t->has_signal = tuner_signal; t->has_signal = tuner_signal;
t->is_stereo = tuner_stereo; t->is_stereo = tuner_stereo;
t->standby = NULL; t->standby = NULL;
return 0; return 0;

View file

@ -81,6 +81,7 @@ static struct tuner_params tuner_philips_ntsc_params[] = {
.ranges = tuner_philips_ntsc_ranges, .ranges = tuner_philips_ntsc_ranges,
.count = ARRAY_SIZE(tuner_philips_ntsc_ranges), .count = ARRAY_SIZE(tuner_philips_ntsc_ranges),
.config = 0x8e, .config = 0x8e,
.cb_first_if_lower_freq = 1,
}, },
}; };
@ -98,6 +99,7 @@ static struct tuner_params tuner_philips_secam_params[] = {
.ranges = tuner_philips_secam_ranges, .ranges = tuner_philips_secam_ranges,
.count = ARRAY_SIZE(tuner_philips_secam_ranges), .count = ARRAY_SIZE(tuner_philips_secam_ranges),
.config = 0x8e, .config = 0x8e,
.cb_first_if_lower_freq = 1,
}, },
}; };
@ -115,6 +117,7 @@ static struct tuner_params tuner_philips_pal_params[] = {
.ranges = tuner_philips_pal_ranges, .ranges = tuner_philips_pal_ranges,
.count = ARRAY_SIZE(tuner_philips_pal_ranges), .count = ARRAY_SIZE(tuner_philips_pal_ranges),
.config = 0x8e, .config = 0x8e,
.cb_first_if_lower_freq = 1,
}, },
}; };
@ -596,6 +599,7 @@ static struct tuner_params tuner_fm1216me_mk3_params[] = {
.ranges = tuner_fm1216me_mk3_pal_ranges, .ranges = tuner_fm1216me_mk3_pal_ranges,
.count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges), .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges),
.config = 0x8e, .config = 0x8e,
.cb_first_if_lower_freq = 1,
}, },
}; };
@ -670,6 +674,7 @@ static struct tuner_params tuner_fm1236_mk3_params[] = {
.ranges = tuner_fm1236_mk3_ntsc_ranges, .ranges = tuner_fm1236_mk3_ntsc_ranges,
.count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
.config = 0x8e, .config = 0x8e,
.cb_first_if_lower_freq = 1,
}, },
}; };
@ -784,6 +789,7 @@ static struct tuner_params tuner_tcl_2002n_params[] = {
.ranges = tuner_tcl_2002n_ntsc_ranges, .ranges = tuner_tcl_2002n_ntsc_ranges,
.count = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges), .count = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges),
.config = 0x8e, .config = 0x8e,
.cb_first_if_lower_freq = 1,
}, },
}; };

View file

@ -306,6 +306,7 @@ static const char *v4l2_int_ioctls[] = {
#endif #endif
[_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO", [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO",
[_IOC_NR(AUDC_SET_INPUT)] = "AUDC_SET_INPUT", [_IOC_NR(AUDC_SET_INPUT)] = "AUDC_SET_INPUT",
[_IOC_NR(MSP_SET_MATRIX)] = "MSP_SET_MATRIX",
[_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR", [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR",
[_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY",

View file

@ -19,6 +19,25 @@ struct tuner_range {
struct tuner_params { struct tuner_params {
enum param_type type; enum param_type type;
/* Many Philips based tuners have a comment like this in their
* datasheet:
*
* For channel selection involving band switching, and to ensure
* smooth tuning to the desired channel without causing
* unnecessary charge pump action, it is recommended to consider
* the difference between wanted channel frequency and the
* current channel frequency. Unnecessary charge pump action
* will result in very low tuning voltage which may drive the
* oscillator to extreme conditions.
*
* Set cb_first_if_lower_freq to 1, if this check is
* required for this tuner.
*
* I tested this for PAL by first setting the TV frequency to
* 203 MHz and then switching to 96.6 MHz FM radio. The result was
* static unless the control byte was sent first.
*/
unsigned int cb_first_if_lower_freq:1;
unsigned char config; /* to be moved into struct tuner_range for dvb-pll merge */ unsigned char config; /* to be moved into struct tuner_range for dvb-pll merge */
unsigned int count; unsigned int count;
@ -27,7 +46,6 @@ struct tuner_params {
struct tunertype { struct tunertype {
char *name; char *name;
unsigned int has_tda988x:1;
struct tuner_params *params; struct tuner_params *params;
}; };

View file

@ -179,7 +179,9 @@ struct tuner {
unsigned int mode; unsigned int mode;
unsigned int mode_mask; /* Combination of allowable modes */ unsigned int mode_mask; /* Combination of allowable modes */
unsigned int freq; /* keep track of the current settings */ unsigned int tv_freq; /* keep track of the current settings */
unsigned int radio_freq;
u16 last_div;
unsigned int audmode; unsigned int audmode;
v4l2_std_id std; v4l2_std_id std;
@ -197,8 +199,8 @@ struct tuner {
unsigned int sgIF; unsigned int sgIF;
/* function ptrs */ /* function ptrs */
void (*tv_freq)(struct i2c_client *c, unsigned int freq); void (*set_tv_freq)(struct i2c_client *c, unsigned int freq);
void (*radio_freq)(struct i2c_client *c, unsigned int freq); void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
int (*has_signal)(struct i2c_client *c); int (*has_signal)(struct i2c_client *c);
int (*is_stereo)(struct i2c_client *c); int (*is_stereo)(struct i2c_client *c);
void (*standby)(struct i2c_client *c); void (*standby)(struct i2c_client *c);

View file

@ -120,6 +120,13 @@ enum v4l2_chip_ident {
/* select from TV,radio,extern,MUTE */ /* select from TV,radio,extern,MUTE */
#define AUDC_SET_INPUT _IOW('d',89,int) #define AUDC_SET_INPUT _IOW('d',89,int)
/* msp3400 ioctl: will be removed in the near future */
struct msp_matrix {
int input;
int output;
};
#define MSP_SET_MATRIX _IOW('m',17,struct msp_matrix)
/* tuner ioctls */ /* tuner ioctls */
/* Sets tuner type and its I2C addr */ /* Sets tuner type and its I2C addr */
#define TUNER_SET_TYPE_ADDR _IOW('d',90,int) #define TUNER_SET_TYPE_ADDR _IOW('d',90,int)