Merge "msm: camera: Convert CSIPHY into platform device" into msm-3.0
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 3636963..41f8879 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -1419,6 +1419,9 @@
 		msm_get_cam_resources(s_info);
 		platform_device_register(cam_dev[i]);
 	}
+
+	platform_device_register(&msm8960_device_csiphy0);
+	platform_device_register(&msm8960_device_csiphy1);
 }
 #endif
 
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 60ddc52..5cc2d1b 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5396,9 +5396,12 @@
 	CLK_LOOKUP("csi_phy_clk",	csi1_phy_clk.c,	"msm_camera_ov2720.0"),
 	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", csiphy_timer_src_clk.c, NULL),
-	CLK_LOOKUP("csi0phy_timer_clk",	csi0phy_timer_clk.c,	NULL),
-	CLK_LOOKUP("csi1phy_timer_clk",	csi1phy_timer_clk.c,	NULL),
+	CLK_LOOKUP("csiphy_timer_src_clk",
+			   csiphy_timer_src_clk.c, "msm_csiphy.0"),
+	CLK_LOOKUP("csiphy_timer_src_clk",
+			   csiphy_timer_src_clk.c, "msm_csiphy.1"),
+	CLK_LOOKUP("csiphy_timer_clk",	csi0phy_timer_clk.c,	"msm_csiphy.0"),
+	CLK_LOOKUP("csiphy_timer_clk",	csi1phy_timer_clk.c,	"msm_csiphy.1"),
 	CLK_LOOKUP("dsi_byte_div_clk",	dsi1_byte_clk.c,	NULL),
 	CLK_LOOKUP("dsi_byte_div_clk",	dsi2_byte_clk.c,	NULL),
 	CLK_LOOKUP("dsi_esc_clk",	dsi1_esc_clk.c,		NULL),
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 5d0a13c..d9bf7db 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1035,18 +1035,6 @@
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "csiphy0",
-		.start	= 0x04800C00,
-		.end	= 0x04800C00 + SZ_1K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	{
-		.name	= "csiphy0",
-		.start	= CSIPHY_4LN_IRQ,
-		.end	= CSIPHY_4LN_IRQ,
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
 		.name	= "csid1",
 		.start	= 0x04800400,
 		.end	= 0x04800400 + SZ_1K - 1,
@@ -1059,18 +1047,6 @@
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
-		.name	= "csiphy1",
-		.start	= 0x04801000,
-		.end	= 0x04801000 + SZ_1K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	{
-		.name	= "csiphy1",
-		.start	= MSM8960_CSIPHY_2LN_IRQ,
-		.end	= MSM8960_CSIPHY_2LN_IRQ,
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
 		.name   = "s3d_rw",
 		.start  = 0x008003E0,
 		.end    = 0x008003E0 + SZ_16 - 1,
@@ -1091,6 +1067,50 @@
 	s_info->num_resources = ARRAY_SIZE(msm_camera_resources);
 	return 0;
 }
+
+static struct resource msm_csiphy0_resources[] = {
+	{
+		.name	= "csiphy",
+		.start	= 0x04800C00,
+		.end	= 0x04800C00 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "csiphy",
+		.start	= CSIPHY_4LN_IRQ,
+		.end	= CSIPHY_4LN_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_csiphy1_resources[] = {
+	{
+		.name	= "csiphy",
+		.start	= 0x04801000,
+		.end	= 0x04801000 + SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "csiphy",
+		.start	= MSM8960_CSIPHY_2LN_IRQ,
+		.end	= MSM8960_CSIPHY_2LN_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_device_csiphy0 = {
+	.name           = "msm_csiphy",
+	.id             = 0,
+	.resource       = msm_csiphy0_resources,
+	.num_resources  = ARRAY_SIZE(msm_csiphy0_resources),
+};
+
+struct platform_device msm8960_device_csiphy1 = {
+	.name           = "msm_csiphy",
+	.id             = 1,
+	.resource       = msm_csiphy1_resources,
+	.num_resources  = ARRAY_SIZE(msm_csiphy1_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 4af3e68..b706fcd 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -58,6 +58,8 @@
 extern struct platform_device msm8960_device_qup_i2c_gsbi12;
 extern struct platform_device msm8960_device_qup_spi_gsbi1;
 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 apq8064_device_uart_gsbi1;
 extern struct platform_device apq8064_device_uart_gsbi3;
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 59c4cab..d0cf567 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -4,8 +4,9 @@
 endif
 
 ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
+  EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
   obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
-  obj-$(CONFIG_MSM_CAMERA) += io/ sensors/ actuators/
+  obj-$(CONFIG_MSM_CAMERA) += io/ sensors/ actuators/ csi/
 else
   obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
 endif
diff --git a/drivers/media/video/msm/csi/Makefile b/drivers/media/video/msm/csi/Makefile
new file mode 100644
index 0000000..4ec67e6
--- /dev/null
+++ b/drivers/media/video/msm/csi/Makefile
@@ -0,0 +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
diff --git a/drivers/media/video/msm/csi/msm_csiphy.c b/drivers/media/video/msm/csi/msm_csiphy.c
new file mode 100644
index 0000000..b62ec84
--- /dev/null
+++ b/drivers/media/video/msm/csi/msm_csiphy.c
@@ -0,0 +1,312 @@
+/* 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 <mach/vreg.h>
+#include <media/msm_isp.h>
+#include "msm_csiphy.h"
+#include "msm.h"
+
+#define DBG_CSIPHY 0
+
+#define V4L2_IDENT_CSIPHY                        50003
+
+/*MIPI CSI PHY registers*/
+#define MIPI_CSIPHY_LNn_CFG1_ADDR                0x0
+#define MIPI_CSIPHY_LNn_CFG2_ADDR                0x4
+#define MIPI_CSIPHY_LNn_CFG3_ADDR                0x8
+#define MIPI_CSIPHY_LNn_CFG4_ADDR                0xC
+#define MIPI_CSIPHY_LNn_CFG5_ADDR                0x10
+#define MIPI_CSIPHY_LNCK_CFG1_ADDR               0x100
+#define MIPI_CSIPHY_LNCK_CFG2_ADDR               0x104
+#define MIPI_CSIPHY_LNCK_CFG3_ADDR               0x108
+#define MIPI_CSIPHY_LNCK_CFG4_ADDR               0x10C
+#define MIPI_CSIPHY_LNCK_CFG5_ADDR               0x110
+#define MIPI_CSIPHY_LNCK_MISC1_ADDR              0x128
+#define MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR        0x1E0
+#define MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR           0x1E8
+#define MIPI_CSIPHY_GLBL_PWR_CFG_ADDR           0x0144
+#define MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR      0x0180
+#define MIPI_CSIPHY_INTERRUPT_STATUS1_ADDR      0x0184
+#define MIPI_CSIPHY_INTERRUPT_STATUS2_ADDR      0x0188
+#define MIPI_CSIPHY_INTERRUPT_STATUS3_ADDR      0x018C
+#define MIPI_CSIPHY_INTERRUPT_STATUS4_ADDR      0x0190
+#define MIPI_CSIPHY_INTERRUPT_MASK0_ADDR        0x01A0
+#define MIPI_CSIPHY_INTERRUPT_MASK1_ADDR        0x01A4
+#define MIPI_CSIPHY_INTERRUPT_MASK2_ADDR        0x01A8
+#define MIPI_CSIPHY_INTERRUPT_MASK3_ADDR        0x01AC
+#define MIPI_CSIPHY_INTERRUPT_MASK4_ADDR        0x01B0
+#define MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR       0x01C0
+#define MIPI_CSIPHY_INTERRUPT_CLEAR1_ADDR       0x01C4
+#define MIPI_CSIPHY_INTERRUPT_CLEAR2_ADDR       0x01C8
+#define MIPI_CSIPHY_INTERRUPT_CLEAR3_ADDR       0x01CC
+#define MIPI_CSIPHY_INTERRUPT_CLEAR4_ADDR       0x01D0
+
+int msm_csiphy_config(struct csiphy_cfg_params *cfg_params)
+{
+	int rc = 0;
+	int i = 0;
+	uint32_t val = 0;
+	struct csiphy_device *csiphy_dev;
+	struct msm_camera_csiphy_params *csiphy_params;
+	void __iomem *csiphybase;
+	csiphy_dev = v4l2_get_subdevdata(cfg_params->subdev);
+	csiphybase = csiphy_dev->base;
+	csiphy_params = cfg_params->parms;
+	if (csiphy_params->lane_cnt < 1 || csiphy_params->lane_cnt > 4) {
+		CDBG("%s: unsupported lane cnt %d\n",
+			__func__, csiphy_params->lane_cnt);
+		return rc;
+	}
+
+	val = 0x3;
+	msm_io_w((((1 << csiphy_params->lane_cnt) - 1) << 2) | val,
+			 csiphybase + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR);
+	msm_io_w(0x1, csiphybase + MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR);
+	msm_io_w(0x1, csiphybase + MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR);
+
+	for (i = 0; i < csiphy_params->lane_cnt; i++) {
+		msm_io_w(0x10, csiphybase + MIPI_CSIPHY_LNn_CFG1_ADDR + 0x40*i);
+		msm_io_w(0x5F, csiphybase + MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i);
+		msm_io_w(csiphy_params->settle_cnt,
+			csiphybase + MIPI_CSIPHY_LNn_CFG3_ADDR + 0x40*i);
+		msm_io_w(0x00000052,
+			csiphybase + MIPI_CSIPHY_LNn_CFG5_ADDR + 0x40*i);
+	}
+
+	msm_io_w(0x00000000, csiphybase + MIPI_CSIPHY_LNCK_CFG1_ADDR);
+	msm_io_w(0x5F, csiphybase + MIPI_CSIPHY_LNCK_CFG2_ADDR);
+	msm_io_w(csiphy_params->settle_cnt,
+			 csiphybase + MIPI_CSIPHY_LNCK_CFG3_ADDR);
+	msm_io_w(0x5, csiphybase + MIPI_CSIPHY_LNCK_CFG4_ADDR);
+	msm_io_w(0x2, csiphybase + MIPI_CSIPHY_LNCK_CFG5_ADDR);
+	msm_io_w(0x0, csiphybase + 0x128);
+
+	msm_io_w(0x24,
+		csiphybase + MIPI_CSIPHY_INTERRUPT_MASK0_ADDR);
+	msm_io_w(0x24,
+		csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR);
+
+	for (i = 1; i <= csiphy_params->lane_cnt; i++) {
+		msm_io_w(0x6F,
+			csiphybase + MIPI_CSIPHY_INTERRUPT_MASK0_ADDR + 0x4*i);
+		msm_io_w(0x6F,
+			csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR + 0x4*i);
+	}
+	return rc;
+}
+
+static irqreturn_t msm_csiphy_irq(int irq_num, void *data)
+{
+	uint32_t irq;
+	struct csiphy_device *csiphy_dev = data;
+	irq = msm_io_r(csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR);
+	msm_io_w(irq, csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR);
+	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS0 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS1_ADDR);
+	msm_io_w(irq, csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR1_ADDR);
+	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS1 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS2_ADDR);
+	msm_io_w(irq, csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR2_ADDR);
+	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS2 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS3_ADDR);
+	msm_io_w(irq, csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR3_ADDR);
+	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS3 = 0x%x\n", __func__, irq);
+	irq = msm_io_r(csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_STATUS4_ADDR);
+	msm_io_w(irq, csiphy_dev->base + MIPI_CSIPHY_INTERRUPT_CLEAR4_ADDR);
+	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS4 = 0x%x\n", __func__, irq);
+	msm_io_w(0x1, csiphy_dev->base + 0x164);
+	msm_io_w(0x0, csiphy_dev->base + 0x164);
+	return IRQ_HANDLED;
+}
+
+static int msm_csiphy_subdev_g_chip_ident(struct v4l2_subdev *sd,
+			struct v4l2_dbg_chip_ident *chip)
+{
+	BUG_ON(!chip);
+	chip->ident = V4L2_IDENT_CSIPHY;
+	chip->revision = 0;
+	return 0;
+}
+
+static struct msm_cam_clk_info csiphy_clk_info[] = {
+	{"csiphy_timer_src_clk", 177780000},
+	{"csiphy_timer_clk", -1},
+};
+
+static int msm_csiphy_init(struct v4l2_subdev *sd)
+{
+	int rc = 0;
+	struct csiphy_device *csiphy_dev;
+	csiphy_dev = v4l2_get_subdevdata(sd);
+	if (csiphy_dev == NULL) {
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	csiphy_dev->base = ioremap(csiphy_dev->mem->start,
+		resource_size(csiphy_dev->mem));
+	if (!csiphy_dev->base) {
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev, csiphy_clk_info,
+			csiphy_dev->csiphy_clk, ARRAY_SIZE(csiphy_clk_info), 1);
+
+	if (rc < 0) {
+		iounmap(csiphy_dev->base);
+		return rc;
+	}
+
+#if DBG_CSIPHY
+	enable_irq(csiphy_dev->irq->start);
+#endif
+
+	return 0;
+}
+
+static int msm_csiphy_release(struct v4l2_subdev *sd)
+{
+	struct csiphy_device *csiphy_dev;
+	int i;
+	csiphy_dev = v4l2_get_subdevdata(sd);
+	for (i = 0; i < 4; i++)
+		msm_io_w(0x0, csiphy_dev->base +
+		MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i);
+
+	msm_io_w(0x0, csiphy_dev->base + MIPI_CSIPHY_LNCK_CFG2_ADDR);
+	msm_io_w(0x0, csiphy_dev->base + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR);
+
+	msm_cam_clk_enable(&csiphy_dev->pdev->dev, csiphy_clk_info,
+		csiphy_dev->csiphy_clk, ARRAY_SIZE(csiphy_clk_info), 0);
+
+#if DBG_CSIPHY
+	disable_irq(csiphy_dev->irq->start);
+#endif
+	iounmap(csiphy_dev->base);
+	return 0;
+}
+
+static long msm_csiphy_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	struct csiphy_cfg_params cfg_params;
+	switch (cmd) {
+	case VIDIOC_MSM_CSIPHY_CFG:
+		cfg_params.subdev = sd;
+		cfg_params.parms = arg;
+		return msm_csiphy_config(
+			(struct csiphy_cfg_params *)&cfg_params);
+	case VIDIOC_MSM_CSIPHY_INIT:
+		return msm_csiphy_init(sd);
+	case VIDIOC_MSM_CSIPHY_RELEASE:
+		return msm_csiphy_release(sd);
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static struct v4l2_subdev_core_ops msm_csiphy_subdev_core_ops = {
+	.g_chip_ident = &msm_csiphy_subdev_g_chip_ident,
+	.ioctl = &msm_csiphy_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_csiphy_subdev_ops = {
+	.core = &msm_csiphy_subdev_core_ops,
+};
+
+static int __devinit csiphy_probe(struct platform_device *pdev)
+{
+	struct csiphy_device *new_csiphy_dev;
+	int rc = 0;
+	CDBG("%s: device id = %d\n", __func__, pdev->id);
+	new_csiphy_dev = kzalloc(sizeof(struct csiphy_device), GFP_KERNEL);
+	if (!new_csiphy_dev) {
+		pr_err("%s: no enough memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	v4l2_subdev_init(&new_csiphy_dev->subdev, &msm_csiphy_subdev_ops);
+	v4l2_set_subdevdata(&new_csiphy_dev->subdev, new_csiphy_dev);
+	platform_set_drvdata(pdev, &new_csiphy_dev->subdev);
+
+	mutex_init(&new_csiphy_dev->mutex);
+
+	new_csiphy_dev->mem = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "csiphy");
+	if (!new_csiphy_dev->mem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		rc = -ENODEV;
+		goto csiphy_no_resource;
+	}
+	new_csiphy_dev->irq = platform_get_resource_byname(pdev,
+					IORESOURCE_IRQ, "csiphy");
+	if (!new_csiphy_dev->irq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		rc = -ENODEV;
+		goto csiphy_no_resource;
+	}
+	new_csiphy_dev->io = request_mem_region(new_csiphy_dev->mem->start,
+		resource_size(new_csiphy_dev->mem), pdev->name);
+	if (!new_csiphy_dev->io) {
+		pr_err("%s: no valid mem region\n", __func__);
+		rc = -EBUSY;
+		goto csiphy_no_resource;
+	}
+
+	rc = request_irq(new_csiphy_dev->irq->start, msm_csiphy_irq,
+		IRQF_TRIGGER_RISING, "csiphy", new_csiphy_dev);
+	if (rc < 0) {
+		release_mem_region(new_csiphy_dev->mem->start,
+			resource_size(new_csiphy_dev->mem));
+		pr_err("%s: irq request fail\n", __func__);
+		rc = -EBUSY;
+		goto csiphy_no_resource;
+	}
+	disable_irq(new_csiphy_dev->irq->start);
+
+	new_csiphy_dev->pdev = pdev;
+	return 0;
+
+csiphy_no_resource:
+	mutex_destroy(&new_csiphy_dev->mutex);
+	kfree(new_csiphy_dev);
+	return 0;
+}
+
+static struct platform_driver csiphy_driver = {
+	.probe = csiphy_probe,
+	.driver = {
+		.name = MSM_CSIPHY_DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_csiphy_init_module(void)
+{
+	return platform_driver_register(&csiphy_driver);
+}
+
+static void __exit msm_csiphy_exit_module(void)
+{
+	platform_driver_unregister(&csiphy_driver);
+}
+
+module_init(msm_csiphy_init_module);
+module_exit(msm_csiphy_exit_module);
+MODULE_DESCRIPTION("MSM CSIPHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/csi/msm_csiphy.h b/drivers/media/video/msm/csi/msm_csiphy.h
new file mode 100644
index 0000000..522a1c1
--- /dev/null
+++ b/drivers/media/video/msm/csi/msm_csiphy.h
@@ -0,0 +1,46 @@
+/* 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_CSIPHY_H
+#define MSM_CSIPHY_H
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <media/v4l2-subdev.h>
+
+struct csiphy_device {
+	struct platform_device *pdev;
+	struct v4l2_subdev subdev;
+	struct resource *mem;
+	struct resource *irq;
+	struct resource *io;
+	void __iomem *base;
+	struct mutex mutex;
+
+	struct clk *csiphy_clk[2];
+};
+
+struct csiphy_cfg_params {
+	struct v4l2_subdev *subdev;
+	void *parms;
+};
+
+#define VIDIOC_MSM_CSIPHY_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct csiphy_cfg_params)
+
+#define VIDIOC_MSM_CSIPHY_INIT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct v4l2_subdev*)
+
+#define VIDIOC_MSM_CSIPHY_RELEASE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct v4l2_subdev*)
+
+#endif
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index f9cf5de..ef6d684 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -41,6 +41,8 @@
 #define ERR_COPY_FROM_USER() ERR_USER_COPY(0)
 #define ERR_COPY_TO_USER() ERR_USER_COPY(1)
 
+#define MSM_CSIPHY_DRV_NAME "msm_csiphy"
+
 /* msm queue management APIs*/
 
 #define msm_dequeue(queue, member) ({	   \
@@ -113,6 +115,7 @@
 	NOTIFY_ISPIF_STREAM, /* arg = enable parameter for s_stream */
 	NOTIFY_VPE_MSG_EVT,
 	NOTIFY_PCLK_CHANGE, /* arg = pclk */
+	NOTIFY_CSIPHY_CFG, /* arg = msm_camera_csiphy_params */
 	NOTIFY_INVALID
 };
 
@@ -215,6 +218,7 @@
 	struct v4l2_subdev *vpe_sdev;    /* vpe sub device : VPE */
 	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 *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 0e4429e..65bf3ad 100644
--- a/drivers/media/video/msm/msm_io_8960.c
+++ b/drivers/media/video/msm/msm_io_8960.c
@@ -26,40 +26,8 @@
 #include <mach/msm_bus_board.h>
 
 #define DBG_CSID 0
-#define DBG_CSIPHY 0
 #define BUFF_SIZE_128 128
 
-/* MIPI	CSI	PHY registers */
-#define MIPI_CSIPHY_LNn_CFG1_ADDR                0x0
-#define MIPI_CSIPHY_LNn_CFG2_ADDR                0x4
-#define MIPI_CSIPHY_LNn_CFG3_ADDR                0x8
-#define MIPI_CSIPHY_LNn_CFG4_ADDR                0xC
-#define MIPI_CSIPHY_LNn_CFG5_ADDR                0x10
-#define MIPI_CSIPHY_LNCK_CFG1_ADDR               0x100
-#define MIPI_CSIPHY_LNCK_CFG2_ADDR               0x104
-#define MIPI_CSIPHY_LNCK_CFG3_ADDR               0x108
-#define MIPI_CSIPHY_LNCK_CFG4_ADDR               0x10C
-#define MIPI_CSIPHY_LNCK_CFG5_ADDR               0x110
-#define MIPI_CSIPHY_LNCK_MISC1_ADDR              0x128
-#define MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR        0x1E0
-#define MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR           0x1E8
-#define MIPI_CSIPHY_GLBL_PWR_CFG_ADDR           0x0144
-#define MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR      0x0180
-#define MIPI_CSIPHY_INTERRUPT_STATUS1_ADDR      0x0184
-#define MIPI_CSIPHY_INTERRUPT_STATUS2_ADDR      0x0188
-#define MIPI_CSIPHY_INTERRUPT_STATUS3_ADDR      0x018C
-#define MIPI_CSIPHY_INTERRUPT_STATUS4_ADDR      0x0190
-#define MIPI_CSIPHY_INTERRUPT_MASK0_ADDR        0x01A0
-#define MIPI_CSIPHY_INTERRUPT_MASK1_ADDR        0x01A4
-#define MIPI_CSIPHY_INTERRUPT_MASK2_ADDR        0x01A8
-#define MIPI_CSIPHY_INTERRUPT_MASK3_ADDR        0x01AC
-#define MIPI_CSIPHY_INTERRUPT_MASK4_ADDR        0x01B0
-#define MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR       0x01C0
-#define MIPI_CSIPHY_INTERRUPT_CLEAR1_ADDR       0x01C4
-#define MIPI_CSIPHY_INTERRUPT_CLEAR2_ADDR       0x01C8
-#define MIPI_CSIPHY_INTERRUPT_CLEAR3_ADDR       0x01CC
-#define MIPI_CSIPHY_INTERRUPT_CLEAR4_ADDR       0x01D0
-
 /* MIPI	CSID registers */
 #define CSID_HW_VERSION_ADDR                    0x0
 #define CSID_CORE_CTRL_ADDR                     0x4
@@ -122,11 +90,8 @@
 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_csiphy0_timer_clk;
-static struct clk *camio_csiphy1_timer_clk;
 static struct clk *camio_vfe_pclk;
 static struct clk *camio_csi0_phy_clk;
-static struct clk *camio_csiphy_timer_src_clk;
 
 /*static struct clk *camio_vfe_pclk;*/
 static struct clk *camio_jpeg_clk;
@@ -144,10 +109,10 @@
 
 static struct msm_camera_io_clk camio_clk;
 static struct platform_device *camio_dev;
-static struct resource *csidio, *csiphyio, *s3drw_io, *s3dctl_io;
-static struct resource *csid_mem, *csiphy_mem, *s3drw_mem, *s3dctl_mem;
-static struct resource *csid_irq, *csiphy_irq;
-void __iomem *csidbase, *csiphybase, *s3d_rw, *s3d_ctl;
+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;
 struct msm_bus_scale_pdata *cam_bus_scale_table;
 
 
@@ -533,22 +498,6 @@
 		msm_camio_clk_rate_set_2(clk, csid_core);
 		break;
 
-	case CAMIO_CSIPHY0_TIMER_CLK:
-		camio_csiphy0_timer_clk =
-		clk = clk_get(NULL, "csi0phy_timer_clk");
-		break;
-
-	case CAMIO_CSIPHY1_TIMER_CLK:
-		camio_csiphy1_timer_clk =
-		clk = clk_get(NULL, "csi1phy_timer_clk");
-		break;
-
-	case CAMIO_CSIPHY_TIMER_SRC_CLK:
-		camio_csiphy_timer_src_clk =
-		clk = clk_get(NULL, "csiphy_timer_src_clk");
-		msm_camio_clk_rate_set_2(clk, 177780000);
-		break;
-
 	case CAMIO_CSI0_PCLK:
 		camio_csi0_pclk =
 		clk = clk_get(NULL, "csi_pclk");
@@ -645,14 +594,6 @@
 		clk = camio_csi_rdi_clk;
 		break;
 
-	case CAMIO_CSIPHY0_TIMER_CLK:
-		clk = camio_csiphy0_timer_clk;
-		break;
-
-	case CAMIO_CSIPHY_TIMER_SRC_CLK:
-		clk = camio_csiphy_timer_src_clk;
-		break;
-
 	case CAMIO_CSI0_PCLK:
 		clk = camio_csi0_pclk;
 		break;
@@ -735,56 +676,6 @@
 	return IRQ_HANDLED;
 }
 #endif
-/*
-void msm_io_read_interrupt(void)
-{
-	uint32_t irq;
-	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR);
-	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS0 = 0x%x\n", __func__, irq);
-	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR);
-	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS0 = 0x%x\n", __func__, irq);
-	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS1_ADDR);
-	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS1 = 0x%x\n", __func__, irq);
-	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS2_ADDR);
-	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS2 = 0x%x\n", __func__, irq);
-	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS3_ADDR);
-	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS3 = 0x%x\n", __func__, irq);
-	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS4_ADDR);
-	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS4 = 0x%x\n", __func__, irq);
-	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR);
-	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR1_ADDR);
-	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR2_ADDR);
-	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR3_ADDR);
-	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR4_ADDR);
-	msm_io_w(0x1, csiphybase + 0x164);
-	msm_io_w(0x0, csiphybase + 0x164);
-	return;
-}
-*/
-#if DBG_CSIPHY
-static irqreturn_t msm_io_csiphy_irq(int irq_num, void *data)
-{
-	uint32_t irq;
-	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR);
-	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR);
-	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS0 = 0x%x\n", __func__, irq);
-	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS1_ADDR);
-	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR1_ADDR);
-	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS1 = 0x%x\n", __func__, irq);
-	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS2_ADDR);
-	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR2_ADDR);
-	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS2 = 0x%x\n", __func__, irq);
-	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS3_ADDR);
-	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR3_ADDR);
-	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS3 = 0x%x\n", __func__, irq);
-	irq = msm_io_r(csiphybase + MIPI_CSIPHY_INTERRUPT_STATUS4_ADDR);
-	msm_io_w(irq, csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR4_ADDR);
-	CDBG("%s MIPI_CSIPHY_INTERRUPT_STATUS4 = 0x%x\n", __func__, irq);
-	msm_io_w(0x1, csiphybase + 0x164);
-	msm_io_w(0x0, csiphybase + 0x164);
-	return IRQ_HANDLED;
-}
-#endif
 
 static int msm_camio_enable_v2_clks(void)
 {
@@ -837,18 +728,7 @@
 	rc = msm_camio_clk_enable(CAMIO_CSI0_PHY_CLK);
 	if (rc < 0)
 		goto csi0_phy_fail;
-	rc = msm_camio_clk_enable(CAMIO_CSIPHY_TIMER_SRC_CLK);
-	if (rc < 0)
-		goto csiphy_timer_src_fail;
-	if (csid_core == 0) {
-		rc = msm_camio_clk_enable(CAMIO_CSIPHY0_TIMER_CLK);
-		if (rc < 0)
-			goto csiphy0_timer_fail;
-	} else if (csid_core == 1) {
-		rc = msm_camio_clk_enable(CAMIO_CSIPHY1_TIMER_CLK);
-		if (rc < 0)
-			goto csiphy1_timer_fail;
-	}
+
 	rc = msm_camio_clk_enable(CAMIO_CSI0_PCLK);
 	if (rc < 0)
 		goto csi0p_fail;
@@ -882,12 +762,6 @@
 vfe_fail:
 	msm_camio_clk_disable(CAMIO_CSI0_PCLK);
 csi0p_fail:
-	msm_camio_clk_disable(CAMIO_CSIPHY0_TIMER_CLK);
-csiphy1_timer_fail:
-	msm_camio_clk_disable(CAMIO_CSIPHY1_TIMER_CLK);
-csiphy0_timer_fail:
-	msm_camio_clk_disable(CAMIO_CSIPHY_TIMER_SRC_CLK);
-csiphy_timer_src_fail:
 	msm_camio_clk_disable(CAMIO_CSI0_PHY_CLK);
 csi0_phy_fail:
 	msm_camio_clk_disable(CAMIO_CSI0_CLK);
@@ -917,11 +791,6 @@
 	msm_camio_clk_disable(CAMIO_VFE_PCLK);
 	msm_camio_clk_disable(CAMIO_VFE_CLK);
 	msm_camio_clk_disable(CAMIO_CSI0_PCLK);
-	if (csid_core == 0)
-		msm_camio_clk_disable(CAMIO_CSIPHY0_TIMER_CLK);
-	else if (csid_core == 1)
-		msm_camio_clk_disable(CAMIO_CSIPHY1_TIMER_CLK);
-	msm_camio_clk_disable(CAMIO_CSIPHY_TIMER_SRC_CLK);
 	msm_camio_clk_disable(CAMIO_CSI0_PHY_CLK);
 	msm_camio_clk_disable(CAMIO_CSI0_CLK);
 	if (csid_core == 1)
@@ -1047,12 +916,10 @@
 	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
 	uint8_t csid_core = camdev->csid_core;
 	char csid[] = "csid0";
-	char csiphy[] = "csiphy0";
 	if (csid_core < 0 || csid_core > 2)
 		return -ENODEV;
 
 	csid[4] = '0' + csid_core;
-	csiphy[6] = '0' + csid_core;
 
 	camio_dev = pdev;
 	camio_clk = camdev->ioclk;
@@ -1072,16 +939,6 @@
 		pr_err("%s: no irq resource?\n", __func__);
 		return -ENODEV;
 	}
-	csiphy_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, csiphy);
-	if (!csiphy_mem) {
-		pr_err("%s: no mem resource?\n", __func__);
-		return -ENODEV;
-	}
-	csiphy_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, csiphy);
-	if (!csiphy_irq) {
-		pr_err("%s: no irq resource?\n", __func__);
-		return -ENODEV;
-	}
 
 	csidio = request_mem_region(csid_mem->start,
 		resource_size(csid_mem), pdev->name);
