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#if 0
390#ifdef TUNER_SET_TYPE_ADDR
391 case TUNER_SET_TYPE_ADDR:
392 {
393 struct tuner_setup *tun_setup = arg;
394 int *type = &tun_setup->type;
395#else
396 case TUNER_SET_TYPE:
397 {
398 int *type = arg;
399#endif
400
401 if (t->type >= 0) {
402 if (t->type != *type)
403 printk(KERN_ERR "wis-sony-tuner: type already "
404 "set to %d, ignoring request for %d\n",
405 t->type, *type);
406 break;
407 }
408 t->type = *type;
409 switch (t->type) {
410 case TUNER_SONY_BTF_PG472Z:
411 switch (force_band_str[0]) {
412 case 'b':
413 case 'B':
414 case 'g':
415 case 'G':
416 printk(KERN_INFO "wis-sony-tuner: forcing "
417 "tuner to PAL-B/G bands\n");
418 force_band = V4L2_STD_PAL_BG;
419 break;
420 case 'i':
421 case 'I':
422 printk(KERN_INFO "wis-sony-tuner: forcing "
423 "tuner to PAL-I band\n");
424 force_band = V4L2_STD_PAL_I;
425 break;
426 case 'd':
427 case 'D':
428 case 'k':
429 case 'K':
430 printk(KERN_INFO "wis-sony-tuner: forcing "
431 "tuner to PAL-D/K bands\n");
432 force_band = V4L2_STD_PAL_I;
433 break;
434 case 'l':
435 case 'L':
436 printk(KERN_INFO "wis-sony-tuner: forcing "
437 "tuner to SECAM-L band\n");
438 force_band = V4L2_STD_SECAM_L;
439 break;
440 default:
441 force_band = 0;
442 break;
443 }
444 if (force_band)
445 t->std = force_band;
446 else
447 t->std = V4L2_STD_PAL_BG;
448 set_if(client);
449 break;
450 case TUNER_SONY_BTF_PK467Z:
451 t->std = V4L2_STD_NTSC_M_JP;
452 break;
453 case TUNER_SONY_BTF_PB463Z:
454 t->std = V4L2_STD_NTSC_M;
455 break;
456 default:
457 printk(KERN_ERR "wis-sony-tuner: tuner type %d is not "
458 "supported by this module\n", *type);
459 break;
460 }
461 if (type >= 0)
462 printk(KERN_INFO
463 "wis-sony-tuner: type set to %d (%s)\n",
464 t->type, sony_tuners[t->type - 200].name);
465 break;
466 }
467#endif
468 case VIDIOC_G_FREQUENCY:
469 {
470 struct v4l2_frequency *f = arg;
471
472 f->frequency = t->freq;
473 break;
474 }
475 case VIDIOC_S_FREQUENCY:
476 {
477 struct v4l2_frequency *f = arg;
478
479 t->freq = f->frequency;
480 set_freq(client, t->freq);
481 break;
482 }
483 case VIDIOC_ENUMSTD:
484 {
485 struct v4l2_standard *std = arg;
486
487 switch (t->type) {
488 case TUNER_SONY_BTF_PG472Z:
489 switch (std->index) {
490 case 0:
491 v4l2_video_std_construct(std,
492 V4L2_STD_PAL_BG, "PAL-B/G");
493 break;
494 case 1:
495 v4l2_video_std_construct(std,
496 V4L2_STD_PAL_I, "PAL-I");
497 break;
498 case 2:
499 v4l2_video_std_construct(std,
500 V4L2_STD_PAL_DK, "PAL-D/K");
501 break;
502 case 3:
503 v4l2_video_std_construct(std,
504 V4L2_STD_SECAM_L, "SECAM-L");
505 break;
506 default:
507 std->id = 0;
508 break;
509 }
510 break;
511 case TUNER_SONY_BTF_PK467Z:
512 if (std->index != 0) {
513 std->id = 0;
514 break;
515 }
516 v4l2_video_std_construct(std,
517 V4L2_STD_NTSC_M_JP, "NTSC-J");
518 break;
519 case TUNER_SONY_BTF_PB463Z:
520 if (std->index != 0) {
521 std->id = 0;
522 break;
523 }
524 v4l2_video_std_construct(std, V4L2_STD_NTSC_M, "NTSC");
525 break;
526 }
527 break;
528 }
529 case VIDIOC_G_STD:
530 {
531 v4l2_std_id *std = arg;
532
533 *std = t->std;
534 break;
535 }
536 case VIDIOC_S_STD:
537 {
538 v4l2_std_id *std = arg;
539 v4l2_std_id old = t->std;
540
541 switch (t->type) {
542 case TUNER_SONY_BTF_PG472Z:
543 if (force_band && (*std & force_band) != *std &&
544 *std != V4L2_STD_PAL &&
545 *std != V4L2_STD_SECAM) {
546 printk(KERN_DEBUG "wis-sony-tuner: ignoring "
547 "requested TV standard in "
548 "favor of force_band value\n");
549 t->std = force_band;
550 } else if (*std & V4L2_STD_PAL_BG) {
551 t->std = V4L2_STD_PAL_BG;
552 } else if (*std & V4L2_STD_PAL_I) {
553 t->std = V4L2_STD_PAL_I;
554 } else if (*std & V4L2_STD_PAL_DK) {
555 t->std = V4L2_STD_PAL_DK;
556 } else if (*std & V4L2_STD_SECAM_L) {
557 t->std = V4L2_STD_SECAM_L;
558 } else {
559 printk(KERN_ERR "wis-sony-tuner: TV standard "
560 "not supported\n");
561 *std = 0;
562 break;
563 }
564 if (old != t->std)
565 set_if(client);
566 break;
567 case TUNER_SONY_BTF_PK467Z:
568 if (!(*std & V4L2_STD_NTSC_M_JP)) {
569 printk(KERN_ERR "wis-sony-tuner: TV standard "
570 "not supported\n");
571 *std = 0;
572 }
573 break;
574 case TUNER_SONY_BTF_PB463Z:
575 if (!(*std & V4L2_STD_NTSC_M)) {
576 printk(KERN_ERR "wis-sony-tuner: TV standard "
577 "not supported\n");
578 *std = 0;
579 }
580 break;
581 }
582 break;
583 }
584 case VIDIOC_QUERYSTD:
585 {
586 v4l2_std_id *std = arg;
587
588 switch (t->type) {
589 case TUNER_SONY_BTF_PG472Z:
590 if (force_band)
591 *std = force_band;
592 else
593 *std = V4L2_STD_PAL_BG | V4L2_STD_PAL_I |
594 V4L2_STD_PAL_DK | V4L2_STD_SECAM_L;
595 break;
596 case TUNER_SONY_BTF_PK467Z:
597 *std = V4L2_STD_NTSC_M_JP;
598 break;
599 case TUNER_SONY_BTF_PB463Z:
600 *std = V4L2_STD_NTSC_M;
601 break;
602 }
603 break;
604 }
605 case VIDIOC_G_TUNER:
606 {
607 struct v4l2_tuner *tun = arg;
608
609 memset(tun, 0, sizeof(*tun));
610 strcpy(tun->name, "Television");
611 tun->type = V4L2_TUNER_ANALOG_TV;
612 tun->rangelow = 0UL;
613 tun->rangehigh = 0xffffffffUL;
614 switch (t->type) {
615 case TUNER_SONY_BTF_PG472Z:
616 tun->capability = V4L2_TUNER_CAP_NORM |
617 V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
618 V4L2_TUNER_CAP_LANG2;
619 tun->rxsubchans = V4L2_TUNER_SUB_MONO |
620 V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 |
621 V4L2_TUNER_SUB_LANG2;
622 break;
623 case TUNER_SONY_BTF_PK467Z:
624 case TUNER_SONY_BTF_PB463Z:
625 tun->capability = V4L2_TUNER_CAP_STEREO;
626 tun->rxsubchans = V4L2_TUNER_SUB_MONO |
627 V4L2_TUNER_SUB_STEREO;
628 break;
629 }
630 tun->audmode = t->audmode;
631 return 0;
632 }
633 case VIDIOC_S_TUNER:
634 {
635 struct v4l2_tuner *tun = arg;
636
637 switch (t->type) {
638 case TUNER_SONY_BTF_PG472Z:
639 if (tun->audmode != t->audmode) {
640 t->audmode = tun->audmode;
641 mpx_setup(client);
642 }
643 break;
644 case TUNER_SONY_BTF_PK467Z:
645 case TUNER_SONY_BTF_PB463Z:
646 break;
647 }
648 return 0;
649 }
650 default:
651 break;
652 }
653 return 0;
654}
655
656static int wis_sony_tuner_probe(struct i2c_client *client,
657 const struct i2c_device_id *id)
658{
659 struct i2c_adapter *adapter = client->adapter;
660 struct wis_sony_tuner *t;
661
662 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
663 return -ENODEV;
664
665 t = kmalloc(sizeof(struct wis_sony_tuner), GFP_KERNEL);
666 if (t == NULL)
667 return -ENOMEM;
668
669 t->type = -1;
670 t->freq = 0;
671 t->mpxmode = 0;
672 t->audmode = V4L2_TUNER_MODE_STEREO;
673 i2c_set_clientdata(client, t);
674
675 printk(KERN_DEBUG
676 "wis-sony-tuner: initializing tuner at address %d on %s\n",
677 client->addr, adapter->name);
678
679 return 0;
680}
681
682static int wis_sony_tuner_remove(struct i2c_client *client)
683{
684 struct wis_sony_tuner *t = i2c_get_clientdata(client);
685
686 i2c_set_clientdata(client, NULL);
687 kfree(t);
688 return 0;
689}
690
691static struct i2c_device_id wis_sony_tuner_id[] = {
692 { "wis_sony_tuner", 0 },
693 { }
694};
695
696static struct i2c_driver wis_sony_tuner_driver = {
697 .driver = {
698 .name = "WIS Sony TV Tuner I2C driver",
699 },
700 .probe = wis_sony_tuner_probe,
701 .remove = wis_sony_tuner_remove,
702 .command = tuner_command,
703 .id_table = wis_sony_tuner_id,
704};
705
706static int __init wis_sony_tuner_init(void)
707{
708 return i2c_add_driver(&wis_sony_tuner_driver);
709}
710
711static void __exit wis_sony_tuner_cleanup(void)
712{
713 i2c_del_driver(&wis_sony_tuner_driver);
714}
715
716module_init(wis_sony_tuner_init);
717module_exit(wis_sony_tuner_cleanup);
718
719MODULE_LICENSE("GPL v2");
720