aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c56
1 files changed, 46 insertions, 10 deletions
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 79eda0fed9f9..6750c49f4c04 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -94,6 +94,7 @@ struct sh_mobile_ceu_dev {
94 spinlock_t lock; 94 spinlock_t lock;
95 struct list_head capture; 95 struct list_head capture;
96 struct videobuf_buffer *active; 96 struct videobuf_buffer *active;
97 int is_interlace;
97 98
98 struct sh_mobile_ceu_info *pdata; 99 struct sh_mobile_ceu_info *pdata;
99 100
@@ -163,7 +164,7 @@ static void free_buffer(struct videobuf_queue *vq,
163static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) 164static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
164{ 165{
165 struct soc_camera_device *icd = pcdev->icd; 166 struct soc_camera_device *icd = pcdev->icd;
166 dma_addr_t phys_addr; 167 dma_addr_t phys_addr_top, phys_addr_bottom;
167 168
168 /* The hardware is _very_ picky about this sequence. Especially 169 /* The hardware is _very_ picky about this sequence. Especially
169 * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge 170 * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge
@@ -178,16 +179,24 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
178 if (!pcdev->active) 179 if (!pcdev->active)
179 return; 180 return;
180 181
181 phys_addr = videobuf_to_dma_contig(pcdev->active); 182 phys_addr_top = videobuf_to_dma_contig(pcdev->active);
182 ceu_write(pcdev, CDAYR, phys_addr); 183 ceu_write(pcdev, CDAYR, phys_addr_top);
184 if (pcdev->is_interlace) {
185 phys_addr_bottom = phys_addr_top + icd->width;
186 ceu_write(pcdev, CDBYR, phys_addr_bottom);
187 }
183 188
184 switch (icd->current_fmt->fourcc) { 189 switch (icd->current_fmt->fourcc) {
185 case V4L2_PIX_FMT_NV12: 190 case V4L2_PIX_FMT_NV12:
186 case V4L2_PIX_FMT_NV21: 191 case V4L2_PIX_FMT_NV21:
187 case V4L2_PIX_FMT_NV16: 192 case V4L2_PIX_FMT_NV16:
188 case V4L2_PIX_FMT_NV61: 193 case V4L2_PIX_FMT_NV61:
189 phys_addr += icd->width * icd->height; 194 phys_addr_top += icd->width * icd->height;
190 ceu_write(pcdev, CDACR, phys_addr); 195 ceu_write(pcdev, CDACR, phys_addr_top);
196 if (pcdev->is_interlace) {
197 phys_addr_bottom = phys_addr_top + icd->width;
198 ceu_write(pcdev, CDBCR, phys_addr_bottom);
199 }
191 } 200 }
192 201
193 pcdev->active->state = VIDEOBUF_ACTIVE; 202 pcdev->active->state = VIDEOBUF_ACTIVE;
@@ -381,7 +390,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
381{ 390{
382 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 391 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
383 struct sh_mobile_ceu_dev *pcdev = ici->priv; 392 struct sh_mobile_ceu_dev *pcdev = ici->priv;
384 int ret, buswidth, width, cfszr_width, cdwdr_width; 393 int ret, buswidth, width, height, cfszr_width, cdwdr_width;
385 unsigned long camera_flags, common_flags, value; 394 unsigned long camera_flags, common_flags, value;
386 int yuv_mode, yuv_lineskip; 395 int yuv_mode, yuv_lineskip;
387 396
@@ -448,7 +457,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
448 ceu_write(pcdev, CAMCR, value); 457 ceu_write(pcdev, CAMCR, value);
449 458
450 ceu_write(pcdev, CAPCR, 0x00300000); 459 ceu_write(pcdev, CAPCR, 0x00300000);
451 ceu_write(pcdev, CAIFR, 0); 460 ceu_write(pcdev, CAIFR, (pcdev->is_interlace) ? 0x101 : 0);
452 461
453 mdelay(1); 462 mdelay(1);
454 463
@@ -463,10 +472,16 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
463 cdwdr_width = buswidth == 16 ? width * 2 : width; 472 cdwdr_width = buswidth == 16 ? width * 2 : width;
464 } 473 }
465 474
475 height = icd->height;
476 if (pcdev->is_interlace) {
477 height /= 2;
478 cdwdr_width *= 2;
479 }
480
466 ceu_write(pcdev, CAMOR, 0); 481 ceu_write(pcdev, CAMOR, 0);
467 ceu_write(pcdev, CAPWR, (icd->height << 16) | width); 482 ceu_write(pcdev, CAPWR, (height << 16) | width);
468 ceu_write(pcdev, CFLCR, 0); /* no scaling */ 483 ceu_write(pcdev, CFLCR, 0); /* no scaling */
469 ceu_write(pcdev, CFSZR, (icd->height << 16) | cfszr_width); 484 ceu_write(pcdev, CFSZR, (height << 16) | cfszr_width);
470 ceu_write(pcdev, CLFCR, 0); /* no lowpass filter */ 485 ceu_write(pcdev, CLFCR, 0); /* no lowpass filter */
471 486
472 /* A few words about byte order (observed in Big Endian mode) 487 /* A few words about byte order (observed in Big Endian mode)
@@ -615,8 +630,10 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
615 struct v4l2_format *f) 630 struct v4l2_format *f)
616{ 631{
617 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 632 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
633 struct sh_mobile_ceu_dev *pcdev = ici->priv;
618 const struct soc_camera_format_xlate *xlate; 634 const struct soc_camera_format_xlate *xlate;
619 __u32 pixfmt = f->fmt.pix.pixelformat; 635 __u32 pixfmt = f->fmt.pix.pixelformat;
636 int ret;
620 637
621 xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); 638 xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
622 if (!xlate) { 639 if (!xlate) {
@@ -642,7 +659,26 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
642 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; 659 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
643 660
644 /* limit to sensor capabilities */ 661 /* limit to sensor capabilities */
645 return icd->ops->try_fmt(icd, f); 662 ret = icd->ops->try_fmt(icd, f);
663 if (ret < 0)
664 return ret;
665
666 switch (f->fmt.pix.field) {
667 case V4L2_FIELD_INTERLACED:
668 pcdev->is_interlace = 1;
669 break;
670 case V4L2_FIELD_ANY:
671 f->fmt.pix.field = V4L2_FIELD_NONE;
672 /* fall-through */
673 case V4L2_FIELD_NONE:
674 pcdev->is_interlace = 0;
675 break;
676 default:
677 ret = -EINVAL;
678 break;
679 }
680
681 return ret;
646} 682}
647 683
648static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf, 684static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf,