From: Libin Yang <lby...@marvell.com>

This patch adds the support of Soc Camera on marvell-ccic mmp-driver.
The Soc Camera mode does not compatible with current mode.
Only one mode can be used at one time.

To enable Soc Camera on mmp:
In Device Drivers --> Multimedia support:
  select Cameras/video grabbers support
Then in Video capture adapters --> V4L platform devices -->
Camera support on Marvell MMP:
  select Marvell MMP camera driver based on SOC_CAMERA
Also in Video capture adapters --> V4L platform devices:
  select SoC camera support
  select the relevant sensor in target platform

Also add MIPI interface and dual CCICs support in Soc Camera mode.

Signed-off-by: Albert Wang <twan...@marvell.com>
Signed-off-by: Libin Yang <lby...@marvell.com>
---
 drivers/media/platform/Makefile                  |    4 +-
 drivers/media/platform/marvell-ccic/Kconfig      |   22 +++
 drivers/media/platform/marvell-ccic/Makefile     |    1 +
 drivers/media/platform/marvell-ccic/mmp-driver.c |  253 
+++++++++++++++++++------
 include/media/mmp-camera.h                    |   13 ++
 5 files changed, 233 insertions(+), 60 deletions(-)

diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index b7da9fa..ca60607 100755
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -146,9 +146,6 @@ obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
 
 obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 
-obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/
-obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/
-
 obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
 
 obj-$(CONFIG_VIDEO_OMAP3)      += omap3isp/
@@ -182,6 +179,7 @@ obj-$(CONFIG_VIDEO_MX1)                     += mx1_camera.o
 obj-$(CONFIG_VIDEO_MX2)                        += mx2_camera.o
 obj-$(CONFIG_VIDEO_MX3)                        += mx3_camera.o
 obj-$(CONFIG_VIDEO_PXA27x)             += pxa_camera.o
+obj-$(CONFIG_VIDEO_MARVELL_CCIC)       += marvell-ccic/
 obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2)     += sh_mobile_csi2.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)      += sh_mobile_ceu_camera.o
 obj-$(CONFIG_VIDEO_OMAP1)              += omap1_camera.o
diff --git a/drivers/media/platform/marvell-ccic/Kconfig 
b/drivers/media/platform/marvell-ccic/Kconfig
index bf739e3..6e3eaa0 100755
--- a/drivers/media/platform/marvell-ccic/Kconfig
+++ b/drivers/media/platform/marvell-ccic/Kconfig
@@ -1,23 +1,45 @@
+config VIDEO_MARVELL_CCIC
+       tristate
+config VIDEO_MRVL_SOC_CAMERA
+       tristate
+
 config VIDEO_CAFE_CCIC
        tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support"
        depends on PCI && I2C && VIDEO_V4L2
        select VIDEO_OV7670
        select VIDEOBUF2_VMALLOC
        select VIDEOBUF2_DMA_CONTIG
+       select VIDEO_MARVELL_CCIC
        ---help---
          This is a video4linux2 driver for the Marvell 88ALP01 integrated
          CMOS camera controller.  This is the controller found on first-
          generation OLPC systems.
 
+choice
+       prompt "Camera support on Marvell MMP"
+       depends on ARCH_MMP && VIDEO_V4L2
+       optional
 config VIDEO_MMP_CAMERA
        tristate "Marvell Armada 610 integrated camera controller support"
        depends on ARCH_MMP && I2C && VIDEO_V4L2
        select VIDEO_OV7670
        select I2C_GPIO
        select VIDEOBUF2_DMA_SG
+       select VIDEO_MARVELL_CCIC
        ---help---
          This is a Video4Linux2 driver for the integrated camera
          controller found on Marvell Armada 610 application
          processors (and likely beyond).  This is the controller found
          in OLPC XO 1.75 systems.
 
+config VIDEO_MMP_SOC_CAMERA
+       bool "Marvell MMP camera driver based on SOC_CAMERA"
+       depends on VIDEO_DEV && SOC_CAMERA && ARCH_MMP && VIDEO_V4L2
+       select VIDEOBUF2_DMA_CONTIG
+       select VIDEO_MARVELL_CCIC
+       select VIDEO_MRVL_SOC_CAMERA
+       ---help---
+         This is a Video4Linux2 driver for the Marvell Mobile Soc
+         PXA910/PXA688/PXA2128/PXA988 CCIC
+         (CMOS Camera Interface Controller)
+endchoice
diff --git a/drivers/media/platform/marvell-ccic/Makefile 
b/drivers/media/platform/marvell-ccic/Makefile
index 05a792c..d6ffd16 100755
--- a/drivers/media/platform/marvell-ccic/Makefile
+++ b/drivers/media/platform/marvell-ccic/Makefile
@@ -2,5 +2,6 @@ obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
 cafe_ccic-y := cafe-driver.o mcam-core.o
 
 obj-$(CONFIG_VIDEO_MMP_CAMERA) += mmp_camera.o
