diff options
-rw-r--r-- | drivers/media/video/msp3400.h | 8 | ||||
-rw-r--r-- | drivers/media/video/mt20xx.c | 12 | ||||
-rw-r--r-- | drivers/media/video/tda8290.c | 4 | ||||
-rw-r--r-- | drivers/media/video/tea5767.c | 18 | ||||
-rw-r--r-- | drivers/media/video/tuner-core.c | 85 | ||||
-rw-r--r-- | drivers/media/video/tuner-simple.c | 44 | ||||
-rw-r--r-- | drivers/media/video/tuner-types.c | 6 | ||||
-rw-r--r-- | drivers/media/video/v4l2-common.c | 1 | ||||
-rw-r--r-- | include/media/tuner-types.h | 18 | ||||
-rw-r--r-- | include/media/tuner.h | 8 | ||||
-rw-r--r-- | include/media/v4l2-common.h | 7 |
11 files changed, 129 insertions, 82 deletions
diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h index 70a5ef8ba017..a9ac57d0700b 100644 --- a/drivers/media/video/msp3400.h +++ b/drivers/media/video/msp3400.h | |||
@@ -6,14 +6,6 @@ | |||
6 | 6 | ||
7 | /* ---------------------------------------------------------------------- */ | 7 | /* ---------------------------------------------------------------------- */ |
8 | 8 | ||
9 | struct 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 0bf1caac5887..c7c9f3f8715c 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 2498b76df429..7b4fb282ac82 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 921fe72f23d5..c2b98f81c192 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 f30ef79d795e..2995b22acb43 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 | ||
97 | static void set_radio_freq(struct i2c_client *c, unsigned int freq) | 103 | 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) | |||
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 | ||
119 | static void set_freq(struct i2c_client *c, unsigned long freq) | 130 | 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) | |||
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 | ||
139 | static void set_type(struct i2c_client *c, unsigned int type, | 151 | 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, | |||
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 3879262cf4ca..37977ff49780 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 32c9be4c5ca6..6fe781798d89 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 5dbd7c1b362a..cd2c4475525e 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 756693188991..b37d59d5a103 100644 --- a/include/media/tuner-types.h +++ b/include/media/tuner-types.h | |||
@@ -20,6 +20,24 @@ struct tuner_range { | |||
20 | struct tuner_params { | 20 | struct 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 a1d63787bc08..a5beeac495c7 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 c74052abb189..d4030a7e16e0 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 */ | ||
124 | struct 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) |