0001
0002
0003
0004
0005
0006 #include <linux/of_device.h>
0007
0008 #include "hdmi.h"
0009
0010 static int msm_hdmi_phy_resource_init(struct hdmi_phy *phy)
0011 {
0012 struct hdmi_phy_cfg *cfg = phy->cfg;
0013 struct device *dev = &phy->pdev->dev;
0014 int i, ret;
0015
0016 phy->regs = devm_kcalloc(dev, cfg->num_regs, sizeof(phy->regs[0]),
0017 GFP_KERNEL);
0018 if (!phy->regs)
0019 return -ENOMEM;
0020
0021 phy->clks = devm_kcalloc(dev, cfg->num_clks, sizeof(phy->clks[0]),
0022 GFP_KERNEL);
0023 if (!phy->clks)
0024 return -ENOMEM;
0025
0026 for (i = 0; i < cfg->num_regs; i++)
0027 phy->regs[i].supply = cfg->reg_names[i];
0028
0029 ret = devm_regulator_bulk_get(dev, cfg->num_regs, phy->regs);
0030 if (ret) {
0031 if (ret != -EPROBE_DEFER)
0032 DRM_DEV_ERROR(dev, "failed to get phy regulators: %d\n", ret);
0033
0034 return ret;
0035 }
0036
0037 for (i = 0; i < cfg->num_clks; i++) {
0038 struct clk *clk;
0039
0040 clk = msm_clk_get(phy->pdev, cfg->clk_names[i]);
0041 if (IS_ERR(clk)) {
0042 ret = PTR_ERR(clk);
0043 DRM_DEV_ERROR(dev, "failed to get phy clock: %s (%d)\n",
0044 cfg->clk_names[i], ret);
0045 return ret;
0046 }
0047
0048 phy->clks[i] = clk;
0049 }
0050
0051 return 0;
0052 }
0053
0054 int msm_hdmi_phy_resource_enable(struct hdmi_phy *phy)
0055 {
0056 struct hdmi_phy_cfg *cfg = phy->cfg;
0057 struct device *dev = &phy->pdev->dev;
0058 int i, ret = 0;
0059
0060 pm_runtime_get_sync(dev);
0061
0062 ret = regulator_bulk_enable(cfg->num_regs, phy->regs);
0063 if (ret) {
0064 DRM_DEV_ERROR(dev, "failed to enable regulators: (%d)\n", ret);
0065 return ret;
0066 }
0067
0068 for (i = 0; i < cfg->num_clks; i++) {
0069 ret = clk_prepare_enable(phy->clks[i]);
0070 if (ret)
0071 DRM_DEV_ERROR(dev, "failed to enable clock: %s (%d)\n",
0072 cfg->clk_names[i], ret);
0073 }
0074
0075 return ret;
0076 }
0077
0078 void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy)
0079 {
0080 struct hdmi_phy_cfg *cfg = phy->cfg;
0081 struct device *dev = &phy->pdev->dev;
0082 int i;
0083
0084 for (i = cfg->num_clks - 1; i >= 0; i--)
0085 clk_disable_unprepare(phy->clks[i]);
0086
0087 regulator_bulk_disable(cfg->num_regs, phy->regs);
0088
0089 pm_runtime_put_sync(dev);
0090 }
0091
0092 void msm_hdmi_phy_powerup(struct hdmi_phy *phy, unsigned long int pixclock)
0093 {
0094 if (!phy || !phy->cfg->powerup)
0095 return;
0096
0097 phy->cfg->powerup(phy, pixclock);
0098 }
0099
0100 void msm_hdmi_phy_powerdown(struct hdmi_phy *phy)
0101 {
0102 if (!phy || !phy->cfg->powerdown)
0103 return;
0104
0105 phy->cfg->powerdown(phy);
0106 }
0107
0108 static int msm_hdmi_phy_pll_init(struct platform_device *pdev,
0109 enum hdmi_phy_type type)
0110 {
0111 int ret;
0112
0113 switch (type) {
0114 case MSM_HDMI_PHY_8960:
0115 ret = msm_hdmi_pll_8960_init(pdev);
0116 break;
0117 case MSM_HDMI_PHY_8996:
0118 ret = msm_hdmi_pll_8996_init(pdev);
0119 break;
0120
0121
0122
0123 case MSM_HDMI_PHY_8x60:
0124 case MSM_HDMI_PHY_8x74:
0125 default:
0126 ret = 0;
0127 break;
0128 }
0129
0130 return ret;
0131 }
0132
0133 static int msm_hdmi_phy_probe(struct platform_device *pdev)
0134 {
0135 struct device *dev = &pdev->dev;
0136 struct hdmi_phy *phy;
0137 int ret;
0138
0139 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
0140 if (!phy)
0141 return -ENODEV;
0142
0143 phy->cfg = (struct hdmi_phy_cfg *)of_device_get_match_data(dev);
0144 if (!phy->cfg)
0145 return -ENODEV;
0146
0147 phy->mmio = msm_ioremap(pdev, "hdmi_phy");
0148 if (IS_ERR(phy->mmio)) {
0149 DRM_DEV_ERROR(dev, "%s: failed to map phy base\n", __func__);
0150 return -ENOMEM;
0151 }
0152
0153 phy->pdev = pdev;
0154
0155 ret = msm_hdmi_phy_resource_init(phy);
0156 if (ret)
0157 return ret;
0158
0159 pm_runtime_enable(&pdev->dev);
0160
0161 ret = msm_hdmi_phy_resource_enable(phy);
0162 if (ret)
0163 return ret;
0164
0165 ret = msm_hdmi_phy_pll_init(pdev, phy->cfg->type);
0166 if (ret) {
0167 DRM_DEV_ERROR(dev, "couldn't init PLL\n");
0168 msm_hdmi_phy_resource_disable(phy);
0169 return ret;
0170 }
0171
0172 msm_hdmi_phy_resource_disable(phy);
0173
0174 platform_set_drvdata(pdev, phy);
0175
0176 return 0;
0177 }
0178
0179 static int msm_hdmi_phy_remove(struct platform_device *pdev)
0180 {
0181 pm_runtime_disable(&pdev->dev);
0182
0183 return 0;
0184 }
0185
0186 static const struct of_device_id msm_hdmi_phy_dt_match[] = {
0187 { .compatible = "qcom,hdmi-phy-8660",
0188 .data = &msm_hdmi_phy_8x60_cfg },
0189 { .compatible = "qcom,hdmi-phy-8960",
0190 .data = &msm_hdmi_phy_8960_cfg },
0191 { .compatible = "qcom,hdmi-phy-8974",
0192 .data = &msm_hdmi_phy_8x74_cfg },
0193 { .compatible = "qcom,hdmi-phy-8084",
0194 .data = &msm_hdmi_phy_8x74_cfg },
0195 { .compatible = "qcom,hdmi-phy-8996",
0196 .data = &msm_hdmi_phy_8996_cfg },
0197 {}
0198 };
0199
0200 static struct platform_driver msm_hdmi_phy_platform_driver = {
0201 .probe = msm_hdmi_phy_probe,
0202 .remove = msm_hdmi_phy_remove,
0203 .driver = {
0204 .name = "msm_hdmi_phy",
0205 .of_match_table = msm_hdmi_phy_dt_match,
0206 },
0207 };
0208
0209 void __init msm_hdmi_phy_driver_register(void)
0210 {
0211 platform_driver_register(&msm_hdmi_phy_platform_driver);
0212 }
0213
0214 void __exit msm_hdmi_phy_driver_unregister(void)
0215 {
0216 platform_driver_unregister(&msm_hdmi_phy_platform_driver);
0217 }