First Support on Ginger and OMAP TI
[linux-ginger.git] / drivers / staging / go7007 / wis-sony-tuner.c
blob086896cec49be78c9628302de14a8e0fba6732f6
1 /*
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 <media/tuner.h>
23 #include <media/v4l2-common.h>
24 #include <media/v4l2-ioctl.h>
26 #include "wis-i2c.h"
28 /* #define MPX_DEBUG */
30 /* AS(IF/MPX) pin: LOW HIGH/OPEN
31 * IF/MPX address: 0x42/0x40 0x43/0x44
33 #define IF_I2C_ADDR 0x43
34 #define MPX_I2C_ADDR 0x44
36 static v4l2_std_id force_band;
37 static char force_band_str[] = "-";
38 module_param_string(force_band, force_band_str, sizeof(force_band_str), 0644);
39 static int force_mpx_mode = -1;
40 module_param(force_mpx_mode, int, 0644);
42 /* Store tuner info in the same format as tuner.c, so maybe we can put the
43 * Sony tuner support in there. */
44 struct sony_tunertype {
45 char *name;
46 unsigned char Vendor; /* unused here */
47 unsigned char Type; /* unused here */
49 unsigned short thresh1; /* band switch VHF_LO <=> VHF_HI */
50 unsigned short thresh2; /* band switch VHF_HI <=> UHF */
51 unsigned char VHF_L;
52 unsigned char VHF_H;
53 unsigned char UHF;
54 unsigned char config;
55 unsigned short IFPCoff;
58 /* This array is indexed by (tuner_type - 200) */
59 static 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},
68 struct wis_sony_tuner {
69 int type;
70 v4l2_std_id std;
71 unsigned int freq;
72 int mpxmode;
73 u32 audmode;
76 /* Basically the same as default_set_tv_freq() in tuner.c */
77 static int set_freq(struct i2c_client *client, int freq)
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];
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;
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;
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);
107 return 0;
110 static int mpx_write(struct i2c_client *client, int dev, int addr, int val)
112 u8 buffer[5];
113 struct i2c_msg msg;
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;
129 * MPX register values for the BTF-PG472Z:
131 * FM_ NICAM_ SCART_
132 * MODUS SOURCE ACB PRESCAL PRESCAL PRESCAL SYSTEM VOLUME
133 * 10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000
134 * ---------------------------------------------------------------
135 * Auto 1003 0020 0100 2603 5000 XXXX 0001 7500
137 * B/G
138 * Mono 1003 0020 0100 2603 5000 XXXX 0003 7500
139 * A2 1003 0020 0100 2601 5000 XXXX 0003 7500
140 * NICAM 1003 0120 0100 2603 5000 XXXX 0008 7500
143 * Mono 1003 0020 0100 2603 7900 XXXX 000A 7500
144 * NICAM 1003 0120 0100 2603 7900 XXXX 000A 7500
146 * D/K
147 * Mono 1003 0020 0100 2603 5000 XXXX 0004 7500
148 * A2-1 1003 0020 0100 2601 5000 XXXX 0004 7500
149 * A2-2 1003 0020 0100 2601 5000 XXXX 0005 7500
150 * A2-3 1003 0020 0100 2601 5000 XXXX 0007 7500
151 * NICAM 1003 0120 0100 2603 5000 XXXX 000B 7500
153 * L/L'
154 * Mono 0003 0200 0100 7C03 5000 2200 0009 7500
155 * NICAM 0003 0120 0100 7C03 5000 XXXX 0009 7500
158 * Mono 1003 0200 0100 2B03 5000 2B00 0002 7500
160 * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX.
162 * Bilingual selection in A2/NICAM:
164 * High byte of SOURCE Left chan Right chan
165 * 0x01 MAIN SUB
166 * 0x03 MAIN MAIN
167 * 0x04 SUB SUB
169 * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or
170 * 0x00 (all other bands). Force mono in A2 with FMONO_A2:
172 * FMONO_A2
173 * 10/0022
174 * --------
175 * Forced mono ON 07F0
176 * Forced mono OFF 0190
179 static 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 /* Auto */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
191 0x5000, 0x0000, 0x0001, 0x7500 },
192 /* B/G Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
193 0x5000, 0x0000, 0x0003, 0x7500 },
194 /* B/G A2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
195 0x5000, 0x0000, 0x0003, 0x7500 },
196 /* B/G NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
197 0x5000, 0x0000, 0x0008, 0x7500 },
198 /* I Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
199 0x7900, 0x0000, 0x000A, 0x7500 },
200 /* I NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
201 0x7900, 0x0000, 0x000A, 0x7500 },
202 /* D/K Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
203 0x5000, 0x0000, 0x0004, 0x7500 },
204 /* D/K A2-1 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
205 0x5000, 0x0000, 0x0004, 0x7500 },
206 /* D/K A2-2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
207 0x5000, 0x0000, 0x0005, 0x7500 },
208 /* D/K A2-3 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
209 0x5000, 0x0000, 0x0007, 0x7500 },
210 /* D/K NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
211 0x5000, 0x0000, 0x000B, 0x7500 },
212 /* L/L' Mono */ { AUD_MONO, 0x0003, 0x0200, 0x0100, 0x7C03,
213 0x5000, 0x2200, 0x0009, 0x7500 },
214 /* L/L' NICAM */{ AUD_NICAM_L, 0x0003, 0x0120, 0x0100, 0x7C03,
215 0x5000, 0x0000, 0x0009, 0x7500 },
218 #define MPX_NUM_MODES ARRAY_SIZE(mpx_audio_modes)
220 static int mpx_setup(struct i2c_client *client)
222 struct wis_sony_tuner *t = i2c_get_clientdata(client);
223 u16 source = 0;
224 u8 buffer[3];
225 struct i2c_msg msg;
227 /* reset MPX */
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);
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;
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;
266 source |= mpx_audio_modes[t->mpxmode].source & 0x00ff;
267 } else
268 source = mpx_audio_modes[t->mpxmode].source;
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);
285 #ifdef MPX_DEBUG
287 u8 buf1[3], buf2[2];
288 struct i2c_msg msgs[2];
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]);
321 #endif
322 return 0;
326 * IF configuration values for the BTF-PG472Z:
328 * B/G: 0x94 0x70 0x49
329 * I: 0x14 0x70 0x4a
330 * D/K: 0x14 0x70 0x4b
331 * L: 0x04 0x70 0x4b
332 * L': 0x44 0x70 0x53
333 * M: 0x50 0x30 0x4c
336 static int set_if(struct i2c_client *client)
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;
343 /* configure IF */
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;
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);
372 /* Select MPX mode if not forced by the user */
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);
381 return 0;
384 static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
386 struct wis_sony_tuner *t = i2c_get_clientdata(client);
388 switch (cmd) {
389 #if 0
390 #ifdef TUNER_SET_TYPE_ADDR
391 case TUNER_SET_TYPE_ADDR:
393 struct tuner_setup *tun_setup = arg;
394 int *type = &tun_setup->type;
395 #else
396 case TUNER_SET_TYPE:
398 int *type = arg;
399 #endif
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;
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;
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;
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;
467 #endif
468 case VIDIOC_G_FREQUENCY:
470 struct v4l2_frequency *f = arg;
472 f->frequency = t->freq;
473 break;
475 case VIDIOC_S_FREQUENCY:
477 struct v4l2_frequency *f = arg;
479 t->freq = f->frequency;
480 set_freq(client, t->freq);
481 break;
483 case VIDIOC_ENUMSTD:
485 struct v4l2_standard *std = arg;
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; /* hack to indicate EINVAL */
508 break;
510 break;
511 case TUNER_SONY_BTF_PK467Z:
512 if (std->index != 0) {
513 std->id = 0; /* hack to indicate EINVAL */
514 break;
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; /* hack to indicate EINVAL */
522 break;
524 v4l2_video_std_construct(std, V4L2_STD_NTSC_M, "NTSC");
525 break;
527 break;
529 case VIDIOC_G_STD:
531 v4l2_std_id *std = arg;
533 *std = t->std;
534 break;
536 case VIDIOC_S_STD:
538 v4l2_std_id *std = arg;
539 v4l2_std_id old = t->std;
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) { /* default */
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; /* hack to indicate EINVAL */
562 break;
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; /* hack to indicate EINVAL */
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; /* hack to indicate EINVAL */
580 break;
582 break;
584 case VIDIOC_QUERYSTD:
586 v4l2_std_id *std = arg;
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;
603 break;
605 case VIDIOC_G_TUNER:
607 struct v4l2_tuner *tun = arg;
609 memset(tun, 0, sizeof(*tun));
610 strcpy(tun->name, "Television");
611 tun->type = V4L2_TUNER_ANALOG_TV;
612 tun->rangelow = 0UL; /* does anything use these? */
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;
630 tun->audmode = t->audmode;
631 return 0;
633 case VIDIOC_S_TUNER:
635 struct v4l2_tuner *tun = arg;
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);
643 break;
644 case TUNER_SONY_BTF_PK467Z:
645 case TUNER_SONY_BTF_PB463Z:
646 break;
648 return 0;
650 default:
651 break;
653 return 0;
656 static int wis_sony_tuner_probe(struct i2c_client *client,
657 const struct i2c_device_id *id)
659 struct i2c_adapter *adapter = client->adapter;
660 struct wis_sony_tuner *t;
662 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
663 return -ENODEV;
665 t = kmalloc(sizeof(struct wis_sony_tuner), GFP_KERNEL);
666 if (t == NULL)
667 return -ENOMEM;
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);
675 printk(KERN_DEBUG
676 "wis-sony-tuner: initializing tuner at address %d on %s\n",
677 client->addr, adapter->name);
679 return 0;
682 static int wis_sony_tuner_remove(struct i2c_client *client)
684 struct wis_sony_tuner *t = i2c_get_clientdata(client);
686 i2c_set_clientdata(client, NULL);
687 kfree(t);
688 return 0;
691 static struct i2c_device_id wis_sony_tuner_id[] = {
692 { "wis_sony_tuner", 0 },
696 static struct i2c_driver wis_sony_tuner_driver = {
697 .driver = {
698 .name = "WIS Sony TV Tuner I2C driver",
700 .probe = wis_sony_tuner_probe,
701 .remove = wis_sony_tuner_remove,
702 .command = tuner_command,
703 .id_table = wis_sony_tuner_id,
706 static int __init wis_sony_tuner_init(void)
708 return i2c_add_driver(&wis_sony_tuner_driver);
711 static void __exit wis_sony_tuner_cleanup(void)
713 i2c_del_driver(&wis_sony_tuner_driver);
716 module_init(wis_sony_tuner_init);
717 module_exit(wis_sony_tuner_cleanup);
719 MODULE_LICENSE("GPL v2");