]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/media/video/tuner-core.c
V4L/DVB (3268): Use combined firmware for DVB-T and ATSC Bluebird FusionHDTV USB...
[mirror_ubuntu-artful-kernel.git] / drivers / media / video / tuner-core.c
CommitLineData
1da177e4 1/*
1da177e4
LT
2 *
3 * i2c tv tuner chip device driver
4 * core core, i.e. kernel interfaces, registering and so on
5 */
6
7#include <linux/module.h>
8#include <linux/moduleparam.h>
9#include <linux/kernel.h>
10#include <linux/sched.h>
11#include <linux/string.h>
12#include <linux/timer.h>
13#include <linux/delay.h>
14#include <linux/errno.h>
15#include <linux/slab.h>
16#include <linux/poll.h>
17#include <linux/i2c.h>
18#include <linux/types.h>
19#include <linux/videodev.h>
20#include <linux/init.h>
21
22#include <media/tuner.h>
23#include <media/audiochip.h>
24
fd3113e8
MCC
25#include "msp3400.h"
26
1da177e4
LT
27#define UNSET (-1U)
28
29/* standard i2c insmod options */
30static unsigned short normal_i2c[] = {
de48eebc 31 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
f5bec396
MCC
32 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
33 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
1da177e4
LT
34 I2C_CLIENT_END
35};
f7ce3cc6 36
1da177e4
LT
37I2C_CLIENT_INSMOD;
38
39/* insmod options used at init time => read/only */
f7ce3cc6 40static unsigned int addr = 0;
c5287ba1 41static unsigned int no_autodetect = 0;
fd3113e8 42static unsigned int show_i2c = 0;
fd3113e8 43
1da177e4 44/* insmod options used at runtime => read/write */
f7ce3cc6 45unsigned int tuner_debug = 0;
1da177e4 46
f7ce3cc6 47static unsigned int tv_range[2] = { 44, 958 };
1da177e4
LT
48static unsigned int radio_range[2] = { 65, 108 };
49
7e578191
MCC
50static char pal[] = "--";
51static char secam[] = "--";
52static char ntsc[] = "-";
53
54module_param(addr, int, 0444);
55module_param(no_autodetect, int, 0444);
56module_param(show_i2c, int, 0444);
57module_param(tuner_debug, int, 0644);
58
59module_param_string(pal, pal, sizeof(pal), 0644);
60module_param_string(secam, secam, sizeof(secam), 0644);
61module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
f7ce3cc6 62module_param_array(tv_range, int, NULL, 0644);
1da177e4
LT
63module_param_array(radio_range, int, NULL, 0644);
64
65MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
66MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
67MODULE_LICENSE("GPL");
68
1da177e4
LT
69static struct i2c_driver driver;
70static struct i2c_client client_template;
71
72/* ---------------------------------------------------------------------- */
73
56fc08ca 74/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
1da177e4
LT
75static void set_tv_freq(struct i2c_client *c, unsigned int freq)
76{
77 struct tuner *t = i2c_get_clientdata(c);
78
79 if (t->type == UNSET) {
f7ce3cc6 80 tuner_warn ("tuner type not set\n");
1da177e4
LT
81 return;
82 }
83 if (NULL == t->tv_freq) {
f7ce3cc6 84 tuner_warn ("Tuner has no way to set tv freq\n");
1da177e4
LT
85 return;
86 }
f7ce3cc6
MCC
87 if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
88 tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
89 freq / 16, freq % 16 * 100 / 16, tv_range[0],
90 tv_range[1]);
1da177e4 91 }
f7ce3cc6 92 t->tv_freq(c, freq);
1da177e4
LT
93}
94
95static void set_radio_freq(struct i2c_client *c, unsigned int freq)
96{
97 struct tuner *t = i2c_get_clientdata(c);
98
99 if (t->type == UNSET) {
f7ce3cc6 100 tuner_warn ("tuner type not set\n");
1da177e4
LT
101 return;
102 }
103 if (NULL == t->radio_freq) {
f7ce3cc6 104 tuner_warn ("tuner has no way to set radio frequency\n");
1da177e4
LT
105 return;
106 }
f7ce3cc6
MCC
107 if (freq <= radio_range[0] * 16000 || freq >= radio_range[1] * 16000) {
108 tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
109 freq / 16000, freq % 16000 * 100 / 16000,
110 radio_range[0], radio_range[1]);
1da177e4 111 }
586b0cab 112
f7ce3cc6 113 t->radio_freq(c, freq);
586b0cab 114 return;
1da177e4
LT
115}
116
117static void set_freq(struct i2c_client *c, unsigned long freq)
118{
119 struct tuner *t = i2c_get_clientdata(c);
120
121 switch (t->mode) {
122 case V4L2_TUNER_RADIO:
123 tuner_dbg("radio freq set to %lu.%02lu\n",
f7ce3cc6
MCC
124 freq / 16000, freq % 16000 * 100 / 16000);
125 set_radio_freq(c, freq);
1da177e4
LT
126 break;
127 case V4L2_TUNER_ANALOG_TV:
128 case V4L2_TUNER_DIGITAL_TV:
129 tuner_dbg("tv freq set to %lu.%02lu\n",
f7ce3cc6 130 freq / 16, freq % 16 * 100 / 16);
1da177e4
LT
131 set_tv_freq(c, freq);
132 break;
133 }
134 t->freq = freq;
135}
136
f7ce3cc6
MCC
137static void set_type(struct i2c_client *c, unsigned int type,
138 unsigned int new_mode_mask)
1da177e4
LT
139{
140 struct tuner *t = i2c_get_clientdata(c);
586b0cab 141 unsigned char buffer[4];
1da177e4 142
f7ce3cc6
MCC
143 if (type == UNSET || type == TUNER_ABSENT) {
144 tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);
1da177e4 145 return;
f7ce3cc6
MCC
146 }
147
148 if (type >= tuner_count) {
149 tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count);
1da177e4 150 return;
f7ce3cc6 151 }
1da177e4 152
f7ce3cc6 153 /* This code detects calls by card attach_inform */
1da177e4 154 if (NULL == t->i2c.dev.driver) {
f7ce3cc6
MCC
155 tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
156
157 t->type=type;
1da177e4
LT
158 return;
159 }
56fc08ca 160
1da177e4 161 t->type = type;
f7ce3cc6 162
1da177e4
LT
163 switch (t->type) {
164 case TUNER_MT2032:
165 microtune_init(c);
166 break;
167 case TUNER_PHILIPS_TDA8290:
168 tda8290_init(c);
169 break;
586b0cab 170 case TUNER_TEA5767:
f7ce3cc6
MCC
171 if (tea5767_tuner_init(c) == EINVAL) {
172 t->type = TUNER_ABSENT;
173 t->mode_mask = T_UNINITIALIZED;
174 return;
175 }
176 t->mode_mask = T_RADIO;
586b0cab
MCC
177 break;
178 case TUNER_PHILIPS_FMD1216ME_MK3:
179 buffer[0] = 0x0b;
180 buffer[1] = 0xdc;
181 buffer[2] = 0x9c;
182 buffer[3] = 0x60;
f7ce3cc6 183 i2c_master_send(c, buffer, 4);
586b0cab
MCC
184 mdelay(1);
185 buffer[2] = 0x86;
186 buffer[3] = 0x54;
f7ce3cc6 187 i2c_master_send(c, buffer, 4);
586b0cab
MCC
188 default_tuner_init(c);
189 break;
793cf9e6
MCC
190 case TUNER_LG_TDVS_H062F:
191 /* Set the Auxiliary Byte. */
192 buffer[2] &= ~0x20;
193 buffer[2] |= 0x18;
194 buffer[3] = 0x20;
195 i2c_master_send(c, buffer, 4);
196 default_tuner_init(c);
197 break;
93df3413
HH
198 case TUNER_PHILIPS_TD1316:
199 buffer[0] = 0x0b;
200 buffer[1] = 0xdc;
201 buffer[2] = 0x86;
202 buffer[3] = 0xa4;
203 i2c_master_send(c,buffer,4);
204 default_tuner_init(c);
1da177e4
LT
205 default:
206 default_tuner_init(c);
207 break;
208 }
f7ce3cc6
MCC
209
210 if (t->mode_mask == T_UNINITIALIZED)
211 t->mode_mask = new_mode_mask;
212
213 set_freq(c, t->freq);
214 tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
604f28e2 215 c->adapter->name, c->driver->driver.name, c->addr << 1, type,
f7ce3cc6 216 t->mode_mask);
1da177e4
LT
217}
218
f7ce3cc6
MCC
219/*
220 * This function apply tuner config to tuner specified
221 * by tun_setup structure. I addr is unset, then admin status
222 * and tun addr status is more precise then current status,
223 * it's applied. Otherwise status and type are applied only to
224 * tuner with exactly the same addr.
225*/
226
227static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
228{
229 struct tuner *t = i2c_get_clientdata(c);
230
291d1d73 231 if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET &&
793cf9e6 232 (t->mode_mask & tun_setup->mode_mask)) ||
291d1d73 233 tun_setup->addr == c->addr)) {
f7ce3cc6 234 set_type(c, tun_setup->type, tun_setup->mode_mask);
f7ce3cc6
MCC
235 }
236}
56fc08ca 237
f7ce3cc6 238static inline int check_mode(struct tuner *t, char *cmd)
56fc08ca 239{
793cf9e6
MCC
240 if ((1 << t->mode & t->mode_mask) == 0) {
241 return EINVAL;
242 }
243
244 switch (t->mode) {
245 case V4L2_TUNER_RADIO:
246 tuner_dbg("Cmd %s accepted for radio\n", cmd);
247 break;
248 case V4L2_TUNER_ANALOG_TV:
249 tuner_dbg("Cmd %s accepted for analog TV\n", cmd);
250 break;
251 case V4L2_TUNER_DIGITAL_TV:
252 tuner_dbg("Cmd %s accepted for digital TV\n", cmd);
253 break;
56fc08ca 254 }
793cf9e6 255 return 0;
56fc08ca 256}
56fc08ca 257
f7ce3cc6 258/* get more precise norm info from insmod option */
1da177e4
LT
259static int tuner_fixup_std(struct tuner *t)
260{
261 if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
1da177e4
LT
262 switch (pal[0]) {
263 case 'b':
264 case 'B':
265 case 'g':
266 case 'G':
f7ce3cc6 267 tuner_dbg ("insmod fixup: PAL => PAL-BG\n");
1da177e4
LT
268 t->std = V4L2_STD_PAL_BG;
269 break;
270 case 'i':
271 case 'I':
f7ce3cc6 272 tuner_dbg ("insmod fixup: PAL => PAL-I\n");
1da177e4
LT
273 t->std = V4L2_STD_PAL_I;
274 break;
275 case 'd':
276 case 'D':
277 case 'k':
278 case 'K':
f7ce3cc6 279 tuner_dbg ("insmod fixup: PAL => PAL-DK\n");
1da177e4
LT
280 t->std = V4L2_STD_PAL_DK;
281 break;
f7ce3cc6
MCC
282 case 'M':
283 case 'm':
284 tuner_dbg ("insmod fixup: PAL => PAL-M\n");
285 t->std = V4L2_STD_PAL_M;
286 break;
287 case 'N':
288 case 'n':
7e578191
MCC
289 if (pal[1] == 'c' || pal[1] == 'C') {
290 tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
291 t->std = V4L2_STD_PAL_Nc;
292 } else {
293 tuner_dbg ("insmod fixup: PAL => PAL-N\n");
294 t->std = V4L2_STD_PAL_N;
295 }
f7ce3cc6 296 break;
21d4df37
MCC
297 case '-':
298 /* default parameter, do nothing */
299 break;
300 default:
301 tuner_warn ("pal= argument not recognised\n");
302 break;
1da177e4
LT
303 }
304 }
f7ce3cc6
MCC
305 if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
306 switch (secam[0]) {
7e578191
MCC
307 case 'b':
308 case 'B':
309 case 'g':
310 case 'G':
311 case 'h':
312 case 'H':
313 tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
314 t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
315 break;
f7ce3cc6
MCC
316 case 'd':
317 case 'D':
318 case 'k':
319 case 'K':
320 tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n");
321 t->std = V4L2_STD_SECAM_DK;
322 break;
323 case 'l':
324 case 'L':
800d3c6f
MCC
325 if ((secam[1]=='C')||(secam[1]=='c')) {
326 tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n");
327 t->std = V4L2_STD_SECAM_LC;
328 } else {
329 tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
330 t->std = V4L2_STD_SECAM_L;
331 }
f7ce3cc6 332 break;
21d4df37
MCC
333 case '-':
334 /* default parameter, do nothing */
335 break;
336 default:
337 tuner_warn ("secam= argument not recognised\n");
338 break;
f7ce3cc6
MCC
339 }
340 }
341
7e578191
MCC
342 if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
343 switch (ntsc[0]) {
344 case 'm':
345 case 'M':
346 tuner_dbg("insmod fixup: NTSC => NTSC-M\n");
347 t->std = V4L2_STD_NTSC_M;
348 break;
349 case 'j':
350 case 'J':
351 tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
352 t->std = V4L2_STD_NTSC_M_JP;
353 break;
354 case '-':
355 /* default parameter, do nothing */
356 break;
357 default:
358 tuner_info("ntsc= argument not recognised\n");
359 break;
360 }
361 }
1da177e4
LT
362 return 0;
363}
364
7e578191
MCC
365static void tuner_status(struct i2c_client *client)
366{
367 struct tuner *t = i2c_get_clientdata(client);
368 unsigned long freq, freq_fraction;
369 const char *p;
370
371 switch (t->mode) {
372 case V4L2_TUNER_RADIO: p = "radio"; break;
373 case V4L2_TUNER_ANALOG_TV: p = "analog TV"; break;
374 case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break;
375 default: p = "undefined"; break;
376 }
377 if (t->mode == V4L2_TUNER_RADIO) {
378 freq = t->freq / 16000;
379 freq_fraction = (t->freq % 16000) * 100 / 16000;
380 } else {
381 freq = t->freq / 16;
382 freq_fraction = (t->freq % 16) * 100 / 16;
383 }
384 tuner_info("Tuner mode: %s\n", p);
385 tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
386 tuner_info("Standard: 0x%08llx\n", t->std);
387 if (t->mode == V4L2_TUNER_RADIO) {
388 if (t->has_signal) {
389 tuner_info("Signal strength: %d\n", t->has_signal(client));
390 }
391 if (t->is_stereo) {
392 tuner_info("Stereo: %s\n", t->is_stereo(client) ? "yes" : "no");
393 }
394 }
395}
1da177e4
LT
396/* ---------------------------------------------------------------------- */
397
f7ce3cc6
MCC
398/* static var Used only in tuner_attach and tuner_probe */
399static unsigned default_mode_mask;
400
401/* During client attach, set_type is called by adapter's attach_inform callback.
402 set_type must then be completed by tuner_attach.
403 */
1da177e4
LT
404static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
405{
406 struct tuner *t;
407
f7ce3cc6
MCC
408 client_template.adapter = adap;
409 client_template.addr = addr;
1da177e4 410
f7ce3cc6
MCC
411 t = kmalloc(sizeof(struct tuner), GFP_KERNEL);
412 if (NULL == t)
413 return -ENOMEM;
414 memset(t, 0, sizeof(struct tuner));
415 memcpy(&t->i2c, &client_template, sizeof(struct i2c_client));
1da177e4 416 i2c_set_clientdata(&t->i2c, t);
f7ce3cc6
MCC
417 t->type = UNSET;
418 t->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
419 t->audmode = V4L2_TUNER_MODE_STEREO;
420 t->mode_mask = T_UNINITIALIZED;
421
fd3113e8
MCC
422 if (show_i2c) {
423 unsigned char buffer[16];
424 int i,rc;
425
426 memset(buffer, 0, sizeof(buffer));
427 rc = i2c_master_recv(&t->i2c, buffer, sizeof(buffer));
67678360 428 tuner_info("I2C RECV = ");
fd3113e8
MCC
429 for (i=0;i<rc;i++)
430 printk("%02x ",buffer[i]);
431 printk("\n");
432 }
f7ce3cc6 433 /* TEA5767 autodetection code - only for addr = 0xc0 */
c5287ba1 434 if (!no_autodetect) {
13dd38d0 435 switch (addr) {
13dd38d0
MCC
436 case 0x42:
437 case 0x43:
438 case 0x4a:
95736034 439 case 0x4b:
67678360
MCC
440 /* If chip is not tda8290, don't register.
441 since it can be tda9887*/
95736034 442 if (tda8290_probe(&t->i2c) != 0) {
b228ede4 443 tuner_dbg("chip at addr %x is not a tda8290\n", addr);
13dd38d0
MCC
444 kfree(t);
445 return 0;
446 }
07345f5d
HH
447 break;
448 case 0x60:
449 if (tea5767_autodetection(&t->i2c) != EINVAL) {
450 t->type = TUNER_TEA5767;
451 t->mode_mask = T_RADIO;
452 t->mode = T_STANDBY;
453 t->freq = 87.5 * 16; /* Sets freq to FM range */
454 default_mode_mask &= ~T_RADIO;
13dd38d0 455
07345f5d
HH
456 goto register_client;
457 }
458 break;
f7ce3cc6
MCC
459 }
460 }
1da177e4 461
f7ce3cc6
MCC
462 /* Initializes only the first adapter found */
463 if (default_mode_mask != T_UNINITIALIZED) {
464 tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask);
465 t->mode_mask = default_mode_mask;
466 t->freq = 400 * 16; /* Sets freq to VHF High */
467 default_mode_mask = T_UNINITIALIZED;
468 }
56fc08ca 469
f7ce3cc6 470 /* Should be just before return */
67678360
MCC
471register_client:
472 tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
f7ce3cc6
MCC
473 i2c_attach_client (&t->i2c);
474 set_type (&t->i2c,t->type, t->mode_mask);
1da177e4
LT
475 return 0;
476}
477
478static int tuner_probe(struct i2c_adapter *adap)
479{
480 if (0 != addr) {
f5bec396
MCC
481 normal_i2c[0] = addr;
482 normal_i2c[1] = I2C_CLIENT_END;
1da177e4 483 }
1da177e4 484
f7ce3cc6 485 default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
391cd727 486
1da177e4
LT
487 if (adap->class & I2C_CLASS_TV_ANALOG)
488 return i2c_probe(adap, &addr_data, tuner_attach);
489 return 0;
490}
491
492static int tuner_detach(struct i2c_client *client)
493{
494 struct tuner *t = i2c_get_clientdata(client);
391cd727
MCC
495 int err;
496
f7ce3cc6 497 err = i2c_detach_client(&t->i2c);
391cd727 498 if (err) {
f7ce3cc6
MCC
499 tuner_warn
500 ("Client deregistration failed, client not detached.\n");
391cd727
MCC
501 return err;
502 }
1da177e4 503
1da177e4
LT
504 kfree(t);
505 return 0;
506}
507
f7ce3cc6
MCC
508/*
509 * Switch tuner to other mode. If tuner support both tv and radio,
510 * set another frequency to some value (This is needed for some pal
511 * tuners to avoid locking). Otherwise, just put second tuner in
512 * standby mode.
513 */
514
515static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
516{
4ac97914
MCC
517 if (mode == t->mode)
518 return 0;
519
520 t->mode = mode;
521
522 if (check_mode(t, cmd) == EINVAL) {
523 t->mode = T_STANDBY;
524 if (t->standby)
525 t->standby (client);
526 return EINVAL;
527 }
528 return 0;
f7ce3cc6
MCC
529}
530
531#define switch_v4l2() if (!t->using_v4l2) \
4ac97914
MCC
532 tuner_dbg("switching to v4l2\n"); \
533 t->using_v4l2 = 1;
f7ce3cc6
MCC
534
535static inline int check_v4l2(struct tuner *t)
536{
537 if (t->using_v4l2) {
538 tuner_dbg ("ignore v4l1 call\n");
539 return EINVAL;
540 }
541 return 0;
542}
1da177e4 543
f7ce3cc6 544static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
1da177e4
LT
545{
546 struct tuner *t = i2c_get_clientdata(client);
1da177e4 547
f7ce3cc6 548 switch (cmd) {
1da177e4 549 /* --- configuration --- */
56fc08ca 550 case TUNER_SET_TYPE_ADDR:
f7ce3cc6
MCC
551 tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x\n",
552 ((struct tuner_setup *)arg)->type,
553 ((struct tuner_setup *)arg)->addr,
554 ((struct tuner_setup *)arg)->mode_mask);
555
556 set_addr(client, (struct tuner_setup *)arg);
391cd727 557 break;
1da177e4 558 case AUDC_SET_RADIO:
f7ce3cc6 559 set_mode(client,t,V4L2_TUNER_RADIO, "AUDC_SET_RADIO");
1da177e4 560 break;
793cf9e6
MCC
561 case TUNER_SET_STANDBY:
562 {
563 if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
564 return 0;
565 if (t->standby)
566 t->standby (client);
567 break;
568 }
fd3113e8
MCC
569 case VIDIOCSAUDIO:
570 if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
571 return 0;
572 if (check_v4l2(t) == EINVAL)
573 return 0;
574
575 /* Should be implemented, since bttv calls it */
576 tuner_dbg("VIDIOCSAUDIO not implemented.\n");
577
578 break;
579 case MSP_SET_MATRIX:
f7ce3cc6
MCC
580 case TDA9887_SET_CONFIG:
581 break;
1da177e4
LT
582 /* --- v4l ioctls --- */
583 /* take care: bttv does userspace copying, we'll get a
584 kernel pointer here... */
585 case VIDIOCSCHAN:
f7ce3cc6
MCC
586 {
587 static const v4l2_std_id map[] = {
588 [VIDEO_MODE_PAL] = V4L2_STD_PAL,
589 [VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M,
590 [VIDEO_MODE_SECAM] = V4L2_STD_SECAM,
591 [4 /* bttv */ ] = V4L2_STD_PAL_M,
592 [5 /* bttv */ ] = V4L2_STD_PAL_N,
593 [6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
594 };
595 struct video_channel *vc = arg;
596
597 if (check_v4l2(t) == EINVAL)
598 return 0;
599
600 if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==EINVAL)
601 return 0;
602
603 if (vc->norm < ARRAY_SIZE(map))
604 t->std = map[vc->norm];
605 tuner_fixup_std(t);
606 if (t->freq)
607 set_tv_freq(client, t->freq);
608 return 0;
609 }
1da177e4 610 case VIDIOCSFREQ:
f7ce3cc6
MCC
611 {
612 unsigned long *v = arg;
1da177e4 613
f7ce3cc6
MCC
614 if (check_mode(t, "VIDIOCSFREQ") == EINVAL)
615 return 0;
616 if (check_v4l2(t) == EINVAL)
617 return 0;
618
619 set_freq(client, *v);
620 return 0;
621 }
1da177e4 622 case VIDIOCGTUNER:
f7ce3cc6
MCC
623 {
624 struct video_tuner *vt = arg;
625
626 if (check_mode(t, "VIDIOCGTUNER") == EINVAL)
627 return 0;
628 if (check_v4l2(t) == EINVAL)
629 return 0;
630
631 if (V4L2_TUNER_RADIO == t->mode) {
632 if (t->has_signal)
633 vt->signal = t->has_signal(client);
634 if (t->is_stereo) {
635 if (t->is_stereo(client))
636 vt->flags |=
637 VIDEO_TUNER_STEREO_ON;
638 else
639 vt->flags &=
640 ~VIDEO_TUNER_STEREO_ON;
641 }
642 vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */
586b0cab 643
f7ce3cc6
MCC
644 vt->rangelow = radio_range[0] * 16000;
645 vt->rangehigh = radio_range[1] * 16000;
586b0cab 646
f7ce3cc6
MCC
647 } else {
648 vt->rangelow = tv_range[0] * 16;
649 vt->rangehigh = tv_range[1] * 16;
650 }
56fc08ca 651
f7ce3cc6
MCC
652 return 0;
653 }
1da177e4 654 case VIDIOCGAUDIO:
f7ce3cc6
MCC
655 {
656 struct video_audio *va = arg;
657
658 if (check_mode(t, "VIDIOCGAUDIO") == EINVAL)
659 return 0;
660 if (check_v4l2(t) == EINVAL)
661 return 0;
662
663 if (V4L2_TUNER_RADIO == t->mode && t->is_stereo)
664 va->mode = t->is_stereo(client)
665 ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
666 return 0;
667 }
1da177e4
LT
668
669 case VIDIOC_S_STD:
f7ce3cc6
MCC
670 {
671 v4l2_std_id *id = arg;
1da177e4 672
f7ce3cc6
MCC
673 if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
674 == EINVAL)
675 return 0;
56fc08ca 676
f7ce3cc6
MCC
677 switch_v4l2();
678
679 t->std = *id;
680 tuner_fixup_std(t);
681 if (t->freq)
682 set_freq(client, t->freq);
683 break;
684 }
1da177e4 685 case VIDIOC_S_FREQUENCY:
f7ce3cc6
MCC
686 {
687 struct v4l2_frequency *f = arg;
688
689 t->freq = f->frequency;
690 switch_v4l2();
691 if (V4L2_TUNER_RADIO == f->type &&
692 V4L2_TUNER_RADIO != t->mode) {
4ac97914 693 if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
f7ce3cc6
MCC
694 == EINVAL)
695 return 0;
696 }
697 set_freq(client,t->freq);
c184ca36 698
f7ce3cc6
MCC
699 break;
700 }
701 case VIDIOC_G_FREQUENCY:
702 {
703 struct v4l2_frequency *f = arg;
704
705 if (check_mode(t, "VIDIOC_G_FREQUENCY") == EINVAL)
706 return 0;
707 switch_v4l2();
708 f->type = t->mode;
709 f->frequency = t->freq;
710 break;
711 }
1da177e4 712 case VIDIOC_G_TUNER:
f7ce3cc6
MCC
713 {
714 struct v4l2_tuner *tuner = arg;
715
716 if (check_mode(t, "VIDIOC_G_TUNER") == EINVAL)
717 return 0;
718 switch_v4l2();
719
720 if (V4L2_TUNER_RADIO == t->mode) {
721
722 if (t->has_signal)
723 tuner->signal = t->has_signal(client);
724
725 if (t->is_stereo) {
726 if (t->is_stereo(client)) {
727 tuner->rxsubchans =
728 V4L2_TUNER_SUB_STEREO |
729 V4L2_TUNER_SUB_MONO;
730 } else {
731 tuner->rxsubchans =
732 V4L2_TUNER_SUB_MONO;
733 }
56fc08ca 734 }
f7ce3cc6
MCC
735
736 tuner->capability |=
737 V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
738
739 tuner->audmode = t->audmode;
740
741 tuner->rangelow = radio_range[0] * 16000;
742 tuner->rangehigh = radio_range[1] * 16000;
743 } else {
744 tuner->rangelow = tv_range[0] * 16;
745 tuner->rangehigh = tv_range[1] * 16;
56fc08ca 746 }
f7ce3cc6
MCC
747 break;
748 }
749 case VIDIOC_S_TUNER:
750 {
751 struct v4l2_tuner *tuner = arg;
752
753 if (check_mode(t, "VIDIOC_S_TUNER") == EINVAL)
754 return 0;
755
756 switch_v4l2();
757
758 if (V4L2_TUNER_RADIO == t->mode) {
759 t->audmode = tuner->audmode;
760 set_radio_freq(client, t->freq);
761 }
762 break;
56fc08ca 763 }
cd43c3f6
HV
764 case VIDIOC_LOG_STATUS:
765 tuner_status(client);
766 break;
1da177e4 767 default:
fd1c3881 768 tuner_dbg("Unimplemented IOCTL 0x%08x(dir=%d,tp='%c',nr=%d,sz=%d)\n",
c5287ba1
MCC
769 cmd, _IOC_DIR(cmd), _IOC_TYPE(cmd),
770 _IOC_NR(cmd), _IOC_SIZE(cmd));
1da177e4
LT
771 break;
772 }
773
774 return 0;
775}
776
9480e307 777static int tuner_suspend(struct device *dev, pm_message_t state)
1da177e4 778{
f7ce3cc6
MCC
779 struct i2c_client *c = container_of (dev, struct i2c_client, dev);
780 struct tuner *t = i2c_get_clientdata (c);
1da177e4 781
f7ce3cc6 782 tuner_dbg ("suspend\n");
1da177e4
LT
783 /* FIXME: power down ??? */
784 return 0;
785}
786
9480e307 787static int tuner_resume(struct device *dev)
1da177e4 788{
f7ce3cc6
MCC
789 struct i2c_client *c = container_of (dev, struct i2c_client, dev);
790 struct tuner *t = i2c_get_clientdata (c);
1da177e4 791
f7ce3cc6 792 tuner_dbg ("resume\n");
1da177e4 793 if (t->freq)
f7ce3cc6 794 set_freq(c, t->freq);
1da177e4
LT
795 return 0;
796}
797
798/* ----------------------------------------------------------------------- */
799
800static struct i2c_driver driver = {
f7ce3cc6 801 .id = I2C_DRIVERID_TUNER,
f7ce3cc6
MCC
802 .attach_adapter = tuner_probe,
803 .detach_client = tuner_detach,
804 .command = tuner_command,
1da177e4 805 .driver = {
604f28e2 806 .name = "tuner",
f7ce3cc6
MCC
807 .suspend = tuner_suspend,
808 .resume = tuner_resume,
809 },
1da177e4 810};
f7ce3cc6 811static struct i2c_client client_template = {
fae91e72 812 .name = "(tuner unset)",
f7ce3cc6 813 .driver = &driver,
1da177e4
LT
814};
815
816static int __init tuner_init_module(void)
817{
818 return i2c_add_driver(&driver);
819}
820
821static void __exit tuner_cleanup_module(void)
822{
823 i2c_del_driver(&driver);
824}
825
826module_init(tuner_init_module);
827module_exit(tuner_cleanup_module);
828
829/*
830 * Overrides for Emacs so that we follow Linus's tabbing style.
831 * ---------------------------------------------------------------------------
832 * Local variables:
833 * c-basic-offset: 8
834 * End:
835 */