const: constify remaining dev_pm_ops
[safe/jmp/linux-2.6] / drivers / media / video / pxa_camera.c
index cfa113c..51b683c 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/sched.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
                        CICR0_EOFM | CICR0_FOM)
 
 /*
- * YUV422P picture size should be a multiple of 16, so the heuristic aligns
- * height, width on 4 byte boundaries to reach the 16 multiple for the size.
- */
-#define YUV422P_X_Y_ALIGN 4
-#define YUV422P_SIZE_ALIGN YUV422P_X_Y_ALIGN * YUV422P_X_Y_ALIGN
-
-/*
  * Structures
  */
 enum pxa_camera_active_dma {
@@ -202,7 +196,7 @@ struct pxa_buffer {
 };
 
 struct pxa_camera_dev {
-       struct device           *dev;
+       struct soc_camera_host  soc_host;
        /* PXA27x is only supposed to handle one camera on its Quick Capture
         * interface. If anyone ever builds hardware to enable more than
         * one camera, they will have to modify this driver too */
@@ -232,6 +226,10 @@ struct pxa_camera_dev {
        u32                     save_cicr[5];
 };
 
+struct pxa_cam {
+       unsigned long flags;
+};
+
 static const char *pxa_cam_driver_description = "PXA_Camera";
 
 static unsigned int vid_limit = 16;    /* Video memory limit, in Mb */
@@ -244,9 +242,9 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
 {
        struct soc_camera_device *icd = vq->priv_data;
 
-       dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
+       dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size);
 
-       *size = roundup(icd->width * icd->height *
+       *size = roundup(icd->user_width * icd->user_height *
                        ((icd->current_fmt->depth + 7) >> 3), 8);
 
        if (0 == *count)
@@ -261,13 +259,12 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
 {
        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;
        struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
        int i;
 
        BUG_ON(in_interrupt());
 
-       dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                &buf->vb, buf->vb.baddr, buf->vb.bsize);
 
        /* This waits until this buffer is out of danger, i.e., until it is no
@@ -278,7 +275,8 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
 
        for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) {
                if (buf->dmas[i].sg_cpu)
-                       dma_free_coherent(pcdev->dev, buf->dmas[i].sg_size,
+                       dma_free_coherent(ici->v4l2_dev.dev,
+                                         buf->dmas[i].sg_size,
                                          buf->dmas[i].sg_cpu,
                                          buf->dmas[i].sg_dma);
                buf->dmas[i].sg_cpu = NULL;
@@ -333,19 +331,20 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
                                struct scatterlist **sg_first, int *sg_first_ofs)
 {
        struct pxa_cam_dma *pxa_dma = &buf->dmas[channel];
+       struct device *dev = pcdev->soc_host.v4l2_dev.dev;
        struct scatterlist *sg;
        int i, offset, sglen;
        int dma_len = 0, xfer_len = 0;
 
        if (pxa_dma->sg_cpu)
-               dma_free_coherent(pcdev->dev, pxa_dma->sg_size,
+               dma_free_coherent(dev, pxa_dma->sg_size,
                                  pxa_dma->sg_cpu, pxa_dma->sg_dma);
 
        sglen = calculate_dma_sglen(*sg_first, dma->sglen,
                                    *sg_first_ofs, size);
 
        pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc);
-       pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->dev, pxa_dma->sg_size,
+       pxa_dma->sg_cpu = dma_alloc_coherent(dev, pxa_dma->sg_size,
                                             &pxa_dma->sg_dma, GFP_KERNEL);
        if (!pxa_dma->sg_cpu)
                return -ENOMEM;
@@ -353,7 +352,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
        pxa_dma->sglen = sglen;
        offset = *sg_first_ofs;
 
-       dev_dbg(pcdev->dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n",
+       dev_dbg(dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n",
                *sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma);
 
 
@@ -376,7 +375,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
                pxa_dma->sg_cpu[i].ddadr =
                        pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc);
 
-               dev_vdbg(pcdev->dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n",
+               dev_vdbg(dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n",
                         pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc),
                         sg_dma_address(sg) + offset, xfer_len);
                offset = 0;
@@ -426,11 +425,12 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
        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;
+       struct device *dev = pcdev->soc_host.v4l2_dev.dev;
        struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
        int ret;
        int size_y, size_u = 0, size_v = 0;
 
-       dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        /* Added list head initialization on alloc */
@@ -449,12 +449,12 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
        buf->inwork = 1;
 
        if (buf->fmt    != icd->current_fmt ||
-           vb->width   != icd->width ||
-           vb->height  != icd->height ||
+           vb->width   != icd->user_width ||
+           vb->height  != icd->user_height ||
            vb->field   != field) {
                buf->fmt        = icd->current_fmt;
-               vb->width       = icd->width;
-               vb->height      = icd->height;
+               vb->width       = icd->user_width;
+               vb->height      = icd->user_height;
                vb->field       = field;
                vb->state       = VIDEOBUF_NEEDS_INIT;
        }
@@ -488,8 +488,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
                ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y,
                                           &sg, &next_ofs);
                if (ret) {
-                       dev_err(pcdev->dev,
-                               "DMA initialization for Y/RGB failed\n");
+                       dev_err(dev, "DMA initialization for Y/RGB failed\n");
                        goto fail;
                }
 
@@ -498,8 +497,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
                        ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1,
                                                   size_u, &sg, &next_ofs);
                if (ret) {
-                       dev_err(pcdev->dev,
-                               "DMA initialization for U failed\n");
+                       dev_err(dev, "DMA initialization for U failed\n");
                        goto fail_u;
                }
 
@@ -508,8 +506,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
                        ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2,
                                                   size_v, &sg, &next_ofs);
                if (ret) {
-                       dev_err(pcdev->dev,
-                               "DMA initialization for V failed\n");
+                       dev_err(dev, "DMA initialization for V failed\n");
                        goto fail_v;
                }
 