+obj-$(CONFIG_VIDEO_MMP_SOC_CAMERA) += mmp_camera.o
 mmp_camera-y := mmp-driver.o mcam-core.o
 
diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c 
b/drivers/media/platform/marvell-ccic/mmp-driver.c
index c4c17fe..afdd702 100755
--- a/drivers/media/platform/marvell-ccic/mmp-driver.c
+++ b/drivers/media/platform/marvell-ccic/mmp-driver.c
@@ -4,6 +4,12 @@
  *
  * Copyright 2011 Jonathan Corbet <cor...@lwn.net>
  *
+ * History:
+ * Support Soc Camera
+ * Support MIPI interface and Dual CCICs in Soc Camera mode
+ * Sep-2012: Libin Yang <lby...@marvell.com>
+ *           Albert Wang <twan...@marvell.com>
+ *
  * This file may be distributed under the terms of the GNU General
  * Public License, version 2.
  */
@@ -17,9 +23,6 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/mmp-camera.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
@@ -27,6 +30,19 @@
 #include <linux/delay.h>
 #include <linux/list.h>
 #include <linux/pm.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/mmp-camera.h>
+#ifdef CONFIG_VIDEO_MMP_SOC_CAMERA
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#endif
+
+#include <mach/regs-apmu.h>
+#include <plat/mfp.h>
 
 #include "mcam-core.h"
 
@@ -39,6 +55,7 @@ struct mmp_camera {
        struct platform_device *pdev;
        struct mcam_camera mcam;
        struct list_head devlist;
+       struct clk *clk[3];     /* CCIC_GATE, CCIC_RST, CCIC_DBG clocks */
        int irq;
 };
 
@@ -90,15 +107,7 @@ static struct mmp_camera *mmpcam_find_device(struct 
platform_device *pdev)
        return NULL;
 }
 
-
-
-
-/*
- * Power-related registers; this almost certainly belongs
- * somewhere else.
- *
- * ARMADA 610 register manual, sec 7.2.1, p1842.
- */
+#ifdef CONFIG_VIDEO_MMP_CAMERA
 #define CPU_SUBSYS_PMU_BASE    0xd4282800
 #define REG_CCIC_DCGCR         0x28    /* CCIC dyn clock gate ctrl reg */
 #define REG_CCIC_CRCR          0x50    /* CCIC clk reset ctrl reg      */
