1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Ingenic SoCs USB PHY driver
4  * Copyright (c) Paul Cercueil <paul@crapouillou.net>
5  * Copyright (c) 漆鹏振 (Qi Pengzhen) <aric.pzqi@ingenic.com>
6  * Copyright (c) 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
7  */
8 
9 #include <linux/bitfield.h>
10 #include <linux/clk.h>
11 #include <linux/delay.h>
12 #include <linux/io.h>
13 #include <linux/module.h>
14 #include <linux/phy/phy.h>
15 #include <linux/platform_device.h>
16 #include <linux/regulator/consumer.h>
17 
18 /* OTGPHY register offsets */
19 #define REG_USBPCR_OFFSET			0x00
20 #define REG_USBRDT_OFFSET			0x04
21 #define REG_USBVBFIL_OFFSET			0x08
22 #define REG_USBPCR1_OFFSET			0x0c
23 
24 /* bits within the USBPCR register */
25 #define USBPCR_USB_MODE				BIT(31)
26 #define USBPCR_AVLD_REG				BIT(30)
27 #define USBPCR_COMMONONN			BIT(25)
28 #define USBPCR_VBUSVLDEXT			BIT(24)
29 #define USBPCR_VBUSVLDEXTSEL		BIT(23)
30 #define USBPCR_POR					BIT(22)
31 #define USBPCR_SIDDQ				BIT(21)
32 #define USBPCR_OTG_DISABLE			BIT(20)
33 #define USBPCR_TXPREEMPHTUNE		BIT(6)
34 
35 #define USBPCR_IDPULLUP_MASK		GENMASK(29, 28)
36 #define USBPCR_IDPULLUP_ALWAYS		0x2
37 #define USBPCR_IDPULLUP_SUSPEND		0x1
38 #define USBPCR_IDPULLUP_OTG			0x0
39 
40 #define USBPCR_COMPDISTUNE_MASK		GENMASK(19, 17)
41 #define USBPCR_COMPDISTUNE_DFT		0x4
42 
43 #define USBPCR_OTGTUNE_MASK			GENMASK(16, 14)
44 #define USBPCR_OTGTUNE_DFT			0x4
45 
46 #define USBPCR_SQRXTUNE_MASK		GENMASK(13, 11)
47 #define USBPCR_SQRXTUNE_DCR_20PCT	0x7
48 #define USBPCR_SQRXTUNE_DFT			0x3
49 
50 #define USBPCR_TXFSLSTUNE_MASK		GENMASK(10, 7)
51 #define USBPCR_TXFSLSTUNE_DCR_50PPT	0xf
52 #define USBPCR_TXFSLSTUNE_DCR_25PPT	0x7
53 #define USBPCR_TXFSLSTUNE_DFT		0x3
54 #define USBPCR_TXFSLSTUNE_INC_25PPT	0x1
55 #define USBPCR_TXFSLSTUNE_INC_50PPT	0x0
56 
57 #define USBPCR_TXHSXVTUNE_MASK		GENMASK(5, 4)
58 #define USBPCR_TXHSXVTUNE_DFT		0x3
59 #define USBPCR_TXHSXVTUNE_DCR_15MV	0x1
60 
61 #define USBPCR_TXRISETUNE_MASK		GENMASK(5, 4)
62 #define USBPCR_TXRISETUNE_DFT		0x3
63 
64 #define USBPCR_TXVREFTUNE_MASK		GENMASK(3, 0)
65 #define USBPCR_TXVREFTUNE_INC_75PPT	0xb
66 #define USBPCR_TXVREFTUNE_INC_25PPT	0x7
67 #define USBPCR_TXVREFTUNE_DFT		0x5
68 
69 /* bits within the USBRDTR register */
70 #define USBRDT_UTMI_RST				BIT(27)
71 #define USBRDT_HB_MASK				BIT(26)
72 #define USBRDT_VBFIL_LD_EN			BIT(25)
73 #define USBRDT_IDDIG_EN				BIT(24)
74 #define USBRDT_IDDIG_REG			BIT(23)
75 #define USBRDT_VBFIL_EN				BIT(2)
76 
77 /* bits within the USBPCR1 register */
78 #define USBPCR1_BVLD_REG			BIT(31)
79 #define USBPCR1_DPPD				BIT(29)
80 #define USBPCR1_DMPD				BIT(28)
81 #define USBPCR1_USB_SEL				BIT(28)
82 #define USBPCR1_PORT_RST			BIT(21)
83 #define USBPCR1_WORD_IF_16BIT		BIT(19)
84 
85 enum ingenic_usb_phy_version {
86 	ID_JZ4770,
87 	ID_JZ4775,
88 	ID_JZ4780,
89 	ID_X1000,
90 	ID_X1830,
91 	ID_X2000,
92 };
93 
94 struct ingenic_soc_info {
95 	enum ingenic_usb_phy_version version;
96 
97 	void (*usb_phy_init)(struct phy *phy);
98 };
99 
100 struct ingenic_usb_phy {
101 	const struct ingenic_soc_info *soc_info;
102 
103 	struct phy *phy;
104 	void __iomem *base;
105 	struct clk *clk;
106 	struct regulator *vcc_supply;
107 };
108 
109 static int ingenic_usb_phy_init(struct phy *phy)
110 {
111 	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
112 	int err;
113 	u32 reg;
114 
115 	err = clk_prepare_enable(priv->clk);
116 	if (err) {
117 		dev_err(&phy->dev, "Unable to start clock: %d\n", err);
118 		return err;
119 	}
120 
121 	priv->soc_info->usb_phy_init(phy);
122 
123 	/* Wait for PHY to reset */
124 	usleep_range(30, 300);
125 	reg = readl(priv->base + REG_USBPCR_OFFSET);
126 	writel(reg & ~USBPCR_POR, priv->base + REG_USBPCR_OFFSET);
127 	usleep_range(300, 1000);
128 
129 	return 0;
130 }
131 
132 static int ingenic_usb_phy_exit(struct phy *phy)
133 {
134 	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
135 
136 	clk_disable_unprepare(priv->clk);
137 	regulator_disable(priv->vcc_supply);
138 
139 	return 0;
140 }
141 
142 static int ingenic_usb_phy_power_on(struct phy *phy)
143 {
144 	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
145 	int err;
146 
147 	err = regulator_enable(priv->vcc_supply);
148 	if (err) {
149 		dev_err(&phy->dev, "Unable to enable VCC: %d\n", err);
150 		return err;
151 	}
152 
153 	return 0;
154 }
155 
156 static int ingenic_usb_phy_power_off(struct phy *phy)
157 {
158 	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
159 
160 	regulator_disable(priv->vcc_supply);
161 
162 	return 0;
163 }
164 
165 static int ingenic_usb_phy_set_mode(struct phy *phy,
166 				  enum phy_mode mode, int submode)
167 {
168 	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
169 	u32 reg;
170 
171 	switch (mode) {
172 	case PHY_MODE_USB_HOST:
173 		reg = readl(priv->base + REG_USBPCR_OFFSET);
174 		u32p_replace_bits(&reg, 1, USBPCR_USB_MODE);
175 		u32p_replace_bits(&reg, 0, USBPCR_VBUSVLDEXT);
176 		u32p_replace_bits(&reg, 0, USBPCR_VBUSVLDEXTSEL);
177 		u32p_replace_bits(&reg, 0, USBPCR_OTG_DISABLE);
178 		writel(reg, priv->base + REG_USBPCR_OFFSET);
179 
180 		break;
181 	case PHY_MODE_USB_DEVICE:
182 		reg = readl(priv->base + REG_USBPCR_OFFSET);
183 		u32p_replace_bits(&reg, 0, USBPCR_USB_MODE);
184 		u32p_replace_bits(&reg, 1, USBPCR_VBUSVLDEXT);
185 		u32p_replace_bits(&reg, 1, USBPCR_VBUSVLDEXTSEL);
186 		u32p_replace_bits(&reg, 1, USBPCR_OTG_DISABLE);
187 		writel(reg, priv->base + REG_USBPCR_OFFSET);
188 
189 		break;
190 	case PHY_MODE_USB_OTG:
191 		reg = readl(priv->base + REG_USBPCR_OFFSET);
192 		u32p_replace_bits(&reg, 1, USBPCR_USB_MODE);
193 		u32p_replace_bits(&reg, 1, USBPCR_VBUSVLDEXT);
194 		u32p_replace_bits(&reg, 1, USBPCR_VBUSVLDEXTSEL);
195 		u32p_replace_bits(&reg, 0, USBPCR_OTG_DISABLE);
196 		writel(reg, priv->base + REG_USBPCR_OFFSET);
197 
198 		break;
199 	default:
200 		return -EINVAL;
201 	}
202 
203 	return 0;
204 }
205 
206 static const struct phy_ops ingenic_usb_phy_ops = {
207 	.init		= ingenic_usb_phy_init,
208 	.exit		= ingenic_usb_phy_exit,
209 	.power_on	= ingenic_usb_phy_power_on,
210 	.power_off	= ingenic_usb_phy_power_off,
211 	.set_mode	= ingenic_usb_phy_set_mode,
212 	.owner		= THIS_MODULE,
213 };
214 
215 static void jz4770_usb_phy_init(struct phy *phy)
216 {
217 	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
218 	u32 reg;
219 
220 	reg = USBPCR_AVLD_REG | USBPCR_COMMONONN | USBPCR_POR |
221 		FIELD_PREP(USBPCR_IDPULLUP_MASK, USBPCR_IDPULLUP_ALWAYS) |
222 		FIELD_PREP(USBPCR_COMPDISTUNE_MASK, USBPCR_COMPDISTUNE_DFT) |
223 		FIELD_PREP(USBPCR_OTGTUNE_MASK, USBPCR_OTGTUNE_DFT) |
224 		FIELD_PREP(USBPCR_SQRXTUNE_MASK, USBPCR_SQRXTUNE_DFT) |
225 		FIELD_PREP(USBPCR_TXFSLSTUNE_MASK, USBPCR_TXFSLSTUNE_DFT) |
226 		FIELD_PREP(USBPCR_TXRISETUNE_MASK, USBPCR_TXRISETUNE_DFT) |
227 		FIELD_PREP(USBPCR_TXVREFTUNE_MASK, USBPCR_TXVREFTUNE_DFT);
228 	writel(reg, priv->base + REG_USBPCR_OFFSET);
229 }
230 
231 static void jz4775_usb_phy_init(struct phy *phy)
232 {
233 	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
234 	u32 reg;
235 
236 	reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_USB_SEL |
237 		USBPCR1_WORD_IF_16BIT;
238 	writel(reg, priv->base + REG_USBPCR1_OFFSET);
239 
240 	reg = USBPCR_COMMONONN | USBPCR_POR |
241 		FIELD_PREP(USBPCR_TXVREFTUNE_MASK, USBPCR_TXVREFTUNE_INC_75PPT);
242 	writel(reg, priv->base + REG_USBPCR_OFFSET);
243 }
244 
245 static void jz4780_usb_phy_init(struct phy *phy)
246 {
247 	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
248 	u32 reg;
249 
250 	reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_USB_SEL |
251 		USBPCR1_WORD_IF_16BIT;
252 	writel(reg, priv->base + REG_USBPCR1_OFFSET);
253 
254 	reg = USBPCR_TXPREEMPHTUNE | USBPCR_COMMONONN | USBPCR_POR;
255 	writel(reg, priv->base + REG_USBPCR_OFFSET);
256 }
257 
258 static void x1000_usb_phy_init(struct phy *phy)
259 {
260 	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
261 	u32 reg;
262 
263 	reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_WORD_IF_16BIT;
264 	writel(reg, priv->base + REG_USBPCR1_OFFSET);
265 
266 	reg = USBPCR_TXPREEMPHTUNE | USBPCR_COMMONONN | USBPCR_POR |
267 		FIELD_PREP(USBPCR_SQRXTUNE_MASK, USBPCR_SQRXTUNE_DCR_20PCT) |
268 		FIELD_PREP(USBPCR_TXHSXVTUNE_MASK, USBPCR_TXHSXVTUNE_DCR_15MV) |
269 		FIELD_PREP(USBPCR_TXVREFTUNE_MASK, USBPCR_TXVREFTUNE_INC_25PPT);
270 	writel(reg, priv->base + REG_USBPCR_OFFSET);
271 }
272 
273 static void x1830_usb_phy_init(struct phy *phy)
274 {
275 	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
276 	u32 reg;
277 
278 	/* rdt */
279 	writel(USBRDT_VBFIL_EN | USBRDT_UTMI_RST, priv->base + REG_USBRDT_OFFSET);
280 
281 	reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_WORD_IF_16BIT |
282 		USBPCR1_DMPD | USBPCR1_DPPD;
283 	writel(reg, priv->base + REG_USBPCR1_OFFSET);
284 
285 	reg = USBPCR_VBUSVLDEXT | USBPCR_TXPREEMPHTUNE | USBPCR_COMMONONN | USBPCR_POR |
286 		FIELD_PREP(USBPCR_IDPULLUP_MASK, USBPCR_IDPULLUP_OTG);
287 	writel(reg, priv->base + REG_USBPCR_OFFSET);
288 }
289 
290 static void x2000_usb_phy_init(struct phy *phy)
291 {
292 	struct ingenic_usb_phy *priv = phy_get_drvdata(phy);
293 	u32 reg;
294 
295 	reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_DPPD | USBPCR1_DMPD;
296 	writel(reg & ~USBPCR1_PORT_RST, priv->base + REG_USBPCR1_OFFSET);
297 
298 	reg = USBPCR_POR | FIELD_PREP(USBPCR_IDPULLUP_MASK, USBPCR_IDPULLUP_OTG);
299 	writel(reg, priv->base + REG_USBPCR_OFFSET);
300 }
301 
302 static const struct ingenic_soc_info jz4770_soc_info = {
303 	.version = ID_JZ4770,
304 
305 	.usb_phy_init = jz4770_usb_phy_init,
306 };
307 
308 static const struct ingenic_soc_info jz4775_soc_info = {
309 	.version = ID_JZ4775,
310 
311 	.usb_phy_init = jz4775_usb_phy_init,
312 };
313 
314 static const struct ingenic_soc_info jz4780_soc_info = {
315 	.version = ID_JZ4780,
316 
317 	.usb_phy_init = jz4780_usb_phy_init,
318 };
319 
320 static const struct ingenic_soc_info x1000_soc_info = {
321 	.version = ID_X1000,
322 
323 	.usb_phy_init = x1000_usb_phy_init,
324 };
325 
326 static const struct ingenic_soc_info x1830_soc_info = {
327 	.version = ID_X1830,
328 
329 	.usb_phy_init = x1830_usb_phy_init,
330 };
331 
332 static const struct ingenic_soc_info x2000_soc_info = {
333 	.version = ID_X2000,
334 
335 	.usb_phy_init = x2000_usb_phy_init,
336 };
337 
338 static int ingenic_usb_phy_probe(struct platform_device *pdev)
339 {
340 	struct ingenic_usb_phy *priv;
341 	struct phy_provider *provider;
342 	struct device *dev = &pdev->dev;
343 	int err;
344 
345 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
346 	if (!priv)
347 		return -ENOMEM;
348 
349 	priv->soc_info = device_get_match_data(dev);
350 	if (!priv->soc_info) {
351 		dev_err(dev, "Error: No device match found\n");
352 		return -ENODEV;
353 	}
354 
355 	priv->base = devm_platform_ioremap_resource(pdev, 0);
356 	if (IS_ERR(priv->base)) {
357 		dev_err(dev, "Failed to map registers\n");
358 		return PTR_ERR(priv->base);
359 	}
360 
361 	priv->clk = devm_clk_get(dev, NULL);
362 	if (IS_ERR(priv->clk)) {
363 		err = PTR_ERR(priv->clk);
364 		if (err != -EPROBE_DEFER)
365 			dev_err(dev, "Failed to get clock\n");
366 		return err;
367 	}
368 
369 	priv->vcc_supply = devm_regulator_get(dev, "vcc");
370 	if (IS_ERR(priv->vcc_supply)) {
371 		err = PTR_ERR(priv->vcc_supply);
372 		if (err != -EPROBE_DEFER)
373 			dev_err(dev, "Failed to get regulator\n");
374 		return err;
375 	}
376 
377 	priv->phy = devm_phy_create(dev, NULL, &ingenic_usb_phy_ops);
378 	if (IS_ERR(priv))
379 		return PTR_ERR(priv);
380 
381 	phy_set_drvdata(priv->phy, priv);
382 
383 	provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
384 
385 	return PTR_ERR_OR_ZERO(provider);
386 }
387 
388 static const struct of_device_id ingenic_usb_phy_of_matches[] = {
389 	{ .compatible = "ingenic,jz4770-phy", .data = &jz4770_soc_info },
390 	{ .compatible = "ingenic,jz4775-phy", .data = &jz4775_soc_info },
391 	{ .compatible = "ingenic,jz4780-phy", .data = &jz4780_soc_info },
392 	{ .compatible = "ingenic,x1000-phy", .data = &x1000_soc_info },
393 	{ .compatible = "ingenic,x1830-phy", .data = &x1830_soc_info },
394 	{ .compatible = "ingenic,x2000-phy", .data = &x2000_soc_info },
395 	{ /* sentinel */ }
396 };
397 MODULE_DEVICE_TABLE(of, ingenic_usb_phy_of_matches);
398 
399 static struct platform_driver ingenic_usb_phy_driver = {
400 	.probe		= ingenic_usb_phy_probe,
401 	.driver		= {
402 		.name	= "ingenic-usb-phy",
403 		.of_match_table = ingenic_usb_phy_of_matches,
404 	},
405 };
406 module_platform_driver(ingenic_usb_phy_driver);
407 
408 MODULE_AUTHOR("周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>");
409 MODULE_AUTHOR("漆鹏振 (Qi Pengzhen) <aric.pzqi@ingenic.com>");
410 MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
411 MODULE_DESCRIPTION("Ingenic SoCs USB PHY driver");
412 MODULE_LICENSE("GPL");
413