@@ -522,10 +519,10 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
        return 0;
 
 fail_v:
-       dma_free_coherent(pcdev->dev, buf->dmas[1].sg_size,
+       dma_free_coherent(dev, buf->dmas[1].sg_size,
                          buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma);
 fail_u:
-       dma_free_coherent(pcdev->dev, buf->dmas[0].sg_size,
+       dma_free_coherent(dev, buf->dmas[0].sg_size,
                          buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma);
 fail:
        free_buffer(vq, buf);
@@ -549,7 +546,8 @@ static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev)
        active = pcdev->active;
 
        for (i = 0; i < pcdev->channels; i++) {
-               dev_dbg(pcdev->dev, "%s (channel=%d) ddadr=%08x\n", __func__,
+               dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+                       "%s (channel=%d) ddadr=%08x\n", __func__,
                        i, active->dmas[i].sg_dma);
                DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma;
                DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
@@ -561,20 +559,12 @@ static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev)
        int i;
 
        for (i = 0; i < pcdev->channels; i++) {
-               dev_dbg(pcdev->dev, "%s (channel=%d)\n", __func__, i);
+               dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+                       "%s (channel=%d)\n", __func__, i);
                DCSR(pcdev->dma_chans[i]) = 0;
        }
 }
 
-static void pxa_dma_update_sg_tail(struct pxa_camera_dev *pcdev,
-                                  struct pxa_buffer *buf)
-{
-       int i;
-
-       for (i = 0; i < pcdev->channels; i++)
-               pcdev->sg_tail[i] = buf->dmas[i].sg_cpu + buf->dmas[i].sglen;
-}
-
 static void pxa_dma_add_tail_buf(struct pxa_camera_dev *pcdev,
                                 struct pxa_buffer *buf)
 {
@@ -585,12 +575,13 @@ static void pxa_dma_add_tail_buf(struct pxa_camera_dev *pcdev,
                buf_last_desc = buf->dmas[i].sg_cpu + buf->dmas[i].sglen;
                buf_last_desc->ddadr = DDADR_STOP;
 
-               if (!pcdev->sg_tail[i])
-                       continue;
-               pcdev->sg_tail[i]->ddadr = buf->dmas[i].sg_dma;
-       }
+               if (pcdev->sg_tail[i])
+                       /* Link the new buffer to the old tail */
+                       pcdev->sg_tail[i]->ddadr = buf->dmas[i].sg_dma;
 
-       pxa_dma_update_sg_tail(pcdev, buf);
+               /* Update the channel tail */
+               pcdev->sg_tail[i] = buf_last_desc;
+       }
 }
 
 /**
@@ -605,7 +596,7 @@ static void pxa_camera_start_capture(struct pxa_camera_dev *pcdev)
 {
        unsigned long cicr0, cifr;
 
-       dev_dbg(pcdev->dev, "%s\n", __func__);
+       dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__);
        /* Reset the FIFOs */
        cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
        __raw_writel(cifr, pcdev->base + CIFR);
@@ -625,9 +616,10 @@ static void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev)
        __raw_writel(cicr0, pcdev->base + CICR0);
 
        pcdev->active = NULL;
-       dev_dbg(pcdev->dev, "%s\n", __func__);
+       dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__);
 }
 
+/* Called under spinlock_irqsave(&pcdev->lock, ...) */
 static void pxa_videobuf_queue(struct videobuf_queue *vq,
                               struct videobuf_buffer *vb)
 {
@@ -635,12 +627,9 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
-       unsigned long flags;
-
-       dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d active=%p\n", __func__,
-               vb, vb->baddr, vb->bsize, pcdev->active);
 
