[PATCH 3/4] soc-camera: sh_mobile_ceu: Add V4L2_FIELD_INTERLACED_BT/TB support
Kuninori Morimoto <[email protected]>
| Newsgroups | gmane.comp.video.video4linux |
|---|---|
| Message-ID | <uab0d9hue.wl%[email protected]> |
Signed-off-by: Kuninori Morimoto <[email protected]> --- drivers/media/video/sh_mobile_ceu_camera.c | 75 +++++++++++++++++++--------- 1 files changed, 52 insertions(+), 23 deletions(-) diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 65ac474..3e15114 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -104,7 +104,8 @@ struct sh_mobile_ceu_dev { u32 cflcr; - unsigned int is_interlaced:1; + enum v4l2_field field; + unsigned int image_mode:1; unsigned int is_16bit:1; }; @@ -208,6 +209,8 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) { struct soc_camera_device *icd = pcdev->icd; dma_addr_t phys_addr_top, phys_addr_bottom; + unsigned long top1, top2; + unsigned long bottom1, bottom2; /* The hardware is _very_ picky about this sequence. Especially * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge @@ -222,11 +225,23 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) if (!pcdev->active) return; + if (V4L2_FIELD_INTERLACED_BT == pcdev->field) { + top1 = CDBYR; + top2 = CDBCR; + bottom1 = CDAYR; + bottom2 = CDACR; + } else { + top1 = CDAYR; + top2 = CDACR; + bottom1 = CDBYR; + bottom2 = CDBCR; + } + phys_addr_top = videobuf_to_dma_contig(pcdev->active); - ceu_write(pcdev, CDAYR, phys_addr_top); - if (pcdev->is_interlaced) { + ceu_write(pcdev, top1, phys_addr_top); + if (V4L2_FIELD_NONE != pcdev->field) { phys_addr_bottom = phys_addr_top + icd->user_width; - ceu_write(pcdev, CDBYR, phys_addr_bottom); + ceu_write(pcdev, bottom1, phys_addr_bottom); } switch (icd->current_fmt->fourcc) { @@ -236,11 +251,10 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) case V4L2_PIX_FMT_NV61: phys_addr_top += icd->user_width * icd->user_height; - ceu_write(pcdev, CDACR, phys_addr_top); - if (pcdev->is_interlaced) { - phys_addr_bottom = phys_addr_top + - icd->user_width; - ceu_write(pcdev, CDBCR, phys_addr_bottom); + ceu_write(pcdev, top2, phys_addr_top); + if (V4L2_FIELD_NONE != pcdev->field) { + phys_addr_bottom = phys_addr_top + icd->user_width; + ceu_write(pcdev, bottom2, phys_addr_bottom); } } @@ -519,7 +533,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd, height = out_height; in_height = rect->height; - if (pcdev->is_interlaced) { + if (V4L2_FIELD_NONE != pcdev->field) { height /= 2; in_height /= 2; top_offset /= 2; @@ -646,7 +660,19 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, ceu_write(pcdev, CAMCR, value); ceu_write(pcdev, CAPCR, 0x00300000); - ceu_write(pcdev, CAIFR, pcdev->is_interlaced ? 0x101 : 0); + + switch (pcdev->field) { + case V4L2_FIELD_INTERLACED_TB: + value = 0x101; + break; + case V4L2_FIELD_INTERLACED_BT: + value = 0x102; + break; + default: + value = 0; + break; + } + ceu_write(pcdev, CAIFR, value); sh_mobile_ceu_set_rect(icd, icd->user_width, icd->user_height); mdelay(1); @@ -1265,7 +1291,8 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ret = client_scale(icd, cam_rect, rect, ceu_rect, &f, - pcdev->image_mode && !pcdev->is_interlaced); + pcdev->image_mode && + V4L2_FIELD_NONE == pcdev->field); dev_geo(dev, "6-9: %d\n", ret); @@ -1323,18 +1350,20 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, unsigned int scale_cam_h, scale_cam_v; u16 scale_v, scale_h; int ret; - bool is_interlaced, image_mode; + bool image_mode; + enum v4l2_field field; switch (pix->field) { + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: + case V4L2_FIELD_NONE: + field = pix->field; + break; case V4L2_FIELD_INTERLACED: - is_interlaced = true; + field = V4L2_FIELD_INTERLACED_TB; break; - case V4L2_FIELD_ANY: default: - pix->field = V4L2_FIELD_NONE; - /* fall-through */ - case V4L2_FIELD_NONE: - is_interlaced = false; + field = pix->field = V4L2_FIELD_NONE; break; } @@ -1402,7 +1431,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, /* 5. - 9. */ ret = client_scale(icd, cam_rect, &cam_subrect, &ceu_rect, &cam_f, - image_mode && !is_interlaced); + image_mode && + V4L2_FIELD_NONE == field); dev_geo(dev, "5-9: client scale %d\n", ret); @@ -1441,7 +1471,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, cam->camera_fmt = xlate->cam_fmt; cam->ceu_rect = ceu_rect; - pcdev->is_interlaced = is_interlaced; + pcdev->field = field; pcdev->image_mode = image_mode; return 0; @@ -1568,8 +1598,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q, &sh_mobile_ceu_videobuf_ops, icd->dev.parent, &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, - pcdev->is_interlaced ? - V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE, + pcdev->field, sizeof(struct sh_mobile_ceu_buffer), icd); } -- 1.6.0.4 -- video4linux-list mailing list Unsubscribe mailto:[email protected]?subject=unsubscribe https://www.redhat.com/mailman/listinfo/video4linux-list