]> err.no Git - linux-2.6/blobdiff - drivers/media/video/pxa_camera.c
V4L/DVB (8340): videobuf: Fix gather spelling
[linux-2.6] / drivers / media / video / pxa_camera.c
index b999bda23c48194b07a223c8315c94b2b500d0c5..b15f82c497662550e4404611e9f1b0aa9e3811cc 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
+#include <media/videobuf-dma-sg.h>
 #include <media/soc_camera.h>
 
 #include <linux/videodev2.h>
@@ -102,11 +103,6 @@ struct pxa_buffer {
        enum pxa_camera_active_dma active_dma;
 };
 
-struct pxa_framebuffer_queue {
-       dma_addr_t              sg_last_dma;
-       struct pxa_dma_desc     *sg_last_cpu;
-};
-
 struct pxa_camera_dev {
        struct device           *dev;
        /* PXA27x is only supposed to handle one camera on its Quick Capture
@@ -118,6 +114,7 @@ struct pxa_camera_dev {
        unsigned int            irq;
        void __iomem            *base;
 
+       int                     channels;
        unsigned int            dma_chans[3];
 
        struct pxacamera_platform_data *pdata;
@@ -130,6 +127,7 @@ struct pxa_camera_dev {
        spinlock_t              lock;
 
        struct pxa_buffer       *active;
+       struct pxa_dma_desc     *sg_tail[3];
 };
 
 static const char *pxa_cam_driver_description = "PXA_Camera";
@@ -143,11 +141,14 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
                              unsigned int *size)
 {
        struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_host *ici =
+               to_soc_camera_host(icd->dev.parent);
+       struct pxa_camera_dev *pcdev = ici->priv;
 
        dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
 
        /* planar capture requires Y, U and V buffers to be page aligned */
-       if (icd->current_fmt->fourcc == V4L2_PIX_FMT_YUV422P) {
+       if (pcdev->channels == 3) {
                *size = PAGE_ALIGN(icd->width * icd->height); /* Y pages */
                *size += PAGE_ALIGN(icd->width * icd->height / 2); /* U pages */
                *size += PAGE_ALIGN(icd->width * icd->height / 2); /* V pages */
@@ -295,7 +296,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
                if (ret)
                        goto fail;
 
-               if (buf->fmt->fourcc == V4L2_PIX_FMT_YUV422P) {
+               if (pcdev->channels == 3) {
                        /* FIXME the calculations should be more precise */
                        sglen_y = dma->sglen / 2;
                        sglen_u = sglen_v = dma->sglen / 4 + 1;
@@ -317,7 +318,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
                        goto fail;
                }
 
-               if (buf->fmt->fourcc == V4L2_PIX_FMT_YUV422P) {
+               if (pcdev->channels == 3) {
                        /* init DMA for U channel */
                        ret = pxa_init_dma_channel(pcdev, buf, dma, 1, sglen_u,
                                                   sglen_y, 0x30, size_u);
@@ -342,7 +343,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
 
        buf->inwork = 0;
        buf->active_dma = DMA_Y;
-       if (buf->fmt->fourcc == V4L2_PIX_FMT_YUV422P)
+       if (pcdev->channels == 3)
                buf->active_dma |= DMA_U | DMA_V;
 
        return 0;
@@ -370,6 +371,7 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
        struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
        struct pxa_buffer *active;
        unsigned long flags;
+       int i;
 
        dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
@@ -382,15 +384,11 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
 
        if (!active) {
                CIFR |= CIFR_RESET_F;
-               DDADR(pcdev->dma_chans[0]) = buf->dmas[0].sg_dma;
-               DCSR(pcdev->dma_chans[0]) = DCSR_RUN;
-
-               if (buf->fmt->fourcc == V4L2_PIX_FMT_YUV422P) {
-                       DDADR(pcdev->dma_chans[1]) = buf->dmas[1].sg_dma;
-                       DCSR(pcdev->dma_chans[1]) = DCSR_RUN;
 
-                       DDADR(pcdev->dma_chans[2]) = buf->dmas[2].sg_dma;
-                       DCSR(pcdev->dma_chans[2]) = DCSR_RUN;
+               for (i = 0; i < pcdev->channels; i++) {
+                       DDADR(pcdev->dma_chans[i]) = buf->dmas[i].sg_dma;
+                       DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
+                       pcdev->sg_tail[i] = buf->dmas[i].sg_cpu + buf->dmas[i].sglen - 1;
                }
 
                pcdev->active = buf;
@@ -398,14 +396,9 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
        } else {
                struct pxa_cam_dma *buf_dma;
                struct pxa_cam_dma *act_dma;
-               int channels = 1;
                int nents;
-               int i;
-
-               if (buf->fmt->fourcc == V4L2_PIX_FMT_YUV422P)
-                       channels = 3;
 
-               for (i = 0; i < channels; i++) {
+               for (i = 0; i < pcdev->channels; i++) {
                        buf_dma = &buf->dmas[i];
                        act_dma = &active->dmas[i];
                        nents = buf_dma->sglen;
@@ -415,8 +408,8 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
 
                        /* Add the descriptors we just initialized to
                           the currently running chain */
-                       act_dma->sg_cpu[act_dma->sglen - 1].ddadr =
-                               buf_dma->sg_dma;
+                       pcdev->sg_tail[i]->ddadr = buf_dma->sg_dma;
+                       pcdev->sg_tail[i] = buf_dma->sg_cpu + buf_dma->sglen - 1;
 
                        /* Setup a dummy descriptor with the DMA engines current
                         * state
@@ -445,20 +438,6 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
 
                        DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
                }
-#ifdef DEBUG
-               if (CISR & (CISR_IFO_0 | CISR_IFO_1 | CISR_IFO_2)) {
-                       dev_warn(pcdev->dev, "FIFO overrun\n");
-                       for (i = 0; i < channels; i++)
-                               DDADR(pcdev->dma_chans[i]) =
-                                       pcdev->active->dmas[i].sg_dma;
-
-                       CICR0 &= ~CICR0_ENB;
-                       CIFR |= CIFR_RESET_F;
-                       for (i = 0; i < channels; i++)
-                               DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
-                       CICR0 |= CICR0_ENB;
-               }
-#endif
        }
 
        spin_unlock_irqrestore(&pcdev->lock, flags);
@@ -522,7 +501,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
 {
        struct pxa_buffer *buf;
        unsigned long flags;
-       unsigned int status;
+       u32 status, camera_status, overrun;
        struct videobuf_buffer *vb;
 
        spin_lock_irqsave(&pcdev->lock, flags);
@@ -546,6 +525,25 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
                goto out;
        }
 
+       camera_status = CISR;
+       overrun = CISR_IFO_0;
+       if (pcdev->channels == 3)
+               overrun |= CISR_IFO_1 | CISR_IFO_2;
+       if (camera_status & overrun) {
+               dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n", camera_status);
+               /* Stop the Capture Interface */
+               CICR0 &= ~CICR0_ENB;
+               /* Stop DMA */
+               DCSR(channel) = 0;
+               /* Reset the FIFOs */
+               CIFR |= CIFR_RESET_F;
+               /* Enable End-Of-Frame Interrupt */
+               CICR0 &= ~CICR0_EOFM;
+               /* Restart the Capture Interface */
+               CICR0 |= CICR0_ENB;
+               goto out;
+       }
+
        vb = &pcdev->active->vb;
        buf = container_of(vb, struct pxa_buffer, vb);
        WARN_ON(buf->inwork || list_empty(&vb->queue));
@@ -585,6 +583,19 @@ static struct videobuf_queue_ops pxa_videobuf_ops = {
        .buf_release    = pxa_videobuf_release,
 };
 
+static void pxa_camera_init_videobuf(struct videobuf_queue *q,
+                             struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct pxa_camera_dev *pcdev = ici->priv;
+
+       /* We must pass NULL as dev pointer, then all pci_* dma operations
+        * transform to normal dma_* ones. */
+       videobuf_queue_sg_init(q, &pxa_videobuf_ops, NULL, &pcdev->lock,
+                               V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+                               sizeof(struct pxa_buffer), icd);
+}
+
 static int mclk_get_divisor(struct pxa_camera_dev *pcdev)
 {
        unsigned int mclk_10khz = pcdev->platform_mclk_10khz;
@@ -670,7 +681,21 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
 
        dev_dbg(pcdev->dev, "Camera interrupt status 0x%x\n", status);
 
+       if (!status)
+               return IRQ_NONE;
+
        CISR = status;
+
+       if (status & CISR_EOF) {
+               int i;
+               for (i = 0; i < pcdev->channels; i++) {
+                       DDADR(pcdev->dma_chans[i]) =
+                               pcdev->active->dmas[i].sg_dma;
+                       DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
+               }
+               CICR0 |= CICR0_EOFM;
+       }
+
        return IRQ_HANDLED;
 }
 
@@ -785,6 +810,8 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
        if (!common_flags)
                return -EINVAL;
 
+       pcdev->channels = 1;
+
        /* Make choises, based on platform preferences */
        if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
            (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
@@ -855,6 +882,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 
        switch (pixfmt) {
        case V4L2_PIX_FMT_YUV422P:
+               pcdev->channels = 3;
                cicr1 |= CICR1_YCBCR_F;
        case V4L2_PIX_FMT_YUYV:
                cicr1 |= CICR1_COLOR_SP_VAL(2);
@@ -969,34 +997,23 @@ static int pxa_camera_querycap(struct soc_camera_host *ici,
        return 0;
 }
 
-static spinlock_t *pxa_camera_spinlock_alloc(struct soc_camera_file *icf)
-{
-       struct soc_camera_host *ici =
-               to_soc_camera_host(icf->icd->dev.parent);
-       struct pxa_camera_dev *pcdev = ici->priv;
-
-       return &pcdev->lock;
-}
-
 static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
        .owner          = THIS_MODULE,
        .add            = pxa_camera_add_device,
        .remove         = pxa_camera_remove_device,
        .set_fmt_cap    = pxa_camera_set_fmt_cap,
        .try_fmt_cap    = pxa_camera_try_fmt_cap,
+       .init_videobuf  = pxa_camera_init_videobuf,
        .reqbufs        = pxa_camera_reqbufs,
        .poll           = pxa_camera_poll,
        .querycap       = pxa_camera_querycap,
        .try_bus_param  = pxa_camera_try_bus_param,
        .set_bus_param  = pxa_camera_set_bus_param,
-       .spinlock_alloc = pxa_camera_spinlock_alloc,
 };
 
 /* Should be allocated dynamically too, but we have only one. */
 static struct soc_camera_host pxa_soc_camera_host = {
        .drv_name               = PXA_CAM_DRV_NAME,
-       .vbq_ops                = &pxa_videobuf_ops,
-       .msize                  = sizeof(struct pxa_buffer),
        .ops                    = &pxa_soc_camera_host_ops,
 };
 
@@ -1005,12 +1022,12 @@ static int pxa_camera_probe(struct platform_device *pdev)
        struct pxa_camera_dev *pcdev;
        struct resource *res;
        void __iomem *base;
-       unsigned int irq;
+       int irq;
        int err = 0;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
-       if (!res || !irq) {
+       if (!res || irq < 0) {
                err = -ENODEV;
                goto exit;
        }