]> Git Repo - J-linux.git/blob - drivers/gpu/drm/msm/hdmi/hdmi_phy.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-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         case MSM_HDMI_PHY_8998:
122                 ret = msm_hdmi_pll_8998_init(pdev);
123                 break;
124         /*
125          * we don't have PLL support for these, don't report an error for now
126          */
127         case MSM_HDMI_PHY_8x60:
128         case MSM_HDMI_PHY_8x74:
129         default:
130                 ret = 0;
131                 break;
132         }
133
134         return ret;
135 }
136
137 static int msm_hdmi_phy_probe(struct platform_device *pdev)
138 {
139         struct device *dev = &pdev->dev;
140         struct hdmi_phy *phy;
141         int ret;
142
143         phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
144         if (!phy)
145                 return -ENODEV;
146
147         phy->cfg = (struct hdmi_phy_cfg *)of_device_get_match_data(dev);
148         if (!phy->cfg)
149                 return -ENODEV;
150
151         phy->mmio = msm_ioremap(pdev, "hdmi_phy");
152         if (IS_ERR(phy->mmio)) {
153                 DRM_DEV_ERROR(dev, "%s: failed to map phy base\n", __func__);
154                 return -ENOMEM;
155         }
156
157         phy->pdev = pdev;
158
159         ret = msm_hdmi_phy_resource_init(phy);
160         if (ret)
161                 return ret;
162
163         pm_runtime_enable(&pdev->dev);
164
165         ret = msm_hdmi_phy_resource_enable(phy);
166         if (ret)
167                 return ret;
168
169         ret = msm_hdmi_phy_pll_init(pdev, phy->cfg->type);
170         if (ret) {
171                 DRM_DEV_ERROR(dev, "couldn't init PLL\n");
172                 msm_hdmi_phy_resource_disable(phy);
173                 return ret;
174         }
175
176         msm_hdmi_phy_resource_disable(phy);
177
178         platform_set_drvdata(pdev, phy);
179
180         return 0;
181 }
182
183 static void msm_hdmi_phy_remove(struct platform_device *pdev)
184 {
185         pm_runtime_disable(&pdev->dev);
186 }
187
188 static const struct of_device_id msm_hdmi_phy_dt_match[] = {
189         { .compatible = "qcom,hdmi-phy-8660",
190           .data = &msm_hdmi_phy_8x60_cfg },
191         { .compatible = "qcom,hdmi-phy-8960",
192           .data = &msm_hdmi_phy_8960_cfg },
193         { .compatible = "qcom,hdmi-phy-8974",
194           .data = &msm_hdmi_phy_8x74_cfg },
195         { .compatible = "qcom,hdmi-phy-8084",
196           .data = &msm_hdmi_phy_8x74_cfg },
197         { .compatible = "qcom,hdmi-phy-8996",
198           .data = &msm_hdmi_phy_8996_cfg },
199         { .compatible = "qcom,hdmi-phy-8998",
200           .data = &msm_hdmi_phy_8998_cfg },
201         {}
202 };
203
204 static struct platform_driver msm_hdmi_phy_platform_driver = {
205         .probe      = msm_hdmi_phy_probe,
206         .remove     = msm_hdmi_phy_remove,
207         .driver     = {
208                 .name   = "msm_hdmi_phy",
209                 .of_match_table = msm_hdmi_phy_dt_match,
210         },
211 };
212
213 void __init msm_hdmi_phy_driver_register(void)
214 {
215         platform_driver_register(&msm_hdmi_phy_platform_driver);
216 }
217
218 void __exit msm_hdmi_phy_driver_unregister(void)
219 {
220         platform_driver_unregister(&msm_hdmi_phy_platform_driver);
221 }
This page took 0.040562 seconds and 4 git commands to generate.