aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2006-01-15 12:04:52 -0500
committerMauro Carvalho Chehab <mchehab@brturbo.com.br>2006-01-15 18:25:32 -0500
commit27487d44712aaa37710cc508d5bd6119f5e9f976 (patch)
tree474acfb51469cc730cd76ebdf6f34680b3809442
parent8f0bb9c069fc487dadebe4cdd1e03f0df5ebf0e6 (diff)
V4L/DVB (3384): Separate tv & radio freqs, fix cb/freq transmit order 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>
-rw-r--r--drivers/media/video/msp3400.h8
-rw-r--r--drivers/media/video/mt20xx.c12
-rw-r--r--drivers/media/video/tda8290.c4
-rw-r--r--drivers/media/video/tea5767.c18
-rw-r--r--drivers/media/video/tuner-core.c85
-rw-r--r--drivers/media/video/tuner-simple.c44
-rw-r--r--drivers/media/video/tuner-types.c6
-rw-r--r--drivers/media/video/v4l2-common.c1
-rw-r--r--include/media/tuner-types.h18
-rw-r--r--include/media/tuner.h8
-rw-r--r--include/media/v4l2-common.h7
11 files changed, 129 insertions, 82 deletions
diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h
index 70a5ef8ba01..a9ac57d0700 100644
--- a/drivers/media/video/msp3400.h
+++ b/drivers/media/video/msp3400.h
@@ -6,14 +6,6 @@
6 6
7/* ---------------------------------------------------------------------- */ 7/* ---------------------------------------------------------------------- */
8 8
9struct msp_matrix {
10 int input;
11 int output;
12};
13
14/* ioctl for MSP_SET_MATRIX will have to be registered */
15#define MSP_SET_MATRIX _IOW('m',17,struct msp_matrix)
16
17/* This macro is allowed for *constants* only, gcc must calculate it 9/* This macro is allowed for *constants* only, gcc must calculate it
18 at compile time. Remember -- no floats in kernel mode */ 10 at compile time. Remember -- no floats in kernel mode */
19#define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24))) 11#define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24)))
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
index 0bf1caac588..c7c9f3f8715 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -353,8 +353,8 @@ static int mt2032_init(struct i2c_client *c)
353 } while (xok != 1 ); 353 } while (xok != 1 );
354 t->xogc=xogc; 354 t->xogc=xogc;
355 355
356 t->tv_freq = mt2032_set_tv_freq; 356 t->set_tv_freq = mt2032_set_tv_freq;
357 t->radio_freq = mt2032_set_radio_freq; 357 t->set_radio_freq = mt2032_set_radio_freq;
358 return(1); 358 return(1);
359} 359}
360 360
@@ -481,8 +481,8 @@ static int mt2050_init(struct i2c_client *c)
481 i2c_master_recv(c,buf,1); 481 i2c_master_recv(c,buf,1);
482 482
483 tuner_dbg("mt2050: sro is %x\n",buf[0]); 483 tuner_dbg("mt2050: sro is %x\n",buf[0]);
484 t->tv_freq = mt2050_set_tv_freq; 484 t->set_tv_freq = mt2050_set_tv_freq;
485 t->radio_freq = mt2050_set_radio_freq; 485 t->set_radio_freq = mt2050_set_radio_freq;
486 return 0; 486 return 0;
487} 487}
488 488
@@ -494,8 +494,8 @@ int microtune_init(struct i2c_client *c)
494 int company_code; 494 int company_code;
495 495
496 memset(buf,0,sizeof(buf)); 496 memset(buf,0,sizeof(buf));
497 t->tv_freq = NULL; 497 t->set_tv_freq = NULL;
498 t->radio_freq = NULL; 498 t->set_radio_freq = NULL;
499 t->standby = NULL; 499 t->standby = NULL;
500 if (t->std & V4L2_STD_525_60) { 500 if (t->std & V4L2_STD_525_60) {
501 tuner_dbg("pinnacle ntsc\n"); 501 tuner_dbg("pinnacle ntsc\n");
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index 2498b76df42..7b4fb282ac8 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -567,8 +567,8 @@ int tda8290_init(struct i2c_client *c)
567 } 567 }
568 tuner_info("tuner: type set to %s\n", c->name); 568 tuner_info("tuner: type set to %s\n", c->name);
569 569
570 t->tv_freq = set_tv_freq; 570 t->set_tv_freq = set_tv_freq;
571 t->radio_freq = set_radio_freq; 571 t->set_radio_freq = set_radio_freq;
572 t->has_signal = has_signal; 572 t->has_signal = has_signal;
573 t->standby = standby; 573 t->standby = standby;
574 t->tda827x_lpsel = 0; 574 t->tda827x_lpsel = 0;
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index 921fe72f23d..c2b98f81c19 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -62,7 +62,7 @@ extern int tuner_debug;
62 62
63#define TEA5767_PORT1_HIGH 0x01 63#define TEA5767_PORT1_HIGH 0x01
64 64
65/* Forth register */ 65/* Fourth register */
66#define TEA5767_PORT2_HIGH 0x80 66#define TEA5767_PORT2_HIGH 0x80
67/* Chips stops working. Only I2C bus remains on */ 67/* Chips stops working. Only I2C bus remains on */
68#define TEA5767_STDBY 0x40 68#define TEA5767_STDBY 0x40
@@ -85,7 +85,7 @@ extern int tuner_debug;
85/* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */ 85/* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */
86#define TEA5767_SRCH_IND 0x01 86#define TEA5767_SRCH_IND 0x01
87 87
88/* Fiveth register */ 88/* Fifth register */
89 89
90/* By activating, it will use Xtal at 13 MHz as reference for divider */ 90/* By activating, it will use Xtal at 13 MHz as reference for divider */
91#define TEA5767_PLLREF_ENABLE 0x80 91#define TEA5767_PLLREF_ENABLE 0x80
@@ -109,13 +109,13 @@ extern int tuner_debug;
109#define TEA5767_STEREO_MASK 0x80 109#define TEA5767_STEREO_MASK 0x80
110#define TEA5767_IF_CNTR_MASK 0x7f 110#define TEA5767_IF_CNTR_MASK 0x7f
111 111
112/* Four register */ 112/* Fourth register */
113#define TEA5767_ADC_LEVEL_MASK 0xf0 113#define TEA5767_ADC_LEVEL_MASK 0xf0
114 114
115/* should be 0 */ 115/* should be 0 */
116#define TEA5767_CHIP_ID_MASK 0x0f 116#define TEA5767_CHIP_ID_MASK 0x0f
117 117
118/* Fiveth register */ 118/* Fifth register */
119/* Reserved for future extensions */ 119/* Reserved for future extensions */
120#define TEA5767_RESERVED_MASK 0xff 120#define TEA5767_RESERVED_MASK 0xff
121 121
@@ -220,19 +220,19 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq)
220 tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n"); 220 tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n");
221 buffer[2] |= TEA5767_HIGH_LO_INJECT; 221 buffer[2] |= TEA5767_HIGH_LO_INJECT;
222 buffer[4] |= TEA5767_PLLREF_ENABLE; 222 buffer[4] |= TEA5767_PLLREF_ENABLE;
223 div = (frq * 4000 / 16 + 700000 + 225000 + 25000) / 50000; 223 div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000;
224 break; 224 break;
225 case TEA5767_LOW_LO_13MHz: 225 case TEA5767_LOW_LO_13MHz:
226 tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 13 MHz\n"); 226 tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 13 MHz\n");
227 227
228 buffer[4] |= TEA5767_PLLREF_ENABLE; 228 buffer[4] |= TEA5767_PLLREF_ENABLE;
229 div = (frq * 4000 / 16 - 700000 - 225000 + 25000) / 50000; 229 div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000;
230 break; 230 break;
231 case TEA5767_LOW_LO_32768: 231 case TEA5767_LOW_LO_32768:
232 tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n"); 232 tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n");
233 buffer[3] |= TEA5767_XTAL_32768; 233 buffer[3] |= TEA5767_XTAL_32768;
234 /* const 700=4000*175 Khz - to adjust freq to right value */ 234 /* const 700=4000*175 Khz - to adjust freq to right value */
235 div = ((frq * 4000 / 16 - 700000 - 225000) + 16384) >> 15; 235 div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15;
236 break; 236 break;
237 case TEA5767_HIGH_LO_32768: 237 case TEA5767_HIGH_LO_32768:
238 default: 238 default:
@@ -350,8 +350,8 @@ int tea5767_tuner_init(struct i2c_client *c)
350 tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio"); 350 tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio");
351 strlcpy(c->name, "tea5767", sizeof(c->name)); 351 strlcpy(c->name, "tea5767", sizeof(c->name));
352 352
353 t->tv_freq = set_tv_freq; 353 t->set_tv_freq = set_tv_freq;
354 t->radio_freq = set_radio_freq; 354 t->set_radio_freq = set_radio_freq;
355 t->has_signal = tea5767_signal; 355 t->has_signal = tea5767_signal;
356 t->is_stereo = tea5767_stereo; 356 t->is_stereo = tea5767_stereo;
357 t->standby = tea5767_standby; 357 t->standby = tea5767_standby;
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index f30ef79d795..2995b22acb4 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -82,7 +82,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
82 tuner_warn ("tuner type not set\n"); 82 tuner_warn ("tuner type not set\n");
83 return; 83 return;
84 } 84 }
85 if (NULL == t->tv_freq) { 85 if (NULL == t->set_tv_freq) {
86 tuner_warn ("Tuner has no way to set tv freq\n"); 86 tuner_warn ("Tuner has no way to set tv freq\n");
87 return; 87 return;
88 } 88 }
@@ -90,8 +90,14 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
90 tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n", 90 tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
91 freq / 16, freq % 16 * 100 / 16, tv_range[0], 91 freq / 16, freq % 16 * 100 / 16, tv_range[0],
92 tv_range[1]); 92 tv_range[1]);
93 /* V4L2 spec: if the freq is not possible then the closest
94 possible value should be selected */
95 if (freq < tv_range[0] * 16)
96 freq = tv_range[0] * 16;
97 else
98 freq = tv_range[1] * 16;
93 } 99 }
94 t->tv_freq(c, freq); 100 t->set_tv_freq(c, freq);
95} 101}
96 102
97static void set_radio_freq(struct i2c_client *c, unsigned int freq) 103static 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)
102 tuner_warn ("tuner type not set\n"); 108 tuner_warn ("tuner type not set\n");
103 return; 109 return;
104 } 110 }
105 if (NULL == t->radio_freq) { 111 if (NULL == t->set_radio_freq) {
106 tuner_warn ("tuner has no way to set radio frequency\n"); 112 tuner_warn ("tuner has no way to set radio frequency\n");
107 return; 113 return;
108 } 114 }
109 if (freq <= radio_range[0] * 16000 || freq >= radio_range[1] * 16000) { 115 if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
110 tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n", 116 tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
111 freq / 16000, freq % 16000 * 100 / 16000, 117 freq / 16000, freq % 16000 * 100 / 16000,
112 radio_range[0], radio_range[1]); 118 radio_range[0], radio_range[1]);
119 /* V4L2 spec: if the freq is not possible then the closest
120 possible value should be selected */
121 if (freq < radio_range[0] * 16000)
122 freq = radio_range[0] * 16000;
123 else
124 freq = radio_range[1] * 16000;
113 } 125 }
114 126
115 t->radio_freq(c, freq); 127 t->set_radio_freq(c, freq);
116 return;
117} 128}
118 129
119static void set_freq(struct i2c_client *c, unsigned long freq) 130static 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)
125 tuner_dbg("radio freq set to %lu.%02lu\n", 136 tuner_dbg("radio freq set to %lu.%02lu\n",
126 freq / 16000, freq % 16000 * 100 / 16000); 137 freq / 16000, freq % 16000 * 100 / 16000);
127 set_radio_freq(c, freq); 138 set_radio_freq(c, freq);
139 t->radio_freq = freq;
128 break; 140 break;
129 case V4L2_TUNER_ANALOG_TV: 141 case V4L2_TUNER_ANALOG_TV:
130 case V4L2_TUNER_DIGITAL_TV: 142 case V4L2_TUNER_DIGITAL_TV:
131 tuner_dbg("tv freq set to %lu.%02lu\n", 143 tuner_dbg("tv freq set to %lu.%02lu\n",
132 freq / 16, freq % 16 * 100 / 16); 144 freq / 16, freq % 16 * 100 / 16);
133 set_tv_freq(c, freq); 145 set_tv_freq(c, freq);
146 t->tv_freq = freq;
134 break; 147 break;
135 } 148 }
136 t->freq = freq;
137} 149}
138 150
139static void set_type(struct i2c_client *c, unsigned int type, 151static 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,
212 if (t->mode_mask == T_UNINITIALIZED) 224 if (t->mode_mask == T_UNINITIALIZED)
213 t->mode_mask = new_mode_mask; 225 t->mode_mask = new_mode_mask;
214 226
215 set_freq(c, t->freq); 227 set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
216 tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n", 228 tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
217 c->adapter->name, c->driver->driver.name, c->addr << 1, type, 229 c->adapter->name, c->driver->driver.name, c->addr << 1, type,
218 t->mode_mask); 230 t->mode_mask);
@@ -377,11 +389,11 @@ static void tuner_status(struct i2c_client *client)
377 default: p = "undefined"; break; 389 default: p = "undefined"; break;
378 } 390 }
379 if (t->mode == V4L2_TUNER_RADIO) { 391 if (t->mode == V4L2_TUNER_RADIO) {
380 freq = t->freq / 16000; 392 freq = t->radio_freq / 16000;
381 freq_fraction = (t->freq % 16000) * 100 / 16000; 393 freq_fraction = (t->radio_freq % 16000) * 100 / 16000;
382 } else { 394 } else {
383 freq = t->freq / 16; 395 freq = t->tv_freq / 16;
384 freq_fraction = (t->freq % 16) * 100 / 16; 396 freq_fraction = (t->tv_freq % 16) * 100 / 16;
385 } 397 }
386 tuner_info("Tuner mode: %s\n", p); 398 tuner_info("Tuner mode: %s\n", p);
387 tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction); 399 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)
456 t->type = TUNER_TEA5767; 468 t->type = TUNER_TEA5767;
457 t->mode_mask = T_RADIO; 469 t->mode_mask = T_RADIO;
458 t->mode = T_STANDBY; 470 t->mode = T_STANDBY;
459 t->freq = 87.5 * 16; /* Sets freq to FM range */ 471 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
460 default_mode_mask &= ~T_RADIO; 472 default_mode_mask &= ~T_RADIO;
461 473
462 goto register_client; 474 goto register_client;
@@ -469,7 +481,8 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
469 if (default_mode_mask != T_UNINITIALIZED) { 481 if (default_mode_mask != T_UNINITIALIZED) {
470 tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask); 482 tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask);
471 t->mode_mask = default_mode_mask; 483 t->mode_mask = default_mode_mask;
472 t->freq = 400 * 16; /* Sets freq to VHF High */ 484 t->tv_freq = 400 * 16; /* Sets freq to VHF High */
485 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
473 default_mode_mask = T_UNINITIALIZED; 486 default_mode_mask = T_UNINITIALIZED;
474 } 487 }
475 488
@@ -565,16 +578,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
565 set_addr(client, (struct tuner_setup *)arg); 578 set_addr(client, (struct tuner_setup *)arg);
566 break; 579 break;
567 case AUDC_SET_RADIO: 580 case AUDC_SET_RADIO:
568 set_mode(client,t,V4L2_TUNER_RADIO, "AUDC_SET_RADIO"); 581 if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
582 == EINVAL)
583 return 0;
584 if (t->radio_freq)
585 set_freq(client, t->radio_freq);
569 break; 586 break;
570 case TUNER_SET_STANDBY: 587 case TUNER_SET_STANDBY:
571 { 588 if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
572 if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL) 589 return 0;
573 return 0; 590 if (t->standby)
574 if (t->standby) 591 t->standby (client);
575 t->standby (client); 592 break;
576 break;
577 }
578 case VIDIOCSAUDIO: 593 case VIDIOCSAUDIO:
579 if (check_mode(t, "VIDIOCSAUDIO") == EINVAL) 594 if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
580 return 0; 595 return 0;
@@ -583,7 +598,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
583 598
584 /* Should be implemented, since bttv calls it */ 599 /* Should be implemented, since bttv calls it */
585 tuner_dbg("VIDIOCSAUDIO not implemented.\n"); 600 tuner_dbg("VIDIOCSAUDIO not implemented.\n");
586
587 break; 601 break;
588 /* --- v4l ioctls --- */ 602 /* --- v4l ioctls --- */
589 /* take care: bttv does userspace copying, we'll get a 603 /* 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)
609 if (vc->norm < ARRAY_SIZE(map)) 623 if (vc->norm < ARRAY_SIZE(map))
610 t->std = map[vc->norm]; 624 t->std = map[vc->norm];
611 tuner_fixup_std(t); 625 tuner_fixup_std(t);
612 if (t->freq) 626 if (t->tv_freq)
613 set_tv_freq(client, t->freq); 627 set_tv_freq(client, t->tv_freq);
614 return 0; 628 return 0;
615 } 629 }
616 case VIDIOCSFREQ: 630 case VIDIOCSFREQ:
@@ -684,15 +698,14 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
684 698
685 t->std = *id; 699 t->std = *id;
686 tuner_fixup_std(t); 700 tuner_fixup_std(t);
687 if (t->freq) 701 if (t->tv_freq)
688 set_freq(client, t->freq); 702 set_freq(client, t->tv_freq);
689 break; 703 break;
690 } 704 }
691 case VIDIOC_S_FREQUENCY: 705 case VIDIOC_S_FREQUENCY:
692 { 706 {
693 struct v4l2_frequency *f = arg; 707 struct v4l2_frequency *f = arg;
694 708
695 t->freq = f->frequency;
696 switch_v4l2(); 709 switch_v4l2();
697 if (V4L2_TUNER_RADIO == f->type && 710 if (V4L2_TUNER_RADIO == f->type &&
698 V4L2_TUNER_RADIO != t->mode) { 711 V4L2_TUNER_RADIO != t->mode) {
@@ -700,7 +713,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
700 == EINVAL) 713 == EINVAL)
701 return 0; 714 return 0;
702 } 715 }
703 set_freq(client,t->freq); 716 set_freq(client,f->frequency);
704 717
705 break; 718 break;
706 } 719 }
@@ -712,7 +725,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
712 return 0; 725 return 0;
713 switch_v4l2(); 726 switch_v4l2();
714 f->type = t->mode; 727 f->type = t->mode;
715 f->frequency = t->freq; 728 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
729 t->radio_freq : t->tv_freq;
716 break; 730 break;
717 } 731 }
718 case VIDIOC_G_TUNER: 732 case VIDIOC_G_TUNER:
@@ -763,7 +777,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
763 777
764 if (V4L2_TUNER_RADIO == t->mode) { 778 if (V4L2_TUNER_RADIO == t->mode) {
765 t->audmode = tuner->audmode; 779 t->audmode = tuner->audmode;
766 set_radio_freq(client, t->freq); 780 set_radio_freq(client, t->radio_freq);
767 } 781 }
768 break; 782 break;
769 } 783 }
@@ -791,8 +805,13 @@ static int tuner_resume(struct device *dev)
791 struct tuner *t = i2c_get_clientdata (c); 805 struct tuner *t = i2c_get_clientdata (c);
792 806
793 tuner_dbg ("resume\n"); 807 tuner_dbg ("resume\n");
794 if (t->freq) 808 if (V4L2_TUNER_RADIO == t->mode) {
795 set_freq(c, t->freq); 809 if (t->radio_freq)
810 set_freq(c, t->radio_freq);
811 } else {
812 if (t->tv_freq)
813 set_freq(c, t->tv_freq);
814 }
796 return 0; 815 return 0;
797} 816}
798 817
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index 3879262cf4c..37977ff4978 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -136,7 +136,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
136 u8 config, tuneraddr; 136 u8 config, tuneraddr;
137 u16 div; 137 u16 div;
138 struct tunertype *tun; 138 struct tunertype *tun;
139 unsigned char buffer[4]; 139 u8 buffer[4];
140 int rc, IFPCoff, i, j; 140 int rc, IFPCoff, i, j;
141 141
142 tun = &tuners[t->type]; 142 tun = &tuners[t->type];
@@ -147,6 +147,11 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
147 continue; 147 continue;
148 break; 148 break;
149 } 149 }
150 if (i == tun->params[j].count) {
151 tuner_dbg("TV frequency out of range (%d > %d)",
152 freq, tun->params[j].ranges[i - 1].limit);
153 freq = tun->params[j].ranges[--i].limit;
154 }
150 config = tun->params[j].ranges[i].cb; 155 config = tun->params[j].ranges[i].cb;
151 /* i == 0 -> VHF_LO */ 156 /* i == 0 -> VHF_LO */
152 /* i == 1 -> VHF_HI */ 157 /* i == 1 -> VHF_HI */
@@ -239,20 +244,6 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
239 break; 244 break;
240 } 245 }
241 246
242 /*
243 * Philips FI1216MK2 remark from specification :
244 * for channel selection involving band switching, and to ensure
245 * smooth tuning to the desired channel without causing
246 * unnecessary charge pump action, it is recommended to consider
247 * the difference between wanted channel frequency and the
248 * current channel frequency. Unnecessary charge pump action
249 * will result in very low tuning voltage which may drive the
250 * oscillator to extreme conditions.
251 *
252 * Progfou: specification says to send config data before
253 * frequency in case (wanted frequency < current frequency).
254 */
255
256 /* IFPCoff = Video Intermediate Frequency - Vif: 247 /* IFPCoff = Video Intermediate Frequency - Vif:
257 940 =16*58.75 NTSC/J (Japan) 248 940 =16*58.75 NTSC/J (Japan)
258 732 =16*45.75 M/N STD 249 732 =16*45.75 M/N STD
@@ -284,7 +275,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
284 offset / 16, offset % 16 * 100 / 16, 275 offset / 16, offset % 16 * 100 / 16,
285 div); 276 div);
286 277
287 if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) { 278 if (tuners[t->type].params->cb_first_if_lower_freq && div < t->last_div) {
288 buffer[0] = tun->params[j].config; 279 buffer[0] = tun->params[j].config;
289 buffer[1] = config; 280 buffer[1] = config;
290 buffer[2] = (div>>8) & 0x7f; 281 buffer[2] = (div>>8) & 0x7f;
@@ -295,6 +286,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
295 buffer[2] = tun->params[j].config; 286 buffer[2] = tun->params[j].config;
296 buffer[3] = config; 287 buffer[3] = config;
297 } 288 }
289 t->last_div = div;
298 tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", 290 tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
299 buffer[0],buffer[1],buffer[2],buffer[3]); 291 buffer[0],buffer[1],buffer[2],buffer[3]);
300 292
@@ -337,8 +329,8 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
337{ 329{
338 struct tunertype *tun; 330 struct tunertype *tun;
339 struct tuner *t = i2c_get_clientdata(c); 331 struct tuner *t = i2c_get_clientdata(c);
340 unsigned char buffer[4]; 332 u8 buffer[4];
341 unsigned div; 333 u16 div;
342 int rc, j; 334 int rc, j;
343 335
344 tun = &tuners[t->type]; 336 tun = &tuners[t->type];
@@ -374,9 +366,19 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
374 } 366 }
375 buffer[0] = (div>>8) & 0x7f; 367 buffer[0] = (div>>8) & 0x7f;
376 buffer[1] = div & 0xff; 368 buffer[1] = div & 0xff;
369 if (tuners[t->type].params->cb_first_if_lower_freq && div < t->last_div) {
370 buffer[0] = buffer[2];
371 buffer[1] = buffer[3];
372 buffer[2] = (div>>8) & 0x7f;
373 buffer[3] = div & 0xff;
374 } else {
375 buffer[0] = (div>>8) & 0x7f;
376 buffer[1] = div & 0xff;
377 }
377 378
378 tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n", 379 tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
379 buffer[0],buffer[1],buffer[2],buffer[3]); 380 buffer[0],buffer[1],buffer[2],buffer[3]);
381 t->last_div = div;
380 382
381 if (4 != (rc = i2c_master_send(c,buffer,4))) 383 if (4 != (rc = i2c_master_send(c,buffer,4)))
382 tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); 384 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)
390 t->type, tuners[t->type].name); 392 t->type, tuners[t->type].name);
391 strlcpy(c->name, tuners[t->type].name, sizeof(c->name)); 393 strlcpy(c->name, tuners[t->type].name, sizeof(c->name));
392 394
393 t->tv_freq = default_set_tv_freq; 395 t->set_tv_freq = default_set_tv_freq;
394 t->radio_freq = default_set_radio_freq; 396 t->set_radio_freq = default_set_radio_freq;
395 t->has_signal = tuner_signal; 397 t->has_signal = tuner_signal;
396 t->is_stereo = tuner_stereo; 398 t->is_stereo = tuner_stereo;
397 t->standby = NULL; 399 t->standby = NULL;
398 400
399 return 0; 401 return 0;
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index 32c9be4c5ca..6fe781798d8 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -81,6 +81,7 @@ static struct tuner_params tuner_philips_ntsc_params[] = {
81 .ranges = tuner_philips_ntsc_ranges, 81 .ranges = tuner_philips_ntsc_ranges,
82 .count = ARRAY_SIZE(tuner_philips_ntsc_ranges), 82 .count = ARRAY_SIZE(tuner_philips_ntsc_ranges),
83 .config = 0x8e, 83 .config = 0x8e,
84 .cb_first_if_lower_freq = 1,
84 }, 85 },
85}; 86};
86 87
@@ -98,6 +99,7 @@ static struct tuner_params tuner_philips_secam_params[] = {
98 .ranges = tuner_philips_secam_ranges, 99 .ranges = tuner_philips_secam_ranges,
99 .count = ARRAY_SIZE(tuner_philips_secam_ranges), 100 .count = ARRAY_SIZE(tuner_philips_secam_ranges),
100 .config = 0x8e, 101 .config = 0x8e,
102 .cb_first_if_lower_freq = 1,
101 }, 103 },
102}; 104};
103 105
@@ -115,6 +117,7 @@ static struct tuner_params tuner_philips_pal_params[] = {
115 .ranges = tuner_philips_pal_ranges, 117 .ranges = tuner_philips_pal_ranges,
116 .count = ARRAY_SIZE(tuner_philips_pal_ranges), 118 .count = ARRAY_SIZE(tuner_philips_pal_ranges),
117 .config = 0x8e, 119 .config = 0x8e,
120 .cb_first_if_lower_freq = 1,
118 }, 121 },
119}; 122};
120 123
@@ -596,6 +599,7 @@ static struct tuner_params tuner_fm1216me_mk3_params[] = {
596 .ranges = tuner_fm1216me_mk3_pal_ranges, 599 .ranges = tuner_fm1216me_mk3_pal_ranges,
597 .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges), 600 .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges),
598 .config = 0x8e, 601 .config = 0x8e,
602 .cb_first_if_lower_freq = 1,
599 }, 603 },
600}; 604};
601 605
@@ -670,6 +674,7 @@ static struct tuner_params tuner_fm1236_mk3_params[] = {
670 .ranges = tuner_fm1236_mk3_ntsc_ranges, 674 .ranges = tuner_fm1236_mk3_ntsc_ranges,
671 .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), 675 .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
672 .config = 0x8e, 676 .config = 0x8e,
677 .cb_first_if_lower_freq = 1,
673 }, 678 },
674}; 679};
675 680
@@ -784,6 +789,7 @@ static struct tuner_params tuner_tcl_2002n_params[] = {
784 .ranges = tuner_tcl_2002n_ntsc_ranges, 789 .ranges = tuner_tcl_2002n_ntsc_ranges,
785 .count = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges), 790 .count = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges),
786 .config = 0x8e, 791 .config = 0x8e,
792 .cb_first_if_lower_freq = 1,
787 }, 793 },
788}; 794};
789 795
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 5dbd7c1b362..cd2c4475525 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -306,6 +306,7 @@ static const char *v4l2_int_ioctls[] = {
306#endif 306#endif
307 [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO", 307 [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO",
308 [_IOC_NR(AUDC_SET_INPUT)] = "AUDC_SET_INPUT", 308 [_IOC_NR(AUDC_SET_INPUT)] = "AUDC_SET_INPUT",
309 [_IOC_NR(MSP_SET_MATRIX)] = "MSP_SET_MATRIX",
309 310
310 [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR", 311 [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR",
311 [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", 312 [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY",
diff --git a/include/media/tuner-types.h b/include/media/tuner-types.h
index 75669318899..b37d59d5a10 100644
--- a/include/media/tuner-types.h
+++ b/include/media/tuner-types.h
@@ -20,6 +20,24 @@ struct tuner_range {
20struct tuner_params { 20struct tuner_params {
21 enum param_type type; 21 enum param_type type;
22 unsigned int tda988x; 22 unsigned int tda988x;
23 /* Many Philips based tuners have a comment like this in their
24 * datasheet:
25 *
26 * For channel selection involving band switching, and to ensure
27 * smooth tuning to the desired channel without causing
28 * unnecessary charge pump action, it is recommended to consider
29 * the difference between wanted channel frequency and the
30 * current channel frequency. Unnecessary charge pump action
31 * will result in very low tuning voltage which may drive the
32 * oscillator to extreme conditions.
33 *
34 * Set this flag to 1 if this tuner needs this check.
35 *
36 * I tested this for PAL by first setting the TV frequency to
37 * 203 MHz and then switching to 96.6 MHz FM radio. The result was
38 * static unless the control byte was sent first.
39 */
40 unsigned int cb_first_if_lower_freq:1;
23 unsigned char config; /* to be moved into struct tuner_range for dvb-pll merge */ 41 unsigned char config; /* to be moved into struct tuner_range for dvb-pll merge */
24 42
25 unsigned int count; 43 unsigned int count;
diff --git a/include/media/tuner.h b/include/media/tuner.h
index a1d63787bc0..a5beeac495c 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -179,7 +179,9 @@ struct tuner {
179 unsigned int mode; 179 unsigned int mode;
180 unsigned int mode_mask; /* Combination of allowable modes */ 180 unsigned int mode_mask; /* Combination of allowable modes */
181 181
182 unsigned int freq; /* keep track of the current settings */ 182 unsigned int tv_freq; /* keep track of the current settings */
183 unsigned int radio_freq;
184 u16 last_div;
183 unsigned int audmode; 185 unsigned int audmode;
184 v4l2_std_id std; 186 v4l2_std_id std;
185 187
@@ -197,8 +199,8 @@ struct tuner {
197 unsigned int sgIF; 199 unsigned int sgIF;
198 200
199 /* function ptrs */ 201 /* function ptrs */
200 void (*tv_freq)(struct i2c_client *c, unsigned int freq); 202 void (*set_tv_freq)(struct i2c_client *c, unsigned int freq);
201 void (*radio_freq)(struct i2c_client *c, unsigned int freq); 203 void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
202 int (*has_signal)(struct i2c_client *c); 204 int (*has_signal)(struct i2c_client *c);
203 int (*is_stereo)(struct i2c_client *c); 205 int (*is_stereo)(struct i2c_client *c);
204 void (*standby)(struct i2c_client *c); 206 void (*standby)(struct i2c_client *c);
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index c74052abb18..d4030a7e16e 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -120,6 +120,13 @@ enum v4l2_chip_ident {
120/* select from TV,radio,extern,MUTE */ 120/* select from TV,radio,extern,MUTE */
121#define AUDC_SET_INPUT _IOW('d',89,int) 121#define AUDC_SET_INPUT _IOW('d',89,int)
122 122
123/* msp3400 ioctl: will be removed in the near future */
124struct msp_matrix {
125 int input;
126 int output;
127};
128#define MSP_SET_MATRIX _IOW('m',17,struct msp_matrix)
129
123/* tuner ioctls */ 130/* tuner ioctls */
124/* Sets tuner type and its I2C addr */ 131/* Sets tuner type and its I2C addr */
125#define TUNER_SET_TYPE_ADDR _IOW('d',90,int) 132#define TUNER_SET_TYPE_ADDR _IOW('d',90,int)