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 130static struct { 131 enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode; 132 u16 modus; 133 u16 source; 134 u16 acb; 135 u16 fm_prescale; 136 u16 nicam_prescale; 137 u16 scart_prescale; 138 u16 system; 139 u16 volume; 140} mpx_audio_modes[] = { 141 /* Auto */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, 142 0x5000, 0x0000, 0x0001, 0x7500 }, 143 /* B/G Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, 144 0x5000, 0x0000, 0x0003, 0x7500 }, 145 /* B/G A2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, 146 0x5000, 0x0000, 0x0003, 0x7500 }, 147 /* B/G NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, 148 0x5000, 0x0000, 0x0008, 0x7500 }, 149 /* I Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, 150 0x7900, 0x0000, 0x000A, 0x7500 }, 151 /* I NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, 152 0x7900, 0x0000, 0x000A, 0x7500 }, 153 /* D/K Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, 154 0x5000, 0x0000, 0x0004, 0x7500 }, 155 /* D/K A2-1 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, 156 0x5000, 0x0000, 0x0004, 0x7500 }, 157 /* D/K A2-2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, 158 0x5000, 0x0000, 0x0005, 0x7500 }, 159 /* D/K A2-3 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, 160 0x5000, 0x0000, 0x0007, 0x7500 }, 161 /* D/K NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, 162 0x5000, 0x0000, 0x000B, 0x7500 }, 163 /* L/L' Mono */ { AUD_MONO, 0x0003, 0x0200, 0x0100, 0x7C03, 164 0x5000, 0x2200, 0x0009, 0x7500 }, 165 /* L/L' NICAM */{ AUD_NICAM_L, 0x0003, 0x0120, 0x0100, 0x7C03, 166 0x5000, 0x0000, 0x0009, 0x7500 }, 167}; 168 169#define MPX_NUM_MODES ARRAY_SIZE(mpx_audio_modes) 170 171static int mpx_setup(struct i2c_client *client) 172{ 173 struct wis_sony_tuner *t = i2c_get_clientdata(client); 174 u16 source = 0; 175 u8 buffer[3]; 176 struct i2c_msg msg; 177 178 /* reset MPX */ 179 buffer[0] = 0x00; 180 buffer[1] = 0x80; 181 buffer[2] = 0x00; 182 msg.addr = MPX_I2C_ADDR; 183 msg.flags = 0; 184 msg.len = 3; 185 msg.buf = buffer; 186 i2c_transfer(client->adapter, &msg, 1); 187 buffer[1] = 0x00; 188 i2c_transfer(client->adapter, &msg, 1); 189 190 if (mpx_audio_modes[t->mpxmode].audio_mode != AUD_MONO) { 191 switch (t->audmode) { 192 case V4L2_TUNER_MODE_MONO: 193 switch (mpx_audio_modes[t->mpxmode].audio_mode) { 194 case AUD_A2: 195 source = mpx_audio_modes[t->mpxmode].source; 196 break; 197 case AUD_NICAM: 198 source = 0x0000; 199 break; 200 case AUD_NICAM_L: 201 source = 0x0200; 202 break; 203 default: 204 break; 205 } 206 break; 207 case V4L2_TUNER_MODE_STEREO: 208 source = mpx_audio_modes[t->mpxmode].source; 209 break; 210 case V4L2_TUNER_MODE_LANG1: 211 source = 0x0300; 212 break; 213 case V4L2_TUNER_MODE_LANG2: 214 source = 0x0400; 215 break; 216 } 217 source |= mpx_audio_modes[t->mpxmode].source & 0x00ff; 218 } else 219 source = mpx_audio_modes[t->mpxmode].source; 220 221 mpx_write(client, 0x10, 0x0030, mpx_audio_modes[t->mpxmode].modus); 222 mpx_write(client, 0x12, 0x0008, source); 223 mpx_write(client, 0x12, 0x0013, mpx_audio_modes[t->mpxmode].acb); 224 mpx_write(client, 0x12, 0x000e, 225 mpx_audio_modes[t->mpxmode].fm_prescale); 226 mpx_write(client, 0x12, 0x0010, 227 mpx_audio_modes[t->mpxmode].nicam_prescale); 228 mpx_write(client, 0x12, 0x000d, 229 mpx_audio_modes[t->mpxmode].scart_prescale); 230 mpx_write(client, 0x10, 0x0020, mpx_audio_modes[t->mpxmode].system); 231 mpx_write(client, 0x12, 0x0000, mpx_audio_modes[t->mpxmode].volume); 232 if (mpx_audio_modes[t->mpxmode].audio_mode == AUD_A2) 233 mpx_write(client, 0x10, 0x0022, 234 t->audmode == V4L2_TUNER_MODE_MONO ? 0x07f0 : 0x0190); 235 236#ifdef MPX_DEBUG 237 { 238 u8 buf1[3], buf2[2]; 239 struct i2c_msg msgs[2]; 240 241 printk(KERN_DEBUG "wis-sony-tuner: MPX registers: %04x %04x " 242 "%04x %04x %04x %04x %04x %04x\n", 243 mpx_audio_modes[t->mpxmode].modus, 244 source, 245 mpx_audio_modes[t->mpxmode].acb, 246 mpx_audio_modes[t->mpxmode].fm_prescale, 247 mpx_audio_modes[t->mpxmode].nicam_prescale, 248 mpx_audio_modes[t->mpxmode].scart_prescale, 249 mpx_audio_modes[t->mpxmode].system, 250 mpx_audio_modes[t->mpxmode].volume); 251 buf1[0] = 0x11; 252 buf1[1] = 0x00; 253 buf1[2] = 0x7e; 254 msgs[0].addr = MPX_I2C_ADDR; 255 msgs[0].flags = 0; 256 msgs[0].len = 3; 257 msgs[0].buf = buf1; 258 msgs[1].addr = MPX_I2C_ADDR; 259 msgs[1].flags = I2C_M_RD; 260 msgs[1].len = 2; 261 msgs[1].buf = buf2; 262 i2c_transfer(client->adapter, msgs, 2); 263 printk(KERN_DEBUG "wis-sony-tuner: MPX system: %02x%02x\n", 264 buf2[0], buf2[1]); 265 buf1[0] = 0x11; 266 buf1[1] = 0x02; 267 buf1[2] = 0x00; 268 i2c_transfer(client->adapter, msgs, 2); 269 printk(KERN_DEBUG "wis-sony-tuner: MPX status: %02x%02x\n", 270 buf2[0], buf2[1]); 271 } 272#endif 273 return 0; 274} 275 276/* 277 * IF configuration values for the BTF-PG472Z: 278 * 279 * B/G: 0x94 0x70 0x49 280 * I: 0x14 0x70 0x4a 281 * D/K: 0x14 0x70 0x4b 282 * L: 0x04 0x70 0x4b 283 * L': 0x44 0x70 0x53 284 * M: 0x50 0x30 0x4c 285 */ 286 287static int set_if(struct i2c_client *client) 288{ 289 struct wis_sony_tuner *t = i2c_get_clientdata(client); 290 u8 buffer[4]; 291 struct i2c_msg msg; 292 int default_mpx_mode = 0; 293 294 /* configure IF */ 295 buffer[0] = 0; 296 if (t->std & V4L2_STD_PAL_BG) { 297 buffer[1] = 0x94; 298 buffer[2] = 0x70; 299 buffer[3] = 0x49; 300 default_mpx_mode = 1; 301 } else if (t->std & V4L2_STD_PAL_I) { 302 buffer[1] = 0x14; 303 buffer[2] = 0x70; 304 buffer[3] = 0x4a; 305 default_mpx_mode = 4; 306 } else if (t->std & V4L2_STD_PAL_DK) { 307 buffer[1] = 0x14; 308 buffer[2] = 0x70; 309 buffer[3] = 0x4b; 310 default_mpx_mode = 6; 311 } else if (t->std & V4L2_STD_SECAM_L) { 312 buffer[1] = 0x04; 313 buffer[2] = 0x70; 314 buffer[3] = 0x4b; 315 default_mpx_mode = 11; 316 } 317 msg.addr = IF_I2C_ADDR; 318 msg.flags = 0; 319 msg.len = 4; 320 msg.buf = buffer; 321 i2c_transfer(client->adapter, &msg, 1); 322 323 /* Select MPX mode if not forced by the user */ 324 if (force_mpx_mode >= 0 && force_mpx_mode < MPX_NUM_MODES) 325 t->mpxmode = force_mpx_mode; 326 else 327 t->mpxmode = default_mpx_mode; 328 printk(KERN_DEBUG "wis-sony-tuner: setting MPX to mode %d\n", 329 t->mpxmode); 330 mpx_setup(client); 331 332 return 0; 333} 334 335static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) 336{ 337 struct wis_sony_tuner *t = i2c_get_clientdata(client); 338 339 switch (cmd) { 340 case VIDIOC_G_FREQUENCY: 341 { 342 struct v4l2_frequency *f = arg; 343 344 f->frequency = t->freq; 345 break; 346 } 347 case VIDIOC_S_FREQUENCY: 348 { 349 struct v4l2_frequency *f = arg; 350 351 t->freq = f->frequency; 352 set_freq(client, t->freq); 353 break; 354 } 355 case VIDIOC_ENUMSTD: 356 { 357 struct v4l2_standard *std = arg; 358 359 switch (t->type) { 360 case TUNER_SONY_BTF_PG472Z: 361 switch (std->index) { 362 case 0: 363 v4l2_video_std_construct(std, 364 V4L2_STD_PAL_BG, "PAL-B/G"); 365 break; 366 case 1: 367 v4l2_video_std_construct(std, 368 V4L2_STD_PAL_I, "PAL-I"); 369 break; 370 case 2: 371 v4l2_video_std_construct(std, 372 V4L2_STD_PAL_DK, "PAL-D/K"); 373 break; 374 case 3: 375 v4l2_video_std_construct(std, 376 V4L2_STD_SECAM_L, "SECAM-L"); 377 break; 378 default: 379 std->id = 0; /* hack to indicate EINVAL */ 380 break; 381 } 382 break; 383 case TUNER_SONY_BTF_PK467Z: 384 if (std->index != 0) { 385 std->id = 0; /* hack to indicate EINVAL */ 386 break; 387 } 388 v4l2_video_std_construct(std, 389 V4L2_STD_NTSC_M_JP, "NTSC-J"); 390 break; 391 case TUNER_SONY_BTF_PB463Z: 392 if (std->index != 0) { 393 std->id = 0; /* hack to indicate EINVAL */ 394 break; 395 } 396 v4l2_video_std_construct(std, V4L2_STD_NTSC_M, "NTSC"); 397 break; 398 } 399 break; 400 } 401 case VIDIOC_G_STD: 402 { 403 v4l2_std_id *std = arg; 404 405 *std = t->std; 406 break; 407 } 408 case VIDIOC_S_STD: 409 { 410 v4l2_std_id *std = arg; 411 v4l2_std_id old = t->std; 412 413 switch (t->type) { 414 case TUNER_SONY_BTF_PG472Z: 415 if (force_band && (*std & force_band) != *std && 416 *std != V4L2_STD_PAL && 417 *std != V4L2_STD_SECAM) { 418 printk(KERN_DEBUG "wis-sony-tuner: ignoring " 419 "requested TV standard in " 420 "favor of force_band value\n"); 421 t->std = force_band; 422 } else if (*std & V4L2_STD_PAL_BG) { /* default */ 423 t->std = V4L2_STD_PAL_BG; 424 } else if (*std & V4L2_STD_PAL_I) { 425 t->std = V4L2_STD_PAL_I; 426 } else if (*std & V4L2_STD_PAL_DK) { 427 t->std = V4L2_STD_PAL_DK; 428 } else if (*std & V4L2_STD_SECAM_L) { 429 t->std = V4L2_STD_SECAM_L; 430 } else { 431 printk(KERN_ERR "wis-sony-tuner: TV standard " 432 "not supported\n"); 433 *std = 0; /* hack to indicate EINVAL */ 434 break; 435 } 436 if (old != t->std) 437 set_if(client); 438 break; 439 case TUNER_SONY_BTF_PK467Z: 440 if (!(*std & V4L2_STD_NTSC_M_JP)) { 441 printk(KERN_ERR "wis-sony-tuner: TV standard " 442 "not supported\n"); 443 *std = 0; /* hack to indicate EINVAL */ 444 } 445 break; 446 case TUNER_SONY_BTF_PB463Z: 447 if (!(*std & V4L2_STD_NTSC_M)) { 448 printk(KERN_ERR "wis-sony-tuner: TV standard " 449 "not supported\n"); 450 *std = 0; /* hack to indicate EINVAL */ 451 } 452 break; 453 } 454 break; 455 } 456 case VIDIOC_QUERYSTD: 457 { 458 v4l2_std_id *std = arg; 459 460 switch (t->type) { 461 case TUNER_SONY_BTF_PG472Z: 462 if (force_band) 463 *std = force_band; 464 else 465 *std = V4L2_STD_PAL_BG | V4L2_STD_PAL_I | 466 V4L2_STD_PAL_DK | V4L2_STD_SECAM_L; 467 break; 468 case TUNER_SONY_BTF_PK467Z: 469 *std = V4L2_STD_NTSC_M_JP; 470 break; 471 case TUNER_SONY_BTF_PB463Z: 472 *std = V4L2_STD_NTSC_M; 473 break; 474 } 475 break; 476 } 477 case VIDIOC_G_TUNER: 478 { 479 struct v4l2_tuner *tun = arg; 480 481 memset(tun, 0, sizeof(*tun)); 482 strcpy(tun->name, "Television"); 483 tun->type = V4L2_TUNER_ANALOG_TV; 484 tun->rangelow = 0UL; /* does anything use these? */ 485 tun->rangehigh = 0xffffffffUL; 486 switch (t->type) { 487 case TUNER_SONY_BTF_PG472Z: 488 tun->capability = V4L2_TUNER_CAP_NORM | 489 V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | 490 V4L2_TUNER_CAP_LANG2; 491 tun->rxsubchans = V4L2_TUNER_SUB_MONO | 492 V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 | 493 V4L2_TUNER_SUB_LANG2; 494 break; 495 case TUNER_SONY_BTF_PK467Z: 496 case TUNER_SONY_BTF_PB463Z: 497 tun->capability = V4L2_TUNER_CAP_STEREO; 498 tun->rxsubchans = V4L2_TUNER_SUB_MONO | 499 V4L2_TUNER_SUB_STEREO; 500 break; 501 } 502 tun->audmode = t->audmode; 503 return 0; 504 } 505 case VIDIOC_S_TUNER: 506 { 507 struct v4l2_tuner *tun = arg; 508 509 switch (t->type) { 510 case TUNER_SONY_BTF_PG472Z: 511 if (tun->audmode != t->audmode) { 512 t->audmode = tun->audmode; 513 mpx_setup(client); 514 } 515 break; 516 case TUNER_SONY_BTF_PK467Z: 517 case TUNER_SONY_BTF_PB463Z: 518 break; 519 } 520 return 0; 521 } 522 default: 523 break; 524 } 525 return 0; 526} 527 528static int wis_sony_tuner_probe(struct i2c_client *client, 529 const struct i2c_device_id *id) 530{ 531 struct i2c_adapter *adapter = client->adapter; 532 struct wis_sony_tuner *t; 533 534 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) 535 return -ENODEV; 536 537 t = kmalloc(sizeof(struct wis_sony_tuner), GFP_KERNEL); 538 if (t == NULL) 539 return -ENOMEM; 540 541 t->type = -1; 542 t->freq = 0; 543 t->mpxmode = 0; 544 t->audmode = V4L2_TUNER_MODE_STEREO; 545 i2c_set_clientdata(client, t); 546 547 printk(KERN_DEBUG 548 "wis-sony-tuner: initializing tuner at address %d on %s\n", 549 client->addr, adapter->name); 550 551 return 0; 552} 553 554static int wis_sony_tuner_remove(struct i2c_client *client) 555{ 556 struct wis_sony_tuner *t = i2c_get_clientdata(client); 557 558 kfree(t); 559 return 0; 560} 561 562static const struct i2c_device_id wis_sony_tuner_id[] = { 563 { "wis_sony_tuner", 0 }, 564 { } 565}; 566 567static struct i2c_driver wis_sony_tuner_driver = { 568 .driver = { 569 .name = "WIS Sony TV Tuner I2C driver", 570 }, 571 .probe = wis_sony_tuner_probe, 572 .remove = wis_sony_tuner_remove, 573 .command = tuner_command, 574 .id_table = wis_sony_tuner_id, 575}; 576 577static int __init wis_sony_tuner_init(void) 578{ 579 return i2c_add_driver(&wis_sony_tuner_driver); 580} 581 582static void __exit wis_sony_tuner_cleanup(void) 583{ 584 i2c_del_driver(&wis_sony_tuner_driver); 585} 586 587module_init(wis_sony_tuner_init); 588module_exit(wis_sony_tuner_cleanup); 589 590MODULE_LICENSE("GPL v2"); 591