diff options
Diffstat (limited to 'drivers/media/video/tuner-core.c')
-rw-r--r-- | drivers/media/video/tuner-core.c | 163 |
1 files changed, 85 insertions, 78 deletions
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index eaabfc85870..6f6bf4a633f 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: tuner-core.c,v 1.15 2005/06/12 01:36:14 mchehab Exp $ | 2 | * $Id: tuner-core.c,v 1.29 2005/06/21 15:40:33 mchehab Exp $ |
3 | * | 3 | * |
4 | * i2c tv tuner chip device driver | 4 | * i2c tv tuner chip device driver |
5 | * core core, i.e. kernel interfaces, registering and so on | 5 | * core core, i.e. kernel interfaces, registering and so on |
@@ -26,7 +26,6 @@ | |||
26 | /* | 26 | /* |
27 | * comment line bellow to return to old behavor, where only one I2C device is supported | 27 | * comment line bellow to return to old behavor, where only one I2C device is supported |
28 | */ | 28 | */ |
29 | #define CONFIG_TUNER_MULTI_I2C /**/ | ||
30 | 29 | ||
31 | #define UNSET (-1U) | 30 | #define UNSET (-1U) |
32 | 31 | ||
@@ -58,9 +57,7 @@ MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); | |||
58 | MODULE_LICENSE("GPL"); | 57 | MODULE_LICENSE("GPL"); |
59 | 58 | ||
60 | static int this_adap; | 59 | static int this_adap; |
61 | #ifdef CONFIG_TUNER_MULTI_I2C | ||
62 | static unsigned short first_tuner, tv_tuner, radio_tuner; | 60 | static unsigned short first_tuner, tv_tuner, radio_tuner; |
63 | #endif | ||
64 | 61 | ||
65 | static struct i2c_driver driver; | 62 | static struct i2c_driver driver; |
66 | static struct i2c_client client_template; | 63 | static struct i2c_client client_template; |
@@ -81,26 +78,9 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) | |||
81 | return; | 78 | return; |
82 | } | 79 | } |
83 | if (freq < tv_range[0]*16 || freq > tv_range[1]*16) { | 80 | if (freq < tv_range[0]*16 || freq > tv_range[1]*16) { |
84 | |||
85 | if (freq >= tv_range[0]*16364 && freq <= tv_range[1]*16384) { | ||
86 | /* V4L2_TUNER_CAP_LOW frequency */ | ||
87 | |||
88 | tuner_dbg("V4L2_TUNER_CAP_LOW freq selected for TV. Tuners yet doesn't support converting it to valid freq.\n"); | ||
89 | |||
90 | t->tv_freq(c,freq>>10); | ||
91 | |||
92 | return; | ||
93 | } else { | ||
94 | /* FIXME: better do that chip-specific, but | ||
95 | right now we don't have that in the config | ||
96 | struct and this way is still better than no | ||
97 | check at all */ | ||
98 | tuner_info("TV freq (%d.%02d) out of range (%d-%d)\n", | 81 | tuner_info("TV freq (%d.%02d) out of range (%d-%d)\n", |
99 | freq/16,freq%16*100/16,tv_range[0],tv_range[1]); | 82 | freq/16,freq%16*100/16,tv_range[0],tv_range[1]); |
100 | return; | ||
101 | } | ||
102 | } | 83 | } |
103 | tuner_dbg("62.5 Khz freq step selected for TV.\n"); | ||
104 | t->tv_freq(c,freq); | 84 | t->tv_freq(c,freq); |
105 | } | 85 | } |
106 | 86 | ||
@@ -116,31 +96,18 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) | |||
116 | tuner_info("no radio tuning for this one, sorry.\n"); | 96 | tuner_info("no radio tuning for this one, sorry.\n"); |
117 | return; | 97 | return; |
118 | } | 98 | } |
119 | if (freq < radio_range[0]*16 || freq > radio_range[1]*16) { | 99 | if (freq >= radio_range[0]*16000 && freq <= radio_range[1]*16000) { |
120 | if (freq >= tv_range[0]*16364 && freq <= tv_range[1]*16384) { | 100 | if (tuner_debug) |
121 | /* V4L2_TUNER_CAP_LOW frequency */ | 101 | tuner_info("radio freq step 62.5Hz (%d.%06d)\n", |
122 | if (t->type == TUNER_TEA5767) { | 102 | freq/16000,freq%16000*1000/16); |
123 | tuner_info("radio freq step 62.5Hz (%d.%06d)\n",(freq>>14),freq%(1<<14)*10000); | 103 | t->radio_freq(c,freq); |
124 | t->radio_freq(c,freq>>10); | 104 | } else { |
125 | return; | 105 | tuner_info("radio freq (%d.%02d) out of range (%d-%d)\n", |
126 | } | 106 | freq/16,freq%16*100/16, |
127 | 107 | radio_range[0],radio_range[1]); | |
128 | tuner_dbg("V4L2_TUNER_CAP_LOW freq selected for Radio. Tuners yet doesn't support converting it to valid freq.\n"); | ||
129 | |||
130 | tuner_info("radio freq (%d.%06d)\n",(freq>>14),freq%(1<<14)*10000); | ||
131 | |||
132 | t->radio_freq(c,freq>>10); | ||
133 | return; | ||
134 | |||
135 | } else { | ||
136 | tuner_info("radio freq (%d.%02d) out of range (%d-%d)\n", | ||
137 | freq/16,freq%16*100/16, | ||
138 | radio_range[0],radio_range[1]); | ||
139 | return; | ||
140 | } | ||
141 | } | 108 | } |
142 | tuner_dbg("62.5 Khz freq step selected for Radio.\n"); | 109 | |
143 | t->radio_freq(c,freq); | 110 | return; |
144 | } | 111 | } |
145 | 112 | ||
146 | static void set_freq(struct i2c_client *c, unsigned long freq) | 113 | static void set_freq(struct i2c_client *c, unsigned long freq) |
@@ -166,8 +133,8 @@ static void set_freq(struct i2c_client *c, unsigned long freq) | |||
166 | static void set_type(struct i2c_client *c, unsigned int type) | 133 | static void set_type(struct i2c_client *c, unsigned int type) |
167 | { | 134 | { |
168 | struct tuner *t = i2c_get_clientdata(c); | 135 | struct tuner *t = i2c_get_clientdata(c); |
136 | unsigned char buffer[4]; | ||
169 | 137 | ||
170 | tuner_dbg ("I2C addr 0x%02x with type %d\n",c->addr<<1,type); | ||
171 | /* sanity check */ | 138 | /* sanity check */ |
172 | if (type == UNSET || type == TUNER_ABSENT) | 139 | if (type == UNSET || type == TUNER_ABSENT) |
173 | return; | 140 | return; |
@@ -179,8 +146,8 @@ static void set_type(struct i2c_client *c, unsigned int type) | |||
179 | t->type = type; | 146 | t->type = type; |
180 | return; | 147 | return; |
181 | } | 148 | } |
182 | if (t->initialized) | 149 | if ((t->initialized) && (t->type == type)) |
183 | /* run only once */ | 150 | /* run only once except type change Hac 04/05*/ |
184 | return; | 151 | return; |
185 | 152 | ||
186 | t->initialized = 1; | 153 | t->initialized = 1; |
@@ -193,25 +160,42 @@ static void set_type(struct i2c_client *c, unsigned int type) | |||
193 | case TUNER_PHILIPS_TDA8290: | 160 | case TUNER_PHILIPS_TDA8290: |
194 | tda8290_init(c); | 161 | tda8290_init(c); |
195 | break; | 162 | break; |
163 | case TUNER_TEA5767: | ||
164 | if (tea5767_tuner_init(c)==EINVAL) t->type=TUNER_ABSENT; | ||
165 | break; | ||
166 | case TUNER_PHILIPS_FMD1216ME_MK3: | ||
167 | buffer[0] = 0x0b; | ||
168 | buffer[1] = 0xdc; | ||
169 | buffer[2] = 0x9c; | ||
170 | buffer[3] = 0x60; | ||
171 | i2c_master_send(c,buffer,4); | ||
172 | mdelay(1); | ||
173 | buffer[2] = 0x86; | ||
174 | buffer[3] = 0x54; | ||
175 | i2c_master_send(c,buffer,4); | ||
176 | default_tuner_init(c); | ||
177 | break; | ||
196 | default: | 178 | default: |
179 | /* TEA5767 autodetection code */ | ||
180 | if (tea5767_tuner_init(c)!=EINVAL) { | ||
181 | t->type = TUNER_TEA5767; | ||
182 | if (first_tuner == 0x60) | ||
183 | first_tuner++; | ||
184 | break; | ||
185 | } | ||
186 | |||
197 | default_tuner_init(c); | 187 | default_tuner_init(c); |
198 | break; | 188 | break; |
199 | } | 189 | } |
190 | tuner_dbg ("I2C addr 0x%02x with type %d\n",c->addr<<1,type); | ||
200 | } | 191 | } |
201 | 192 | ||
202 | #ifdef CONFIG_TUNER_MULTI_I2C | ||
203 | #define CHECK_ADDR(tp,cmd,tun) if (client->addr!=tp) { \ | 193 | #define CHECK_ADDR(tp,cmd,tun) if (client->addr!=tp) { \ |
204 | return 0; } else \ | 194 | return 0; } else if (tuner_debug) \ |
205 | tuner_info ("Cmd %s accepted to "tun"\n",cmd); | 195 | tuner_info ("Cmd %s accepted to "tun"\n",cmd); |
206 | #define CHECK_MODE(cmd) if (t->mode == V4L2_TUNER_RADIO) { \ | 196 | #define CHECK_MODE(cmd) if (t->mode == V4L2_TUNER_RADIO) { \ |
207 | CHECK_ADDR(radio_tuner,cmd,"radio") } else \ | 197 | CHECK_ADDR(radio_tuner,cmd,"radio") } else \ |
208 | { CHECK_ADDR(tv_tuner,cmd,"TV"); } | 198 | { CHECK_ADDR(tv_tuner,cmd,"TV"); } |
209 | #else | ||
210 | #define CHECK_ADDR(tp,cmd,tun) tuner_info ("Cmd %s accepted to "tun"\n",cmd); | ||
211 | #define CHECK_MODE(cmd) tuner_info ("Cmd %s accepted\n",cmd); | ||
212 | #endif | ||
213 | |||
214 | #ifdef CONFIG_TUNER_MULTI_I2C | ||
215 | 199 | ||
216 | static void set_addr(struct i2c_client *c, struct tuner_addr *tun_addr) | 200 | static void set_addr(struct i2c_client *c, struct tuner_addr *tun_addr) |
217 | { | 201 | { |
@@ -242,9 +226,6 @@ static void set_addr(struct i2c_client *c, struct tuner_addr *tun_addr) | |||
242 | } | 226 | } |
243 | set_type(c,tun_addr->type); | 227 | set_type(c,tun_addr->type); |
244 | } | 228 | } |
245 | #else | ||
246 | #define set_addr(c,tun_addr) set_type(c,(tun_addr)->type) | ||
247 | #endif | ||
248 | 229 | ||
249 | static char pal[] = "-"; | 230 | static char pal[] = "-"; |
250 | module_param_string(pal, pal, sizeof(pal), 0644); | 231 | module_param_string(pal, pal, sizeof(pal), 0644); |
@@ -284,17 +265,12 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) | |||
284 | { | 265 | { |
285 | struct tuner *t; | 266 | struct tuner *t; |
286 | 267 | ||
287 | #ifndef CONFIG_TUNER_MULTI_I2C | ||
288 | if (this_adap > 0) | ||
289 | return -1; | ||
290 | #else | ||
291 | /* by default, first I2C card is both tv and radio tuner */ | 268 | /* by default, first I2C card is both tv and radio tuner */ |
292 | if (this_adap == 0) { | 269 | if (this_adap == 0) { |
293 | first_tuner = addr; | 270 | first_tuner = addr; |
294 | tv_tuner = addr; | 271 | tv_tuner = addr; |
295 | radio_tuner = addr; | 272 | radio_tuner = addr; |
296 | } | 273 | } |
297 | #endif | ||
298 | this_adap++; | 274 | this_adap++; |
299 | 275 | ||
300 | client_template.adapter = adap; | 276 | client_template.adapter = adap; |
@@ -308,6 +284,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) | |||
308 | i2c_set_clientdata(&t->i2c, t); | 284 | i2c_set_clientdata(&t->i2c, t); |
309 | t->type = UNSET; | 285 | t->type = UNSET; |
310 | t->radio_if2 = 10700*1000; /* 10.7MHz - FM radio */ | 286 | t->radio_if2 = 10700*1000; /* 10.7MHz - FM radio */ |
287 | t->audmode = V4L2_TUNER_MODE_STEREO; | ||
311 | 288 | ||
312 | i2c_attach_client(&t->i2c); | 289 | i2c_attach_client(&t->i2c); |
313 | tuner_info("chip found @ 0x%x (%s)\n", | 290 | tuner_info("chip found @ 0x%x (%s)\n", |
@@ -325,11 +302,9 @@ static int tuner_probe(struct i2c_adapter *adap) | |||
325 | } | 302 | } |
326 | this_adap = 0; | 303 | this_adap = 0; |
327 | 304 | ||
328 | #ifdef CONFIG_TUNER_MULTI_I2C | ||
329 | first_tuner = 0; | 305 | first_tuner = 0; |
330 | tv_tuner = 0; | 306 | tv_tuner = 0; |
331 | radio_tuner = 0; | 307 | radio_tuner = 0; |
332 | #endif | ||
333 | 308 | ||
334 | if (adap->class & I2C_CLASS_TV_ANALOG) | 309 | if (adap->class & I2C_CLASS_TV_ANALOG) |
335 | return i2c_probe(adap, &addr_data, tuner_attach); | 310 | return i2c_probe(adap, &addr_data, tuner_attach); |
@@ -392,8 +367,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
392 | t->radio_if2 = 41300 * 1000; | 367 | t->radio_if2 = 41300 * 1000; |
393 | break; | 368 | break; |
394 | } | 369 | } |
395 | break; | 370 | break; |
396 | |||
397 | /* --- v4l ioctls --- */ | 371 | /* --- v4l ioctls --- */ |
398 | /* take care: bttv does userspace copying, we'll get a | 372 | /* take care: bttv does userspace copying, we'll get a |
399 | kernel pointer here... */ | 373 | kernel pointer here... */ |
@@ -440,11 +414,18 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
440 | vt->signal = t->has_signal(client); | 414 | vt->signal = t->has_signal(client); |
441 | if (t->is_stereo) { | 415 | if (t->is_stereo) { |
442 | if (t->is_stereo(client)) | 416 | if (t->is_stereo(client)) |
443 | vt-> flags |= VIDEO_TUNER_STEREO_ON; | 417 | vt->flags |= VIDEO_TUNER_STEREO_ON; |
444 | else | 418 | else |
445 | vt-> flags &= 0xffff ^ VIDEO_TUNER_STEREO_ON; | 419 | vt->flags &= ~VIDEO_TUNER_STEREO_ON; |
446 | } | 420 | } |
447 | vt->flags |= V4L2_TUNER_CAP_LOW; /* Allow freqs at 62.5 Hz */ | 421 | vt->flags |= V4L2_TUNER_CAP_LOW; /* Allow freqs at 62.5 Hz */ |
422 | |||
423 | vt->rangelow = radio_range[0] * 16000; | ||
424 | vt->rangehigh = radio_range[1] * 16000; | ||
425 | |||
426 | } else { | ||
427 | vt->rangelow = tv_range[0] * 16; | ||
428 | vt->rangehigh = tv_range[1] * 16; | ||
448 | } | 429 | } |
449 | 430 | ||
450 | return 0; | 431 | return 0; |
@@ -510,20 +491,46 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
510 | tuner -> signal = t->has_signal(client); | 491 | tuner -> signal = t->has_signal(client); |
511 | if (t->is_stereo) { | 492 | if (t->is_stereo) { |
512 | if (t->is_stereo(client)) { | 493 | if (t->is_stereo(client)) { |
513 | tuner -> capability |= V4L2_TUNER_CAP_STEREO; | 494 | tuner -> rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; |
514 | tuner -> rxsubchans |= V4L2_TUNER_SUB_STEREO; | ||
515 | } else { | 495 | } else { |
516 | tuner -> rxsubchans &= 0xffff ^ V4L2_TUNER_SUB_STEREO; | 496 | tuner -> rxsubchans = V4L2_TUNER_SUB_MONO; |
517 | } | 497 | } |
518 | } | 498 | } |
499 | tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; | ||
500 | tuner->audmode = t->audmode; | ||
501 | |||
502 | tuner->rangelow = radio_range[0] * 16000; | ||
503 | tuner->rangehigh = radio_range[1] * 16000; | ||
504 | } else { | ||
505 | tuner->rangelow = tv_range[0] * 16; | ||
506 | tuner->rangehigh = tv_range[1] * 16; | ||
519 | } | 507 | } |
520 | /* Wow to deal with V4L2_TUNER_CAP_LOW ? For now, it accepts from low at 62.5KHz step to high at 62.5 Hz */ | ||
521 | tuner->rangelow = tv_range[0] * 16; | ||
522 | // tuner->rangehigh = tv_range[1] * 16; | ||
523 | // tuner->rangelow = tv_range[0] * 16384; | ||
524 | tuner->rangehigh = tv_range[1] * 16384; | ||
525 | break; | 508 | break; |
526 | } | 509 | } |
510 | case VIDIOC_S_TUNER: /* Allow changing radio range and audio mode */ | ||
511 | { | ||
512 | struct v4l2_tuner *tuner = arg; | ||
513 | |||
514 | CHECK_ADDR(radio_tuner,"VIDIOC_S_TUNER","radio"); | ||
515 | SWITCH_V4L2; | ||
516 | |||
517 | /* To switch the audio mode, applications initialize the | ||
518 | index and audmode fields and the reserved array and | ||
519 | call the VIDIOC_S_TUNER ioctl. */ | ||
520 | /* rxsubchannels: V4L2_TUNER_MODE_MONO, V4L2_TUNER_MODE_STEREO, | ||
521 | V4L2_TUNER_MODE_LANG1, V4L2_TUNER_MODE_LANG2, | ||
522 | V4L2_TUNER_MODE_SAP */ | ||
523 | |||
524 | if (tuner->audmode == V4L2_TUNER_MODE_MONO) | ||
525 | t->audmode = V4L2_TUNER_MODE_MONO; | ||
526 | else | ||
527 | t->audmode = V4L2_TUNER_MODE_STEREO; | ||
528 | |||
529 | set_radio_freq(client, t->freq); | ||
530 | break; | ||
531 | } | ||
532 | case TDA9887_SET_CONFIG: /* Nothing to do on tuner-core */ | ||
533 | break; | ||
527 | default: | 534 | default: |
528 | tuner_dbg ("Unimplemented IOCTL 0x%08x called to tuner.\n", cmd); | 535 | tuner_dbg ("Unimplemented IOCTL 0x%08x called to tuner.\n", cmd); |
529 | /* nothing */ | 536 | /* nothing */ |