msm: camera: Convert CSID into platform device

Make CSID platform devices as well as
v4l2 sub-devices. They are created at system boot-up,
and registered during camera open.

The subdevices are decoupled from the v4l2 devices by
using device model APIs to find and register them.

Change-Id: Icdb7d878456e749500b3e7a9e183997dba651cfd
Signed-off-by: Kevin Chan <ktchan@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 537605b..507bc32 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -1422,6 +1422,8 @@
 
 	platform_device_register(&msm8960_device_csiphy0);
 	platform_device_register(&msm8960_device_csiphy1);
+	platform_device_register(&msm8960_device_csid0);
+	platform_device_register(&msm8960_device_csid1);
 }
 #endif
 
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 5cc2d1b..52d8f63 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5379,21 +5379,12 @@
 	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"msm_camera_imx074.0"),
 	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"msm_camera_ov2720.0"),
 	CLK_LOOKUP("cam_clk",	cam0_clk.c,	"msm_camera_qs_mt9p017.0"),
-	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,		NULL),
-	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,		NULL),
-	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,	"msm_camera_imx074.0"),
-	CLK_LOOKUP("csi_src_clk", csi0_src_clk.c, "msm_camera_qs_mt9p017.0"),
-	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,	"msm_camera_ov2720.0"),
-	CLK_LOOKUP("csi_clk",		csi0_clk.c,		NULL),
-	CLK_LOOKUP("csi_clk",		csi1_clk.c,		NULL),
-	CLK_LOOKUP("csi_clk",		csi0_clk.c,	"msm_camera_imx074.0"),
-	CLK_LOOKUP("csi_clk",	csi0_clk.c,	"msm_camera_qs_mt9p017.0"),
-	CLK_LOOKUP("csi_clk",		csi1_clk.c,	"msm_camera_ov2720.0"),
-	CLK_LOOKUP("csi_phy_clk",	csi0_phy_clk.c,		NULL),
-	CLK_LOOKUP("csi_phy_clk",	csi1_phy_clk.c,		NULL),
-	CLK_LOOKUP("csi_phy_clk",	csi0_phy_clk.c,	"msm_camera_imx074.0"),
-	CLK_LOOKUP("csi_phy_clk", csi0_phy_clk.c, "msm_camera_qs_mt9p017.0"),
-	CLK_LOOKUP("csi_phy_clk",	csi1_phy_clk.c,	"msm_camera_ov2720.0"),
+	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_clk",		csi0_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_clk",		csi1_clk.c,		"msm_csid.1"),
+	CLK_LOOKUP("csi_phy_clk",	csi0_phy_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_phy_clk",	csi1_phy_clk.c,		"msm_csid.1"),
 	CLK_LOOKUP("csi_pix_clk",	csi_pix_clk.c,		NULL),
 	CLK_LOOKUP("csi_rdi_clk",	csi_rdi_clk.c,		NULL),
 	CLK_LOOKUP("csiphy_timer_src_clk",
@@ -5450,7 +5441,8 @@
 	CLK_LOOKUP("bus_b_clk",        vcodec_axi_b_clk.c, "footswitch-8x60.7"),
 	CLK_LOOKUP("bus_clk",		vpe_axi_clk.c,	"footswitch-8x60.9"),
 	CLK_LOOKUP("amp_pclk",		amp_p_clk.c,		NULL),
-	CLK_LOOKUP("csi_pclk",		csi_p_clk.c,		NULL),
+	CLK_LOOKUP("csi_pclk",		csi_p_clk.c,		"msm_csid.0"),
+	CLK_LOOKUP("csi_pclk",		csi_p_clk.c,		"msm_csid.1"),
 	CLK_LOOKUP("dsi_m_pclk",	dsi1_m_p_clk.c,		NULL),
 	CLK_LOOKUP("dsi_s_pclk",	dsi1_s_p_clk.c,		NULL),
 	CLK_LOOKUP("dsi_m_pclk",	dsi2_m_p_clk.c,		NULL),
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index c5eee63..1b314f2 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1023,30 +1023,6 @@
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "csid0",
-		.start	= 0x04800000,
-		.end	= 0x04800000 + SZ_1K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	{
-		.name	= "csid0",
-		.start	= CSI_0_IRQ,
-		.end	= CSI_0_IRQ,
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
-		.name	= "csid1",
-		.start	= 0x04800400,
-		.end	= 0x04800400 + SZ_1K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	{
-		.name	= "csid1",
-		.start	= CSI_1_IRQ,
-		.end	= CSI_1_IRQ,
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
 		.name   = "s3d_rw",
 		.start  = 0x008003E0,
 		.end    = 0x008003E0 + SZ_16 - 1,
@@ -1058,7 +1034,6 @@
 		.end    = 0x008020B8 + SZ_16 - 1,
 		.flags  = IORESOURCE_MEM,
 	},
-
 };
 
 int __init msm_get_cam_resources(struct msm_camera_sensor_info *s_info)
@@ -1111,6 +1086,50 @@
 	.resource       = msm_csiphy1_resources,
 	.num_resources  = ARRAY_SIZE(msm_csiphy1_resources),
 };
+
+static struct resource msm_csid0_resources[] = {
+	{
+		.name	= "csid",
+		.start	= 0x04800000,
+		.end	= 0x04800000 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "csid",
+		.start	= CSI_0_IRQ,
+		.end	= CSI_0_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_csid1_resources[] = {
+	{
+		.name	= "csid",
+		.start	= 0x04800400,
+		.end	= 0x04800400 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "csid",
+		.start	= CSI_1_IRQ,
+		.end	= CSI_1_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_device_csid0 = {
+	.name           = "msm_csid",
+	.id             = 0,
+	.resource       = msm_csid0_resources,
+	.num_resources  = ARRAY_SIZE(msm_csid0_resources),
+};
+
+struct platform_device msm8960_device_csid1 = {
+	.name           = "msm_csid",
+	.id             = 1,
+	.resource       = msm_csid1_resources,
+	.num_resources  = ARRAY_SIZE(msm_csid1_resources),
+};
 #endif
 
 static struct resource resources_ssbi_pm8921[] = {
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 7196224..fbbcd70 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -60,6 +60,8 @@
 extern struct platform_device msm8960_gemini_device;
 extern struct platform_device msm8960_device_csiphy0;
 extern struct platform_device msm8960_device_csiphy1;
+extern struct platform_device msm8960_device_csid0;
+extern struct platform_device msm8960_device_csid1;
 
 extern struct platform_device apq8064_device_uart_gsbi1;
 extern struct platform_device apq8064_device_uart_gsbi3;
diff --git a/drivers/media/video/msm/csi/Makefile b/drivers/media/video/msm/csi/Makefile
index 4ec67e6..9425c47 100644
--- a/drivers/media/video/msm/csi/Makefile
+++ b/drivers/media/video/msm/csi/Makefile
@@ -1,3 +1,3 @@
 GCC_VERSION      := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
 EXTRA_CFLAGS += -Idrivers/media/video/msm
-obj-$(CONFIG_ARCH_MSM8960) += msm_csiphy.o
+obj-$(CONFIG_ARCH_MSM8960) += msm_csiphy.o msm_csid.o
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
new file mode 100644
index 0000000..fb809c9
--- /dev/null
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -0,0 +1,306 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <media/msm_isp.h>
+#include "msm_csid.h"
+#include "msm.h"
+
+#define V4L2_IDENT_CSID                            50002
+
+/* MIPI	CSID registers */
+#define CSID_HW_VERSION_ADDR                        0x0
+#define CSID_CORE_CTRL_ADDR                         0x4
+#define CSID_RST_CMD_ADDR                           0x8
+#define CSID_CID_LUT_VC_0_ADDR                      0xc
+#define CSID_CID_LUT_VC_1_ADDR                      0x10
+#define CSID_CID_LUT_VC_2_ADDR                      0x14
+#define CSID_CID_LUT_VC_3_ADDR                      0x18
+#define CSID_CID_n_CFG_ADDR                         0x1C
+#define CSID_IRQ_CLEAR_CMD_ADDR                     0x5c
+#define CSID_IRQ_MASK_ADDR                          0x60
+#define CSID_IRQ_STATUS_ADDR                        0x64
+#define CSID_CAPTURED_UNMAPPED_LONG_PKT_HDR_ADDR    0x68
+#define CSID_CAPTURED_MMAPPED_LONG_PKT_HDR_ADDR     0x6c
+#define CSID_CAPTURED_SHORT_PKT_ADDR                0x70
+#define CSID_CAPTURED_LONG_PKT_HDR_ADDR             0x74
+#define CSID_CAPTURED_LONG_PKT_FTR_ADDR             0x78
+#define CSID_PIF_MISR_DL0_ADDR                      0x7C
+#define CSID_PIF_MISR_DL1_ADDR                      0x80
+#define CSID_PIF_MISR_DL2_ADDR                      0x84
+#define CSID_PIF_MISR_DL3_ADDR                      0x88
+#define CSID_STATS_TOTAL_PKTS_RCVD_ADDR             0x8C
+#define CSID_STATS_ECC_ADDR                         0x90
+#define CSID_STATS_CRC_ADDR                         0x94
+#define CSID_TG_CTRL_ADDR                           0x9C
+#define CSID_TG_VC_CFG_ADDR                         0xA0
+#define CSID_TG_DT_n_CFG_0_ADDR                     0xA8
+#define CSID_TG_DT_n_CFG_1_ADDR                     0xAC
+#define CSID_TG_DT_n_CFG_2_ADDR                     0xB0
+#define CSID_TG_DT_n_CFG_3_ADDR                     0xD8
+
+#define DBG_CSID 0
+
+static int msm_csid_cid_lut(
+	struct msm_camera_csid_lut_params *csid_lut_params,
+	void __iomem *csidbase)
+{
+	int rc = 0, i = 0;
+	uint32_t val = 0;
+
+	for (i = 0; i < csid_lut_params->num_cid && i < 4; i++) {
+		if (csid_lut_params->vc_cfg[i].dt < 0x12 ||
+			csid_lut_params->vc_cfg[i].dt > 0x37) {
+			CDBG("%s: unsupported data type 0x%x\n",
+				 __func__, csid_lut_params->vc_cfg[i].dt);
+			return rc;
+		}
+		val = msm_io_r(csidbase + CSID_CID_LUT_VC_0_ADDR +
+		(csid_lut_params->vc_cfg[i].cid >> 2) * 4)
+		& ~(0xFF << csid_lut_params->vc_cfg[i].cid * 8);
+		val |= csid_lut_params->vc_cfg[i].dt <<
+			csid_lut_params->vc_cfg[i].cid * 8;
+		msm_io_w(val, csidbase + CSID_CID_LUT_VC_0_ADDR +
+			(csid_lut_params->vc_cfg[i].cid >> 2) * 4);
+		val = csid_lut_params->vc_cfg[i].decode_format << 4 | 0x3;
+		msm_io_w(val, csidbase + CSID_CID_n_CFG_ADDR +
+			(csid_lut_params->vc_cfg[i].cid * 4));
+	}
+	return rc;
+}
+
+static int msm_csid_config(struct csid_cfg_params *cfg_params)
+{
+	int rc = 0;
+	uint32_t val = 0;
+	struct csid_device *csid_dev;
+	struct msm_camera_csid_params *csid_params;
+	void __iomem *csidbase;
+	csid_dev = v4l2_get_subdevdata(cfg_params->subdev);
+	csidbase = csid_dev->base;
+	csid_params = cfg_params->parms;
+	val = csid_params->lane_cnt - 1;
+	val |= csid_params->lane_assign << 2;
+	val |= 0x1 << 10;
+	val |= 0x1 << 11;
+	val |= 0x1 << 12;
+	val |= 0x1 << 28;
+	msm_io_w(val, csidbase + CSID_CORE_CTRL_ADDR);
+
+	rc = msm_csid_cid_lut(&csid_params->lut_params, csidbase);
+	if (rc < 0)
+		return rc;
+
+	msm_io_w(0x7fF10800, csidbase + CSID_IRQ_MASK_ADDR);
+	msm_io_w(0x7fF10800, csidbase + CSID_IRQ_CLEAR_CMD_ADDR);
+
+	msleep(20);
+	return rc;
+}
+
+static irqreturn_t msm_csid_irq(int irq_num, void *data)
+{
+	uint32_t irq;
+	struct csid_device *csid_dev = data;
+	irq = msm_io_r(csid_dev->base + CSID_IRQ_STATUS_ADDR);
+	CDBG("%s CSID_IRQ_STATUS_ADDR = 0x%x\n", __func__, irq);
+	msm_io_w(irq, csid_dev->base + CSID_IRQ_CLEAR_CMD_ADDR);
+	return IRQ_HANDLED;
+}
+
+static int msm_csid_subdev_g_chip_ident(struct v4l2_subdev *sd,
+			struct v4l2_dbg_chip_ident *chip)
+{
+	BUG_ON(!chip);
+	chip->ident = V4L2_IDENT_CSID;
+	chip->revision = 0;
+	return 0;
+}
+
+static struct msm_cam_clk_info csid_clk_info[] = {
+	{"csi_src_clk", 177780000},
+	{"csi_clk", -1},
+	{"csi_phy_clk", -1},
+	{"csi_pclk", -1},
+};
+
+static int msm_csid_init(struct v4l2_subdev *sd, uint32_t *csid_version)
+{
+	int rc = 0;
+	struct csid_device *csid_dev;
+	csid_dev = v4l2_get_subdevdata(sd);
+	if (csid_dev == NULL) {
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	csid_dev->base = ioremap(csid_dev->mem->start,
+		resource_size(csid_dev->mem));
+	if (!csid_dev->base) {
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	rc = msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info,
+		csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 1);
+	if (rc < 0) {
+		iounmap(csid_dev->base);
+		return rc;
+	}
+
+#if DBG_CSID
+	enable_irq(csid_dev->irq->start);
+#endif
+
+	*csid_version = csid_dev->hw_version;
+
+	return 0;
+}
+
+static int msm_csid_release(struct v4l2_subdev *sd)
+{
+	struct csid_device *csid_dev;
+	csid_dev = v4l2_get_subdevdata(sd);
+
+#if DBG_CSID
+	disable_irq(csid_dev->irq->start);
+#endif
+
+	msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info,
+		csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 0);
+
+	iounmap(csid_dev->base);
+	return 0;
+}
+
+static long msm_csid_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	struct csid_cfg_params cfg_params;
+	switch (cmd) {
+	case VIDIOC_MSM_CSID_CFG:
+		cfg_params.subdev = sd;
+		cfg_params.parms = arg;
+		return msm_csid_config((struct csid_cfg_params *)&cfg_params);
+	case VIDIOC_MSM_CSID_INIT:
+		return msm_csid_init(sd, (uint32_t *)arg);
+	case VIDIOC_MSM_CSID_RELEASE:
+		return msm_csid_release(sd);
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static struct v4l2_subdev_core_ops msm_csid_subdev_core_ops = {
+	.g_chip_ident = &msm_csid_subdev_g_chip_ident,
+	.ioctl = &msm_csid_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_csid_subdev_ops = {
+	.core = &msm_csid_subdev_core_ops,
+};
+
+static int __devinit csid_probe(struct platform_device *pdev)
+{
+	struct csid_device *new_csid_dev;
+	int rc = 0;
+	CDBG("%s: device id = %d\n", __func__, pdev->id);
+	new_csid_dev = kzalloc(sizeof(struct csid_device), GFP_KERNEL);
+	if (!new_csid_dev) {
+		pr_err("%s: no enough memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	v4l2_subdev_init(&new_csid_dev->subdev, &msm_csid_subdev_ops);
+	v4l2_set_subdevdata(&new_csid_dev->subdev, new_csid_dev);
+	platform_set_drvdata(pdev, &new_csid_dev->subdev);
+	mutex_init(&new_csid_dev->mutex);
+
+	new_csid_dev->mem = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "csid");
+	if (!new_csid_dev->mem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		rc = -ENODEV;
+		goto csid_no_resource;
+	}
+	new_csid_dev->irq = platform_get_resource_byname(pdev,
+					IORESOURCE_IRQ, "csid");
+	if (!new_csid_dev->irq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		rc = -ENODEV;
+		goto csid_no_resource;
+	}
+	new_csid_dev->io = request_mem_region(new_csid_dev->mem->start,
+		resource_size(new_csid_dev->mem), pdev->name);
+	if (!new_csid_dev->io) {
+		pr_err("%s: no valid mem region\n", __func__);
+		rc = -EBUSY;
+		goto csid_no_resource;
+	}
+
+	rc = request_irq(new_csid_dev->irq->start, msm_csid_irq,
+		IRQF_TRIGGER_RISING, "csid", new_csid_dev);
+	if (rc < 0) {
+		release_mem_region(new_csid_dev->mem->start,
+			resource_size(new_csid_dev->mem));
+		pr_err("%s: irq request fail\n", __func__);
+		rc = -EBUSY;
+		goto csid_no_resource;
+	}
+	disable_irq(new_csid_dev->irq->start);
+
+	new_csid_dev->base = ioremap(new_csid_dev->mem->start,
+		resource_size(new_csid_dev->mem));
+	if (!new_csid_dev->base) {
+		rc = -ENOMEM;
+		goto csid_no_resource;
+	}
+
+	new_csid_dev->hw_version =
+		msm_io_r(new_csid_dev->base + CSID_HW_VERSION_ADDR);
+	iounmap(new_csid_dev->base);
+
+	new_csid_dev->pdev = pdev;
+	return 0;
+
+csid_no_resource:
+	mutex_destroy(&new_csid_dev->mutex);
+	kfree(new_csid_dev);
+	return 0;
+}
+
+static struct platform_driver csid_driver = {
+	.probe = csid_probe,
+	.driver = {
+		.name = MSM_CSID_DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_csid_init_module(void)
+{
+	return platform_driver_register(&csid_driver);
+}
+
+static void __exit msm_csid_exit_module(void)
+{
+	platform_driver_unregister(&csid_driver);
+}
+
+module_init(msm_csid_init_module);
+module_exit(msm_csid_exit_module);
+MODULE_DESCRIPTION("MSM CSID driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/csi/msm_csid.h b/drivers/media/video/msm/csi/msm_csid.h
new file mode 100644
index 0000000..f90abf2
--- /dev/null
+++ b/drivers/media/video/msm/csi/msm_csid.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSID_H
+#define MSM_CSID_H
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <media/v4l2-subdev.h>
+
+struct csid_device {
+	struct platform_device *pdev;
+	struct v4l2_subdev subdev;
+	struct resource *mem;
+	struct resource *irq;
+	struct resource *io;
+	void __iomem *base;
+	struct mutex mutex;
+	uint32_t hw_version;
+
+	struct clk *csid_clk[5];
+};
+
+struct csid_cfg_params {
+	struct v4l2_subdev *subdev;
+	void *parms;
+};
+
+#define VIDIOC_MSM_CSID_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csid_cfg_params)
+
+#define VIDIOC_MSM_CSID_INIT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct v4l2_subdev*)
+
+#define VIDIOC_MSM_CSID_RELEASE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct v4l2_subdev*)
+
+#endif
+
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index ef6d684..c8b4abf 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -42,6 +42,7 @@
 #define ERR_COPY_TO_USER() ERR_USER_COPY(1)
 
 #define MSM_CSIPHY_DRV_NAME "msm_csiphy"
+#define MSM_CSID_DRV_NAME "msm_csid"
 
 /* msm queue management APIs*/
 
@@ -116,6 +117,7 @@
 	NOTIFY_VPE_MSG_EVT,
 	NOTIFY_PCLK_CHANGE, /* arg = pclk */
 	NOTIFY_CSIPHY_CFG, /* arg = msm_camera_csiphy_params */
+	NOTIFY_CSID_CFG, /* arg = msm_camera_csid_params */
 	NOTIFY_INVALID
 };
 
@@ -219,6 +221,7 @@
 	struct v4l2_subdev *flash_sdev;    /* vpe sub device : VPE */
 	struct msm_cam_config_dev *config_device;
 	struct v4l2_subdev *csiphy_sdev; /*csiphy sub device*/
+	struct v4l2_subdev *csid_sdev; /*csid sub device*/
 	struct v4l2_subdev *ispif_sdev; /* ispif sub device */
 	struct v4l2_subdev *act_sdev; /* actuator sub device */
 
diff --git a/drivers/media/video/msm/msm_io_8960.c b/drivers/media/video/msm/msm_io_8960.c
index 65bf3ad..de8d679 100644
--- a/drivers/media/video/msm/msm_io_8960.c
+++ b/drivers/media/video/msm/msm_io_8960.c
@@ -25,42 +25,8 @@
 #include <mach/msm_bus.h>
 #include <mach/msm_bus_board.h>
 
-#define DBG_CSID 0
 #define BUFF_SIZE_128 128
 
-/* MIPI	CSID registers */
-#define CSID_HW_VERSION_ADDR                    0x0
-#define CSID_CORE_CTRL_ADDR                     0x4
-#define CSID_RST_CMD_ADDR                       0x8
-#define CSID_CID_LUT_VC_0_ADDR                  0xc
-#define CSID_CID_LUT_VC_1_ADDR                  0x10
-#define CSID_CID_LUT_VC_2_ADDR                  0x14
-#define CSID_CID_LUT_VC_3_ADDR                  0x18
-#define CSID_CID_n_CFG_ADDR                     0x1C
-#define CSID_IRQ_CLEAR_CMD_ADDR                 0x5c
-#define CSID_IRQ_MASK_ADDR                      0x60
-#define CSID_IRQ_STATUS_ADDR                    0x64
-#define CSID_CAPTURED_UNMAPPED_LONG_PKT_HDR_ADDR    0x68
-#define CSID_CAPTURED_MMAPPED_LONG_PKT_HDR_ADDR     0x6c
-#define CSID_CAPTURED_SHORT_PKT_ADDR                0x70
-#define CSID_CAPTURED_LONG_PKT_HDR_ADDR             0x74
-#define CSID_CAPTURED_LONG_PKT_FTR_ADDR             0x78
-#define CSID_PIF_MISR_DL0_ADDR                      0x7C
-#define CSID_PIF_MISR_DL1_ADDR                      0x80
-#define CSID_PIF_MISR_DL2_ADDR                      0x84
-#define CSID_PIF_MISR_DL3_ADDR                      0x88
-#define CSID_STATS_TOTAL_PKTS_RCVD_ADDR             0x8C
-#define CSID_STATS_ECC_ADDR                         0x90
-#define CSID_STATS_CRC_ADDR                         0x94
-#define CSID_TG_CTRL_ADDR                           0x9C
-#define CSID_TG_VC_CFG_ADDR                         0xA0
-#define CSID_TG_DT_n_CFG_0_ADDR                     0xA8
-#define CSID_TG_DT_n_CFG_1_ADDR                     0xAC
-#define CSID_TG_DT_n_CFG_2_ADDR                     0xB0
-#define CSID_TG_DT_n_CFG_3_ADDR                     0xD8
-
-/* Regulator Voltage and Current */
-
 #define CAM_VAF_MINUV                 2800000
 #define CAM_VAF_MAXUV                 2800000
 #define CAM_VDIG_MINUV                    1200000
@@ -75,23 +41,15 @@
 #define CAM_VANA_LOAD_UA                  85600
 #define CAM_CSI_LOAD_UA                    20000
 
-#define CSID_VERSION_V2              0x2000011
-
-static uint32_t csid_hw_version;
 static struct clk *camio_cam_clk;
 static struct clk *camio_vfe_clk;
-static struct clk *camio_csi_src_clk;
-static struct clk *camio_csi1_src_clk;
 static struct clk *camio_csi0_vfe_clk;
-static struct clk *camio_csi0_clk;
-static struct clk *camio_csi0_pclk;
 static struct clk *camio_csi_pix_clk;
 static struct clk *camio_csi_pix1_clk;
 static struct clk *camio_csi_rdi_clk;
 static struct clk *camio_csi_rdi1_clk;
 static struct clk *camio_csi_rdi2_clk;
 static struct clk *camio_vfe_pclk;
-static struct clk *camio_csi0_phy_clk;
 
 /*static struct clk *camio_vfe_pclk;*/
 static struct clk *camio_jpeg_clk;
@@ -109,10 +67,9 @@
 
 static struct msm_camera_io_clk camio_clk;
 static struct platform_device *camio_dev;
-static struct resource *csidio, *s3drw_io, *s3dctl_io;
-static struct resource *csid_mem, *s3drw_mem, *s3dctl_mem;
-static struct resource *csid_irq;
-void __iomem *csidbase, *s3d_rw, *s3d_ctl;
+static struct resource *s3drw_io, *s3dctl_io;
+static struct resource *s3drw_mem, *s3dctl_mem;
+void __iomem *s3d_rw, *s3d_ctl;
 struct msm_bus_scale_pdata *cam_bus_scale_table;
 
 
@@ -441,28 +398,6 @@
 		clk = clk_get(&camio_dev->dev, "csi_vfe_clk");
 		break;
 */
-	case CAMIO_CSI_SRC_CLK:
-		camio_csi_src_clk =
-		clk = clk_get(NULL, "csi_src_clk");
-		msm_camio_clk_rate_set_2(clk, 177780000);
-		break;
-
-	case CAMIO_CSI1_SRC_CLK:
-		camio_csi1_src_clk =
-		clk = clk_get(&camio_dev->dev, "csi_src_clk");
-		msm_camio_clk_rate_set_2(clk, 177780000);
-		break;
-
-	case CAMIO_CSI0_CLK:
-		camio_csi0_clk =
-		clk = clk_get(&camio_dev->dev, "csi_clk");
-		break;
-
-	case CAMIO_CSI0_PHY_CLK:
-		camio_csi0_phy_clk =
-		clk = clk_get(&camio_dev->dev, "csi_phy_clk");
-		break;
-
 	case CAMIO_CSI_PIX_CLK:
 		camio_csi_pix_clk =
 		clk = clk_get(NULL, "csi_pix_clk");
@@ -498,11 +433,6 @@
 		msm_camio_clk_rate_set_2(clk, csid_core);
 		break;
 
-	case CAMIO_CSI0_PCLK:
-		camio_csi0_pclk =
-		clk = clk_get(NULL, "csi_pclk");
-		break;
-
 	case CAMIO_JPEG_CLK:
 		camio_jpeg_clk =
 		clk = clk_get(NULL, "ijpeg_clk");
@@ -562,18 +492,6 @@
 		clk = camio_csi0_vfe_clk;
 		break;
 
-	case CAMIO_CSI_SRC_CLK:
-		clk = camio_csi_src_clk;
-		break;
-
-	case CAMIO_CSI0_CLK:
-		clk = camio_csi0_clk;
-		break;
-
-	case CAMIO_CSI0_PHY_CLK:
-		clk = camio_csi0_phy_clk;
-		break;
-
 	case CAMIO_CSI_PIX1_CLK:
 		clk = camio_csi_pix1_clk;
 		break;
@@ -594,10 +512,6 @@
 		clk = camio_csi_rdi_clk;
 		break;
 
-	case CAMIO_CSI0_PCLK:
-		clk = camio_csi0_pclk;
-		break;
-
 	case CAMIO_JPEG_CLK:
 		clk = camio_jpeg_clk;
 		break;
@@ -666,73 +580,10 @@
 	clk_set_min_rate(clk, rate);
 }
 
-#if DBG_CSID
-static irqreturn_t msm_io_csi_irq(int irq_num, void *data)
-{
-	uint32_t irq;
-	irq = msm_io_r(csidbase + CSID_IRQ_STATUS_ADDR);
-	CDBG("%s CSID_IRQ_STATUS_ADDR = 0x%x\n", __func__, irq);
-	msm_io_w(irq, csidbase + CSID_IRQ_CLEAR_CMD_ADDR);
-	return IRQ_HANDLED;
-}
-#endif
-
-static int msm_camio_enable_v2_clks(void)
-{
-	int rc = 0;
-	csid_hw_version = msm_io_r(csidbase +
-				CSID_HW_VERSION_ADDR);
-	CDBG("%s csid_hw_version %d\n",
-		__func__,
-		csid_hw_version);
-
-	if (csid_hw_version == CSID_VERSION_V2) {
-		rc = msm_camio_clk_enable(CAMIO_CSI_PIX1_CLK);
-		if (rc < 0)
-			goto csi_pix1_fail;
-
-		rc = msm_camio_clk_enable(CAMIO_CSI_RDI1_CLK);
-		if (rc < 0)
-			goto csi_rdi1_fail;
-
-		rc = msm_camio_clk_enable(CAMIO_CSI_RDI2_CLK);
-		if (rc < 0)
-			goto csi_rdi2_fail;
-	}
-
-	return rc;
-
-csi_rdi2_fail:
-	msm_camio_clk_disable(CAMIO_CSI_RDI1_CLK);
-csi_rdi1_fail:
-	msm_camio_clk_disable(CAMIO_CSI_PIX1_CLK);
-csi_pix1_fail:
-	return rc;
-}
-
 static int msm_camio_enable_all_clks(uint8_t csid_core)
 {
 	int rc = 0;
 
-	rc = msm_camio_clk_enable(CAMIO_CSI_SRC_CLK);
-	if (rc < 0)
-		goto csi_src_fail;
-	if (csid_core == 1) {
-		rc = msm_camio_clk_enable(CAMIO_CSI1_SRC_CLK);
-		if (rc < 0)
-			goto csi1_src_fail;
-	}
-	rc = msm_camio_clk_enable(CAMIO_CSI0_CLK);
-	if (rc < 0)
-		goto csi0_fail;
-	rc = msm_camio_clk_enable(CAMIO_CSI0_PHY_CLK);
-	if (rc < 0)
-		goto csi0_phy_fail;
-
-	rc = msm_camio_clk_enable(CAMIO_CSI0_PCLK);
-	if (rc < 0)
-		goto csi0p_fail;
-
 	rc = msm_camio_clk_enable(CAMIO_VFE_CLK);
 	if (rc < 0)
 		goto vfe_fail;
@@ -760,42 +611,16 @@
 vfep_fail:
 	msm_camio_clk_disable(CAMIO_VFE_CLK);
 vfe_fail:
-	msm_camio_clk_disable(CAMIO_CSI0_PCLK);
-csi0p_fail:
-	msm_camio_clk_disable(CAMIO_CSI0_PHY_CLK);
-csi0_phy_fail:
-	msm_camio_clk_disable(CAMIO_CSI0_CLK);
-csi0_fail:
-	msm_camio_clk_disable(CAMIO_CSI1_SRC_CLK);
-csi1_src_fail:
-	msm_camio_clk_disable(CAMIO_CSI_SRC_CLK);
-csi_src_fail:
 	return rc;
 }
 
-static void msm_camio_disable_v2_clks(void)
-{
-	if (csid_hw_version == CSID_VERSION_V2) {
-		msm_camio_clk_disable(CAMIO_CSI_RDI2_CLK);
-		msm_camio_clk_disable(CAMIO_CSI_RDI1_CLK);
-		msm_camio_clk_disable(CAMIO_CSI_PIX1_CLK);
-	}
-}
-
 static void msm_camio_disable_all_clks(uint8_t csid_core)
 {
-	msm_camio_disable_v2_clks();
 	msm_camio_clk_disable(CAMIO_CSI_RDI_CLK);
 	msm_camio_clk_disable(CAMIO_CSI_PIX_CLK);
 	msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
 	msm_camio_clk_disable(CAMIO_VFE_PCLK);
 	msm_camio_clk_disable(CAMIO_VFE_CLK);
-	msm_camio_clk_disable(CAMIO_CSI0_PCLK);
-	msm_camio_clk_disable(CAMIO_CSI0_PHY_CLK);
-	msm_camio_clk_disable(CAMIO_CSI0_CLK);
-	if (csid_core == 1)
-		msm_camio_clk_disable(CAMIO_CSI1_SRC_CLK);
-	msm_camio_clk_disable(CAMIO_CSI_SRC_CLK);
 }
 
 int msm_camio_jpeg_clk_disable(void)
@@ -915,11 +740,6 @@
 	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
 	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
 	uint8_t csid_core = camdev->csid_core;
-	char csid[] = "csid0";
-	if (csid_core < 0 || csid_core > 2)
-		return -ENODEV;
-
-	csid[4] = '0' + csid_core;
 
 	camio_dev = pdev;
 	camio_clk = camdev->ioclk;
@@ -927,48 +747,12 @@
 
 	rc = msm_camio_enable_all_clks(csid_core);
 	if (rc < 0)
-		return rc;
-
-	csid_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, csid);
-	if (!csid_mem) {
-		pr_err("%s: no mem resource?\n", __func__);
-		return -ENODEV;
-	}
-	csid_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, csid);
-	if (!csid_irq) {
-		pr_err("%s: no irq resource?\n", __func__);
-		return -ENODEV;
-	}
-
-	csidio = request_mem_region(csid_mem->start,
-		resource_size(csid_mem), pdev->name);
-	if (!csidio) {
-		rc = -EBUSY;
 		goto common_fail;
-	}
-	csidbase = ioremap(csid_mem->start,
-		resource_size(csid_mem));
-	if (!csidbase) {
-		rc = -ENOMEM;
-		goto csi_busy;
-	}
-#if DBG_CSID
-	rc = request_irq(csid_irq->start, msm_io_csi_irq,
-		IRQF_TRIGGER_RISING, "csid", 0);
-	if (rc < 0)
-		goto csi_irq_fail;
-#endif
-	msm_camio_enable_v2_clks();
+
 	CDBG("camio enable done\n");
 	return 0;
-#if DBG_CSID
-csi_irq_fail:
-	iounmap(csidbase);
-#endif
-csi_busy:
-	release_mem_region(csid_mem->start, resource_size(csid_mem));
+
 common_fail:
-	msm_camio_disable_all_clks(csid_core);
 	msm_camera_vreg_disable();
 	config_gpio_table(0);
 	return rc;
@@ -979,12 +763,6 @@
 	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
 	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
 	uint8_t csid_core = camdev->csid_core;
-#if DBG_CSID
-	free_irq(csid_irq->start, 0);
-#endif
-	iounmap(csidbase);
-	release_mem_region(csid_mem->start, resource_size(csid_mem));
-
 	msm_camio_disable_all_clks(csid_core);
 }
 
@@ -1135,55 +913,6 @@
 	return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
 }
 
-int msm_camio_csid_cid_lut(struct msm_camera_csid_lut_params *csid_lut_params)
-{
-	int rc = 0, i = 0;
-	uint32_t val = 0;
-
-	for (i = 0; i < csid_lut_params->num_cid && i < 4; i++)	{
-		if (csid_lut_params->vc_cfg[i].dt < 0x12 ||
-			csid_lut_params->vc_cfg[i].dt > 0x37) {
-			CDBG("%s: unsupported data type 0x%x\n",
-				 __func__, csid_lut_params->vc_cfg[i].dt);
-			return rc;
-		}
-		val = msm_io_r(csidbase + CSID_CID_LUT_VC_0_ADDR +
-		(csid_lut_params->vc_cfg[i].cid >> 2) * 4)
-		& ~(0xFF << csid_lut_params->vc_cfg[i].cid * 8);
-		val |= csid_lut_params->vc_cfg[i].dt <<
-			csid_lut_params->vc_cfg[i].cid * 8;
-		msm_io_w(val, csidbase + CSID_CID_LUT_VC_0_ADDR +
-			(csid_lut_params->vc_cfg[i].cid >> 2) * 4);
-		val = csid_lut_params->vc_cfg[i].decode_format << 4 | 0x3;
-		msm_io_w(val, csidbase + CSID_CID_n_CFG_ADDR +
-			(csid_lut_params->vc_cfg[i].cid * 4));
-	}
-	return rc;
-}
-
-int msm_camio_csid_config(struct msm_camera_csid_params *csid_params)
-{
-	int rc = 0;
-	uint32_t val = 0;
-	val = csid_params->lane_cnt - 1;
-	val |= csid_params->lane_assign << 2;
-	val |= 0x1 << 10;
-	val |= 0x1 << 11;
-	val |= 0x1 << 12;
-	val |= 0x1 << 28;
-	msm_io_w(val, csidbase + CSID_CORE_CTRL_ADDR);
-
-	rc = msm_camio_csid_cid_lut(&csid_params->lut_params);
-	if (rc < 0)
-		return rc;
-
-	msm_io_w(0x7fF10800, csidbase + CSID_IRQ_MASK_ADDR);
-	msm_io_w(0x7fF10800, csidbase + CSID_IRQ_CLEAR_CMD_ADDR);
-
-	msleep(20);
-	return rc;
-}
-
 void msm_camio_mode_config(enum msm_cam_mode mode)
 {
 	uint32_t val;
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 1a5b14c..406dbae 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -28,6 +28,7 @@
 #include <linux/android_pmem.h>
 
 #include "msm.h"
+#include "msm_csid.h"
 #include "msm_csiphy.h"
 #include "msm_ispif.h"
 
@@ -224,6 +225,10 @@
 		rc = v4l2_subdev_call(p_mctl->csiphy_sdev,
 			core, ioctl, VIDIOC_MSM_CSIPHY_CFG, arg);
 		break;
+	case NOTIFY_CSID_CFG:
+		rc = v4l2_subdev_call(p_mctl->csid_sdev,
+			core, ioctl, VIDIOC_MSM_CSID_CFG, arg);
+		break;
 	default:
 		break;
 	}
@@ -349,6 +354,19 @@
 	p_mctl->csiphy_sdev = dev_get_drvdata(dev);
 	put_driver(driver);
 
+	/* register csid subdev */
+	driver = driver_find(MSM_CSID_DRV_NAME, &platform_bus_type);
+	if (!driver)
+		goto out;
+
+	dev = driver_find_device(driver, NULL, (void *)core_index,
+				msm_mctl_subdev_match_core);
+	if (!dev)
+		goto out_put_driver;
+
+	p_mctl->csid_sdev = dev_get_drvdata(dev);
+	put_driver(driver);
+
 	rc = 0;
 	return rc;
 out_put_driver:
@@ -377,6 +395,7 @@
 	mutex_lock(&sync->lock);
 	/* open sub devices - once only*/
 	if (!sync->opencnt) {
+		uint32_t csid_version;
 		wake_lock(&sync->wake_lock);
 
 		sinfo = sync->pdev->dev.platform_data;
@@ -397,6 +416,22 @@
 			goto msm_open_done;
 		}
 
+		rc = v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
+			VIDIOC_MSM_CSIPHY_INIT, NULL);
+		if (rc < 0) {
+			pr_err("%s: csiphy initialization failed %d\n",
+				__func__, rc);
+			goto msm_open_done;
+		}
+
+		rc = v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
+			VIDIOC_MSM_CSID_INIT, &csid_version);
+		if (rc < 0) {
+			pr_err("%s: csid initialization failed %d\n",
+				__func__, rc);
+			goto msm_open_done;
+		}
+
 		/* ISP first*/
 		if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_open)
 			rc = p_mctl->isp_sdev->isp_open(
@@ -407,14 +442,6 @@
 			goto msm_open_done;
 		}
 
-		rc = v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
-			VIDIOC_MSM_CSIPHY_INIT, NULL);
-		if (rc < 0) {
-			pr_err("%s: csiphy initialization failed %d\n",
-				__func__, rc);
-			goto msm_open_done;
-		}
-
 		/*This has to be after isp_open, because isp_open initialize
 		 *platform resource. This dependency needs to be removed. */
 		rc = msm_ispif_init(&p_mctl->ispif_sdev, sync->pdev);
@@ -454,12 +481,15 @@
 	struct msm_sync *sync = &(p_mctl->sync);
 	msm_ispif_release(p_mctl->ispif_sdev);
 
-	v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
-		VIDIOC_MSM_CSIPHY_RELEASE, NULL);
-
 	if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
 		p_mctl->isp_sdev->isp_release(&p_mctl->sync);
 
+	v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
+		VIDIOC_MSM_CSID_RELEASE, NULL);
+
+	v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
+		VIDIOC_MSM_CSIPHY_RELEASE, NULL);
+
 	if (p_mctl->sync.actctrl.a_power_down)
 		p_mctl->sync.actctrl.a_power_down();
 
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index c31e750..76ade6c 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -238,7 +238,8 @@
 		msm_sensor_write_res_settings(s_ctrl, res);
 		if (s_ctrl->curr_csi_params != s_ctrl->csi_params[res]) {
 			s_ctrl->curr_csi_params = s_ctrl->csi_params[res];
-			rc = msm_camio_csid_config(
+			v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+				NOTIFY_CSID_CFG,
 				&s_ctrl->curr_csi_params->csid_params);
 			v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
 						NOTIFY_CID_CHANGE, NULL);