1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/module.h>
19#include <linux/init.h>
20#include <linux/i2c.h>
21#include <linux/videodev2.h>
22#include <media/tuner.h>
23#include <media/v4l2-common.h>
24#include <media/v4l2-ioctl.h>
25
26#include "wis-i2c.h"
27
28
29
30
31
32
33#define IF_I2C_ADDR 0x43
34#define MPX_I2C_ADDR 0x44
35
36static v4l2_std_id force_band;
37static char force_band_str[] = "-";
38module_param_string(force_band, force_band_str, sizeof(force_band_str), 0644);
39static int force_mpx_mode = -1;
40module_param(force_mpx_mode, int, 0644);
41
42
43
44struct sony_tunertype {
45 char *name;
46 unsigned char Vendor;
47 unsigned char Type;
48
49 unsigned short thresh1;
50 unsigned short thresh2;
51 unsigned char VHF_L;
52 unsigned char VHF_H;
53 unsigned char UHF;
54 unsigned char config;
55 unsigned short IFPCoff;
56};
57
58
59static struct sony_tunertype sony_tuners[] = {
60 { "Sony PAL+SECAM (BTF-PG472Z)", 0, 0,
61 16*144.25, 16*427.25, 0x01, 0x02, 0x04, 0xc6, 623},
62 { "Sony NTSC_JP (BTF-PK467Z)", 0, 0,
63 16*220.25, 16*467.25, 0x01, 0x02, 0x04, 0xc6, 940},
64 { "Sony NTSC (BTF-PB463Z)", 0, 0,
65 16*130.25, 16*364.25, 0x01, 0x02, 0x04, 0xc6, 732},
66};
67
68struct wis_sony_tuner {
69 int type;
70 v4l2_std_id std;
71 unsigned int freq;
72 int mpxmode;
73 u32 audmode;
74};
75
76
77static int set_freq(struct i2c_client *client, int freq)
78{
79 struct wis_sony_tuner *t = i2c_get_clientdata(client);
80 char *band_name;
81 int n;
82 int band_select;
83 struct sony_tunertype *tun;
84 u8 buffer[4];
85
86 tun = &sony_tuners[t->type - 200];
87 if (freq < tun->thresh1) {
88 band_name = "VHF_L";
89 band_select = tun->VHF_L;
90 } else if (freq < tun->thresh2) {
91 band_name = "VHF_H";
92 band_select = tun->VHF_H;
93 } else {
94 band_name = "UHF";
95 band_select = tun->UHF;
96 }
97 printk(KERN_DEBUG "wis-sony-tuner: tuning to frequency %d.%04d (%s)\n",
98 freq / 16, (freq % 16) * 625, band_name);
99 n = freq + tun->IFPCoff;
100
101 buffer[0] = n >> 8;
102 buffer[1] = n & 0xff;
103 buffer[2] = tun->config;
104 buffer[3] = band_select;
105 i2c_master_send(client, buffer, 4);
106
107 return 0;
108}
109
110static int mpx_write(struct i2c_client *client, int dev, int addr, int val)
111{
112 u8 buffer[5];
113 struct i2c_msg msg;
114
115 buffer[0] = dev;
116 buffer[1] = addr >> 8;
117 buffer[2] = addr & 0xff;
118 buffer[3] = val >> 8;
119 buffer[4] = val & 0xff;
120 msg.addr = MPX_I2C_ADDR;
121 msg.flags = 0;
122 msg.len = 5;
123 msg.buf = buffer;
124 i2c_transfer(client->adapter, &msg, 1);
125 return 0;
126}
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179static struct {
180 enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode;
181 u16 modus;
182 u16 source;
183 u16 acb;
184 u16 fm_prescale;
185 u16 nicam_prescale;
186 u16 scart_prescale;
187 u16 system;
188 u16 volume;
189} mpx_audio_modes[] = {
190 { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
191 0x5000, 0x0000, 0x0001, 0x7500 },
192 { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
193 0x5000, 0x0000, 0x0003, 0x7500 },
194 { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
195 0x5000, 0x0000, 0x0003, 0x7500 },
196 { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
197 0x5000, 0x0000, 0x0008, 0x7500 },
198 { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
199 0x7900, 0x0000, 0x000A, 0x7500 },
200 { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
201 0x7900, 0x0000, 0x000A, 0x7500 },
202 { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
203 0x5000, 0x0000, 0x0004, 0x7500 },
204 { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
205 0x5000, 0x0000, 0x0004, 0x7500 },
206 { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
207 0x5000, 0x0000, 0x0005, 0x7500 },
208 { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
209 0x5000, 0x0000, 0x0007, 0x7500 },
210 { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
211 0x5000, 0x0000, 0x000B, 0x7500 },
212 { AUD_MONO, 0x0003, 0x0200, 0x0100, 0x7C03,
213 0x5000, 0x2200, 0x0009, 0x7500 },
214 { AUD_NICAM_L, 0x0003, 0x0120, 0x0100, 0x7C03,
215 0x5000, 0x0000, 0x0009, 0x7500 },
216};
217
218#define MPX_NUM_MODES ARRAY_SIZE(mpx_audio_modes)
219
220static int mpx_setup(struct i2c_client *client)
221{
222 struct wis_sony_tuner *t = i2c_get_clientdata(client);
223 u16 source = 0;
224 u8 buffer[3];
225 struct i2c_msg msg;
226
227
228 buffer[0] = 0x00;
229 buffer[1] = 0x80;
230 buffer[2] = 0x00;
231 msg.addr = MPX_I2C_ADDR;
232 msg.flags = 0;
233 msg.len = 3;
234 msg.buf = buffer;
235 i2c_transfer(client->adapter, &msg, 1);
236 buffer[1] = 0x00;
237 i2c_transfer(client->adapter, &msg, 1);
238
239 if (mpx_audio_modes[t->mpxmode].audio_mode != AUD_MONO) {
240 switch (t->audmode) {
241 case V4L2_TUNER_MODE_MONO:
242 switch (mpx_audio_modes[t->mpxmode].audio_mode) {
243 case AUD_A2:
244 source = mpx_audio_modes[t->mpxmode].source;
245 break;
246 case AUD_NICAM:
247 source = 0x0000;
248 break;
249 case AUD_NICAM_L:
250 source = 0x0200;
251 break;
252 default:
253 break;
254 }
255 break;
256 case V4L2_TUNER_MODE_STEREO:
257 source = mpx_audio_modes[t->mpxmode].source;
258 break;
259 case V4L2_TUNER_MODE_LANG1:
260 source = 0x0300;
261 break;
262 case V4L2_TUNER_MODE_LANG2:
263 source = 0x0400;
264 break;
265 }
266 source |= mpx_audio_modes[t->mpxmode].source & 0x00ff;
267 } else
268 source = mpx_audio_modes[t->mpxmode].source;
269
270 mpx_write(client, 0x10, 0x0030, mpx_audio_modes[t->mpxmode].modus);
271 mpx_write(client, 0x12, 0x0008, source);
272 mpx_write(client, 0x12, 0x0013, mpx_audio_modes[t->mpxmode].acb);
273 mpx_write(client, 0x12, 0x000e,
274 mpx_audio_modes[t->mpxmode].fm_prescale);
275 mpx_write(client, 0x12, 0x0010,
276 mpx_audio_modes[t->mpxmode].nicam_prescale);
277 mpx_write(client, 0x12, 0x000d,
278 mpx_audio_modes[t->mpxmode].scart_prescale);
279 mpx_write(client, 0x10, 0x0020, mpx_audio_modes[t->mpxmode].system);
280 mpx_write(client, 0x12, 0x0000, mpx_audio_modes[t->mpxmode].volume);
281 if (mpx_audio_modes[t->mpxmode].audio_mode == AUD_A2)
282 mpx_write(client, 0x10, 0x0022,
283 t->audmode == V4L2_TUNER_MODE_MONO ? 0x07f0 : 0x0190);
284
285#ifdef MPX_DEBUG
286 {
287 u8 buf1[3], buf2[2];
288 struct i2c_msg msgs[2];
289
290 printk(KERN_DEBUG "wis-sony-tuner: MPX registers: %04x %04x "
291 "%04x %04x %04x %04x %04x %04x\n",
292 mpx_audio_modes[t->mpxmode].modus,
293 source,
294 mpx_audio_modes[t->mpxmode].acb,
295 mpx_audio_modes[t->mpxmode].fm_prescale,
296 mpx_audio_modes[t->mpxmode].nicam_prescale,
297 mpx_audio_modes[t->mpxmode].scart_prescale,
298 mpx_audio_modes[t->mpxmode].system,
299 mpx_audio_modes[t->mpxmode].volume);
300 buf1[0] = 0x11;
301 buf1[1] = 0x00;
302 buf1[2] = 0x7e;
303 msgs[0].addr = MPX_I2C_ADDR;
304 msgs[0].flags = 0;
305 msgs[0].len = 3;
306 msgs[0].buf = buf1;
307 msgs[1].addr = MPX_I2C_ADDR;
308 msgs[1].flags = I2C_M_RD;
309 msgs[1].len = 2;
310 msgs[1].buf = buf2;
311 i2c_transfer(client->adapter, msgs, 2);
312 printk(KERN_DEBUG "wis-sony-tuner: MPX system: %02x%02x\n",
313 buf2[0], buf2[1]);
314 buf1[0] = 0x11;
315 buf1[1] = 0x02;
316 buf1[2] = 0x00;
317 i2c_transfer(client->adapter, msgs, 2);
318 printk(KERN_DEBUG "wis-sony-tuner: MPX status: %02x%02x\n",
319 buf2[0], buf2[1]);
320 }
321#endif
322 return 0;
323}
324
325
326
327
328
329
330
331
332
333
334
335
336static int set_if(struct i2c_client *client)
337{
338 struct wis_sony_tuner *t = i2c_get_clientdata(client);
339 u8 buffer[4];
340 struct i2c_msg msg;
341 int default_mpx_mode = 0;
342
343
344 buffer[0] = 0;
345 if (t->std & V4L2_STD_PAL_BG) {
346 buffer[1] = 0x94;
347 buffer[2] = 0x70;
348 buffer[3] = 0x49;
349 default_mpx_mode = 1;
350 } else if (t->std & V4L2_STD_PAL_I) {
351 buffer[1] = 0x14;
352 buffer[2] = 0x70;
353 buffer[3] = 0x4a;
354 default_mpx_mode = 4;
355 } else if (t->std & V4L2_STD_PAL_DK) {
356 buffer[1] = 0x14;
357 buffer[2] = 0x70;
358 buffer[3] = 0x4b;
359 default_mpx_mode = 6;
360 } else if (t->std & V4L2_STD_SECAM_L) {
361 buffer[1] = 0x04;
362 buffer[2] = 0x70;
363 buffer[3] = 0x4b;
364 default_mpx_mode = 11;
365 }
366 msg.addr = IF_I2C_ADDR;
367 msg.flags = 0;
368 msg.len = 4;
369 msg.buf = buffer;
370 i2c_transfer(client->adapter, &msg, 1);
371
372
373 if (force_mpx_mode >= 0 || force_mpx_mode < MPX_NUM_MODES)
374 t->mpxmode = force_mpx_mode;
375 else
376 t->mpxmode = default_mpx_mode;
377 printk(KERN_DEBUG "wis-sony-tuner: setting MPX to mode %d\n",
378 t->mpxmode);
379 mpx_setup(client);
380
381 return 0;
382}
383
384static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
385{
386 struct wis_sony_tuner *t = i2c_get_clientdata(client);
387
388 switch (cmd) {
389#ifdef TUNER_SET_TYPE_ADDR
390 case TUNER_SET_TYPE_ADDR:
391 {
392 struct tuner_setup *tun_setup = arg;
393 int *type = &tun_setup->type;
394#else
395 case TUNER_SET_TYPE:
396 {
397 int *type = arg;
398#endif
399
400 if (t->type >= 0) {
401 if (t->type != *type)
402 printk(KERN_ERR "wis-sony-tuner: type already "
403 "set to %d, ignoring request for %d\n",
404 t->type, *type);
405 break;
406 }
407 t->type = *type;
408 switch (t->type) {
409 case TUNER_SONY_BTF_PG472Z:
410 switch (force_band_str[0]) {
411 case 'b':
412 case 'B':
413 case 'g':
414 case 'G':
415 printk(KERN_INFO "wis-sony-tuner: forcing "
416 "tuner to PAL-B/G bands\n");
417 force_band = V4L2_STD_PAL_BG;
418 break;
419 case 'i':
420 case 'I':
421 printk(KERN_INFO "wis-sony-tuner: forcing "
422 "tuner to PAL-I band\n");
423 force_band = V4L2_STD_PAL_I;
424 break;
425 case 'd':
426 case 'D':
427 case 'k':
428 case 'K':
429 printk(KERN_INFO "wis-sony-tuner: forcing "
430 "tuner to PAL-D/K bands\n");
431 force_band = V4L2_STD_PAL_I;
432 break;
433 case 'l':
434 case 'L':
435 printk(KERN_INFO "wis-sony-tuner: forcing "
436 "tuner to SECAM-L band\n");
437 force_band = V4L2_STD_SECAM_L;
438 break;
439 default:
440 force_band = 0;
441 break;
442 }
443 if (force_band)
444 t->std = force_band;
445 else
446 t->std = V4L2_STD_PAL_BG;
447 set_if(client);
448 break;
449 case TUNER_SONY_BTF_PK467Z:
450 t->std = V4L2_STD_NTSC_M_JP;
451 break;
452 case TUNER_SONY_BTF_PB463Z:
453 t->std = V4L2_STD_NTSC_M;
454 break;
455 default:
456 printk(KERN_ERR "wis-sony-tuner: tuner type %d is not "
457 "supported by this module\n", *type);
458 break;
459 }
460 if (type >= 0)
461 printk(KERN_INFO
462 "wis-sony-tuner: type set to %d (%s)\n",
463 t->type, sony_tuners[t->type - 200].name);
464 break;
465 }
466 case VIDIOC_G_FREQUENCY:
467 {
468 struct v4l2_frequency *f = arg;
469
470 f->frequency = t->freq;
471 break;
472 }
473 case VIDIOC_S_FREQUENCY:
474 {
475 struct v4l2_frequency *f = arg;
476
477 t->freq = f->frequency;
478 set_freq(client, t->freq);
479 break;
480 }
481 case VIDIOC_ENUMSTD:
482 {
483 struct v4l2_standard *std = arg;
484
485 switch (t->type) {
486 case TUNER_SONY_BTF_PG472Z:
487 switch (std->index) {
488 case 0:
489 v4l2_video_std_construct(std,
490 V4L2_STD_PAL_BG, "PAL-B/G");
491 break;
492 case 1:
493 v4l2_video_std_construct(std,
494 V4L2_STD_PAL_I, "PAL-I");
495 break;
496 case 2:
497 v4l2_video_std_construct(std,
498 V4L2_STD_PAL_DK, "PAL-D/K");
499 break;
500 case 3:
501 v4l2_video_std_construct(std,
502 V4L2_STD_SECAM_L, "SECAM-L");
503 break;
504 default:
505 std->id = 0;
506 break;
507 }
508 break;
509 case TUNER_SONY_BTF_PK467Z:
510 if (std->index != 0) {
511 std->id = 0;
512 break;
513 }
514 v4l2_video_std_construct(std,
515 V4L2_STD_NTSC_M_JP, "NTSC-J");
516 break;
517 case TUNER_SONY_BTF_PB463Z:
518 if (std->index != 0) {
519 std->id = 0;
520 break;
521 }
522 v4l2_video_std_construct(std, V4L2_STD_NTSC_M, "NTSC");
523 break;
524 }
525 break;
526 }
527 case VIDIOC_G_STD:
528 {
529 v4l2_std_id *std = arg;
530
531 *std = t->std;
532 break;
533 }
534 case VIDIOC_S_STD:
535 {
536 v4l2_std_id *std = arg;
537 v4l2_std_id old = t->std;
538
539 switch (t->type) {
540 case TUNER_SONY_BTF_PG472Z:
541 if (force_band && (*std & force_band) != *std &&
542 *std != V4L2_STD_PAL &&
543 *std != V4L2_STD_SECAM) {
544 printk(KERN_DEBUG "wis-sony-tuner: ignoring "
545 "requested TV standard in "
546 "favor of force_band value\n");
547 t->std = force_band;
548 } else if (*std & V4L2_STD_PAL_BG) {
549 t->std = V4L2_STD_PAL_BG;
550 } else if (*std & V4L2_STD_PAL_I) {
551 t->std = V4L2_STD_PAL_I;
552 } else if (*std & V4L2_STD_PAL_DK) {
553 t->std = V4L2_STD_PAL_DK;
554 } else if (*std & V4L2_STD_SECAM_L) {
555 t->std = V4L2_STD_SECAM_L;
556 } else {
557 printk(KERN_ERR "wis-sony-tuner: TV standard "
558 "not supported\n");
559 *std = 0;
560 break;
561 }
562 if (old != t->std)
563 set_if(client);
564 break;
565 case TUNER_SONY_BTF_PK467Z:
566 if (!(*std & V4L2_STD_NTSC_M_JP)) {
567 printk(KERN_ERR "wis-sony-tuner: TV standard "
568 "not supported\n");
569 *std = 0;
570 }
571 break;
572 case TUNER_SONY_BTF_PB463Z:
573 if (!(*std & V4L2_STD_NTSC_M)) {
574 printk(KERN_ERR "wis-sony-tuner: TV standard "
575 "not supported\n");
576 *std = 0;
577 }
578 break;
579 }
580 break;
581 }
582 case VIDIOC_QUERYSTD:
583 {
584 v4l2_std_id *std = arg;
585
586 switch (t->type) {
587 case TUNER_SONY_BTF_PG472Z:
588 if (force_band)
589 *std = force_band;
590 else
591 *std = V4L2_STD_PAL_BG | V4L2_STD_PAL_I |
592 V4L2_STD_PAL_DK | V4L2_STD_SECAM_L;
593 break;
594 case TUNER_SONY_BTF_PK467Z:
595 *std = V4L2_STD_NTSC_M_JP;
596 break;
597 case TUNER_SONY_BTF_PB463Z:
598 *std = V4L2_STD_NTSC_M;
599 break;
600 }
601 break;
602 }
603 case VIDIOC_G_TUNER:
604 {
605 struct v4l2_tuner *tun = arg;
606
607 memset(t, 0, sizeof(*tun));
608 strcpy(tun->name, "Television");
609 tun->type = V4L2_TUNER_ANALOG_TV;
610 tun->rangelow = 0UL;
611 tun->rangehigh = 0xffffffffUL;
612 switch (t->type) {
613 case TUNER_SONY_BTF_PG472Z:
614 tun->capability = V4L2_TUNER_CAP_NORM |
615 V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
616 V4L2_TUNER_CAP_LANG2;
617 tun->rxsubchans = V4L2_TUNER_SUB_MONO |
618 V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 |
619 V4L2_TUNER_SUB_LANG2;
620 break;
621 case TUNER_SONY_BTF_PK467Z:
622 case TUNER_SONY_BTF_PB463Z:
623 tun->capability = V4L2_TUNER_CAP_STEREO;
624 tun->rxsubchans = V4L2_TUNER_SUB_MONO |
625 V4L2_TUNER_SUB_STEREO;
626 break;
627 }
628 tun->audmode = t->audmode;
629 return 0;
630 }
631 case VIDIOC_S_TUNER:
632 {
633 struct v4l2_tuner *tun = arg;
634
635 switch (t->type) {
636 case TUNER_SONY_BTF_PG472Z:
637 if (tun->audmode != t->audmode) {
638 t->audmode = tun->audmode;
639 mpx_setup(client);
640 }
641 break;
642 case TUNER_SONY_BTF_PK467Z:
643 case TUNER_SONY_BTF_PB463Z:
644 break;
645 }
646 return 0;
647 }
648 default:
649 break;
650 }
651 return 0;
652}
653
654static struct i2c_driver wis_sony_tuner_driver;
655
656static struct i2c_client wis_sony_tuner_client_templ = {
657 .name = "Sony TV Tuner (WIS)",
658 .driver = &wis_sony_tuner_driver,
659};
660
661static int wis_sony_tuner_detect(struct i2c_adapter *adapter,
662 int addr, int kind)
663{
664 struct i2c_client *client;
665 struct wis_sony_tuner *t;
666
667 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
668 return 0;
669
670 client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
671 if (client == NULL)
672 return -ENOMEM;
673 memcpy(client, &wis_sony_tuner_client_templ,
674 sizeof(wis_sony_tuner_client_templ));
675 client->adapter = adapter;
676 client->addr = addr;
677
678 t = kmalloc(sizeof(struct wis_sony_tuner), GFP_KERNEL);
679 if (t == NULL) {
680 kfree(client);
681 return -ENOMEM;
682 }
683 t->type = -1;
684 t->freq = 0;
685 t->mpxmode = 0;
686 t->audmode = V4L2_TUNER_MODE_STEREO;
687 i2c_set_clientdata(client, t);
688
689 printk(KERN_DEBUG
690 "wis-sony-tuner: initializing tuner at address %d on %s\n",
691 addr, adapter->name);
692
693 i2c_attach_client(client);
694
695 return 0;
696}
697
698static int wis_sony_tuner_detach(struct i2c_client *client)
699{
700 struct wis_sony_tuner *t = i2c_get_clientdata(client);
701 int r;
702
703 r = i2c_detach_client(client);
704 if (r < 0)
705 return r;
706
707 kfree(t);
708 kfree(client);
709 return 0;
710}
711
712static struct i2c_driver wis_sony_tuner_driver = {
713 .driver = {
714 .name = "WIS Sony TV Tuner I2C driver",
715 },
716 .id = I2C_DRIVERID_WIS_SONY_TUNER,
717 .detach_client = wis_sony_tuner_detach,
718 .command = tuner_command,
719};
720
721static int __init wis_sony_tuner_init(void)
722{
723 int r;
724
725 r = i2c_add_driver(&wis_sony_tuner_driver);
726 if (r < 0)
727 return r;
728 return wis_i2c_add_driver(wis_sony_tuner_driver.id,
729 wis_sony_tuner_detect);
730}
731
732static void __exit wis_sony_tuner_cleanup(void)
733{
734 wis_i2c_del_driver(wis_sony_tuner_detect);
735 i2c_del_driver(&wis_sony_tuner_driver);
736}
737
738module_init(wis_sony_tuner_init);
739module_exit(wis_sony_tuner_cleanup);
740
741MODULE_LICENSE("GPL v2");
742