bonding: fix rx_handler locking
[linux/fpc-iii.git] / drivers / staging / go7007 / wis-sony-tuner.c
blob8f1b7d4f6a2e976504a849c262d462b0916a2b49
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 <linux/slab.h>
23 #include <media/tuner.h>
24 #include <media/v4l2-common.h>
25 #include <media/v4l2-ioctl.h>
27 #include "wis-i2c.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 {
46 char *name;
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 */
52 unsigned char VHF_L;
53 unsigned char VHF_H;
54 unsigned char UHF;
55 unsigned char config;
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 {
70 int type;
71 v4l2_std_id std;
72 unsigned int freq;
73 int mpxmode;
74 u32 audmode;
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);
81 char *band_name;
82 int n;
83 int band_select;
84 struct sony_tunertype *tun;
85 u8 buffer[4];
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;
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;
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);
108 return 0;
111 static int mpx_write(struct i2c_client *client, int dev, int addr, int val)
113 u8 buffer[5];
114 struct i2c_msg msg;
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;
130 * MPX register values for the BTF-PG472Z:
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
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
144 * Mono 1003 0020 0100 2603 7900 XXXX 000A 7500
145 * NICAM 1003 0120 0100 2603 7900 XXXX 000A 7500
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
154 * L/L'
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
166 * 0x01 MAIN SUB
167 * 0x03 MAIN MAIN
168 * 0x04 SUB SUB
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:
173 * FMONO_A2
174 * 10/0022
175 * --------
176 * Forced mono ON 07F0
177 * Forced mono OFF 0190
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 },
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);
224 u16 source = 0;
225 u8 buffer[3];
226 struct i2c_msg msg;
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);
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;
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;
267 source |= mpx_audio_modes[t->mpxmode].source & 0x00ff;
268 } else
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);
286 #ifdef MPX_DEBUG
288 u8 buf1[3], buf2[2];
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,
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]);
322 #endif
323 return 0;
327 * IF configuration values for the BTF-PG472Z:
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
337 static int set_if(struct i2c_client *client)
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;
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;
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);
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);
382 return 0;
385 static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
387 struct wis_sony_tuner *t = i2c_get_clientdata(client);
389 switch (cmd) {
390 #if 0
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;
396 #else
397 case TUNER_SET_TYPE:
399 int *type = arg;
400 #endif
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;
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;
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;
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;
468 #endif
469 case VIDIOC_G_FREQUENCY:
471 struct v4l2_frequency *f = arg;
473 f->frequency = t->freq;
474 break;
476 case VIDIOC_S_FREQUENCY:
478 struct v4l2_frequency *f = arg;
480 t->freq = f->frequency;
481 set_freq(client, t->freq);
482 break;
484 case VIDIOC_ENUMSTD:
486 struct v4l2_standard *std = arg;
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;
511 break;
512 case TUNER_SONY_BTF_PK467Z:
513 if (std->index != 0) {
514 std->id = 0; /* hack to indicate EINVAL */
515 break;
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;
525 v4l2_video_std_construct(std, V4L2_STD_NTSC_M, "NTSC");
526 break;
528 break;
530 case VIDIOC_G_STD:
532 v4l2_std_id *std = arg;
534 *std = t->std;
535 break;
537 case VIDIOC_S_STD:
539 v4l2_std_id *std = arg;
540 v4l2_std_id old = t->std;
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;
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 */
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 */
581 break;
583 break;
585 case VIDIOC_QUERYSTD:
587 v4l2_std_id *std = arg;
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;
604 break;
606 case VIDIOC_G_TUNER:
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;
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;
631 tun->audmode = t->audmode;
632 return 0;
634 case VIDIOC_S_TUNER:
636 struct v4l2_tuner *tun = arg;
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);
644 break;
645 case TUNER_SONY_BTF_PK467Z:
646 case TUNER_SONY_BTF_PB463Z:
647 break;
649 return 0;
651 default:
652 break;
654 return 0;
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))
664 return -ENODEV;
666 t = kmalloc(sizeof(struct wis_sony_tuner), GFP_KERNEL);
667 if (t == NULL)
668 return -ENOMEM;
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);
676 printk(KERN_DEBUG
677 "wis-sony-tuner: initializing tuner at address %d on %s\n",
678 client->addr, adapter->name);
680 return 0;
683 static int wis_sony_tuner_remove(struct i2c_client *client)
685 struct wis_sony_tuner *t = i2c_get_clientdata(client);
687 kfree(t);
688 return 0;
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 = {
698 .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");