aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/pxa_camera.c
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2009-08-25 10:50:46 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-09-18 23:19:17 -0400
commit6a6c8786725c0b3d143674effa8b772f47b1c189 (patch)
tree8bb76c5dcbd579f13e876bd1a0bb56bee4bcebdd /drivers/media/video/pxa_camera.c
parent0166b74374cae3fa8bff0caef726a3d960a9a50a (diff)
V4L/DVB (12534): soc-camera: V4L2 API compliant scaling (S_FMT) and cropping (S_CROP)
The initial soc-camera scaling and cropping implementation turned out to be incompliant with the V4L2 API, e.g., it expected the user to specify cropping in output window pixels, instead of input window pixels. This patch converts the soc-camera core and all drivers to comply with the standard. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/pxa_camera.c')
-rw-r--r--drivers/media/video/pxa_camera.c201
1 files changed, 143 insertions, 58 deletions
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 1fd6ef392a54..a19bb76e175d 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -225,6 +225,10 @@ struct pxa_camera_dev {
225 u32 save_cicr[5]; 225 u32 save_cicr[5];
226}; 226};
227 227
228struct pxa_cam {
229 unsigned long flags;
230};
231
228static const char *pxa_cam_driver_description = "PXA_Camera"; 232static const char *pxa_cam_driver_description = "PXA_Camera";
229 233
230static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ 234static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
@@ -239,7 +243,7 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
239 243
240 dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size); 244 dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size);
241 245
242 *size = roundup(icd->rect_current.width * icd->rect_current.height * 246 *size = roundup(icd->user_width * icd->user_height *
243 ((icd->current_fmt->depth + 7) >> 3), 8); 247 ((icd->current_fmt->depth + 7) >> 3), 8);
244 248
245 if (0 == *count) 249 if (0 == *count)
@@ -443,12 +447,12 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
443 buf->inwork = 1; 447 buf->inwork = 1;
444 448
445 if (buf->fmt != icd->current_fmt || 449 if (buf->fmt != icd->current_fmt ||
446 vb->width != icd->rect_current.width || 450 vb->width != icd->user_width ||
447 vb->height != icd->rect_current.height || 451 vb->height != icd->user_height ||
448 vb->field != field) { 452 vb->field != field) {
449 buf->fmt = icd->current_fmt; 453 buf->fmt = icd->current_fmt;
450 vb->width = icd->rect_current.width; 454 vb->width = icd->user_width;
451 vb->height = icd->rect_current.height; 455 vb->height = icd->user_height;
452 vb->field = field; 456 vb->field = field;
453 vb->state = VIDEOBUF_NEEDS_INIT; 457 vb->state = VIDEOBUF_NEEDS_INIT;
454 } 458 }
@@ -839,7 +843,7 @@ static u32 mclk_get_divisor(struct platform_device *pdev,
839 struct pxa_camera_dev *pcdev) 843 struct pxa_camera_dev *pcdev)
840{ 844{
841 unsigned long mclk = pcdev->mclk; 845 unsigned long mclk = pcdev->mclk;
842 struct device *dev = pcdev->soc_host.v4l2_dev.dev; 846 struct device *dev = &pdev->dev;
843 u32 div; 847 u32 div;
844 unsigned long lcdclk; 848 unsigned long lcdclk;
845 849
@@ -1040,57 +1044,17 @@ static int test_platform_param(struct pxa_camera_dev *pcdev,
1040 return 0; 1044 return 0;
1041} 1045}
1042 1046
1043static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) 1047static void pxa_camera_setup_cicr(struct soc_camera_device *icd,
1048 unsigned long flags, __u32 pixfmt)
1044{ 1049{
1045 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 1050 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
1046 struct pxa_camera_dev *pcdev = ici->priv; 1051 struct pxa_camera_dev *pcdev = ici->priv;
1047 unsigned long dw, bpp, bus_flags, camera_flags, common_flags; 1052 unsigned long dw, bpp;
1048 u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0; 1053 u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0;
1049 int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
1050
1051 if (ret < 0)
1052 return ret;
1053
1054 camera_flags = icd->ops->query_bus_param(icd);
1055
1056 common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
1057 if (!common_flags)
1058 return -EINVAL;
1059
1060 pcdev->channels = 1;
1061
1062 /* Make choises, based on platform preferences */
1063 if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
1064 (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
1065 if (pcdev->platform_flags & PXA_CAMERA_HSP)
1066 common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
1067 else
1068 common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
1069 }
1070
1071 if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
1072 (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
1073 if (pcdev->platform_flags & PXA_CAMERA_VSP)
1074 common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
1075 else
1076 common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
1077 }
1078
1079 if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
1080 (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
1081 if (pcdev->platform_flags & PXA_CAMERA_PCP)
1082 common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
1083 else
1084 common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
1085 }
1086
1087 ret = icd->ops->set_bus_param(icd, common_flags);
1088 if (ret < 0)
1089 return ret;
1090 1054
1091 /* Datawidth is now guaranteed to be equal to one of the three values. 1055 /* Datawidth is now guaranteed to be equal to one of the three values.
1092 * We fix bit-per-pixel equal to data-width... */ 1056 * We fix bit-per-pixel equal to data-width... */
1093 switch (common_flags & SOCAM_DATAWIDTH_MASK) { 1057 switch (flags & SOCAM_DATAWIDTH_MASK) {
1094 case SOCAM_DATAWIDTH_10: 1058 case SOCAM_DATAWIDTH_10:
1095 dw = 4; 1059 dw = 4;
1096 bpp = 0x40; 1060 bpp = 0x40;
@@ -1111,18 +1075,18 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
1111 cicr4 |= CICR4_PCLK_EN; 1075 cicr4 |= CICR4_PCLK_EN;
1112 if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) 1076 if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
1113 cicr4 |= CICR4_MCLK_EN; 1077 cicr4 |= CICR4_MCLK_EN;
1114 if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) 1078 if (flags & SOCAM_PCLK_SAMPLE_FALLING)
1115 cicr4 |= CICR4_PCP; 1079 cicr4 |= CICR4_PCP;
1116 if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) 1080 if (flags & SOCAM_HSYNC_ACTIVE_LOW)
1117 cicr4 |= CICR4_HSP; 1081 cicr4 |= CICR4_HSP;
1118 if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) 1082 if (flags & SOCAM_VSYNC_ACTIVE_LOW)
1119 cicr4 |= CICR4_VSP; 1083 cicr4 |= CICR4_VSP;
1120 1084
1121 cicr0 = __raw_readl(pcdev->base + CICR0); 1085 cicr0 = __raw_readl(pcdev->base + CICR0);
1122 if (cicr0 & CICR0_ENB) 1086 if (cicr0 & CICR0_ENB)
1123 __raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0); 1087 __raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0);
1124 1088
1125 cicr1 = CICR1_PPL_VAL(icd->rect_current.width - 1) | bpp | dw; 1089 cicr1 = CICR1_PPL_VAL(icd->user_width - 1) | bpp | dw;
1126 1090
1127 switch (pixfmt) { 1091 switch (pixfmt) {
1128 case V4L2_PIX_FMT_YUV422P: 1092 case V4L2_PIX_FMT_YUV422P:
@@ -1151,7 +1115,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
1151 } 1115 }
1152 1116
1153 cicr2 = 0; 1117 cicr2 = 0;
1154 cicr3 = CICR3_LPF_VAL(icd->rect_current.height - 1) | 1118 cicr3 = CICR3_LPF_VAL(icd->user_height - 1) |
1155 CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top)); 1119 CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top));
1156 cicr4 |= pcdev->mclk_divisor; 1120 cicr4 |= pcdev->mclk_divisor;
1157 1121
@@ -1165,6 +1129,59 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
1165 CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP)); 1129 CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP));
1166 cicr0 |= CICR0_DMAEN | CICR0_IRQ_MASK; 1130 cicr0 |= CICR0_DMAEN | CICR0_IRQ_MASK;
1167 __raw_writel(cicr0, pcdev->base + CICR0); 1131 __raw_writel(cicr0, pcdev->base + CICR0);
1132}
1133
1134static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
1135{
1136 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
1137 struct pxa_camera_dev *pcdev = ici->priv;
1138 unsigned long bus_flags, camera_flags, common_flags;
1139 int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
1140 struct pxa_cam *cam = icd->host_priv;
1141
1142 if (ret < 0)
1143 return ret;
1144
1145 camera_flags = icd->ops->query_bus_param(icd);
1146
1147 common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
1148 if (!common_flags)
1149 return -EINVAL;
1150
1151 pcdev->channels = 1;
1152
1153 /* Make choises, based on platform preferences */
1154 if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
1155 (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
1156 if (pcdev->platform_flags & PXA_CAMERA_HSP)
1157 common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
1158 else
1159 common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
1160 }
1161
1162 if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
1163 (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
1164 if (pcdev->platform_flags & PXA_CAMERA_VSP)
1165 common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
1166 else
1167 common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
1168 }
1169
1170 if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
1171 (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
1172 if (pcdev->platform_flags & PXA_CAMERA_PCP)
1173 common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
1174 else
1175 common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
1176 }
1177
1178 cam->flags = common_flags;
1179
1180 ret = icd->ops->set_bus_param(icd, common_flags);
1181 if (ret < 0)
1182 return ret;
1183
1184 pxa_camera_setup_cicr(icd, common_flags, pixfmt);
1168 1185
1169 return 0; 1186 return 0;
1170} 1187}
@@ -1230,6 +1247,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
1230{ 1247{
1231 struct device *dev = icd->dev.parent; 1248 struct device *dev = icd->dev.parent;
1232 int formats = 0, buswidth, ret; 1249 int formats = 0, buswidth, ret;
1250 struct pxa_cam *cam;
1233 1251
1234 buswidth = required_buswidth(icd->formats + idx); 1252 buswidth = required_buswidth(icd->formats + idx);
1235 1253
@@ -1240,6 +1258,16 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
1240 if (ret < 0) 1258 if (ret < 0)
1241 return 0; 1259 return 0;
1242 1260
1261 if (!icd->host_priv) {
1262 cam = kzalloc(sizeof(*cam), GFP_KERNEL);
1263 if (!cam)
1264 return -ENOMEM;
1265
1266 icd->host_priv = cam;
1267 } else {
1268 cam = icd->host_priv;
1269 }
1270
1243 switch (icd->formats[idx].fourcc) { 1271 switch (icd->formats[idx].fourcc) {
1244 case V4L2_PIX_FMT_UYVY: 1272 case V4L2_PIX_FMT_UYVY:
1245 formats++; 1273 formats++;
@@ -1284,6 +1312,19 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
1284 return formats; 1312 return formats;
1285} 1313}
1286 1314
1315static void pxa_camera_put_formats(struct soc_camera_device *icd)
1316{
1317 kfree(icd->host_priv);
1318 icd->host_priv = NULL;
1319}
1320
1321static int pxa_camera_check_frame(struct v4l2_pix_format *pix)
1322{
1323 /* limit to pxa hardware capabilities */
1324 return pix->height < 32 || pix->height > 2048 || pix->width < 48 ||
1325 pix->width > 2048 || (pix->width & 0x01);
1326}
1327
1287static int pxa_camera_set_crop(struct soc_camera_device *icd, 1328static int pxa_camera_set_crop(struct soc_camera_device *icd,
1288 struct v4l2_crop *a) 1329 struct v4l2_crop *a)
1289{ 1330{
@@ -1296,6 +1337,9 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
1296 .master_clock = pcdev->mclk, 1337 .master_clock = pcdev->mclk,
1297 .pixel_clock_max = pcdev->ciclk / 4, 1338 .pixel_clock_max = pcdev->ciclk / 4,
1298 }; 1339 };
1340 struct v4l2_format f;
1341 struct v4l2_pix_format *pix = &f.fmt.pix, pix_tmp;
1342 struct pxa_cam *cam = icd->host_priv;
1299 int ret; 1343 int ret;
1300 1344
1301 /* If PCLK is used to latch data from the sensor, check sense */ 1345 /* If PCLK is used to latch data from the sensor, check sense */
@@ -1309,7 +1353,37 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
1309 if (ret < 0) { 1353 if (ret < 0) {
1310 dev_warn(dev, "Failed to crop to %ux%u@%u:%u\n", 1354 dev_warn(dev, "Failed to crop to %ux%u@%u:%u\n",
1311 rect->width, rect->height, rect->left, rect->top); 1355 rect->width, rect->height, rect->left, rect->top);
1312 } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { 1356 return ret;
1357 }
1358
1359 f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1360
1361 ret = v4l2_subdev_call(sd, video, g_fmt, &f);
1362 if (ret < 0)
1363 return ret;
1364
1365 pix_tmp = *pix;
1366 if (pxa_camera_check_frame(pix)) {
1367 /*
1368 * Camera cropping produced a frame beyond our capabilities.
1369 * FIXME: just extract a subframe, that we can process.
1370 */
1371 v4l_bound_align_image(&pix->width, 48, 2048, 1,
1372 &pix->height, 32, 2048, 0,
1373 icd->current_fmt->fourcc == V4L2_PIX_FMT_YUV422P ?
1374 4 : 0);
1375 ret = v4l2_subdev_call(sd, video, s_fmt, &f);
1376 if (ret < 0)
1377 return ret;
1378
1379 if (pxa_camera_check_frame(pix)) {
1380 dev_warn(icd->dev.parent,
1381 "Inconsistent state. Use S_FMT to repair\n");
1382 return -EINVAL;
1383 }
1384 }
1385
1386 if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
1313 if (sense.pixel_clock > sense.pixel_clock_max) { 1387 if (sense.pixel_clock > sense.pixel_clock_max) {
1314 dev_err(dev, 1388 dev_err(dev,
1315 "pixel clock %lu set by the camera too high!", 1389 "pixel clock %lu set by the camera too high!",
@@ -1319,6 +1393,11 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
1319 recalculate_fifo_timeout(pcdev, sense.pixel_clock); 1393 recalculate_fifo_timeout(pcdev, sense.pixel_clock);
1320 } 1394 }
1321 1395
1396 icd->user_width = pix->width;
1397 icd->user_height = pix->height;
1398
1399 pxa_camera_setup_cicr(icd, cam->flags, icd->current_fmt->fourcc);
1400
1322 return ret; 1401 return ret;
1323} 1402}
1324 1403
@@ -1359,6 +1438,11 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
1359 if (ret < 0) { 1438 if (ret < 0) {
1360 dev_warn(dev, "Failed to configure for format %x\n", 1439 dev_warn(dev, "Failed to configure for format %x\n",
1361 pix->pixelformat); 1440 pix->pixelformat);
1441 } else if (pxa_camera_check_frame(pix)) {
1442 dev_warn(dev,
1443 "Camera driver produced an unsupported frame %dx%d\n",
1444 pix->width, pix->height);
1445 ret = -EINVAL;
1362 } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { 1446 } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
1363 if (sense.pixel_clock > sense.pixel_clock_max) { 1447 if (sense.pixel_clock > sense.pixel_clock_max) {
1364 dev_err(dev, 1448 dev_err(dev,
@@ -1402,7 +1486,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
1402 */ 1486 */
1403 v4l_bound_align_image(&pix->width, 48, 2048, 1, 1487 v4l_bound_align_image(&pix->width, 48, 2048, 1,
1404 &pix->height, 32, 2048, 0, 1488 &pix->height, 32, 2048, 0,
1405 xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0); 1489 pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0);
1406 1490
1407 pix->bytesperline = pix->width * 1491 pix->bytesperline = pix->width *
1408 DIV_ROUND_UP(xlate->host_fmt->depth, 8); 1492 DIV_ROUND_UP(xlate->host_fmt->depth, 8);
@@ -1412,7 +1496,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
1412 pix->pixelformat = xlate->cam_fmt->fourcc; 1496 pix->pixelformat = xlate->cam_fmt->fourcc;
1413 /* limit to sensor capabilities */ 1497 /* limit to sensor capabilities */
1414 ret = v4l2_subdev_call(sd, video, try_fmt, f); 1498 ret = v4l2_subdev_call(sd, video, try_fmt, f);
1415 pix->pixelformat = xlate->host_fmt->fourcc; 1499 pix->pixelformat = pixfmt;
1416 1500
1417 field = pix->field; 1501 field = pix->field;
1418 1502
@@ -1525,6 +1609,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
1525 .resume = pxa_camera_resume, 1609 .resume = pxa_camera_resume,
1526 .set_crop = pxa_camera_set_crop, 1610 .set_crop = pxa_camera_set_crop,
1527 .get_formats = pxa_camera_get_formats, 1611 .get_formats = pxa_camera_get_formats,
1612 .put_formats = pxa_camera_put_formats,
1528 .set_fmt = pxa_camera_set_fmt, 1613 .set_fmt = pxa_camera_set_fmt,
1529 .try_fmt = pxa_camera_try_fmt, 1614 .try_fmt = pxa_camera_try_fmt,
1530 .init_videobuf = pxa_camera_init_videobuf, 1615 .init_videobuf = pxa_camera_init_videobuf,