]> Git Repo - linux.git/blob - drivers/gpu/drm/msm/hdmi/hdmi_phy.c
Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
[linux.git] / drivers / gpu / drm / msm / hdmi / hdmi_phy.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2016, The Linux Foundation. All rights reserved.
4  */
5
6 #include <linux/of.h>
7 #include <linux/platform_device.h>
8
9 #include "hdmi.h"
10
11 static int msm_hdmi_phy_resource_init(struct hdmi_phy *phy)
12 {
13         struct hdmi_phy_cfg *cfg = phy->cfg;
14         struct device *dev = &phy->pdev->dev;
15         int i, ret;
16
17         phy->regs = devm_kcalloc(dev, cfg->num_regs, sizeof(phy->regs[0]),
18                                  GFP_KERNEL);
19         if (!phy->regs)
20                 return -ENOMEM;
21
22         phy->clks = devm_kcalloc(dev, cfg->num_clks, sizeof(phy->clks[0]),
23                                  GFP_KERNEL);
24         if (!phy->clks)
25                 return -ENOMEM;
26
27         for (i = 0; i < cfg->num_regs; i++)
28                 phy->regs[i].supply = cfg->reg_names[i];
29
30         ret = devm_regulator_bulk_get(dev, cfg->num_regs, phy->regs);
31         if (ret) {
32                 if (ret != -EPROBE_DEFER)
33                         DRM_DEV_ERROR(dev, "failed to get phy regulators: %d\n", ret);
34
35                 return ret;
36         }
37
38         for (i = 0; i < cfg->num_clks; i++) {
39                 struct clk *clk;
40
41                 clk = msm_clk_get(phy->pdev, cfg->clk_names[i]);
42                 if (IS_ERR(clk)) {
43                         ret = PTR_ERR(clk);
44                         DRM_DEV_ERROR(dev, "failed to get phy clock: %s (%d)\n",
45                                 cfg->clk_names[i], ret);
46                         return ret;
47                 }
48
49                 phy->clks[i] = clk;
50         }
51
52         return 0;
53 }
54
55 int msm_hdmi_phy_resource_enable(struct hdmi_phy *phy)
56 {
57         struct hdmi_phy_cfg *cfg = phy->cfg;
58         struct device *dev = &phy->pdev->dev;
59         int i, ret = 0;
60
61         pm_runtime_get_sync(dev);
62
63         ret = regulator_bulk_enable(cfg->num_regs, phy->regs);
64         if (ret) {
65                 DRM_DEV_ERROR(dev, "failed to enable regulators: (%d)\n", ret);
66                 return ret;
67         }
68
69         for (i = 0; i < cfg->num_clks; i++) {
70                 ret = clk_prepare_enable(phy->clks[i]);
71                 if (ret)
72                         DRM_DEV_ERROR(dev, "failed to enable clock: %s (%d)\n",
73                                 cfg->clk_names[i], ret);
74         }
75
76         return ret;
77 }
78
79 void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy)
80 {
81         struct hdmi_phy_cfg *cfg = phy->cfg;
82         struct device *dev = &phy->pdev->dev;
83         int i;
84
85         for (i = cfg->num_clks - 1; i >= 0; i--)
86                 clk_disable_unprepare(phy->clks[i]);
87
88         regulator_bulk_disable(cfg->num_regs, phy->regs);
89
90         pm_runtime_put_sync(dev);
91 }
92
93 void msm_hdmi_phy_powerup(struct hdmi_phy *phy, unsigned long int pixclock)
94 {
95         if (!phy || !phy->cfg->powerup)
96                 return;
97
98         phy->cfg->powerup(phy, pixclock);
99 }
100
101 void msm_hdmi_phy_powerdown(struct hdmi_phy *phy)
102 {
103         if (!phy || !phy->cfg->powerdown)
104                 return;
105
106         phy->cfg->powerdown(phy);
107 }
108
109 static int msm_hdmi_phy_pll_init(struct platform_device *pdev,
110                              enum hdmi_phy_type type)
111 {
112         int ret;
113
114         switch (type) {
115         case MSM_HDMI_PHY_8960:
116                 ret = msm_hdmi_pll_8960_init(pdev);
117                 break;
118         case MSM_HDMI_PHY_8996:
119                 ret = msm_hdmi_pll_8996_init(pdev);
120                 break;
121         /*
122          * we don't have PLL support for these, don't report an error for now
123          */
124         case MSM_HDMI_PHY_8x60:
125         case MSM_HDMI_PHY_8x74:
126         default:
127                 ret = 0;
128                 break;
129         }
130
131         return ret;
132 }
133
134 static int msm_hdmi_phy_probe(struct platform_device *pdev)
135 {
136         struct device *dev = &pdev->dev;
137         struct hdmi_phy *phy;
138         int ret;
139
140         phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
141         if (!phy)
142                 return -ENODEV;
143
144         phy->cfg = (struct hdmi_phy_cfg *)of_device_get_match_data(dev);
145         if (!phy->cfg)
146                 return -ENODEV;
147
148         phy->mmio = msm_ioremap(pdev, "hdmi_phy");
149         if (IS_ERR(phy->mmio)) {
150                 DRM_DEV_ERROR(dev, "%s: failed to map phy base\n", __func__);
151                 return -ENOMEM;
152         }
153
154         phy->pdev = pdev;
155
156         ret = msm_hdmi_phy_resource_init(phy);
157         if (ret)
158                 return ret;
159
160         pm_runtime_enable(&pdev->dev);
161
162         ret = msm_hdmi_phy_resource_enable(phy);
163         if (ret)
164                 return ret;
165
166         ret = msm_hdmi_phy_pll_init(pdev, phy->cfg->type);
167         if (ret) {
168                 DRM_DEV_ERROR(dev, "couldn't init PLL\n");
169                 msm_hdmi_phy_resource_disable(phy);
170                 return ret;
171         }
172
173         msm_hdmi_phy_resource_disable(phy);
174
175         platform_set_drvdata(pdev, phy);
176
177         return 0;
178 }
179
180 static void msm_hdmi_phy_remove(struct platform_device *pdev)
181 {
182         pm_runtime_disable(&pdev->dev);
183 }
184
185 static const struct of_device_id msm_hdmi_phy_dt_match[] = {
186         { .compatible = "qcom,hdmi-phy-8660",
187           .data = &msm_hdmi_phy_8x60_cfg },
188         { .compatible = "qcom,hdmi-phy-8960",
189           .data = &msm_hdmi_phy_8960_cfg },
190         { .compatible = "qcom,hdmi-phy-8974",
191           .data = &msm_hdmi_phy_8x74_cfg },
192         { .compatible = "qcom,hdmi-phy-8084",
193           .data = &msm_hdmi_phy_8x74_cfg },
194         { .compatible = "qcom,hdmi-phy-8996",
195           .data = &msm_hdmi_phy_8996_cfg },
196         {}
197 };
198
199 static struct platform_driver msm_hdmi_phy_platform_driver = {
200         .probe      = msm_hdmi_phy_probe,
201         .remove_new = msm_hdmi_phy_remove,
202         .driver     = {
203                 .name   = "msm_hdmi_phy",
204                 .of_match_table = msm_hdmi_phy_dt_match,
205         },
206 };
207
208 void __init msm_hdmi_phy_driver_register(void)
209 {
210         platform_driver_register(&msm_hdmi_phy_platform_driver);
211 }
212
213 void __exit msm_hdmi_phy_driver_unregister(void)
214 {
215         platform_driver_unregister(&msm_hdmi_phy_platform_driver);
216 }
This page took 0.047118 seconds and 4 git commands to generate.