aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchunhui dai <chunhui.dai@mediatek.com>2018-10-02 23:41:47 -0400
committerCK Hu <ck.hu@mediatek.com>2018-10-02 23:56:32 -0400
commitbe28b6507c46050f5b7244d9d98a19c03b9cf074 (patch)
tree4fdd9687ee93c513674bdb5728b7fee0396442ea
parentd08b5ab972449b0ab494600fa985979e91e090ca (diff)
drm/mediatek: separate hdmi phy to different file
Different IC has different phy setting of HDMI. This patch separates the phy hardware relate part for mt8173. Signed-off-by: chunhui dai <chunhui.dai@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com>
-rw-r--r--drivers/gpu/drm/mediatek/Makefile6
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi.c1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi.h2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi_phy.c232
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi_phy.h58
-rw-r--r--drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c226
6 files changed, 302 insertions, 223 deletions
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index ce83c396a742..61cf0d2ab28a 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -1,4 +1,5 @@
1# SPDX-License-Identifier: GPL-2.0 1# SPDX-License-Identifier: GPL-2.0
2
2mediatek-drm-y := mtk_disp_color.o \ 3mediatek-drm-y := mtk_disp_color.o \
3 mtk_disp_ovl.o \ 4 mtk_disp_ovl.o \
4 mtk_disp_rdma.o \ 5 mtk_disp_rdma.o \
@@ -18,6 +19,7 @@ obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o
18mediatek-drm-hdmi-objs := mtk_cec.o \ 19mediatek-drm-hdmi-objs := mtk_cec.o \
19 mtk_hdmi.o \ 20 mtk_hdmi.o \
20 mtk_hdmi_ddc.o \ 21 mtk_hdmi_ddc.o \
21 mtk_mt8173_hdmi_phy.o 22 mtk_mt8173_hdmi_phy.o \
23 mtk_hdmi_phy.o
22 24
23obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o 25obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o \ No newline at end of file
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index 2d45d1dd9554..2ca9f6a64dab 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -233,6 +233,7 @@ static void mtk_hdmi_hw_vid_black(struct mtk_hdmi *hdmi, bool black)
233static void mtk_hdmi_hw_make_reg_writable(struct mtk_hdmi *hdmi, bool enable) 233static void mtk_hdmi_hw_make_reg_writable(struct mtk_hdmi *hdmi, bool enable)
234{ 234{
235 struct arm_smccc_res res; 235 struct arm_smccc_res res;
236 struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(hdmi->phy);
236 237
237 /* 238 /*
238 * MT8173 HDMI hardware has an output control bit to enable/disable HDMI 239 * MT8173 HDMI hardware has an output control bit to enable/disable HDMI
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.h b/drivers/gpu/drm/mediatek/mtk_hdmi.h
index 6371b3de1ff6..3e9fb8d19802 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.h
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.h
@@ -13,11 +13,11 @@
13 */ 13 */
14#ifndef _MTK_HDMI_CTRL_H 14#ifndef _MTK_HDMI_CTRL_H
15#define _MTK_HDMI_CTRL_H 15#define _MTK_HDMI_CTRL_H
16#include "mtk_hdmi_phy.h"
16 17
17struct platform_driver; 18struct platform_driver;
18 19
19extern struct platform_driver mtk_cec_driver; 20extern struct platform_driver mtk_cec_driver;
20extern struct platform_driver mtk_hdmi_ddc_driver; 21extern struct platform_driver mtk_hdmi_ddc_driver;
21extern struct platform_driver mtk_hdmi_phy_driver;
22 22
23#endif /* _MTK_HDMI_CTRL_H */ 23#endif /* _MTK_HDMI_CTRL_H */
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c
new file mode 100644
index 000000000000..514f3e9a8767
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c
@@ -0,0 +1,232 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2018 MediaTek Inc.
4 * Author: Jie Qiu <jie.qiu@mediatek.com>
5 */
6
7#include "mtk_hdmi_phy.h"
8
9static int mtk_hdmi_phy_power_on(struct phy *phy);
10static int mtk_hdmi_phy_power_off(struct phy *phy);
11
12static const struct phy_ops mtk_hdmi_phy_dev_ops = {
13 .power_on = mtk_hdmi_phy_power_on,
14 .power_off = mtk_hdmi_phy_power_off,
15 .owner = THIS_MODULE,
16};
17
18long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate,
19 unsigned long *parent_rate)
20{
21 struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
22
23 hdmi_phy->pll_rate = rate;
24 if (rate <= 74250000)
25 *parent_rate = rate;
26 else
27 *parent_rate = rate / 2;
28
29 return rate;
30}
31
32unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw,
33 unsigned long parent_rate)
34{
35 struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
36
37 return hdmi_phy->pll_rate;
38}
39
40void mtk_hdmi_phy_clear_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset,
41 u32 bits)
42{
43 void __iomem *reg = hdmi_phy->regs + offset;
44 u32 tmp;
45
46 tmp = readl(reg);
47 tmp &= ~bits;
48 writel(tmp, reg);
49}
50
51void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset,
52 u32 bits)
53{
54 void __iomem *reg = hdmi_phy->regs + offset;
55 u32 tmp;
56
57 tmp = readl(reg);
58 tmp |= bits;
59 writel(tmp, reg);
60}
61
62void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset,
63 u32 val, u32 mask)
64{
65 void __iomem *reg = hdmi_phy->regs + offset;
66 u32 tmp;
67
68 tmp = readl(reg);
69 tmp = (tmp & ~mask) | (val & mask);
70 writel(tmp, reg);
71}
72
73inline struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw)
74{
75 return container_of(hw, struct mtk_hdmi_phy, pll_hw);
76}
77
78static int mtk_hdmi_phy_power_on(struct phy *phy)
79{
80 struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
81 int ret;
82
83 ret = clk_prepare_enable(hdmi_phy->pll);
84 if (ret < 0)
85 return ret;
86
87 hdmi_phy->conf->hdmi_phy_enable_tmds(hdmi_phy);
88 return 0;
89}
90
91static int mtk_hdmi_phy_power_off(struct phy *phy)
92{
93 struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
94
95 hdmi_phy->conf->hdmi_phy_disable_tmds(hdmi_phy);
96 clk_disable_unprepare(hdmi_phy->pll);
97
98 return 0;
99}
100
101static const struct phy_ops *
102mtk_hdmi_phy_dev_get_ops(const struct mtk_hdmi_phy *hdmi_phy)
103{
104 if (hdmi_phy && hdmi_phy->conf &&
105 hdmi_phy->conf->hdmi_phy_enable_tmds &&
106 hdmi_phy->conf->hdmi_phy_disable_tmds)
107 return &mtk_hdmi_phy_dev_ops;
108
109 dev_err(hdmi_phy->dev, "Failed to get dev ops of phy\n");
110 return NULL;
111}
112
113static void mtk_hdmi_phy_clk_get_ops(struct mtk_hdmi_phy *hdmi_phy,
114 const struct clk_ops **ops)
115{
116 if (hdmi_phy && hdmi_phy->conf && hdmi_phy->conf->hdmi_phy_clk_ops)
117 *ops = hdmi_phy->conf->hdmi_phy_clk_ops;
118 else
119 dev_err(hdmi_phy->dev, "Failed to get clk ops of phy\n");
120}
121
122static int mtk_hdmi_phy_probe(struct platform_device *pdev)
123{
124 struct device *dev = &pdev->dev;
125 struct mtk_hdmi_phy *hdmi_phy;
126 struct resource *mem;
127 struct clk *ref_clk;
128 const char *ref_clk_name;
129 struct clk_init_data clk_init = {
130 .num_parents = 1,
131 .parent_names = (const char * const *)&ref_clk_name,
132 .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE,
133 };
134
135 struct phy *phy;
136 struct phy_provider *phy_provider;
137 int ret;
138
139 hdmi_phy = devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL);
140 if (!hdmi_phy)
141 return -ENOMEM;
142
143 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
144 hdmi_phy->regs = devm_ioremap_resource(dev, mem);
145 if (IS_ERR(hdmi_phy->regs)) {
146 ret = PTR_ERR(hdmi_phy->regs);
147 dev_err(dev, "Failed to get memory resource: %d\n", ret);
148 return ret;
149 }
150
151 ref_clk = devm_clk_get(dev, "pll_ref");
152 if (IS_ERR(ref_clk)) {
153 ret = PTR_ERR(ref_clk);
154 dev_err(&pdev->dev, "Failed to get PLL reference clock: %d\n",
155 ret);
156 return ret;
157 }
158 ref_clk_name = __clk_get_name(ref_clk);
159
160 ret = of_property_read_string(dev->of_node, "clock-output-names",
161 &clk_init.name);
162 if (ret < 0) {
163 dev_err(dev, "Failed to read clock-output-names: %d\n", ret);
164 return ret;
165 }
166
167 hdmi_phy->dev = dev;
168 hdmi_phy->conf =
169 (struct mtk_hdmi_phy_conf *)of_device_get_match_data(dev);
170 mtk_hdmi_phy_clk_get_ops(hdmi_phy, &clk_init.ops);
171 hdmi_phy->pll_hw.init = &clk_init;
172 hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw);
173 if (IS_ERR(hdmi_phy->pll)) {
174 ret = PTR_ERR(hdmi_phy->pll);
175 dev_err(dev, "Failed to register PLL: %d\n", ret);
176 return ret;
177 }
178
179 ret = of_property_read_u32(dev->of_node, "mediatek,ibias",
180 &hdmi_phy->ibias);
181 if (ret < 0) {
182 dev_err(&pdev->dev, "Failed to get ibias: %d\n", ret);
183 return ret;
184 }
185
186 ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up",
187 &hdmi_phy->ibias_up);
188 if (ret < 0) {
189 dev_err(&pdev->dev, "Failed to get ibias up: %d\n", ret);
190 return ret;
191 }
192
193 dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n");
194 hdmi_phy->drv_imp_clk = 0x30;
195 hdmi_phy->drv_imp_d2 = 0x30;
196 hdmi_phy->drv_imp_d1 = 0x30;
197 hdmi_phy->drv_imp_d0 = 0x30;
198
199 phy = devm_phy_create(dev, NULL, mtk_hdmi_phy_dev_get_ops(hdmi_phy));
200 if (IS_ERR(phy)) {
201 dev_err(dev, "Failed to create HDMI PHY\n");
202 return PTR_ERR(phy);
203 }
204 phy_set_drvdata(phy, hdmi_phy);
205
206 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
207 if (IS_ERR(phy_provider)) {
208 dev_err(dev, "Failed to register HDMI PHY\n");
209 return PTR_ERR(phy_provider);
210 }
211
212 return of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
213 hdmi_phy->pll);
214}
215
216static const struct of_device_id mtk_hdmi_phy_match[] = {
217 { .compatible = "mediatek,mt8173-hdmi-phy",
218 .data = &mtk_hdmi_phy_8173_conf,
219 },
220 {},
221};
222
223struct platform_driver mtk_hdmi_phy_driver = {
224 .probe = mtk_hdmi_phy_probe,
225 .driver = {
226 .name = "mediatek-hdmi-phy",
227 .of_match_table = mtk_hdmi_phy_match,
228 },
229};
230
231MODULE_DESCRIPTION("MediaTek HDMI PHY Driver");
232MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h
new file mode 100644
index 000000000000..09b8f525e6b8
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h
@@ -0,0 +1,58 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Copyright (c) 2018 MediaTek Inc.
4 * Author: Chunhui Dai <chunhui.dai@mediatek.com>
5 */
6
7#ifndef _MTK_HDMI_PHY_H
8#define _MTK_HDMI_PHY_H
9#include <linux/clk.h>
10#include <linux/clk-provider.h>
11#include <linux/delay.h>
12#include <linux/io.h>
13#include <linux/mfd/syscon.h>
14#include <linux/module.h>
15#include <linux/of_device.h>
16#include <linux/phy/phy.h>
17#include <linux/platform_device.h>
18#include <linux/types.h>
19
20struct mtk_hdmi_phy;
21
22struct mtk_hdmi_phy_conf {
23 const struct clk_ops *hdmi_phy_clk_ops;
24 void (*hdmi_phy_enable_tmds)(struct mtk_hdmi_phy *hdmi_phy);
25 void (*hdmi_phy_disable_tmds)(struct mtk_hdmi_phy *hdmi_phy);
26};
27
28struct mtk_hdmi_phy {
29 void __iomem *regs;
30 struct device *dev;
31 struct mtk_hdmi_phy_conf *conf;
32 struct clk *pll;
33 struct clk_hw pll_hw;
34 unsigned long pll_rate;
35 unsigned char drv_imp_clk;
36 unsigned char drv_imp_d2;
37 unsigned char drv_imp_d1;
38 unsigned char drv_imp_d0;
39 unsigned int ibias;
40 unsigned int ibias_up;
41};
42
43void mtk_hdmi_phy_clear_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset,
44 u32 bits);
45void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset,
46 u32 bits);
47void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset,
48 u32 val, u32 mask);
49struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw);
50long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate,
51 unsigned long *parent_rate);
52unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw,
53 unsigned long parent_rate);
54
55extern struct platform_driver mtk_hdmi_phy_driver;
56extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf;
57
58#endif /* _MTK_HDMI_PHY_H */
diff --git a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
index 51cb9cfb6646..ed5916b27658 100644
--- a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
+++ b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
@@ -12,15 +12,7 @@
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 */ 13 */
14 14
15#include <linux/clk.h> 15#include "mtk_hdmi_phy.h"
16#include <linux/clk-provider.h>
17#include <linux/delay.h>
18#include <linux/io.h>
19#include <linux/mfd/syscon.h>
20#include <linux/module.h>
21#include <linux/phy/phy.h>
22#include <linux/platform_device.h>
23#include <linux/types.h>
24 16
25#define HDMI_CON0 0x00 17#define HDMI_CON0 0x00
26#define RG_HDMITX_PLL_EN BIT(31) 18#define RG_HDMITX_PLL_EN BIT(31)
@@ -123,20 +115,6 @@
123#define RGS_HDMITX_5T1_EDG (0xf << 4) 115#define RGS_HDMITX_5T1_EDG (0xf << 4)
124#define RGS_HDMITX_PLUG_TST BIT(0) 116#define RGS_HDMITX_PLUG_TST BIT(0)
125 117
126struct mtk_hdmi_phy {
127 void __iomem *regs;
128 struct device *dev;
129 struct clk *pll;
130 struct clk_hw pll_hw;
131 unsigned long pll_rate;
132 u8 drv_imp_clk;
133 u8 drv_imp_d2;
134 u8 drv_imp_d1;
135 u8 drv_imp_d0;
136 u32 ibias;
137 u32 ibias_up;
138};
139
140static const u8 PREDIV[3][4] = { 118static const u8 PREDIV[3][4] = {
141 {0x0, 0x0, 0x0, 0x0}, /* 27Mhz */ 119 {0x0, 0x0, 0x0, 0x0}, /* 27Mhz */
142 {0x1, 0x1, 0x1, 0x1}, /* 74Mhz */ 120 {0x1, 0x1, 0x1, 0x1}, /* 74Mhz */
@@ -185,44 +163,6 @@ static const u8 HTPLLBR[3][4] = {
185 {0x1, 0x2, 0x2, 0x1} /* 148Mhz */ 163 {0x1, 0x2, 0x2, 0x1} /* 148Mhz */
186}; 164};
187 165
188static void mtk_hdmi_phy_clear_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset,
189 u32 bits)
190{
191 void __iomem *reg = hdmi_phy->regs + offset;
192 u32 tmp;
193
194 tmp = readl(reg);
195 tmp &= ~bits;
196 writel(tmp, reg);
197}
198
199static void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset,
200 u32 bits)
201{
202 void __iomem *reg = hdmi_phy->regs + offset;
203 u32 tmp;
204
205 tmp = readl(reg);
206 tmp |= bits;
207 writel(tmp, reg);
208}
209
210static void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset,
211 u32 val, u32 mask)
212{
213 void __iomem *reg = hdmi_phy->regs + offset;
214 u32 tmp;
215
216 tmp = readl(reg);
217 tmp = (tmp & ~mask) | (val & mask);
218 writel(tmp, reg);
219}
220
221static inline struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw)
222{
223 return container_of(hw, struct mtk_hdmi_phy, pll_hw);
224}
225
226static int mtk_hdmi_pll_prepare(struct clk_hw *hw) 166static int mtk_hdmi_pll_prepare(struct clk_hw *hw)
227{ 167{
228 struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); 168 struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
@@ -345,29 +285,7 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
345 return 0; 285 return 0;
346} 286}
347 287
348static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, 288static const struct clk_ops mtk_hdmi_phy_pll_ops = {
349 unsigned long *parent_rate)
350{
351 struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
352
353 hdmi_phy->pll_rate = rate;
354 if (rate <= 74250000)
355 *parent_rate = rate;
356 else
357 *parent_rate = rate / 2;
358
359 return rate;
360}
361
362static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw,
363 unsigned long parent_rate)
364{
365 struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
366
367 return hdmi_phy->pll_rate;
368}
369
370static const struct clk_ops mtk_hdmi_pll_ops = {
371 .prepare = mtk_hdmi_pll_prepare, 289 .prepare = mtk_hdmi_pll_prepare,
372 .unprepare = mtk_hdmi_pll_unprepare, 290 .unprepare = mtk_hdmi_pll_unprepare,
373 .set_rate = mtk_hdmi_pll_set_rate, 291 .set_rate = mtk_hdmi_pll_set_rate,
@@ -390,142 +308,10 @@ static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy)
390 RG_HDMITX_SER_EN); 308 RG_HDMITX_SER_EN);
391} 309}
392 310
393static int mtk_hdmi_phy_power_on(struct phy *phy) 311struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf = {
394{ 312 .hdmi_phy_clk_ops = &mtk_hdmi_phy_pll_ops,
395 struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy); 313 .hdmi_phy_enable_tmds = mtk_hdmi_phy_enable_tmds,
396 int ret; 314 .hdmi_phy_disable_tmds = mtk_hdmi_phy_disable_tmds,
397
398 ret = clk_prepare_enable(hdmi_phy->pll);
399 if (ret < 0)
400 return ret;
401
402 mtk_hdmi_phy_enable_tmds(hdmi_phy);
403
404 return 0;
405}
406
407static int mtk_hdmi_phy_power_off(struct phy *phy)
408{
409 struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
410
411 mtk_hdmi_phy_disable_tmds(hdmi_phy);
412 clk_disable_unprepare(hdmi_phy->pll);
413
414 return 0;
415}
416
417static const struct phy_ops mtk_hdmi_phy_ops = {
418 .power_on = mtk_hdmi_phy_power_on,
419 .power_off = mtk_hdmi_phy_power_off,
420 .owner = THIS_MODULE,
421};
422
423static int mtk_hdmi_phy_probe(struct platform_device *pdev)
424{
425 struct device *dev = &pdev->dev;
426 struct mtk_hdmi_phy *hdmi_phy;
427 struct resource *mem;
428 struct clk *ref_clk;
429 const char *ref_clk_name;
430 struct clk_init_data clk_init = {
431 .ops = &mtk_hdmi_pll_ops,
432 .num_parents = 1,
433 .parent_names = (const char * const *)&ref_clk_name,
434 .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE,
435 };
436 struct phy *phy;
437 struct phy_provider *phy_provider;
438 int ret;
439
440 hdmi_phy = devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL);
441 if (!hdmi_phy)
442 return -ENOMEM;
443
444 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
445 hdmi_phy->regs = devm_ioremap_resource(dev, mem);
446 if (IS_ERR(hdmi_phy->regs)) {
447 ret = PTR_ERR(hdmi_phy->regs);
448 dev_err(dev, "Failed to get memory resource: %d\n", ret);
449 return ret;
450 }
451
452 ref_clk = devm_clk_get(dev, "pll_ref");
453 if (IS_ERR(ref_clk)) {
454 ret = PTR_ERR(ref_clk);
455 dev_err(&pdev->dev, "Failed to get PLL reference clock: %d\n",
456 ret);
457 return ret;
458 }
459 ref_clk_name = __clk_get_name(ref_clk);
460
461 ret = of_property_read_string(dev->of_node, "clock-output-names",
462 &clk_init.name);
463 if (ret < 0) {
464 dev_err(dev, "Failed to read clock-output-names: %d\n", ret);
465 return ret;
466 }
467
468 hdmi_phy->pll_hw.init = &clk_init;
469 hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw);
470 if (IS_ERR(hdmi_phy->pll)) {
471 ret = PTR_ERR(hdmi_phy->pll);
472 dev_err(dev, "Failed to register PLL: %d\n", ret);
473 return ret;
474 }
475
476 ret = of_property_read_u32(dev->of_node, "mediatek,ibias",
477 &hdmi_phy->ibias);
478 if (ret < 0) {
479 dev_err(&pdev->dev, "Failed to get ibias: %d\n", ret);
480 return ret;
481 }
482
483 ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up",
484 &hdmi_phy->ibias_up);
485 if (ret < 0) {
486 dev_err(&pdev->dev, "Failed to get ibias up: %d\n", ret);
487 return ret;
488 }
489
490 dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n");
491 hdmi_phy->drv_imp_clk = 0x30;
492 hdmi_phy->drv_imp_d2 = 0x30;
493 hdmi_phy->drv_imp_d1 = 0x30;
494 hdmi_phy->drv_imp_d0 = 0x30;
495
496 phy = devm_phy_create(dev, NULL, &mtk_hdmi_phy_ops);
497 if (IS_ERR(phy)) {
498 dev_err(dev, "Failed to create HDMI PHY\n");
499 return PTR_ERR(phy);
500 }
501 phy_set_drvdata(phy, hdmi_phy);
502
503 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
504 if (IS_ERR(phy_provider))
505 return PTR_ERR(phy_provider);
506
507 hdmi_phy->dev = dev;
508 return of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
509 hdmi_phy->pll);
510}
511
512static int mtk_hdmi_phy_remove(struct platform_device *pdev)
513{
514 return 0;
515}
516
517static const struct of_device_id mtk_hdmi_phy_match[] = {
518 { .compatible = "mediatek,mt8173-hdmi-phy", },
519 {},
520};
521
522struct platform_driver mtk_hdmi_phy_driver = {
523 .probe = mtk_hdmi_phy_probe,
524 .remove = mtk_hdmi_phy_remove,
525 .driver = {
526 .name = "mediatek-hdmi-phy",
527 .of_match_table = mtk_hdmi_phy_match,
528 },
529}; 315};
530 316
531MODULE_AUTHOR("Jie Qiu <jie.qiu@mediatek.com>"); 317MODULE_AUTHOR("Jie Qiu <jie.qiu@mediatek.com>");