aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/pxa_camera.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/pxa_camera.c')
-rw-r--r--drivers/media/video/pxa_camera.c156
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
584static int pxa_camera_set_capture_format(struct soc_camera_device *icd, 584static 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
622static 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
674static int pxa_camera_try_fmt_cap(struct soc_camera_host *ici, 719static 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
735static 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
741static 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
691static int pxa_camera_reqbufs(struct soc_camera_file *icf, 759static 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
752static int pxa_camera_probe(struct platform_device *pdev) 822static 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 "