diff --git a/Documentation/devicetree/bindings/drm/msm/dsi.txt b/Documentation/devicetree/bindings/drm/msm/dsi.txt
index b3cf325..2b17281 100644
--- a/Documentation/devicetree/bindings/drm/msm/dsi.txt
+++ b/Documentation/devicetree/bindings/drm/msm/dsi.txt
@@ -1,15 +1,12 @@
 Qualcomm Technologies Inc. adreno/snapdragon DSI output
 
+DSI Controller:
 Required properties:
 - compatible:
   * "qcom,mdss-dsi-ctrl"
-- reg: Physical base address and length of the registers of controller, PLL,
-  PHY and PHY regulator
+- reg: Physical base address and length of the registers of controller
 - reg-names: The names of register regions. The following regions are required:
   * "dsi_ctrl"
-  * "dsi_pll"
-  * "dsi_phy"
-  * "dsi_phy_regulator"
 - qcom,dsi-host-index: The ID of DSI controller hardware instance. This should
   be 0 or 1, since we have 2 DSI controllers at most for now.
 - interrupts: The interrupt signal from the DSI block.
@@ -24,10 +21,10 @@ Required properties:
   * "iface_clk"
   * "mdp_core_clk"
   * "pixel_clk"
-- #clock-cells: The value should be 1.
 - vdd-supply: phandle to vdd regulator device node
 - vddio-supply: phandle to vdd-io regulator device node
 - vdda-supply: phandle to vdda regulator device node
+- qcom,dsi-phy: phandle to DSI PHY device node
 
 Optional properties:
 - panel@0: Node of panel connected to this DSI controller.
@@ -42,22 +39,34 @@ Optional properties:
 - interrupt-parent: phandle to the MDP block if the interrupt signal is routed
   through MDP block
 
+DSI PHY:
+Required properties:
+- compatible: Could be the following
+  * "qcom,dsi-phy-28nm-hpm"
+  * "qcom,dsi-phy-28nm-lp"
+- reg: Physical base address and length of the registers of PLL, PHY and PHY
+  regulator
+- reg-names: The names of register regions. The following regions are required:
+  * "dsi_pll"
+  * "dsi_phy"
+  * "dsi_phy_regulator"
+- qcom,dsi-phy-index: The ID of DSI PHY hardware instance. This should
+  be 0 or 1, since we have 2 DSI PHYs at most for now.
+- power-domains: Should be <&mmcc MDSS_GDSC>.
+- clocks: device clocks
+  See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details.
+- clock-names: the following clocks are required:
+  * "iface_clk"
+- vddio-supply: phandle to vdd-io regulator device node
+
 Example:
 	mdss_dsi0: qcom,mdss_dsi@fd922800 {
 		compatible = "qcom,mdss-dsi-ctrl";
 		qcom,dsi-host-index = <0>;
 		interrupt-parent = <&mdss_mdp>;
 		interrupts = <4 0>;
-		reg-names =
-			"dsi_ctrl",
-			"dsi_pll",
-			"dsi_phy",
-			"dsi_phy_regulator",
-		reg =	<0xfd922800 0x200>,
-			<0xfd922a00 0xd4>,
-			<0xfd922b00 0x2b0>,
-			<0xfd922d80 0x7b>,
-			<0xfd828000 0x108>;
+		reg-names = "dsi_ctrl";
+		reg = <0xfd922800 0x200>;
 		power-domains = <&mmcc MDSS_GDSC>;
 		clock-names =
 			"bus_clk",
@@ -75,11 +84,12 @@ Example:
 			<&mmcc MDSS_AHB_CLK>,
 			<&mmcc MDSS_MDP_CLK>,
 			<&mmcc MDSS_PCLK0_CLK>;
-		#clock-cells = <1>;
 		vdda-supply = <&pma8084_l2>;
 		vdd-supply = <&pma8084_l22>;
 		vddio-supply = <&pma8084_l12>;
 
+		qcom,dsi-phy = <&mdss_dsi_phy0>;
+
 		qcom,dual-panel-mode;
 		qcom,master-panel;
 		qcom,sync-dual-panel;
@@ -94,4 +104,17 @@ Example:
 		};
 	};
 
