msm: camera: Convert VFE into platform device

Make VFE 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: I91a7144794505af23a6f32de58f1c7cc340f4882
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 892921a..a7cc933 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -1425,6 +1425,7 @@
 	platform_device_register(&msm8960_device_csid0);
 	platform_device_register(&msm8960_device_csid1);
 	platform_device_register(&msm8960_device_ispif);
+	platform_device_register(&msm8960_device_vfe);
 }
 #endif
 
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 262c3b7..e85b4ca 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5430,9 +5430,9 @@
 	CLK_LOOKUP("core_clk",		hdmi_app_clk.c,	"hdmi_msm.1"),
 	CLK_LOOKUP("vpe_clk",		vpe_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		vpe_clk.c,	"footswitch-8x60.9"),
-	CLK_LOOKUP("vfe_clk",		vfe_clk.c,		NULL),
+	CLK_LOOKUP("vfe_clk",		vfe_clk.c,		"msm_vfe.0"),
 	CLK_LOOKUP("core_clk",		vfe_clk.c,	"footswitch-8x60.8"),
-	CLK_LOOKUP("csi_vfe_clk",	csi_vfe_clk.c,		NULL),
+	CLK_LOOKUP("csi_vfe_clk",	csi_vfe_clk.c,		"msm_vfe.0"),
 	CLK_LOOKUP("bus_clk",		vfe_axi_clk.c,	"footswitch-8x60.8"),
 	CLK_LOOKUP("bus_clk",		mdp_axi_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("bus_clk",		rot_axi_clk.c,	"footswitch-8x60.6"),
@@ -5467,7 +5467,7 @@
 	CLK_LOOKUP("tv_enc_pclk",	tv_enc_p_clk.c,		NULL),
 	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,	"msm_vidc.0"),
 	CLK_LOOKUP("iface_clk",		vcodec_p_clk.c,	"footswitch-8x60.7"),
-	CLK_LOOKUP("vfe_pclk",		vfe_p_clk.c,		NULL),
+	CLK_LOOKUP("vfe_pclk",		vfe_p_clk.c,		"msm_vfe.0"),
 	CLK_LOOKUP("iface_clk",		vfe_p_clk.c,	"footswitch-8x60.8"),
 	CLK_LOOKUP("vpe_pclk",		vpe_p_clk.c,		NULL),
 	CLK_LOOKUP("iface_clk",		vpe_p_clk.c,	"footswitch-8x60.9"),
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 725e1c2..edaa008 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -983,18 +983,6 @@
 #ifdef CONFIG_MSM_CAMERA
 struct resource msm_camera_resources[] = {
 	{
-		.name	= "vfe",
-		.start	= 0x04500000,
-		.end	= 0x04500000 + SZ_1M - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	{
-		.name	= "vfe",
-		.start	= VFE_IRQ,
-		.end	= VFE_IRQ,
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
 		.name	= "vpe",
 		.start	= 0x05300000,
 		.end	= 0x05300000 + SZ_1M - 1,
@@ -1140,6 +1128,28 @@
 	.resource       = msm_ispif_resources,
 	.num_resources  = ARRAY_SIZE(msm_ispif_resources),
 };
+
+static struct resource msm_vfe_resources[] = {
+	{
+		.name	= "vfe32",
+		.start	= 0x04500000,
+		.end	= 0x04500000 + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "vfe32",
+		.start	= VFE_IRQ,
+		.end	= VFE_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm8960_device_vfe = {
+	.name           = "msm_vfe",
+	.id             = 0,
+	.resource       = msm_vfe_resources,
+	.num_resources  = ARRAY_SIZE(msm_vfe_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 ff3cfce..871a7d3 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -63,6 +63,7 @@
 extern struct platform_device msm8960_device_csid0;
 extern struct platform_device msm8960_device_csid1;
 extern struct platform_device msm8960_device_ispif;
+extern struct platform_device msm8960_device_vfe;
 
 extern struct platform_device apq8064_device_uart_gsbi1;
 extern struct platform_device apq8064_device_uart_gsbi3;
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 8ef0de9..c772e64 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -1473,7 +1473,7 @@
 
 		/* Register isp subdev */
 		rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
-					&pcam->mctl.isp_sdev->sd);
+					pcam->mctl.isp_sdev->sd);
 		if (rc < 0) {
 			mutex_unlock(&pcam->vid_lock);
 			pr_err("%s: v4l2_device_register_subdev failed rc = %d\n",
@@ -1613,7 +1613,7 @@
 	f->private_data = NULL;
 
 	if (pcam->use_count == 0) {
-		v4l2_device_unregister_subdev(&pcam->mctl.isp_sdev->sd);
+		v4l2_device_unregister_subdev(pcam->mctl.isp_sdev->sd);
 		v4l2_device_unregister_subdev(&pcam->mctl.isp_sdev->sd_vpe);
 		rc = msm_cam_server_close_session(&g_server_dev, pcam);
 		if (rc < 0)
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 1409903..563ab56 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -44,6 +44,7 @@
 #define MSM_CSIPHY_DRV_NAME "msm_csiphy"
 #define MSM_CSID_DRV_NAME "msm_csid"
 #define MSM_ISPIF_DRV_NAME "msm_ispif"
+#define MSM_VFE_DRV_NAME "msm_vfe"
 
 /* msm queue management APIs*/
 
@@ -247,7 +248,7 @@
 		 struct msm_mctl_pp_cmd, void *data);
 
 	/* vfe subdevice */
-	struct v4l2_subdev sd;
+	struct v4l2_subdev *sd;
 	struct v4l2_subdev sd_vpe;
 };
 
diff --git a/drivers/media/video/msm/msm_io_8960.c b/drivers/media/video/msm/msm_io_8960.c
index b2b2c2f..a280ab0 100644
--- a/drivers/media/video/msm/msm_io_8960.c
+++ b/drivers/media/video/msm/msm_io_8960.c
@@ -42,16 +42,11 @@
 #define CAM_CSI_LOAD_UA                    20000
 
 static struct clk *camio_cam_clk;
-static struct clk *camio_vfe_clk;
-static struct clk *camio_csi0_vfe_clk;
-static struct clk *camio_vfe_pclk;
 
-/*static struct clk *camio_vfe_pclk;*/
 static struct clk *camio_jpeg_clk;
 static struct clk *camio_jpeg_pclk;
 static struct clk *camio_vpe_clk;
 static struct clk *camio_vpe_pclk;
-static struct regulator *fs_vfe;
 static struct regulator *fs_ijpeg;
 static struct regulator *fs_vpe;
 static struct regulator *cam_vana;
@@ -255,18 +250,6 @@
 			goto cam_vaf_disable;
 		}
 	}
-	if (fs_vfe == NULL) {
-		fs_vfe = regulator_get(&pdev->dev, "fs_vfe");
-		if (IS_ERR(fs_vfe)) {
-			pr_err("%s: Regulator FS_VFE get failed %ld\n",
-				__func__, PTR_ERR(fs_vfe));
-			fs_vfe = NULL;
-		} else if (regulator_enable(fs_vfe)) {
-			pr_err("%s: Regulator FS_VFE enable failed\n",
-							__func__);
-			regulator_put(fs_vfe);
-		}
-	}
 	return 0;
 
 cam_vaf_disable:
@@ -349,12 +332,6 @@
 		regulator_put(cam_vaf);
 		cam_vaf = NULL;
 	}
-
-	if (fs_vfe) {
-		regulator_disable(fs_vfe);
-		regulator_put(fs_vfe);
-		fs_vfe = NULL;
-	}
 }
 
 int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
@@ -369,27 +346,6 @@
 		msm_camio_clk_rate_set_2(clk, camio_clk.mclk_clk_rate);
 		break;
 
-	case CAMIO_VFE_CLK:
-		camio_vfe_clk =
-		clk = clk_get(NULL, "vfe_clk");
-		msm_camio_clk_rate_set_2(clk, camio_clk.vfe_clk_rate);
-		break;
-
-	case CAMIO_VFE_PCLK:
-		camio_vfe_pclk =
-		clk = clk_get(NULL, "vfe_pclk");
-		break;
-
-	case CAMIO_CSI0_VFE_CLK:
-		camio_csi0_vfe_clk =
-		clk = clk_get(NULL, "csi_vfe_clk");
-		break;
-/*
-	case CAMIO_CSI1_VFE_CLK:
-		camio_csi1_vfe_clk =
-		clk = clk_get(&camio_dev->dev, "csi_vfe_clk");
-		break;
-*/
 	case CAMIO_JPEG_CLK:
 		camio_jpeg_clk =
 		clk = clk_get(NULL, "ijpeg_clk");
@@ -437,18 +393,6 @@
 		clk = camio_cam_clk;
 		break;
 
-	case CAMIO_VFE_CLK:
-		clk = camio_vfe_clk;
-		break;
-
-	case CAMIO_VFE_PCLK:
-		clk = camio_vfe_pclk;
-		break;
-
-	case CAMIO_CSI0_VFE_CLK:
-		clk = camio_csi0_vfe_clk;
-		break;
-
 	case CAMIO_JPEG_CLK:
 		clk = camio_jpeg_clk;
 		break;
@@ -481,26 +425,6 @@
 	return rc;
 }
 
