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 17 #include <linux/module.h> 18 #include <linux/init.h> 19 #include <linux/delay.h> 20 #include <linux/types.h> 21 #include <linux/slab.h> 22 #include <linux/uaccess.h> 23 #include <linux/i2c.h> 24 #include <linux/videodev2.h> 25 #include <media/v4l2-device.h> 26 #include <media/v4l2-ctrls.h> 27 28 MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver"); 29 MODULE_AUTHOR("Laurent Pinchart"); 30 MODULE_LICENSE("GPL"); 31 32 static int debug; 33 module_param(debug, int, 0); 34 MODULE_PARM_DESC(debug, "Debug level (0-1)"); 35 36 37 #define VPX_TIMEOUT_COUNT 10 38 39 /* ----------------------------------------------------------------------- */ 40 41 struct vpx3220 { 42 struct v4l2_subdev sd; 43 struct v4l2_ctrl_handler hdl; 44 unsigned char reg[255]; 45 46 v4l2_std_id norm; 47 int input; 48 int enable; 49 }; 50 51 static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd) 52 { 53 return container_of(sd, struct vpx3220, sd); 54 } 55 56 static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) 57 { 58 return &container_of(ctrl->handler, struct vpx3220, hdl)->sd; 59 } 60 61 static char *inputs[] = { "internal", "composite", "svideo" }; 62 63 /* ----------------------------------------------------------------------- */ 64 65 static inline int vpx3220_write(struct v4l2_subdev *sd, u8 reg, u8 value) 66 { 67 struct i2c_client *client = v4l2_get_subdevdata(sd); 68 struct vpx3220 *decoder = i2c_get_clientdata(client); 69 70 decoder->reg[reg] = value; 71 return i2c_smbus_write_byte_data(client, reg, value); 72 } 73 74 static inline int vpx3220_read(struct v4l2_subdev *sd, u8 reg) 75 { 76 struct i2c_client *client = v4l2_get_subdevdata(sd); 77 78 return i2c_smbus_read_byte_data(client, reg); 79 } 80 81 static int vpx3220_fp_status(struct v4l2_subdev *sd) 82 { 83 unsigned char status; 84 unsigned int i; 85 86 for (i = 0; i < VPX_TIMEOUT_COUNT; i++) { 87 status = vpx3220_read(sd, 0x29); 88 89 if (!(status & 4)) 90 return 0; 91 92 udelay(10); 93 94 if (need_resched()) 95 cond_resched(); 96 } 97 98 return -1; 99 } 100 101 static int vpx3220_fp_write(struct v4l2_subdev *sd, u8 fpaddr, u16 data) 102 { 103 struct i2c_client *client = v4l2_get_subdevdata(sd); 104 105 /* Write the 16-bit address to the FPWR register */ 106 if (i2c_smbus_write_word_data(client, 0x27, swab16(fpaddr)) == -1) { 107 v4l2_dbg(1, debug, sd, "%s: failed\n", __func__); 108 return -1; 109 } 110 111 if (vpx3220_fp_status(sd) < 0) 112 return -1; 113 114 /* Write the 16-bit data to the FPDAT register */ 115 if (i2c_smbus_write_word_data(client, 0x28, swab16(data)) == -1) { 116 v4l2_dbg(1, debug, sd, "%s: failed\n", __func__); 117 return -1; 118 } 119 120 return 0; 121 } 122 123 static int vpx3220_fp_read(struct v4l2_subdev *sd, u16 fpaddr) 124 { 125 struct i2c_client *client = v4l2_get_subdevdata(sd); 126 s16 data; 127 128 /* Write the 16-bit address to the FPRD register */ 129 if (i2c_smbus_write_word_data(client, 0x26, swab16(fpaddr)) == -1) { 130 v4l2_dbg(1, debug, sd, "%s: failed\n", __func__); 131 return -1; 132 } 133 134 if (vpx3220_fp_status(sd) < 0) 135 return -1; 136 137 /* Read the 16-bit data from the FPDAT register */ 138 data = i2c_smbus_read_word_data(client, 0x28); 139 if (data == -1) { 140 v4l2_dbg(1, debug, sd, "%s: failed\n", __func__); 141 return -1; 142 } 143 144 return swab16(data); 145 } 146 147 static int vpx3220_write_block(struct v4l2_subdev *sd, const u8 *data, unsigned int len) 148 { 149 u8 reg; 150 int ret = -1; 151 152 while (len >= 2) { 153 reg = *data++; 154 ret = vpx3220_write(sd, reg, *data++); 155 if (ret < 0) 156 break; 157 len -= 2; 158 } 159 160 return ret; 161 } 162 163 static int vpx3220_write_fp_block(struct v4l2_subdev *sd, 164 const u16 *data, unsigned int len) 165 { 166 u8 reg; 167 int ret = 0; 168 169 while (len > 1) { 170 reg = *data++; 171 ret |= vpx3220_fp_write(sd, reg, *data++); 172 len -= 2; 173 } 174 175 return ret; 176 } 177 178 /* ---------------------------------------------------------------------- */ 179 180 static const unsigned short init_ntsc[] = { 181 0x1c, 0x00, /* NTSC tint angle */ 182 0x88, 17, /* Window 1 vertical */ 183 0x89, 240, /* Vertical lines in */ 184 0x8a, 240, /* Vertical lines out */ 185 0x8b, 000, /* Horizontal begin */ 186 0x8c, 640, /* Horizontal length */ 187 0x8d, 640, /* Number of pixels */ 188 0x8f, 0xc00, /* Disable window 2 */ 189 0xf0, 0x73, /* 13.5 MHz transport, Forced 190 * mode, latch windows */ 191 0xf2, 0x13, /* NTSC M, composite input */ 192 0xe7, 0x1e1, /* Enable vertical standard 193 * locking @ 240 lines */ 194 }; 195 196 static const unsigned short init_pal[] = { 197 0x88, 23, /* Window 1 vertical begin */ 198 0x89, 288, /* Vertical lines in (16 lines 199 * skipped by the VFE) */ 200 0x8a, 288, /* Vertical lines out (16 lines 201 * skipped by the VFE) */ 202 0x8b, 16, /* Horizontal begin */ 203 0x8c, 768, /* Horizontal length */ 204 0x8d, 784, /* Number of pixels 205 * Must be >= Horizontal begin + Horizontal length */ 206 0x8f, 0xc00, /* Disable window 2 */ 207 0xf0, 0x77, /* 13.5 MHz transport, Forced 208 * mode, latch windows */ 209 0xf2, 0x3d1, /* PAL B,G,H,I, composite input */ 210 0xe7, 0x241, /* PAL/SECAM set to 288 lines */ 211 }; 212 213 static const unsigned short init_secam[] = { 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, 0x3d5, /* SECAM, composite input */ 227 0xe7, 0x241, /* PAL/SECAM set to 288 lines */ 228 }; 229 230 static const unsigned char init_common[] = { 231 0xf2, 0x00, /* Disable all outputs */ 232 0x33, 0x0d, /* Luma : VIN2, Chroma : CIN 233 * (clamp off) */ 234 0xd8, 0xa8, /* HREF/VREF active high, VREF 235 * pulse = 2, Odd/Even flag */ 236 0x20, 0x03, /* IF compensation 0dB/oct */ 237 0xe0, 0xff, /* Open up all comparators */ 238 0xe1, 0x00, 239 0xe2, 0x7f, 240 0xe3, 0x80, 241 0xe4, 0x7f, 242 0xe5, 0x80, 243 0xe6, 0x00, /* Brightness set to 0 */ 244 0xe7, 0xe0, /* Contrast to 1.0, noise shaping 245 * 10 to 8 2-bit error diffusion */ 246 0xe8, 0xf8, /* YUV422, CbCr binary offset, 247 * ... (p.32) */ 248 0xea, 0x18, /* LLC2 connected, output FIFO 249 * reset with VACTintern */ 250 0xf0, 0x8a, /* Half full level to 10, bus 251 * shuffler [7:0, 23:16, 15:8] */ 252 0xf1, 0x18, /* Single clock, sync mode, no 253 * FE delay, no HLEN counter */ 254 0xf8, 0x12, /* Port A, PIXCLK, HF# & FE# 255 * strength to 2 */ 256 0xf9, 0x24, /* Port B, HREF, VREF, PREF & 257 * ALPHA strength to 4 */ 258 }; 259 260 static const unsigned short init_fp[] = { 261 0x59, 0, 262 0xa0, 2070, /* ACC reference */ 263 0xa3, 0, 264 0xa4, 0, 265 0xa8, 30, 266 0xb2, 768, 267 0xbe, 27, 268 0x58, 0, 269 0x26, 0, 270 0x4b, 0x298, /* PLL gain */ 271 }; 272 273 274 static int vpx3220_init(struct v4l2_subdev *sd, u32 val) 275 { 276 struct vpx3220 *decoder = to_vpx3220(sd); 277 278 vpx3220_write_block(sd, init_common, sizeof(init_common)); 279 vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1); 280 if (decoder->norm & V4L2_STD_NTSC) 281 vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1); 282 else if (decoder->norm & V4L2_STD_PAL) 283 vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1); 284 else if (decoder->norm & V4L2_STD_SECAM) 285 vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1); 286 else 287 vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1); 288 return 0; 289 } 290 291 static int vpx3220_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd) 292 { 293 int res = V4L2_IN_ST_NO_SIGNAL, status; 294 v4l2_std_id std = pstd ? *pstd : V4L2_STD_ALL; 295 296 status = vpx3220_fp_read(sd, 0x0f3); 297 298 v4l2_dbg(1, debug, sd, "status: 0x%04x\n", status); 299 300 if (status < 0) 301 return status; 302 303 if ((status & 0x20) == 0) { 304 res = 0; 305 306 switch (status & 0x18) { 307 case 0x00: 308 case 0x10: 309 case 0x14: 310 case 0x18: 311 std &= V4L2_STD_PAL; 312 break; 313 314 case 0x08: 315 std &= V4L2_STD_SECAM; 316 break; 317 318 case 0x04: 319 case 0x0c: 320 case 0x1c: 321 std &= V4L2_STD_NTSC; 322 break; 323 } 324 } else { 325 std = V4L2_STD_UNKNOWN; 326 } 327 if (pstd) 328 *pstd = std; 329 if (pstatus) 330 *pstatus = res; 331 return 0; 332 } 333 334 static int vpx3220_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) 335 { 336 v4l2_dbg(1, debug, sd, "querystd\n"); 337 return vpx3220_status(sd, NULL, std); 338 } 339 340 static int vpx3220_g_input_status(struct v4l2_subdev *sd, u32 *status) 341 { 342 v4l2_dbg(1, debug, sd, "g_input_status\n"); 343 return vpx3220_status(sd, status, NULL); 344 } 345 346 static int vpx3220_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 347 { 348 struct vpx3220 *decoder = to_vpx3220(sd); 349 int temp_input; 350 351 /* Here we back up the input selection because it gets 352 overwritten when we fill the registers with the 353 chosen video norm */ 354 temp_input = vpx3220_fp_read(sd, 0xf2); 355 356 v4l2_dbg(1, debug, sd, "s_std %llx\n", (unsigned long long)std); 357 if (std & V4L2_STD_NTSC) { 358 vpx3220_write_fp_block(sd, init_ntsc, sizeof(init_ntsc) >> 1); 359 v4l2_dbg(1, debug, sd, "norm switched to NTSC\n"); 360 } else if (std & V4L2_STD_PAL) { 361 vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1); 362 v4l2_dbg(1, debug, sd, "norm switched to PAL\n"); 363 } else if (std & V4L2_STD_SECAM) { 364 vpx3220_write_fp_block(sd, init_secam, sizeof(init_secam) >> 1); 365 v4l2_dbg(1, debug, sd, "norm switched to SECAM\n"); 366 } else { 367 return -EINVAL; 368 } 369 370 decoder->norm = std; 371 372 /* And here we set the backed up video input again */ 373 vpx3220_fp_write(sd, 0xf2, temp_input | 0x0010); 374 udelay(10); 375 return 0; 376 } 377 378 static int vpx3220_s_routing(struct v4l2_subdev *sd, 379 u32 input, u32 output, u32 config) 380 { 381 int data; 382 383 /* RJ: input = 0: ST8 (PCTV) input 384 input = 1: COMPOSITE input 385 input = 2: SVHS input */ 386 387 const int input_vals[3][2] = { 388 {0x0c, 0}, 389 {0x0d, 0}, 390 {0x0e, 1} 391 }; 392 393 if (input > 2) 394 return -EINVAL; 395 396 v4l2_dbg(1, debug, sd, "input switched to %s\n", inputs[input]); 397 398 vpx3220_write(sd, 0x33, input_vals[input][0]); 399 400 data = vpx3220_fp_read(sd, 0xf2) & ~(0x0020); 401 if (data < 0) 402 return data; 403 /* 0x0010 is required to latch the setting */ 404 vpx3220_fp_write(sd, 0xf2, 405 data | (input_vals[input][1] << 5) | 0x0010); 406 407 udelay(10); 408 return 0; 409 } 410 411 static int vpx3220_s_stream(struct v4l2_subdev *sd, int enable) 412 { 413 v4l2_dbg(1, debug, sd, "s_stream %s\n", enable ? "on" : "off"); 414 415 vpx3220_write(sd, 0xf2, (enable ? 0x1b : 0x00)); 416 return 0; 417 } 418 419 static int vpx3220_s_ctrl(struct v4l2_ctrl *ctrl) 420 { 421 struct v4l2_subdev *sd = to_sd(ctrl); 422 423 switch (ctrl->id) { 424 case V4L2_CID_BRIGHTNESS: 425 vpx3220_write(sd, 0xe6, ctrl->val); 426 return 0; 427 case V4L2_CID_CONTRAST: 428 /* Bit 7 and 8 is for noise shaping */ 429 vpx3220_write(sd, 0xe7, ctrl->val + 192); 430 return 0; 431 case V4L2_CID_SATURATION: 432 vpx3220_fp_write(sd, 0xa0, ctrl->val); 433 return 0; 434 case V4L2_CID_HUE: 435 vpx3220_fp_write(sd, 0x1c, ctrl->val); 436 return 0; 437 } 438 return -EINVAL; 439 } 440 441 /* ----------------------------------------------------------------------- */ 442 443 static const struct v4l2_ctrl_ops vpx3220_ctrl_ops = { 444 .s_ctrl = vpx3220_s_ctrl, 445 }; 446 447 static const struct v4l2_subdev_core_ops vpx3220_core_ops = { 448 .init = vpx3220_init, 449 }; 450 451 static const struct v4l2_subdev_video_ops vpx3220_video_ops = { 452 .s_std = vpx3220_s_std, 453 .s_routing = vpx3220_s_routing, 454 .s_stream = vpx3220_s_stream, 455 .querystd = vpx3220_querystd, 456 .g_input_status = vpx3220_g_input_status, 457 }; 458 459 static const struct v4l2_subdev_ops vpx3220_ops = { 460 .core = &vpx3220_core_ops, 461 .video = &vpx3220_video_ops, 462 }; 463 464 /* ----------------------------------------------------------------------- 465 * Client management code 466 */ 467 468 static int vpx3220_probe(struct i2c_client *client, 469 const struct i2c_device_id *id) 470 { 471 struct vpx3220 *decoder; 472 struct v4l2_subdev *sd; 473 const char *name = NULL; 474 u8 ver; 475 u16 pn; 476 477 /* Check if the adapter supports the needed features */ 478 if (!i2c_check_functionality(client->adapter, 479 I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) 480 return -ENODEV; 481 482 decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL); 483 if (decoder == NULL) 484 return -ENOMEM; 485 sd = &decoder->sd; 486 v4l2_i2c_subdev_init(sd, client, &vpx3220_ops); 487 decoder->norm = V4L2_STD_PAL; 488 decoder->input = 0; 489 decoder->enable = 1; 490 v4l2_ctrl_handler_init(&decoder->hdl, 4); 491 v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops, 492 V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); 493 v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops, 494 V4L2_CID_CONTRAST, 0, 63, 1, 32); 495 v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops, 496 V4L2_CID_SATURATION, 0, 4095, 1, 2048); 497 v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops, 498 V4L2_CID_HUE, -512, 511, 1, 0); 499 sd->ctrl_handler = &decoder->hdl; 500 if (decoder->hdl.error) { 501 int err = decoder->hdl.error; 502 503 v4l2_ctrl_handler_free(&decoder->hdl); 504 return err; 505 } 506 v4l2_ctrl_handler_setup(&decoder->hdl); 507 508 ver = i2c_smbus_read_byte_data(client, 0x00); 509 pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) + 510 i2c_smbus_read_byte_data(client, 0x01); 511 if (ver == 0xec) { 512 switch (pn) { 513 case 0x4680: 514 name = "vpx3220a"; 515 break; 516 case 0x4260: 517 name = "vpx3216b"; 518 break; 519 case 0x4280: 520 name = "vpx3214c"; 521 break; 522 } 523 } 524 if (name) 525 v4l2_info(sd, "%s found @ 0x%x (%s)\n", name, 526 client->addr << 1, client->adapter->name); 527 else 528 v4l2_info(sd, "chip (%02x:%04x) found @ 0x%x (%s)\n", 529 ver, pn, client->addr << 1, client->adapter->name); 530 531 vpx3220_write_block(sd, init_common, sizeof(init_common)); 532 vpx3220_write_fp_block(sd, init_fp, sizeof(init_fp) >> 1); 533 /* Default to PAL */ 534 vpx3220_write_fp_block(sd, init_pal, sizeof(init_pal) >> 1); 535 return 0; 536 } 537 538 static int vpx3220_remove(struct i2c_client *client) 539 { 540 struct v4l2_subdev *sd = i2c_get_clientdata(client); 541 struct vpx3220 *decoder = to_vpx3220(sd); 542 543 v4l2_device_unregister_subdev(sd); 544 v4l2_ctrl_handler_free(&decoder->hdl); 545 546 return 0; 547 } 548 549 static const struct i2c_device_id vpx3220_id[] = { 550 { "vpx3220a", 0 }, 551 { "vpx3216b", 0 }, 552 { "vpx3214c", 0 }, 553 { } 554 }; 555 MODULE_DEVICE_TABLE(i2c, vpx3220_id); 556 557 static struct i2c_driver vpx3220_driver = { 558 .driver = { 559 .name = "vpx3220", 560 }, 561 .probe = vpx3220_probe, 562 .remove = vpx3220_remove, 563 .id_table = vpx3220_id, 564 }; 565 566 module_i2c_driver(vpx3220_driver); 567