1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2014-2023, The Linux Foundation. All rights reserved.
4 */
5
6#include <linux/clk.h>
7#include <linux/delay.h>
8#include <linux/err.h>
9#include <linux/io.h>
10#include <linux/kernel.h>
11#include <linux/module.h>
12#include <linux/of.h>
13#include <linux/phy/phy.h>
14#include <linux/platform_device.h>
15#include <linux/reset.h>
16#include <linux/slab.h>
17
18#define USB2PHY_PORT_UTMI_CTRL1 0x40
19
20#define USB2PHY_PORT_UTMI_CTRL2 0x44
21 #define UTMI_ULPI_SEL BIT(7)
22 #define UTMI_TEST_MUX_SEL BIT(6)
23
24#define HS_PHY_CTRL_REG 0x10
25 #define UTMI_OTG_VBUS_VALID BIT(20)
26 #define SW_SESSVLD_SEL BIT(28)
27
28#define USB_PHY_UTMI_CTRL0 0x3c
29
30#define USB_PHY_UTMI_CTRL5 0x50
31 #define POR_EN BIT(1)
32
33#define USB_PHY_HS_PHY_CTRL_COMMON0 0x54
34 #define COMMONONN BIT(7)
35 #define FSEL BIT(4)
36 #define RETENABLEN BIT(3)
37 #define FREQ_24MHZ (BIT(6) | BIT(4))
38
39#define USB_PHY_HS_PHY_CTRL2 0x64
40 #define USB2_SUSPEND_N_SEL BIT(3)
41 #define USB2_SUSPEND_N BIT(2)
42 #define USB2_UTMI_CLK_EN BIT(1)
43
44#define USB_PHY_CFG0 0x94
45 #define UTMI_PHY_OVERRIDE_EN BIT(1)
46
47#define USB_PHY_REFCLK_CTRL 0xa0
48 #define CLKCORE BIT(1)
49
50#define USB2PHY_PORT_POWERDOWN 0xa4
51 #define POWER_UP BIT(0)
52 #define POWER_DOWN 0
53
54#define USB_PHY_FSEL_SEL 0xb8
55 #define FREQ_SEL BIT(0)
56
57#define USB2PHY_USB_PHY_M31_XCFGI_1 0xbc
58 #define USB2_0_TX_ENABLE BIT(2)
59
60#define USB2PHY_USB_PHY_M31_XCFGI_4 0xc8
61 #define HSTX_SLEW_RATE_565PS GENMASK(1, 0)
62 #define PLL_CHARGING_PUMP_CURRENT_35UA GENMASK(4, 3)
63 #define ODT_VALUE_38_02_OHM GENMASK(7, 6)
64
65#define USB2PHY_USB_PHY_M31_XCFGI_5 0xcc
66 #define ODT_VALUE_45_02_OHM BIT(2)
67 #define HSTX_PRE_EMPHASIS_LEVEL_0_55MA BIT(0)
68
69#define USB2PHY_USB_PHY_M31_XCFGI_11 0xe4
70 #define XCFG_COARSE_TUNE_NUM BIT(1)
71 #define XCFG_FINE_TUNE_NUM BIT(3)
72
73struct m31_phy_regs {
74 u32 off;
75 u32 val;
76 u32 delay;
77};
78
79struct m31_priv_data {
80 bool ulpi_mode;
81 const struct m31_phy_regs *regs;
82 unsigned int nregs;
83};
84
85static const struct m31_phy_regs m31_ipq5018_regs[] = {
86 {
87 .off = USB_PHY_CFG0,
88 .val = UTMI_PHY_OVERRIDE_EN
89 },
90 {
91 .off = USB_PHY_UTMI_CTRL5,
92 .val = POR_EN,
93 .delay = 15
94 },
95 {
96 .off = USB_PHY_FSEL_SEL,
97 .val = FREQ_SEL
98 },
99 {
100 .off = USB_PHY_HS_PHY_CTRL_COMMON0,
101 .val = COMMONONN | FSEL | RETENABLEN
102 },
103 {
104 .off = USB_PHY_REFCLK_CTRL,
105 .val = CLKCORE
106 },
107 {
108 .off = USB_PHY_UTMI_CTRL5,
109 .val = POR_EN
110 },
111 {
112 .off = USB_PHY_HS_PHY_CTRL2,
113 .val = USB2_SUSPEND_N_SEL | USB2_SUSPEND_N | USB2_UTMI_CLK_EN
114 },
115 {
116 .off = USB_PHY_UTMI_CTRL5,
117 .val = 0x0
118 },
119 {
120 .off = USB_PHY_HS_PHY_CTRL2,
121 .val = USB2_SUSPEND_N | USB2_UTMI_CLK_EN
122 },
123 {
124 .off = USB_PHY_CFG0,
125 .val = 0x0
126 },
127};
128
129static struct m31_phy_regs m31_ipq5332_regs[] = {
130 {
131 USB_PHY_CFG0,
132 UTMI_PHY_OVERRIDE_EN,
133 0
134 },
135 {
136 USB_PHY_UTMI_CTRL5,
137 POR_EN,
138 15
139 },
140 {
141 USB_PHY_FSEL_SEL,
142 FREQ_SEL,
143 0
144 },
145 {
146 USB_PHY_HS_PHY_CTRL_COMMON0,
147 COMMONONN | FREQ_24MHZ | RETENABLEN,
148 0
149 },
150 {
151 USB_PHY_UTMI_CTRL5,
152 POR_EN,
153 0
154 },
155 {
156 USB_PHY_HS_PHY_CTRL2,
157 USB2_SUSPEND_N_SEL | USB2_SUSPEND_N | USB2_UTMI_CLK_EN,
158 0
159 },
160 {
161 USB2PHY_USB_PHY_M31_XCFGI_11,
162 XCFG_COARSE_TUNE_NUM | XCFG_FINE_TUNE_NUM,
163 0
164 },
165 {
166 USB2PHY_USB_PHY_M31_XCFGI_4,
167 HSTX_SLEW_RATE_565PS | PLL_CHARGING_PUMP_CURRENT_35UA | ODT_VALUE_38_02_OHM,
168 0
169 },
170 {
171 USB2PHY_USB_PHY_M31_XCFGI_1,
172 USB2_0_TX_ENABLE,
173 0
174 },
175 {
176 USB2PHY_USB_PHY_M31_XCFGI_5,
177 ODT_VALUE_45_02_OHM | HSTX_PRE_EMPHASIS_LEVEL_0_55MA,
178 4
179 },
180 {
181 USB_PHY_UTMI_CTRL5,
182 0x0,
183 0
184 },
185 {
186 USB_PHY_HS_PHY_CTRL2,
187 USB2_SUSPEND_N | USB2_UTMI_CLK_EN,
188 0
189 },
190};
191
192struct m31usb_phy {
193 struct phy *phy;
194 void __iomem *base;
195 const struct m31_phy_regs *regs;
196 int nregs;
197
198 struct regulator *vreg;
199 struct clk *clk;
200 struct reset_control *reset;
201
202 bool ulpi_mode;
203};
204
205static int m31usb_phy_init(struct phy *phy)
206{
207 struct m31usb_phy *qphy = phy_get_drvdata(phy);
208 const struct m31_phy_regs *regs = qphy->regs;
209 int i, ret;
210
211 ret = regulator_enable(regulator: qphy->vreg);
212 if (ret) {
213 dev_err(&phy->dev, "failed to enable regulator, %d\n", ret);
214 return ret;
215 }
216
217 ret = clk_prepare_enable(clk: qphy->clk);
218 if (ret) {
219 regulator_disable(regulator: qphy->vreg);
220 dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);
221 return ret;
222 }
223
224 /* Perform phy reset */
225 reset_control_assert(rstc: qphy->reset);
226 udelay(5);
227 reset_control_deassert(rstc: qphy->reset);
228
229 /* configure for ULPI mode if requested */
230 if (qphy->ulpi_mode)
231 writel(val: 0x0, addr: qphy->base + USB2PHY_PORT_UTMI_CTRL2);
232
233 /* Enable the PHY */
234 writel(POWER_UP, addr: qphy->base + USB2PHY_PORT_POWERDOWN);
235
236 /* Turn on phy ref clock */
237 for (i = 0; i < qphy->nregs; i++) {
238 writel(val: regs[i].val, addr: qphy->base + regs[i].off);
239 if (regs[i].delay)
240 udelay(regs[i].delay);
241 }
242
243 return 0;
244}
245
246static int m31usb_phy_shutdown(struct phy *phy)
247{
248 struct m31usb_phy *qphy = phy_get_drvdata(phy);
249
250 /* Disable the PHY */
251 writel_relaxed(POWER_DOWN, qphy->base + USB2PHY_PORT_POWERDOWN);
252
253 clk_disable_unprepare(clk: qphy->clk);
254
255 regulator_disable(regulator: qphy->vreg);
256
257 return 0;
258}
259
260static const struct phy_ops m31usb_phy_gen_ops = {
261 .power_on = m31usb_phy_init,
262 .power_off = m31usb_phy_shutdown,
263 .owner = THIS_MODULE,
264};
265
266static int m31usb_phy_probe(struct platform_device *pdev)
267{
268 struct phy_provider *phy_provider;
269 const struct m31_priv_data *data;
270 struct device *dev = &pdev->dev;
271 struct m31usb_phy *qphy;
272
273 qphy = devm_kzalloc(dev, size: sizeof(*qphy), GFP_KERNEL);
274 if (!qphy)
275 return -ENOMEM;
276
277 qphy->base = devm_platform_ioremap_resource(pdev, index: 0);
278 if (IS_ERR(ptr: qphy->base))
279 return PTR_ERR(ptr: qphy->base);
280
281 qphy->reset = devm_reset_control_get_exclusive_by_index(dev, index: 0);
282 if (IS_ERR(ptr: qphy->reset))
283 return PTR_ERR(ptr: qphy->reset);
284
285 qphy->clk = devm_clk_get(dev, NULL);
286 if (IS_ERR(ptr: qphy->clk))
287 return dev_err_probe(dev, err: PTR_ERR(ptr: qphy->clk),
288 fmt: "failed to get clk\n");
289
290 data = of_device_get_match_data(dev);
291 qphy->regs = data->regs;
292 qphy->nregs = data->nregs;
293 qphy->ulpi_mode = data->ulpi_mode;
294
295 qphy->phy = devm_phy_create(dev, NULL, ops: &m31usb_phy_gen_ops);
296 if (IS_ERR(ptr: qphy->phy))
297 return dev_err_probe(dev, err: PTR_ERR(ptr: qphy->phy),
298 fmt: "failed to create phy\n");
299
300 qphy->vreg = devm_regulator_get(dev, id: "vdda-phy");
301 if (IS_ERR(ptr: qphy->vreg))
302 return dev_err_probe(dev, err: PTR_ERR(ptr: qphy->vreg),
303 fmt: "failed to get vreg\n");
304
305 phy_set_drvdata(phy: qphy->phy, data: qphy);
306
307 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
308 if (!IS_ERR(ptr: phy_provider))
309 dev_info(dev, "Registered M31 USB phy\n");
310
311 return PTR_ERR_OR_ZERO(ptr: phy_provider);
312}
313
314static const struct m31_priv_data m31_ipq5018_data = {
315 .ulpi_mode = false,
316 .regs = m31_ipq5018_regs,
317 .nregs = ARRAY_SIZE(m31_ipq5018_regs),
318};
319
320static const struct m31_priv_data m31_ipq5332_data = {
321 .ulpi_mode = false,
322 .regs = m31_ipq5332_regs,
323 .nregs = ARRAY_SIZE(m31_ipq5332_regs),
324};
325
326static const struct of_device_id m31usb_phy_id_table[] = {
327 { .compatible = "qcom,ipq5018-usb-hsphy", .data = &m31_ipq5018_data },
328 { .compatible = "qcom,ipq5332-usb-hsphy", .data = &m31_ipq5332_data },
329 { },
330};
331MODULE_DEVICE_TABLE(of, m31usb_phy_id_table);
332
333static struct platform_driver m31usb_phy_driver = {
334 .probe = m31usb_phy_probe,
335 .driver = {
336 .name = "qcom-m31usb-phy",
337 .of_match_table = m31usb_phy_id_table,
338 },
339};
340
341module_platform_driver(m31usb_phy_driver);
342
343MODULE_DESCRIPTION("USB2 Qualcomm M31 HSPHY driver");
344MODULE_LICENSE("GPL");
345

source code of linux/drivers/phy/qualcomm/phy-qcom-m31.c