-int msm_camio_vfe_clk_rate_set(int rate)
-{
-	int rc = 0;
-	int round_rate;
-	struct clk *clk = camio_vfe_clk;
-	round_rate = clk_round_rate(clk, rate);
-	if (rc < 0) {
-		pr_err("%s: clk_round_rate failed %d\n",
-					__func__, rc);
-		return rc;
-	}
-
-	rc = clk_set_rate(clk, round_rate);
-	if (rc < 0)
-		pr_err("%s: clk_set_rate failed %d\n",
-					__func__, rc);
-
-	return rc;
-}
-
 void msm_camio_clk_rate_set(int rate)
 {
 	struct clk *clk = camio_cam_clk;
@@ -517,37 +441,6 @@
 	clk_set_min_rate(clk, rate);
 }
 
-static int msm_camio_enable_all_clks(uint8_t csid_core)
-{
-	int rc = 0;
-
-	rc = msm_camio_clk_enable(CAMIO_VFE_CLK);
-	if (rc < 0)
-		goto vfe_fail;
-	rc = msm_camio_clk_enable(CAMIO_VFE_PCLK);
-	if (rc < 0)
-		goto vfep_fail;
-
-	rc = msm_camio_clk_enable(CAMIO_CSI0_VFE_CLK);
-	if (rc < 0)
-		goto csi0_vfe_fail;
-
-	return rc;
-csi0_vfe_fail:
-	msm_camio_clk_disable(CAMIO_VFE_PCLK);
-vfep_fail:
-	msm_camio_clk_disable(CAMIO_VFE_CLK);
-vfe_fail:
-	return rc;
-}
-
-static void msm_camio_disable_all_clks(uint8_t csid_core)
-{
-	msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
-	msm_camio_clk_disable(CAMIO_VFE_PCLK);
-	msm_camio_clk_disable(CAMIO_VFE_CLK);
-}
-
 int msm_camio_jpeg_clk_disable(void)
 {
 	int rc = 0;
@@ -659,38 +552,6 @@
 	return rc;
 }
 