-       spin_lock_irqsave(&pcdev->lock, flags);
+       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d active=%p\n",
+               __func__, vb, vb->baddr, vb->bsize, pcdev->active);
 
        list_add_tail(&vb->queue, &pcdev->capture);
 
@@ -649,8 +638,6 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
 
        if (!pcdev->active)
                pxa_camera_start_capture(pcdev);
-
-       spin_unlock_irqrestore(&pcdev->lock, flags);
 }
 
 static void pxa_videobuf_release(struct videobuf_queue *vq,
@@ -659,22 +646,23 @@ static void pxa_videobuf_release(struct videobuf_queue *vq,
        struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
 #ifdef DEBUG
        struct soc_camera_device *icd = vq->priv_data;
+       struct device *dev = icd->dev.parent;
 
-       dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        switch (vb->state) {
        case VIDEOBUF_ACTIVE:
-               dev_dbg(&icd->dev, "%s (active)\n", __func__);
+               dev_dbg(dev, "%s (active)\n", __func__);
                break;
        case VIDEOBUF_QUEUED:
-               dev_dbg(&icd->dev, "%s (queued)\n", __func__);
+               dev_dbg(dev, "%s (queued)\n", __func__);
                break;
        case VIDEOBUF_PREPARED:
-               dev_dbg(&icd->dev, "%s (prepared)\n", __func__);
+               dev_dbg(dev, "%s (prepared)\n", __func__);
                break;
        default:
-               dev_dbg(&icd->dev, "%s (unknown)\n", __func__);
+               dev_dbg(dev, "%s (unknown)\n", __func__);
                break;
        }
 #endif
@@ -694,7 +682,8 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
        do_gettimeofday(&vb->ts);
        vb->field_count++;
        wake_up(&vb->done);
-       dev_dbg(pcdev->dev, "%s dequeud buffer (vb=0x%p)\n", __func__, vb);
+       dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s dequeud buffer (vb=0x%p)\n",
+               __func__, vb);
 
        if (list_empty(&pcdev->capture)) {
                pxa_camera_stop_capture(pcdev);
@@ -730,7 +719,8 @@ static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev)
        for (i = 0; i < pcdev->channels; i++)
                if (DDADR(pcdev->dma_chans[i]) != DDADR_STOP)
                        is_dma_stopped = 0;
-       dev_dbg(pcdev->dev, "%s : top queued buffer=%p, dma_stopped=%d\n",
+       dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+               "%s : top queued buffer=%p, dma_stopped=%d\n",
                __func__, pcdev->active, is_dma_stopped);
        if (pcdev->active && is_dma_stopped)
                pxa_camera_start_capture(pcdev);
@@ -739,6 +729,7 @@ static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev)
 static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
                               enum pxa_camera_active_dma act_dma)
 {
+       struct device *dev = pcdev->soc_host.v4l2_dev.dev;
        struct pxa_buffer *buf;
        unsigned long flags;
        u32 status, camera_status, overrun;
@@ -755,13 +746,13 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
                overrun |= CISR_IFO_1 | CISR_IFO_2;
 
        if (status & DCSR_BUSERR) {
-               dev_err(pcdev->dev, "DMA Bus Error IRQ!\n");
+               dev_err(dev, "DMA Bus Error IRQ!\n");
                goto out;
        }
 
        if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) {
-               dev_err(pcdev->dev, "Unknown DMA IRQ source, "
-                       "status: 0x%08x\n", status);
+               dev_err(dev, "Unknown DMA IRQ source, status: 0x%08x\n",
+                       status);
                goto out;
        }
 
@@ -784,7 +775,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
        buf = container_of(vb, struct pxa_buffer, vb);
        WARN_ON(buf->inwork || list_empty(&vb->queue));
 
-       dev_dbg(pcdev->dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n",
+       dev_dbg(dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n",
                __func__, channel, status & DCSR_STARTINTR ? "SOF " : "",
                status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel));
 
@@ -795,7 +786,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
                 */
                if (camera_status & overrun &&
                    !list_is_last(pcdev->capture.next, &pcdev->capture)) {
-                       dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n",
+                       dev_dbg(dev, "FIFO overrun! CISR: %x\n",
                                camera_status);
                        pxa_camera_stop_capture(pcdev);
                        pxa_camera_start_capture(pcdev);
@@ -850,9 +841,11 @@ static void pxa_camera_init_videobuf(struct videobuf_queue *q,
                                sizeof(struct pxa_buffer), icd);
 }
 
