1 /*
2  * Copyright (C) 2005-2006 Micronas USA Inc.
3  *
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.
7  *
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.
12  *
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.
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 /* #define MPX_DEBUG */
30 
31 /* AS(IF/MPX) pin:      LOW      HIGH/OPEN
32  * IF/MPX address:   0x42/0x40   0x43/0x44
33  */
34 #define IF_I2C_ADDR	0x43
35 #define MPX_I2C_ADDR	0x44
36 
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);
42 
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 {
46 	char *name;
47 	unsigned char Vendor; /* unused here */
48 	unsigned char Type; /* unused here */
49 
50 	unsigned short thresh1; /*  band switch VHF_LO <=> VHF_HI */
51 	unsigned short thresh2; /*  band switch VHF_HI <=> UHF */
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 /* 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},
67 };
68 
69 struct wis_sony_tuner {
70 	int type;
71 	v4l2_std_id std;
72 	unsigned int freq;
73 	int mpxmode;
74 	u32 audmode;
75 };
76 
77 /* Basically the same as default_set_tv_freq() in tuner.c */
set_freq(struct i2c_client * client,int freq)78 static 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 
mpx_write(struct i2c_client * client,int dev,int addr,int val)111 static 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  * MPX register values for the BTF-PG472Z:
131  *
132  *                                 FM_     NICAM_  SCART_
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
137  *
138  * B/G
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
142  *
143  * I
144  *  Mono    1003    0020    0100    2603    7900    XXXX    000A    7500
145  *  NICAM   1003    0120    0100    2603    7900    XXXX    000A    7500
146  *
147  * D/K
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
153  *
154  * L/L'
155  *  Mono    0003    0200    0100    7C03    5000    2200    0009    7500
156  *  NICAM   0003    0120    0100    7C03    5000    XXXX    0009    7500
157  *
158  * M
159  *  Mono    1003    0200    0100    2B03    5000    2B00    0002    7500
160  *
161  * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX.
162  *
163  * Bilingual selection in A2/NICAM:
164  *
165  *         High byte of SOURCE     Left chan   Right chan
166  *                 0x01              MAIN         SUB
167  *                 0x03              MAIN         MAIN
168  *                 0x04              SUB          SUB
169  *
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:
172  *
173  *                      FMONO_A2
174  *                      10/0022
175  *                      --------
176  *     Forced mono ON     07F0
177  *     Forced mono OFF    0190
178  */
179 
180 static 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 	/* 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 },
217 };
218 
219 #define MPX_NUM_MODES	ARRAY_SIZE(mpx_audio_modes)
220 
mpx_setup(struct i2c_client * client)221 static 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 	/* reset MPX */
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  * IF configuration values for the BTF-PG472Z:
328  *
329  *	B/G: 0x94 0x70 0x49
330  *	I:   0x14 0x70 0x4a
331  *	D/K: 0x14 0x70 0x4b
332  *	L:   0x04 0x70 0x4b
333  *	L':  0x44 0x70 0x53
334  *	M:   0x50 0x30 0x4c
335  */
336 
set_if(struct i2c_client * client)337 static 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 	/* configure IF */
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 	/* 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;
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 
tuner_command(struct i2c_client * client,unsigned int cmd,void * arg)385 static 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; /* hack to indicate EINVAL */
509 				break;
510 			}
511 			break;
512 		case TUNER_SONY_BTF_PK467Z:
513 			if (std->index != 0) {
514 				std->id = 0; /* hack to indicate EINVAL */
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; /* hack to indicate EINVAL */
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) { /* 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;
559 			} else {
560 				printk(KERN_ERR "wis-sony-tuner: TV standard "
561 						"not supported\n");
562 				*std = 0; /* hack to indicate EINVAL */
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; /* hack to indicate EINVAL */
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; /* hack to indicate EINVAL */
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; /* does anything use these? */
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 
657 static 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 
683 static 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 
691 static const struct i2c_device_id wis_sony_tuner_id[] = {
692 	{ "wis_sony_tuner", 0 },
693 	{ }
694 };
695 MODULE_DEVICE_TABLE(i2c, wis_sony_tuner_id);
696 
697 static 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 
707 static int __init wis_sony_tuner_init(void)
708 {
709 	return i2c_add_driver(&wis_sony_tuner_driver);
710 }
711 
712 static void __exit wis_sony_tuner_cleanup(void)
713 {
714 	i2c_del_driver(&wis_sony_tuner_driver);
715 }
716 
717 module_init(wis_sony_tuner_init);
718 module_exit(wis_sony_tuner_cleanup);
719 
720 MODULE_LICENSE("GPL v2");
721