-int msm_camio_enable(struct platform_device *pdev)
-{
-	int rc = 0;
-	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;
-
-	camio_dev = pdev;
-	camio_clk = camdev->ioclk;
-	cam_bus_scale_table = camdev->cam_bus_scale_table;
-
-	rc = msm_camio_enable_all_clks(csid_core);
-	if (rc < 0)
-		goto common_fail;
-
-	CDBG("camio enable done\n");
-	return 0;
-
-common_fail:
-	msm_camera_vreg_disable();
-	config_gpio_table(0);
-	return rc;
-}
-
-void msm_camio_disable(struct platform_device *pdev)
-{
-	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;
-	msm_camio_disable_all_clks(csid_core);
-}
-
 int32_t msm_camio_3d_enable(const struct msm_camera_sensor_info *s_info)
 {
 	int32_t val = 0, rc = 0;
@@ -858,9 +719,13 @@
 void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
 {
 	static uint32_t bus_perf_client;
+	struct msm_camera_sensor_info *sinfo = camio_dev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
 	int rc = 0;
 	switch (perf_setting) {
 	case S_INIT:
+		cam_bus_scale_table = camdev->cam_bus_scale_table;
 		bus_perf_client =
 			msm_bus_scale_register_client(cam_bus_scale_table);
 		if (!bus_perf_client) {
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index e12d6b1..e4d4f27 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -638,7 +638,7 @@
 
 	int rc = -EINVAL;
 	void __user *argp = (void __user *)arg;
-	struct v4l2_subdev *sd = &pmctl->isp_sdev->sd;
+	struct v4l2_subdev *sd = pmctl->isp_sdev->sd;
 
 	D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
 	switch (cmd) {
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index b23bba1..8d2caba 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -209,7 +209,7 @@
 	case NOTIFY_VFE_BUF_EVT:
 		if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_notify) {
 			rc = p_mctl->isp_sdev->isp_notify(
-				&p_mctl->isp_sdev->sd, notification, arg);
+				p_mctl->isp_sdev->sd, notification, arg);
 		}
 		break;
 	case NOTIFY_VPE_MSG_EVT:
@@ -219,7 +219,8 @@
 		}
 		break;
 	case NOTIFY_PCLK_CHANGE:
-		rc = msm_camio_vfe_clk_rate_set(*(uint32_t *)arg);
+		rc = v4l2_subdev_call(p_mctl->isp_sdev->sd, video,
+			s_crystal_freq, *(uint32_t *)arg, 0);
 		break;
 	case NOTIFY_CSIPHY_CFG:
 		rc = v4l2_subdev_call(p_mctl->csiphy_sdev,
@@ -380,6 +381,19 @@
 	p_mctl->ispif_sdev = dev_get_drvdata(dev);
 	put_driver(driver);
 
+	/* register vfe subdev */
+	driver = driver_find(MSM_VFE_DRV_NAME, &platform_bus_type);
+	if (!driver)
+		goto out;
+
+	dev = driver_find_device(driver, NULL, 0,
+				msm_mctl_subdev_match_core);
+	if (!dev)
+		goto out_put_driver;
+
+	p_mctl->isp_sdev->sd = dev_get_drvdata(dev);
+	put_driver(driver);
+
 	rc = 0;
 	return rc;
 out_put_driver:
@@ -412,6 +426,8 @@
 		wake_lock(&sync->wake_lock);
 
 		sinfo = sync->pdev->dev.platform_data;
+		sync->pdev->resource = sinfo->resource;
+		sync->pdev->num_resources = sinfo->num_resources;
 		camdev = sinfo->pdata;
 		csid_core = camdev->csid_core;
 		rc = msm_mctl_register_subdevs(p_mctl, csid_core);
@@ -448,7 +464,7 @@
 		/* ISP first*/
 		if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_open)
 			rc = p_mctl->isp_sdev->isp_open(
-				&p_mctl->isp_sdev->sd,
+				p_mctl->isp_sdev->sd,
 				&p_mctl->isp_sdev->sd_vpe, sync);
 		if (rc < 0) {
 			pr_err("%s: isp init failed: %d\n", __func__, rc);
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index 4a3e49f..e8904e2 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -15,6 +15,8 @@
 #include <linux/slab.h>
 #include <linux/io.h>
 #include <linux/atomic.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
 #include <mach/irqs.h>
 #include <mach/camera.h>
 #include <media/v4l2-device.h>
@@ -23,7 +25,6 @@
 
 #include "msm.h"
 #include "msm_vfe32.h"
-#include "msm_ispif.h"
 
 atomic_t irq_cnt;
 
@@ -54,8 +55,8 @@
 	vfe32_put_ch_ping_addr((chn), (addr)))
 
 static struct vfe32_ctrl_type *vfe32_ctrl;
-static struct msm_camera_io_clk camio_clk;
 static void  *vfe_syncdata;
+static uint32_t vfe_clk_rate;
 
 struct vfe32_isr_queue_cmd {
 	struct list_head list;
@@ -437,7 +438,7 @@
 	rp->evt_msg.type   = MSM_CAMERA_MSG;
 	rp->evt_msg.msg_id = path;
 	rp->type	   = id;
-	v4l2_subdev_notify(vfe32_ctrl->subdev, NOTIFY_VFE_BUF_EVT, rp);
+	v4l2_subdev_notify(&vfe32_ctrl->subdev, NOTIFY_VFE_BUF_EVT, rp);
 	spin_unlock_irqrestore(&vfe32_ctrl->sd_notify_lock, flags);
 }
 
@@ -1019,7 +1020,7 @@
 			 8 + ((vfe32_ctrl->sync_timer_number) * 12));
 	/* Sync Timer Pixel Duration */
 	value = *tbl++;
-	val = camio_clk.vfe_clk_rate / 10000;
+	val = vfe_clk_rate / 10000;
 	val = 10000000 / val;
 	val = value * 10000 / val;
 	CDBG("%s: Pixel Clk Cycles!!! %d\n", __func__, val);
@@ -1205,7 +1206,7 @@
 
 	isp_msg_evt.msg_id = isp_msg_id;
 	isp_msg_evt.sof_count = vfe32_ctrl->vfeFrameId;
-	v4l2_subdev_notify(vctrl->subdev,
+	v4l2_subdev_notify(&vctrl->subdev,
 			NOTIFY_ISP_MSG_EVT,
 			(void *)&isp_msg_evt);
 }
@@ -2637,7 +2638,7 @@
 	msg.buf.ch_paddr[2]	= ch2_paddr;
 	msg.frameCounter = vfe32_ctrl->vfeFrameId;
 
-	v4l2_subdev_notify(vfe32_ctrl->subdev,
+	v4l2_subdev_notify(&vfe32_ctrl->subdev,
 			NOTIFY_VFE_MSG_OUT,
 			&msg);
 	return;
@@ -2703,13 +2704,13 @@
 			VFE_MODE_OF_OPERATION_SNAPSHOT) {
 			/* will add message for multi-shot. */
 			vfe32_ctrl->outpath.out0.capture_cnt--;
-			vfe_send_outmsg(vfe32_ctrl->subdev,
+			vfe_send_outmsg(&vfe32_ctrl->subdev,
 				MSG_ID_OUTPUT_T, ch0_paddr,
 				ch1_paddr, ch2_paddr);
 		} else {
 			/* always send message for continous mode. */
 			/* if continuous mode, for display. (preview) */
-			vfe_send_outmsg(vfe32_ctrl->subdev,
+			vfe_send_outmsg(&vfe32_ctrl->subdev,
 				MSG_ID_OUTPUT_P, ch0_paddr,
 				ch1_paddr, ch2_paddr);
 		}
@@ -2749,7 +2750,7 @@
 			vfe32_put_ch_addr(ping_pong,
 				vfe32_ctrl->outpath.out1.ch2,
 				free_buf->ch_paddr[2]);
-		vfe_send_outmsg(vfe32_ctrl->subdev,
+		vfe_send_outmsg(&vfe32_ctrl->subdev,
 			MSG_ID_OUTPUT_T, ch0_paddr,
 			ch1_paddr, ch2_paddr);
 	}
@@ -2775,7 +2776,7 @@
 		vfe32_put_ch_addr(ping_pong,
 			vfe32_ctrl->outpath.out2.ch1,
 			free_buf->ch_paddr[1]);
-		vfe_send_outmsg(vfe32_ctrl->subdev,
+		vfe_send_outmsg(&vfe32_ctrl->subdev,
 			MSG_ID_OUTPUT_S, ch0_paddr,
 			ch1_paddr, ch2_paddr);
 	}
@@ -2844,7 +2845,7 @@
 			vfe32_ctrl->operation_mode ==
 			VFE_MODE_OF_OPERATION_RAW_SNAPSHOT) {
 			vfe32_ctrl->outpath.out1.capture_cnt--;
-			vfe_send_outmsg(vfe32_ctrl->subdev,
+			vfe_send_outmsg(&vfe32_ctrl->subdev,
 				MSG_ID_OUTPUT_S, ch0_paddr,
 				ch1_paddr, ch2_paddr);
 		}
@@ -2907,7 +2908,7 @@
 				vfe32_ctrl->outpath.out2.ch2,
 				free_buf->ch_paddr[2]);
 
-		vfe_send_outmsg(vfe32_ctrl->subdev,
+		vfe_send_outmsg(&vfe32_ctrl->subdev,
 			MSG_ID_OUTPUT_V, ch0_paddr,
 			ch1_paddr, ch2_paddr);
 
@@ -2999,7 +3000,7 @@
 		goto stats_done;
 	}
 
-	v4l2_subdev_notify(vfe32_ctrl->subdev,
+	v4l2_subdev_notify(&vfe32_ctrl->subdev,
 				NOTIFY_VFE_MSG_STATS,
 				&msgStats);
 stats_done:
@@ -3295,91 +3296,6 @@
 	return IRQ_HANDLED;
 }
 
-static int vfe32_resource_init(struct platform_device *pdev, void *sdata)
-{
-	struct resource	*vfemem, *vfeirq, *vfeio;
-	int rc;
-	struct msm_camera_sensor_info *s_info;
-	s_info = pdev->dev.platform_data;
-
-	pdev->resource = s_info->resource;
-	pdev->num_resources = s_info->num_resources;
-
-	vfemem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!vfemem) {
-		pr_err("%s: no mem resource?\n", __func__);
-		return -ENODEV;
-	}
-
-	vfeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (!vfeirq) {
-		pr_err("%s: no irq resource?\n", __func__);
-		return -ENODEV;
-	}
-
-	vfeio = request_mem_region(vfemem->start,
-		resource_size(vfemem), pdev->name);
-	if (!vfeio) {
-		pr_err("%s: VFE region already claimed\n", __func__);
-		return -EBUSY;
-	}
-
-	vfe32_ctrl = kzalloc(sizeof(struct vfe32_ctrl_type), GFP_KERNEL);
-	if (!vfe32_ctrl) {
-		rc = -ENOMEM;
-		goto cmd_init_failed1;
-	}
-
-	vfe32_ctrl->vfeirq = vfeirq->start;
-
-	vfe32_ctrl->vfebase =
-		ioremap(vfemem->start, (vfemem->end - vfemem->start) + 1);
-	if (!vfe32_ctrl->vfebase) {
-		rc = -ENOMEM;
-		pr_err("%s: vfe ioremap failed\n", __func__);
-		goto cmd_init_failed2;
-	}
-
-	vfe32_ctrl->extdata =
-		kmalloc(sizeof(struct vfe32_frame_extra), GFP_KERNEL);
-	if (!vfe32_ctrl->extdata) {
-		rc = -ENOMEM;
-		goto cmd_init_failed3;
-	}
-
-	vfe32_ctrl->extlen = sizeof(struct vfe32_frame_extra);
-
-	spin_lock_init(&vfe32_ctrl->stop_flag_lock);
-	spin_lock_init(&vfe32_ctrl->state_lock);
-	spin_lock_init(&vfe32_ctrl->io_lock);
-	spin_lock_init(&vfe32_ctrl->update_ack_lock);
-	spin_lock_init(&vfe32_ctrl->tasklet_lock);
-
-	spin_lock_init(&vfe32_ctrl->aec_ack_lock);
-	spin_lock_init(&vfe32_ctrl->awb_ack_lock);
-	spin_lock_init(&vfe32_ctrl->af_ack_lock);
-	spin_lock_init(&vfe32_ctrl->sd_notify_lock);
-	INIT_LIST_HEAD(&vfe32_ctrl->tasklet_q);
-
-	vfe32_ctrl->syncdata = sdata;
-	vfe32_ctrl->vfemem = vfemem;
-	vfe32_ctrl->vfeio  = vfeio;
-	vfe32_ctrl->update_linear = false;
-	vfe32_ctrl->update_rolloff = false;
-	vfe32_ctrl->update_la = false;
-	vfe32_ctrl->update_gamma = false;
-	return 0;
-
-cmd_init_failed3:
-	free_irq(vfe32_ctrl->vfeirq, 0);
-	iounmap(vfe32_ctrl->vfebase);
-cmd_init_failed2:
-	kfree(vfe32_ctrl);
-cmd_init_failed1:
-	release_mem_region(vfemem->start, (vfemem->end - vfemem->start) + 1);
-	return rc;
-}
-
 static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd,
 			unsigned int subdev_cmd, void *arg)
 {
@@ -3678,36 +3594,103 @@
 	return rc;
 }
 
