diff options
-rw-r--r-- | drivers/media/video/mx3_camera.c | 197 |
1 files changed, 89 insertions, 108 deletions
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index c8e958a07e91..f4ef6b993ff1 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c | |||
@@ -109,6 +109,7 @@ struct mx3_camera_dev { | |||
109 | 109 | ||
110 | unsigned long platform_flags; | 110 | unsigned long platform_flags; |
111 | unsigned long mclk; | 111 | unsigned long mclk; |
112 | u16 width_flags; /* max 15 bits */ | ||
112 | 113 | ||
113 | struct list_head capture; | 114 | struct list_head capture; |
114 | spinlock_t lock; /* Protects video buffer lists */ | 115 | spinlock_t lock; /* Protects video buffer lists */ |
@@ -548,58 +549,27 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam, | |||
548 | unsigned char buswidth, unsigned long *flags) | 549 | unsigned char buswidth, unsigned long *flags) |
549 | { | 550 | { |
550 | /* | 551 | /* |
552 | * If requested data width is supported by the platform, use it or any | ||
553 | * possible lower value - i.MX31 is smart enough to shift bits | ||
554 | */ | ||
555 | if (buswidth > fls(mx3_cam->width_flags)) | ||
556 | return -EINVAL; | ||
557 | |||
558 | /* | ||
551 | * Platform specified synchronization and pixel clock polarities are | 559 | * Platform specified synchronization and pixel clock polarities are |
552 | * only a recommendation and are only used during probing. MX3x | 560 | * only a recommendation and are only used during probing. MX3x |
553 | * camera interface only works in master mode, i.e., uses HSYNC and | 561 | * camera interface only works in master mode, i.e., uses HSYNC and |
554 | * VSYNC signals from the sensor | 562 | * VSYNC signals from the sensor |
555 | */ | 563 | */ |
556 | *flags = SOCAM_MASTER | | 564 | *flags = V4L2_MBUS_MASTER | |
557 | SOCAM_HSYNC_ACTIVE_HIGH | | 565 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | |
558 | SOCAM_HSYNC_ACTIVE_LOW | | 566 | V4L2_MBUS_HSYNC_ACTIVE_LOW | |
559 | SOCAM_VSYNC_ACTIVE_HIGH | | 567 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | |
560 | SOCAM_VSYNC_ACTIVE_LOW | | 568 | V4L2_MBUS_VSYNC_ACTIVE_LOW | |
561 | SOCAM_PCLK_SAMPLE_RISING | | 569 | V4L2_MBUS_PCLK_SAMPLE_RISING | |
562 | SOCAM_PCLK_SAMPLE_FALLING | | 570 | V4L2_MBUS_PCLK_SAMPLE_FALLING | |
563 | SOCAM_DATA_ACTIVE_HIGH | | 571 | V4L2_MBUS_DATA_ACTIVE_HIGH | |
564 | SOCAM_DATA_ACTIVE_LOW; | 572 | V4L2_MBUS_DATA_ACTIVE_LOW; |
565 | |||
566 | /* | ||
567 | * If requested data width is supported by the platform, use it or any | ||
568 | * possible lower value - i.MX31 is smart enough to schift bits | ||
569 | */ | ||
570 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) | ||
571 | *flags |= SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_10 | | ||
572 | SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; | ||
573 | else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) | ||
574 | *flags |= SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8 | | ||
575 | SOCAM_DATAWIDTH_4; | ||
576 | else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) | ||
577 | *flags |= SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; | ||
578 | else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4) | ||
579 | *flags |= SOCAM_DATAWIDTH_4; | ||
580 | |||
581 | switch (buswidth) { | ||
582 | case 15: | ||
583 | if (!(*flags & SOCAM_DATAWIDTH_15)) | ||
584 | return -EINVAL; | ||
585 | break; | ||
586 | case 10: | ||
587 | if (!(*flags & SOCAM_DATAWIDTH_10)) | ||
588 | return -EINVAL; | ||
589 | break; | ||
590 | case 8: | ||
591 | if (!(*flags & SOCAM_DATAWIDTH_8)) | ||
592 | return -EINVAL; | ||
593 | break; | ||
594 | case 4: | ||
595 | if (!(*flags & SOCAM_DATAWIDTH_4)) | ||
596 | return -EINVAL; | ||
597 | break; | ||
598 | default: | ||
599 | dev_warn(mx3_cam->soc_host.v4l2_dev.dev, | ||
600 | "Unsupported bus width %d\n", buswidth); | ||
601 | return -EINVAL; | ||
602 | } | ||
603 | 573 | ||
604 | return 0; | 574 | return 0; |
605 | } | 575 | } |
@@ -607,9 +577,11 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam, | |||
607 | static int mx3_camera_try_bus_param(struct soc_camera_device *icd, | 577 | static int mx3_camera_try_bus_param(struct soc_camera_device *icd, |
608 | const unsigned int depth) | 578 | const unsigned int depth) |
609 | { | 579 | { |
580 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
610 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 581 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
611 | struct mx3_camera_dev *mx3_cam = ici->priv; | 582 | struct mx3_camera_dev *mx3_cam = ici->priv; |
612 | unsigned long bus_flags, camera_flags; | 583 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
584 | unsigned long bus_flags, common_flags; | ||
613 | int ret = test_platform_param(mx3_cam, depth, &bus_flags); | 585 | int ret = test_platform_param(mx3_cam, depth, &bus_flags); |
614 | 586 | ||
615 | dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret); | 587 | dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret); |
@@ -617,15 +589,21 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd, | |||
617 | if (ret < 0) | 589 | if (ret < 0) |
618 | return ret; | 590 | return ret; |
619 | 591 | ||
620 | camera_flags = icd->ops->query_bus_param(icd); | 592 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
621 | 593 | if (!ret) { | |
622 | ret = soc_camera_bus_param_compatible(camera_flags, bus_flags); | 594 | common_flags = soc_mbus_config_compatible(&cfg, |
623 | if (ret < 0) | 595 | bus_flags); |
624 | dev_warn(icd->parent, | 596 | if (!common_flags) { |
625 | "Flags incompatible: camera %lx, host %lx\n", | 597 | dev_warn(icd->parent, |
626 | camera_flags, bus_flags); | 598 | "Flags incompatible: camera 0x%x, host 0x%lx\n", |
599 | cfg.flags, bus_flags); | ||
600 | return -EINVAL; | ||
601 | } | ||
602 | } else if (ret != -ENOIOCTLCMD) { | ||
603 | return ret; | ||
604 | } | ||
627 | 605 | ||
628 | return ret; | 606 | return 0; |
629 | } | 607 | } |
630 | 608 | ||
631 | static bool chan_filter(struct dma_chan *chan, void *arg) | 609 | static bool chan_filter(struct dma_chan *chan, void *arg) |
@@ -994,9 +972,11 @@ static int mx3_camera_querycap(struct soc_camera_host *ici, | |||
994 | 972 | ||
995 | static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | 973 | static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) |
996 | { | 974 | { |
975 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
997 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 976 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
998 | struct mx3_camera_dev *mx3_cam = ici->priv; | 977 | struct mx3_camera_dev *mx3_cam = ici->priv; |
999 | unsigned long bus_flags, camera_flags, common_flags; | 978 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
979 | unsigned long bus_flags, common_flags; | ||
1000 | u32 dw, sens_conf; | 980 | u32 dw, sens_conf; |
1001 | const struct soc_mbus_pixelfmt *fmt; | 981 | const struct soc_mbus_pixelfmt *fmt; |
1002 | int buswidth; | 982 | int buswidth; |
@@ -1008,83 +988,76 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1008 | if (!fmt) | 988 | if (!fmt) |
1009 | return -EINVAL; | 989 | return -EINVAL; |
1010 | 990 | ||
1011 | buswidth = fmt->bits_per_sample; | ||
1012 | ret = test_platform_param(mx3_cam, buswidth, &bus_flags); | ||
1013 | |||
1014 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 991 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); |
1015 | if (!xlate) { | 992 | if (!xlate) { |
1016 | dev_warn(dev, "Format %x not found\n", pixfmt); | 993 | dev_warn(dev, "Format %x not found\n", pixfmt); |
1017 | return -EINVAL; | 994 | return -EINVAL; |
1018 | } | 995 | } |
1019 | 996 | ||
997 | buswidth = fmt->bits_per_sample; | ||
998 | ret = test_platform_param(mx3_cam, buswidth, &bus_flags); | ||
999 | |||
1020 | dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret); | 1000 | dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret); |
1021 | 1001 | ||
1022 | if (ret < 0) | 1002 | if (ret < 0) |
1023 | return ret; | 1003 | return ret; |
1024 | 1004 | ||
1025 | camera_flags = icd->ops->query_bus_param(icd); | 1005 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
1026 | 1006 | if (!ret) { | |
1027 | common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); | 1007 | common_flags = soc_mbus_config_compatible(&cfg, |
1028 | dev_dbg(dev, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n", | 1008 | bus_flags); |
1029 | camera_flags, bus_flags, common_flags); | 1009 | if (!common_flags) { |
1030 | if (!common_flags) { | 1010 | dev_warn(icd->parent, |
1031 | dev_dbg(dev, "no common flags"); | 1011 | "Flags incompatible: camera 0x%x, host 0x%lx\n", |
1032 | return -EINVAL; | 1012 | cfg.flags, bus_flags); |
1013 | return -EINVAL; | ||
1014 | } | ||
1015 | } else if (ret != -ENOIOCTLCMD) { | ||
1016 | return ret; | ||
1017 | } else { | ||
1018 | common_flags = bus_flags; | ||
1033 | } | 1019 | } |
1034 | 1020 | ||
1021 | dev_dbg(dev, "Flags cam: 0x%x host: 0x%lx common: 0x%lx\n", | ||
1022 | cfg.flags, bus_flags, common_flags); | ||
1023 | |||
1035 | /* Make choices, based on platform preferences */ | 1024 | /* Make choices, based on platform preferences */ |
1036 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && | 1025 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && |
1037 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { | 1026 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { |
1038 | if (mx3_cam->platform_flags & MX3_CAMERA_HSP) | 1027 | if (mx3_cam->platform_flags & MX3_CAMERA_HSP) |
1039 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; | 1028 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; |
1040 | else | 1029 | else |
1041 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; | 1030 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; |
1042 | } | 1031 | } |
1043 | 1032 | ||
1044 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | 1033 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && |
1045 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | 1034 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { |
1046 | if (mx3_cam->platform_flags & MX3_CAMERA_VSP) | 1035 | if (mx3_cam->platform_flags & MX3_CAMERA_VSP) |
1047 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | 1036 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; |
1048 | else | 1037 | else |
1049 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | 1038 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; |
1050 | } | 1039 | } |
1051 | 1040 | ||
1052 | if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) && | 1041 | if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) && |
1053 | (common_flags & SOCAM_DATA_ACTIVE_LOW)) { | 1042 | (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) { |
1054 | if (mx3_cam->platform_flags & MX3_CAMERA_DP) | 1043 | if (mx3_cam->platform_flags & MX3_CAMERA_DP) |
1055 | common_flags &= ~SOCAM_DATA_ACTIVE_HIGH; | 1044 | common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH; |
1056 | else | 1045 | else |
1057 | common_flags &= ~SOCAM_DATA_ACTIVE_LOW; | 1046 | common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW; |
1058 | } | 1047 | } |
1059 | 1048 | ||
1060 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | 1049 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && |
1061 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | 1050 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { |
1062 | if (mx3_cam->platform_flags & MX3_CAMERA_PCP) | 1051 | if (mx3_cam->platform_flags & MX3_CAMERA_PCP) |
1063 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | 1052 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; |
1064 | else | 1053 | else |
1065 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | 1054 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; |
1066 | } | 1055 | } |
1067 | 1056 | ||
1068 | /* | 1057 | cfg.flags = common_flags; |
1069 | * Make the camera work in widest common mode, we'll take care of | 1058 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); |
1070 | * the rest | 1059 | if (ret < 0 && ret != -ENOIOCTLCMD) { |
1071 | */ | 1060 | dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n", |
1072 | if (common_flags & SOCAM_DATAWIDTH_15) | ||
1073 | common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | | ||
1074 | SOCAM_DATAWIDTH_15; | ||
1075 | else if (common_flags & SOCAM_DATAWIDTH_10) | ||
1076 | common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | | ||
1077 | SOCAM_DATAWIDTH_10; | ||
1078 | else if (common_flags & SOCAM_DATAWIDTH_8) | ||
1079 | common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | | ||
1080 | SOCAM_DATAWIDTH_8; | ||
1081 | else | ||
1082 | common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | | ||
1083 | SOCAM_DATAWIDTH_4; | ||
1084 | |||
1085 | ret = icd->ops->set_bus_param(icd, common_flags); | ||
1086 | if (ret < 0) { | ||
1087 | dev_dbg(dev, "camera set_bus_param(%lx) returned %d\n", | ||
1088 | common_flags, ret); | 1061 | common_flags, ret); |
1089 | return ret; | 1062 | return ret; |
1090 | } | 1063 | } |
@@ -1108,13 +1081,13 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1108 | /* This has been set in mx3_camera_activate(), but we clear it above */ | 1081 | /* This has been set in mx3_camera_activate(), but we clear it above */ |
1109 | sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER; | 1082 | sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER; |
1110 | 1083 | ||
1111 | if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) | 1084 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) |
1112 | sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; | 1085 | sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; |
1113 | if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) | 1086 | if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) |
1114 | sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; | 1087 | sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; |
1115 | if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) | 1088 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) |
1116 | sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; | 1089 | sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; |
1117 | if (common_flags & SOCAM_DATA_ACTIVE_LOW) | 1090 | if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW) |
1118 | sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; | 1091 | sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; |
1119 | 1092 | ||
1120 | /* Just do what we're asked to do */ | 1093 | /* Just do what we're asked to do */ |
@@ -1199,6 +1172,14 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev) | |||
1199 | "data widths, using default 8 bit\n"); | 1172 | "data widths, using default 8 bit\n"); |
1200 | mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8; | 1173 | mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8; |
1201 | } | 1174 | } |
1175 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4) | ||
1176 | mx3_cam->width_flags = 1 << 3; | ||
1177 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) | ||
1178 | mx3_cam->width_flags |= 1 << 7; | ||
1179 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) | ||
1180 | mx3_cam->width_flags |= 1 << 9; | ||
1181 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) | ||
1182 | mx3_cam->width_flags |= 1 << 14; | ||
1202 | 1183 | ||
1203 | mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000; | 1184 | mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000; |
1204 | if (!mx3_cam->mclk) { | 1185 | if (!mx3_cam->mclk) { |