summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/drm/msm/dsi.txt59
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.c45
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.h25
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_host.c25
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_phy.c266
5 files changed, 326 insertions, 94 deletions
diff --git a/Documentation/devicetree/bindings/drm/msm/dsi.txt b/Documentation/devicetree/bindings/drm/msm/dsi.txt
index ff8aebb2f8f8..cd8fe6cf536c 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;
@@ -93,3 +103,18 @@ Example:
backlight = <...>;
};
};
+
+ 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 beb26dfca276..1f2561e2ff71 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 8022814f7914..92d697de4858 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 43ea8a30c121..bc2e405758e3 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;
@@ -1534,7 +1514,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 2b1c8fdb10de..2d3b33ce1cc5 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(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(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,