+static struct msm_cam_clk_info vfe32_clk_info[] = {
+	{"vfe_clk", 228570000},
+	{"vfe_pclk", -1},
+	{"csi_vfe_clk", -1},
+};
+
+static int msm_vfe_subdev_s_crystal_freq(struct v4l2_subdev *sd,
+						u32 freq, u32 flags)
+{
+	int rc = 0;
+	int round_rate;
+
+	round_rate = clk_round_rate(vfe32_ctrl->vfe_clk[0], freq);
+	if (rc < 0) {
+		pr_err("%s: clk_round_rate failed %d\n",
+					__func__, rc);
+		return rc;
+	}
+
+	vfe_clk_rate = round_rate;
+	rc = clk_set_rate(vfe32_ctrl->vfe_clk[0], round_rate);
+	if (rc < 0)
+		pr_err("%s: clk_set_rate failed %d\n",
+					__func__, rc);
+
+	return rc;
+}
+
+static const struct v4l2_subdev_video_ops msm_vfe_subdev_video_ops = {
+	.s_crystal_freq = msm_vfe_subdev_s_crystal_freq,
+};
+
 static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = {
 	.ioctl = msm_vfe_subdev_ioctl,
 };
 
 static const struct v4l2_subdev_ops msm_vfe_subdev_ops = {
 	.core = &msm_vfe_subdev_core_ops,
+	.video = &msm_vfe_subdev_video_ops,
 };
 
 int msm_vfe_subdev_init(struct v4l2_subdev *sd, void *data,
 	struct platform_device *pdev)
 {
 	int rc = 0;
-	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
-	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
-
-	v4l2_subdev_init(sd, &msm_vfe_subdev_ops);
 	v4l2_set_subdev_hostdata(sd, data);
-	snprintf(sd->name, sizeof(sd->name), "vfe3.2");
-
 	vfe_syncdata = data;
 
-	camio_clk = camdev->ioclk;
+	spin_lock_init(&vfe32_ctrl->stop_flag_lock);
+	spin_lock_init(&vfe32_ctrl->state_lock);
+	spin_lock_init(&vfe32_ctrl->io_lock);
+	spin_lock_init(&vfe32_ctrl->update_ack_lock);
+	spin_lock_init(&vfe32_ctrl->tasklet_lock);
 
-	rc = vfe32_resource_init(pdev, vfe_syncdata);
+	spin_lock_init(&vfe32_ctrl->aec_ack_lock);
+	spin_lock_init(&vfe32_ctrl->awb_ack_lock);
+	spin_lock_init(&vfe32_ctrl->af_ack_lock);
+	spin_lock_init(&vfe32_ctrl->sd_notify_lock);
+	INIT_LIST_HEAD(&vfe32_ctrl->tasklet_q);
+
+	vfe32_ctrl->update_linear = false;
+	vfe32_ctrl->update_rolloff = false;
+	vfe32_ctrl->update_la = false;
+	vfe32_ctrl->update_gamma = false;
+
+	enable_irq(vfe32_ctrl->vfeirq->start);
+
+	vfe32_ctrl->vfebase = ioremap(vfe32_ctrl->vfemem->start,
+		resource_size(vfe32_ctrl->vfemem));
+	if (!vfe32_ctrl->vfebase) {
+		rc = -ENOMEM;
+		pr_err("%s: vfe ioremap failed\n", __func__);
+		goto vfe_remap_failed;
+	}
+
+	if (vfe32_ctrl->fs_vfe == NULL) {
+		vfe32_ctrl->fs_vfe =
+			regulator_get(&vfe32_ctrl->pdev->dev, "fs_vfe");
+		if (IS_ERR(vfe32_ctrl->fs_vfe)) {
+			pr_err("%s: Regulator FS_VFE get failed %ld\n",
+				__func__, PTR_ERR(vfe32_ctrl->fs_vfe));
+			vfe32_ctrl->fs_vfe = NULL;
+			goto vfe_fs_failed;
+		} else if (regulator_enable(vfe32_ctrl->fs_vfe)) {
+			pr_err("%s: Regulator FS_VFE enable failed\n",
+							__func__);
+			regulator_put(vfe32_ctrl->fs_vfe);
+			vfe32_ctrl->fs_vfe = NULL;
+			goto vfe_fs_failed;
+		}
+	}
+
+	rc = msm_cam_clk_enable(&vfe32_ctrl->pdev->dev, vfe32_clk_info,
+			vfe32_ctrl->vfe_clk, ARRAY_SIZE(vfe32_clk_info), 1);
 	if (rc < 0)
-		return rc;
+		goto vfe_clk_enable_failed;
 
-	vfe32_ctrl->subdev = sd;
-	/* Bring up all the required GPIOs and Clocks */
-	rc = msm_camio_enable(pdev);
 	msm_camio_set_perf_lvl(S_INIT);
 	msm_camio_set_perf_lvl(S_PREVIEW);
 
@@ -3717,38 +3700,118 @@
 	else
 		vfe32_ctrl->register_total = VFE33_REGISTER_TOTAL;
 
-	/* TO DO: Need to release the VFE resources */
-	rc = request_irq(vfe32_ctrl->vfeirq, vfe32_parse_irq,
-			IRQF_TRIGGER_RISING, "vfe", 0);
+	return rc;
 
+vfe_clk_enable_failed:
+	regulator_disable(vfe32_ctrl->fs_vfe);
+	regulator_put(vfe32_ctrl->fs_vfe);
+	vfe32_ctrl->fs_vfe = NULL;
+vfe_fs_failed:
+	iounmap(vfe32_ctrl->vfebase);
+vfe_remap_failed:
+	disable_irq(vfe32_ctrl->vfeirq->start);
 	return rc;
 }
 
 void msm_vfe_subdev_release(struct platform_device *pdev)
 {
-	struct resource	*vfemem, *vfeio;
-
+	msm_cam_clk_enable(&vfe32_ctrl->pdev->dev, vfe32_clk_info,
+			vfe32_ctrl->vfe_clk, ARRAY_SIZE(vfe32_clk_info), 0);
+	if (vfe32_ctrl->fs_vfe) {
+		regulator_disable(vfe32_ctrl->fs_vfe);
+		regulator_put(vfe32_ctrl->fs_vfe);
+		vfe32_ctrl->fs_vfe = NULL;
+	}
 	CDBG("%s, free_irq\n", __func__);
-	free_irq(vfe32_ctrl->vfeirq, 0);
+	disable_irq(vfe32_ctrl->vfeirq->start);
 	tasklet_kill(&vfe32_tasklet);
+	iounmap(vfe32_ctrl->vfebase);
 
 	if (atomic_read(&irq_cnt))
 		pr_warning("%s, Warning IRQ Count not ZERO\n", __func__);
 
-	vfemem = vfe32_ctrl->vfemem;
-	vfeio  = vfe32_ctrl->vfeio;
-
-	kfree(vfe32_ctrl->extdata);
-	iounmap(vfe32_ctrl->vfebase);
-	kfree(vfe32_ctrl);
-	vfe32_ctrl = NULL;
-	release_mem_region(vfemem->start, (vfemem->end - vfemem->start) + 1);
-
-	CDBG("%s, msm_camio_disable\n", __func__);
-	msm_camio_disable(pdev);
 	msm_camio_set_perf_lvl(S_EXIT);
-
 	vfe_syncdata = NULL;
 }
 
