diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/pxa_camera.c | 207 |
1 files changed, 165 insertions, 42 deletions
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 665eef236f5b..97923e1bd06d 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c | |||
@@ -765,6 +765,9 @@ static int test_platform_param(struct pxa_camera_dev *pcdev, | |||
765 | if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8)) | 765 | if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8)) |
766 | return -EINVAL; | 766 | return -EINVAL; |
767 | *flags |= SOCAM_DATAWIDTH_8; | 767 | *flags |= SOCAM_DATAWIDTH_8; |
768 | break; | ||
769 | default: | ||
770 | return -EINVAL; | ||
768 | } | 771 | } |
769 | 772 | ||
770 | return 0; | 773 | return 0; |
@@ -823,12 +826,10 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
823 | * We fix bit-per-pixel equal to data-width... */ | 826 | * We fix bit-per-pixel equal to data-width... */ |
824 | switch (common_flags & SOCAM_DATAWIDTH_MASK) { | 827 | switch (common_flags & SOCAM_DATAWIDTH_MASK) { |
825 | case SOCAM_DATAWIDTH_10: | 828 | case SOCAM_DATAWIDTH_10: |
826 | icd->buswidth = 10; | ||
827 | dw = 4; | 829 | dw = 4; |
828 | bpp = 0x40; | 830 | bpp = 0x40; |
829 | break; | 831 | break; |
830 | case SOCAM_DATAWIDTH_9: | 832 | case SOCAM_DATAWIDTH_9: |
831 | icd->buswidth = 9; | ||
832 | dw = 3; | 833 | dw = 3; |
833 | bpp = 0x20; | 834 | bpp = 0x20; |
834 | break; | 835 | break; |
@@ -836,7 +837,6 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
836 | /* Actually it can only be 8 now, | 837 | /* Actually it can only be 8 now, |
837 | * default is just to silence compiler warnings */ | 838 | * default is just to silence compiler warnings */ |
838 | case SOCAM_DATAWIDTH_8: | 839 | case SOCAM_DATAWIDTH_8: |
839 | icd->buswidth = 8; | ||
840 | dw = 2; | 840 | dw = 2; |
841 | bpp = 0; | 841 | bpp = 0; |
842 | } | 842 | } |
@@ -862,7 +862,17 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
862 | case V4L2_PIX_FMT_YUV422P: | 862 | case V4L2_PIX_FMT_YUV422P: |
863 | pcdev->channels = 3; | 863 | pcdev->channels = 3; |
864 | cicr1 |= CICR1_YCBCR_F; | 864 | cicr1 |= CICR1_YCBCR_F; |
865 | /* | ||
866 | * Normally, pxa bus wants as input UYVY format. We allow all | ||
867 | * reorderings of the YUV422 format, as no processing is done, | ||
868 | * and the YUV stream is just passed through without any | ||
869 | * transformation. Note that UYVY is the only format that | ||
870 | * should be used if pxa framebuffer Overlay2 is used. | ||
871 | */ | ||
872 | case V4L2_PIX_FMT_UYVY: | ||
873 | case V4L2_PIX_FMT_VYUY: | ||
865 | case V4L2_PIX_FMT_YUYV: | 874 | case V4L2_PIX_FMT_YUYV: |
875 | case V4L2_PIX_FMT_YVYU: | ||
866 | cicr1 |= CICR1_COLOR_SP_VAL(2); | 876 | cicr1 |= CICR1_COLOR_SP_VAL(2); |
867 | break; | 877 | break; |
868 | case V4L2_PIX_FMT_RGB555: | 878 | case V4L2_PIX_FMT_RGB555: |
@@ -888,13 +898,14 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
888 | return 0; | 898 | return 0; |
889 | } | 899 | } |
890 | 900 | ||
891 | static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | 901 | static int pxa_camera_try_bus_param(struct soc_camera_device *icd, |
902 | unsigned char buswidth) | ||
892 | { | 903 | { |
893 | struct soc_camera_host *ici = | 904 | struct soc_camera_host *ici = |
894 | to_soc_camera_host(icd->dev.parent); | 905 | to_soc_camera_host(icd->dev.parent); |
895 | struct pxa_camera_dev *pcdev = ici->priv; | 906 | struct pxa_camera_dev *pcdev = ici->priv; |
896 | unsigned long bus_flags, camera_flags; | 907 | unsigned long bus_flags, camera_flags; |
897 | int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags); | 908 | int ret = test_platform_param(pcdev, buswidth, &bus_flags); |
898 | 909 | ||
899 | if (ret < 0) | 910 | if (ret < 0) |
900 | return ret; | 911 | return ret; |
@@ -904,25 +915,139 @@ static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
904 | return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL; | 915 | return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL; |
905 | } | 916 | } |
906 | 917 | ||
918 | static const struct soc_camera_data_format pxa_camera_formats[] = { | ||
919 | { | ||
920 | .name = "Planar YUV422 16 bit", | ||
921 | .depth = 16, | ||
922 | .fourcc = V4L2_PIX_FMT_YUV422P, | ||
923 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
924 | }, | ||
925 | }; | ||
926 | |||
927 | static bool buswidth_supported(struct soc_camera_device *icd, int depth) | ||
928 | { | ||
929 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
930 | struct pxa_camera_dev *pcdev = ici->priv; | ||
931 | |||
932 | switch (depth) { | ||
933 | case 8: | ||
934 | return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8); | ||
935 | case 9: | ||
936 | return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9); | ||
937 | case 10: | ||
938 | return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10); | ||
939 | } | ||
940 | return false; | ||
941 | } | ||
942 | |||
943 | static int required_buswidth(const struct soc_camera_data_format *fmt) | ||
944 | { | ||
945 | switch (fmt->fourcc) { | ||
946 | case V4L2_PIX_FMT_UYVY: | ||
947 | case V4L2_PIX_FMT_VYUY: | ||
948 | case V4L2_PIX_FMT_YUYV: | ||
949 | case V4L2_PIX_FMT_YVYU: | ||
950 | case V4L2_PIX_FMT_RGB565: | ||
951 | case V4L2_PIX_FMT_RGB555: | ||
952 | return 8; | ||
953 | default: | ||
954 | return fmt->depth; | ||
955 | } | ||
956 | } | ||
957 | |||
958 | static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, | ||
959 | struct soc_camera_format_xlate *xlate) | ||
960 | { | ||
961 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
962 | int formats = 0, buswidth, ret; | ||
963 | |||
964 | buswidth = required_buswidth(icd->formats + idx); | ||
965 | |||
966 | if (!buswidth_supported(icd, buswidth)) | ||
967 | return 0; | ||
968 | |||
969 | ret = pxa_camera_try_bus_param(icd, buswidth); | ||
970 | if (ret < 0) | ||
971 | return 0; | ||
972 | |||
973 | switch (icd->formats[idx].fourcc) { | ||
974 | case V4L2_PIX_FMT_UYVY: | ||
975 | formats++; | ||
976 | if (xlate) { | ||
977 | xlate->host_fmt = &pxa_camera_formats[0]; | ||
978 | xlate->cam_fmt = icd->formats + idx; | ||
979 | xlate->buswidth = buswidth; | ||
980 | xlate++; | ||
981 | dev_dbg(&ici->dev, "Providing format %s using %s\n", | ||
982 | pxa_camera_formats[0].name, | ||
983 | icd->formats[idx].name); | ||
984 | } | ||
985 | case V4L2_PIX_FMT_VYUY: | ||
986 | case V4L2_PIX_FMT_YUYV: | ||
987 | case V4L2_PIX_FMT_YVYU: | ||
988 | case V4L2_PIX_FMT_RGB565: | ||
989 | case V4L2_PIX_FMT_RGB555: | ||
990 | formats++; | ||
991 | if (xlate) { | ||
992 | xlate->host_fmt = icd->formats + idx; | ||
993 | xlate->cam_fmt = icd->formats + idx; | ||
994 | xlate->buswidth = buswidth; | ||
995 | xlate++; | ||
996 | dev_dbg(&ici->dev, "Providing format %s packed\n", | ||
997 | icd->formats[idx].name); | ||
998 | } | ||
999 | break; | ||
1000 | default: | ||
1001 | /* Generic pass-through */ | ||
1002 | formats++; | ||
1003 | if (xlate) { | ||
1004 | xlate->host_fmt = icd->formats + idx; | ||
1005 | xlate->cam_fmt = icd->formats + idx; | ||
1006 | xlate->buswidth = icd->formats[idx].depth; | ||
1007 | xlate++; | ||
1008 | dev_dbg(&ici->dev, | ||
1009 | "Providing format %s in pass-through mode\n", | ||
1010 | icd->formats[idx].name); | ||
1011 | } | ||
1012 | } | ||
1013 | |||
1014 | return formats; | ||
1015 | } | ||
1016 | |||
907 | static int pxa_camera_set_fmt(struct soc_camera_device *icd, | 1017 | static int pxa_camera_set_fmt(struct soc_camera_device *icd, |
908 | __u32 pixfmt, struct v4l2_rect *rect) | 1018 | __u32 pixfmt, struct v4l2_rect *rect) |
909 | { | 1019 | { |
910 | const struct soc_camera_data_format *cam_fmt; | 1020 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
911 | int ret; | 1021 | const struct soc_camera_data_format *host_fmt, *cam_fmt = NULL; |
1022 | const struct soc_camera_format_xlate *xlate; | ||
1023 | int ret, buswidth; | ||
912 | 1024 | ||
913 | /* | 1025 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); |
914 | * TODO: find a suitable supported by the SoC output format, check | 1026 | if (!xlate) { |
915 | * whether the sensor supports one of acceptable input formats. | 1027 | dev_warn(&ici->dev, "Format %x not found\n", pixfmt); |
916 | */ | 1028 | return -EINVAL; |
917 | if (pixfmt) { | ||
918 | cam_fmt = soc_camera_format_by_fourcc(icd, pixfmt); | ||
919 | if (!cam_fmt) | ||
920 | return -EINVAL; | ||
921 | } | 1029 | } |
922 | 1030 | ||
923 | ret = icd->ops->set_fmt(icd, pixfmt, rect); | 1031 | buswidth = xlate->buswidth; |
924 | if (pixfmt && !ret) | 1032 | host_fmt = xlate->host_fmt; |
925 | icd->current_fmt = cam_fmt; | 1033 | cam_fmt = xlate->cam_fmt; |
1034 | |||
1035 | switch (pixfmt) { | ||
1036 | case 0: /* Only geometry change */ | ||
1037 | ret = icd->ops->set_fmt(icd, pixfmt, rect); | ||
1038 | break; | ||
1039 | default: | ||
1040 | ret = icd->ops->set_fmt(icd, cam_fmt->fourcc, rect); | ||
1041 | } | ||
1042 | |||
1043 | if (ret < 0) | ||
1044 | dev_warn(&ici->dev, "Failed to configure for format %x\n", | ||
1045 | pixfmt); | ||
1046 | |||
1047 | if (pixfmt && !ret) { | ||
1048 | icd->buswidth = buswidth; | ||
1049 | icd->current_fmt = host_fmt; | ||
1050 | } | ||
926 | 1051 | ||
927 | return ret; | 1052 | return ret; |
928 | } | 1053 | } |
@@ -930,34 +1055,31 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, | |||
930 | static int pxa_camera_try_fmt(struct soc_camera_device *icd, | 1055 | static int pxa_camera_try_fmt(struct soc_camera_device *icd, |
931 | struct v4l2_format *f) | 1056 | struct v4l2_format *f) |
932 | { | 1057 | { |
933 | const struct soc_camera_data_format *cam_fmt; | 1058 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
934 | int ret = pxa_camera_try_bus_param(icd, f->fmt.pix.pixelformat); | 1059 | const struct soc_camera_format_xlate *xlate; |
935 | 1060 | struct v4l2_pix_format *pix = &f->fmt.pix; | |
936 | if (ret < 0) | 1061 | __u32 pixfmt = pix->pixelformat; |
937 | return ret; | ||
938 | 1062 | ||
939 | /* | 1063 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); |
940 | * TODO: find a suitable supported by the SoC output format, check | 1064 | if (!xlate) { |
941 | * whether the sensor supports one of acceptable input formats. | 1065 | dev_warn(&ici->dev, "Format %x not found\n", pixfmt); |
942 | */ | ||
943 | cam_fmt = soc_camera_format_by_fourcc(icd, f->fmt.pix.pixelformat); | ||
944 | if (!cam_fmt) | ||
945 | return -EINVAL; | 1066 | return -EINVAL; |
1067 | } | ||
946 | 1068 | ||
947 | /* limit to pxa hardware capabilities */ | 1069 | /* limit to pxa hardware capabilities */ |
948 | if (f->fmt.pix.height < 32) | 1070 | if (pix->height < 32) |
949 | f->fmt.pix.height = 32; | 1071 | pix->height = 32; |
950 | if (f->fmt.pix.height > 2048) | 1072 | if (pix->height > 2048) |
951 | f->fmt.pix.height = 2048; | 1073 | pix->height = 2048; |
952 | if (f->fmt.pix.width < 48) | 1074 | if (pix->width < 48) |
953 | f->fmt.pix.width = 48; | 1075 | pix->width = 48; |
954 | if (f->fmt.pix.width > 2048) | 1076 | if (pix->width > 2048) |
955 | f->fmt.pix.width = 2048; | 1077 | pix->width = 2048; |
956 | f->fmt.pix.width &= ~0x01; | 1078 | pix->width &= ~0x01; |
957 | 1079 | ||
958 | f->fmt.pix.bytesperline = f->fmt.pix.width * | 1080 | pix->bytesperline = pix->width * |
959 | DIV_ROUND_UP(cam_fmt->depth, 8); | 1081 | DIV_ROUND_UP(xlate->host_fmt->depth, 8); |
960 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | 1082 | pix->sizeimage = pix->height * pix->bytesperline; |
961 | 1083 | ||
962 | /* limit to sensor capabilities */ | 1084 | /* limit to sensor capabilities */ |
963 | return icd->ops->try_fmt(icd, f); | 1085 | return icd->ops->try_fmt(icd, f); |
@@ -1068,6 +1190,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = { | |||
1068 | .remove = pxa_camera_remove_device, | 1190 | .remove = pxa_camera_remove_device, |
1069 | .suspend = pxa_camera_suspend, | 1191 | .suspend = pxa_camera_suspend, |
1070 | .resume = pxa_camera_resume, | 1192 | .resume = pxa_camera_resume, |
1193 | .get_formats = pxa_camera_get_formats, | ||
1071 | .set_fmt = pxa_camera_set_fmt, | 1194 | .set_fmt = pxa_camera_set_fmt, |
1072 | .try_fmt = pxa_camera_try_fmt, | 1195 | .try_fmt = pxa_camera_try_fmt, |
1073 | .init_videobuf = pxa_camera_init_videobuf, | 1196 | .init_videobuf = pxa_camera_init_videobuf, |