aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@pengutronix.de>2008-03-07 19:57:18 -0500
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-04-24 13:07:49 -0400
commitad5f2e859d76dccb7eb1aa942171b1a32211efc2 (patch)
tree1716d5c82322d55886de36dddd9535b90dd57630
parent1c659689fe9959c017bfaaa8301243f7d99f1a46 (diff)
V4L/DVB (7336): soc-camera: streamline hardware parameter negotiation
Improve hardware parameter negotiation between the camera host driver and camera drivers. Parameters like horizontal and vertical synchronisation, pixel clock polarity shall be set depending on capabilities of the parties. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r--drivers/media/video/mt9m001.c77
-rw-r--r--drivers/media/video/mt9v022.c129
-rw-r--r--drivers/media/video/pxa_camera.c156
-rw-r--r--drivers/media/video/soc_camera.c49
-rw-r--r--include/media/soc_camera.h52
5 files changed, 301 insertions, 162 deletions
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index 4ad834326fa8..acb5454b57eb 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -210,40 +210,64 @@ static int bus_switch_act(struct mt9m001 *mt9m001, int go8bit)
210#endif 210#endif
211} 211}
212 212
213static int mt9m001_set_capture_format(struct soc_camera_device *icd, 213static int bus_switch_possible(struct mt9m001 *mt9m001)
214 __u32 pixfmt, struct v4l2_rect *rect, unsigned int flags) 214{
215#ifdef CONFIG_MT9M001_PCA9536_SWITCH
216 return gpio_is_valid(mt9m001->switch_gpio);
217#else
218 return 0;
219#endif
220}
221
222static int mt9m001_set_bus_param(struct soc_camera_device *icd,
223 unsigned long flags)
215{ 224{
216 struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); 225 struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
217 unsigned int width_flag = flags & (IS_DATAWIDTH_10 | IS_DATAWIDTH_9 | 226 unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
218 IS_DATAWIDTH_8);
219 int ret; 227 int ret;
220 const u16 hblank = 9, vblank = 25;
221 228
222 /* MT9M001 has all capture_format parameters fixed */ 229 /* Flags validity verified in test_bus_param */
223 if (!(flags & IS_MASTER) ||
224 !(flags & IS_PCLK_SAMPLE_RISING) ||
225 !(flags & IS_HSYNC_ACTIVE_HIGH) ||
226 !(flags & IS_VSYNC_ACTIVE_HIGH))
227 return -EINVAL;
228
229 /* Only one width bit may be set */
230 if (!is_power_of_2(width_flag))
231 return -EINVAL;
232 230
233 if ((mt9m001->datawidth != 10 && (width_flag == IS_DATAWIDTH_10)) || 231 if ((mt9m001->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
234 (mt9m001->datawidth != 9 && (width_flag == IS_DATAWIDTH_9)) || 232 (mt9m001->datawidth != 9 && (width_flag == SOCAM_DATAWIDTH_9)) ||
235 (mt9m001->datawidth != 8 && (width_flag == IS_DATAWIDTH_8))) { 233 (mt9m001->datawidth != 8 && (width_flag == SOCAM_DATAWIDTH_8))) {
236 /* Well, we actually only can do 10 or 8 bits... */ 234 /* Well, we actually only can do 10 or 8 bits... */
237 if (width_flag == IS_DATAWIDTH_9) 235 if (width_flag == SOCAM_DATAWIDTH_9)
238 return -EINVAL; 236 return -EINVAL;
239 ret = bus_switch_act(mt9m001, 237 ret = bus_switch_act(mt9m001,
240 width_flag == IS_DATAWIDTH_8); 238 width_flag == SOCAM_DATAWIDTH_8);
241 if (ret < 0) 239 if (ret < 0)
242 return ret; 240 return ret;
243 241
244 mt9m001->datawidth = width_flag == IS_DATAWIDTH_8 ? 8 : 10; 242 mt9m001->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
245 } 243 }
246 244
245 return 0;
246}
247
248static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
249{
250 struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
251 unsigned int width_flag = SOCAM_DATAWIDTH_10;
252
253 if (bus_switch_possible(mt9m001))
254 width_flag |= SOCAM_DATAWIDTH_8;
255
256 /* MT9M001 has all capture_format parameters fixed */
257 return SOCAM_PCLK_SAMPLE_RISING |
258 SOCAM_HSYNC_ACTIVE_HIGH |
259 SOCAM_VSYNC_ACTIVE_HIGH |
260 SOCAM_MASTER |
261 width_flag;
262}
263
264static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
265 __u32 pixfmt, struct v4l2_rect *rect)
266{
267 struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
268 int ret;
269 const u16 hblank = 9, vblank = 25;
270
247 /* Blanking and start values - default... */ 271 /* Blanking and start values - default... */
248 ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank); 272 ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank);
249 if (ret >= 0) 273 if (ret >= 0)
@@ -348,12 +372,6 @@ static int mt9m001_set_register(struct soc_camera_device *icd,
348} 372}
349#endif 373#endif
350 374
351static unsigned int mt9m001_get_datawidth(struct soc_camera_device *icd)
352{
353 struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
354 return mt9m001->datawidth;
355}
356
357const struct v4l2_queryctrl mt9m001_controls[] = { 375const struct v4l2_queryctrl mt9m001_controls[] = {
358 { 376 {
359 .id = V4L2_CID_VFLIP, 377 .id = V4L2_CID_VFLIP,
@@ -401,11 +419,12 @@ static struct soc_camera_ops mt9m001_ops = {
401 .release = mt9m001_release, 419 .release = mt9m001_release,
402 .start_capture = mt9m001_start_capture, 420 .start_capture = mt9m001_start_capture,
403 .stop_capture = mt9m001_stop_capture, 421 .stop_capture = mt9m001_stop_capture,
404 .set_capture_format = mt9m001_set_capture_format, 422 .set_fmt_cap = mt9m001_set_fmt_cap,
405 .try_fmt_cap = mt9m001_try_fmt_cap, 423 .try_fmt_cap = mt9m001_try_fmt_cap,
424 .set_bus_param = mt9m001_set_bus_param,
425 .query_bus_param = mt9m001_query_bus_param,
406 .formats = NULL, /* Filled in later depending on the */ 426 .formats = NULL, /* Filled in later depending on the */
407 .num_formats = 0, /* camera type and data widths */ 427 .num_formats = 0, /* camera type and data widths */
408 .get_datawidth = mt9m001_get_datawidth,
409 .controls = mt9m001_controls, 428 .controls = mt9m001_controls,
410 .num_controls = ARRAY_SIZE(mt9m001_controls), 429 .num_controls = ARRAY_SIZE(mt9m001_controls),
411 .get_control = mt9m001_get_control, 430 .get_control = mt9m001_get_control,
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index d677344d233d..a2f161dcc72d 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -241,19 +241,89 @@ static int bus_switch_act(struct mt9v022 *mt9v022, int go8bit)
241#endif 241#endif
242} 242}
243 243
244static int mt9v022_set_capture_format(struct soc_camera_device *icd, 244static int bus_switch_possible(struct mt9v022 *mt9v022)
245 __u32 pixfmt, struct v4l2_rect *rect, unsigned int flags) 245{
246#ifdef CONFIG_MT9V022_PCA9536_SWITCH
247 return gpio_is_valid(mt9v022->switch_gpio);
248#else
249 return 0;
250#endif
251}
252
253static int mt9v022_set_bus_param(struct soc_camera_device *icd,
254 unsigned long flags)
246{ 255{
247 struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); 256 struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
248 unsigned int width_flag = flags & (IS_DATAWIDTH_10 | IS_DATAWIDTH_9 | 257 unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
249 IS_DATAWIDTH_8);
250 u16 pixclk = 0;
251 int ret; 258 int ret;
259 u16 pixclk = 0;
252 260
253 /* Only one width bit may be set */ 261 /* Only one width bit may be set */
254 if (!is_power_of_2(width_flag)) 262 if (!is_power_of_2(width_flag))
255 return -EINVAL; 263 return -EINVAL;
256 264
265 if ((mt9v022->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
266 (mt9v022->datawidth != 9 && (width_flag == SOCAM_DATAWIDTH_9)) ||
267 (mt9v022->datawidth != 8 && (width_flag == SOCAM_DATAWIDTH_8))) {
268 /* Well, we actually only can do 10 or 8 bits... */
269 if (width_flag == SOCAM_DATAWIDTH_9)
270 return -EINVAL;
271
272 ret = bus_switch_act(mt9v022,
273 width_flag == SOCAM_DATAWIDTH_8);
274 if (ret < 0)
275 return ret;
276
277 mt9v022->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
278 }
279
280 if (flags & SOCAM_PCLK_SAMPLE_RISING)
281 pixclk |= 0x10;
282
283 if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH))
284 pixclk |= 0x1;
285
286 if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH))
287 pixclk |= 0x2;
288
289 ret = reg_write(icd, MT9V022_PIXCLK_FV_LV, pixclk);
290 if (ret < 0)
291 return ret;
292
293 if (!(flags & SOCAM_MASTER))
294 mt9v022->chip_control &= ~0x8;
295
296 ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
297 if (ret < 0)
298 return ret;
299
300 dev_dbg(&icd->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
301 pixclk, mt9v022->chip_control);
302
303 return 0;
304}
305
306static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
307{
308 struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
309 unsigned int width_flag = SOCAM_DATAWIDTH_10;
310
311 if (bus_switch_possible(mt9v022))
312 width_flag |= SOCAM_DATAWIDTH_8;
313
314 return SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING |
315 SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW |
316 SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |
317 SOCAM_MASTER | SOCAM_SLAVE |
318 width_flag;
319}
320
321static int mt9v022_set_fmt_cap(struct soc_camera_device *icd,
322 __u32 pixfmt, struct v4l2_rect *rect)
323{
324 struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
325 int ret;
326
257 /* The caller provides a supported format, as verified per call to 327 /* The caller provides a supported format, as verified per call to
258 * icd->try_fmt_cap(), datawidth is from our supported format list */ 328 * icd->try_fmt_cap(), datawidth is from our supported format list */
259 switch (pixfmt) { 329 switch (pixfmt) {
@@ -308,44 +378,6 @@ static int mt9v022_set_capture_format(struct soc_camera_device *icd,
308 378
309 dev_dbg(&icd->dev, "Frame %ux%u pixel\n", rect->width, rect->height); 379 dev_dbg(&icd->dev, "Frame %ux%u pixel\n", rect->width, rect->height);
310 380
311 if ((mt9v022->datawidth != 10 && (width_flag == IS_DATAWIDTH_10)) ||
312 (mt9v022->datawidth != 9 && (width_flag == IS_DATAWIDTH_9)) ||
313 (mt9v022->datawidth != 8 && (width_flag == IS_DATAWIDTH_8))) {
314 /* Well, we actually only can do 10 or 8 bits... */
315 if (width_flag == IS_DATAWIDTH_9)
316 return -EINVAL;
317
318 ret = bus_switch_act(mt9v022,
319 width_flag == IS_DATAWIDTH_8);
320 if (ret < 0)
321 return ret;
322
323 mt9v022->datawidth = width_flag == IS_DATAWIDTH_8 ? 8 : 10;
324 }
325
326 if (flags & IS_PCLK_SAMPLE_RISING)
327 pixclk |= 0x10;
328
329 if (!(flags & IS_HSYNC_ACTIVE_HIGH))
330 pixclk |= 0x1;
331
332 if (!(flags & IS_VSYNC_ACTIVE_HIGH))
333 pixclk |= 0x2;
334
335 ret = reg_write(icd, MT9V022_PIXCLK_FV_LV, pixclk);
336 if (ret < 0)
337 return ret;
338
339 if (!(flags & IS_MASTER))
340 mt9v022->chip_control &= ~0x8;
341
342 ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
343 if (ret < 0)
344 return ret;
345
346 dev_dbg(&icd->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
347 pixclk, mt9v022->chip_control);
348
349 return 0; 381 return 0;
350} 382}
351 383
@@ -420,12 +452,6 @@ static int mt9v022_set_register(struct soc_camera_device *icd,
420} 452}
421#endif 453#endif
422 454
423static unsigned int mt9v022_get_datawidth(struct soc_camera_device *icd)
424{
425 struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
426 return mt9v022->datawidth;
427}
428
429const struct v4l2_queryctrl mt9v022_controls[] = { 455const struct v4l2_queryctrl mt9v022_controls[] = {
430 { 456 {
431 .id = V4L2_CID_VFLIP, 457 .id = V4L2_CID_VFLIP,
@@ -491,11 +517,12 @@ static struct soc_camera_ops mt9v022_ops = {
491 .release = mt9v022_release, 517 .release = mt9v022_release,
492 .start_capture = mt9v022_start_capture, 518 .start_capture = mt9v022_start_capture,
493 .stop_capture = mt9v022_stop_capture, 519 .stop_capture = mt9v022_stop_capture,
494 .set_capture_format = mt9v022_set_capture_format, 520 .set_fmt_cap = mt9v022_set_fmt_cap,
495 .try_fmt_cap = mt9v022_try_fmt_cap, 521 .try_fmt_cap = mt9v022_try_fmt_cap,
522 .set_bus_param = mt9v022_set_bus_param,
523 .query_bus_param = mt9v022_query_bus_param,
496 .formats = NULL, /* Filled in later depending on the */ 524 .formats = NULL, /* Filled in later depending on the */
497 .num_formats = 0, /* sensor type and data widths */ 525 .num_formats = 0, /* sensor type and data widths */
498 .get_datawidth = mt9v022_get_datawidth,
499 .controls = mt9v022_controls, 526 .controls = mt9v022_controls,
500 .num_controls = ARRAY_SIZE(mt9v022_controls), 527 .num_controls = ARRAY_SIZE(mt9v022_controls),
501 .get_control = mt9v022_get_control, 528 .get_control = mt9v022_get_control,
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 "
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 322f837bcfea..bd8677cb1cab 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -75,12 +75,13 @@ static int soc_camera_try_fmt_cap(struct file *file, void *priv,
75 return -EINVAL; 75 return -EINVAL;
76 } 76 }
77 77
78 /* limit to host capabilities */ 78 /* test physical bus parameters */
79 ret = ici->try_fmt_cap(ici, f); 79 ret = ici->try_bus_param(icd, f->fmt.pix.pixelformat);
80 if (ret)
81 return ret;
80 82
81 /* limit to sensor capabilities */ 83 /* limit format to hardware capabilities */
82 if (!ret) 84 ret = ici->try_fmt_cap(icd, f);
83 ret = icd->ops->try_fmt_cap(icd, f);
84 85
85 /* calculate missing fields */ 86 /* calculate missing fields */
86 f->fmt.pix.field = field; 87 f->fmt.pix.field = field;
@@ -344,8 +345,8 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv,
344 if (!data_fmt) 345 if (!data_fmt)
345 return -EINVAL; 346 return -EINVAL;
346 347
347 /* cached_datawidth may be further adjusted by the ici */ 348 /* buswidth may be further adjusted by the ici */
348 icd->cached_datawidth = data_fmt->depth; 349 icd->buswidth = data_fmt->depth;
349 350
350 ret = soc_camera_try_fmt_cap(file, icf, f); 351 ret = soc_camera_try_fmt_cap(file, icf, f);
351 if (ret < 0) 352 if (ret < 0)
@@ -355,22 +356,23 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv,
355 rect.top = icd->y_current; 356 rect.top = icd->y_current;
356 rect.width = f->fmt.pix.width; 357 rect.width = f->fmt.pix.width;
357 rect.height = f->fmt.pix.height; 358 rect.height = f->fmt.pix.height;
358 ret = ici->set_capture_format(icd, f->fmt.pix.pixelformat, &rect); 359 ret = ici->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect);
360 if (ret < 0)
361 return ret;
359 362
360 if (!ret) { 363 icd->current_fmt = data_fmt;
361 icd->current_fmt = data_fmt; 364 icd->width = rect.width;
362 icd->width = rect.width; 365 icd->height = rect.height;
363 icd->height = rect.height; 366 icf->vb_vidq.field = f->fmt.pix.field;
364 icf->vb_vidq.field = f->fmt.pix.field; 367 if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type)
365 if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type) 368 dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
366 dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", 369 f->type);
367 f->type);
368
369 dev_dbg(&icd->dev, "set width: %d height: %d\n",
370 icd->width, icd->height);
371 }
372 370
373 return ret; 371 dev_dbg(&icd->dev, "set width: %d height: %d\n",
372 icd->width, icd->height);
373
374 /* set physical bus parameters */
375 return ici->set_bus_param(icd, f->fmt.pix.pixelformat);
374} 376}
375 377
376static int soc_camera_enum_fmt_cap(struct file *file, void *priv, 378static int soc_camera_enum_fmt_cap(struct file *file, void *priv,
@@ -577,7 +579,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
577 if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 579 if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
578 return -EINVAL; 580 return -EINVAL;
579 581
580 ret = ici->set_capture_format(icd, 0, &a->c); 582 ret = ici->set_fmt_cap(icd, 0, &a->c);
581 if (!ret) { 583 if (!ret) {
582 icd->width = a->c.width; 584 icd->width = a->c.width;
583 icd->height = a->c.height; 585 icd->height = a->c.height;
@@ -860,9 +862,6 @@ int soc_camera_device_register(struct soc_camera_device *icd)
860 862
861 icd->dev.release = dummy_release; 863 icd->dev.release = dummy_release;
862 864
863 if (icd->ops->get_datawidth)
864 icd->cached_datawidth = icd->ops->get_datawidth(icd);
865
866 return scan_add_device(icd); 865 return scan_add_device(icd);
867} 866}
868EXPORT_SYMBOL(soc_camera_device_register); 867EXPORT_SYMBOL(soc_camera_device_register);
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index c886b1e64872..3e48e435b21a 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -34,7 +34,7 @@ struct soc_camera_device {
34 unsigned short exposure; 34 unsigned short exposure;
35 unsigned char iface; /* Host number */ 35 unsigned char iface; /* Host number */
36 unsigned char devnum; /* Device number per host */ 36 unsigned char devnum; /* Device number per host */
37 unsigned char cached_datawidth; /* See comment in .c */ 37 unsigned char buswidth; /* See comment in .c */
38 struct soc_camera_ops *ops; 38 struct soc_camera_ops *ops;
39 struct video_device *vdev; 39 struct video_device *vdev;
40 const struct soc_camera_data_format *current_fmt; 40 const struct soc_camera_data_format *current_fmt;
@@ -61,11 +61,13 @@ struct soc_camera_host {
61 char *drv_name; 61 char *drv_name;
62 int (*add)(struct soc_camera_device *); 62 int (*add)(struct soc_camera_device *);
63 void (*remove)(struct soc_camera_device *); 63 void (*remove)(struct soc_camera_device *);
64 int (*set_capture_format)(struct soc_camera_device *, __u32, 64 int (*set_fmt_cap)(struct soc_camera_device *, __u32,
65 struct v4l2_rect *); 65 struct v4l2_rect *);
66 int (*try_fmt_cap)(struct soc_camera_host *, struct v4l2_format *); 66 int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *);
67 int (*reqbufs)(struct soc_camera_file *, struct v4l2_requestbuffers *); 67 int (*reqbufs)(struct soc_camera_file *, struct v4l2_requestbuffers *);
68 int (*querycap)(struct soc_camera_host *, struct v4l2_capability *); 68 int (*querycap)(struct soc_camera_host *, struct v4l2_capability *);
69 int (*try_bus_param)(struct soc_camera_device *, __u32);
70 int (*set_bus_param)(struct soc_camera_device *, __u32);
69 unsigned int (*poll)(struct file *, poll_table *); 71 unsigned int (*poll)(struct file *, poll_table *);
70}; 72};
71 73
@@ -108,9 +110,11 @@ struct soc_camera_ops {
108 int (*release)(struct soc_camera_device *); 110 int (*release)(struct soc_camera_device *);
109 int (*start_capture)(struct soc_camera_device *); 111 int (*start_capture)(struct soc_camera_device *);
110 int (*stop_capture)(struct soc_camera_device *); 112 int (*stop_capture)(struct soc_camera_device *);
111 int (*set_capture_format)(struct soc_camera_device *, __u32, 113 int (*set_fmt_cap)(struct soc_camera_device *, __u32,
112 struct v4l2_rect *, unsigned int); 114 struct v4l2_rect *);
113 int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *); 115 int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *);
116 unsigned long (*query_bus_param)(struct soc_camera_device *);
117 int (*set_bus_param)(struct soc_camera_device *, unsigned long);
114 int (*get_chip_id)(struct soc_camera_device *, 118 int (*get_chip_id)(struct soc_camera_device *,
115 struct v4l2_chip_ident *); 119 struct v4l2_chip_ident *);
116#ifdef CONFIG_VIDEO_ADV_DEBUG 120#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -123,7 +127,6 @@ struct soc_camera_ops {
123 int (*set_control)(struct soc_camera_device *, struct v4l2_control *); 127 int (*set_control)(struct soc_camera_device *, struct v4l2_control *);
124 const struct v4l2_queryctrl *controls; 128 const struct v4l2_queryctrl *controls;
125 int num_controls; 129 int num_controls;
126 unsigned int(*get_datawidth)(struct soc_camera_device *icd);
127}; 130};
128 131
129static inline struct v4l2_queryctrl const *soc_camera_find_qctrl( 132static inline struct v4l2_queryctrl const *soc_camera_find_qctrl(
@@ -138,12 +141,33 @@ static inline struct v4l2_queryctrl const *soc_camera_find_qctrl(
138 return NULL; 141 return NULL;
139} 142}
140 143
141#define IS_MASTER (1<<0) 144#define SOCAM_MASTER (1 << 0)
142#define IS_HSYNC_ACTIVE_HIGH (1<<1) 145#define SOCAM_SLAVE (1 << 1)
143#define IS_VSYNC_ACTIVE_HIGH (1<<2) 146#define SOCAM_HSYNC_ACTIVE_HIGH (1 << 2)
144#define IS_DATAWIDTH_8 (1<<3) 147#define SOCAM_HSYNC_ACTIVE_LOW (1 << 3)
145#define IS_DATAWIDTH_9 (1<<4) 148#define SOCAM_VSYNC_ACTIVE_HIGH (1 << 4)
146#define IS_DATAWIDTH_10 (1<<5) 149#define SOCAM_VSYNC_ACTIVE_LOW (1 << 5)
147#define IS_PCLK_SAMPLE_RISING (1<<6) 150#define SOCAM_DATAWIDTH_8 (1 << 6)
151#define SOCAM_DATAWIDTH_9 (1 << 7)
152#define SOCAM_DATAWIDTH_10 (1 << 8)
153#define SOCAM_PCLK_SAMPLE_RISING (1 << 9)
154#define SOCAM_PCLK_SAMPLE_FALLING (1 << 10)
155
156#define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_9 | \
157 SOCAM_DATAWIDTH_10)
158
159static inline unsigned long soc_camera_bus_param_compatible(
160 unsigned long camera_flags, unsigned long bus_flags)
161{
162 unsigned long common_flags, hsync, vsync, pclk;
163
164 common_flags = camera_flags & bus_flags;
165
166 hsync = common_flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW);
167 vsync = common_flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW);
168 pclk = common_flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING);
169
170 return (!hsync || !vsync || !pclk) ? 0 : common_flags;
171}
148 172
149#endif 173#endif