+static int __devinit vfe32_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	CDBG("%s: device id = %d\n", __func__, pdev->id);
+	vfe32_ctrl = kzalloc(sizeof(struct vfe32_ctrl_type), GFP_KERNEL);
+	if (!vfe32_ctrl) {
+		pr_err("%s: no enough memory\n", __func__);
+		return -ENOMEM;
+	}
 
+	v4l2_subdev_init(&vfe32_ctrl->subdev, &msm_vfe_subdev_ops);
+	snprintf(vfe32_ctrl->subdev.name,
+			 sizeof(vfe32_ctrl->subdev.name), "vfe3.2");
+	v4l2_set_subdevdata(&vfe32_ctrl->subdev, vfe32_ctrl);
+	platform_set_drvdata(pdev, &vfe32_ctrl->subdev);
+
+	vfe32_ctrl->vfemem = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "vfe32");
+	if (!vfe32_ctrl->vfemem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		rc = -ENODEV;
+		goto vfe32_no_resource;
+	}
+	vfe32_ctrl->vfeirq = platform_get_resource_byname(pdev,
+					IORESOURCE_IRQ, "vfe32");
+	if (!vfe32_ctrl->vfeirq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		rc = -ENODEV;
+		goto vfe32_no_resource;
+	}
+
+	vfe32_ctrl->vfeio = request_mem_region(vfe32_ctrl->vfemem->start,
+		resource_size(vfe32_ctrl->vfemem), pdev->name);
+	if (!vfe32_ctrl->vfeio) {
+		pr_err("%s: no valid mem region\n", __func__);
+		rc = -EBUSY;
+		goto vfe32_no_resource;
+	}
+
+	rc = request_irq(vfe32_ctrl->vfeirq->start, vfe32_parse_irq,
+		IRQF_TRIGGER_RISING, "vfe", 0);
+	if (rc < 0) {
+		release_mem_region(vfe32_ctrl->vfemem->start,
+			resource_size(vfe32_ctrl->vfemem));
+		pr_err("%s: irq request fail\n", __func__);
+		rc = -EBUSY;
+		goto vfe32_no_resource;
+	}
+
+	disable_irq(vfe32_ctrl->vfeirq->start);
+
+	vfe32_ctrl->pdev = pdev;
+	return 0;
+
+vfe32_no_resource:
+	kfree(vfe32_ctrl);
+	return 0;
+}
+
+static struct platform_driver vfe32_driver = {
+	.probe = vfe32_probe,
+	.driver = {
+		.name = MSM_VFE_DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_vfe32_init_module(void)
+{
+	return platform_driver_register(&vfe32_driver);
+}
+
+static void __exit msm_vfe32_exit_module(void)
+{
+	platform_driver_unregister(&vfe32_driver);
+}
+
+module_init(msm_vfe32_init_module);
+module_exit(msm_vfe32_exit_module);
+MODULE_DESCRIPTION("VFE 3.2 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
index a01d910..e41a544 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -915,13 +915,14 @@
 
 	spinlock_t  tasklet_lock;
 	struct list_head tasklet_q;
-	int vfeirq;
 	void __iomem *vfebase;
 	void *syncdata;
 	uint32_t register_total;
 
 	struct resource	*vfemem;
 	struct resource *vfeio;
+	struct resource *vfeirq;
+	struct regulator *fs_vfe;
 
 	uint32_t stats_comp;
 	atomic_t vstate;
@@ -945,7 +946,9 @@
 	struct vfe_stats_control csStatsControl;
 
 	/* v4l2 subdev */
-	struct v4l2_subdev *subdev;
+	struct v4l2_subdev subdev;
+	struct platform_device *pdev;
+	struct clk *vfe_clk[3];
 	spinlock_t  sd_notify_lock;
 };
 
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index c59918d..e4384f5 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -670,13 +670,13 @@
 	}
 	vpe_device = &vpe_ctrl->device_data;
 	/* does the device exist? */
-	vpeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+	vpeirq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!vpeirq) {
 		pr_err("%s: no vpe irq resource.\n", __func__);
 		rc = -ENODEV;
 		goto vpe_free_device;
 	}
-	vpemem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	vpemem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!vpemem) {
 		pr_err("%s: no vpe mem resource!\n", __func__);
 		rc = -ENODEV;