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 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/* Store tuner info in the same format as tuner.c, so maybe we can put the 44 * Sony tuner support in there. */ 45struct 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) */ 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/* Basically the same as default_set_tv_freq() in tuner.c */ 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 * 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 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 /* 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 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 /* 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 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 /* 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 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; /* 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 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