diff options
-rw-r--r-- | drivers/media/video/ks0127.c | 646 | ||||
-rw-r--r-- | include/media/v4l2-chip-ident.h | 5 |
2 files changed, 315 insertions, 336 deletions
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c index c97d55a43c07..9ae94484da64 100644 --- a/drivers/media/video/ks0127.c +++ b/drivers/media/video/ks0127.c | |||
@@ -39,8 +39,9 @@ | |||
39 | #include <linux/errno.h> | 39 | #include <linux/errno.h> |
40 | #include <linux/kernel.h> | 40 | #include <linux/kernel.h> |
41 | #include <linux/i2c.h> | 41 | #include <linux/i2c.h> |
42 | #include <linux/video_decoder.h> | 42 | #include <linux/videodev2.h> |
43 | #include <media/v4l2-common.h> | 43 | #include <media/v4l2-device.h> |
44 | #include <media/v4l2-chip-ident.h> | ||
44 | #include <media/v4l2-i2c-drv-legacy.h> | 45 | #include <media/v4l2-i2c-drv-legacy.h> |
45 | #include "ks0127.h" | 46 | #include "ks0127.h" |
46 | 47 | ||
@@ -48,10 +49,17 @@ MODULE_DESCRIPTION("KS0127 video decoder driver"); | |||
48 | MODULE_AUTHOR("Ryan Drake"); | 49 | MODULE_AUTHOR("Ryan Drake"); |
49 | MODULE_LICENSE("GPL"); | 50 | MODULE_LICENSE("GPL"); |
50 | 51 | ||
51 | #define KS_TYPE_UNKNOWN 0 | 52 | /* Addresses to scan */ |
52 | #define KS_TYPE_0122S 1 | 53 | #define I2C_KS0127_ADDON 0xD8 |
53 | #define KS_TYPE_0127 2 | 54 | #define I2C_KS0127_ONBOARD 0xDA |
54 | #define KS_TYPE_0127B 3 | 55 | |
56 | static unsigned short normal_i2c[] = { | ||
57 | I2C_KS0127_ADDON >> 1, | ||
58 | I2C_KS0127_ONBOARD >> 1, | ||
59 | I2C_CLIENT_END | ||
60 | }; | ||
61 | |||
62 | I2C_CLIENT_INSMOD; | ||
55 | 63 | ||
56 | /* ks0127 control registers */ | 64 | /* ks0127 control registers */ |
57 | #define KS_STAT 0x00 | 65 | #define KS_STAT 0x00 |
@@ -197,15 +205,17 @@ struct adjust { | |||
197 | }; | 205 | }; |
198 | 206 | ||
199 | struct ks0127 { | 207 | struct ks0127 { |
200 | int format_width; | 208 | struct v4l2_subdev sd; |
201 | int format_height; | ||
202 | int cap_width; | ||
203 | int cap_height; | ||
204 | v4l2_std_id norm; | 209 | v4l2_std_id norm; |
205 | int ks_type; | 210 | int ident; |
206 | u8 regs[256]; | 211 | u8 regs[256]; |
207 | }; | 212 | }; |
208 | 213 | ||
214 | static inline struct ks0127 *to_ks0127(struct v4l2_subdev *sd) | ||
215 | { | ||
216 | return container_of(sd, struct ks0127, sd); | ||
217 | } | ||
218 | |||
209 | 219 | ||
210 | static int debug; /* insmod parameter */ | 220 | static int debug; /* insmod parameter */ |
211 | 221 | ||
@@ -311,43 +321,45 @@ static void init_reg_defaults(void) | |||
311 | */ | 321 | */ |
312 | 322 | ||
313 | 323 | ||
314 | static u8 ks0127_read(struct i2c_client *c, u8 reg) | 324 | static u8 ks0127_read(struct v4l2_subdev *sd, u8 reg) |
315 | { | 325 | { |
326 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
316 | char val = 0; | 327 | char val = 0; |
317 | struct i2c_msg msgs[] = { | 328 | struct i2c_msg msgs[] = { |
318 | { c->addr, 0, sizeof(reg), ® }, | 329 | { client->addr, 0, sizeof(reg), ® }, |
319 | { c->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val } | 330 | { client->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val } |
320 | }; | 331 | }; |
321 | int ret; | 332 | int ret; |
322 | 333 | ||
323 | ret = i2c_transfer(c->adapter, msgs, ARRAY_SIZE(msgs)); | 334 | ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); |
324 | if (ret != ARRAY_SIZE(msgs)) | 335 | if (ret != ARRAY_SIZE(msgs)) |
325 | v4l_dbg(1, debug, c, "read error\n"); | 336 | v4l2_dbg(1, debug, sd, "read error\n"); |
326 | 337 | ||
327 | return val; | 338 | return val; |
328 | } | 339 | } |
329 | 340 | ||
330 | 341 | ||
331 | static void ks0127_write(struct i2c_client *c, u8 reg, u8 val) | 342 | static void ks0127_write(struct v4l2_subdev *sd, u8 reg, u8 val) |
332 | { | 343 | { |
333 | struct ks0127 *ks = i2c_get_clientdata(c); | 344 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
345 | struct ks0127 *ks = to_ks0127(sd); | ||
334 | char msg[] = { reg, val }; | 346 | char msg[] = { reg, val }; |
335 | 347 | ||
336 | if (i2c_master_send(c, msg, sizeof(msg)) != sizeof(msg)) | 348 | if (i2c_master_send(client, msg, sizeof(msg)) != sizeof(msg)) |
337 | v4l_dbg(1, debug, c, "write error\n"); | 349 | v4l2_dbg(1, debug, sd, "write error\n"); |
338 | 350 | ||
339 | ks->regs[reg] = val; | 351 | ks->regs[reg] = val; |
340 | } | 352 | } |
341 | 353 | ||
342 | 354 | ||
343 | /* generic bit-twiddling */ | 355 | /* generic bit-twiddling */ |
344 | static void ks0127_and_or(struct i2c_client *client, u8 reg, u8 and_v, u8 or_v) | 356 | static void ks0127_and_or(struct v4l2_subdev *sd, u8 reg, u8 and_v, u8 or_v) |
345 | { | 357 | { |
346 | struct ks0127 *ks = i2c_get_clientdata(client); | 358 | struct ks0127 *ks = to_ks0127(sd); |
347 | 359 | ||
348 | u8 val = ks->regs[reg]; | 360 | u8 val = ks->regs[reg]; |
349 | val = (val & and_v) | or_v; | 361 | val = (val & and_v) | or_v; |
350 | ks0127_write(client, reg, val); | 362 | ks0127_write(sd, reg, val); |
351 | } | 363 | } |
352 | 364 | ||
353 | 365 | ||
@@ -355,391 +367,353 @@ static void ks0127_and_or(struct i2c_client *client, u8 reg, u8 and_v, u8 or_v) | |||
355 | /**************************************************************************** | 367 | /**************************************************************************** |
356 | * ks0127 private api | 368 | * ks0127 private api |
357 | ****************************************************************************/ | 369 | ****************************************************************************/ |
358 | static void ks0127_reset(struct i2c_client *c) | 370 | static void ks0127_init(struct v4l2_subdev *sd) |
359 | { | 371 | { |
360 | struct ks0127 *ks = i2c_get_clientdata(c); | 372 | struct ks0127 *ks = to_ks0127(sd); |
361 | u8 *table = reg_defaults; | 373 | u8 *table = reg_defaults; |
362 | int i; | 374 | int i; |
363 | 375 | ||
364 | ks->ks_type = KS_TYPE_UNKNOWN; | 376 | ks->ident = V4L2_IDENT_KS0127; |
365 | 377 | ||
366 | v4l_dbg(1, debug, c, "reset\n"); | 378 | v4l2_dbg(1, debug, sd, "reset\n"); |
367 | msleep(1); | 379 | msleep(1); |
368 | 380 | ||
369 | /* initialize all registers to known values */ | 381 | /* initialize all registers to known values */ |
370 | /* (except STAT, 0x21, 0x22, TEST and 0x38,0x39) */ | 382 | /* (except STAT, 0x21, 0x22, TEST and 0x38,0x39) */ |
371 | 383 | ||
372 | for (i = 1; i < 33; i++) | 384 | for (i = 1; i < 33; i++) |
373 | ks0127_write(c, i, table[i]); | 385 | ks0127_write(sd, i, table[i]); |
374 | 386 | ||
375 | for (i = 35; i < 40; i++) | 387 | for (i = 35; i < 40; i++) |
376 | ks0127_write(c, i, table[i]); | 388 | ks0127_write(sd, i, table[i]); |
377 | 389 | ||
378 | for (i = 41; i < 56; i++) | 390 | for (i = 41; i < 56; i++) |
379 | ks0127_write(c, i, table[i]); | 391 | ks0127_write(sd, i, table[i]); |
380 | 392 | ||
381 | for (i = 58; i < 64; i++) | 393 | for (i = 58; i < 64; i++) |
382 | ks0127_write(c, i, table[i]); | 394 | ks0127_write(sd, i, table[i]); |
383 | 395 | ||
384 | 396 | ||
385 | if ((ks0127_read(c, KS_STAT) & 0x80) == 0) { | 397 | if ((ks0127_read(sd, KS_STAT) & 0x80) == 0) { |
386 | ks->ks_type = KS_TYPE_0122S; | 398 | ks->ident = V4L2_IDENT_KS0122S; |
387 | v4l_dbg(1, debug, c, "ks0122s found\n"); | 399 | v4l2_dbg(1, debug, sd, "ks0122s found\n"); |
388 | return; | 400 | return; |
389 | } | 401 | } |
390 | 402 | ||
391 | switch (ks0127_read(c, KS_CMDE) & 0x0f) { | 403 | switch (ks0127_read(sd, KS_CMDE) & 0x0f) { |
392 | case 0: | 404 | case 0: |
393 | ks->ks_type = KS_TYPE_0127; | 405 | v4l2_dbg(1, debug, sd, "ks0127 found\n"); |
394 | v4l_dbg(1, debug, c, "ks0127 found\n"); | ||
395 | break; | 406 | break; |
396 | 407 | ||
397 | case 9: | 408 | case 9: |
398 | ks->ks_type = KS_TYPE_0127B; | 409 | ks->ident = V4L2_IDENT_KS0127B; |
399 | v4l_dbg(1, debug, c, "ks0127B Revision A found\n"); | 410 | v4l2_dbg(1, debug, sd, "ks0127B Revision A found\n"); |
400 | break; | 411 | break; |
401 | 412 | ||
402 | default: | 413 | default: |
403 | v4l_dbg(1, debug, c, "unknown revision\n"); | 414 | v4l2_dbg(1, debug, sd, "unknown revision\n"); |
404 | break; | 415 | break; |
405 | } | 416 | } |
406 | } | 417 | } |
407 | 418 | ||
408 | static int ks0127_command(struct i2c_client *c, unsigned cmd, void *arg) | 419 | static int ks0127_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route) |
409 | { | 420 | { |
410 | struct ks0127 *ks = i2c_get_clientdata(c); | 421 | struct ks0127 *ks = to_ks0127(sd); |
411 | struct v4l2_routing *route = arg; | 422 | |
412 | int *iarg = (int *)arg; | 423 | switch (route->input) { |
413 | v4l2_std_id *istd = arg; | 424 | case KS_INPUT_COMPOSITE_1: |
414 | int status; | 425 | case KS_INPUT_COMPOSITE_2: |
415 | 426 | case KS_INPUT_COMPOSITE_3: | |
416 | if (!ks) | 427 | case KS_INPUT_COMPOSITE_4: |
417 | return -ENODEV; | 428 | case KS_INPUT_COMPOSITE_5: |
418 | 429 | case KS_INPUT_COMPOSITE_6: | |
419 | switch (cmd) { | 430 | v4l2_dbg(1, debug, sd, |
420 | case VIDIOC_INT_INIT: | 431 | "VIDIOC_S_INPUT %d: Composite\n", route->input); |
421 | v4l_dbg(1, debug, c, "VIDIOC_INT_INIT\n"); | 432 | /* autodetect 50/60 Hz */ |
422 | ks0127_reset(c); | 433 | ks0127_and_or(sd, KS_CMDA, 0xfc, 0x00); |
434 | /* VSE=0 */ | ||
435 | ks0127_and_or(sd, KS_CMDA, ~0x40, 0x00); | ||
436 | /* set input line */ | ||
437 | ks0127_and_or(sd, KS_CMDB, 0xb0, route->input); | ||
438 | /* non-freerunning mode */ | ||
439 | ks0127_and_or(sd, KS_CMDC, 0x70, 0x0a); | ||
440 | /* analog input */ | ||
441 | ks0127_and_or(sd, KS_CMDD, 0x03, 0x00); | ||
442 | /* enable chroma demodulation */ | ||
443 | ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x00); | ||
444 | /* chroma trap, HYBWR=1 */ | ||
445 | ks0127_and_or(sd, KS_LUMA, 0x00, | ||
446 | (reg_defaults[KS_LUMA])|0x0c); | ||
447 | /* scaler fullbw, luma comb off */ | ||
448 | ks0127_and_or(sd, KS_VERTIA, 0x08, 0x81); | ||
449 | /* manual chroma comb .25 .5 .25 */ | ||
450 | ks0127_and_or(sd, KS_VERTIC, 0x0f, 0x90); | ||
451 | |||
452 | /* chroma path delay */ | ||
453 | ks0127_and_or(sd, KS_CHROMB, 0x0f, 0x90); | ||
454 | |||
455 | ks0127_write(sd, KS_UGAIN, reg_defaults[KS_UGAIN]); | ||
456 | ks0127_write(sd, KS_VGAIN, reg_defaults[KS_VGAIN]); | ||
457 | ks0127_write(sd, KS_UVOFFH, reg_defaults[KS_UVOFFH]); | ||
458 | ks0127_write(sd, KS_UVOFFL, reg_defaults[KS_UVOFFL]); | ||
423 | break; | 459 | break; |
424 | 460 | ||
425 | case VIDIOC_INT_S_VIDEO_ROUTING: | 461 | case KS_INPUT_SVIDEO_1: |
426 | switch (route->input) { | 462 | case KS_INPUT_SVIDEO_2: |
427 | case KS_INPUT_COMPOSITE_1: | 463 | case KS_INPUT_SVIDEO_3: |
428 | case KS_INPUT_COMPOSITE_2: | 464 | v4l2_dbg(1, debug, sd, |
429 | case KS_INPUT_COMPOSITE_3: | 465 | "VIDIOC_S_INPUT %d: S-Video\n", route->input); |
430 | case KS_INPUT_COMPOSITE_4: | 466 | /* autodetect 50/60 Hz */ |
431 | case KS_INPUT_COMPOSITE_5: | 467 | ks0127_and_or(sd, KS_CMDA, 0xfc, 0x00); |
432 | case KS_INPUT_COMPOSITE_6: | 468 | /* VSE=0 */ |
433 | v4l_dbg(1, debug, c, | 469 | ks0127_and_or(sd, KS_CMDA, ~0x40, 0x00); |
434 | "VIDIOC_S_INPUT %d: Composite\n", *iarg); | 470 | /* set input line */ |
435 | /* autodetect 50/60 Hz */ | 471 | ks0127_and_or(sd, KS_CMDB, 0xb0, route->input); |
436 | ks0127_and_or(c, KS_CMDA, 0xfc, 0x00); | 472 | /* non-freerunning mode */ |
437 | /* VSE=0 */ | 473 | ks0127_and_or(sd, KS_CMDC, 0x70, 0x0a); |
438 | ks0127_and_or(c, KS_CMDA, ~0x40, 0x00); | 474 | /* analog input */ |
439 | /* set input line */ | 475 | ks0127_and_or(sd, KS_CMDD, 0x03, 0x00); |
440 | ks0127_and_or(c, KS_CMDB, 0xb0, *iarg); | 476 | /* enable chroma demodulation */ |
441 | /* non-freerunning mode */ | 477 | ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x00); |
442 | ks0127_and_or(c, KS_CMDC, 0x70, 0x0a); | 478 | ks0127_and_or(sd, KS_LUMA, 0x00, |
443 | /* analog input */ | 479 | reg_defaults[KS_LUMA]); |
444 | ks0127_and_or(c, KS_CMDD, 0x03, 0x00); | 480 | /* disable luma comb */ |
445 | /* enable chroma demodulation */ | 481 | ks0127_and_or(sd, KS_VERTIA, 0x08, |
446 | ks0127_and_or(c, KS_CTRACK, 0xcf, 0x00); | 482 | (reg_defaults[KS_VERTIA]&0xf0)|0x01); |
447 | /* chroma trap, HYBWR=1 */ | 483 | ks0127_and_or(sd, KS_VERTIC, 0x0f, |
448 | ks0127_and_or(c, KS_LUMA, 0x00, | 484 | reg_defaults[KS_VERTIC]&0xf0); |
449 | (reg_defaults[KS_LUMA])|0x0c); | 485 | |
450 | /* scaler fullbw, luma comb off */ | 486 | ks0127_and_or(sd, KS_CHROMB, 0x0f, |
451 | ks0127_and_or(c, KS_VERTIA, 0x08, 0x81); | 487 | reg_defaults[KS_CHROMB]&0xf0); |
452 | /* manual chroma comb .25 .5 .25 */ | 488 | |
453 | ks0127_and_or(c, KS_VERTIC, 0x0f, 0x90); | 489 | ks0127_write(sd, KS_UGAIN, reg_defaults[KS_UGAIN]); |
454 | 490 | ks0127_write(sd, KS_VGAIN, reg_defaults[KS_VGAIN]); | |
455 | /* chroma path delay */ | 491 | ks0127_write(sd, KS_UVOFFH, reg_defaults[KS_UVOFFH]); |
456 | ks0127_and_or(c, KS_CHROMB, 0x0f, 0x90); | 492 | ks0127_write(sd, KS_UVOFFL, reg_defaults[KS_UVOFFL]); |
457 | |||
458 | ks0127_write(c, KS_UGAIN, reg_defaults[KS_UGAIN]); | ||
459 | ks0127_write(c, KS_VGAIN, reg_defaults[KS_VGAIN]); | ||
460 | ks0127_write(c, KS_UVOFFH, reg_defaults[KS_UVOFFH]); | ||
461 | ks0127_write(c, KS_UVOFFL, reg_defaults[KS_UVOFFL]); | ||
462 | break; | ||
463 | |||
464 | case KS_INPUT_SVIDEO_1: | ||
465 | case KS_INPUT_SVIDEO_2: | ||
466 | case KS_INPUT_SVIDEO_3: | ||
467 | v4l_dbg(1, debug, c, | ||
468 | "VIDIOC_S_INPUT %d: S-Video\n", *iarg); | ||
469 | /* autodetect 50/60 Hz */ | ||
470 | ks0127_and_or(c, KS_CMDA, 0xfc, 0x00); | ||
471 | /* VSE=0 */ | ||
472 | ks0127_and_or(c, KS_CMDA, ~0x40, 0x00); | ||
473 | /* set input line */ | ||
474 | ks0127_and_or(c, KS_CMDB, 0xb0, *iarg); | ||
475 | /* non-freerunning mode */ | ||
476 | ks0127_and_or(c, KS_CMDC, 0x70, 0x0a); | ||
477 | /* analog input */ | ||
478 | ks0127_and_or(c, KS_CMDD, 0x03, 0x00); | ||
479 | /* enable chroma demodulation */ | ||
480 | ks0127_and_or(c, KS_CTRACK, 0xcf, 0x00); | ||
481 | ks0127_and_or(c, KS_LUMA, 0x00, | ||
482 | reg_defaults[KS_LUMA]); | ||
483 | /* disable luma comb */ | ||
484 | ks0127_and_or(c, KS_VERTIA, 0x08, | ||
485 | (reg_defaults[KS_VERTIA]&0xf0)|0x01); | ||
486 | ks0127_and_or(c, KS_VERTIC, 0x0f, | ||
487 | reg_defaults[KS_VERTIC]&0xf0); | ||
488 | |||
489 | ks0127_and_or(c, KS_CHROMB, 0x0f, | ||
490 | reg_defaults[KS_CHROMB]&0xf0); | ||
491 | |||
492 | ks0127_write(c, KS_UGAIN, reg_defaults[KS_UGAIN]); | ||
493 | ks0127_write(c, KS_VGAIN, reg_defaults[KS_VGAIN]); | ||
494 | ks0127_write(c, KS_UVOFFH, reg_defaults[KS_UVOFFH]); | ||
495 | ks0127_write(c, KS_UVOFFL, reg_defaults[KS_UVOFFL]); | ||
496 | break; | ||
497 | |||
498 | case KS_INPUT_YUV656: | ||
499 | v4l_dbg(1, debug, c, | ||
500 | "VIDIOC_S_INPUT 15: YUV656\n"); | ||
501 | if (ks->norm & V4L2_STD_525_60) | ||
502 | /* force 60 Hz */ | ||
503 | ks0127_and_or(c, KS_CMDA, 0xfc, 0x03); | ||
504 | else | ||
505 | /* force 50 Hz */ | ||
506 | ks0127_and_or(c, KS_CMDA, 0xfc, 0x02); | ||
507 | |||
508 | ks0127_and_or(c, KS_CMDA, 0xff, 0x40); /* VSE=1 */ | ||
509 | /* set input line and VALIGN */ | ||
510 | ks0127_and_or(c, KS_CMDB, 0xb0, (*iarg | 0x40)); | ||
511 | /* freerunning mode, */ | ||
512 | /* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0 VMEM=1*/ | ||
513 | ks0127_and_or(c, KS_CMDC, 0x70, 0x87); | ||
514 | /* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */ | ||
515 | ks0127_and_or(c, KS_CMDD, 0x03, 0x08); | ||
516 | /* disable chroma demodulation */ | ||
517 | ks0127_and_or(c, KS_CTRACK, 0xcf, 0x30); | ||
518 | /* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */ | ||
519 | ks0127_and_or(c, KS_LUMA, 0x00, 0x71); | ||
520 | ks0127_and_or(c, KS_VERTIC, 0x0f, | ||
521 | reg_defaults[KS_VERTIC]&0xf0); | ||
522 | |||
523 | /* scaler fullbw, luma comb off */ | ||
524 | ks0127_and_or(c, KS_VERTIA, 0x08, 0x81); | ||
525 | |||
526 | ks0127_and_or(c, KS_CHROMB, 0x0f, | ||
527 | reg_defaults[KS_CHROMB]&0xf0); | ||
528 | |||
529 | ks0127_and_or(c, KS_CON, 0x00, 0x00); | ||
530 | ks0127_and_or(c, KS_BRT, 0x00, 32); /* spec: 34 */ | ||
531 | /* spec: 229 (e5) */ | ||
532 | ks0127_and_or(c, KS_SAT, 0x00, 0xe8); | ||
533 | ks0127_and_or(c, KS_HUE, 0x00, 0); | ||
534 | |||
535 | ks0127_and_or(c, KS_UGAIN, 0x00, 238); | ||
536 | ks0127_and_or(c, KS_VGAIN, 0x00, 0x00); | ||
537 | |||
538 | /*UOFF:0x30, VOFF:0x30, TSTCGN=1 */ | ||
539 | ks0127_and_or(c, KS_UVOFFH, 0x00, 0x4f); | ||
540 | ks0127_and_or(c, KS_UVOFFL, 0x00, 0x00); | ||
541 | break; | ||
542 | |||
543 | default: | ||
544 | v4l_dbg(1, debug, c, | ||
545 | "VIDIOC_INT_S_VIDEO_ROUTING: Unknown input %d\n", route->input); | ||
546 | break; | ||
547 | } | ||
548 | |||
549 | /* hack: CDMLPF sometimes spontaneously switches on; */ | ||
550 | /* force back off */ | ||
551 | ks0127_write(c, KS_DEMOD, reg_defaults[KS_DEMOD]); | ||
552 | break; | 493 | break; |
553 | 494 | ||
554 | case VIDIOC_S_STD: /* sam This block mixes old and new norm names... */ | 495 | case KS_INPUT_YUV656: |
555 | /* Set to automatic SECAM/Fsc mode */ | 496 | v4l2_dbg(1, debug, sd, "VIDIOC_S_INPUT 15: YUV656\n"); |
556 | ks0127_and_or(c, KS_DEMOD, 0xf0, 0x00); | 497 | if (ks->norm & V4L2_STD_525_60) |
557 | 498 | /* force 60 Hz */ | |
558 | ks->norm = *istd; | 499 | ks0127_and_or(sd, KS_CMDA, 0xfc, 0x03); |
559 | 500 | else | |
560 | if (*istd & V4L2_STD_NTSC) { | 501 | /* force 50 Hz */ |
561 | v4l_dbg(1, debug, c, | 502 | ks0127_and_or(sd, KS_CMDA, 0xfc, 0x02); |
562 | "VIDIOC_S_STD: NTSC_M\n"); | 503 | |
563 | ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20); | 504 | ks0127_and_or(sd, KS_CMDA, 0xff, 0x40); /* VSE=1 */ |
564 | ks->format_height = 240; | 505 | /* set input line and VALIGN */ |
565 | ks->format_width = 704; | 506 | ks0127_and_or(sd, KS_CMDB, 0xb0, (route->input | 0x40)); |
566 | } else if (*istd & V4L2_STD_PAL_N) { | 507 | /* freerunning mode, */ |
567 | v4l_dbg(1, debug, c, | 508 | /* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0 VMEM=1*/ |
568 | "KS0127_SET_NORM: NTSC_N (fixme)\n"); | 509 | ks0127_and_or(sd, KS_CMDC, 0x70, 0x87); |
569 | ks0127_and_or(c, KS_CHROMA, 0x9f, 0x40); | 510 | /* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */ |
570 | ks->format_height = 240; | 511 | ks0127_and_or(sd, KS_CMDD, 0x03, 0x08); |
571 | ks->format_width = 704; | 512 | /* disable chroma demodulation */ |
572 | } else if (*istd & V4L2_STD_PAL) { | 513 | ks0127_and_or(sd, KS_CTRACK, 0xcf, 0x30); |
573 | v4l_dbg(1, debug, c, | 514 | /* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */ |
574 | "VIDIOC_S_STD: PAL_N\n"); | 515 | ks0127_and_or(sd, KS_LUMA, 0x00, 0x71); |
575 | ks0127_and_or(c, KS_CHROMA, 0x9f, 0x20); | 516 | ks0127_and_or(sd, KS_VERTIC, 0x0f, |
576 | ks->format_height = 290; | 517 | reg_defaults[KS_VERTIC]&0xf0); |
577 | ks->format_width = 704; | 518 | |
578 | } else if (*istd & V4L2_STD_PAL_M) { | 519 | /* scaler fullbw, luma comb off */ |
579 | v4l_dbg(1, debug, c, | 520 | ks0127_and_or(sd, KS_VERTIA, 0x08, 0x81); |
580 | "KS0127_SET_NORM: PAL_M (fixme)\n"); | 521 | |
581 | ks0127_and_or(c, KS_CHROMA, 0x9f, 0x40); | 522 | ks0127_and_or(sd, KS_CHROMB, 0x0f, |
582 | ks->format_height = 290; | 523 | reg_defaults[KS_CHROMB]&0xf0); |
583 | ks->format_width = 704; | 524 | |
584 | } else if (*istd & V4L2_STD_SECAM) { | 525 | ks0127_and_or(sd, KS_CON, 0x00, 0x00); |
585 | v4l_dbg(1, debug, c, | 526 | ks0127_and_or(sd, KS_BRT, 0x00, 32); /* spec: 34 */ |
586 | "KS0127_SET_NORM: SECAM\n"); | 527 | /* spec: 229 (e5) */ |
587 | ks->format_height = 290; | 528 | ks0127_and_or(sd, KS_SAT, 0x00, 0xe8); |
588 | ks->format_width = 704; | 529 | ks0127_and_or(sd, KS_HUE, 0x00, 0); |
589 | 530 | ||
590 | /* set to secam autodetection */ | 531 | ks0127_and_or(sd, KS_UGAIN, 0x00, 238); |
591 | ks0127_and_or(c, KS_CHROMA, 0xdf, 0x20); | 532 | ks0127_and_or(sd, KS_VGAIN, 0x00, 0x00); |
592 | ks0127_and_or(c, KS_DEMOD, 0xf0, 0x00); | 533 | |
593 | schedule_timeout_interruptible(HZ/10+1); | 534 | /*UOFF:0x30, VOFF:0x30, TSTCGN=1 */ |
594 | 535 | ks0127_and_or(sd, KS_UVOFFH, 0x00, 0x4f); | |
595 | /* did it autodetect? */ | 536 | ks0127_and_or(sd, KS_UVOFFL, 0x00, 0x00); |
596 | if (!(ks0127_read(c, KS_DEMOD) & 0x40)) | ||
597 | /* force to secam mode */ | ||
598 | ks0127_and_or(c, KS_DEMOD, 0xf0, 0x0f); | ||
599 | } else { | ||
600 | v4l_dbg(1, debug, c, | ||
601 | "VIDIOC_S_STD: Unknown norm %llx\n", *istd); | ||
602 | } | ||
603 | break; | 537 | break; |
604 | 538 | ||
605 | case VIDIOC_QUERYCTRL: | 539 | default: |
606 | { | 540 | v4l2_dbg(1, debug, sd, |
607 | return -EINVAL; | 541 | "VIDIOC_INT_S_VIDEO_ROUTING: Unknown input %d\n", route->input); |
608 | } | ||
609 | |||
610 | case VIDIOC_S_CTRL: | ||
611 | v4l_dbg(1, debug, c, | ||
612 | "VIDIOC_S_CTRL: not yet supported\n"); | ||
613 | return -EINVAL; | ||
614 | |||
615 | case VIDIOC_G_CTRL: | ||
616 | v4l_dbg(1, debug, c, | ||
617 | "VIDIOC_G_CTRL: not yet supported\n"); | ||
618 | return -EINVAL; | ||
619 | |||
620 | /* sam todo: KS0127_SET_BRIGHTNESS: Merge into VIDIOC_S_CTRL */ | ||
621 | /* sam todo: KS0127_SET_CONTRAST: Merge into VIDIOC_S_CTRL */ | ||
622 | /* sam todo: KS0127_SET_HUE: Merge into VIDIOC_S_CTRL? */ | ||
623 | /* sam todo: KS0127_SET_SATURATION: Merge into VIDIOC_S_CTRL */ | ||
624 | /* sam todo: KS0127_SET_AGC_MODE: */ | ||
625 | /* sam todo: KS0127_SET_AGC: */ | ||
626 | /* sam todo: KS0127_SET_CHROMA_MODE: */ | ||
627 | /* sam todo: KS0127_SET_PIXCLK_MODE: */ | ||
628 | /* sam todo: KS0127_SET_GAMMA_MODE: */ | ||
629 | /* sam todo: KS0127_SET_UGAIN: */ | ||
630 | /* sam todo: KS0127_SET_VGAIN: */ | ||
631 | /* sam todo: KS0127_SET_INVALY: */ | ||
632 | /* sam todo: KS0127_SET_INVALU: */ | ||
633 | /* sam todo: KS0127_SET_INVALV: */ | ||
634 | /* sam todo: KS0127_SET_UNUSEY: */ | ||
635 | /* sam todo: KS0127_SET_UNUSEU: */ | ||
636 | /* sam todo: KS0127_SET_UNUSEV: */ | ||
637 | /* sam todo: KS0127_SET_VSALIGN_MODE: */ | ||
638 | |||
639 | case VIDIOC_STREAMON: | ||
640 | case VIDIOC_STREAMOFF: | ||
641 | { | ||
642 | int enable = cmd == VIDIOC_STREAMON; | ||
643 | |||
644 | if (enable) { | ||
645 | v4l_dbg(1, debug, c, | ||
646 | "VIDIOC_STREAMON\n"); | ||
647 | /* All output pins on */ | ||
648 | ks0127_and_or(c, KS_OFMTA, 0xcf, 0x30); | ||
649 | /* Obey the OEN pin */ | ||
650 | ks0127_and_or(c, KS_CDEM, 0x7f, 0x00); | ||
651 | } else { | ||
652 | v4l_dbg(1, debug, c, | ||
653 | "VIDIOC_STREAMOFF\n"); | ||
654 | /* Video output pins off */ | ||
655 | ks0127_and_or(c, KS_OFMTA, 0xcf, 0x00); | ||
656 | /* Ignore the OEN pin */ | ||
657 | ks0127_and_or(c, KS_CDEM, 0x7f, 0x80); | ||
658 | } | ||
659 | break; | 542 | break; |
660 | } | 543 | } |
661 | 544 | ||
662 | /* sam todo: KS0127_SET_OUTPUT_MODE: */ | 545 | /* hack: CDMLPF sometimes spontaneously switches on; */ |
663 | /* sam todo: KS0127_SET_WIDTH: */ | 546 | /* force back off */ |
664 | /* sam todo: KS0127_SET_HEIGHT: */ | 547 | ks0127_write(sd, KS_DEMOD, reg_defaults[KS_DEMOD]); |
665 | /* sam todo: KS0127_SET_HSCALE: */ | 548 | return 0; |
666 | 549 | } | |
667 | case VIDIOC_QUERYSTD: | 550 | |
668 | case VIDIOC_INT_G_INPUT_STATUS: { | 551 | static int ks0127_s_std(struct v4l2_subdev *sd, v4l2_std_id std) |
669 | int stat = V4L2_IN_ST_NO_SIGNAL; | 552 | { |
670 | v4l2_std_id std = V4L2_STD_ALL; | 553 | struct ks0127 *ks = to_ks0127(sd); |
671 | v4l_dbg(1, debug, c, "VIDIOC_QUERYSTD/VIDIOC_INT_G_INPUT_STATUS\n"); | 554 | |
672 | status = ks0127_read(c, KS_STAT); | 555 | /* Set to automatic SECAM/Fsc mode */ |
673 | if (!(status & 0x20)) /* NOVID not set */ | 556 | ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x00); |
674 | stat = 0; | 557 | |
675 | if (!(status & 0x01)) /* CLOCK set */ | 558 | ks->norm = std; |
676 | stat |= V4L2_IN_ST_NO_COLOR; | 559 | if (std & V4L2_STD_NTSC) { |
677 | if ((status & 0x08)) /* PALDET set */ | 560 | v4l2_dbg(1, debug, sd, |
678 | std = V4L2_STD_PAL; | 561 | "VIDIOC_S_STD: NTSC_M\n"); |
679 | else | 562 | ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x20); |
680 | std = V4L2_STD_NTSC; | 563 | } else if (std & V4L2_STD_PAL_N) { |
681 | if (cmd == VIDIOC_QUERYSTD) | 564 | v4l2_dbg(1, debug, sd, |
682 | *istd = std; | 565 | "KS0127_SET_NORM: NTSC_N (fixme)\n"); |
683 | else | 566 | ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x40); |
684 | *iarg = stat; | 567 | } else if (std & V4L2_STD_PAL) { |
685 | break; | 568 | v4l2_dbg(1, debug, sd, |
569 | "VIDIOC_S_STD: PAL_N\n"); | ||
570 | ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x20); | ||
571 | } else if (std & V4L2_STD_PAL_M) { | ||
572 | v4l2_dbg(1, debug, sd, | ||
573 | "KS0127_SET_NORM: PAL_M (fixme)\n"); | ||
574 | ks0127_and_or(sd, KS_CHROMA, 0x9f, 0x40); | ||
575 | } else if (std & V4L2_STD_SECAM) { | ||
576 | v4l2_dbg(1, debug, sd, | ||
577 | "KS0127_SET_NORM: SECAM\n"); | ||
578 | |||
579 | /* set to secam autodetection */ | ||
580 | ks0127_and_or(sd, KS_CHROMA, 0xdf, 0x20); | ||
581 | ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x00); | ||
582 | schedule_timeout_interruptible(HZ/10+1); | ||
583 | |||
584 | /* did it autodetect? */ | ||
585 | if (!(ks0127_read(sd, KS_DEMOD) & 0x40)) | ||
586 | /* force to secam mode */ | ||
587 | ks0127_and_or(sd, KS_DEMOD, 0xf0, 0x0f); | ||
588 | } else { | ||
589 | v4l2_dbg(1, debug, sd, | ||
590 | "VIDIOC_S_STD: Unknown norm %llx\n", std); | ||
686 | } | 591 | } |
592 | return 0; | ||
593 | } | ||
687 | 594 | ||
688 | /* Catch any unknown command */ | 595 | static int ks0127_s_stream(struct v4l2_subdev *sd, int enable) |
689 | default: | 596 | { |
690 | v4l_dbg(1, debug, c, "unknown: 0x%08x\n", cmd); | 597 | v4l2_dbg(1, debug, sd, "s_stream(%d)\n", enable); |
691 | return -EINVAL; | 598 | if (enable) { |
599 | /* All output pins on */ | ||
600 | ks0127_and_or(sd, KS_OFMTA, 0xcf, 0x30); | ||
601 | /* Obey the OEN pin */ | ||
602 | ks0127_and_or(sd, KS_CDEM, 0x7f, 0x00); | ||
603 | } else { | ||
604 | /* Video output pins off */ | ||
605 | ks0127_and_or(sd, KS_OFMTA, 0xcf, 0x00); | ||
606 | /* Ignore the OEN pin */ | ||
607 | ks0127_and_or(sd, KS_CDEM, 0x7f, 0x80); | ||
692 | } | 608 | } |
693 | return 0; | 609 | return 0; |
694 | } | 610 | } |
695 | 611 | ||
612 | static int ks0127_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd) | ||
613 | { | ||
614 | int stat = V4L2_IN_ST_NO_SIGNAL; | ||
615 | u8 status; | ||
616 | v4l2_std_id std = V4L2_STD_ALL; | ||
617 | |||
618 | v4l2_dbg(1, debug, sd, "VIDIOC_QUERYSTD/VIDIOC_INT_G_INPUT_STATUS\n"); | ||
619 | status = ks0127_read(sd, KS_STAT); | ||
620 | if (!(status & 0x20)) /* NOVID not set */ | ||
621 | stat = 0; | ||
622 | if (!(status & 0x01)) /* CLOCK set */ | ||
623 | stat |= V4L2_IN_ST_NO_COLOR; | ||
624 | if ((status & 0x08)) /* PALDET set */ | ||
625 | std = V4L2_STD_PAL; | ||
626 | else | ||
627 | std = V4L2_STD_NTSC; | ||
628 | if (pstd) | ||
629 | *pstd = std; | ||
630 | if (pstatus) | ||
631 | *pstatus = stat; | ||
632 | return 0; | ||
633 | } | ||
696 | 634 | ||
697 | /* Addresses to scan */ | 635 | static int ks0127_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) |
698 | #define I2C_KS0127_ADDON 0xD8 | 636 | { |
699 | #define I2C_KS0127_ONBOARD 0xDA | 637 | return ks0127_status(sd, NULL, std); |
638 | } | ||
700 | 639 | ||
701 | static unsigned short normal_i2c[] = { | 640 | static int ks0127_g_input_status(struct v4l2_subdev *sd, u32 *status) |
702 | I2C_KS0127_ADDON >> 1, | 641 | { |
703 | I2C_KS0127_ONBOARD >> 1, | 642 | return ks0127_status(sd, status, NULL); |
704 | I2C_CLIENT_END | 643 | } |
644 | |||
645 | static int ks0127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) | ||
646 | { | ||
647 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
648 | struct ks0127 *ks = to_ks0127(sd); | ||
649 | |||
650 | return v4l2_chip_ident_i2c_client(client, chip, ks->ident, 0); | ||
651 | } | ||
652 | |||
653 | static int ks0127_command(struct i2c_client *client, unsigned cmd, void *arg) | ||
654 | { | ||
655 | return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg); | ||
656 | } | ||
657 | |||
658 | /* ----------------------------------------------------------------------- */ | ||
659 | |||
660 | static const struct v4l2_subdev_core_ops ks0127_core_ops = { | ||
661 | .g_chip_ident = ks0127_g_chip_ident, | ||
705 | }; | 662 | }; |
706 | 663 | ||
707 | I2C_CLIENT_INSMOD; | 664 | static const struct v4l2_subdev_tuner_ops ks0127_tuner_ops = { |
665 | .s_std = ks0127_s_std, | ||
666 | }; | ||
667 | |||
668 | static const struct v4l2_subdev_video_ops ks0127_video_ops = { | ||
669 | .s_routing = ks0127_s_routing, | ||
670 | .s_stream = ks0127_s_stream, | ||
671 | .querystd = ks0127_querystd, | ||
672 | .g_input_status = ks0127_g_input_status, | ||
673 | }; | ||
708 | 674 | ||
709 | static int ks0127_probe(struct i2c_client *c, const struct i2c_device_id *id) | 675 | static const struct v4l2_subdev_ops ks0127_ops = { |
676 | .core = &ks0127_core_ops, | ||
677 | .tuner = &ks0127_tuner_ops, | ||
678 | .video = &ks0127_video_ops, | ||
679 | }; | ||
680 | |||
681 | /* ----------------------------------------------------------------------- */ | ||
682 | |||
683 | |||
684 | static int ks0127_probe(struct i2c_client *client, const struct i2c_device_id *id) | ||
710 | { | 685 | { |
711 | struct ks0127 *ks; | 686 | struct ks0127 *ks; |
687 | struct v4l2_subdev *sd; | ||
712 | 688 | ||
713 | v4l_info(c, "%s chip found @ 0x%x (%s)\n", | 689 | v4l_info(client, "%s chip found @ 0x%x (%s)\n", |
714 | c->addr == (I2C_KS0127_ADDON >> 1) ? "addon" : "on-board", | 690 | client->addr == (I2C_KS0127_ADDON >> 1) ? "addon" : "on-board", |
715 | c->addr << 1, c->adapter->name); | 691 | client->addr << 1, client->adapter->name); |
716 | 692 | ||
717 | ks = kzalloc(sizeof(*ks), GFP_KERNEL); | 693 | ks = kzalloc(sizeof(*ks), GFP_KERNEL); |
718 | if (ks == NULL) | 694 | if (ks == NULL) |
719 | return -ENOMEM; | 695 | return -ENOMEM; |
720 | 696 | sd = &ks->sd; | |
721 | i2c_set_clientdata(c, ks); | 697 | v4l2_i2c_subdev_init(sd, client, &ks0127_ops); |
722 | |||
723 | ks->ks_type = KS_TYPE_UNKNOWN; | ||
724 | 698 | ||
725 | /* power up */ | 699 | /* power up */ |
726 | init_reg_defaults(); | 700 | init_reg_defaults(); |
727 | ks0127_write(c, KS_CMDA, 0x2c); | 701 | ks0127_write(sd, KS_CMDA, 0x2c); |
728 | mdelay(10); | 702 | mdelay(10); |
729 | 703 | ||
730 | /* reset the device */ | 704 | /* reset the device */ |
731 | ks0127_reset(c); | 705 | ks0127_init(sd); |
732 | return 0; | 706 | return 0; |
733 | } | 707 | } |
734 | 708 | ||
735 | static int ks0127_remove(struct i2c_client *c) | 709 | static int ks0127_remove(struct i2c_client *client) |
736 | { | 710 | { |
737 | struct ks0127 *ks = i2c_get_clientdata(c); | 711 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
738 | |||
739 | ks0127_write(c, KS_OFMTA, 0x20); /* tristate */ | ||
740 | ks0127_write(c, KS_CMDA, 0x2c | 0x80); /* power down */ | ||
741 | 712 | ||
742 | kfree(ks); | 713 | v4l2_device_unregister_subdev(sd); |
714 | ks0127_write(sd, KS_OFMTA, 0x20); /* tristate */ | ||
715 | ks0127_write(sd, KS_CMDA, 0x2c | 0x80); /* power down */ | ||
716 | kfree(to_ks0127(sd)); | ||
743 | return 0; | 717 | return 0; |
744 | } | 718 | } |
745 | 719 | ||
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 69e3092fd288..b5ed91a4ce92 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h | |||
@@ -82,6 +82,11 @@ enum { | |||
82 | /* module bt866: just ident 866 */ | 82 | /* module bt866: just ident 866 */ |
83 | V4L2_IDENT_BT866 = 866, | 83 | V4L2_IDENT_BT866 = 866, |
84 | 84 | ||
85 | /* module ks0127: reserved range 1120-1129 */ | ||
86 | V4L2_IDENT_KS0122S = 1122, | ||
87 | V4L2_IDENT_KS0127 = 1127, | ||
88 | V4L2_IDENT_KS0127B = 1128, | ||
89 | |||
85 | /* module vp27smpx: just ident 2700 */ | 90 | /* module vp27smpx: just ident 2700 */ |
86 | V4L2_IDENT_VP27SMPX = 2700, | 91 | V4L2_IDENT_VP27SMPX = 2700, |
87 | 92 | ||