diff options
Diffstat (limited to 'drivers/media/video/pxa_camera.c')
-rw-r--r-- | drivers/media/video/pxa_camera.c | 156 |
1 files changed, 113 insertions, 43 deletions
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index a34a193249f6..4756699d16aa 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c | |||
@@ -581,64 +581,109 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd) | |||
581 | pcdev->icd = NULL; | 581 | pcdev->icd = NULL; |
582 | } | 582 | } |
583 | 583 | ||
584 | static int pxa_camera_set_capture_format(struct soc_camera_device *icd, | 584 | static int test_platform_param(struct pxa_camera_dev *pcdev, |
585 | __u32 pixfmt, struct v4l2_rect *rect) | 585 | unsigned char buswidth, unsigned long *flags) |
586 | { | 586 | { |
587 | struct soc_camera_host *ici = | 587 | /* |
588 | to_soc_camera_host(icd->dev.parent); | 588 | * Platform specified synchronization and pixel clock polarities are |
589 | struct pxa_camera_dev *pcdev = ici->priv; | 589 | * only a recommendation and are only used during probing. The PXA270 |
590 | unsigned int datawidth = 0, dw, bpp; | 590 | * quick capture interface supports both. |
591 | u32 cicr0, cicr4 = 0; | 591 | */ |
592 | int ret; | 592 | *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ? |
593 | SOCAM_MASTER : SOCAM_SLAVE) | | ||
594 | SOCAM_HSYNC_ACTIVE_HIGH | | ||
595 | SOCAM_HSYNC_ACTIVE_LOW | | ||
596 | SOCAM_VSYNC_ACTIVE_HIGH | | ||
597 | SOCAM_VSYNC_ACTIVE_LOW | | ||
598 | SOCAM_PCLK_SAMPLE_RISING | | ||
599 | SOCAM_PCLK_SAMPLE_FALLING; | ||
593 | 600 | ||
594 | /* If requested data width is supported by the platform, use it */ | 601 | /* If requested data width is supported by the platform, use it */ |
595 | switch (icd->cached_datawidth) { | 602 | switch (buswidth) { |
596 | case 10: | 603 | case 10: |
597 | if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10) | 604 | if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10)) |
598 | datawidth = IS_DATAWIDTH_10; | 605 | return -EINVAL; |
606 | *flags |= SOCAM_DATAWIDTH_10; | ||
599 | break; | 607 | break; |
600 | case 9: | 608 | case 9: |
601 | if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9) | 609 | if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9)) |
602 | datawidth = IS_DATAWIDTH_9; | 610 | return -EINVAL; |
611 | *flags |= SOCAM_DATAWIDTH_9; | ||
603 | break; | 612 | break; |
604 | case 8: | 613 | case 8: |
605 | if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8) | 614 | if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8)) |
606 | datawidth = IS_DATAWIDTH_8; | 615 | return -EINVAL; |
616 | *flags |= SOCAM_DATAWIDTH_8; | ||
607 | } | 617 | } |
608 | if (!datawidth) | 618 | |
619 | return 0; | ||
620 | } | ||
621 | |||
622 | static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | ||
623 | { | ||
624 | struct soc_camera_host *ici = | ||
625 | to_soc_camera_host(icd->dev.parent); | ||
626 | struct pxa_camera_dev *pcdev = ici->priv; | ||
627 | unsigned long dw, bpp, bus_flags, camera_flags, common_flags; | ||
628 | u32 cicr0, cicr4 = 0; | ||
629 | int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags); | ||
630 | |||
631 | if (ret < 0) | ||
632 | return ret; | ||
633 | |||
634 | camera_flags = icd->ops->query_bus_param(icd); | ||
635 | |||
636 | common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); | ||
637 | if (!common_flags) | ||
609 | return -EINVAL; | 638 | return -EINVAL; |
610 | 639 | ||
611 | ret = icd->ops->set_capture_format(icd, pixfmt, rect, | 640 | /* Make choises, based on platform preferences */ |
612 | datawidth | | 641 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && |
613 | (pcdev->platform_flags & PXA_CAMERA_MASTER ? | 642 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { |
614 | IS_MASTER : 0) | | 643 | if (pcdev->platform_flags & PXA_CAMERA_HSP) |
615 | (pcdev->platform_flags & PXA_CAMERA_HSP ? | 644 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; |
616 | 0 : IS_HSYNC_ACTIVE_HIGH) | | 645 | else |
617 | (pcdev->platform_flags & PXA_CAMERA_VSP ? | 646 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; |
618 | 0 : IS_VSYNC_ACTIVE_HIGH) | | 647 | } |
619 | (pcdev->platform_flags & PXA_CAMERA_PCP ? | 648 | |
620 | 0 : IS_PCLK_SAMPLE_RISING)); | 649 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && |
650 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | ||
651 | if (pcdev->platform_flags & PXA_CAMERA_VSP) | ||
652 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | ||
653 | else | ||
654 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | ||
655 | } | ||
656 | |||
657 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | ||
658 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | ||
659 | if (pcdev->platform_flags & PXA_CAMERA_PCP) | ||
660 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | ||
661 | else | ||
662 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | ||
663 | } | ||
664 | |||
665 | ret = icd->ops->set_bus_param(icd, common_flags); | ||
621 | if (ret < 0) | 666 | if (ret < 0) |
622 | return ret; | 667 | return ret; |
623 | 668 | ||
624 | /* Datawidth is now guaranteed to be equal to one of the three values. | 669 | /* Datawidth is now guaranteed to be equal to one of the three values. |
625 | * We fix bit-per-pixel equal to data-width... */ | 670 | * We fix bit-per-pixel equal to data-width... */ |
626 | switch (datawidth) { | 671 | switch (common_flags & SOCAM_DATAWIDTH_MASK) { |
627 | case IS_DATAWIDTH_10: | 672 | case SOCAM_DATAWIDTH_10: |
628 | icd->cached_datawidth = 10; | 673 | icd->buswidth = 10; |
629 | dw = 4; | 674 | dw = 4; |
630 | bpp = 0x40; | 675 | bpp = 0x40; |
631 | break; | 676 | break; |
632 | case IS_DATAWIDTH_9: | 677 | case SOCAM_DATAWIDTH_9: |
633 | icd->cached_datawidth = 9; | 678 | icd->buswidth = 9; |
634 | dw = 3; | 679 | dw = 3; |
635 | bpp = 0x20; | 680 | bpp = 0x20; |
636 | break; | 681 | break; |
637 | default: | 682 | default: |
638 | /* Actually it can only be 8 now, | 683 | /* Actually it can only be 8 now, |
639 | * default is just to silence compiler warnings */ | 684 | * default is just to silence compiler warnings */ |
640 | case IS_DATAWIDTH_8: | 685 | case SOCAM_DATAWIDTH_8: |
641 | icd->cached_datawidth = 8; | 686 | icd->buswidth = 8; |
642 | dw = 2; | 687 | dw = 2; |
643 | bpp = 0; | 688 | bpp = 0; |
644 | } | 689 | } |
@@ -647,19 +692,19 @@ static int pxa_camera_set_capture_format(struct soc_camera_device *icd, | |||
647 | cicr4 |= CICR4_PCLK_EN; | 692 | cicr4 |= CICR4_PCLK_EN; |
648 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) | 693 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) |
649 | cicr4 |= CICR4_MCLK_EN; | 694 | cicr4 |= CICR4_MCLK_EN; |
650 | if (pcdev->platform_flags & PXA_CAMERA_PCP) | 695 | if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) |
651 | cicr4 |= CICR4_PCP; | 696 | cicr4 |= CICR4_PCP; |
652 | if (pcdev->platform_flags & PXA_CAMERA_HSP) | 697 | if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) |
653 | cicr4 |= CICR4_HSP; | 698 | cicr4 |= CICR4_HSP; |
654 | if (pcdev->platform_flags & PXA_CAMERA_VSP) | 699 | if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) |
655 | cicr4 |= CICR4_VSP; | 700 | cicr4 |= CICR4_VSP; |
656 | 701 | ||
657 | cicr0 = CICR0; | 702 | cicr0 = CICR0; |
658 | if (cicr0 & CICR0_ENB) | 703 | if (cicr0 & CICR0_ENB) |
659 | CICR0 = cicr0 & ~CICR0_ENB; | 704 | CICR0 = cicr0 & ~CICR0_ENB; |
660 | CICR1 = CICR1_PPL_VAL(rect->width - 1) | bpp | dw; | 705 | CICR1 = CICR1_PPL_VAL(icd->width - 1) | bpp | dw; |
661 | CICR2 = 0; | 706 | CICR2 = 0; |
662 | CICR3 = CICR3_LPF_VAL(rect->height - 1) | | 707 | CICR3 = CICR3_LPF_VAL(icd->height - 1) | |
663 | CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top)); | 708 | CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top)); |
664 | CICR4 = mclk_get_divisor(pcdev) | cicr4; | 709 | CICR4 = mclk_get_divisor(pcdev) | cicr4; |
665 | 710 | ||
@@ -671,7 +716,29 @@ static int pxa_camera_set_capture_format(struct soc_camera_device *icd, | |||
671 | return 0; | 716 | return 0; |
672 | } | 717 | } |
673 | 718 | ||
674 | static int pxa_camera_try_fmt_cap(struct soc_camera_host *ici, | 719 | static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt) |
720 | { | ||
721 | struct soc_camera_host *ici = | ||
722 | to_soc_camera_host(icd->dev.parent); | ||
723 | struct pxa_camera_dev *pcdev = ici->priv; | ||
724 | unsigned long bus_flags, camera_flags; | ||
725 | int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags); | ||
726 | |||
727 | if (ret < 0) | ||
728 | return ret; | ||
729 | |||
730 | camera_flags = icd->ops->query_bus_param(icd); | ||
731 | |||
732 | return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL; | ||
733 | } | ||
734 | |||
735 | static int pxa_camera_set_fmt_cap(struct soc_camera_device *icd, | ||
736 | __u32 pixfmt, struct v4l2_rect *rect) | ||
737 | { | ||
738 | return icd->ops->set_fmt_cap(icd, pixfmt, rect); | ||
739 | } | ||
740 | |||
741 | static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd, | ||
675 | struct v4l2_format *f) | 742 | struct v4l2_format *f) |
676 | { | 743 | { |
677 | /* limit to pxa hardware capabilities */ | 744 | /* limit to pxa hardware capabilities */ |
@@ -685,7 +752,8 @@ static int pxa_camera_try_fmt_cap(struct soc_camera_host *ici, | |||
685 | f->fmt.pix.width = 2048; | 752 | f->fmt.pix.width = 2048; |
686 | f->fmt.pix.width &= ~0x01; | 753 | f->fmt.pix.width &= ~0x01; |
687 | 754 | ||
688 | return 0; | 755 | /* limit to sensor capabilities */ |
756 | return icd->ops->try_fmt_cap(icd, f); | ||
689 | } | 757 | } |
690 | 758 | ||
691 | static int pxa_camera_reqbufs(struct soc_camera_file *icf, | 759 | static int pxa_camera_reqbufs(struct soc_camera_file *icf, |
@@ -742,11 +810,13 @@ static struct soc_camera_host pxa_soc_camera_host = { | |||
742 | .add = pxa_camera_add_device, | 810 | .add = pxa_camera_add_device, |
743 | .remove = pxa_camera_remove_device, | 811 | .remove = pxa_camera_remove_device, |
744 | .msize = sizeof(struct pxa_buffer), | 812 | .msize = sizeof(struct pxa_buffer), |
745 | .set_capture_format = pxa_camera_set_capture_format, | 813 | .set_fmt_cap = pxa_camera_set_fmt_cap, |
746 | .try_fmt_cap = pxa_camera_try_fmt_cap, | 814 | .try_fmt_cap = pxa_camera_try_fmt_cap, |
747 | .reqbufs = pxa_camera_reqbufs, | 815 | .reqbufs = pxa_camera_reqbufs, |
748 | .poll = pxa_camera_poll, | 816 | .poll = pxa_camera_poll, |
749 | .querycap = pxa_camera_querycap, | 817 | .querycap = pxa_camera_querycap, |
818 | .try_bus_param = pxa_camera_try_bus_param, | ||
819 | .set_bus_param = pxa_camera_set_bus_param, | ||
750 | }; | 820 | }; |
751 | 821 | ||
752 | static int pxa_camera_probe(struct platform_device *pdev) | 822 | static int pxa_camera_probe(struct platform_device *pdev) |
@@ -782,8 +852,8 @@ static int pxa_camera_probe(struct platform_device *pdev) | |||
782 | 852 | ||
783 | pcdev->pdata = pdev->dev.platform_data; | 853 | pcdev->pdata = pdev->dev.platform_data; |
784 | pcdev->platform_flags = pcdev->pdata->flags; | 854 | pcdev->platform_flags = pcdev->pdata->flags; |
785 | if (!pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 | | 855 | if (!(pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 | |
786 | PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10)) { | 856 | PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10))) { |
787 | /* Platform hasn't set available data widths. This is bad. | 857 | /* Platform hasn't set available data widths. This is bad. |
788 | * Warn and use a default. */ | 858 | * Warn and use a default. */ |
789 | dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " | 859 | dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " |