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