Merge tag 'v3.8-rc1' into staging/for_v3.9
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / media / platform / soc_camera / mx2_camera.c
index 3c5ba63cd3112ae97d409749907727a25e1144b4..28d5c84eef82a8c21ab34175ea83ed61bf975066 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/videodev2.h>
 
 #include <linux/platform_data/camera-mx2.h>
-#include <mach/hardware.h>
 
 #include <asm/dma.h>
 
 
 #define CSICR1                 0x00
 #define CSICR2                 0x04
-#define CSISR                  (cpu_is_mx27() ? 0x08 : 0x18)
+#define CSISR_IMX25            0x18
+#define CSISR_IMX27            0x08
 #define CSISTATFIFO            0x0c
 #define CSIRFIFO               0x10
 #define CSIRXCNT               0x14
-#define CSICR3                 (cpu_is_mx27() ? 0x1C : 0x08)
+#define CSICR3_IMX25           0x08
+#define CSICR3_IMX27           0x1c
 #define CSIDMASA_STATFIFO      0x20
 #define CSIDMATA_STATFIFO      0x24
 #define CSIDMASA_FB1           0x28
@@ -268,11 +269,17 @@ struct mx2_buffer {
        struct mx2_buf_internal         internal;
 };
 
+enum mx2_camera_type {
+       IMX25_CAMERA,
+       IMX27_CAMERA,
+};
+
 struct mx2_camera_dev {
        struct device           *dev;
        struct soc_camera_host  soc_host;
        struct soc_camera_device *icd;
-       struct clk              *clk_csi, *clk_emma_ahb, *clk_emma_ipg;
+       struct clk              *clk_emma_ahb, *clk_emma_ipg;
+       struct clk              *clk_csi_ahb, *clk_csi_per;
 
        void __iomem            *base_csi, *base_emma;
 
@@ -291,6 +298,9 @@ struct mx2_camera_dev {
        struct mx2_buffer       *fb2_active;
 
        u32                     csicr1;
+       u32                     reg_csisr;
+       u32                     reg_csicr3;
+       enum mx2_camera_type    devtype;
 
        struct mx2_buf_internal buf_discard[2];
        void                    *discard_buffer;
@@ -303,6 +313,29 @@ struct mx2_camera_dev {
        struct vb2_alloc_ctx    *alloc_ctx;
 };
 
+static struct platform_device_id mx2_camera_devtype[] = {
+       {
+               .name = "imx25-camera",
+               .driver_data = IMX25_CAMERA,
+       }, {
+               .name = "imx27-camera",
+               .driver_data = IMX27_CAMERA,
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(platform, mx2_camera_devtype);
+
+static inline int is_imx25_camera(struct mx2_camera_dev *pcdev)
+{
+       return pcdev->devtype == IMX25_CAMERA;
+}
+
+static inline int is_imx27_camera(struct mx2_camera_dev *pcdev)
+{
+       return pcdev->devtype == IMX27_CAMERA;
+}
+
 static struct mx2_buffer *mx2_ibuf_to_buf(struct mx2_buf_internal *int_buf)
 {
        return container_of(int_buf, struct mx2_buffer, internal);
@@ -432,11 +465,12 @@ static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev)
 {
        unsigned long flags;
 
-       clk_disable_unprepare(pcdev->clk_csi);
+       clk_disable_unprepare(pcdev->clk_csi_ahb);
+       clk_disable_unprepare(pcdev->clk_csi_per);
        writel(0, pcdev->base_csi + CSICR1);
-       if (cpu_is_mx27()) {
+       if (is_imx27_camera(pcdev)) {
                writel(0, pcdev->base_emma + PRP_CNTL);
-       } else if (cpu_is_mx25()) {
+       } else if (is_imx25_camera(pcdev)) {
                spin_lock_irqsave(&pcdev->lock, flags);
                pcdev->fb1_active = NULL;
                pcdev->fb2_active = NULL;
@@ -460,13 +494,17 @@ static int mx2_camera_add_device(struct soc_camera_device *icd)
        if (pcdev->icd)
                return -EBUSY;
 
-       ret = clk_prepare_enable(pcdev->clk_csi);
+       ret = clk_prepare_enable(pcdev->clk_csi_ahb);
        if (ret < 0)
                return ret;
 
+       ret = clk_prepare_enable(pcdev->clk_csi_per);
+       if (ret < 0)
+               goto exit_csi_ahb;
+
        csicr1 = CSICR1_MCLKEN;
 
-       if (cpu_is_mx27())
+       if (is_imx27_camera(pcdev))
                csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC |
                        CSICR1_RXFF_LEVEL(0);
 
@@ -480,6 +518,11 @@ static int mx2_camera_add_device(struct soc_camera_device *icd)
                 icd->devnum);
 
        return 0;
+
+exit_csi_ahb:
+       clk_disable_unprepare(pcdev->clk_csi_ahb);
+
+       return ret;
 }
 
 static void mx2_camera_remove_device(struct soc_camera_device *icd)
@@ -542,7 +585,7 @@ out:
 static irqreturn_t mx25_camera_irq(int irq_csi, void *data)
 {
        struct mx2_camera_dev *pcdev = data;
-       u32 status = readl(pcdev->base_csi + CSISR);
+       u32 status = readl(pcdev->base_csi + pcdev->reg_csisr);
 
        if (status & CSISR_DMA_TSF_FB1_INT)
                mx25_camera_frame_done(pcdev, 1, MX2_STATE_DONE);
@@ -551,7 +594,7 @@ static irqreturn_t mx25_camera_irq(int irq_csi, void *data)
 
        /* FIXME: handle CSISR_RFF_OR_INT */
 
-       writel(status, pcdev->base_csi + CSISR);
+       writel(status, pcdev->base_csi + pcdev->reg_csisr);
 
        return IRQ_HANDLED;
 }
@@ -636,7 +679,7 @@ static void mx2_videobuf_queue(struct vb2_buffer *vb)
        buf->state = MX2_STATE_QUEUED;
        list_add_tail(&buf->internal.queue, &pcdev->capture);
 
-       if (cpu_is_mx25()) {
+       if (is_imx25_camera(pcdev)) {
                u32 csicr3, dma_inten = 0;
 
                if (pcdev->fb1_active == NULL) {
@@ -655,20 +698,20 @@ static void mx2_videobuf_queue(struct vb2_buffer *vb)
                        list_del(&buf->internal.queue);
                        buf->state = MX2_STATE_ACTIVE;
 
-                       csicr3 = readl(pcdev->base_csi + CSICR3);
+                       csicr3 = readl(pcdev->base_csi + pcdev->reg_csicr3);
 
                        /* Reflash DMA */
                        writel(csicr3 | CSICR3_DMA_REFLASH_RFF,
-                                       pcdev->base_csi + CSICR3);
+                                       pcdev->base_csi + pcdev->reg_csicr3);
 
                        /* clear & enable interrupts */
-                       writel(dma_inten, pcdev->base_csi + CSISR);
+                       writel(dma_inten, pcdev->base_csi + pcdev->reg_csisr);
                        pcdev->csicr1 |= dma_inten;
                        writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
 
                        /* enable DMA */
                        csicr3 |= CSICR3_DMA_REQ_EN_RFF | CSICR3_RXFF_LEVEL(1);
-                       writel(csicr3, pcdev->base_csi + CSICR3);
+                       writel(csicr3, pcdev->base_csi + pcdev->reg_csicr3);
                }
        }
 
@@ -712,7 +755,7 @@ static void mx2_videobuf_release(struct vb2_buffer *vb)
         */
 
        spin_lock_irqsave(&pcdev->lock, flags);
-       if (cpu_is_mx25() && buf->state == MX2_STATE_ACTIVE) {
+       if (is_imx25_camera(pcdev) && buf->state == MX2_STATE_ACTIVE) {
                if (pcdev->fb1_active == buf) {
                        pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN;
                        writel(0, pcdev->base_csi + CSIDMASA_FB1);
@@ -835,7 +878,7 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count)
        unsigned long phys;
        int bytesperline;
 
-       if (cpu_is_mx27()) {
+       if (is_imx27_camera(pcdev)) {
                unsigned long flags;
                if (count < 2)
                        return -EINVAL;
@@ -934,7 +977,7 @@ static int mx2_stop_streaming(struct vb2_queue *q)
        void *b;
        u32 cntl;
 
-       if (cpu_is_mx27()) {
+       if (is_imx27_camera(pcdev)) {
                spin_lock_irqsave(&pcdev->lock, flags);
 
                cntl = readl(pcdev->base_emma + PRP_CNTL);
@@ -1086,11 +1129,11 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
        if (bytesperline < 0)
                return bytesperline;
 
-       if (cpu_is_mx27()) {
+       if (is_imx27_camera(pcdev)) {
                ret = mx27_camera_emma_prp_reset(pcdev);
                if (ret)
                        return ret;
-       } else if (cpu_is_mx25()) {
+       } else if (is_imx25_camera(pcdev)) {
                writel((bytesperline * icd->user_height) >> 2,
                                pcdev->base_csi + CSIRXCNT);
                writel((bytesperline << 16) | icd->user_height,
@@ -1395,7 +1438,7 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
        }
 
        /* limit to MX25 hardware capabilities */
-       if (cpu_is_mx25()) {
+       if (is_imx25_camera(pcdev)) {
                if (xlate->host_fmt->bits_per_sample <= 8)
                        width_limit = 0xffff * 4;
                else
@@ -1735,10 +1778,31 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
                goto exit;
        }
 
-       pcdev->clk_csi = devm_clk_get(&pdev->dev, "ahb");
-       if (IS_ERR(pcdev->clk_csi)) {
-               dev_err(&pdev->dev, "Could not get csi clock\n");
-               err = PTR_ERR(pcdev->clk_csi);
+       pcdev->devtype = pdev->id_entry->driver_data;
+       switch (pcdev->devtype) {
+       case IMX25_CAMERA:
+               pcdev->reg_csisr = CSISR_IMX25;
+               pcdev->reg_csicr3 = CSICR3_IMX25;
+               break;
+       case IMX27_CAMERA:
+               pcdev->reg_csisr = CSISR_IMX27;
+               pcdev->reg_csicr3 = CSICR3_IMX27;
+               break;
+       default:
+               break;
+       }
+
+       pcdev->clk_csi_ahb = devm_clk_get(&pdev->dev, "ahb");
+       if (IS_ERR(pcdev->clk_csi_ahb)) {
+               dev_err(&pdev->dev, "Could not get csi ahb clock\n");
+               err = PTR_ERR(pcdev->clk_csi_ahb);
+               goto exit;
+       }
+
+       pcdev->clk_csi_per = devm_clk_get(&pdev->dev, "per");
+       if (IS_ERR(pcdev->clk_csi_per)) {
+               dev_err(&pdev->dev, "Could not get csi per clock\n");
+               err = PTR_ERR(pcdev->clk_csi_per);
                goto exit;
        }
 
@@ -1748,12 +1812,13 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
 
                pcdev->platform_flags = pcdev->pdata->flags;
 
-               rate = clk_round_rate(pcdev->clk_csi, pcdev->pdata->clk * 2);
+               rate = clk_round_rate(pcdev->clk_csi_per,
+                                               pcdev->pdata->clk * 2);
                if (rate <= 0) {
                        err = -ENODEV;
                        goto exit;
                }
-               err = clk_set_rate(pcdev->clk_csi, rate);
+               err = clk_set_rate(pcdev->clk_csi_per, rate);
                if (err < 0)
                        goto exit;
        }
@@ -1772,7 +1837,7 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
        pcdev->dev = &pdev->dev;
        platform_set_drvdata(pdev, pcdev);
 
-       if (cpu_is_mx25()) {
+       if (is_imx25_camera(pcdev)) {
                err = devm_request_irq(&pdev->dev, irq_csi, mx25_camera_irq, 0,
                                       MX2_CAM_DRV_NAME, pcdev);
                if (err) {
@@ -1781,7 +1846,7 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
                }
        }
 
-       if (cpu_is_mx27()) {
+       if (is_imx27_camera(pcdev)) {
                err = mx27_camera_emma_init(pdev);
                if (err)
                        goto exit;
@@ -1798,7 +1863,7 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
        pcdev->soc_host.priv            = pcdev;
        pcdev->soc_host.v4l2_dev.dev    = &pdev->dev;
        pcdev->soc_host.nr              = pdev->id;
-       if (cpu_is_mx25())
+       if (is_imx25_camera(pcdev))
                pcdev->soc_host.capabilities = SOCAM_HOST_CAP_STRIDE;
 
        pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
@@ -1811,14 +1876,14 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
                goto exit_free_emma;
 
        dev_info(&pdev->dev, "MX2 Camera (CSI) driver probed, clock frequency: %ld\n",
-                       clk_get_rate(pcdev->clk_csi));
+                       clk_get_rate(pcdev->clk_csi_per));
 
        return 0;
 
 exit_free_emma:
        vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
 eallocctx:
-       if (cpu_is_mx27()) {
+       if (is_imx27_camera(pcdev)) {
                clk_disable_unprepare(pcdev->clk_emma_ipg);
                clk_disable_unprepare(pcdev->clk_emma_ahb);
        }
@@ -1836,7 +1901,7 @@ static int __devexit mx2_camera_remove(struct platform_device *pdev)
 
        vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
 
-       if (cpu_is_mx27()) {
+       if (is_imx27_camera(pcdev)) {
                clk_disable_unprepare(pcdev->clk_emma_ipg);
                clk_disable_unprepare(pcdev->clk_emma_ahb);
        }
@@ -1850,6 +1915,7 @@ static struct platform_driver mx2_camera_driver = {
        .driver         = {
                .name   = MX2_CAM_DRV_NAME,
        },
+       .id_table       = mx2_camera_devtype,
        .remove         = __devexit_p(mx2_camera_remove),
 };