-static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
+static u32 mclk_get_divisor(struct platform_device *pdev,
+                           struct pxa_camera_dev *pcdev)
 {
        unsigned long mclk = pcdev->mclk;
+       struct device *dev = &pdev->dev;
        u32 div;
        unsigned long lcdclk;
 
@@ -862,7 +855,7 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
        /* mclk <= ciclk / 4 (27.4.2) */
        if (mclk > lcdclk / 4) {
                mclk = lcdclk / 4;
-               dev_warn(pcdev->dev, "Limiting master clock to %lu\n", mclk);
+               dev_warn(dev, "Limiting master clock to %lu\n", mclk);
        }
 
        /* We verify mclk != 0, so if anyone breaks it, here comes their Oops */
@@ -872,8 +865,8 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
        if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
                pcdev->mclk = lcdclk / (2 * (div + 1));
 
-       dev_dbg(pcdev->dev, "LCD clock %luHz, target freq %luHz, "
-               "divisor %u\n", lcdclk, mclk, div);
+       dev_dbg(dev, "LCD clock %luHz, target freq %luHz, divisor %u\n",
+               lcdclk, mclk, div);
 
        return div;
 }
@@ -890,14 +883,15 @@ static void recalculate_fifo_timeout(struct pxa_camera_dev *pcdev,
 static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
 {
        struct pxacamera_platform_data *pdata = pcdev->pdata;
+       struct device *dev = pcdev->soc_host.v4l2_dev.dev;
        u32 cicr4 = 0;
 
-       dev_dbg(pcdev->dev, "Registered platform device at %p data %p\n",
+       dev_dbg(dev, "Registered platform device at %p data %p\n",
                pcdev, pdata);
 
        if (pdata && pdata->init) {
-               dev_dbg(pcdev->dev, "%s: Init gpios\n", __func__);
-               pdata->init(pcdev->dev);
+               dev_dbg(dev, "%s: Init gpios\n", __func__);
+               pdata->init(dev);
        }
 
        /* disable all interrupts */
@@ -939,7 +933,8 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
        struct videobuf_buffer *vb;
 
        status = __raw_readl(pcdev->base + CISR);
-       dev_dbg(pcdev->dev, "Camera interrupt status 0x%lx\n", status);
+       dev_dbg(pcdev->soc_host.v4l2_dev.dev,
+               "Camera interrupt status 0x%lx\n", status);
 
        if (!status)
                return IRQ_NONE;
@@ -971,24 +966,18 @@ static int pxa_camera_add_device(struct soc_camera_device *icd)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
-       int ret;
 
-       if (pcdev->icd) {
-               ret = -EBUSY;
-               goto ebusy;
-       }
-
-       dev_info(&icd->dev, "PXA Camera driver attached to camera %d\n",
-                icd->devnum);
+       if (pcdev->icd)
+               return -EBUSY;
 
        pxa_camera_activate(pcdev);
-       ret = icd->ops->init(icd);
 
-       if (!ret)
-               pcdev->icd = icd;
+       pcdev->icd = icd;
 
-ebusy:
-       return ret;
+       dev_info(icd->dev.parent, "PXA Camera driver attached to camera %d\n",
+                icd->devnum);
+
+       return 0;
 }
 
 /* Called with .video_lock held */
@@ -999,7 +988,7 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd)
 
        BUG_ON(icd != pcdev->icd);
 
-       dev_info(&icd->dev, "PXA Camera driver detached from camera %d\n",
+       dev_info(icd->dev.parent, "PXA Camera driver detached from camera %d\n",
                 icd->devnum);
 
        /* disable capture, disable interrupts */
@@ -1010,8 +999,6 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd)
        DCSR(pcdev->dma_chans[1]) = 0;
        DCSR(pcdev->dma_chans[2]) = 0;
 
-       icd->ops->release(icd);
-
        pxa_camera_deactivate(pcdev);
 
        pcdev->icd = NULL;
@@ -1059,57 +1046,17 @@ static int test_platform_param(struct pxa_camera_dev *pcdev,
        return 0;
 }
 
-static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+static void pxa_camera_setup_cicr(struct soc_camera_device *icd,
+                                 unsigned long flags, __u32 pixfmt)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
-       unsigned long dw, bpp, bus_flags, camera_flags, common_flags;
+       unsigned long dw, bpp;
        u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0;
-       int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
-
-       if (ret < 0)
-               return ret;
-
-       camera_flags = icd->ops->query_bus_param(icd);
-
-       common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
-       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)) {
-               if (pcdev->platform_flags & PXA_CAMERA_HSP)
-                       common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
-               else
-                       common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
-       }
-
-       if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
-           (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
-               if (pcdev->platform_flags & PXA_CAMERA_VSP)
-                       common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
-               else
-                       common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
-       }
-
-       if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
-           (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
-               if (pcdev->platform_flags & PXA_CAMERA_PCP)
-                       common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
-               else
-                       common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
-       }
-
-       ret = icd->ops->set_bus_param(icd, common_flags);
-       if (ret < 0)
-               return ret;
 
        /* Datawidth is now guaranteed to be equal to one of the three values.
         * We fix bit-per-pixel equal to data-width... */