@@ -1101,35 +958,13 @@
 	if (rc < 0)
 		goto csi_irq_fail;
 #endif
-	csiphyio = request_mem_region(csiphy_mem->start,
-		resource_size(csiphy_mem), pdev->name);
-	if (!csidio) {
-		rc = -EBUSY;
-		goto csi_irq_fail;
-	}
-	csiphybase = ioremap(csiphy_mem->start,
-		resource_size(csiphy_mem));
-	if (!csiphybase) {
-		rc = -ENOMEM;
-		goto csiphy_busy;
-	}
-#if DBG_CSIPHY
-	rc = request_irq(csiphy_irq->start, msm_io_csiphy_irq,
-		IRQF_TRIGGER_RISING, "csiphy", 0);
-	if (rc < 0)
-		goto csiphy_irq_fail;
-#endif
 	msm_camio_enable_v2_clks();
 	CDBG("camio enable done\n");
 	return 0;
-#if DBG_CSIPHY
-csiphy_irq_fail:
-	iounmap(csiphybase);
-#endif
-csiphy_busy:
-	release_mem_region(csiphy_mem->start, resource_size(csiphy_mem));
+#if DBG_CSID
 csi_irq_fail:
 	iounmap(csidbase);
+#endif
 csi_busy:
 	release_mem_region(csid_mem->start, resource_size(csid_mem));
 common_fail:
@@ -1144,12 +979,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_CSIPHY
-	free_irq(csiphy_irq->start, 0);
-#endif
-	iounmap(csiphybase);
-	release_mem_region(csiphy_mem->start, resource_size(csiphy_mem));
-
 #if DBG_CSID
 	free_irq(csid_irq->start, 0);
 #endif
@@ -1355,54 +1184,6 @@
 	return rc;
 }
 
-int msm_camio_csiphy_config(struct msm_camera_csiphy_params *csiphy_params)
-{
-	int rc = 0;
-	int i = 0;
-	uint32_t val = 0;
-	if (csiphy_params->lane_cnt < 1 || csiphy_params->lane_cnt > 4) {
-		CDBG("%s: unsupported lane cnt %d\n",
-			__func__, csiphy_params->lane_cnt);
-		return rc;
-	}
-
-	val = 0x3;
-	msm_io_w((((1 << csiphy_params->lane_cnt) - 1) << 2) | val,
-			 csiphybase + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR);
-	msm_io_w(0x1, csiphybase + MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR);
-	msm_io_w(0x1, csiphybase + MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR);
-
-	for (i = 0; i < csiphy_params->lane_cnt; i++) {
-		msm_io_w(0x10, csiphybase + MIPI_CSIPHY_LNn_CFG1_ADDR + 0x40*i);
-		msm_io_w(0x5F, csiphybase + MIPI_CSIPHY_LNn_CFG2_ADDR + 0x40*i);
-		msm_io_w(csiphy_params->settle_cnt,
-			csiphybase + MIPI_CSIPHY_LNn_CFG3_ADDR + 0x40*i);
-		msm_io_w(0x00000052,
-			csiphybase + MIPI_CSIPHY_LNn_CFG5_ADDR + 0x40*i);
-	}
-
-	msm_io_w(0x00000000, csiphybase + MIPI_CSIPHY_LNCK_CFG1_ADDR);
-	msm_io_w(0x5F, csiphybase + MIPI_CSIPHY_LNCK_CFG2_ADDR);
-	msm_io_w(csiphy_params->settle_cnt,
-			 csiphybase + MIPI_CSIPHY_LNCK_CFG3_ADDR);
-	msm_io_w(0x5, csiphybase + MIPI_CSIPHY_LNCK_CFG4_ADDR);
-	msm_io_w(0x2, csiphybase + MIPI_CSIPHY_LNCK_CFG5_ADDR);
-	msm_io_w(0x0, csiphybase + 0x128);
-
-	msm_io_w(0x24,
-		csiphybase + MIPI_CSIPHY_INTERRUPT_MASK0_ADDR);
-	msm_io_w(0x24,
-		csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR);
-
-	for (i = 1; i <= csiphy_params->lane_cnt; i++) {
-		msm_io_w(0x6F,
-			csiphybase + MIPI_CSIPHY_INTERRUPT_MASK0_ADDR + 0x4*i);
-		msm_io_w(0x6F,
-			csiphybase + MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR + 0x4*i);
-	}
-	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 a7fe8a2..1a5b14c 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_csiphy.h"
 #include "msm_ispif.h"
 
 #ifdef CONFIG_MSM_CAMERA_DEBUG
@@ -219,6 +220,10 @@
 	case NOTIFY_PCLK_CHANGE:
 		rc = msm_camio_vfe_clk_rate_set(*(uint32_t *)arg);
 		break;
+	case NOTIFY_CSIPHY_CFG:
+		rc = v4l2_subdev_call(p_mctl->csiphy_sdev,
+			core, ioctl, VIDIOC_MSM_CSIPHY_CFG, arg);
+		break;
 	default:
 		break;
 	}
