diff options
Diffstat (limited to 'drivers/media/video/pxa_camera.c')
-rw-r--r-- | drivers/media/video/pxa_camera.c | 140 |
1 files changed, 80 insertions, 60 deletions
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index d07df22a5ec..79fb22c89ae 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c | |||
@@ -214,6 +214,7 @@ struct pxa_camera_dev { | |||
214 | unsigned long ciclk; | 214 | unsigned long ciclk; |
215 | unsigned long mclk; | 215 | unsigned long mclk; |
216 | u32 mclk_divisor; | 216 | u32 mclk_divisor; |
217 | u16 width_flags; /* max 10 bits */ | ||
217 | 218 | ||
218 | struct list_head capture; | 219 | struct list_head capture; |
219 | 220 | ||
@@ -1020,37 +1021,20 @@ static int test_platform_param(struct pxa_camera_dev *pcdev, | |||
1020 | * quick capture interface supports both. | 1021 | * quick capture interface supports both. |
1021 | */ | 1022 | */ |
1022 | *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ? | 1023 | *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ? |
1023 | SOCAM_MASTER : SOCAM_SLAVE) | | 1024 | V4L2_MBUS_MASTER : V4L2_MBUS_SLAVE) | |
1024 | SOCAM_HSYNC_ACTIVE_HIGH | | 1025 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | |
1025 | SOCAM_HSYNC_ACTIVE_LOW | | 1026 | V4L2_MBUS_HSYNC_ACTIVE_LOW | |
1026 | SOCAM_VSYNC_ACTIVE_HIGH | | 1027 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | |
1027 | SOCAM_VSYNC_ACTIVE_LOW | | 1028 | V4L2_MBUS_VSYNC_ACTIVE_LOW | |
1028 | SOCAM_DATA_ACTIVE_HIGH | | 1029 | V4L2_MBUS_DATA_ACTIVE_HIGH | |
1029 | SOCAM_PCLK_SAMPLE_RISING | | 1030 | V4L2_MBUS_PCLK_SAMPLE_RISING | |
1030 | SOCAM_PCLK_SAMPLE_FALLING; | 1031 | V4L2_MBUS_PCLK_SAMPLE_FALLING; |
1031 | 1032 | ||
1032 | /* If requested data width is supported by the platform, use it */ | 1033 | /* If requested data width is supported by the platform, use it */ |
1033 | switch (buswidth) { | 1034 | if ((1 << (buswidth - 1)) & pcdev->width_flags) |
1034 | case 10: | 1035 | return 0; |
1035 | if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10)) | ||
1036 | return -EINVAL; | ||
1037 | *flags |= SOCAM_DATAWIDTH_10; | ||
1038 | break; | ||
1039 | case 9: | ||
1040 | if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9)) | ||
1041 | return -EINVAL; | ||
1042 | *flags |= SOCAM_DATAWIDTH_9; | ||
1043 | break; | ||
1044 | case 8: | ||
1045 | if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8)) | ||
1046 | return -EINVAL; | ||
1047 | *flags |= SOCAM_DATAWIDTH_8; | ||
1048 | break; | ||
1049 | default: | ||
1050 | return -EINVAL; | ||
1051 | } | ||
1052 | 1036 | ||
1053 | return 0; | 1037 | return -EINVAL; |
1054 | } | 1038 | } |
1055 | 1039 | ||
1056 | static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | 1040 | static void pxa_camera_setup_cicr(struct soc_camera_device *icd, |
@@ -1070,12 +1054,12 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
1070 | * Datawidth is now guaranteed to be equal to one of the three values. | 1054 | * Datawidth is now guaranteed to be equal to one of the three values. |
1071 | * We fix bit-per-pixel equal to data-width... | 1055 | * We fix bit-per-pixel equal to data-width... |
1072 | */ | 1056 | */ |
1073 | switch (flags & SOCAM_DATAWIDTH_MASK) { | 1057 | switch (icd->current_fmt->host_fmt->bits_per_sample) { |
1074 | case SOCAM_DATAWIDTH_10: | 1058 | case 10: |
1075 | dw = 4; | 1059 | dw = 4; |
1076 | bpp = 0x40; | 1060 | bpp = 0x40; |
1077 | break; | 1061 | break; |
1078 | case SOCAM_DATAWIDTH_9: | 1062 | case 9: |
1079 | dw = 3; | 1063 | dw = 3; |
1080 | bpp = 0x20; | 1064 | bpp = 0x20; |
1081 | break; | 1065 | break; |
@@ -1084,7 +1068,7 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
1084 | * Actually it can only be 8 now, | 1068 | * Actually it can only be 8 now, |
1085 | * default is just to silence compiler warnings | 1069 | * default is just to silence compiler warnings |
1086 | */ | 1070 | */ |
1087 | case SOCAM_DATAWIDTH_8: | 1071 | case 8: |
1088 | dw = 2; | 1072 | dw = 2; |
1089 | bpp = 0; | 1073 | bpp = 0; |
1090 | } | 1074 | } |
@@ -1093,11 +1077,11 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
1093 | cicr4 |= CICR4_PCLK_EN; | 1077 | cicr4 |= CICR4_PCLK_EN; |
1094 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) | 1078 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) |
1095 | cicr4 |= CICR4_MCLK_EN; | 1079 | cicr4 |= CICR4_MCLK_EN; |
1096 | if (flags & SOCAM_PCLK_SAMPLE_FALLING) | 1080 | if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) |
1097 | cicr4 |= CICR4_PCP; | 1081 | cicr4 |= CICR4_PCP; |
1098 | if (flags & SOCAM_HSYNC_ACTIVE_LOW) | 1082 | if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) |
1099 | cicr4 |= CICR4_HSP; | 1083 | cicr4 |= CICR4_HSP; |
1100 | if (flags & SOCAM_VSYNC_ACTIVE_LOW) | 1084 | if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) |
1101 | cicr4 |= CICR4_VSP; | 1085 | cicr4 |= CICR4_VSP; |
1102 | 1086 | ||
1103 | cicr0 = __raw_readl(pcdev->base + CICR0); | 1087 | cicr0 = __raw_readl(pcdev->base + CICR0); |
@@ -1151,9 +1135,11 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
1151 | 1135 | ||
1152 | static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | 1136 | static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) |
1153 | { | 1137 | { |
1138 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1154 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 1139 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
1155 | struct pxa_camera_dev *pcdev = ici->priv; | 1140 | struct pxa_camera_dev *pcdev = ici->priv; |
1156 | unsigned long bus_flags, camera_flags, common_flags; | 1141 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
1142 | unsigned long bus_flags, common_flags; | ||
1157 | int ret; | 1143 | int ret; |
1158 | struct pxa_cam *cam = icd->host_priv; | 1144 | struct pxa_cam *cam = icd->host_priv; |
1159 | 1145 | ||
@@ -1162,44 +1148,58 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1162 | if (ret < 0) | 1148 | if (ret < 0) |
1163 | return ret; | 1149 | return ret; |
1164 | 1150 | ||
1165 | camera_flags = icd->ops->query_bus_param(icd); | 1151 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
1166 | 1152 | if (!ret) { | |
1167 | common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); | 1153 | common_flags = soc_mbus_config_compatible(&cfg, |
1168 | if (!common_flags) | 1154 | bus_flags); |
1169 | return -EINVAL; | 1155 | if (!common_flags) { |
1156 | dev_warn(icd->parent, | ||
1157 | "Flags incompatible: camera 0x%x, host 0x%lx\n", | ||
1158 | cfg.flags, bus_flags); | ||
1159 | return -EINVAL; | ||
1160 | } | ||
1161 | } else if (ret != -ENOIOCTLCMD) { | ||
1162 | return ret; | ||
1163 | } else { | ||
1164 | common_flags = bus_flags; | ||
1165 | } | ||
1170 | 1166 | ||
1171 | pcdev->channels = 1; | 1167 | pcdev->channels = 1; |
1172 | 1168 | ||
1173 | /* Make choises, based on platform preferences */ | 1169 | /* Make choises, based on platform preferences */ |
1174 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && | 1170 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && |
1175 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { | 1171 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { |
1176 | if (pcdev->platform_flags & PXA_CAMERA_HSP) | 1172 | if (pcdev->platform_flags & PXA_CAMERA_HSP) |
1177 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; | 1173 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; |
1178 | else | 1174 | else |
1179 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; | 1175 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; |
1180 | } | 1176 | } |
1181 | 1177 | ||
1182 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | 1178 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && |
1183 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | 1179 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { |
1184 | if (pcdev->platform_flags & PXA_CAMERA_VSP) | 1180 | if (pcdev->platform_flags & PXA_CAMERA_VSP) |
1185 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | 1181 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; |
1186 | else | 1182 | else |
1187 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | 1183 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; |
1188 | } | 1184 | } |
1189 | 1185 | ||
1190 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | 1186 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && |
1191 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | 1187 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { |
1192 | if (pcdev->platform_flags & PXA_CAMERA_PCP) | 1188 | if (pcdev->platform_flags & PXA_CAMERA_PCP) |
1193 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | 1189 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; |
1194 | else | 1190 | else |
1195 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | 1191 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; |
1196 | } | 1192 | } |
1197 | 1193 | ||
1198 | cam->flags = common_flags; | 1194 | cfg.flags = common_flags; |
1199 | 1195 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); | |
1200 | ret = icd->ops->set_bus_param(icd, common_flags); | 1196 | if (ret < 0 && ret != -ENOIOCTLCMD) { |
1201 | if (ret < 0) | 1197 | dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", |
1198 | common_flags, ret); | ||
1202 | return ret; | 1199 | return ret; |
1200 | } | ||
1201 | |||
1202 | cam->flags = common_flags; | ||
1203 | 1203 | ||
1204 | pxa_camera_setup_cicr(icd, common_flags, pixfmt); | 1204 | pxa_camera_setup_cicr(icd, common_flags, pixfmt); |
1205 | 1205 | ||
@@ -1209,17 +1209,31 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1209 | static int pxa_camera_try_bus_param(struct soc_camera_device *icd, | 1209 | static int pxa_camera_try_bus_param(struct soc_camera_device *icd, |
1210 | unsigned char buswidth) | 1210 | unsigned char buswidth) |
1211 | { | 1211 | { |
1212 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1212 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 1213 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
1213 | struct pxa_camera_dev *pcdev = ici->priv; | 1214 | struct pxa_camera_dev *pcdev = ici->priv; |
1214 | unsigned long bus_flags, camera_flags; | 1215 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
1216 | unsigned long bus_flags, common_flags; | ||
1215 | int ret = test_platform_param(pcdev, buswidth, &bus_flags); | 1217 | int ret = test_platform_param(pcdev, buswidth, &bus_flags); |
1216 | 1218 | ||
1217 | if (ret < 0) | 1219 | if (ret < 0) |
1218 | return ret; | 1220 | return ret; |
1219 | 1221 | ||
1220 | camera_flags = icd->ops->query_bus_param(icd); | 1222 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
1223 | if (!ret) { | ||
1224 | common_flags = soc_mbus_config_compatible(&cfg, | ||
1225 | bus_flags); | ||
1226 | if (!common_flags) { | ||
1227 | dev_warn(icd->parent, | ||
1228 | "Flags incompatible: camera 0x%x, host 0x%lx\n", | ||
1229 | cfg.flags, bus_flags); | ||
1230 | return -EINVAL; | ||
1231 | } | ||
1232 | } else if (ret == -ENOIOCTLCMD) { | ||
1233 | ret = 0; | ||
1234 | } | ||
1221 | 1235 | ||
1222 | return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL; | 1236 | return ret; |
1223 | } | 1237 | } |
1224 | 1238 | ||
1225 | static const struct soc_mbus_pixelfmt pxa_camera_formats[] = { | 1239 | static const struct soc_mbus_pixelfmt pxa_camera_formats[] = { |
@@ -1687,6 +1701,12 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev) | |||
1687 | "data widths, using default 10 bit\n"); | 1701 | "data widths, using default 10 bit\n"); |
1688 | pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; | 1702 | pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; |
1689 | } | 1703 | } |
1704 | if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8) | ||
1705 | pcdev->width_flags = 1 << 7; | ||
1706 | if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9) | ||
1707 | pcdev->width_flags |= 1 << 8; | ||
1708 | if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10) | ||
1709 | pcdev->width_flags |= 1 << 9; | ||
1690 | pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; | 1710 | pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; |
1691 | if (!pcdev->mclk) { | 1711 | if (!pcdev->mclk) { |
1692 | dev_warn(&pdev->dev, | 1712 | dev_warn(&pdev->dev, |