-       switch (common_flags & SOCAM_DATAWIDTH_MASK) {
+       switch (flags & SOCAM_DATAWIDTH_MASK) {
        case SOCAM_DATAWIDTH_10:
                dw = 4;
                bpp = 0x40;
@@ -1130,18 +1077,18 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
                cicr4 |= CICR4_PCLK_EN;
        if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
                cicr4 |= CICR4_MCLK_EN;
-       if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
+       if (flags & SOCAM_PCLK_SAMPLE_FALLING)
                cicr4 |= CICR4_PCP;
-       if (common_flags & SOCAM_HSYNC_ACTIVE_LOW)
+       if (flags & SOCAM_HSYNC_ACTIVE_LOW)
                cicr4 |= CICR4_HSP;
-       if (common_flags & SOCAM_VSYNC_ACTIVE_LOW)
+       if (flags & SOCAM_VSYNC_ACTIVE_LOW)
                cicr4 |= CICR4_VSP;
 
        cicr0 = __raw_readl(pcdev->base + CICR0);
        if (cicr0 & CICR0_ENB)
                __raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0);
 
-       cicr1 = CICR1_PPL_VAL(icd->width - 1) | bpp | dw;
+       cicr1 = CICR1_PPL_VAL(icd->user_width - 1) | bpp | dw;
 
        switch (pixfmt) {
        case V4L2_PIX_FMT_YUV422P:
@@ -1170,7 +1117,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
        }
 
        cicr2 = 0;
-       cicr3 = CICR3_LPF_VAL(icd->height - 1) |
+       cicr3 = CICR3_LPF_VAL(icd->user_height - 1) |
                CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top));
        cicr4 |= pcdev->mclk_divisor;
 
@@ -1184,6 +1131,59 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
                CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP));
        cicr0 |= CICR0_DMAEN | CICR0_IRQ_MASK;
        __raw_writel(cicr0, pcdev->base + CICR0);
+}
+
+static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct pxa_camera_dev *pcdev = ici->priv;
+       unsigned long bus_flags, camera_flags, common_flags;
+       int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
+       struct pxa_cam *cam = icd->host_priv;
+
+       if (ret < 0)
+               return ret;
+
+       camera_flags = icd->ops->query_bus_param(icd);
+
+       common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
+       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)) {
+               if (pcdev->platform_flags & PXA_CAMERA_HSP)
+                       common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
+               else
+                       common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
+       }
+
+       if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
+           (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
+               if (pcdev->platform_flags & PXA_CAMERA_VSP)
+                       common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
+               else
+                       common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
+       }
+
+       if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
+           (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
+               if (pcdev->platform_flags & PXA_CAMERA_PCP)
+                       common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
+               else
+                       common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
+       }
+
+       cam->flags = common_flags;
+
+       ret = icd->ops->set_bus_param(icd, common_flags);
+       if (ret < 0)
+               return ret;
+
+       pxa_camera_setup_cicr(icd, common_flags, pixfmt);
 
        return 0;
 }
@@ -1247,8 +1247,9 @@ static int required_buswidth(const struct soc_camera_data_format *fmt)
 static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
                                  struct soc_camera_format_xlate *xlate)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->dev.parent;
        int formats = 0, buswidth, ret;
+       struct pxa_cam *cam;
 
        buswidth = required_buswidth(icd->formats + idx);
 
@@ -1259,6 +1260,16 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
        if (ret < 0)
                return 0;
 
+       if (!icd->host_priv) {
+               cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+               if (!cam)
+                       return -ENOMEM;
+
+               icd->host_priv = cam;
+       } else {
+               cam = icd->host_priv;
+       }
+
        switch (icd->formats[idx].fourcc) {
        case V4L2_PIX_FMT_UYVY:
                formats++;
@@ -1267,7 +1278,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = buswidth;
                        xlate++;
-                       dev_dbg(&ici->dev, "Providing format %s using %s\n",
+                       dev_dbg(dev, "Providing format %s using %s\n",
                                pxa_camera_formats[0].name,
                                icd->formats[idx].name);
                }
@@ -1282,7 +1293,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = buswidth;
                        xlate++;
-                       dev_dbg(&ici->dev, "Providing format %s packed\n",
+                       dev_dbg(dev, "Providing format %s packed\n",
                                icd->formats[idx].name);
                }
                break;
@@ -1294,7 +1305,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = icd->formats[idx].depth;
                        xlate++;
-                       dev_dbg(&ici->dev,
+                       dev_dbg(dev,
                                "Providing format %s in pass-through mode\n",
                                icd->formats[idx].name);
                }
@@ -1303,31 +1314,80 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
        return formats;
 }
 