@@ -117,13 +126,13 @@ static void mmpcam_power_up(struct mcam_camera *mcam)
 {
        struct mmp_camera *cam = mcam_to_cam(mcam);
        struct mmp_camera_platform_data *pdata;
-/*
- * Turn on power and clocks to the controller.
- */
+       /*
+        * Turn on power and clocks to the controller.
+        */
        mmpcam_power_up_ctlr(cam);
-/*
- * Provide power to the sensor.
- */
+       /*
+        * Provide power to the sensor.
+        */
        mcam_reg_write(mcam, REG_CLKCTRL, 0x60000002);
        pdata = cam->pdev->dev.platform_data;
        gpio_set_value(pdata->sensor_power_gpio, 1);
@@ -139,19 +148,91 @@ static void mmpcam_power_down(struct mcam_camera *mcam)
 {
        struct mmp_camera *cam = mcam_to_cam(mcam);
        struct mmp_camera_platform_data *pdata;
-/*
- * Turn off clocks and set reset lines
- */
+       /*
+        * Turn off clocks and set reset lines
+        */
        iowrite32(0, cam->power_regs + REG_CCIC_DCGCR);
        iowrite32(0, cam->power_regs + REG_CCIC_CRCR);
-/*
- * Shut down the sensor.
- */
+       /*
+        * Shut down the sensor.
+        */
        pdata = cam->pdev->dev.platform_data;
        gpio_set_value(pdata->sensor_power_gpio, 0);
        gpio_set_value(pdata->sensor_reset_gpio, 0);
 }
 
+void mmpcam_calc_dphy(struct mcam_camera *mcam,
+                       struct v4l2_subdev_frame_interval *inter)
+{
+       return;
+}
+#else
+/* setup the camera clk gate in APMU */
+static void mmpcam_island_clk(struct mmp_camera *cam, int on)
+{
+       if (on)
+               clk_enable(cam->clk[0]);
+       else
+               clk_disable(cam->clk[0]);
+}
+
+static void mmpcam_power_up(struct mcam_camera *mcam)
+{
+       struct mmp_camera *cam = mcam_to_cam(mcam);
+       mmpcam_island_clk(cam, 1);
+}
+
+static void mmpcam_power_up_ctlr(struct mmp_camera *cam)
+{
+       mmpcam_power_up(&cam->mcam);
+}
+
+static void mmpcam_power_down(struct mcam_camera *mcam)
+{
+       struct mmp_camera *cam = mcam_to_cam(mcam);
+       mmpcam_island_clk(cam, 0);
+}
+
+void mmpcam_calc_dphy(struct mcam_camera *mcam,
+                       struct v4l2_subdev_frame_interval *inter)
+{
+       struct mmp_camera *cam = mcam_to_cam(mcam);
+       struct mmp_camera_platform_data *pdata = cam->pdev->dev.platform_data;
+       struct device *dev = &cam->pdev->dev;
+       unsigned long tx_clk_esc;
+       struct clk *pll1;
+
+       if (pdata->dphy3_algo == 1)
+               /*
+                * dphy3_algo == 1
+                * Calculate CSI2_DPHY3 algo for PXA910
+                */
+               pdata->dphy[0] = ((1 + inter->pad * 80 / 1000) & 0xff) << 8
+                       | (1 + inter->pad * 35 / 1000);
+       else if (pdata->dphy3_algo == 2)
+               /*
+                * dphy3_algo == 2
+                * Calculate CSI2_DPHY3 algo for PXA2128
+                */
+               pdata->dphy[0] = ((2 + inter->pad * 110 / 1000) & 0xff) << 8
+                       | (1 + inter->pad * 35 / 1000);
+
+       pll1 = clk_get(dev, "pll1");
+       if (IS_ERR(pll1)) {
+               dev_err(dev, "Could not get pll1 clock\n");
+               return;
+       }
+
+       tx_clk_esc = clk_get_rate(pll1) / 1000000 / 12;
+       clk_put(pll1);
+
+       /*
+        * Update dphy6 according to current tx_clk_esc
+        */
+       pdata->dphy[2] = ((534 * tx_clk_esc / 2000 - 1) & 0xff) << 8
+                       | ((38 * tx_clk_esc / 1000 - 1) & 0xff);
+}
+#endif
 
 static irqreturn_t mmpcam_irq(int irq, void *data)
 {
@@ -160,12 +241,15 @@ static irqreturn_t mmpcam_irq(int irq, void *data)
 
        spin_lock(&mcam->dev_lock);
        irqs = mcam_reg_read(mcam, REG_IRQSTAT);
+       if (!(irqs & FRAMEIRQS)) {
+               spin_unlock(&mcam->dev_lock);
+               return IRQ_NONE;
+       }
        handled = mccic_irq(mcam, irqs);
        spin_unlock(&mcam->dev_lock);
        return IRQ_RETVAL(handled);
 }
 
-
 static int mmpcam_probe(struct platform_device *pdev)
 {
        struct mmp_camera *cam;
@@ -174,35 +258,76 @@ static int mmpcam_probe(struct platform_device *pdev)
        struct mmp_camera_platform_data *pdata;
        int ret;
 
-       cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+       pdata = pdev->dev.platform_data;
+
+       cam = devm_kzalloc(&pdev->dev, sizeof(*cam), GFP_KERNEL);
        if (cam == NULL)
                return -ENOMEM;
+
        cam->pdev = pdev;
        INIT_LIST_HEAD(&cam->devlist);
-
+       spin_lock_init(&mcam->dev_lock);
+       cam->clk[0] = clk_get(&pdev->dev, pdata->clk_name[0]);
        mcam = &cam->mcam;
        mcam->plat_power_up = mmpcam_power_up;
        mcam->plat_power_down = mmpcam_power_down;
+       mcam->calc_dphy = mmpcam_calc_dphy;
        mcam->dev = &pdev->dev;
        mcam->use_smbus = 0;
+       mcam->bus_type = pdata->bus_type;
+       mcam->ccic_id = pdev->id;
+       mcam->card_name = pdata->name;
+       mcam->mclk_min = pdata->mclk_min;
+       mcam->mclk_src = pdata->mclk_src;
+       mcam->mclk_div = pdata->mclk_div;
+       mcam->dphy = &(pdata->dphy);
+       mcam->mipi_enabled = 0;
+       mcam->lane = pdata->lane;
+#ifdef CONFIG_VIDEO_MMP_SOC_CAMERA
+       mcam->chip_id = pdata->chip_id;
+       mcam->buffer_mode = B_DMA_contig;
+#else
        mcam->chip_id = V4L2_IDENT_ARMADA610;
        mcam->buffer_mode = B_DMA_sg;
-       spin_lock_init(&mcam->dev_lock);
+#endif
+       switch (pdata->dma_burst) {
+       case 128:
+               mcam->burst = C1_DMAB128;
+               break;
+       case 256:
+               mcam->burst = C1_DMAB256;
+               break;
+       default:
+               mcam->burst = C1_DMAB64;
+               break;
+       }
+       INIT_LIST_HEAD(&mcam->buffers);
        /*
         * Get our I/O memory.
         */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
                dev_err(&pdev->dev, "no iomem resource!\n");
-               ret = -ENODEV;
-               goto out_free;
+               return -ENODEV;
        }
-       mcam->regs = ioremap(res->start, resource_size(res));
+       mcam->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (mcam->regs == NULL) {
                dev_err(&pdev->dev, "MMIO ioremap fail\n");
-               ret = -ENODEV;
-               goto out_free;
+               return -ENODEV;
        }
+
+#ifdef CONFIG_VIDEO_MMP_SOC_CAMERA
+       mcam->vb_alloc_ctx = (struct vb2_alloc_ctx *)
+               vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(mcam->vb_alloc_ctx))
+               return PTR_ERR(mcam->vb_alloc_ctx);
+
+       ret = mcam_soc_camera_host_register(mcam);
+       if (ret)
+               goto out_free_ctx;
+#endif
+
+#ifdef CONFIG_VIDEO_MMP_CAMERA
        /*
         * Power/clock memory is elsewhere; get it too.  Perhaps this
         * should really be managed outside of this driver?
@@ -211,24 +336,25 @@ static int mmpcam_probe(struct platform_device *pdev)
        if (res == NULL) {
                dev_err(&pdev->dev, "no power resource!\n");
                ret = -ENODEV;
-               goto out_unmap1;
+               goto out_host_unregister;
        }
-       cam->power_regs = ioremap(res->start, resource_size(res));
+       cam->power_regs = devm_request_and_ioremap(&pdev->dev, res);
        if (cam->power_regs == NULL) {
                dev_err(&pdev->dev, "power MMIO ioremap fail\n");
                ret = -ENODEV;
-               goto out_unmap1;
+               goto out_host_unregister;
        }
+
        /*
         * Find the i2c adapter.  This assumes, of course, that the
         * i2c bus is already up and functioning.
+        * soc-camera manages i2c interface in sensor side
         */
