diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/sh_mobile_ceu_camera.c | 309 |
1 files changed, 259 insertions, 50 deletions
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index c0dc4a1e8e52..3fee7c01fd57 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c | |||
@@ -92,10 +92,17 @@ struct sh_mobile_ceu_dev { | |||
92 | spinlock_t lock; | 92 | spinlock_t lock; |
93 | struct list_head capture; | 93 | struct list_head capture; |
94 | struct videobuf_buffer *active; | 94 | struct videobuf_buffer *active; |
95 | int is_interlaced; | ||
96 | 95 | ||
97 | struct sh_mobile_ceu_info *pdata; | 96 | struct sh_mobile_ceu_info *pdata; |
98 | 97 | ||
98 | unsigned int is_interlaced:1; | ||
99 | unsigned int image_mode:1; | ||
100 | unsigned int is_16bit:1; | ||
101 | }; | ||
102 | |||
103 | struct sh_mobile_ceu_cam { | ||
104 | struct v4l2_rect camera_rect; | ||
105 | const struct soc_camera_data_format *extra_fmt; | ||
99 | const struct soc_camera_data_format *camera_fmt; | 106 | const struct soc_camera_data_format *camera_fmt; |
100 | }; | 107 | }; |
101 | 108 | ||
@@ -428,14 +435,101 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) | |||
428 | pcdev->icd = NULL; | 435 | pcdev->icd = NULL; |
429 | } | 436 | } |
430 | 437 | ||
438 | static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd, | ||
439 | struct v4l2_rect *rect) | ||
440 | { | ||
441 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
442 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
443 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
444 | int width, height, cfszr_width, cdwdr_width; | ||
445 | unsigned int left_offset, top_offset; | ||
446 | u32 camor; | ||
447 | |||
448 | if (rect->left > cam->camera_rect.left) { | ||
449 | left_offset = rect->left - cam->camera_rect.left; | ||
450 | } else { | ||
451 | left_offset = 0; | ||
452 | rect->left = cam->camera_rect.left; | ||
453 | } | ||
454 | |||
455 | if (rect->top > cam->camera_rect.top) { | ||
456 | top_offset = rect->top - cam->camera_rect.top; | ||
457 | } else { | ||
458 | top_offset = 0; | ||
459 | rect->top = cam->camera_rect.top; | ||
460 | } | ||
461 | |||
462 | dev_dbg(&icd->dev, "Offsets %u:%u\n", left_offset, top_offset); | ||
463 | |||
464 | if (pcdev->image_mode) { | ||
465 | width = rect->width; | ||
466 | if (!pcdev->is_16bit) | ||
467 | width *= 2; | ||
468 | cfszr_width = cdwdr_width = rect->width; | ||
469 | } else { | ||
470 | width = rect->width * | ||
471 | ((icd->current_fmt->depth + 7) >> 3); | ||
472 | width = pcdev->is_16bit ? width / 2 : width; | ||
473 | cfszr_width = pcdev->is_16bit ? width : width / 2; | ||
474 | cdwdr_width = pcdev->is_16bit ? width * 2 : width; | ||
475 | } | ||
476 | |||
477 | height = rect->height; | ||
478 | if (pcdev->is_interlaced) { | ||
479 | height /= 2; | ||
480 | cdwdr_width *= 2; | ||
481 | } | ||
482 | |||
483 | camor = left_offset | (top_offset << 16); | ||
484 | ceu_write(pcdev, CAMOR, camor); | ||
485 | ceu_write(pcdev, CAPWR, (height << 16) | width); | ||
486 | ceu_write(pcdev, CFSZR, (height << 16) | cfszr_width); | ||
487 | ceu_write(pcdev, CDWDR, cdwdr_width); | ||
488 | } | ||
489 | |||
490 | static u32 capture_save_reset(struct sh_mobile_ceu_dev *pcdev) | ||
491 | { | ||
492 | u32 capsr = ceu_read(pcdev, CAPSR); | ||
493 | ceu_write(pcdev, CAPSR, 1 << 16); /* reset, stop capture */ | ||
494 | return capsr; | ||
495 | } | ||
496 | |||
497 | static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr) | ||
498 | { | ||
499 | unsigned long timeout = jiffies + 10 * HZ; | ||
500 | |||
501 | /* | ||
502 | * Wait until the end of the current frame. It can take a long time, | ||
503 | * but if it has been aborted by a CAPSR reset, it shoule exit sooner. | ||
504 | */ | ||
505 | while ((ceu_read(pcdev, CSTSR) & 1) && time_before(jiffies, timeout)) | ||
506 | msleep(1); | ||
507 | |||
508 | if (time_after(jiffies, timeout)) { | ||
509 | dev_err(pcdev->ici.v4l2_dev.dev, | ||
510 | "Timeout waiting for frame end! Interface problem?\n"); | ||
511 | return; | ||
512 | } | ||
513 | |||
514 | /* Wait until reset clears, this shall not hang... */ | ||
515 | while (ceu_read(pcdev, CAPSR) & (1 << 16)) | ||
516 | udelay(10); | ||
517 | |||
518 | /* Anything to restore? */ | ||
519 | if (capsr & ~(1 << 16)) | ||
520 | ceu_write(pcdev, CAPSR, capsr); | ||
521 | } | ||
522 | |||
431 | static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | 523 | static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, |
432 | __u32 pixfmt) | 524 | __u32 pixfmt) |
433 | { | 525 | { |
434 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 526 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
435 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 527 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
436 | int ret, buswidth, width, height, cfszr_width, cdwdr_width; | 528 | int ret; |
437 | unsigned long camera_flags, common_flags, value; | 529 | unsigned long camera_flags, common_flags, value; |
438 | int yuv_mode, yuv_lineskip; | 530 | int yuv_lineskip; |
531 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
532 | u32 capsr = capture_save_reset(pcdev); | ||
439 | 533 | ||
440 | camera_flags = icd->ops->query_bus_param(icd); | 534 | camera_flags = icd->ops->query_bus_param(icd); |
441 | common_flags = soc_camera_bus_param_compatible(camera_flags, | 535 | common_flags = soc_camera_bus_param_compatible(camera_flags, |
@@ -449,10 +543,10 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
449 | 543 | ||
450 | switch (common_flags & SOCAM_DATAWIDTH_MASK) { | 544 | switch (common_flags & SOCAM_DATAWIDTH_MASK) { |
451 | case SOCAM_DATAWIDTH_8: | 545 | case SOCAM_DATAWIDTH_8: |
452 | buswidth = 8; | 546 | pcdev->is_16bit = 0; |
453 | break; | 547 | break; |
454 | case SOCAM_DATAWIDTH_16: | 548 | case SOCAM_DATAWIDTH_16: |
455 | buswidth = 16; | 549 | pcdev->is_16bit = 1; |
456 | break; | 550 | break; |
457 | default: | 551 | default: |
458 | return -EINVAL; | 552 | return -EINVAL; |
@@ -462,7 +556,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
462 | ceu_write(pcdev, CRCMPR, 0); | 556 | ceu_write(pcdev, CRCMPR, 0); |
463 | 557 | ||
464 | value = 0x00000010; /* data fetch by default */ | 558 | value = 0x00000010; /* data fetch by default */ |
465 | yuv_mode = yuv_lineskip = 0; | 559 | pcdev->image_mode = yuv_lineskip = 0; |
466 | 560 | ||
467 | switch (icd->current_fmt->fourcc) { | 561 | switch (icd->current_fmt->fourcc) { |
468 | case V4L2_PIX_FMT_NV12: | 562 | case V4L2_PIX_FMT_NV12: |
@@ -471,8 +565,8 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
471 | /* fall-through */ | 565 | /* fall-through */ |
472 | case V4L2_PIX_FMT_NV16: | 566 | case V4L2_PIX_FMT_NV16: |
473 | case V4L2_PIX_FMT_NV61: | 567 | case V4L2_PIX_FMT_NV61: |
474 | yuv_mode = 1; | 568 | pcdev->image_mode = 1; |
475 | switch (pcdev->camera_fmt->fourcc) { | 569 | switch (cam->camera_fmt->fourcc) { |
476 | case V4L2_PIX_FMT_UYVY: | 570 | case V4L2_PIX_FMT_UYVY: |
477 | value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */ | 571 | value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */ |
478 | break; | 572 | break; |
@@ -496,36 +590,16 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
496 | 590 | ||
497 | value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; | 591 | value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; |
498 | value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; | 592 | value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; |
499 | value |= buswidth == 16 ? 1 << 12 : 0; | 593 | value |= pcdev->is_16bit ? 1 << 12 : 0; |
500 | ceu_write(pcdev, CAMCR, value); | 594 | ceu_write(pcdev, CAMCR, value); |
501 | 595 | ||
502 | ceu_write(pcdev, CAPCR, 0x00300000); | 596 | ceu_write(pcdev, CAPCR, 0x00300000); |
503 | ceu_write(pcdev, CAIFR, pcdev->is_interlaced ? 0x101 : 0); | 597 | ceu_write(pcdev, CAIFR, pcdev->is_interlaced ? 0x101 : 0); |
504 | 598 | ||
505 | mdelay(1); | 599 | mdelay(1); |
600 | sh_mobile_ceu_set_rect(icd, &icd->rect_current); | ||
506 | 601 | ||
507 | if (yuv_mode) { | ||
508 | width = icd->rect_current.width * 2; | ||
509 | width = buswidth == 16 ? width / 2 : width; | ||
510 | cfszr_width = cdwdr_width = icd->rect_current.width; | ||
511 | } else { | ||
512 | width = icd->rect_current.width * | ||
513 | ((icd->current_fmt->depth + 7) >> 3); | ||
514 | width = buswidth == 16 ? width / 2 : width; | ||
515 | cfszr_width = buswidth == 8 ? width / 2 : width; | ||
516 | cdwdr_width = buswidth == 16 ? width * 2 : width; | ||
517 | } | ||
518 | |||
519 | height = icd->rect_current.height; | ||
520 | if (pcdev->is_interlaced) { | ||
521 | height /= 2; | ||
522 | cdwdr_width *= 2; | ||
523 | } | ||
524 | |||
525 | ceu_write(pcdev, CAMOR, 0); | ||
526 | ceu_write(pcdev, CAPWR, (height << 16) | width); | ||
527 | ceu_write(pcdev, CFLCR, 0); /* no scaling */ | 602 | ceu_write(pcdev, CFLCR, 0); /* no scaling */ |
528 | ceu_write(pcdev, CFSZR, (height << 16) | cfszr_width); | ||
529 | 603 | ||
530 | /* A few words about byte order (observed in Big Endian mode) | 604 | /* A few words about byte order (observed in Big Endian mode) |
531 | * | 605 | * |
@@ -544,10 +618,16 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
544 | value &= ~0x00000010; /* convert 4:2:2 -> 4:2:0 */ | 618 | value &= ~0x00000010; /* convert 4:2:2 -> 4:2:0 */ |
545 | 619 | ||
546 | ceu_write(pcdev, CDOCR, value); | 620 | ceu_write(pcdev, CDOCR, value); |
547 | |||
548 | ceu_write(pcdev, CDWDR, cdwdr_width); | ||
549 | ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ | 621 | ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ |
550 | 622 | ||
623 | dev_dbg(&icd->dev, "S_FMT successful for %c%c%c%c %ux%u@%u.%u\n", | ||
624 | pixfmt & 0xff, (pixfmt >> 8) & 0xff, | ||
625 | (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff, | ||
626 | icd->rect_current.width, icd->rect_current.height, | ||
627 | icd->rect_current.left, icd->rect_current.top); | ||
628 | |||
629 | capture_restore(pcdev, capsr); | ||
630 | |||
551 | /* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */ | 631 | /* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */ |
552 | return 0; | 632 | return 0; |
553 | } | 633 | } |
@@ -600,21 +680,32 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, | |||
600 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 680 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
601 | int ret, k, n; | 681 | int ret, k, n; |
602 | int formats = 0; | 682 | int formats = 0; |
683 | struct sh_mobile_ceu_cam *cam; | ||
603 | 684 | ||
604 | ret = sh_mobile_ceu_try_bus_param(icd); | 685 | ret = sh_mobile_ceu_try_bus_param(icd); |
605 | if (ret < 0) | 686 | if (ret < 0) |
606 | return 0; | 687 | return 0; |
607 | 688 | ||
689 | if (!icd->host_priv) { | ||
690 | cam = kzalloc(sizeof(*cam), GFP_KERNEL); | ||
691 | if (!cam) | ||
692 | return -ENOMEM; | ||
693 | |||
694 | icd->host_priv = cam; | ||
695 | } else { | ||
696 | cam = icd->host_priv; | ||
697 | } | ||
698 | |||
608 | /* Beginning of a pass */ | 699 | /* Beginning of a pass */ |
609 | if (!idx) | 700 | if (!idx) |
610 | icd->host_priv = NULL; | 701 | cam->extra_fmt = NULL; |
611 | 702 | ||
612 | switch (icd->formats[idx].fourcc) { | 703 | switch (icd->formats[idx].fourcc) { |
613 | case V4L2_PIX_FMT_UYVY: | 704 | case V4L2_PIX_FMT_UYVY: |
614 | case V4L2_PIX_FMT_VYUY: | 705 | case V4L2_PIX_FMT_VYUY: |
615 | case V4L2_PIX_FMT_YUYV: | 706 | case V4L2_PIX_FMT_YUYV: |
616 | case V4L2_PIX_FMT_YVYU: | 707 | case V4L2_PIX_FMT_YVYU: |
617 | if (icd->host_priv) | 708 | if (cam->extra_fmt) |
618 | goto add_single_format; | 709 | goto add_single_format; |
619 | 710 | ||
620 | /* | 711 | /* |
@@ -626,7 +717,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, | |||
626 | * the host_priv pointer and check whether the format you're | 717 | * the host_priv pointer and check whether the format you're |
627 | * going to add now is already there. | 718 | * going to add now is already there. |
628 | */ | 719 | */ |
629 | icd->host_priv = (void *)sh_mobile_ceu_formats; | 720 | cam->extra_fmt = (void *)sh_mobile_ceu_formats; |
630 | 721 | ||
631 | n = ARRAY_SIZE(sh_mobile_ceu_formats); | 722 | n = ARRAY_SIZE(sh_mobile_ceu_formats); |
632 | formats += n; | 723 | formats += n; |
@@ -657,18 +748,130 @@ add_single_format: | |||
657 | return formats; | 748 | return formats; |
658 | } | 749 | } |
659 | 750 | ||
751 | static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd) | ||
752 | { | ||
753 | kfree(icd->host_priv); | ||
754 | icd->host_priv = NULL; | ||
755 | } | ||
756 | |||
757 | static bool is_smaller(struct v4l2_rect *r1, struct v4l2_rect *r2) | ||
758 | { | ||
759 | return r1->width < r2->width || r1->height < r2->height; | ||
760 | } | ||
761 | |||
660 | static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | 762 | static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, |
661 | struct v4l2_rect *rect) | 763 | struct v4l2_rect *rect) |
662 | { | 764 | { |
663 | return icd->ops->set_crop(icd, rect); | 765 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
766 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
767 | struct v4l2_rect cam_rect = *rect; | ||
768 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | ||
769 | unsigned short width, height; | ||
770 | u32 capsr; | ||
771 | int ret; | ||
772 | |||
773 | capsr = capture_save_reset(pcdev); | ||
774 | dev_dbg(&icd->dev, "CAPSR %x\n", capsr); | ||
775 | |||
776 | ret = icd->ops->set_crop(icd, &cam_rect); | ||
777 | if (!ret && !memcmp(rect, &cam_rect, sizeof(*rect))) { | ||
778 | dev_dbg(&icd->dev, "Camera S_CROP successful for %ux%u@%u.%u\n", | ||
779 | cam_rect.width, cam_rect.height, | ||
780 | cam_rect.left, cam_rect.top); | ||
781 | goto ceu_set_rect; | ||
782 | } | ||
783 | |||
784 | /* Try to fix cropping, that camera hasn't managed to do */ | ||
785 | dev_dbg(&icd->dev, "Fix camera S_CROP %d for %ux%u@%u.%u\n", | ||
786 | ret, cam_rect.width, cam_rect.height, | ||
787 | cam_rect.left, cam_rect.top); | ||
788 | |||
789 | /* | ||
790 | * Popular special case - some cameras can only handle fixed sizes like | ||
791 | * QVGA, VGA,... Take care to avoid infinite loop. | ||
792 | */ | ||
793 | width = max(cam_rect.width, 1) * 2; | ||
794 | height = max(cam_rect.height, 1) * 2; | ||
795 | while (!ret && is_smaller(&cam_rect, rect) && | ||
796 | (icd->rect_max.width >= width && | ||
797 | icd->rect_max.height >= height)) { | ||
798 | cam_rect.width = width; | ||
799 | cam_rect.height = height; | ||
800 | |||
801 | if (cam_rect.width + cam_rect.left > | ||
802 | icd->rect_max.width + icd->rect_max.left) | ||
803 | cam_rect.left = icd->rect_max.width + | ||
804 | icd->rect_max.left - cam_rect.width; | ||
805 | |||
806 | if (cam_rect.height + cam_rect.top > | ||
807 | icd->rect_max.height + icd->rect_max.top) | ||
808 | cam_rect.top = icd->rect_max.height + | ||
809 | icd->rect_max.top - cam_rect.height; | ||
810 | |||
811 | ret = icd->ops->set_crop(icd, &cam_rect); | ||
812 | dev_dbg(&icd->dev, "Camera S_CROP %d for %ux%u@%u.%u\n", | ||
813 | ret, cam_rect.width, cam_rect.height, | ||
814 | cam_rect.left, cam_rect.top); | ||
815 | width *= 2; | ||
816 | height *= 2; | ||
817 | } | ||
818 | |||
819 | /* | ||
820 | * If the camera failed to configure cropping, it should not modify the | ||
821 | * rectangle | ||
822 | */ | ||
823 | if ((ret < 0 && is_smaller(&icd->rect_current, rect)) || | ||
824 | is_smaller(&cam_rect, rect)) { | ||
825 | /* | ||
826 | * The camera failed to configure a suitable cropping, | ||
827 | * we cannot use the current rectangle, set to max | ||
828 | */ | ||
829 | cam_rect = icd->rect_max; | ||
830 | ret = icd->ops->set_crop(icd, &cam_rect); | ||
831 | dev_dbg(&icd->dev, "Camera S_CROP %d for max %ux%u@%u.%u\n", | ||
832 | ret, cam_rect.width, cam_rect.height, | ||
833 | cam_rect.left, cam_rect.top); | ||
834 | if (ret < 0) | ||
835 | /* All failed, hopefully resume current capture */ | ||
836 | goto resume_capture; | ||
837 | } | ||
838 | |||
839 | /* We now have a rectangle, larger than requested, let's crop */ | ||
840 | |||
841 | /* | ||
842 | * We have to preserve camera rectangle between close() / open(), | ||
843 | * because soc-camera core calls .set_fmt() on each first open() with | ||
844 | * last before last close() _user_ rectangle, which can be different | ||
845 | * from camera rectangle. | ||
846 | */ | ||
847 | dev_dbg(&icd->dev, "SH S_CROP from %ux%u@%u.%u to %ux%u@%u.%u\n", | ||
848 | cam_rect.width, cam_rect.height, cam_rect.left, cam_rect.top, | ||
849 | rect->width, rect->height, rect->left, rect->top); | ||
850 | |||
851 | ret = 0; | ||
852 | |||
853 | ceu_set_rect: | ||
854 | cam->camera_rect = cam_rect; | ||
855 | |||
856 | /* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */ | ||
857 | if (pcdev->active) | ||
858 | capsr |= 1; | ||
859 | sh_mobile_ceu_set_rect(icd, rect); | ||
860 | capture_restore(pcdev, capsr); | ||
861 | |||
862 | resume_capture: | ||
863 | |||
864 | /* Even if only camera cropping succeeded */ | ||
865 | return ret; | ||
664 | } | 866 | } |
665 | 867 | ||
666 | static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | 868 | static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, |
667 | struct v4l2_format *f) | 869 | struct v4l2_format *f) |
668 | { | 870 | { |
669 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 871 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
670 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 872 | struct sh_mobile_ceu_cam *cam = icd->host_priv; |
671 | __u32 pixfmt = f->fmt.pix.pixelformat; | 873 | struct v4l2_pix_format *pix = &f->fmt.pix; |
874 | __u32 pixfmt = pix->pixelformat; | ||
672 | const struct soc_camera_format_xlate *xlate; | 875 | const struct soc_camera_format_xlate *xlate; |
673 | int ret; | 876 | int ret; |
674 | 877 | ||
@@ -678,13 +881,17 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
678 | return -EINVAL; | 881 | return -EINVAL; |
679 | } | 882 | } |
680 | 883 | ||
681 | f->fmt.pix.pixelformat = xlate->cam_fmt->fourcc; | 884 | pix->pixelformat = xlate->cam_fmt->fourcc; |
682 | ret = v4l2_device_call_until_err(&ici->v4l2_dev, (__u32)icd, video, s_fmt, f); | 885 | ret = v4l2_device_call_until_err(&ici->v4l2_dev, (__u32)icd, video, s_fmt, f); |
683 | f->fmt.pix.pixelformat = pixfmt; | 886 | pix->pixelformat = pixfmt; |
684 | if (!ret) { | 887 | if (!ret) { |
685 | icd->buswidth = xlate->buswidth; | 888 | icd->buswidth = xlate->buswidth; |
686 | icd->current_fmt = xlate->host_fmt; | 889 | icd->current_fmt = xlate->host_fmt; |
687 | pcdev->camera_fmt = xlate->cam_fmt; | 890 | cam->camera_fmt = xlate->cam_fmt; |
891 | cam->camera_rect.width = pix->width; | ||
892 | cam->camera_rect.height = pix->height; | ||
893 | cam->camera_rect.left = icd->rect_current.left; | ||
894 | cam->camera_rect.top = icd->rect_current.top; | ||
688 | } | 895 | } |
689 | 896 | ||
690 | return ret; | 897 | return ret; |
@@ -696,7 +903,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | |||
696 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 903 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
697 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 904 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
698 | const struct soc_camera_format_xlate *xlate; | 905 | const struct soc_camera_format_xlate *xlate; |
699 | __u32 pixfmt = f->fmt.pix.pixelformat; | 906 | struct v4l2_pix_format *pix = &f->fmt.pix; |
907 | __u32 pixfmt = pix->pixelformat; | ||
700 | int ret; | 908 | int ret; |
701 | 909 | ||
702 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 910 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); |
@@ -707,27 +915,27 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | |||
707 | 915 | ||
708 | /* FIXME: calculate using depth and bus width */ | 916 | /* FIXME: calculate using depth and bus width */ |
709 | 917 | ||
710 | v4l_bound_align_image(&f->fmt.pix.width, 2, 2560, 1, | 918 | v4l_bound_align_image(&pix->width, 2, 2560, 1, |
711 | &f->fmt.pix.height, 4, 1920, 2, 0); | 919 | &pix->height, 4, 1920, 2, 0); |
712 | 920 | ||
713 | f->fmt.pix.bytesperline = f->fmt.pix.width * | 921 | pix->bytesperline = pix->width * |
714 | DIV_ROUND_UP(xlate->host_fmt->depth, 8); | 922 | DIV_ROUND_UP(xlate->host_fmt->depth, 8); |
715 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | 923 | pix->sizeimage = pix->height * pix->bytesperline; |
716 | 924 | ||
717 | f->fmt.pix.pixelformat = xlate->cam_fmt->fourcc; | 925 | pix->pixelformat = xlate->cam_fmt->fourcc; |
718 | 926 | ||
719 | /* limit to sensor capabilities */ | 927 | /* limit to sensor capabilities */ |
720 | ret = v4l2_device_call_until_err(&ici->v4l2_dev, (__u32)icd, video, try_fmt, f); | 928 | ret = v4l2_device_call_until_err(&ici->v4l2_dev, (__u32)icd, video, try_fmt, f); |
721 | f->fmt.pix.pixelformat = pixfmt; | 929 | pix->pixelformat = pixfmt; |
722 | if (ret < 0) | 930 | if (ret < 0) |
723 | return ret; | 931 | return ret; |
724 | 932 | ||
725 | switch (f->fmt.pix.field) { | 933 | switch (pix->field) { |
726 | case V4L2_FIELD_INTERLACED: | 934 | case V4L2_FIELD_INTERLACED: |
727 | pcdev->is_interlaced = 1; | 935 | pcdev->is_interlaced = 1; |
728 | break; | 936 | break; |
729 | case V4L2_FIELD_ANY: | 937 | case V4L2_FIELD_ANY: |
730 | f->fmt.pix.field = V4L2_FIELD_NONE; | 938 | pix->field = V4L2_FIELD_NONE; |
731 | /* fall-through */ | 939 | /* fall-through */ |
732 | case V4L2_FIELD_NONE: | 940 | case V4L2_FIELD_NONE: |
733 | pcdev->is_interlaced = 0; | 941 | pcdev->is_interlaced = 0; |
@@ -856,6 +1064,7 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { | |||
856 | .add = sh_mobile_ceu_add_device, | 1064 | .add = sh_mobile_ceu_add_device, |
857 | .remove = sh_mobile_ceu_remove_device, | 1065 | .remove = sh_mobile_ceu_remove_device, |
858 | .get_formats = sh_mobile_ceu_get_formats, | 1066 | .get_formats = sh_mobile_ceu_get_formats, |
1067 | .put_formats = sh_mobile_ceu_put_formats, | ||
859 | .set_crop = sh_mobile_ceu_set_crop, | 1068 | .set_crop = sh_mobile_ceu_set_crop, |
860 | .set_fmt = sh_mobile_ceu_set_fmt, | 1069 | .set_fmt = sh_mobile_ceu_set_fmt, |
861 | .try_fmt = sh_mobile_ceu_try_fmt, | 1070 | .try_fmt = sh_mobile_ceu_try_fmt, |