+static void pxa_camera_put_formats(struct soc_camera_device *icd)
+{
+       kfree(icd->host_priv);
+       icd->host_priv = NULL;
+}
+
+static int pxa_camera_check_frame(struct v4l2_pix_format *pix)
+{
+       /* limit to pxa hardware capabilities */
+       return pix->height < 32 || pix->height > 2048 || pix->width < 48 ||
+               pix->width > 2048 || (pix->width & 0x01);
+}
+
 static int pxa_camera_set_crop(struct soc_camera_device *icd,
-                              struct v4l2_rect *rect)
+                              struct v4l2_crop *a)
 {
+       struct v4l2_rect *rect = &a->c;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
+       struct device *dev = icd->dev.parent;
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        struct soc_camera_sense sense = {
                .master_clock = pcdev->mclk,
                .pixel_clock_max = pcdev->ciclk / 4,
        };
+       struct v4l2_format f;
+       struct v4l2_pix_format *pix = &f.fmt.pix, pix_tmp;
+       struct pxa_cam *cam = icd->host_priv;
        int ret;
 
        /* If PCLK is used to latch data from the sensor, check sense */
        if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
                icd->sense = &sense;
 
-       ret = icd->ops->set_crop(icd, rect);
+       ret = v4l2_subdev_call(sd, video, s_crop, a);
 
        icd->sense = NULL;
 
        if (ret < 0) {
-               dev_warn(&ici->dev, "Failed to crop to %ux%u@%u:%u\n",
+               dev_warn(dev, "Failed to crop to %ux%u@%u:%u\n",
                         rect->width, rect->height, rect->left, rect->top);
-       } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
+               return ret;
+       }
+
+       f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       ret = v4l2_subdev_call(sd, video, g_fmt, &f);
+       if (ret < 0)
+               return ret;
+
+       pix_tmp = *pix;
+       if (pxa_camera_check_frame(pix)) {
+               /*
+                * Camera cropping produced a frame beyond our capabilities.
+                * FIXME: just extract a subframe, that we can process.
+                */
+               v4l_bound_align_image(&pix->width, 48, 2048, 1,
+                       &pix->height, 32, 2048, 0,
+                       icd->current_fmt->fourcc == V4L2_PIX_FMT_YUV422P ?
+                               4 : 0);
+               ret = v4l2_subdev_call(sd, video, s_fmt, &f);
+               if (ret < 0)
+                       return ret;
+
+               if (pxa_camera_check_frame(pix)) {
+                       dev_warn(icd->dev.parent,
+                                "Inconsistent state. Use S_FMT to repair\n");
+                       return -EINVAL;
+               }
+       }
+
+       if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
                if (sense.pixel_clock > sense.pixel_clock_max) {
-                       dev_err(&ici->dev,
+                       dev_err(dev,
                                "pixel clock %lu set by the camera too high!",
                                sense.pixel_clock);
                        return -EIO;
@@ -1335,6 +1395,11 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
                recalculate_fifo_timeout(pcdev, sense.pixel_clock);
        }
 
+       icd->user_width = pix->width;
+       icd->user_height = pix->height;
+
+       pxa_camera_setup_cicr(icd, cam->flags, icd->current_fmt->fourcc);
+
        return ret;
 }
 
@@ -1343,6 +1408,8 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
+       struct device *dev = icd->dev.parent;
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        const struct soc_camera_data_format *cam_fmt = NULL;
        const struct soc_camera_format_xlate *xlate = NULL;
        struct soc_camera_sense sense = {
@@ -1355,7 +1422,7 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat);
+               dev_warn(dev, "Format %x not found\n", pix->pixelformat);
                return -EINVAL;
        }
 
@@ -1366,16 +1433,23 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
                icd->sense = &sense;
 
        cam_f.fmt.pix.pixelformat = cam_fmt->fourcc;
