hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/phy/ti/phy-omap-usb2.c
....@@ -1,43 +1,95 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
2
- * omap-usb2.c - USB PHY, talking to musb controller in OMAP.
3
+ * omap-usb2.c - USB PHY, talking to USB controller on TI SoCs.
34 *
4
- * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
5
- * This program is free software; you can redistribute it and/or modify
6
- * it under the terms of the GNU General Public License as published by
7
- * the Free Software Foundation; either version 2 of the License, or
8
- * (at your option) any later version.
9
- *
5
+ * Copyright (C) 2012-2020 Texas Instruments Incorporated - http://www.ti.com
106 * Author: Kishon Vijay Abraham I <kishon@ti.com>
11
- *
12
- * This program is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- * GNU General Public License for more details.
16
- *
177 */
188
19
-#include <linux/module.h>
20
-#include <linux/platform_device.h>
21
-#include <linux/slab.h>
22
-#include <linux/of.h>
23
-#include <linux/io.h>
24
-#include <linux/phy/omap_usb.h>
25
-#include <linux/usb/phy_companion.h>
269 #include <linux/clk.h>
27
-#include <linux/err.h>
28
-#include <linux/pm_runtime.h>
2910 #include <linux/delay.h>
30
-#include <linux/phy/omap_control_phy.h>
31
-#include <linux/phy/phy.h>
11
+#include <linux/err.h>
12
+#include <linux/io.h>
3213 #include <linux/mfd/syscon.h>
33
-#include <linux/regmap.h>
14
+#include <linux/module.h>
15
+#include <linux/of.h>
3416 #include <linux/of_platform.h>
17
+#include <linux/phy/omap_control_phy.h>
18
+#include <linux/phy/omap_usb.h>
19
+#include <linux/phy/phy.h>
20
+#include <linux/platform_device.h>
21
+#include <linux/pm_runtime.h>
22
+#include <linux/regmap.h>
23
+#include <linux/slab.h>
24
+#include <linux/sys_soc.h>
25
+#include <linux/usb/phy_companion.h>
3526
36
-#define USB2PHY_DISCON_BYP_LATCH (1 << 31)
37
-#define USB2PHY_ANA_CONFIG1 0x4c
27
+#define USB2PHY_ANA_CONFIG1 0x4c
28
+#define USB2PHY_DISCON_BYP_LATCH BIT(31)
29
+
30
+#define USB2PHY_CHRG_DET 0x14
31
+#define USB2PHY_CHRG_DET_USE_CHG_DET_REG BIT(29)
32
+#define USB2PHY_CHRG_DET_DIS_CHG_DET BIT(28)
33
+
34
+/* SoC Specific USB2_OTG register definitions */
35
+#define AM654_USB2_OTG_PD BIT(8)
36
+#define AM654_USB2_VBUS_DET_EN BIT(5)
37
+#define AM654_USB2_VBUSVALID_DET_EN BIT(4)
38
+
39
+#define OMAP_DEV_PHY_PD BIT(0)
40
+#define OMAP_USB2_PHY_PD BIT(28)
41
+
42
+#define AM437X_USB2_PHY_PD BIT(0)
43
+#define AM437X_USB2_OTG_PD BIT(1)
44
+#define AM437X_USB2_OTGVDET_EN BIT(19)
45
+#define AM437X_USB2_OTGSESSEND_EN BIT(20)
46
+
47
+/* Driver Flags */
48
+#define OMAP_USB2_HAS_START_SRP BIT(0)
49
+#define OMAP_USB2_HAS_SET_VBUS BIT(1)
50
+#define OMAP_USB2_CALIBRATE_FALSE_DISCONNECT BIT(2)
51
+#define OMAP_USB2_DISABLE_CHRG_DET BIT(3)
52
+
53
+struct omap_usb {
54
+ struct usb_phy phy;
55
+ struct phy_companion *comparator;
56
+ void __iomem *pll_ctrl_base;
57
+ void __iomem *phy_base;
58
+ struct device *dev;
59
+ struct device *control_dev;
60
+ struct clk *wkupclk;
61
+ struct clk *optclk;
62
+ u8 flags;
63
+ struct regmap *syscon_phy_power; /* ctrl. reg. acces */
64
+ unsigned int power_reg; /* power reg. index within syscon */
65
+ u32 mask;
66
+ u32 power_on;
67
+ u32 power_off;
68
+};
69
+
70
+#define phy_to_omapusb(x) container_of((x), struct omap_usb, phy)
71
+
72
+struct usb_phy_data {
73
+ const char *label;
74
+ u8 flags;
75
+ u32 mask;
76
+ u32 power_on;
77
+ u32 power_off;
78
+};
79
+
80
+static inline u32 omap_usb_readl(void __iomem *addr, unsigned int offset)
81
+{
82
+ return __raw_readl(addr + offset);
83
+}
84
+
85
+static inline void omap_usb_writel(void __iomem *addr, unsigned int offset,
86
+ u32 data)
87
+{
88
+ __raw_writel(data, addr + offset);
89
+}
3890
3991 /**
40
- * omap_usb2_set_comparator - links the comparator present in the sytem with
92
+ * omap_usb2_set_comparator - links the comparator present in the system with
4193 * this phy
4294 * @comparator - the companion phy(comparator) for this phy
4395 *
....@@ -90,7 +142,7 @@
90142 }
91143
92144 static int omap_usb_set_peripheral(struct usb_otg *otg,
93
- struct usb_gadget *gadget)
145
+ struct usb_gadget *gadget)
94146 {
95147 otg->gadget = gadget;
96148 if (!gadget)
....@@ -135,9 +187,9 @@
135187
136188 static int omap_usb2_disable_clocks(struct omap_usb *phy)
137189 {
138
- clk_disable(phy->wkupclk);
190
+ clk_disable_unprepare(phy->wkupclk);
139191 if (!IS_ERR(phy->optclk))
140
- clk_disable(phy->optclk);
192
+ clk_disable_unprepare(phy->optclk);
141193
142194 return 0;
143195 }
....@@ -146,14 +198,14 @@
146198 {
147199 int ret;
148200
149
- ret = clk_enable(phy->wkupclk);
201
+ ret = clk_prepare_enable(phy->wkupclk);
150202 if (ret < 0) {
151203 dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
152204 goto err0;
153205 }
154206
155207 if (!IS_ERR(phy->optclk)) {
156
- ret = clk_enable(phy->optclk);
208
+ ret = clk_prepare_enable(phy->optclk);
157209 if (ret < 0) {
158210 dev_err(phy->dev, "Failed to enable optclk %d\n", ret);
159211 goto err1;
....@@ -163,7 +215,7 @@
163215 return 0;
164216
165217 err1:
166
- clk_disable(phy->wkupclk);
218
+ clk_disable_unprepare(phy->wkupclk);
167219
168220 err0:
169221 return ret;
....@@ -188,6 +240,13 @@
188240 val = omap_usb_readl(phy->phy_base, USB2PHY_ANA_CONFIG1);
189241 val |= USB2PHY_DISCON_BYP_LATCH;
190242 omap_usb_writel(phy->phy_base, USB2PHY_ANA_CONFIG1, val);
243
+ }
244
+
245
+ if (phy->flags & OMAP_USB2_DISABLE_CHRG_DET) {
246
+ val = omap_usb_readl(phy->phy_base, USB2PHY_CHRG_DET);
247
+ val |= USB2PHY_CHRG_DET_USE_CHG_DET_REG |
248
+ USB2PHY_CHRG_DET_DIS_CHG_DET;
249
+ omap_usb_writel(phy->phy_base, USB2PHY_CHRG_DET, val);
191250 }
192251
193252 return 0;
....@@ -245,6 +304,15 @@
245304 .power_off = AM437X_USB2_PHY_PD | AM437X_USB2_OTG_PD,
246305 };
247306
307
+static const struct usb_phy_data am654_usb2_data = {
308
+ .label = "am654_usb2",
309
+ .flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
310
+ .mask = AM654_USB2_OTG_PD | AM654_USB2_VBUS_DET_EN |
311
+ AM654_USB2_VBUSVALID_DET_EN,
312
+ .power_on = AM654_USB2_VBUS_DET_EN | AM654_USB2_VBUSVALID_DET_EN,
313
+ .power_off = AM654_USB2_OTG_PD,
314
+};
315
+
248316 static const struct of_device_id omap_usb2_id_table[] = {
249317 {
250318 .compatible = "ti,omap-usb2",
....@@ -266,9 +334,33 @@
266334 .compatible = "ti,am437x-usb2",
267335 .data = &am437x_usb2_data,
268336 },
337
+ {
338
+ .compatible = "ti,am654-usb2",
339
+ .data = &am654_usb2_data,
340
+ },
269341 {},
270342 };
271343 MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
344
+
345
+static void omap_usb2_init_errata(struct omap_usb *phy)
346
+{
347
+ static const struct soc_device_attribute am65x_sr10_soc_devices[] = {
348
+ { .family = "AM65X", .revision = "SR1.0" },
349
+ { /* sentinel */ }
350
+ };
351
+
352
+ /*
353
+ * Errata i2075: USB2PHY: USB2PHY Charger Detect is Enabled by
354
+ * Default Without VBUS Presence.
355
+ *
356
+ * AM654x SR1.0 has a silicon bug due to which D+ is pulled high after
357
+ * POR, which could cause enumeration failure with some USB hubs.
358
+ * Disabling the USB2_PHY Charger Detect function will put D+
359
+ * into the normal state.
360
+ */
361
+ if (soc_device_match(am65x_sr10_soc_devices))
362
+ phy->flags |= OMAP_USB2_DISABLE_CHRG_DET;
363
+}
272364
273365 static int omap_usb2_probe(struct platform_device *pdev)
274366 {
....@@ -307,17 +399,17 @@
307399 phy->mask = phy_data->mask;
308400 phy->power_on = phy_data->power_on;
309401 phy->power_off = phy_data->power_off;
402
+ phy->flags = phy_data->flags;
310403
311
- if (phy_data->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) {
312
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
313
- phy->phy_base = devm_ioremap_resource(&pdev->dev, res);
314
- if (IS_ERR(phy->phy_base))
315
- return PTR_ERR(phy->phy_base);
316
- phy->flags |= OMAP_USB2_CALIBRATE_FALSE_DISCONNECT;
317
- }
404
+ omap_usb2_init_errata(phy);
405
+
406
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
407
+ phy->phy_base = devm_ioremap_resource(&pdev->dev, res);
408
+ if (IS_ERR(phy->phy_base))
409
+ return PTR_ERR(phy->phy_base);
318410
319411 phy->syscon_phy_power = syscon_regmap_lookup_by_phandle(node,
320
- "syscon-phy-power");
412
+ "syscon-phy-power");
321413 if (IS_ERR(phy->syscon_phy_power)) {
322414 dev_dbg(&pdev->dev,
323415 "can't get syscon-phy-power, using control device\n");
....@@ -346,13 +438,51 @@
346438 }
347439 }
348440
349
- otg->set_host = omap_usb_set_host;
350
- otg->set_peripheral = omap_usb_set_peripheral;
441
+ phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
442
+ if (IS_ERR(phy->wkupclk)) {
443
+ if (PTR_ERR(phy->wkupclk) == -EPROBE_DEFER)
444
+ return -EPROBE_DEFER;
445
+
446
+ dev_warn(&pdev->dev, "unable to get wkupclk %ld, trying old name\n",
447
+ PTR_ERR(phy->wkupclk));
448
+ phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
449
+
450
+ if (IS_ERR(phy->wkupclk)) {
451
+ if (PTR_ERR(phy->wkupclk) != -EPROBE_DEFER)
452
+ dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
453
+ return PTR_ERR(phy->wkupclk);
454
+ }
455
+
456
+ dev_warn(&pdev->dev,
457
+ "found usb_phy_cm_clk32k, please fix DTS\n");
458
+ }
459
+
460
+ phy->optclk = devm_clk_get(phy->dev, "refclk");
461
+ if (IS_ERR(phy->optclk)) {
462
+ if (PTR_ERR(phy->optclk) == -EPROBE_DEFER)
463
+ return -EPROBE_DEFER;
464
+
465
+ dev_dbg(&pdev->dev, "unable to get refclk, trying old name\n");
466
+ phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m");
467
+
468
+ if (IS_ERR(phy->optclk)) {
469
+ if (PTR_ERR(phy->optclk) != -EPROBE_DEFER) {
470
+ dev_dbg(&pdev->dev,
471
+ "unable to get usb_otg_ss_refclk960m\n");
472
+ }
473
+ } else {
474
+ dev_warn(&pdev->dev,
475
+ "found usb_otg_ss_refclk960m, please fix DTS\n");
476
+ }
477
+ }
478
+
479
+ otg->set_host = omap_usb_set_host;
480
+ otg->set_peripheral = omap_usb_set_peripheral;
351481 if (phy_data->flags & OMAP_USB2_HAS_SET_VBUS)
352
- otg->set_vbus = omap_usb_set_vbus;
482
+ otg->set_vbus = omap_usb_set_vbus;
353483 if (phy_data->flags & OMAP_USB2_HAS_START_SRP)
354
- otg->start_srp = omap_usb_start_srp;
355
- otg->usb_phy = &phy->phy;
484
+ otg->start_srp = omap_usb_start_srp;
485
+ otg->usb_phy = &phy->phy;
356486
357487 platform_set_drvdata(pdev, phy);
358488 pm_runtime_enable(phy->dev);
....@@ -367,42 +497,11 @@
367497 omap_usb_power_off(generic_phy);
368498
369499 phy_provider = devm_of_phy_provider_register(phy->dev,
370
- of_phy_simple_xlate);
500
+ of_phy_simple_xlate);
371501 if (IS_ERR(phy_provider)) {
372502 pm_runtime_disable(phy->dev);
373503 return PTR_ERR(phy_provider);
374504 }
375
-
376
- phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
377
- if (IS_ERR(phy->wkupclk)) {
378
- dev_warn(&pdev->dev, "unable to get wkupclk, trying old name\n");
379
- phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
380
- if (IS_ERR(phy->wkupclk)) {
381
- dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
382
- pm_runtime_disable(phy->dev);
383
- return PTR_ERR(phy->wkupclk);
384
- } else {
385
- dev_warn(&pdev->dev,
386
- "found usb_phy_cm_clk32k, please fix DTS\n");
387
- }
388
- }
389
- clk_prepare(phy->wkupclk);
390
-
391
- phy->optclk = devm_clk_get(phy->dev, "refclk");
392
- if (IS_ERR(phy->optclk)) {
393
- dev_dbg(&pdev->dev, "unable to get refclk, trying old name\n");
394
- phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m");
395
- if (IS_ERR(phy->optclk)) {
396
- dev_dbg(&pdev->dev,
397
- "unable to get usb_otg_ss_refclk960m\n");
398
- } else {
399
- dev_warn(&pdev->dev,
400
- "found usb_otg_ss_refclk960m, please fix DTS\n");
401
- }
402
- }
403
-
404
- if (!IS_ERR(phy->optclk))
405
- clk_prepare(phy->optclk);
406505
407506 usb_add_phy_dev(&phy->phy);
408507
....@@ -413,9 +512,6 @@
413512 {
414513 struct omap_usb *phy = platform_get_drvdata(pdev);
415514
416
- clk_unprepare(phy->wkupclk);
417
- if (!IS_ERR(phy->optclk))
418
- clk_unprepare(phy->optclk);
419515 usb_remove_phy(&phy->phy);
420516 pm_runtime_disable(phy->dev);
421517