2 * Copyright (C) 2005-2006 Micronas USA Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License (Version 2) as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
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>
29 /* #define MPX_DEBUG */
31 /* AS(IF/MPX) pin: LOW HIGH/OPEN
32 * IF/MPX address: 0x42/0x40 0x43/0x44
34 #define IF_I2C_ADDR 0x43
35 #define MPX_I2C_ADDR 0x44
37 static v4l2_std_id force_band
;
38 static char force_band_str
[] = "-";
39 module_param_string(force_band
, force_band_str
, sizeof(force_band_str
), 0644);
40 static int force_mpx_mode
= -1;
41 module_param(force_mpx_mode
, int, 0644);
43 /* Store tuner info in the same format as tuner.c, so maybe we can put the
44 * Sony tuner support in there. */
45 struct sony_tunertype
{
47 unsigned char Vendor
; /* unused here */
48 unsigned char Type
; /* unused here */
50 unsigned short thresh1
; /* band switch VHF_LO <=> VHF_HI */
51 unsigned short thresh2
; /* band switch VHF_HI <=> UHF */
56 unsigned short IFPCoff
;
59 /* This array is indexed by (tuner_type - 200) */
60 static 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},
69 struct wis_sony_tuner
{
77 /* Basically the same as default_set_tv_freq() in tuner.c */
78 static int set_freq(struct i2c_client
*client
, int freq
)
80 struct wis_sony_tuner
*t
= i2c_get_clientdata(client
);
84 struct sony_tunertype
*tun
;
87 tun
= &sony_tuners
[t
->type
- 200];
88 if (freq
< tun
->thresh1
) {
90 band_select
= tun
->VHF_L
;
91 } else if (freq
< tun
->thresh2
) {
93 band_select
= tun
->VHF_H
;
96 band_select
= tun
->UHF
;
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
;
103 buffer
[1] = n
& 0xff;
104 buffer
[2] = tun
->config
;
105 buffer
[3] = band_select
;
106 i2c_master_send(client
, buffer
, 4);
111 static int mpx_write(struct i2c_client
*client
, int dev
, int addr
, int val
)
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
;
125 i2c_transfer(client
->adapter
, &msg
, 1);
130 * MPX register values for the BTF-PG472Z:
133 * MODUS SOURCE ACB PRESCAL PRESCAL PRESCAL SYSTEM VOLUME
134 * 10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000
135 * ---------------------------------------------------------------
136 * Auto 1003 0020 0100 2603 5000 XXXX 0001 7500
139 * Mono 1003 0020 0100 2603 5000 XXXX 0003 7500
140 * A2 1003 0020 0100 2601 5000 XXXX 0003 7500
141 * NICAM 1003 0120 0100 2603 5000 XXXX 0008 7500
144 * Mono 1003 0020 0100 2603 7900 XXXX 000A 7500
145 * NICAM 1003 0120 0100 2603 7900 XXXX 000A 7500
148 * Mono 1003 0020 0100 2603 5000 XXXX 0004 7500
149 * A2-1 1003 0020 0100 2601 5000 XXXX 0004 7500
150 * A2-2 1003 0020 0100 2601 5000 XXXX 0005 7500
151 * A2-3 1003 0020 0100 2601 5000 XXXX 0007 7500
152 * NICAM 1003 0120 0100 2603 5000 XXXX 000B 7500
155 * Mono 0003 0200 0100 7C03 5000 2200 0009 7500
156 * NICAM 0003 0120 0100 7C03 5000 XXXX 0009 7500
159 * Mono 1003 0200 0100 2B03 5000 2B00 0002 7500
161 * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX.
163 * Bilingual selection in A2/NICAM:
165 * High byte of SOURCE Left chan Right chan
170 * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or
171 * 0x00 (all other bands). Force mono in A2 with FMONO_A2:
176 * Forced mono ON 07F0
177 * Forced mono OFF 0190
181 enum { AUD_MONO
, AUD_A2
, AUD_NICAM
, AUD_NICAM_L
} audio_mode
;
190 } mpx_audio_modes
[] = {
191 /* Auto */ { AUD_MONO
, 0x1003, 0x0020, 0x0100, 0x2603,
192 0x5000, 0x0000, 0x0001, 0x7500 },
193 /* B/G Mono */ { AUD_MONO
, 0x1003, 0x0020, 0x0100, 0x2603,
194 0x5000, 0x0000, 0x0003, 0x7500 },
195 /* B/G A2 */ { AUD_A2
, 0x1003, 0x0020, 0x0100, 0x2601,
196 0x5000, 0x0000, 0x0003, 0x7500 },
197 /* B/G NICAM */ { AUD_NICAM
, 0x1003, 0x0120, 0x0100, 0x2603,
198 0x5000, 0x0000, 0x0008, 0x7500 },
199 /* I Mono */ { AUD_MONO
, 0x1003, 0x0020, 0x0100, 0x2603,
200 0x7900, 0x0000, 0x000A, 0x7500 },
201 /* I NICAM */ { AUD_NICAM
, 0x1003, 0x0120, 0x0100, 0x2603,
202 0x7900, 0x0000, 0x000A, 0x7500 },
203 /* D/K Mono */ { AUD_MONO
, 0x1003, 0x0020, 0x0100, 0x2603,
204 0x5000, 0x0000, 0x0004, 0x7500 },
205 /* D/K A2-1 */ { AUD_A2
, 0x1003, 0x0020, 0x0100, 0x2601,
206 0x5000, 0x0000, 0x0004, 0x7500 },
207 /* D/K A2-2 */ { AUD_A2
, 0x1003, 0x0020, 0x0100, 0x2601,
208 0x5000, 0x0000, 0x0005, 0x7500 },
209 /* D/K A2-3 */ { AUD_A2
, 0x1003, 0x0020, 0x0100, 0x2601,
210 0x5000, 0x0000, 0x0007, 0x7500 },
211 /* D/K NICAM */ { AUD_NICAM
, 0x1003, 0x0120, 0x0100, 0x2603,
212 0x5000, 0x0000, 0x000B, 0x7500 },
213 /* L/L' Mono */ { AUD_MONO
, 0x0003, 0x0200, 0x0100, 0x7C03,
214 0x5000, 0x2200, 0x0009, 0x7500 },
215 /* L/L' NICAM */{ AUD_NICAM_L
, 0x0003, 0x0120, 0x0100, 0x7C03,
216 0x5000, 0x0000, 0x0009, 0x7500 },
219 #define MPX_NUM_MODES ARRAY_SIZE(mpx_audio_modes)
221 static int mpx_setup(struct i2c_client
*client
)
223 struct wis_sony_tuner
*t
= i2c_get_clientdata(client
);
232 msg
.addr
= MPX_I2C_ADDR
;
236 i2c_transfer(client
->adapter
, &msg
, 1);
238 i2c_transfer(client
->adapter
, &msg
, 1);
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
) {
245 source
= mpx_audio_modes
[t
->mpxmode
].source
;
257 case V4L2_TUNER_MODE_STEREO
:
258 source
= mpx_audio_modes
[t
->mpxmode
].source
;
260 case V4L2_TUNER_MODE_LANG1
:
263 case V4L2_TUNER_MODE_LANG2
:
267 source
|= mpx_audio_modes
[t
->mpxmode
].source
& 0x00ff;
269 source
= mpx_audio_modes
[t
->mpxmode
].source
;
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);
289 struct i2c_msg msgs
[2];
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
,
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
);
304 msgs
[0].addr
= MPX_I2C_ADDR
;
308 msgs
[1].addr
= MPX_I2C_ADDR
;
309 msgs
[1].flags
= I2C_M_RD
;
312 i2c_transfer(client
->adapter
, msgs
, 2);
313 printk(KERN_DEBUG
"wis-sony-tuner: MPX system: %02x%02x\n",
318 i2c_transfer(client
->adapter
, msgs
, 2);
319 printk(KERN_DEBUG
"wis-sony-tuner: MPX status: %02x%02x\n",
327 * IF configuration values for the BTF-PG472Z:
329 * B/G: 0x94 0x70 0x49
331 * D/K: 0x14 0x70 0x4b
337 static int set_if(struct i2c_client
*client
)
339 struct wis_sony_tuner
*t
= i2c_get_clientdata(client
);
342 int default_mpx_mode
= 0;
346 if (t
->std
& V4L2_STD_PAL_BG
) {
350 default_mpx_mode
= 1;
351 } else if (t
->std
& V4L2_STD_PAL_I
) {
355 default_mpx_mode
= 4;
356 } else if (t
->std
& V4L2_STD_PAL_DK
) {
360 default_mpx_mode
= 6;
361 } else if (t
->std
& V4L2_STD_SECAM_L
) {
365 default_mpx_mode
= 11;
367 msg
.addr
= IF_I2C_ADDR
;
371 i2c_transfer(client
->adapter
, &msg
, 1);
373 /* Select MPX mode if not forced by the user */
374 if (force_mpx_mode
>= 0 && force_mpx_mode
< MPX_NUM_MODES
)
375 t
->mpxmode
= force_mpx_mode
;
377 t
->mpxmode
= default_mpx_mode
;
378 printk(KERN_DEBUG
"wis-sony-tuner: setting MPX to mode %d\n",
385 static int tuner_command(struct i2c_client
*client
, unsigned int cmd
, void *arg
)
387 struct wis_sony_tuner
*t
= i2c_get_clientdata(client
);
391 #ifdef TUNER_SET_TYPE_ADDR
392 case TUNER_SET_TYPE_ADDR
:
394 struct tuner_setup
*tun_setup
= arg
;
395 int *type
= &tun_setup
->type
;
403 if (t
->type
!= *type
)
404 printk(KERN_ERR
"wis-sony-tuner: type already "
405 "set to %d, ignoring request for %d\n",
411 case TUNER_SONY_BTF_PG472Z
:
412 switch (force_band_str
[0]) {
417 printk(KERN_INFO
"wis-sony-tuner: forcing "
418 "tuner to PAL-B/G bands\n");
419 force_band
= V4L2_STD_PAL_BG
;
423 printk(KERN_INFO
"wis-sony-tuner: forcing "
424 "tuner to PAL-I band\n");
425 force_band
= V4L2_STD_PAL_I
;
431 printk(KERN_INFO
"wis-sony-tuner: forcing "
432 "tuner to PAL-D/K bands\n");
433 force_band
= V4L2_STD_PAL_I
;
437 printk(KERN_INFO
"wis-sony-tuner: forcing "
438 "tuner to SECAM-L band\n");
439 force_band
= V4L2_STD_SECAM_L
;
448 t
->std
= V4L2_STD_PAL_BG
;
451 case TUNER_SONY_BTF_PK467Z
:
452 t
->std
= V4L2_STD_NTSC_M_JP
;
454 case TUNER_SONY_BTF_PB463Z
:
455 t
->std
= V4L2_STD_NTSC_M
;
458 printk(KERN_ERR
"wis-sony-tuner: tuner type %d is not "
459 "supported by this module\n", *type
);
464 "wis-sony-tuner: type set to %d (%s)\n",
465 t
->type
, sony_tuners
[t
->type
- 200].name
);
469 case VIDIOC_G_FREQUENCY
:
471 struct v4l2_frequency
*f
= arg
;
473 f
->frequency
= t
->freq
;
476 case VIDIOC_S_FREQUENCY
:
478 struct v4l2_frequency
*f
= arg
;
480 t
->freq
= f
->frequency
;
481 set_freq(client
, t
->freq
);
486 struct v4l2_standard
*std
= arg
;
489 case TUNER_SONY_BTF_PG472Z
:
490 switch (std
->index
) {
492 v4l2_video_std_construct(std
,
493 V4L2_STD_PAL_BG
, "PAL-B/G");
496 v4l2_video_std_construct(std
,
497 V4L2_STD_PAL_I
, "PAL-I");
500 v4l2_video_std_construct(std
,
501 V4L2_STD_PAL_DK
, "PAL-D/K");
504 v4l2_video_std_construct(std
,
505 V4L2_STD_SECAM_L
, "SECAM-L");
508 std
->id
= 0; /* hack to indicate EINVAL */
512 case TUNER_SONY_BTF_PK467Z
:
513 if (std
->index
!= 0) {
514 std
->id
= 0; /* hack to indicate EINVAL */
517 v4l2_video_std_construct(std
,
518 V4L2_STD_NTSC_M_JP
, "NTSC-J");
520 case TUNER_SONY_BTF_PB463Z
:
521 if (std
->index
!= 0) {
522 std
->id
= 0; /* hack to indicate EINVAL */
525 v4l2_video_std_construct(std
, V4L2_STD_NTSC_M
, "NTSC");
532 v4l2_std_id
*std
= arg
;
539 v4l2_std_id
*std
= arg
;
540 v4l2_std_id old
= t
->std
;
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");
551 } else if (*std
& V4L2_STD_PAL_BG
) { /* default */
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
;
560 printk(KERN_ERR
"wis-sony-tuner: TV standard "
562 *std
= 0; /* hack to indicate EINVAL */
568 case TUNER_SONY_BTF_PK467Z
:
569 if (!(*std
& V4L2_STD_NTSC_M_JP
)) {
570 printk(KERN_ERR
"wis-sony-tuner: TV standard "
572 *std
= 0; /* hack to indicate EINVAL */
575 case TUNER_SONY_BTF_PB463Z
:
576 if (!(*std
& V4L2_STD_NTSC_M
)) {
577 printk(KERN_ERR
"wis-sony-tuner: TV standard "
579 *std
= 0; /* hack to indicate EINVAL */
585 case VIDIOC_QUERYSTD
:
587 v4l2_std_id
*std
= arg
;
590 case TUNER_SONY_BTF_PG472Z
:
594 *std
= V4L2_STD_PAL_BG
| V4L2_STD_PAL_I
|
595 V4L2_STD_PAL_DK
| V4L2_STD_SECAM_L
;
597 case TUNER_SONY_BTF_PK467Z
:
598 *std
= V4L2_STD_NTSC_M_JP
;
600 case TUNER_SONY_BTF_PB463Z
:
601 *std
= V4L2_STD_NTSC_M
;
608 struct v4l2_tuner
*tun
= arg
;
610 memset(tun
, 0, sizeof(*tun
));
611 strcpy(tun
->name
, "Television");
612 tun
->type
= V4L2_TUNER_ANALOG_TV
;
613 tun
->rangelow
= 0UL; /* does anything use these? */
614 tun
->rangehigh
= 0xffffffffUL
;
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
;
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
;
631 tun
->audmode
= t
->audmode
;
636 struct v4l2_tuner
*tun
= arg
;
639 case TUNER_SONY_BTF_PG472Z
:
640 if (tun
->audmode
!= t
->audmode
) {
641 t
->audmode
= tun
->audmode
;
645 case TUNER_SONY_BTF_PK467Z
:
646 case TUNER_SONY_BTF_PB463Z
:
657 static int wis_sony_tuner_probe(struct i2c_client
*client
,
658 const struct i2c_device_id
*id
)
660 struct i2c_adapter
*adapter
= client
->adapter
;
661 struct wis_sony_tuner
*t
;
663 if (!i2c_check_functionality(adapter
, I2C_FUNC_SMBUS_I2C_BLOCK
))
666 t
= kmalloc(sizeof(struct wis_sony_tuner
), GFP_KERNEL
);
673 t
->audmode
= V4L2_TUNER_MODE_STEREO
;
674 i2c_set_clientdata(client
, t
);
677 "wis-sony-tuner: initializing tuner at address %d on %s\n",
678 client
->addr
, adapter
->name
);
683 static int wis_sony_tuner_remove(struct i2c_client
*client
)
685 struct wis_sony_tuner
*t
= i2c_get_clientdata(client
);
691 static const struct i2c_device_id wis_sony_tuner_id
[] = {
692 { "wis_sony_tuner", 0 },
695 MODULE_DEVICE_TABLE(i2c
, wis_sony_tuner_id
);
697 static struct i2c_driver wis_sony_tuner_driver
= {
699 .name
= "WIS Sony TV Tuner I2C driver",
701 .probe
= wis_sony_tuner_probe
,
702 .remove
= wis_sony_tuner_remove
,
703 .command
= tuner_command
,
704 .id_table
= wis_sony_tuner_id
,
707 static int __init
wis_sony_tuner_init(void)
709 return i2c_add_driver(&wis_sony_tuner_driver
);
712 static void __exit
wis_sony_tuner_cleanup(void)
714 i2c_del_driver(&wis_sony_tuner_driver
);
717 module_init(wis_sony_tuner_init
);
718 module_exit(wis_sony_tuner_cleanup
);
720 MODULE_LICENSE("GPL v2");