-       ret = icd->ops->set_fmt(icd, &cam_f);
+       ret = v4l2_subdev_call(sd, video, s_fmt, &cam_f);
+       cam_f.fmt.pix.pixelformat = pix->pixelformat;
+       *pix = cam_f.fmt.pix;
 
        icd->sense = NULL;
 
        if (ret < 0) {
-               dev_warn(&ici->dev, "Failed to configure for format %x\n",
+               dev_warn(dev, "Failed to configure for format %x\n",
                         pix->pixelformat);
+       } else if (pxa_camera_check_frame(pix)) {
+               dev_warn(dev,
+                        "Camera driver produced an unsupported frame %dx%d\n",
+                        pix->width, pix->height);
+               ret = -EINVAL;
        } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
                if (sense.pixel_clock > sense.pixel_clock_max) {
-                       dev_err(&ici->dev,
+                       dev_err(dev,
                                "pixel clock %lu set by the camera too high!",
                                sense.pixel_clock);
                        return -EIO;
@@ -1395,6 +1469,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
                              struct v4l2_format *f)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        const struct soc_camera_format_xlate *xlate;
        struct v4l2_pix_format *pix = &f->fmt.pix;
        __u32 pixfmt = pix->pixelformat;
@@ -1403,32 +1478,19 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               dev_warn(ici->v4l2_dev.dev, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
-       /* limit to pxa hardware capabilities */
-       if (pix->height < 32)
-               pix->height = 32;
-       if (pix->height > 2048)
-               pix->height = 2048;
-       if (pix->width < 48)
-               pix->width = 48;
-       if (pix->width > 2048)
-               pix->width = 2048;
-       pix->width &= ~0x01;
-
        /*
-        * YUV422P planar format requires images size to be a 16 bytes
-        * multiple. If not, zeros will be inserted between Y and U planes, and
-        * U and V planes, and YUV422P standard would be violated.
+        * Limit to pxa hardware capabilities.  YUV422P planar format requires
+        * images size to be a multiple of 16 bytes.  If not, zeros will be
+        * inserted between Y and U planes, and U and V planes, which violates
+        * the YUV422P standard.
         */
-       if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUV422P) {
-               if (!IS_ALIGNED(pix->width * pix->height, YUV422P_SIZE_ALIGN))
-                       pix->height = ALIGN(pix->height, YUV422P_X_Y_ALIGN);
-               if (!IS_ALIGNED(pix->width * pix->height, YUV422P_SIZE_ALIGN))
-                       pix->width = ALIGN(pix->width, YUV422P_X_Y_ALIGN);
-       }
+       v4l_bound_align_image(&pix->width, 48, 2048, 1,
+                             &pix->height, 32, 2048, 0,
+                             pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0);
 
        pix->bytesperline = pix->width *
                DIV_ROUND_UP(xlate->host_fmt->depth, 8);
@@ -1437,15 +1499,15 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
        /* camera has to see its format, but the user the original one */
        pix->pixelformat = xlate->cam_fmt->fourcc;
        /* limit to sensor capabilities */
-       ret = icd->ops->try_fmt(icd, f);
-       pix->pixelformat = xlate->host_fmt->fourcc;
+       ret = v4l2_subdev_call(sd, video, try_fmt, f);
+       pix->pixelformat = pixfmt;
 
        field = pix->field;
 
        if (field == V4L2_FIELD_ANY) {
                pix->field = V4L2_FIELD_NONE;
        } else if (field != V4L2_FIELD_NONE) {
-               dev_err(&icd->dev, "Field type %d unsupported.\n", field);
+               dev_err(icd->dev.parent, "Field type %d unsupported.\n", field);
                return -EINVAL;
        }
 
@@ -1551,6 +1613,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
        .resume         = pxa_camera_resume,
        .set_crop       = pxa_camera_set_crop,
        .get_formats    = pxa_camera_get_formats,
+       .put_formats    = pxa_camera_put_formats,
        .set_fmt        = pxa_camera_set_fmt,
        .try_fmt        = pxa_camera_try_fmt,
        .init_videobuf  = pxa_camera_init_videobuf,
@@ -1560,13 +1623,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
        .set_bus_param  = pxa_camera_set_bus_param,
 };
 
-/* 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,
-       .ops                    = &pxa_soc_camera_host_ops,
-};
-
-static int pxa_camera_probe(struct platform_device *pdev)
+static int __devinit pxa_camera_probe(struct platform_device *pdev)
 {
        struct pxa_camera_dev *pcdev;
        struct resource *res;
@@ -1594,7 +1651,6 @@ static int pxa_camera_probe(struct platform_device *pdev)
                goto exit_kfree;
        }
 
-       dev_set_drvdata(&pdev->dev, pcdev);
        pcdev->res = res;
 
        pcdev->pdata = pdev->dev.platform_data;
@@ -1615,8 +1671,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
                pcdev->mclk = 20000000;
        }
 
-       pcdev->dev = &pdev->dev;
-       pcdev->mclk_divisor = mclk_get_divisor(pcdev);
+       pcdev->mclk_divisor = mclk_get_divisor(pdev, pcdev);
 
        INIT_LIST_HEAD(&pcdev->capture);
        spin_lock_init(&pcdev->lock);
@@ -1624,13 +1679,13 @@ static int pxa_camera_probe(struct platform_device *pdev)
        /*
         * Request the regions.
         */
-       if (!request_mem_region(res->start, res->end - res->start + 1,
+       if (!request_mem_region(res->start, resource_size(res),
                                PXA_CAM_DRV_NAME)) {
                err = -EBUSY;
                goto exit_clk;
        }
 
-       base = ioremap(res->start, res->end - res->start + 1);
+       base = ioremap(res->start, resource_size(res));
        if (!base) {
                err = -ENOMEM;
                goto exit_release;
@@ -1642,29 +1697,29 @@ static int pxa_camera_probe(struct platform_device *pdev)
        err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
                              pxa_camera_dma_irq_y, pcdev);
        if (err < 0) {
-               dev_err(pcdev->dev, "Can't request DMA for Y\n");
+               dev_err(&pdev->dev, "Can't request DMA for Y\n");
                goto exit_iounmap;
        }
        pcdev->dma_chans[0] = err;
-       dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]);
+       dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]);
 
        err = pxa_request_dma("CI_U", DMA_PRIO_HIGH,
                              pxa_camera_dma_irq_u, pcdev);
        if (err < 0) {
-               dev_err(pcdev->dev, "Can't request DMA for U\n");
+               dev_err(&pdev->dev, "Can't request DMA for U\n");
                goto exit_free_dma_y;
        }
        pcdev->dma_chans[1] = err;
