diff options
-rw-r--r-- | drivers/media/video/gspca/ov519.c | 1142 |
1 files changed, 596 insertions, 546 deletions
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index c132f8d2cf05..4062aed24139 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c | |||
@@ -63,11 +63,10 @@ struct sd { | |||
63 | #define SEN_OV6630 2 | 63 | #define SEN_OV6630 2 |
64 | #define SEN_OV7610 3 | 64 | #define SEN_OV7610 3 |
65 | #define SEN_OV7620 4 | 65 | #define SEN_OV7620 4 |
66 | #define SEN_OV7630 5 | 66 | #define SEN_OV7640 5 |
67 | #define SEN_OV7640 6 | 67 | #define SEN_OV7670 6 |
68 | #define SEN_OV7670 7 | 68 | #define SEN_OV76BE 7 |
69 | #define SEN_OV76BE 8 | 69 | #define SEN_OV8610 8 |
70 | #define SEN_OV8610 9 | ||
71 | 70 | ||
72 | }; | 71 | }; |
73 | 72 | ||
@@ -293,6 +292,541 @@ static struct v4l2_pix_format sif_mode[] = { | |||
293 | #define OV7670_REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ | 292 | #define OV7670_REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ |
294 | #define OV7670_REG_BD60MAX 0xab /* 60hz banding step limit */ | 293 | #define OV7670_REG_BD60MAX 0xab /* 60hz banding step limit */ |
295 | 294 | ||
295 | struct ov_regvals { | ||
296 | __u8 reg; | ||
297 | __u8 val; | ||
298 | }; | ||
299 | struct ov_i2c_regvals { | ||
300 | __u8 reg; | ||
301 | __u8 val; | ||
302 | }; | ||
303 | |||
304 | static const struct ov_i2c_regvals norm_6x20[] = { | ||
305 | { 0x12, 0x80 }, /* reset */ | ||
306 | { 0x11, 0x01 }, | ||
307 | { 0x03, 0x60 }, | ||
308 | { 0x05, 0x7f }, /* For when autoadjust is off */ | ||
309 | { 0x07, 0xa8 }, | ||
310 | /* The ratio of 0x0c and 0x0d controls the white point */ | ||
311 | { 0x0c, 0x24 }, | ||
312 | { 0x0d, 0x24 }, | ||
313 | { 0x0f, 0x15 }, /* COMS */ | ||
314 | { 0x10, 0x75 }, /* AEC Exposure time */ | ||
315 | { 0x12, 0x24 }, /* Enable AGC */ | ||
316 | { 0x14, 0x04 }, | ||
317 | /* 0x16: 0x06 helps frame stability with moving objects */ | ||
318 | { 0x16, 0x06 }, | ||
319 | /* { 0x20, 0x30 }, * Aperture correction enable */ | ||
320 | { 0x26, 0xb2 }, /* BLC enable */ | ||
321 | /* 0x28: 0x05 Selects RGB format if RGB on */ | ||
322 | { 0x28, 0x05 }, | ||
323 | { 0x2a, 0x04 }, /* Disable framerate adjust */ | ||
324 | /* { 0x2b, 0xac }, * Framerate; Set 2a[7] first */ | ||
325 | { 0x2d, 0x99 }, | ||
326 | { 0x33, 0xa0 }, /* Color Processing Parameter */ | ||
327 | { 0x34, 0xd2 }, /* Max A/D range */ | ||
328 | { 0x38, 0x8b }, | ||
329 | { 0x39, 0x40 }, | ||
330 | |||
331 | { 0x3c, 0x39 }, /* Enable AEC mode changing */ | ||
332 | { 0x3c, 0x3c }, /* Change AEC mode */ | ||
333 | { 0x3c, 0x24 }, /* Disable AEC mode changing */ | ||
334 | |||
335 | { 0x3d, 0x80 }, | ||
336 | /* These next two registers (0x4a, 0x4b) are undocumented. | ||
337 | * They control the color balance */ | ||
338 | { 0x4a, 0x80 }, | ||
339 | { 0x4b, 0x80 }, | ||
340 | { 0x4d, 0xd2 }, /* This reduces noise a bit */ | ||
341 | { 0x4e, 0xc1 }, | ||
342 | { 0x4f, 0x04 }, | ||
343 | /* Do 50-53 have any effect? */ | ||
344 | /* Toggle 0x12[2] off and on here? */ | ||
345 | }; | ||
346 | |||
347 | static const struct ov_i2c_regvals norm_6x30[] = { | ||
348 | { 0x12, 0x80 }, /* Reset */ | ||
349 | { 0x00, 0x1f }, /* Gain */ | ||
350 | { 0x01, 0x99 }, /* Blue gain */ | ||
351 | { 0x02, 0x7c }, /* Red gain */ | ||
352 | { 0x03, 0xc0 }, /* Saturation */ | ||
353 | { 0x05, 0x0a }, /* Contrast */ | ||
354 | { 0x06, 0x95 }, /* Brightness */ | ||
355 | { 0x07, 0x2d }, /* Sharpness */ | ||
356 | { 0x0c, 0x20 }, | ||
357 | { 0x0d, 0x20 }, | ||
358 | { 0x0e, 0x20 }, | ||
359 | { 0x0f, 0x05 }, | ||
360 | { 0x10, 0x9a }, | ||
361 | { 0x11, 0x00 }, /* Pixel clock = fastest */ | ||
362 | { 0x12, 0x24 }, /* Enable AGC and AWB */ | ||
363 | { 0x13, 0x21 }, | ||
364 | { 0x14, 0x80 }, | ||
365 | { 0x15, 0x01 }, | ||
366 | { 0x16, 0x03 }, | ||
367 | { 0x17, 0x38 }, | ||
368 | { 0x18, 0xea }, | ||
369 | { 0x19, 0x04 }, | ||
370 | { 0x1a, 0x93 }, | ||
371 | { 0x1b, 0x00 }, | ||
372 | { 0x1e, 0xc4 }, | ||
373 | { 0x1f, 0x04 }, | ||
374 | { 0x20, 0x20 }, | ||
375 | { 0x21, 0x10 }, | ||
376 | { 0x22, 0x88 }, | ||
377 | { 0x23, 0xc0 }, /* Crystal circuit power level */ | ||
378 | { 0x25, 0x9a }, /* Increase AEC black ratio */ | ||
379 | { 0x26, 0xb2 }, /* BLC enable */ | ||
380 | { 0x27, 0xa2 }, | ||
381 | { 0x28, 0x00 }, | ||
382 | { 0x29, 0x00 }, | ||
383 | { 0x2a, 0x84 }, /* 60 Hz power */ | ||
384 | { 0x2b, 0xa8 }, /* 60 Hz power */ | ||
385 | { 0x2c, 0xa0 }, | ||
386 | { 0x2d, 0x95 }, /* Enable auto-brightness */ | ||
387 | { 0x2e, 0x88 }, | ||
388 | { 0x33, 0x26 }, | ||
389 | { 0x34, 0x03 }, | ||
390 | { 0x36, 0x8f }, | ||
391 | { 0x37, 0x80 }, | ||
392 | { 0x38, 0x83 }, | ||
393 | { 0x39, 0x80 }, | ||
394 | { 0x3a, 0x0f }, | ||
395 | { 0x3b, 0x3c }, | ||
396 | { 0x3c, 0x1a }, | ||
397 | { 0x3d, 0x80 }, | ||
398 | { 0x3e, 0x80 }, | ||
399 | { 0x3f, 0x0e }, | ||
400 | { 0x40, 0x00 }, /* White bal */ | ||
401 | { 0x41, 0x00 }, /* White bal */ | ||
402 | { 0x42, 0x80 }, | ||
403 | { 0x43, 0x3f }, /* White bal */ | ||
404 | { 0x44, 0x80 }, | ||
405 | { 0x45, 0x20 }, | ||
406 | { 0x46, 0x20 }, | ||
407 | { 0x47, 0x80 }, | ||
408 | { 0x48, 0x7f }, | ||
409 | { 0x49, 0x00 }, | ||
410 | { 0x4a, 0x00 }, | ||
411 | { 0x4b, 0x80 }, | ||
412 | { 0x4c, 0xd0 }, | ||
413 | { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ | ||
414 | { 0x4e, 0x40 }, | ||
415 | { 0x4f, 0x07 }, /* UV avg., col. killer: max */ | ||
416 | { 0x50, 0xff }, | ||
417 | { 0x54, 0x23 }, /* Max AGC gain: 18dB */ | ||
418 | { 0x55, 0xff }, | ||
419 | { 0x56, 0x12 }, | ||
420 | { 0x57, 0x81 }, | ||
421 | { 0x58, 0x75 }, | ||
422 | { 0x59, 0x01 }, /* AGC dark current comp.: +1 */ | ||
423 | { 0x5a, 0x2c }, | ||
424 | { 0x5b, 0x0f }, /* AWB chrominance levels */ | ||
425 | { 0x5c, 0x10 }, | ||
426 | { 0x3d, 0x80 }, | ||
427 | { 0x27, 0xa6 }, | ||
428 | { 0x12, 0x20 }, /* Toggle AWB */ | ||
429 | { 0x12, 0x24 }, | ||
430 | }; | ||
431 | |||
432 | /* Lawrence Glaister <lg@jfm.bc.ca> reports: | ||
433 | * | ||
434 | * Register 0x0f in the 7610 has the following effects: | ||
435 | * | ||
436 | * 0x85 (AEC method 1): Best overall, good contrast range | ||
437 | * 0x45 (AEC method 2): Very overexposed | ||
438 | * 0xa5 (spec sheet default): Ok, but the black level is | ||
439 | * shifted resulting in loss of contrast | ||
440 | * 0x05 (old driver setting): very overexposed, too much | ||
441 | * contrast | ||
442 | */ | ||
443 | static const struct ov_i2c_regvals norm_7610[] = { | ||
444 | { 0x10, 0xff }, | ||
445 | { 0x16, 0x06 }, | ||
446 | { 0x28, 0x24 }, | ||
447 | { 0x2b, 0xac }, | ||
448 | { 0x12, 0x00 }, | ||
449 | { 0x38, 0x81 }, | ||
450 | { 0x28, 0x24 }, /* 0c */ | ||
451 | { 0x0f, 0x85 }, /* lg's setting */ | ||
452 | { 0x15, 0x01 }, | ||
453 | { 0x20, 0x1c }, | ||
454 | { 0x23, 0x2a }, | ||
455 | { 0x24, 0x10 }, | ||
456 | { 0x25, 0x8a }, | ||
457 | { 0x26, 0xa2 }, | ||
458 | { 0x27, 0xc2 }, | ||
459 | { 0x2a, 0x04 }, | ||
460 | { 0x2c, 0xfe }, | ||
461 | { 0x2d, 0x93 }, | ||
462 | { 0x30, 0x71 }, | ||
463 | { 0x31, 0x60 }, | ||
464 | { 0x32, 0x26 }, | ||
465 | { 0x33, 0x20 }, | ||
466 | { 0x34, 0x48 }, | ||
467 | { 0x12, 0x24 }, | ||
468 | { 0x11, 0x01 }, | ||
469 | { 0x0c, 0x24 }, | ||
470 | { 0x0d, 0x24 }, | ||
471 | }; | ||
472 | |||
473 | static const struct ov_i2c_regvals norm_7620[] = { | ||
474 | { 0x00, 0x00 }, /* gain */ | ||
475 | { 0x01, 0x80 }, /* blue gain */ | ||
476 | { 0x02, 0x80 }, /* red gain */ | ||
477 | { 0x03, 0xc0 }, /* OV7670_REG_VREF */ | ||
478 | { 0x06, 0x60 }, | ||
479 | { 0x07, 0x00 }, | ||
480 | { 0x0c, 0x24 }, | ||
481 | { 0x0c, 0x24 }, | ||
482 | { 0x0d, 0x24 }, | ||
483 | { 0x11, 0x01 }, | ||
484 | { 0x12, 0x24 }, | ||
485 | { 0x13, 0x01 }, | ||
486 | { 0x14, 0x84 }, | ||
487 | { 0x15, 0x01 }, | ||
488 | { 0x16, 0x03 }, | ||
489 | { 0x17, 0x2f }, | ||
490 | { 0x18, 0xcf }, | ||
491 | { 0x19, 0x06 }, | ||
492 | { 0x1a, 0xf5 }, | ||
493 | { 0x1b, 0x00 }, | ||
494 | { 0x20, 0x18 }, | ||
495 | { 0x21, 0x80 }, | ||
496 | { 0x22, 0x80 }, | ||
497 | { 0x23, 0x00 }, | ||
498 | { 0x26, 0xa2 }, | ||
499 | { 0x27, 0xea }, | ||
500 | { 0x28, 0x20 }, | ||
501 | { 0x29, 0x00 }, | ||
502 | { 0x2a, 0x10 }, | ||
503 | { 0x2b, 0x00 }, | ||
504 | { 0x2c, 0x88 }, | ||
505 | { 0x2d, 0x91 }, | ||
506 | { 0x2e, 0x80 }, | ||
507 | { 0x2f, 0x44 }, | ||
508 | { 0x60, 0x27 }, | ||
509 | { 0x61, 0x02 }, | ||
510 | { 0x62, 0x5f }, | ||
511 | { 0x63, 0xd5 }, | ||
512 | { 0x64, 0x57 }, | ||
513 | { 0x65, 0x83 }, | ||
514 | { 0x66, 0x55 }, | ||
515 | { 0x67, 0x92 }, | ||
516 | { 0x68, 0xcf }, | ||
517 | { 0x69, 0x76 }, | ||
518 | { 0x6a, 0x22 }, | ||
519 | { 0x6b, 0x00 }, | ||
520 | { 0x6c, 0x02 }, | ||
521 | { 0x6d, 0x44 }, | ||
522 | { 0x6e, 0x80 }, | ||
523 | { 0x6f, 0x1d }, | ||
524 | { 0x70, 0x8b }, | ||
525 | { 0x71, 0x00 }, | ||
526 | { 0x72, 0x14 }, | ||
527 | { 0x73, 0x54 }, | ||
528 | { 0x74, 0x00 }, | ||
529 | { 0x75, 0x8e }, | ||
530 | { 0x76, 0x00 }, | ||
531 | { 0x77, 0xff }, | ||
532 | { 0x78, 0x80 }, | ||
533 | { 0x79, 0x80 }, | ||
534 | { 0x7a, 0x80 }, | ||
535 | { 0x7b, 0xe2 }, | ||
536 | { 0x7c, 0x00 }, | ||
537 | }; | ||
538 | |||
539 | /* 7640 and 7648. The defaults should be OK for most registers. */ | ||
540 | static const struct ov_i2c_regvals norm_7640[] = { | ||
541 | { 0x12, 0x80 }, | ||
542 | { 0x12, 0x14 }, | ||
543 | }; | ||
544 | |||
545 | /* 7670. Defaults taken from OmniVision provided data, | ||
546 | * as provided by Jonathan Corbet of OLPC */ | ||
547 | static const struct ov_i2c_regvals norm_7670[] = { | ||
548 | { OV7670_REG_COM7, OV7670_COM7_RESET }, | ||
549 | { OV7670_REG_TSLB, 0x04 }, /* OV */ | ||
550 | { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */ | ||
551 | { OV7670_REG_CLKRC, 0x01 }, | ||
552 | /* | ||
553 | * Set the hardware window. These values from OV don't entirely | ||
554 | * make sense - hstop is less than hstart. But they work... | ||
555 | */ | ||
556 | { OV7670_REG_HSTART, 0x13 }, | ||
557 | { OV7670_REG_HSTOP, 0x01 }, | ||
558 | { OV7670_REG_HREF, 0xb6 }, | ||
559 | { OV7670_REG_VSTART, 0x02 }, | ||
560 | { OV7670_REG_VSTOP, 0x7a }, | ||
561 | { OV7670_REG_VREF, 0x0a }, | ||
562 | |||
563 | { OV7670_REG_COM3, 0 }, | ||
564 | { OV7670_REG_COM14, 0 }, | ||
565 | /* Mystery scaling numbers */ | ||
566 | { 0x70, 0x3a }, | ||
567 | { 0x71, 0x35 }, | ||
568 | { 0x72, 0x11 }, | ||
569 | { 0x73, 0xf0 }, | ||
570 | { 0xa2, 0x02 }, | ||
571 | /* { OV7670_REG_COM10, 0x0 }, */ | ||
572 | |||
573 | /* Gamma curve values */ | ||
574 | { 0x7a, 0x20 }, | ||
575 | { 0x7b, 0x10 }, | ||
576 | { 0x7c, 0x1e }, | ||
577 | { 0x7d, 0x35 }, | ||
578 | { 0x7e, 0x5a }, | ||
579 | { 0x7f, 0x69 }, | ||
580 | { 0x80, 0x76 }, | ||
581 | { 0x81, 0x80 }, | ||
582 | { 0x82, 0x88 }, | ||
583 | { 0x83, 0x8f }, | ||
584 | { 0x84, 0x96 }, | ||
585 | { 0x85, 0xa3 }, | ||
586 | { 0x86, 0xaf }, | ||
587 | { 0x87, 0xc4 }, | ||
588 | { 0x88, 0xd7 }, | ||
589 | { 0x89, 0xe8 }, | ||
590 | |||
591 | /* AGC and AEC parameters. Note we start by disabling those features, | ||
592 | then turn them only after tweaking the values. */ | ||
593 | { OV7670_REG_COM8, OV7670_COM8_FASTAEC | ||
594 | | OV7670_COM8_AECSTEP | ||
595 | | OV7670_COM8_BFILT }, | ||
596 | { OV7670_REG_GAIN, 0 }, | ||
597 | { OV7670_REG_AECH, 0 }, | ||
598 | { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */ | ||
599 | { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */ | ||
600 | { OV7670_REG_BD50MAX, 0x05 }, | ||
601 | { OV7670_REG_BD60MAX, 0x07 }, | ||
602 | { OV7670_REG_AEW, 0x95 }, | ||
603 | { OV7670_REG_AEB, 0x33 }, | ||
604 | { OV7670_REG_VPT, 0xe3 }, | ||
605 | { OV7670_REG_HAECC1, 0x78 }, | ||
606 | { OV7670_REG_HAECC2, 0x68 }, | ||
607 | { 0xa1, 0x03 }, /* magic */ | ||
608 | { OV7670_REG_HAECC3, 0xd8 }, | ||
609 | { OV7670_REG_HAECC4, 0xd8 }, | ||
610 | { OV7670_REG_HAECC5, 0xf0 }, | ||
611 | { OV7670_REG_HAECC6, 0x90 }, | ||
612 | { OV7670_REG_HAECC7, 0x94 }, | ||
613 | { OV7670_REG_COM8, OV7670_COM8_FASTAEC | ||
614 | | OV7670_COM8_AECSTEP | ||
615 | | OV7670_COM8_BFILT | ||
616 | | OV7670_COM8_AGC | ||
617 | | OV7670_COM8_AEC }, | ||
618 | |||
619 | /* Almost all of these are magic "reserved" values. */ | ||
620 | { OV7670_REG_COM5, 0x61 }, | ||
621 | { OV7670_REG_COM6, 0x4b }, | ||
622 | { 0x16, 0x02 }, | ||
623 | { OV7670_REG_MVFP, 0x07 }, | ||
624 | { 0x21, 0x02 }, | ||
625 | { 0x22, 0x91 }, | ||
626 | { 0x29, 0x07 }, | ||
627 | { 0x33, 0x0b }, | ||
628 | { 0x35, 0x0b }, | ||
629 | { 0x37, 0x1d }, | ||
630 | { 0x38, 0x71 }, | ||
631 | { 0x39, 0x2a }, | ||
632 | { OV7670_REG_COM12, 0x78 }, | ||
633 | { 0x4d, 0x40 }, | ||
634 | { 0x4e, 0x20 }, | ||
635 | { OV7670_REG_GFIX, 0 }, | ||
636 | { 0x6b, 0x4a }, | ||
637 | { 0x74, 0x10 }, | ||
638 | { 0x8d, 0x4f }, | ||
639 | { 0x8e, 0 }, | ||
640 | { 0x8f, 0 }, | ||
641 | { 0x90, 0 }, | ||
642 | { 0x91, 0 }, | ||
643 | { 0x96, 0 }, | ||
644 | { 0x9a, 0 }, | ||
645 | { 0xb0, 0x84 }, | ||
646 | { 0xb1, 0x0c }, | ||
647 | { 0xb2, 0x0e }, | ||
648 | { 0xb3, 0x82 }, | ||
649 | { 0xb8, 0x0a }, | ||
650 | |||
651 | /* More reserved magic, some of which tweaks white balance */ | ||
652 | { 0x43, 0x0a }, | ||
653 | { 0x44, 0xf0 }, | ||
654 | { 0x45, 0x34 }, | ||
655 | { 0x46, 0x58 }, | ||
656 | { 0x47, 0x28 }, | ||
657 | { 0x48, 0x3a }, | ||
658 | { 0x59, 0x88 }, | ||
659 | { 0x5a, 0x88 }, | ||
660 | { 0x5b, 0x44 }, | ||
661 | { 0x5c, 0x67 }, | ||
662 | { 0x5d, 0x49 }, | ||
663 | { 0x5e, 0x0e }, | ||
664 | { 0x6c, 0x0a }, | ||
665 | { 0x6d, 0x55 }, | ||
666 | { 0x6e, 0x11 }, | ||
667 | { 0x6f, 0x9f }, | ||
668 | /* "9e for advance AWB" */ | ||
669 | { 0x6a, 0x40 }, | ||
670 | { OV7670_REG_BLUE, 0x40 }, | ||
671 | { OV7670_REG_RED, 0x60 }, | ||
672 | { OV7670_REG_COM8, OV7670_COM8_FASTAEC | ||
673 | | OV7670_COM8_AECSTEP | ||
674 | | OV7670_COM8_BFILT | ||
675 | | OV7670_COM8_AGC | ||
676 | | OV7670_COM8_AEC | ||
677 | | OV7670_COM8_AWB }, | ||
678 | |||
679 | /* Matrix coefficients */ | ||
680 | { 0x4f, 0x80 }, | ||
681 | { 0x50, 0x80 }, | ||
682 | { 0x51, 0 }, | ||
683 | { 0x52, 0x22 }, | ||
684 | { 0x53, 0x5e }, | ||
685 | { 0x54, 0x80 }, | ||
686 | { 0x58, 0x9e }, | ||
687 | |||
688 | { OV7670_REG_COM16, OV7670_COM16_AWBGAIN }, | ||
689 | { OV7670_REG_EDGE, 0 }, | ||
690 | { 0x75, 0x05 }, | ||
691 | { 0x76, 0xe1 }, | ||
692 | { 0x4c, 0 }, | ||
693 | { 0x77, 0x01 }, | ||
694 | { OV7670_REG_COM13, OV7670_COM13_GAMMA | ||
695 | | OV7670_COM13_UVSAT | ||
696 | | 2}, /* was 3 */ | ||
697 | { 0x4b, 0x09 }, | ||
698 | { 0xc9, 0x60 }, | ||
699 | { OV7670_REG_COM16, 0x38 }, | ||
700 | { 0x56, 0x40 }, | ||
701 | |||
702 | { 0x34, 0x11 }, | ||
703 | { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO }, | ||
704 | { 0xa4, 0x88 }, | ||
705 | { 0x96, 0 }, | ||
706 | { 0x97, 0x30 }, | ||
707 | { 0x98, 0x20 }, | ||
708 | { 0x99, 0x30 }, | ||
709 | { 0x9a, 0x84 }, | ||
710 | { 0x9b, 0x29 }, | ||
711 | { 0x9c, 0x03 }, | ||
712 | { 0x9d, 0x4c }, | ||
713 | { 0x9e, 0x3f }, | ||
714 | { 0x78, 0x04 }, | ||
715 | |||
716 | /* Extra-weird stuff. Some sort of multiplexor register */ | ||
717 | { 0x79, 0x01 }, | ||
718 | { 0xc8, 0xf0 }, | ||
719 | { 0x79, 0x0f }, | ||
720 | { 0xc8, 0x00 }, | ||
721 | { 0x79, 0x10 }, | ||
722 | { 0xc8, 0x7e }, | ||
723 | { 0x79, 0x0a }, | ||
724 | { 0xc8, 0x80 }, | ||
725 | { 0x79, 0x0b }, | ||
726 | { 0xc8, 0x01 }, | ||
727 | { 0x79, 0x0c }, | ||
728 | { 0xc8, 0x0f }, | ||
729 | { 0x79, 0x0d }, | ||
730 | { 0xc8, 0x20 }, | ||
731 | { 0x79, 0x09 }, | ||
732 | { 0xc8, 0x80 }, | ||
733 | { 0x79, 0x02 }, | ||
734 | { 0xc8, 0xc0 }, | ||
735 | { 0x79, 0x03 }, | ||
736 | { 0xc8, 0x40 }, | ||
737 | { 0x79, 0x05 }, | ||
738 | { 0xc8, 0x30 }, | ||
739 | { 0x79, 0x26 }, | ||
740 | }; | ||
741 | |||
742 | static const struct ov_i2c_regvals norm_8610[] = { | ||
743 | { 0x12, 0x80 }, | ||
744 | { 0x00, 0x00 }, | ||
745 | { 0x01, 0x80 }, | ||
746 | { 0x02, 0x80 }, | ||
747 | { 0x03, 0xc0 }, | ||
748 | { 0x04, 0x30 }, | ||
749 | { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */ | ||
750 | { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */ | ||
751 | { 0x0a, 0x86 }, | ||
752 | { 0x0b, 0xb0 }, | ||
753 | { 0x0c, 0x20 }, | ||
754 | { 0x0d, 0x20 }, | ||
755 | { 0x11, 0x01 }, | ||
756 | { 0x12, 0x25 }, | ||
757 | { 0x13, 0x01 }, | ||
758 | { 0x14, 0x04 }, | ||
759 | { 0x15, 0x01 }, /* Lin and Win think different about UV order */ | ||
760 | { 0x16, 0x03 }, | ||
761 | { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */ | ||
762 | { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */ | ||
763 | { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */ | ||
764 | { 0x1a, 0xf5 }, | ||
765 | { 0x1b, 0x00 }, | ||
766 | { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */ | ||
767 | { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */ | ||
768 | { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */ | ||
769 | { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */ | ||
770 | { 0x26, 0xa2 }, | ||
771 | { 0x27, 0xea }, | ||
772 | { 0x28, 0x00 }, | ||
773 | { 0x29, 0x00 }, | ||
774 | { 0x2a, 0x80 }, | ||
775 | { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */ | ||
776 | { 0x2c, 0xac }, | ||
777 | { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */ | ||
778 | { 0x2e, 0x80 }, | ||
779 | { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */ | ||
780 | { 0x4c, 0x00 }, | ||
781 | { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */ | ||
782 | { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */ | ||
783 | { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */ | ||
784 | { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */ | ||
785 | { 0x63, 0xff }, | ||
786 | { 0x64, 0x53 }, /* new windrv 090403 says 0x57, | ||
787 | * maybe thats wrong */ | ||
788 | { 0x65, 0x00 }, | ||
789 | { 0x66, 0x55 }, | ||
790 | { 0x67, 0xb0 }, | ||
791 | { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */ | ||
792 | { 0x69, 0x02 }, | ||
793 | { 0x6a, 0x22 }, | ||
794 | { 0x6b, 0x00 }, | ||
795 | { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but | ||
796 | * deleting bit7 colors the first images red */ | ||
797 | { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */ | ||
798 | { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */ | ||
799 | { 0x6f, 0x01 }, | ||
800 | { 0x70, 0x8b }, | ||
801 | { 0x71, 0x00 }, | ||
802 | { 0x72, 0x14 }, | ||
803 | { 0x73, 0x54 }, | ||
804 | { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */ | ||
805 | { 0x75, 0x0e }, | ||
806 | { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */ | ||
807 | { 0x77, 0xff }, | ||
808 | { 0x78, 0x80 }, | ||
809 | { 0x79, 0x80 }, | ||
810 | { 0x7a, 0x80 }, | ||
811 | { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */ | ||
812 | { 0x7c, 0x00 }, | ||
813 | { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */ | ||
814 | { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */ | ||
815 | { 0x7f, 0xfb }, | ||
816 | { 0x80, 0x28 }, | ||
817 | { 0x81, 0x00 }, | ||
818 | { 0x82, 0x23 }, | ||
819 | { 0x83, 0x0b }, | ||
820 | { 0x84, 0x00 }, | ||
821 | { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */ | ||
822 | { 0x86, 0xc9 }, | ||
823 | { 0x87, 0x00 }, | ||
824 | { 0x88, 0x00 }, | ||
825 | { 0x89, 0x01 }, | ||
826 | { 0x12, 0x20 }, | ||
827 | { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */ | ||
828 | }; | ||
829 | |||
296 | static unsigned char ov7670_abs_to_sm(unsigned char v) | 830 | static unsigned char ov7670_abs_to_sm(unsigned char v) |
297 | { | 831 | { |
298 | if (v > 127) | 832 | if (v > 127) |
@@ -537,18 +1071,10 @@ static int ov51x_set_slave_ids(struct sd *sd, | |||
537 | rc = reg_w(sd, R51x_I2C_W_SID, slave); | 1071 | rc = reg_w(sd, R51x_I2C_W_SID, slave); |
538 | if (rc < 0) | 1072 | if (rc < 0) |
539 | return rc; | 1073 | return rc; |
1074 | sd->primary_i2c_slave = slave; | ||
540 | return reg_w(sd, R51x_I2C_R_SID, slave + 1); | 1075 | return reg_w(sd, R51x_I2C_R_SID, slave + 1); |
541 | } | 1076 | } |
542 | 1077 | ||
543 | struct ov_regvals { | ||
544 | __u8 reg; | ||
545 | __u8 val; | ||
546 | }; | ||
547 | struct ov_i2c_regvals { | ||
548 | __u8 reg; | ||
549 | __u8 val; | ||
550 | }; | ||
551 | |||
552 | static int write_regvals(struct sd *sd, | 1078 | static int write_regvals(struct sd *sd, |
553 | const struct ov_regvals *regvals, | 1079 | const struct ov_regvals *regvals, |
554 | int n) | 1080 | int n) |
@@ -591,101 +1117,9 @@ static int write_i2c_regvals(struct sd *sd, | |||
591 | static int ov8xx0_configure(struct sd *sd) | 1117 | static int ov8xx0_configure(struct sd *sd) |
592 | { | 1118 | { |
593 | int rc; | 1119 | int rc; |
594 | static const struct ov_i2c_regvals norm_8610[] = { | ||
595 | { 0x12, 0x80 }, | ||
596 | { 0x00, 0x00 }, | ||
597 | { 0x01, 0x80 }, | ||
598 | { 0x02, 0x80 }, | ||
599 | { 0x03, 0xc0 }, | ||
600 | { 0x04, 0x30 }, | ||
601 | { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */ | ||
602 | { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */ | ||
603 | { 0x0a, 0x86 }, | ||
604 | { 0x0b, 0xb0 }, | ||
605 | { 0x0c, 0x20 }, | ||
606 | { 0x0d, 0x20 }, | ||
607 | { 0x11, 0x01 }, | ||
608 | { 0x12, 0x25 }, | ||
609 | { 0x13, 0x01 }, | ||
610 | { 0x14, 0x04 }, | ||
611 | { 0x15, 0x01 }, /* Lin and Win think different about UV order */ | ||
612 | { 0x16, 0x03 }, | ||
613 | { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */ | ||
614 | { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */ | ||
615 | { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */ | ||
616 | { 0x1a, 0xf5 }, | ||
617 | { 0x1b, 0x00 }, | ||
618 | { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */ | ||
619 | { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */ | ||
620 | { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */ | ||
621 | { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */ | ||
622 | { 0x26, 0xa2 }, | ||
623 | { 0x27, 0xea }, | ||
624 | { 0x28, 0x00 }, | ||
625 | { 0x29, 0x00 }, | ||
626 | { 0x2a, 0x80 }, | ||
627 | { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */ | ||
628 | { 0x2c, 0xac }, | ||
629 | { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */ | ||
630 | { 0x2e, 0x80 }, | ||
631 | { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */ | ||
632 | { 0x4c, 0x00 }, | ||
633 | { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */ | ||
634 | { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */ | ||
635 | { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */ | ||
636 | { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */ | ||
637 | { 0x63, 0xff }, | ||
638 | { 0x64, 0x53 }, /* new windrv 090403 says 0x57, | ||
639 | * maybe thats wrong */ | ||
640 | { 0x65, 0x00 }, | ||
641 | { 0x66, 0x55 }, | ||
642 | { 0x67, 0xb0 }, | ||
643 | { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */ | ||
644 | { 0x69, 0x02 }, | ||
645 | { 0x6a, 0x22 }, | ||
646 | { 0x6b, 0x00 }, | ||
647 | { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but | ||
648 | deleting bit7 colors the first images red */ | ||
649 | { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */ | ||
650 | { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */ | ||
651 | { 0x6f, 0x01 }, | ||
652 | { 0x70, 0x8b }, | ||
653 | { 0x71, 0x00 }, | ||
654 | { 0x72, 0x14 }, | ||
655 | { 0x73, 0x54 }, | ||
656 | { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */ | ||
657 | { 0x75, 0x0e }, | ||
658 | { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */ | ||
659 | { 0x77, 0xff }, | ||
660 | { 0x78, 0x80 }, | ||
661 | { 0x79, 0x80 }, | ||
662 | { 0x7a, 0x80 }, | ||
663 | { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */ | ||
664 | { 0x7c, 0x00 }, | ||
665 | { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */ | ||
666 | { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */ | ||
667 | { 0x7f, 0xfb }, | ||
668 | { 0x80, 0x28 }, | ||
669 | { 0x81, 0x00 }, | ||
670 | { 0x82, 0x23 }, | ||
671 | { 0x83, 0x0b }, | ||
672 | { 0x84, 0x00 }, | ||
673 | { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */ | ||
674 | { 0x86, 0xc9 }, | ||
675 | { 0x87, 0x00 }, | ||
676 | { 0x88, 0x00 }, | ||
677 | { 0x89, 0x01 }, | ||
678 | { 0x12, 0x20 }, | ||
679 | { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */ | ||
680 | }; | ||
681 | 1120 | ||
682 | PDEBUG(D_PROBE, "starting ov8xx0 configuration"); | 1121 | PDEBUG(D_PROBE, "starting ov8xx0 configuration"); |
683 | 1122 | ||
684 | if (init_ov_sensor(sd) < 0) | ||
685 | PDEBUG(D_ERR|D_PROBE, "Failed to read sensor ID"); | ||
686 | else | ||
687 | PDEBUG(D_PROBE, "OV86x0 initialized"); | ||
688 | |||
689 | /* Detect sensor (sub)type */ | 1123 | /* Detect sensor (sub)type */ |
690 | rc = i2c_r(sd, OV7610_REG_COM_I); | 1124 | rc = i2c_r(sd, OV7610_REG_COM_I); |
691 | if (rc < 0) { | 1125 | if (rc < 0) { |
@@ -698,9 +1132,6 @@ static int ov8xx0_configure(struct sd *sd) | |||
698 | PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3); | 1132 | PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3); |
699 | return -1; | 1133 | return -1; |
700 | } | 1134 | } |
701 | PDEBUG(D_PROBE, "Writing 8610 registers"); | ||
702 | if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610))) | ||
703 | return -1; | ||
704 | 1135 | ||
705 | /* Set sensor-specific vars */ | 1136 | /* Set sensor-specific vars */ |
706 | /* sd->sif = 0; already done */ | 1137 | /* sd->sif = 0; already done */ |
@@ -714,252 +1145,6 @@ static int ov7xx0_configure(struct sd *sd) | |||
714 | { | 1145 | { |
715 | int rc, high, low; | 1146 | int rc, high, low; |
716 | 1147 | ||
717 | /* Lawrence Glaister <lg@jfm.bc.ca> reports: | ||
718 | * | ||
719 | * Register 0x0f in the 7610 has the following effects: | ||
720 | * | ||
721 | * 0x85 (AEC method 1): Best overall, good contrast range | ||
722 | * 0x45 (AEC method 2): Very overexposed | ||
723 | * 0xa5 (spec sheet default): Ok, but the black level is | ||
724 | * shifted resulting in loss of contrast | ||
725 | * 0x05 (old driver setting): very overexposed, too much | ||
726 | * contrast | ||
727 | */ | ||
728 | static const struct ov_i2c_regvals norm_7610[] = { | ||
729 | { 0x10, 0xff }, | ||
730 | { 0x16, 0x06 }, | ||
731 | { 0x28, 0x24 }, | ||
732 | { 0x2b, 0xac }, | ||
733 | { 0x12, 0x00 }, | ||
734 | { 0x38, 0x81 }, | ||
735 | { 0x28, 0x24 }, /* 0c */ | ||
736 | { 0x0f, 0x85 }, /* lg's setting */ | ||
737 | { 0x15, 0x01 }, | ||
738 | { 0x20, 0x1c }, | ||
739 | { 0x23, 0x2a }, | ||
740 | { 0x24, 0x10 }, | ||
741 | { 0x25, 0x8a }, | ||
742 | { 0x26, 0xa2 }, | ||
743 | { 0x27, 0xc2 }, | ||
744 | { 0x2a, 0x04 }, | ||
745 | { 0x2c, 0xfe }, | ||
746 | { 0x2d, 0x93 }, | ||
747 | { 0x30, 0x71 }, | ||
748 | { 0x31, 0x60 }, | ||
749 | { 0x32, 0x26 }, | ||
750 | { 0x33, 0x20 }, | ||
751 | { 0x34, 0x48 }, | ||
752 | { 0x12, 0x24 }, | ||
753 | { 0x11, 0x01 }, | ||
754 | { 0x0c, 0x24 }, | ||
755 | { 0x0d, 0x24 }, | ||
756 | }; | ||
757 | |||
758 | static const struct ov_i2c_regvals norm_7620[] = { | ||
759 | { 0x00, 0x00 }, /* gain */ | ||
760 | { 0x01, 0x80 }, /* blue gain */ | ||
761 | { 0x02, 0x80 }, /* red gain */ | ||
762 | { 0x03, 0xc0 }, /* OV7670_REG_VREF */ | ||
763 | { 0x06, 0x60 }, | ||
764 | { 0x07, 0x00 }, | ||
765 | { 0x0c, 0x24 }, | ||
766 | { 0x0c, 0x24 }, | ||
767 | { 0x0d, 0x24 }, | ||
768 | { 0x11, 0x01 }, | ||
769 | { 0x12, 0x24 }, | ||
770 | { 0x13, 0x01 }, | ||
771 | { 0x14, 0x84 }, | ||
772 | { 0x15, 0x01 }, | ||
773 | { 0x16, 0x03 }, | ||
774 | { 0x17, 0x2f }, | ||
775 | { 0x18, 0xcf }, | ||
776 | { 0x19, 0x06 }, | ||
777 | { 0x1a, 0xf5 }, | ||
778 | { 0x1b, 0x00 }, | ||
779 | { 0x20, 0x18 }, | ||
780 | { 0x21, 0x80 }, | ||
781 | { 0x22, 0x80 }, | ||
782 | { 0x23, 0x00 }, | ||
783 | { 0x26, 0xa2 }, | ||
784 | { 0x27, 0xea }, | ||
785 | { 0x28, 0x20 }, | ||
786 | { 0x29, 0x00 }, | ||
787 | { 0x2a, 0x10 }, | ||
788 | { 0x2b, 0x00 }, | ||
789 | { 0x2c, 0x88 }, | ||
790 | { 0x2d, 0x91 }, | ||
791 | { 0x2e, 0x80 }, | ||
792 | { 0x2f, 0x44 }, | ||
793 | { 0x60, 0x27 }, | ||
794 | { 0x61, 0x02 }, | ||
795 | { 0x62, 0x5f }, | ||
796 | { 0x63, 0xd5 }, | ||
797 | { 0x64, 0x57 }, | ||
798 | { 0x65, 0x83 }, | ||
799 | { 0x66, 0x55 }, | ||
800 | { 0x67, 0x92 }, | ||
801 | { 0x68, 0xcf }, | ||
802 | { 0x69, 0x76 }, | ||
803 | { 0x6a, 0x22 }, | ||
804 | { 0x6b, 0x00 }, | ||
805 | { 0x6c, 0x02 }, | ||
806 | { 0x6d, 0x44 }, | ||
807 | { 0x6e, 0x80 }, | ||
808 | { 0x6f, 0x1d }, | ||
809 | { 0x70, 0x8b }, | ||
810 | { 0x71, 0x00 }, | ||
811 | { 0x72, 0x14 }, | ||
812 | { 0x73, 0x54 }, | ||
813 | { 0x74, 0x00 }, | ||
814 | { 0x75, 0x8e }, | ||
815 | { 0x76, 0x00 }, | ||
816 | { 0x77, 0xff }, | ||
817 | { 0x78, 0x80 }, | ||
818 | { 0x79, 0x80 }, | ||
819 | { 0x7a, 0x80 }, | ||
820 | { 0x7b, 0xe2 }, | ||
821 | { 0x7c, 0x00 }, | ||
822 | }; | ||
823 | |||
824 | /* 7640 and 7648. The defaults should be OK for most registers. */ | ||
825 | static const struct ov_i2c_regvals norm_7640[] = { | ||
826 | { 0x12, 0x80 }, | ||
827 | { 0x12, 0x14 }, | ||
828 | }; | ||
829 | |||
830 | /* 7670. Defaults taken from OmniVision provided data, | ||
831 | * as provided by Jonathan Corbet of OLPC */ | ||
832 | static const struct ov_i2c_regvals norm_7670[] = { | ||
833 | { OV7670_REG_COM7, OV7670_COM7_RESET }, | ||
834 | { OV7670_REG_TSLB, 0x04 }, /* OV */ | ||
835 | { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */ | ||
836 | { OV7670_REG_CLKRC, 0x01 }, | ||
837 | /* | ||
838 | * Set the hardware window. These values from OV don't entirely | ||
839 | * make sense - hstop is less than hstart. But they work... | ||
840 | */ | ||
841 | { OV7670_REG_HSTART, 0x13 }, { OV7670_REG_HSTOP, 0x01 }, | ||
842 | { OV7670_REG_HREF, 0xb6 }, { OV7670_REG_VSTART, 0x02 }, | ||
843 | { OV7670_REG_VSTOP, 0x7a }, { OV7670_REG_VREF, 0x0a }, | ||
844 | |||
845 | { OV7670_REG_COM3, 0 }, { OV7670_REG_COM14, 0 }, | ||
846 | /* Mystery scaling numbers */ | ||
847 | { 0x70, 0x3a }, { 0x71, 0x35 }, | ||
848 | { 0x72, 0x11 }, { 0x73, 0xf0 }, | ||
849 | { 0xa2, 0x02 }, | ||
850 | /* { OV7670_REG_COM10, 0x0 }, */ | ||
851 | |||
852 | /* Gamma curve values */ | ||
853 | { 0x7a, 0x20 }, | ||
854 | { 0x7b, 0x10 }, | ||
855 | { 0x7c, 0x1e }, | ||
856 | { 0x7d, 0x35 }, | ||
857 | { 0x7e, 0x5a }, { 0x7f, 0x69 }, | ||
858 | { 0x80, 0x76 }, { 0x81, 0x80 }, | ||
859 | { 0x82, 0x88 }, { 0x83, 0x8f }, | ||
860 | { 0x84, 0x96 }, { 0x85, 0xa3 }, | ||
861 | { 0x86, 0xaf }, { 0x87, 0xc4 }, | ||
862 | { 0x88, 0xd7 }, { 0x89, 0xe8 }, | ||
863 | |||
864 | /* AGC and AEC parameters. Note we start by disabling those features, | ||
865 | then turn them only after tweaking the values. */ | ||
866 | { OV7670_REG_COM8, OV7670_COM8_FASTAEC | ||
867 | | OV7670_COM8_AECSTEP | ||
868 | | OV7670_COM8_BFILT }, | ||
869 | { OV7670_REG_GAIN, 0 }, { OV7670_REG_AECH, 0 }, | ||
870 | { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */ | ||
871 | { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */ | ||
872 | { OV7670_REG_BD50MAX, 0x05 }, { OV7670_REG_BD60MAX, 0x07 }, | ||
873 | { OV7670_REG_AEW, 0x95 }, { OV7670_REG_AEB, 0x33 }, | ||
874 | { OV7670_REG_VPT, 0xe3 }, { OV7670_REG_HAECC1, 0x78 }, | ||
875 | { OV7670_REG_HAECC2, 0x68 }, | ||
876 | { 0xa1, 0x03 }, /* magic */ | ||
877 | { OV7670_REG_HAECC3, 0xd8 }, { OV7670_REG_HAECC4, 0xd8 }, | ||
878 | { OV7670_REG_HAECC5, 0xf0 }, { OV7670_REG_HAECC6, 0x90 }, | ||
879 | { OV7670_REG_HAECC7, 0x94 }, | ||
880 | { OV7670_REG_COM8, OV7670_COM8_FASTAEC | ||
881 | | OV7670_COM8_AECSTEP | ||
882 | | OV7670_COM8_BFILT | ||
883 | | OV7670_COM8_AGC | ||
884 | | OV7670_COM8_AEC }, | ||
885 | |||
886 | /* Almost all of these are magic "reserved" values. */ | ||
887 | { OV7670_REG_COM5, 0x61 }, { OV7670_REG_COM6, 0x4b }, | ||
888 | { 0x16, 0x02 }, | ||
889 | { OV7670_REG_MVFP, 0x07 }, | ||
890 | { 0x21, 0x02 }, { 0x22, 0x91 }, | ||
891 | { 0x29, 0x07 }, { 0x33, 0x0b }, | ||
892 | { 0x35, 0x0b }, { 0x37, 0x1d }, | ||
893 | { 0x38, 0x71 }, { 0x39, 0x2a }, | ||
894 | { OV7670_REG_COM12, 0x78 }, { 0x4d, 0x40 }, | ||
895 | { 0x4e, 0x20 }, { OV7670_REG_GFIX, 0 }, | ||
896 | { 0x6b, 0x4a }, { 0x74, 0x10 }, | ||
897 | { 0x8d, 0x4f }, { 0x8e, 0 }, | ||
898 | { 0x8f, 0 }, { 0x90, 0 }, | ||
899 | { 0x91, 0 }, { 0x96, 0 }, | ||
900 | { 0x9a, 0 }, { 0xb0, 0x84 }, | ||
901 | { 0xb1, 0x0c }, { 0xb2, 0x0e }, | ||
902 | { 0xb3, 0x82 }, { 0xb8, 0x0a }, | ||
903 | |||
904 | /* More reserved magic, some of which tweaks white balance */ | ||
905 | { 0x43, 0x0a }, { 0x44, 0xf0 }, | ||
906 | { 0x45, 0x34 }, { 0x46, 0x58 }, | ||
907 | { 0x47, 0x28 }, { 0x48, 0x3a }, | ||
908 | { 0x59, 0x88 }, { 0x5a, 0x88 }, | ||
909 | { 0x5b, 0x44 }, { 0x5c, 0x67 }, | ||
910 | { 0x5d, 0x49 }, { 0x5e, 0x0e }, | ||
911 | { 0x6c, 0x0a }, { 0x6d, 0x55 }, | ||
912 | { 0x6e, 0x11 }, { 0x6f, 0x9f }, | ||
913 | /* "9e for advance AWB" */ | ||
914 | { 0x6a, 0x40 }, { OV7670_REG_BLUE, 0x40 }, | ||
915 | { OV7670_REG_RED, 0x60 }, | ||
916 | { OV7670_REG_COM8, OV7670_COM8_FASTAEC | ||
917 | | OV7670_COM8_AECSTEP | ||
918 | | OV7670_COM8_BFILT | ||
919 | | OV7670_COM8_AGC | ||
920 | | OV7670_COM8_AEC | ||
921 | | OV7670_COM8_AWB }, | ||
922 | |||
923 | /* Matrix coefficients */ | ||
924 | { 0x4f, 0x80 }, { 0x50, 0x80 }, | ||
925 | { 0x51, 0 }, { 0x52, 0x22 }, | ||
926 | { 0x53, 0x5e }, { 0x54, 0x80 }, | ||
927 | { 0x58, 0x9e }, | ||
928 | |||
929 | { OV7670_REG_COM16, OV7670_COM16_AWBGAIN }, | ||
930 | { OV7670_REG_EDGE, 0 }, | ||
931 | { 0x75, 0x05 }, { 0x76, 0xe1 }, | ||
932 | { 0x4c, 0 }, { 0x77, 0x01 }, | ||
933 | { OV7670_REG_COM13, OV7670_COM13_GAMMA | ||
934 | | OV7670_COM13_UVSAT | ||
935 | | 2}, /* was 3 */ | ||
936 | { 0x4b, 0x09 }, | ||
937 | { 0xc9, 0x60 }, { OV7670_REG_COM16, 0x38 }, | ||
938 | { 0x56, 0x40 }, | ||
939 | |||
940 | { 0x34, 0x11 }, | ||
941 | { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO }, | ||
942 | { 0xa4, 0x88 }, { 0x96, 0 }, | ||
943 | { 0x97, 0x30 }, { 0x98, 0x20 }, | ||
944 | { 0x99, 0x30 }, { 0x9a, 0x84 }, | ||
945 | { 0x9b, 0x29 }, { 0x9c, 0x03 }, | ||
946 | { 0x9d, 0x4c }, { 0x9e, 0x3f }, | ||
947 | { 0x78, 0x04 }, | ||
948 | |||
949 | /* Extra-weird stuff. Some sort of multiplexor register */ | ||
950 | { 0x79, 0x01 }, { 0xc8, 0xf0 }, | ||
951 | { 0x79, 0x0f }, { 0xc8, 0x00 }, | ||
952 | { 0x79, 0x10 }, { 0xc8, 0x7e }, | ||
953 | { 0x79, 0x0a }, { 0xc8, 0x80 }, | ||
954 | { 0x79, 0x0b }, { 0xc8, 0x01 }, | ||
955 | { 0x79, 0x0c }, { 0xc8, 0x0f }, | ||
956 | { 0x79, 0x0d }, { 0xc8, 0x20 }, | ||
957 | { 0x79, 0x09 }, { 0xc8, 0x80 }, | ||
958 | { 0x79, 0x02 }, { 0xc8, 0xc0 }, | ||
959 | { 0x79, 0x03 }, { 0xc8, 0x40 }, | ||
960 | { 0x79, 0x05 }, { 0xc8, 0x30 }, | ||
961 | { 0x79, 0x26 }, | ||
962 | }; | ||
963 | 1148 | ||
964 | PDEBUG(D_PROBE, "starting OV7xx0 configuration"); | 1149 | PDEBUG(D_PROBE, "starting OV7xx0 configuration"); |
965 | 1150 | ||
@@ -1011,8 +1196,9 @@ static int ov7xx0_configure(struct sd *sd) | |||
1011 | switch (low) { | 1196 | switch (low) { |
1012 | case 0x30: | 1197 | case 0x30: |
1013 | PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635"); | 1198 | PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635"); |
1014 | sd->sensor = SEN_OV7630; | 1199 | PDEBUG(D_ERR, |
1015 | break; | 1200 | "7630 is not supported by this driver"); |
1201 | return -1; | ||
1016 | case 0x40: | 1202 | case 0x40: |
1017 | PDEBUG(D_PROBE, "Sensor is an OV7645"); | 1203 | PDEBUG(D_PROBE, "Sensor is an OV7645"); |
1018 | sd->sensor = SEN_OV7640; /* FIXME */ | 1204 | sd->sensor = SEN_OV7640; /* FIXME */ |
@@ -1038,32 +1224,6 @@ static int ov7xx0_configure(struct sd *sd) | |||
1038 | return -1; | 1224 | return -1; |
1039 | } | 1225 | } |
1040 | 1226 | ||
1041 | switch (sd->sensor) { | ||
1042 | case SEN_OV7620: | ||
1043 | PDEBUG(D_PROBE, "Writing 7620 registers"); | ||
1044 | if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620))) | ||
1045 | return -1; | ||
1046 | break; | ||
1047 | case SEN_OV7630: | ||
1048 | PDEBUG(D_ERR, "7630 is not supported by this driver version"); | ||
1049 | return -1; | ||
1050 | case SEN_OV7640: | ||
1051 | PDEBUG(D_PROBE, "Writing 7640 registers"); | ||
1052 | if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640))) | ||
1053 | return -1; | ||
1054 | break; | ||
1055 | case SEN_OV7670: | ||
1056 | PDEBUG(D_PROBE, "Writing 7670 registers"); | ||
1057 | if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670))) | ||
1058 | return -1; | ||
1059 | break; | ||
1060 | default: | ||
1061 | PDEBUG(D_PROBE, "Writing 7610 registers"); | ||
1062 | if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610))) | ||
1063 | return -1; | ||
1064 | break; | ||
1065 | } | ||
1066 | |||
1067 | /* Set sensor-specific vars */ | 1227 | /* Set sensor-specific vars */ |
1068 | /* sd->sif = 0; already done */ | 1228 | /* sd->sif = 0; already done */ |
1069 | return 0; | 1229 | return 0; |
@@ -1073,141 +1233,7 @@ static int ov7xx0_configure(struct sd *sd) | |||
1073 | static int ov6xx0_configure(struct sd *sd) | 1233 | static int ov6xx0_configure(struct sd *sd) |
1074 | { | 1234 | { |
1075 | int rc; | 1235 | int rc; |
1076 | static const struct ov_i2c_regvals norm_6x20[] = { | 1236 | PDEBUG(D_PROBE, "starting OV6xx0 configuration"); |
1077 | { 0x12, 0x80 }, /* reset */ | ||
1078 | { 0x11, 0x01 }, | ||
1079 | { 0x03, 0x60 }, | ||
1080 | { 0x05, 0x7f }, /* For when autoadjust is off */ | ||
1081 | { 0x07, 0xa8 }, | ||
1082 | /* The ratio of 0x0c and 0x0d controls the white point */ | ||
1083 | { 0x0c, 0x24 }, | ||
1084 | { 0x0d, 0x24 }, | ||
1085 | { 0x0f, 0x15 }, /* COMS */ | ||
1086 | { 0x10, 0x75 }, /* AEC Exposure time */ | ||
1087 | { 0x12, 0x24 }, /* Enable AGC */ | ||
1088 | { 0x14, 0x04 }, | ||
1089 | /* 0x16: 0x06 helps frame stability with moving objects */ | ||
1090 | { 0x16, 0x06 }, | ||
1091 | /* { 0x20, 0x30 }, * Aperture correction enable */ | ||
1092 | { 0x26, 0xb2 }, /* BLC enable */ | ||
1093 | /* 0x28: 0x05 Selects RGB format if RGB on */ | ||
1094 | { 0x28, 0x05 }, | ||
1095 | { 0x2a, 0x04 }, /* Disable framerate adjust */ | ||
1096 | /* { 0x2b, 0xac }, * Framerate; Set 2a[7] first */ | ||
1097 | { 0x2d, 0x99 }, | ||
1098 | { 0x33, 0xa0 }, /* Color Processing Parameter */ | ||
1099 | { 0x34, 0xd2 }, /* Max A/D range */ | ||
1100 | { 0x38, 0x8b }, | ||
1101 | { 0x39, 0x40 }, | ||
1102 | |||
1103 | { 0x3c, 0x39 }, /* Enable AEC mode changing */ | ||
1104 | { 0x3c, 0x3c }, /* Change AEC mode */ | ||
1105 | { 0x3c, 0x24 }, /* Disable AEC mode changing */ | ||
1106 | |||
1107 | { 0x3d, 0x80 }, | ||
1108 | /* These next two registers (0x4a, 0x4b) are undocumented. | ||
1109 | * They control the color balance */ | ||
1110 | { 0x4a, 0x80 }, | ||
1111 | { 0x4b, 0x80 }, | ||
1112 | { 0x4d, 0xd2 }, /* This reduces noise a bit */ | ||
1113 | { 0x4e, 0xc1 }, | ||
1114 | { 0x4f, 0x04 }, | ||
1115 | /* Do 50-53 have any effect? */ | ||
1116 | /* Toggle 0x12[2] off and on here? */ | ||
1117 | }; | ||
1118 | |||
1119 | static const struct ov_i2c_regvals norm_6x30[] = { | ||
1120 | { 0x12, 0x80 }, /* Reset */ | ||
1121 | { 0x00, 0x1f }, /* Gain */ | ||
1122 | { 0x01, 0x99 }, /* Blue gain */ | ||
1123 | { 0x02, 0x7c }, /* Red gain */ | ||
1124 | { 0x03, 0xc0 }, /* Saturation */ | ||
1125 | { 0x05, 0x0a }, /* Contrast */ | ||
1126 | { 0x06, 0x95 }, /* Brightness */ | ||
1127 | { 0x07, 0x2d }, /* Sharpness */ | ||
1128 | { 0x0c, 0x20 }, | ||
1129 | { 0x0d, 0x20 }, | ||
1130 | { 0x0e, 0x20 }, | ||
1131 | { 0x0f, 0x05 }, | ||
1132 | { 0x10, 0x9a }, | ||
1133 | { 0x11, 0x00 }, /* Pixel clock = fastest */ | ||
1134 | { 0x12, 0x24 }, /* Enable AGC and AWB */ | ||
1135 | { 0x13, 0x21 }, | ||
1136 | { 0x14, 0x80 }, | ||
1137 | { 0x15, 0x01 }, | ||
1138 | { 0x16, 0x03 }, | ||
1139 | { 0x17, 0x38 }, | ||
1140 | { 0x18, 0xea }, | ||
1141 | { 0x19, 0x04 }, | ||
1142 | { 0x1a, 0x93 }, | ||
1143 | { 0x1b, 0x00 }, | ||
1144 | { 0x1e, 0xc4 }, | ||
1145 | { 0x1f, 0x04 }, | ||
1146 | { 0x20, 0x20 }, | ||
1147 | { 0x21, 0x10 }, | ||
1148 | { 0x22, 0x88 }, | ||
1149 | { 0x23, 0xc0 }, /* Crystal circuit power level */ | ||
1150 | { 0x25, 0x9a }, /* Increase AEC black ratio */ | ||
1151 | { 0x26, 0xb2 }, /* BLC enable */ | ||
1152 | { 0x27, 0xa2 }, | ||
1153 | { 0x28, 0x00 }, | ||
1154 | { 0x29, 0x00 }, | ||
1155 | { 0x2a, 0x84 }, /* 60 Hz power */ | ||
1156 | { 0x2b, 0xa8 }, /* 60 Hz power */ | ||
1157 | { 0x2c, 0xa0 }, | ||
1158 | { 0x2d, 0x95 }, /* Enable auto-brightness */ | ||
1159 | { 0x2e, 0x88 }, | ||
1160 | { 0x33, 0x26 }, | ||
1161 | { 0x34, 0x03 }, | ||
1162 | { 0x36, 0x8f }, | ||
1163 | { 0x37, 0x80 }, | ||
1164 | { 0x38, 0x83 }, | ||
1165 | { 0x39, 0x80 }, | ||
1166 | { 0x3a, 0x0f }, | ||
1167 | { 0x3b, 0x3c }, | ||
1168 | { 0x3c, 0x1a }, | ||
1169 | { 0x3d, 0x80 }, | ||
1170 | { 0x3e, 0x80 }, | ||
1171 | { 0x3f, 0x0e }, | ||
1172 | { 0x40, 0x00 }, /* White bal */ | ||
1173 | { 0x41, 0x00 }, /* White bal */ | ||
1174 | { 0x42, 0x80 }, | ||
1175 | { 0x43, 0x3f }, /* White bal */ | ||
1176 | { 0x44, 0x80 }, | ||
1177 | { 0x45, 0x20 }, | ||
1178 | { 0x46, 0x20 }, | ||
1179 | { 0x47, 0x80 }, | ||
1180 | { 0x48, 0x7f }, | ||
1181 | { 0x49, 0x00 }, | ||
1182 | { 0x4a, 0x00 }, | ||
1183 | { 0x4b, 0x80 }, | ||
1184 | { 0x4c, 0xd0 }, | ||
1185 | { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ | ||
1186 | { 0x4e, 0x40 }, | ||
1187 | { 0x4f, 0x07 }, /* UV avg., col. killer: max */ | ||
1188 | { 0x50, 0xff }, | ||
1189 | { 0x54, 0x23 }, /* Max AGC gain: 18dB */ | ||
1190 | { 0x55, 0xff }, | ||
1191 | { 0x56, 0x12 }, | ||
1192 | { 0x57, 0x81 }, | ||
1193 | { 0x58, 0x75 }, | ||
1194 | { 0x59, 0x01 }, /* AGC dark current comp.: +1 */ | ||
1195 | { 0x5a, 0x2c }, | ||
1196 | { 0x5b, 0x0f }, /* AWB chrominance levels */ | ||
1197 | { 0x5c, 0x10 }, | ||
1198 | { 0x3d, 0x80 }, | ||
1199 | { 0x27, 0xa6 }, | ||
1200 | { 0x12, 0x20 }, /* Toggle AWB */ | ||
1201 | { 0x12, 0x24 }, | ||
1202 | }; | ||
1203 | |||
1204 | PDEBUG(D_PROBE, "starting sensor configuration"); | ||
1205 | |||
1206 | if (init_ov_sensor(sd) < 0) { | ||
1207 | PDEBUG(D_ERR, "Failed to read sensor ID."); | ||
1208 | return -1; | ||
1209 | } | ||
1210 | PDEBUG(D_PROBE, "OV6xx0 sensor detected"); | ||
1211 | 1237 | ||
1212 | /* Detect sensor (sub)type */ | 1238 | /* Detect sensor (sub)type */ |
1213 | rc = i2c_r(sd, OV7610_REG_COM_I); | 1239 | rc = i2c_r(sd, OV7610_REG_COM_I); |
@@ -1251,15 +1277,6 @@ static int ov6xx0_configure(struct sd *sd) | |||
1251 | /* Set sensor-specific vars */ | 1277 | /* Set sensor-specific vars */ |
1252 | sd->sif = 1; | 1278 | sd->sif = 1; |
1253 | 1279 | ||
1254 | if (sd->sensor == SEN_OV6620) { | ||
1255 | PDEBUG(D_PROBE, "Writing 6x20 registers"); | ||
1256 | if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20))) | ||
1257 | return -1; | ||
1258 | } else { | ||
1259 | PDEBUG(D_PROBE, "Writing 6x30 registers"); | ||
1260 | if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30))) | ||
1261 | return -1; | ||
1262 | } | ||
1263 | return 0; | 1280 | return 0; |
1264 | } | 1281 | } |
1265 | 1282 | ||
@@ -1298,22 +1315,31 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
1298 | ov51x_led_control(sd, 0); /* turn LED off */ | 1315 | ov51x_led_control(sd, 0); /* turn LED off */ |
1299 | 1316 | ||
1300 | /* Test for 76xx */ | 1317 | /* Test for 76xx */ |
1301 | sd->primary_i2c_slave = OV7xx0_SID; | ||
1302 | if (ov51x_set_slave_ids(sd, OV7xx0_SID) < 0) | 1318 | if (ov51x_set_slave_ids(sd, OV7xx0_SID) < 0) |
1303 | goto error; | 1319 | goto error; |
1304 | 1320 | ||
1305 | /* The OV519 must be more aggressive about sensor detection since | 1321 | /* The OV519 must be more aggressive about sensor detection since |
1306 | * I2C write will never fail if the sensor is not present. We have | 1322 | * I2C write will never fail if the sensor is not present. We have |
1307 | * to try to initialize the sensor to detect its presence */ | 1323 | * to try to initialize the sensor to detect its presence */ |
1308 | if (init_ov_sensor(sd) < 0) { | 1324 | if (init_ov_sensor(sd) >= 0) { |
1325 | if (ov7xx0_configure(sd) < 0) { | ||
1326 | PDEBUG(D_ERR, "Failed to configure OV7xx0"); | ||
1327 | goto error; | ||
1328 | } | ||
1329 | } else { | ||
1330 | |||
1309 | /* Test for 6xx0 */ | 1331 | /* Test for 6xx0 */ |
1310 | sd->primary_i2c_slave = OV6xx0_SID; | ||
1311 | if (ov51x_set_slave_ids(sd, OV6xx0_SID) < 0) | 1332 | if (ov51x_set_slave_ids(sd, OV6xx0_SID) < 0) |
1312 | goto error; | 1333 | goto error; |
1313 | 1334 | ||
1314 | if (init_ov_sensor(sd) < 0) { | 1335 | if (init_ov_sensor(sd) >= 0) { |
1336 | if (ov6xx0_configure(sd) < 0) { | ||
1337 | PDEBUG(D_ERR, "Failed to configure OV6xx0"); | ||
1338 | goto error; | ||
1339 | } | ||
1340 | } else { | ||
1341 | |||
1315 | /* Test for 8xx0 */ | 1342 | /* Test for 8xx0 */ |
1316 | sd->primary_i2c_slave = OV8xx0_SID; | ||
1317 | if (ov51x_set_slave_ids(sd, OV8xx0_SID) < 0) | 1343 | if (ov51x_set_slave_ids(sd, OV8xx0_SID) < 0) |
1318 | goto error; | 1344 | goto error; |
1319 | 1345 | ||
@@ -1321,24 +1347,13 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
1321 | PDEBUG(D_ERR, | 1347 | PDEBUG(D_ERR, |
1322 | "Can't determine sensor slave IDs"); | 1348 | "Can't determine sensor slave IDs"); |
1323 | goto error; | 1349 | goto error; |
1324 | } else { | ||
1325 | if (ov8xx0_configure(sd) < 0) { | ||
1326 | PDEBUG(D_ERR, | ||
1327 | "Failed to configure OV8xx0 sensor"); | ||
1328 | goto error; | ||
1329 | } | ||
1330 | } | 1350 | } |
1331 | } else { | 1351 | if (ov8xx0_configure(sd) < 0) { |
1332 | if (ov6xx0_configure(sd) < 0) { | 1352 | PDEBUG(D_ERR, |
1333 | PDEBUG(D_ERR, "Failed to configure OV6xx0"); | 1353 | "Failed to configure OV8xx0 sensor"); |
1334 | goto error; | 1354 | goto error; |
1335 | } | 1355 | } |
1336 | } | 1356 | } |
1337 | } else { | ||
1338 | if (ov7xx0_configure(sd) < 0) { | ||
1339 | PDEBUG(D_ERR, "Failed to configure OV7xx0"); | ||
1340 | goto error; | ||
1341 | } | ||
1342 | } | 1357 | } |
1343 | 1358 | ||
1344 | cam = &gspca_dev->cam; | 1359 | cam = &gspca_dev->cam; |
@@ -1364,6 +1379,41 @@ error: | |||
1364 | /* this function is called at open time */ | 1379 | /* this function is called at open time */ |
1365 | static int sd_open(struct gspca_dev *gspca_dev) | 1380 | static int sd_open(struct gspca_dev *gspca_dev) |
1366 | { | 1381 | { |
1382 | struct sd *sd = (struct sd *) gspca_dev; | ||
1383 | |||
1384 | /* initialize the sensor */ | ||
1385 | switch (sd->sensor) { | ||
1386 | case SEN_OV6620: | ||
1387 | if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20))) | ||
1388 | return -EIO; | ||
1389 | break; | ||
1390 | case SEN_OV6630: | ||
1391 | if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30))) | ||
1392 | return -EIO; | ||
1393 | break; | ||
1394 | default: | ||
1395 | /* case SEN_OV7610: */ | ||
1396 | /* case SEN_OV76BE: */ | ||
1397 | if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610))) | ||
1398 | return -EIO; | ||
1399 | break; | ||
1400 | case SEN_OV7620: | ||
1401 | if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620))) | ||
1402 | return -EIO; | ||
1403 | break; | ||
1404 | case SEN_OV7640: | ||
1405 | if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640))) | ||
1406 | return -EIO; | ||
1407 | break; | ||
1408 | case SEN_OV7670: | ||
1409 | if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670))) | ||
1410 | return -EIO; | ||
1411 | break; | ||
1412 | case SEN_OV8610: | ||
1413 | if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610))) | ||
1414 | return -EIO; | ||
1415 | break; | ||
1416 | } | ||
1367 | return 0; | 1417 | return 0; |
1368 | } | 1418 | } |
1369 | 1419 | ||