2 * Copyright (c) 2016, The Linux Foundation. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include <linux/of_device.h>
18 static int msm_hdmi_phy_resource_init(struct hdmi_phy
*phy
)
20 struct hdmi_phy_cfg
*cfg
= phy
->cfg
;
21 struct device
*dev
= &phy
->pdev
->dev
;
24 phy
->regs
= devm_kcalloc(dev
, cfg
->num_regs
, sizeof(phy
->regs
[0]),
29 phy
->clks
= devm_kcalloc(dev
, cfg
->num_clks
, sizeof(phy
->clks
[0]),
34 for (i
= 0; i
< cfg
->num_regs
; i
++) {
35 struct regulator
*reg
;
37 reg
= devm_regulator_get(dev
, cfg
->reg_names
[i
]);
40 DRM_DEV_ERROR(dev
, "failed to get phy regulator: %s (%d)\n",
41 cfg
->reg_names
[i
], ret
);
48 for (i
= 0; i
< cfg
->num_clks
; i
++) {
51 clk
= msm_clk_get(phy
->pdev
, cfg
->clk_names
[i
]);
54 DRM_DEV_ERROR(dev
, "failed to get phy clock: %s (%d)\n",
55 cfg
->clk_names
[i
], ret
);
65 int msm_hdmi_phy_resource_enable(struct hdmi_phy
*phy
)
67 struct hdmi_phy_cfg
*cfg
= phy
->cfg
;
68 struct device
*dev
= &phy
->pdev
->dev
;
71 pm_runtime_get_sync(dev
);
73 for (i
= 0; i
< cfg
->num_regs
; i
++) {
74 ret
= regulator_enable(phy
->regs
[i
]);
76 DRM_DEV_ERROR(dev
, "failed to enable regulator: %s (%d)\n",
77 cfg
->reg_names
[i
], ret
);
80 for (i
= 0; i
< cfg
->num_clks
; i
++) {
81 ret
= clk_prepare_enable(phy
->clks
[i
]);
83 DRM_DEV_ERROR(dev
, "failed to enable clock: %s (%d)\n",
84 cfg
->clk_names
[i
], ret
);
90 void msm_hdmi_phy_resource_disable(struct hdmi_phy
*phy
)
92 struct hdmi_phy_cfg
*cfg
= phy
->cfg
;
93 struct device
*dev
= &phy
->pdev
->dev
;
96 for (i
= cfg
->num_clks
- 1; i
>= 0; i
--)
97 clk_disable_unprepare(phy
->clks
[i
]);
99 for (i
= cfg
->num_regs
- 1; i
>= 0; i
--)
100 regulator_disable(phy
->regs
[i
]);
102 pm_runtime_put_sync(dev
);
105 void msm_hdmi_phy_powerup(struct hdmi_phy
*phy
, unsigned long int pixclock
)
107 if (!phy
|| !phy
->cfg
->powerup
)
110 phy
->cfg
->powerup(phy
, pixclock
);
113 void msm_hdmi_phy_powerdown(struct hdmi_phy
*phy
)
115 if (!phy
|| !phy
->cfg
->powerdown
)
118 phy
->cfg
->powerdown(phy
);
121 static int msm_hdmi_phy_pll_init(struct platform_device
*pdev
,
122 enum hdmi_phy_type type
)
127 case MSM_HDMI_PHY_8960
:
128 ret
= msm_hdmi_pll_8960_init(pdev
);
130 case MSM_HDMI_PHY_8996
:
131 ret
= msm_hdmi_pll_8996_init(pdev
);
134 * we don't have PLL support for these, don't report an error for now
136 case MSM_HDMI_PHY_8x60
:
137 case MSM_HDMI_PHY_8x74
:
146 static int msm_hdmi_phy_probe(struct platform_device
*pdev
)
148 struct device
*dev
= &pdev
->dev
;
149 struct hdmi_phy
*phy
;
152 phy
= devm_kzalloc(dev
, sizeof(*phy
), GFP_KERNEL
);
156 phy
->cfg
= (struct hdmi_phy_cfg
*)of_device_get_match_data(dev
);
160 phy
->mmio
= msm_ioremap(pdev
, "hdmi_phy", "HDMI_PHY");
161 if (IS_ERR(phy
->mmio
)) {
162 DRM_DEV_ERROR(dev
, "%s: failed to map phy base\n", __func__
);
168 ret
= msm_hdmi_phy_resource_init(phy
);
172 pm_runtime_enable(&pdev
->dev
);
174 ret
= msm_hdmi_phy_resource_enable(phy
);
178 ret
= msm_hdmi_phy_pll_init(pdev
, phy
->cfg
->type
);
180 DRM_DEV_ERROR(dev
, "couldn't init PLL\n");
181 msm_hdmi_phy_resource_disable(phy
);
185 msm_hdmi_phy_resource_disable(phy
);
187 platform_set_drvdata(pdev
, phy
);
192 static int msm_hdmi_phy_remove(struct platform_device
*pdev
)
194 pm_runtime_disable(&pdev
->dev
);
199 static const struct of_device_id msm_hdmi_phy_dt_match
[] = {
200 { .compatible
= "qcom,hdmi-phy-8660",
201 .data
= &msm_hdmi_phy_8x60_cfg
},
202 { .compatible
= "qcom,hdmi-phy-8960",
203 .data
= &msm_hdmi_phy_8960_cfg
},
204 { .compatible
= "qcom,hdmi-phy-8974",
205 .data
= &msm_hdmi_phy_8x74_cfg
},
206 { .compatible
= "qcom,hdmi-phy-8084",
207 .data
= &msm_hdmi_phy_8x74_cfg
},
208 { .compatible
= "qcom,hdmi-phy-8996",
209 .data
= &msm_hdmi_phy_8996_cfg
},
213 static struct platform_driver msm_hdmi_phy_platform_driver
= {
214 .probe
= msm_hdmi_phy_probe
,
215 .remove
= msm_hdmi_phy_remove
,
217 .name
= "msm_hdmi_phy",
218 .of_match_table
= msm_hdmi_phy_dt_match
,
222 void __init
msm_hdmi_phy_driver_register(void)
224 platform_driver_register(&msm_hdmi_phy_platform_driver
);
227 void __exit
msm_hdmi_phy_driver_unregister(void)
229 platform_driver_unregister(&msm_hdmi_phy_platform_driver
);