-       dev_dbg(pcdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]);
+       dev_dbg(&pdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]);
 
        err = pxa_request_dma("CI_V", DMA_PRIO_HIGH,
                              pxa_camera_dma_irq_v, pcdev);
        if (err < 0) {
-               dev_err(pcdev->dev, "Can't request DMA for V\n");
+               dev_err(&pdev->dev, "Can't request DMA for V\n");
                goto exit_free_dma_u;
        }
        pcdev->dma_chans[2] = err;
-       dev_dbg(pcdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]);
+       dev_dbg(&pdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]);
 
        DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD;
        DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD;
@@ -1674,14 +1729,17 @@ static int pxa_camera_probe(struct platform_device *pdev)
        err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME,
                          pcdev);
        if (err) {
-               dev_err(pcdev->dev, "Camera interrupt register failed \n");
+               dev_err(&pdev->dev, "Camera interrupt register failed \n");
                goto exit_free_dma;
        }
 
-       pxa_soc_camera_host.priv        = pcdev;
-       pxa_soc_camera_host.dev.parent  = &pdev->dev;
-       pxa_soc_camera_host.nr          = pdev->id;
-       err = soc_camera_host_register(&pxa_soc_camera_host);
+       pcdev->soc_host.drv_name        = PXA_CAM_DRV_NAME;
+       pcdev->soc_host.ops             = &pxa_soc_camera_host_ops;
+       pcdev->soc_host.priv            = pcdev;
+       pcdev->soc_host.v4l2_dev.dev    = &pdev->dev;
+       pcdev->soc_host.nr              = pdev->id;
+
+       err = soc_camera_host_register(&pcdev->soc_host);
        if (err)
                goto exit_free_irq;
 
@@ -1698,7 +1756,7 @@ exit_free_dma_y:
 exit_iounmap:
        iounmap(base);
 exit_release:
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 exit_clk:
        clk_put(pcdev->clk);
 exit_kfree:
@@ -1709,7 +1767,9 @@ exit:
 
 static int __devexit pxa_camera_remove(struct platform_device *pdev)
 {
-       struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev);
+       struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+       struct pxa_camera_dev *pcdev = container_of(soc_host,
+                                       struct pxa_camera_dev, soc_host);
        struct resource *res;
 
        clk_put(pcdev->clk);
@@ -1719,12 +1779,12 @@ static int __devexit pxa_camera_remove(struct platform_device *pdev)
        pxa_free_dma(pcdev->dma_chans[2]);
        free_irq(pcdev->irq, pcdev);
 
-       soc_camera_host_unregister(&pxa_soc_camera_host);
+       soc_camera_host_unregister(soc_host);
 
        iounmap(pcdev->base);
 
        res = pcdev->res;
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 
        kfree(pcdev);
 
@@ -1738,11 +1798,11 @@ static struct platform_driver pxa_camera_driver = {
                .name   = PXA_CAM_DRV_NAME,
        },
        .probe          = pxa_camera_probe,
-       .remove         = __exit_p(pxa_camera_remove),
+       .remove         = __devexit_p(pxa_camera_remove),
 };
 
 
-static int __devinit pxa_camera_init(void)
+static int __init pxa_camera_init(void)
 {
        return platform_driver_register(&pxa_camera_driver);
 }
@@ -1758,3 +1818,4 @@ module_exit(pxa_camera_exit);
 MODULE_DESCRIPTION("PXA27x SoC Camera Host driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" PXA_CAM_DRV_NAME);