-
+	mdss_dsi_phy0: qcom,mdss_dsi_phy@fd922a00 {
+		compatible = "qcom,dsi-phy-28nm-hpm";
+		qcom,dsi-phy-index = <0>;
+		reg-names =
+			"dsi_pll",
+			"dsi_phy",
+			"dsi_phy_regulator";
+		reg =   <0xfd922a00 0xd4>,
+			<0xfd922b00 0x2b0>,
+			<0xfd922d80 0x7b>;
+		clock-names = "iface_clk";
+		clocks = <&mmcc MDSS_AHB_CLK>;
+		vddio-supply = <&pma8084_l12>;
+	}
diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
index beb26df..1f2561e 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.c
+++ b/drivers/gpu/drm/msm/dsi/dsi.c
@@ -23,6 +23,34 @@ struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
 		msm_dsi->encoders[MSM_DSI_CMD_ENCODER_ID];
 }
 
+static int dsi_get_phy(struct msm_dsi *msm_dsi)
+{
+	struct platform_device *pdev = msm_dsi->pdev;
+	struct platform_device *phy_pdev;
+	struct device_node *phy_node;
+
+	phy_node = of_parse_phandle(pdev->dev.of_node, "qcom,dsi-phy", 0);
+	if (!phy_node) {
+		dev_err(&pdev->dev, "cannot find phy device\n");
+		return -ENXIO;
+	}
+
+	phy_pdev = of_find_device_by_node(phy_node);
+	if (phy_pdev)
+		msm_dsi->phy = platform_get_drvdata(phy_pdev);
+
+	of_node_put(phy_node);
+
+	if (!phy_pdev || !msm_dsi->phy) {
+		dev_err(&pdev->dev, "%s: phy driver is not ready\n", __func__);
+		return -EPROBE_DEFER;
+	}
+
+	msm_dsi->phy_dev = get_device(&phy_pdev->dev);
+
+	return 0;
+}
+
 static void dsi_destroy(struct msm_dsi *msm_dsi)
 {
 	if (!msm_dsi)
@@ -30,9 +58,10 @@ static void dsi_destroy(struct msm_dsi *msm_dsi)
 
 	msm_dsi_manager_unregister(msm_dsi);
 
-	if (msm_dsi->phy) {
-		msm_dsi_phy_destroy(msm_dsi->phy);
+	if (msm_dsi->phy_dev) {
+		put_device(msm_dsi->phy_dev);
 		msm_dsi->phy = NULL;
+		msm_dsi->phy_dev = NULL;
 	}
 
 	if (msm_dsi->host) {
@@ -49,7 +78,6 @@ static struct msm_dsi *dsi_init(struct platform_device *pdev)
 	int ret;
 
 	if (!pdev) {
-		dev_err(&pdev->dev, "no dsi device\n");
 		ret = -ENXIO;
 		goto fail;
 	}
@@ -69,13 +97,10 @@ static struct msm_dsi *dsi_init(struct platform_device *pdev)
 	if (ret)
 		goto fail;
 
-	/* Init dsi PHY */
-	msm_dsi->phy = msm_dsi_phy_init(pdev, msm_dsi->phy_type, msm_dsi->id);
-	if (!msm_dsi->phy) {
-		ret = -ENXIO;
-		pr_err("%s: phy init failed\n", __func__);
+	/* GET dsi PHY */
+	ret = dsi_get_phy(msm_dsi);
+	if (ret)
 		goto fail;
-	}
 
 	/* Register to dsi manager */
 	ret = msm_dsi_manager_register(msm_dsi);
@@ -156,12 +181,14 @@ static struct platform_driver dsi_driver = {
 void __init msm_dsi_register(void)
 {
 	DBG("");
+	msm_dsi_phy_driver_register();
 	platform_driver_register(&dsi_driver);
 }
 
 void __exit msm_dsi_unregister(void)
 {
 	DBG("");
+	msm_dsi_phy_driver_unregister();
 	platform_driver_unregister(&dsi_driver);
 }
 
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index 8022814..92d697d 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -14,6 +14,7 @@
 #ifndef __DSI_CONNECTOR_H__
 #define __DSI_CONNECTOR_H__
 
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 
 #include "drm_crtc.h"
@@ -39,12 +40,27 @@
 #define DSI_ENCODER_SLAVE	DSI_0
 
 enum msm_dsi_phy_type {
-	MSM_DSI_PHY_UNKNOWN,
 	MSM_DSI_PHY_28NM_HPM,
 	MSM_DSI_PHY_28NM_LP,
 	MSM_DSI_PHY_MAX
 };
 
+#define DSI_DEV_REGULATOR_MAX	8
+
+/* Regulators for DSI devices */
+struct dsi_reg_entry {
+	char name[32];
+	int min_voltage;
+	int max_voltage;
+	int enable_load;
+	int disable_load;
+};
+
+struct dsi_reg_config {
+	int num;
+	struct dsi_reg_entry regs[DSI_DEV_REGULATOR_MAX];
+};
+
 struct msm_dsi {
 	struct drm_device *dev;
 	struct platform_device *pdev;
@@ -57,7 +73,7 @@ struct msm_dsi {
 	struct drm_panel *panel;
 	unsigned long panel_flags;
 
-	enum msm_dsi_phy_type phy_type;
+	struct device *phy_dev;
 	bool phy_enabled;
 
 	/* the encoders we are hooked to (outside of dsi block) */
@@ -135,9 +151,8 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi);
 
 /* dsi phy */
 struct msm_dsi_phy;
-struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev,
-			enum msm_dsi_phy_type type, int id);
-void msm_dsi_phy_destroy(struct msm_dsi_phy *phy);
+void msm_dsi_phy_driver_register(void);
+void msm_dsi_phy_driver_unregister(void);
 int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
 	const unsigned long bit_rate, const unsigned long esc_rate);
 int msm_dsi_phy_disable(struct msm_dsi_phy *phy);
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 1cf9f11..59e524b 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -36,35 +36,19 @@
 
 #define DSI_6G_REG_SHIFT	4
 
-#define DSI_REGULATOR_MAX	8
-struct dsi_reg_entry {
-	char name[32];
-	int min_voltage;
-	int max_voltage;
-	int enable_load;
-	int disable_load;
-};
-
-struct dsi_reg_config {
-	int num;
-	struct dsi_reg_entry regs[DSI_REGULATOR_MAX];
-};
-
 struct dsi_config {
 	u32 major;
 	u32 minor;
 	u32 io_offset;
-	enum msm_dsi_phy_type phy_type;
 	struct dsi_reg_config reg_cfg;
 };
 
 static const struct dsi_config dsi_cfgs[] = {
-	{MSM_DSI_VER_MAJOR_V2, 0, 0, MSM_DSI_PHY_UNKNOWN},
+	{MSM_DSI_VER_MAJOR_V2, 0, 0, {0,} },
 	{ /* 8974 v1 */
 		.major = MSM_DSI_VER_MAJOR_6G,
 		.minor = MSM_DSI_6G_VER_MINOR_V1_0,
 		.io_offset = DSI_6G_REG_SHIFT,
-		.phy_type = MSM_DSI_PHY_28NM_HPM,
 		.reg_cfg = {
 			.num = 4,
 			.regs = {
@@ -79,7 +63,6 @@ static const struct dsi_config dsi_cfgs[] = {
 		.major = MSM_DSI_VER_MAJOR_6G,
 		.minor = MSM_DSI_6G_VER_MINOR_V1_1,
 		.io_offset = DSI_6G_REG_SHIFT,
-		.phy_type = MSM_DSI_PHY_28NM_HPM,
 		.reg_cfg = {
 			.num = 4,
 			.regs = {
@@ -94,7 +77,6 @@ static const struct dsi_config dsi_cfgs[] = {
 		.major = MSM_DSI_VER_MAJOR_6G,
 		.minor = MSM_DSI_6G_VER_MINOR_V1_1_1,
 		.io_offset = DSI_6G_REG_SHIFT,
-		.phy_type = MSM_DSI_PHY_28NM_HPM,
 		.reg_cfg = {
 			.num = 4,
 			.regs = {
@@ -109,7 +91,6 @@ static const struct dsi_config dsi_cfgs[] = {
 		.major = MSM_DSI_VER_MAJOR_6G,
 		.minor = MSM_DSI_6G_VER_MINOR_V1_2,
 		.io_offset = DSI_6G_REG_SHIFT,
-		.phy_type = MSM_DSI_PHY_28NM_HPM,
 		.reg_cfg = {
 			.num = 4,
 			.regs = {
@@ -124,7 +105,6 @@ static const struct dsi_config dsi_cfgs[] = {
 		.major = MSM_DSI_VER_MAJOR_6G,
 		.minor = MSM_DSI_6G_VER_MINOR_V1_3_1,
 		.io_offset = DSI_6G_REG_SHIFT,
-		.phy_type = MSM_DSI_PHY_28NM_LP,
 		.reg_cfg = {
 			.num = 4,
 			.regs = {
@@ -197,7 +177,7 @@ struct msm_dsi_host {
 	int id;
 
 	void __iomem *ctrl_base;
-	struct regulator_bulk_data supplies[DSI_REGULATOR_MAX];
+	struct regulator_bulk_data supplies[DSI_DEV_REGULATOR_MAX];
 	struct clk *mdp_core_clk;
 	struct clk *ahb_clk;
 	struct clk *axi_clk;
@@ -1529,7 +1509,6 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
 
 	msm_dsi->host = &msm_host->base;
 	msm_dsi->id = msm_host->id;
-	msm_dsi->phy_type = msm_host->cfg->phy_type;
 
 	DBG("Dsi Host %d initialized", msm_host->id);
 	return 0;
diff --git a/drivers/gpu/drm/msm/dsi/dsi_phy.c b/drivers/gpu/drm/msm/dsi/dsi_phy.c
index e313e52..3d9d130 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_phy.c
@@ -11,12 +11,27 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
 #include "dsi.h"
 #include "dsi.xml.h"
 
 #define dsi_phy_read(offset) msm_readl((offset))
 #define dsi_phy_write(offset, data) msm_writel((data), (offset))
 
+struct dsi_phy_ops {
+	int (*enable)(struct msm_dsi_phy *phy, bool is_dual_panel,
+		const unsigned long bit_rate, const unsigned long esc_rate);
+	int (*disable)(struct msm_dsi_phy *phy);
+};
+
+struct dsi_phy_cfg {
+	enum msm_dsi_phy_type type;
+	struct dsi_reg_config reg_cfg;
+	struct dsi_phy_ops ops;
+};
+
 struct dsi_dphy_timing {
 	u32 clk_pre;
 	u32 clk_post;
@@ -40,17 +55,100 @@ struct msm_dsi_phy {
 	int id;
 
 	struct clk *ahb_clk;
+	struct regulator_bulk_data supplies[DSI_DEV_REGULATOR_MAX];
 
 	struct dsi_dphy_timing timing;
-	enum msm_dsi_phy_type type;
+	const struct dsi_phy_cfg *cfg;
 
 	struct msm_dsi_pll *pll;
-
-	int (*enable)(struct msm_dsi_phy *phy, bool is_dual_panel,
-		const unsigned long bit_rate, const unsigned long esc_rate);
-	int (*disable)(struct msm_dsi_phy *phy);
 };
 
+static int dsi_phy_regulator_init(struct msm_dsi_phy *phy)
+{
+	struct regulator_bulk_data *s = phy->supplies;
+	const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
+	struct device *dev = &phy->pdev->dev;
+	int num = phy->cfg->reg_cfg.num;
+	int i, ret;
+
+	for (i = 0; i < num; i++)
+		s[i].supply = regs[i].name;
+
+	ret = devm_regulator_bulk_get(&phy->pdev->dev, num, s);
+	if (ret < 0) {
+		dev_err(dev, "%s: failed to init regulator, ret=%d\n",
+						__func__, ret);
+		return ret;
+	}
+
+	for (i = 0; i < num; i++) {
+		if ((regs[i].min_voltage >= 0) && (regs[i].max_voltage >= 0)) {
+			ret = regulator_set_voltage(s[i].consumer,
+				regs[i].min_voltage, regs[i].max_voltage);
+			if (ret < 0) {
+				dev_err(dev,
+					"regulator %d set voltage failed, %d\n",
+					i, ret);
+				return ret;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void dsi_phy_regulator_disable(struct msm_dsi_phy *phy)
+{
+	struct regulator_bulk_data *s = phy->supplies;
+	const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
+	int num = phy->cfg->reg_cfg.num;
+	int i;
+
+	DBG("");
+	for (i = num - 1; i >= 0; i--)
+		if (regs[i].disable_load >= 0)
+			regulator_set_load(s[i].consumer,
+						regs[i].disable_load);
+
+	regulator_bulk_disable(num, s);
+}
+
+static int dsi_phy_regulator_enable(struct msm_dsi_phy *phy)
+{
+	struct regulator_bulk_data *s = phy->supplies;
+	const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
+	struct device *dev = &phy->pdev->dev;
+	int num = phy->cfg->reg_cfg.num;
+	int ret, i;
+
+	DBG("");
+	for (i = 0; i < num; i++) {
+		if (regs[i].enable_load >= 0) {
+			ret = regulator_set_load(s[i].consumer,
+							regs[i].enable_load);
+			if (ret < 0) {
+				dev_err(dev,
+					"regulator %d set op mode failed, %d\n",
+					i, ret);
+				goto fail;
+			}
+		}
+	}
+
+	ret = regulator_bulk_enable(num, s);
+	if (ret < 0) {
+		dev_err(dev, "regulator enable failed, %d\n", ret);
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	for (i--; i >= 0; i--)
+		regulator_set_load(s[i].consumer, regs[i].disable_load);
+	return ret;
+}
+
 #define S_DIV_ROUND_UP(n, d)	\
 	(((n) >= 0) ? (((n) + (d) - 1) / (d)) : (((n) - (d) + 1) / (d)))
 
@@ -313,51 +411,94 @@ static void dsi_phy_disable_resource(struct msm_dsi_phy *phy)
 	pm_runtime_put_sync(&phy->pdev->dev);
 }
 
-#define dsi_phy_func_init(name)	\
-	do {	\
-		phy->enable = dsi_##name##_phy_enable;	\
-		phy->disable = dsi_##name##_phy_disable;	\
-	} while (0)
+static const struct dsi_phy_cfg dsi_phy_cfgs[MSM_DSI_PHY_MAX] = {
+	[MSM_DSI_PHY_28NM_HPM] = {
+		.type = MSM_DSI_PHY_28NM_HPM,
+		.reg_cfg = {
+			.num = 1,
+			.regs = {
+				{"vddio", 1800000, 1800000, 100000, 100},
+			},
+		},
+		.ops = {
+			.enable = dsi_28nm_phy_enable,
+			.disable = dsi_28nm_phy_disable,
+		}
+	},
+	[MSM_DSI_PHY_28NM_LP] = {
+		.type = MSM_DSI_PHY_28NM_LP,
+		.reg_cfg = {
+			.num = 1,
+			.regs = {
+				{"vddio", 1800000, 1800000, 100000, 100},
+			},
+		},
+		.ops = {
+			.enable = dsi_28nm_phy_enable,
+			.disable = dsi_28nm_phy_disable,
+		}
+	},
+};
+
+static const struct of_device_id dsi_phy_dt_match[] = {
+	{ .compatible = "qcom,dsi-phy-28nm-hpm",
+	  .data = &dsi_phy_cfgs[MSM_DSI_PHY_28NM_HPM],},
+	{ .compatible = "qcom,dsi-phy-28nm-lp",
+	  .data = &dsi_phy_cfgs[MSM_DSI_PHY_28NM_LP],},
+	{}
+};
 
-struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev,
-			enum msm_dsi_phy_type type, int id)
+static int dsi_phy_driver_probe(struct platform_device *pdev)
 {
 	struct msm_dsi_phy *phy;
+	const struct of_device_id *match;
 	int ret;
 
 	phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
 	if (!phy)
-		return NULL;
+		return -ENOMEM;
+
+	match = of_match_node(dsi_phy_dt_match, pdev->dev.of_node);
+	if (!match)
+		return -ENODEV;
+
+	phy->cfg = match->data;
+	phy->pdev = pdev;
+
+	ret = of_property_read_u32(pdev->dev.of_node,
+				"qcom,dsi-phy-index", &phy->id);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"%s: PHY index not specified, ret=%d\n",
+			__func__, ret);
+		goto fail;
+	}
 
 	phy->base = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
 	if (IS_ERR_OR_NULL(phy->base)) {
-		pr_err("%s: failed to map phy base\n", __func__);
-		return NULL;
+		dev_err(&pdev->dev, "%s: failed to map phy base\n", __func__);
+		ret = -ENOMEM;
+		goto fail;
 	}
 	phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator", "DSI_PHY_REG");
 	if (IS_ERR_OR_NULL(phy->reg_base)) {
-		pr_err("%s: failed to map phy regulator base\n", __func__);
-		return NULL;
+		dev_err(&pdev->dev,
+			"%s: failed to map phy regulator base\n", __func__);
+		ret = -ENOMEM;
+		goto fail;
 	}
 
-	switch (type) {
-	case MSM_DSI_PHY_28NM_HPM:
-	case MSM_DSI_PHY_28NM_LP:
-		dsi_phy_func_init(28nm);
-		break;
-	default:
-		pr_err("%s: unsupported type, %d\n", __func__, type);
-		return NULL;
+	ret = dsi_phy_regulator_init(phy);
+	if (ret) {
+		dev_err(&pdev->dev, "%s: failed to init regulator\n", __func__);
+		goto fail;
 	}
 
-	phy->type = type;
-	phy->id = id;
-	phy->pdev = pdev;
-
 	phy->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
 	if (IS_ERR(phy->ahb_clk)) {
 		pr_err("%s: Unable to get ahb clk\n", __func__);
-		return NULL;
+		ret = PTR_ERR(phy->ahb_clk);
+		goto fail;
 	}
 
 	/* PLL init will call into clk_register which requires
@@ -365,39 +506,84 @@ struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev,
 	 */
 	ret = dsi_phy_enable_resource(phy);
 	if (ret)
-		return NULL;
+		goto fail;
 
-	phy->pll = msm_dsi_pll_init(pdev, type, id);
+	phy->pll = msm_dsi_pll_init(pdev, phy->cfg->type, phy->id);
 	if (!phy->pll)
-		pr_info("%s: pll init failed, need separate pll clk driver\n",
+		dev_info(&pdev->dev,
+			"%s: pll init failed, need separate pll clk driver\n",
 			__func__);
 
 	dsi_phy_disable_resource(phy);
 
-	return phy;
+	platform_set_drvdata(pdev, phy);
+
+	return 0;
+
+fail:
+	return ret;
 }
 
-void msm_dsi_phy_destroy(struct msm_dsi_phy *phy)
+static int dsi_phy_driver_remove(struct platform_device *pdev)
 {
-	if (phy->pll) {
+	struct msm_dsi_phy *phy = platform_get_drvdata(pdev);
+
+	if (phy && phy->pll) {
 		msm_dsi_pll_destroy(phy->pll);
 		phy->pll = NULL;
 	}
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver dsi_phy_platform_driver = {
+	.probe      = dsi_phy_driver_probe,
+	.remove     = dsi_phy_driver_remove,
+	.driver     = {
+		.name   = "msm_dsi_phy",
+		.of_match_table = dsi_phy_dt_match,
+	},
+};
+
+void __init msm_dsi_phy_driver_register(void)
+{
+	platform_driver_register(&dsi_phy_platform_driver);
+}
+
+void __exit msm_dsi_phy_driver_unregister(void)
+{
+	platform_driver_unregister(&dsi_phy_platform_driver);
 }
 
 int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
 	const unsigned long bit_rate, const unsigned long esc_rate)
 {
-	if (!phy || !phy->enable)
+	int ret;
+
+	if (!phy || !phy->cfg->ops.enable)
 		return -EINVAL;
-	return phy->enable(phy, is_dual_panel, bit_rate, esc_rate);
+
+	ret = dsi_phy_regulator_enable(phy);
+	if (ret) {
+		dev_err(&phy->pdev->dev, "%s: regulator enable failed, %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	return phy->cfg->ops.enable(phy, is_dual_panel, bit_rate, esc_rate);
 }
 
 int msm_dsi_phy_disable(struct msm_dsi_phy *phy)
 {
-	if (!phy || !phy->disable)
+	if (!phy || !phy->cfg->ops.disable)
 		return -EINVAL;
-	return phy->disable(phy);
+
+	phy->cfg->ops.disable(phy);
+	dsi_phy_regulator_disable(phy);
+
+	return 0;
 }
 
 void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy,