-       pdata = pdev->dev.platform_data;
        mcam->i2c_adapter = platform_get_drvdata(pdata->i2c_device);
        if (mcam->i2c_adapter == NULL) {
                ret = -ENODEV;
                dev_err(&pdev->dev, "No i2c adapter\n");
-               goto out_unmap2;
+               goto out_host_unregister;
        }
        /*
         * Sensor GPIO pins.
@@ -237,23 +363,26 @@ static int mmpcam_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(&pdev->dev, "Can't get sensor power gpio %d",
                                pdata->sensor_power_gpio);
-               goto out_unmap2;
+               goto out_host_unregister;
        }
        gpio_direction_output(pdata->sensor_power_gpio, 0);
        ret = gpio_request(pdata->sensor_reset_gpio, "cam-reset");
        if (ret) {
                dev_err(&pdev->dev, "Can't get sensor reset gpio %d",
                                pdata->sensor_reset_gpio);
-               goto out_gpio;
+               goto out_gpio1;
        }
        gpio_direction_output(pdata->sensor_reset_gpio, 0);
+
        /*
         * Power the device up and hand it off to the core.
         */
        mmpcam_power_up(mcam);
+#endif
        ret = mccic_register(mcam);
        if (ret)
                goto out_gpio2;
+
        /*
         * Finally, set up our IRQ now that the core is ready to
         * deal with it.
@@ -264,7 +393,7 @@ static int mmpcam_probe(struct platform_device *pdev)
                goto out_unregister;
        }
        cam->irq = res->start;
-       ret = request_irq(cam->irq, mmpcam_irq, IRQF_SHARED,
+       ret = devm_request_irq(&pdev->dev, cam->irq, mmpcam_irq, IRQF_SHARED,
                        "mmp-camera", mcam);
        if (ret == 0) {
                mmpcam_add_device(cam);
@@ -274,35 +403,46 @@ static int mmpcam_probe(struct platform_device *pdev)
 out_unregister:
        mccic_shutdown(mcam);
 out_gpio2:
+#ifdef CONFIG_VIDEO_MMP_CAMERA
        mmpcam_power_down(mcam);
        gpio_free(pdata->sensor_reset_gpio);
-out_gpio:
+out_gpio1:
        gpio_free(pdata->sensor_power_gpio);
-out_unmap2:
-       iounmap(cam->power_regs);
-out_unmap1:
-       iounmap(mcam->regs);
-out_free:
-       kfree(cam);
+out_host_unregister:
+#endif
+#ifdef CONFIG_VIDEO_MMP_SOC_CAMERA
+       soc_camera_host_unregister(&mcam->soc_host);
+out_free_ctx:
+       vb2_dma_contig_cleanup_ctx(mcam->vb_alloc_ctx);
+       mcam->vb_alloc_ctx = NULL;
+#endif
        return ret;
 }
 
-
 static int mmpcam_remove(struct mmp_camera *cam)
 {
        struct mcam_camera *mcam = &cam->mcam;
-       struct mmp_camera_platform_data *pdata;
+#ifdef CONFIG_VIDEO_MMP_SOC_CAMERA
+       struct soc_camera_host *soc_host = &mcam->soc_host;
+#else
+       struct mmp_camera_platform_data *pdata = cam->pdev->dev.platform_data;
+#endif
 
        mmpcam_remove_device(cam);
-       free_irq(cam->irq, mcam);
+       devm_free_irq(&cam->pdev->dev, cam->irq, mcam);
        mccic_shutdown(mcam);
        mmpcam_power_down(mcam);
-       pdata = cam->pdev->dev.platform_data;
+#ifdef CONFIG_VIDEO_MMP_SOC_CAMERA
+       soc_camera_host_unregister(soc_host);
+       vb2_dma_contig_cleanup_ctx(mcam->vb_alloc_ctx);
+       mcam->vb_alloc_ctx = NULL;
+#else
        gpio_free(pdata->sensor_reset_gpio);
        gpio_free(pdata->sensor_power_gpio);
-       iounmap(cam->power_regs);
-       iounmap(mcam->regs);
-       kfree(cam);
+       devm_iounmap(&cam->pdev->dev, cam->power_regs);
+#endif
+       devm_iounmap(&cam->pdev->dev, mcam->regs);
+       devm_kfree(&cam->pdev->dev, cam);
        return 0;
 }
 
@@ -312,6 +452,7 @@ static int mmpcam_platform_remove(struct platform_device 
*pdev)
 
        if (cam == NULL)
                return -ENODEV;
+
        return mmpcam_remove(cam);
 }
 
@@ -345,7 +486,6 @@ static int mmpcam_resume(struct platform_device *pdev)
 
 #endif
 
-
 static struct platform_driver mmpcam_driver = {
        .probe          = mmpcam_probe,
        .remove         = mmpcam_platform_remove,
@@ -359,7 +499,6 @@ static struct platform_driver mmpcam_driver = {
        }
 };
 
-
 static int __init mmpcam_init_module(void)
 {
        mutex_init(&mmpcam_devices_lock);
diff --git a/include/media/mmp-camera.h b/include/media/mmp-camera.h
index 7611963..f90f8c4 100755
--- a/include/media/mmp-camera.h
+++ b/include/media/mmp-camera.h
@@ -6,4 +6,17 @@ struct mmp_camera_platform_data {
        struct platform_device *i2c_device;
        int sensor_power_gpio;
        int sensor_reset_gpio;
+       char *clk_name[3];
+       char name[16];
+       int clk_enabled;
+       int dphy[3];            /* DPHY: CSI2_DPHY3, CSI2_DPHY5, CSI2_DPHY6 */
+       int dphy3_algo;         /* Exist 2 algos for calculate CSI2_DPHY3 */
+       int bus_type;
+       int mipi_enabled;       /* MIPI enabled flag */
+       int lane;               /* ccic used lane number; 0 means DVP mode */
+       int dma_burst;
+       int mclk_min;
+       int mclk_src;
+       int mclk_div;
+       int chip_id;
 };
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to