@@ -313,11 +318,53 @@
 	return rc;
 }
 
+static int msm_mctl_subdev_match_core(struct device *dev, void *data)
+{
+	int core_index = (int)data;
+	struct platform_device *pdev = to_platform_device(dev);
+
+	if (pdev->id == core_index)
+		return 1;
+	else
+		return 0;
+}
+
+static int msm_mctl_register_subdevs(struct msm_cam_media_controller *p_mctl,
+	int core_index)
+{
+	struct device_driver *driver;
+	struct device *dev;
+	int rc = -ENODEV;
+
+	/* register csiphy subdev */
+	driver = driver_find(MSM_CSIPHY_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->csiphy_sdev = dev_get_drvdata(dev);
+	put_driver(driver);
+
+	rc = 0;
+	return rc;
+out_put_driver:
+	put_driver(driver);
+out:
+	return rc;
+}
+
 static int msm_mctl_open(struct msm_cam_media_controller *p_mctl,
 				 const char *const apps_id)
 {
 	int rc = 0;
 	struct msm_sync *sync = NULL;
+	struct msm_camera_sensor_info *sinfo;
+	struct msm_camera_device_platform_data *camdev;
+	uint8_t csid_core;
 	D("%s\n", __func__);
 	if (!p_mctl) {
 		pr_err("%s: param is NULL", __func__);
@@ -332,6 +379,16 @@
 	if (!sync->opencnt) {
 		wake_lock(&sync->wake_lock);
 
+		sinfo = sync->pdev->dev.platform_data;
+		camdev = sinfo->pdata;
+		csid_core = camdev->csid_core;
+		rc = msm_mctl_register_subdevs(p_mctl, csid_core);
+		if (rc < 0) {
+			pr_err("%s: msm_mctl_register_subdevs failed:%d\n",
+				__func__, rc);
+			goto msm_open_done;
+		}
+
 		/* turn on clock */
 		rc = msm_camio_sensor_clk_on(sync->pdev);
 		if (rc < 0) {
@@ -350,6 +407,14 @@
 			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);
@@ -385,13 +450,13 @@
 
 static int msm_mctl_release(struct msm_cam_media_controller *p_mctl)
 {
-	struct msm_sync *sync = NULL;
 	int rc = 0;
-
-	sync = &(p_mctl->sync);
-
+	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);
 
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 19cf8c7..c31e750 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -243,7 +243,8 @@
 			v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
 						NOTIFY_CID_CHANGE, NULL);
 			mb();
-			rc = msm_camio_csiphy_config(
+			v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+				NOTIFY_CSIPHY_CFG,
 				&s_ctrl->curr_csi_params->csiphy_params);
 			mb();
 			msleep(20);