1/* 2 * vpx3220a, vpx3216b & vpx3214c video decoder driver version 0.0.1 3 * 4 * Copyright (C) 2001 Laurent Pinchart <lpinchart@freegates.be> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 21#include <linux/module.h> 22#include <linux/init.h> 23#include <linux/delay.h> 24#include <linux/types.h> 25#include <linux/slab.h> 26 27#include <linux/byteorder/swab.h> 28 29#include <asm/io.h> 30#include <asm/uaccess.h> 31 32#include <linux/i2c.h> 33 34#define I2C_NAME(x) (x)->name 35 36#include <linux/videodev.h> 37#include <media/v4l2-common.h> 38#include <linux/video_decoder.h> 39 40#define I2C_VPX3220 0x86 41#define VPX3220_DEBUG KERN_DEBUG "vpx3220: " 42 43static int debug = 0; 44module_param(debug, int, 0); 45MODULE_PARM_DESC(debug, "Debug level (0-1)"); 46 47#define dprintk(num, format, args...) \ 48 do { \ 49 if (debug >= num) \ 50 printk(format, ##args); \ 51 } while (0) 52 53#define VPX_TIMEOUT_COUNT 10 54 55/* ----------------------------------------------------------------------- */ 56 57struct vpx3220 { 58 unsigned char reg[255]; 59 60 int norm; 61 int input; 62 int enable; 63 int bright; 64 int contrast; 65 int hue; 66 int sat; 67}; 68 69static char *inputs[] = { "internal", "composite", "svideo" }; 70 71/* ----------------------------------------------------------------------- */ 72static inline int 73vpx3220_write (struct i2c_client *client, 74 u8 reg, 75 u8 value) 76{ 77 struct vpx3220 *decoder = i2c_get_clientdata(client); 78 79 decoder->reg[reg] = value; 80 return i2c_smbus_write_byte_data(client, reg, value); 81} 82 83static inline int 84vpx3220_read (struct i2c_client *client, 85 u8 reg) 86{ 87 return i2c_smbus_read_byte_data(client, reg); 88} 89 90static int 91vpx3220_fp_status (struct i2c_client *client) 92{ 93 unsigned char status; 94 unsigned int i; 95 96 for (i = 0; i < VPX_TIMEOUT_COUNT; i++) { 97 status = vpx3220_read(client, 0x29); 98 99 if (!(status & 4)) 100 return 0; 101 102 udelay(10); 103 104 if (need_resched()) 105 cond_resched(); 106 } 107 108 return -1; 109} 110 111static int 112vpx3220_fp_write (struct i2c_client *client, 113 u8 fpaddr, 114 u16 data) 115{ 116 /* Write the 16-bit address to the FPWR register */ 117 if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) { 118 dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__); 119 return -1; 120 } 121 122 if (vpx3220_fp_status(client) < 0) 123 return -1; 124 125 /* Write the 16-bit data to the FPDAT register */ 126 if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) { 127 dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__); 128 return -1; 129 } 130 131 return 0; 132} 133 134static u16 135vpx3220_fp_read (struct i2c_client *client, 136 u16 fpaddr) 137{ 138 s16 data; 139 140 /* Write the 16-bit address to the FPRD register */ 141 if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) { 142 dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__); 143 return -1; 144 } 145 146 if (vpx3220_fp_status(client) < 0) 147 return -1; 148 149 /* Read the 16-bit data from the FPDAT register */ 150 data = i2c_smbus_read_word_data(client, 0x28); 151 if (data == -1) { 152 dprintk(1, VPX3220_DEBUG "%s: failed\n", __func__); 153 return -1; 154 } 155 156 return swab16(data); 157} 158 159static int 160vpx3220_write_block (struct i2c_client *client, 161 const u8 *data, 162 unsigned int len) 163{ 164 u8 reg; 165 int ret = -1; 166 167 while (len >= 2) { 168 reg = *data++; 169 if ((ret = 170 vpx3220_write(client, reg, *data++)) < 0) 171 break; 172 len -= 2; 173 } 174 175 return ret; 176} 177 178static int 179vpx3220_write_fp_block (struct i2c_client *client, 180 const u16 *data, 181 unsigned int len) 182{ 183 u8 reg; 184 int ret = 0; 185 186 while (len > 1) { 187 reg = *data++; 188 ret |= vpx3220_fp_write(client, reg, *data++); 189 len -= 2; 190 } 191 192 return ret; 193} 194 195/* ---------------------------------------------------------------------- */ 196 197static const unsigned short init_ntsc[] = { 198 0x1c, 0x00, /* NTSC tint angle */ 199 0x88, 17, /* Window 1 vertical */ 200 0x89, 240, /* Vertical lines in */ 201 0x8a, 240, /* Vertical lines out */ 202 0x8b, 000, /* Horizontal begin */ 203 0x8c, 640, /* Horizontal length */ 204 0x8d, 640, /* Number of pixels */ 205 0x8f, 0xc00, /* Disable window 2 */ 206 0xf0, 0x73, /* 13.5 MHz transport, Forced 207 * mode, latch windows */ 208 0xf2, 0x13, /* NTSC M, composite input */ 209 0xe7, 0x1e1, /* Enable vertical standard 210 * locking @ 240 lines */ 211}; 212 213static const unsigned short init_pal[] = { 214 0x88, 23, /* Window 1 vertical begin */ 215 0x89, 288, /* Vertical lines in (16 lines 216 * skipped by the VFE) */ 217 0x8a, 288, /* Vertical lines out (16 lines 218 * skipped by the VFE) */ 219 0x8b, 16, /* Horizontal begin */ 220 0x8c, 768, /* Horizontal length */ 221 0x8d, 784, /* Number of pixels 222 * Must be >= Horizontal begin + Horizontal length */ 223 0x8f, 0xc00, /* Disable window 2 */ 224 0xf0, 0x77, /* 13.5 MHz transport, Forced 225 * mode, latch windows */ 226 0xf2, 0x3d1, /* PAL B,G,H,I, composite input */ 227 0xe7, 0x241, /* PAL/SECAM set to 288 lines */ 228}; 229 230static const unsigned short init_secam[] = { 231 0x88, 23, /* Window 1 vertical begin */ 232 0x89, 288, /* Vertical lines in (16 lines 233 * skipped by the VFE) */ 234 0x8a, 288, /* Vertical lines out (16 lines 235 * skipped by the VFE) */ 236 0x8b, 16, /* Horizontal begin */ 237 0x8c, 768, /* Horizontal length */ 238 0x8d, 784, /* Number of pixels 239 * Must be >= Horizontal begin + Horizontal length */ 240 0x8f, 0xc00, /* Disable window 2 */ 241 0xf0, 0x77, /* 13.5 MHz transport, Forced 242 * mode, latch windows */ 243 0xf2, 0x3d5, /* SECAM, composite input */ 244 0xe7, 0x241, /* PAL/SECAM set to 288 lines */ 245}; 246 247static const unsigned char init_common[] = { 248 0xf2, 0x00, /* Disable all outputs */ 249 0x33, 0x0d, /* Luma : VIN2, Chroma : CIN 250 * (clamp off) */ 251 0xd8, 0xa8, /* HREF/VREF active high, VREF 252 * pulse = 2, Odd/Even flag */ 253 0x20, 0x03, /* IF compensation 0dB/oct */ 254 0xe0, 0xff, /* Open up all comparators */ 255 0xe1, 0x00, 256 0xe2, 0x7f, 257 0xe3, 0x80, 258 0xe4, 0x7f, 259 0xe5, 0x80, 260 0xe6, 0x00, /* Brightness set to 0 */ 261 0xe7, 0xe0, /* Contrast to 1.0, noise shaping 262 * 10 to 8 2-bit error diffusion */ 263 0xe8, 0xf8, /* YUV422, CbCr binary offset, 264 * ... (p.32) */ 265 0xea, 0x18, /* LLC2 connected, output FIFO 266 * reset with VACTintern */ 267 0xf0, 0x8a, /* Half full level to 10, bus 268 * shuffler [7:0, 23:16, 15:8] */ 269 0xf1, 0x18, /* Single clock, sync mode, no 270 * FE delay, no HLEN counter */ 271 0xf8, 0x12, /* Port A, PIXCLK, HF# & FE# 272 * strength to 2 */ 273 0xf9, 0x24, /* Port B, HREF, VREF, PREF & 274 * ALPHA strength to 4 */ 275}; 276 277static const unsigned short init_fp[] = { 278 0x59, 0, 279 0xa0, 2070, /* ACC reference */ 280 0xa3, 0, 281 0xa4, 0, 282 0xa8, 30, 283 0xb2, 768, 284 0xbe, 27, 285 0x58, 0, 286 0x26, 0, 287 0x4b, 0x298, /* PLL gain */ 288}; 289 290static void 291vpx3220_dump_i2c (struct i2c_client *client) 292{ 293 int len = sizeof(init_common); 294 const unsigned char *data = init_common; 295 296 while (len > 1) { 297 dprintk(1, 298 KERN_DEBUG "vpx3216b i2c reg 0x%02x data 0x%02x\n", 299 *data, vpx3220_read(client, *data)); 300 data += 2; 301 len -= 2; 302 } 303} 304 305static int 306vpx3220_command (struct i2c_client *client, 307 unsigned int cmd, 308 void *arg) 309{ 310 struct vpx3220 *decoder = i2c_get_clientdata(client); 311 312 switch (cmd) { 313 case 0: 314 { 315 vpx3220_write_block(client, init_common, 316 sizeof(init_common)); 317 vpx3220_write_fp_block(client, init_fp, 318 sizeof(init_fp) >> 1); 319 switch (decoder->norm) { 320 321 case VIDEO_MODE_NTSC: 322 vpx3220_write_fp_block(client, init_ntsc, 323 sizeof(init_ntsc) >> 1); 324 break; 325 326 case VIDEO_MODE_PAL: 327 vpx3220_write_fp_block(client, init_pal, 328 sizeof(init_pal) >> 1); 329 break; 330 case VIDEO_MODE_SECAM: 331 vpx3220_write_fp_block(client, init_secam, 332 sizeof(init_secam) >> 1); 333 break; 334 default: 335 vpx3220_write_fp_block(client, init_pal, 336 sizeof(init_pal) >> 1); 337 break; 338 } 339 } 340 break; 341 342 case DECODER_DUMP: 343 { 344 vpx3220_dump_i2c(client); 345 } 346 break; 347 348 case DECODER_GET_CAPABILITIES: 349 { 350 struct video_decoder_capability *cap = arg; 351 352 dprintk(1, KERN_DEBUG "%s: DECODER_GET_CAPABILITIES\n", 353 I2C_NAME(client)); 354 355 cap->flags = VIDEO_DECODER_PAL | 356 VIDEO_DECODER_NTSC | 357 VIDEO_DECODER_SECAM | 358 VIDEO_DECODER_AUTO | 359 VIDEO_DECODER_CCIR; 360 cap->inputs = 3; 361 cap->outputs = 1; 362 } 363 break; 364 365 case DECODER_GET_STATUS: 366 { 367 int res = 0, status; 368 369 dprintk(1, KERN_INFO "%s: DECODER_GET_STATUS\n", 370 I2C_NAME(client)); 371 372 status = vpx3220_fp_read(client, 0x0f3); 373 374 dprintk(1, KERN_INFO "%s: status: 0x%04x\n", I2C_NAME(client), 375 status); 376 377 if (status < 0) 378 return status; 379 380 if ((status & 0x20) == 0) { 381 res |= DECODER_STATUS_GOOD | DECODER_STATUS_COLOR; 382 383 switch (status & 0x18) { 384 385 case 0x00: 386 case 0x10: 387 case 0x14: 388 case 0x18: 389 res |= DECODER_STATUS_PAL; 390 break; 391 392 case 0x08: 393 res |= DECODER_STATUS_SECAM; 394 break; 395 396 case 0x04: 397 case 0x0c: 398 case 0x1c: 399 res |= DECODER_STATUS_NTSC; 400 break; 401 } 402 } 403 404 *(int *) arg = res; 405 } 406 break; 407 408 case DECODER_SET_NORM: 409 { 410 int *iarg = arg, data; 411 int temp_input; 412 413 /* Here we back up the input selection because it gets 414 overwritten when we fill the registers with the 415 choosen video norm */ 416 temp_input = vpx3220_fp_read(client, 0xf2); 417 418 dprintk(1, KERN_DEBUG "%s: DECODER_SET_NORM %d\n", 419 I2C_NAME(client), *iarg); 420 switch (*iarg) { 421 422 case VIDEO_MODE_NTSC: 423 vpx3220_write_fp_block(client, init_ntsc, 424 sizeof(init_ntsc) >> 1); 425 dprintk(1, KERN_INFO "%s: norm switched to NTSC\n", 426 I2C_NAME(client)); 427 break; 428 429 case VIDEO_MODE_PAL: 430 vpx3220_write_fp_block(client, init_pal, 431 sizeof(init_pal) >> 1); 432 dprintk(1, KERN_INFO "%s: norm switched to PAL\n", 433 I2C_NAME(client)); 434 break; 435 436 case VIDEO_MODE_SECAM: 437 vpx3220_write_fp_block(client, init_secam, 438 sizeof(init_secam) >> 1); 439 dprintk(1, KERN_INFO "%s: norm switched to SECAM\n", 440 I2C_NAME(client)); 441 break; 442 443 case VIDEO_MODE_AUTO: 444 data = vpx3220_fp_read(client, 0xf2) & 0x20; 445 vpx3220_fp_write(client, 0xf2, 0x00c0 | data); 446 dprintk(1, KERN_INFO "%s: norm switched to Auto\n", 447 I2C_NAME(client)); 448 break; 449 450 default: 451 return -EINVAL; 452 453 } 454 decoder->norm = *iarg; 455 456 /* And here we set the backed up video input again */ 457 vpx3220_fp_write(client, 0xf2, temp_input | 0x0010); 458 udelay(10); 459 } 460 break; 461 462 case DECODER_SET_INPUT: 463 { 464 int *iarg = arg, data; 465 466 /* RJ: *iarg = 0: ST8 (PCTV) input 467 *iarg = 1: COMPOSITE input 468 *iarg = 2: SVHS input */ 469 470 const int input[3][2] = { 471 {0x0c, 0}, 472 {0x0d, 0}, 473 {0x0e, 1} 474 }; 475 476 if (*iarg < 0 || *iarg > 2) 477 return -EINVAL; 478 479 dprintk(1, KERN_INFO "%s: input switched to %s\n", 480 I2C_NAME(client), inputs[*iarg]); 481 482 vpx3220_write(client, 0x33, input[*iarg][0]); 483 484 data = vpx3220_fp_read(client, 0xf2) & ~(0x0020); 485 if (data < 0) 486 return data; 487 /* 0x0010 is required to latch the setting */ 488 vpx3220_fp_write(client, 0xf2, 489 data | (input[*iarg][1] << 5) | 0x0010); 490 491 udelay(10); 492 } 493 break; 494 495 case DECODER_SET_OUTPUT: 496 { 497 int *iarg = arg; 498 499 /* not much choice of outputs */ 500 if (*iarg != 0) { 501 return -EINVAL; 502 } 503 } 504 break; 505 506 case DECODER_ENABLE_OUTPUT: 507 { 508 int *iarg = arg; 509 510 dprintk(1, KERN_DEBUG "%s: DECODER_ENABLE_OUTPUT %d\n", 511 I2C_NAME(client), *iarg); 512 513 vpx3220_write(client, 0xf2, (*iarg ? 0x1b : 0x00)); 514 } 515 break; 516 517 case DECODER_SET_PICTURE: 518 { 519 struct video_picture *pic = arg; 520 521 if (decoder->bright != pic->brightness) { 522 /* We want -128 to 128 we get 0-65535 */ 523 decoder->bright = pic->brightness; 524 vpx3220_write(client, 0xe6, 525 (decoder->bright - 32768) >> 8); 526 } 527 if (decoder->contrast != pic->contrast) { 528 /* We want 0 to 64 we get 0-65535 */ 529 /* Bit 7 and 8 is for noise shaping */ 530 decoder->contrast = pic->contrast; 531 vpx3220_write(client, 0xe7, 532 (decoder->contrast >> 10) + 192); 533 } 534 if (decoder->sat != pic->colour) { 535 /* We want 0 to 4096 we get 0-65535 */ 536 decoder->sat = pic->colour; 537 vpx3220_fp_write(client, 0xa0, 538 decoder->sat >> 4); 539 } 540 if (decoder->hue != pic->hue) { 541 /* We want -512 to 512 we get 0-65535 */ 542 decoder->hue = pic->hue; 543 vpx3220_fp_write(client, 0x1c, 544 ((decoder->hue - 32768) >> 6) & 0xFFF); 545 } 546 } 547 break; 548 549 default: 550 return -EINVAL; 551 } 552 553 return 0; 554} 555 556static int 557vpx3220_init_client (struct i2c_client *client) 558{ 559 vpx3220_write_block(client, init_common, sizeof(init_common)); 560 vpx3220_write_fp_block(client, init_fp, sizeof(init_fp) >> 1); 561 /* Default to PAL */ 562 vpx3220_write_fp_block(client, init_pal, sizeof(init_pal) >> 1); 563 564 return 0; 565} 566 567/* ----------------------------------------------------------------------- 568 * Client managment code 569 */ 570 571/* 572 * Generic i2c probe 573 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' 574 */ 575static unsigned short normal_i2c[] = 576 { I2C_VPX3220 >> 1, (I2C_VPX3220 >> 1) + 4, 577 I2C_CLIENT_END 578}; 579 580static unsigned short ignore = I2C_CLIENT_END; 581 582static struct i2c_client_address_data addr_data = { 583 .normal_i2c = normal_i2c, 584 .probe = &ignore, 585 .ignore = &ignore, 586}; 587 588static struct i2c_driver vpx3220_i2c_driver; 589 590static int 591vpx3220_detach_client (struct i2c_client *client) 592{ 593 struct vpx3220 *decoder = i2c_get_clientdata(client); 594 int err; 595 596 err = i2c_detach_client(client); 597 if (err) { 598 return err; 599 } 600 601 kfree(decoder); 602 kfree(client); 603 604 return 0; 605} 606 607static int 608vpx3220_detect_client (struct i2c_adapter *adapter, 609 int address, 610 int kind) 611{ 612 int err; 613 struct i2c_client *client; 614 struct vpx3220 *decoder; 615 616 dprintk(1, VPX3220_DEBUG "%s\n", __func__); 617 618 /* Check if the adapter supports the needed features */ 619 if (!i2c_check_functionality 620 (adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) 621 return 0; 622 623 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); 624 if (client == NULL) { 625 return -ENOMEM; 626 } 627 628 client->addr = address; 629 client->adapter = adapter; 630 client->driver = &vpx3220_i2c_driver; 631 632 /* Check for manufacture ID and part number */ 633 if (kind < 0) { 634 u8 id; 635 u16 pn; 636 637 id = vpx3220_read(client, 0x00); 638 if (id != 0xec) { 639 dprintk(1, 640 KERN_INFO 641 "vpx3220_attach: Wrong manufacturer ID (0x%02x)\n", 642 id); 643 kfree(client); 644 return 0; 645 } 646 647 pn = (vpx3220_read(client, 0x02) << 8) + 648 vpx3220_read(client, 0x01); 649 switch (pn) { 650 case 0x4680: 651 strlcpy(I2C_NAME(client), "vpx3220a", 652 sizeof(I2C_NAME(client))); 653 break; 654 case 0x4260: 655 strlcpy(I2C_NAME(client), "vpx3216b", 656 sizeof(I2C_NAME(client))); 657 break; 658 case 0x4280: 659 strlcpy(I2C_NAME(client), "vpx3214c", 660 sizeof(I2C_NAME(client))); 661 break; 662 default: 663 dprintk(1, 664 KERN_INFO 665 "%s: Wrong part number (0x%04x)\n", 666 __func__, pn); 667 kfree(client); 668 return 0; 669 } 670 } else { 671 strlcpy(I2C_NAME(client), "forced vpx32xx", 672 sizeof(I2C_NAME(client))); 673 } 674 675 decoder = kzalloc(sizeof(struct vpx3220), GFP_KERNEL); 676 if (decoder == NULL) { 677 kfree(client); 678 return -ENOMEM; 679 } 680 decoder->norm = VIDEO_MODE_PAL; 681 decoder->input = 0; 682 decoder->enable = 1; 683 decoder->bright = 32768; 684 decoder->contrast = 32768; 685 decoder->hue = 32768; 686 decoder->sat = 32768; 687 i2c_set_clientdata(client, decoder); 688 689 err = i2c_attach_client(client); 690 if (err) { 691 kfree(client); 692 kfree(decoder); 693 return err; 694 } 695 696 dprintk(1, KERN_INFO "%s: vpx32xx client found at address 0x%02x\n", 697 I2C_NAME(client), client->addr << 1); 698 699 vpx3220_init_client(client); 700 701 return 0; 702} 703 704static int 705vpx3220_attach_adapter (struct i2c_adapter *adapter) 706{ 707 int ret; 708 709 ret = i2c_probe(adapter, &addr_data, &vpx3220_detect_client); 710 dprintk(1, VPX3220_DEBUG "%s: i2c_probe returned %d\n", 711 __func__, ret); 712 return ret; 713} 714 715/* ----------------------------------------------------------------------- 716 * Driver initialization and cleanup code 717 */ 718 719static struct i2c_driver vpx3220_i2c_driver = { 720 .driver = { 721 .name = "vpx3220", 722 }, 723 724 .id = I2C_DRIVERID_VPX3220, 725 726 .attach_adapter = vpx3220_attach_adapter, 727 .detach_client = vpx3220_detach_client, 728 .command = vpx3220_command, 729}; 730 731static int __init 732vpx3220_init (void) 733{ 734 return i2c_add_driver(&vpx3220_i2c_driver); 735} 736 737static void __exit 738vpx3220_cleanup (void) 739{ 740 i2c_del_driver(&vpx3220_i2c_driver); 741} 742 743module_init(vpx3220_init); 744module_exit(vpx3220_cleanup); 745 746MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver"); 747MODULE_AUTHOR("Laurent Pinchart"); 748MODULE_LICENSE("GPL"); 749