aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/gemini/patches-4.19/0016-usb-host-fotg2-add-Gemini-specific-handling.patch
blob: 55d44b0e1011e7092c5b2c7fd6580bec115b486f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
From b331ae758123ba20ba41199e007ac33fc0f242e3 Mon Sep 17 00:00:00 2001
From: Linus Walleij <linus.walleij@linaro.org>
Date: Fri, 21 Apr 2017 22:19:00 +0200
Subject: [PATCH 16/18] usb: host: fotg2: add Gemini-specific handling

The Cortina Systems Gemini has bolted on a PHY inside the
silicon that can be handled by six bits in a MISC register in
the system controller.

If we are running on Gemini, look up a syscon regmap through
a phandle and enable VBUS and optionally the Mini-B connector.

If the device is flagged as "wakeup-source" using the standard
DT bindings, we also enable this in the global controller for
respective port.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/usb/host/Kconfig       |  1 +
 drivers/usb/host/fotg210-hcd.c | 76 ++++++++++++++++++++++++++++++++++
 2 files changed, 77 insertions(+)

diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 1a4ea98cac2a..308d514c9a2a 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -372,6 +372,7 @@ config USB_ISP1362_HCD
 config USB_FOTG210_HCD
 	tristate "FOTG210 HCD support"
 	depends on USB && HAS_DMA && HAS_IOMEM
+	select MFD_SYSCON
 	---help---
 	  Faraday FOTG210 is an OTG controller which can be configured as
 	  an USB2.0 host. It is designed to meet USB2.0 EHCI specification
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
index 6e4b40cd5916..5abb07f4136f 100644
--- a/drivers/usb/host/fotg210-hcd.c
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -33,6 +33,10 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/clk.h>
+#include <linux/bitops.h>
+/* For Cortina Gemini */
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -5554,6 +5558,72 @@ static void fotg210_init(struct fotg210_hcd *fotg210)
 	iowrite32(value, &fotg210->regs->otgcsr);
 }
 
+/*
+ * Gemini-specific initialization function, only executed on the
+ * Gemini SoC using the global misc control register.
+ */
+#define GEMINI_GLOBAL_MISC_CTRL		0x30
+#define GEMINI_MISC_USB0_WAKEUP		BIT(14)
+#define GEMINI_MISC_USB1_WAKEUP		BIT(15)
+#define GEMINI_MISC_USB0_VBUS_ON	BIT(22)
+#define GEMINI_MISC_USB1_VBUS_ON	BIT(23)
+#define GEMINI_MISC_USB0_MINI_B		BIT(29)
+#define GEMINI_MISC_USB1_MINI_B		BIT(30)
+
+static int fotg210_gemini_init(struct device *dev, struct usb_hcd *hcd)
+{
+	struct device_node *np = dev->of_node;
+	struct regmap *map;
+	bool mini_b;
+	bool wakeup;
+	u32 mask, val;
+	int ret;
+
+	map = syscon_regmap_lookup_by_phandle(np, "syscon");
+	if (IS_ERR(map)) {
+		dev_err(dev, "no syscon\n");
+		return PTR_ERR(map);
+	}
+	mini_b = of_property_read_bool(np, "cortina,gemini-mini-b");
+	wakeup = of_property_read_bool(np, "wakeup-source");
+
+	/*
+	 * Figure out if this is USB0 or USB1 by simply checking the
+	 * physical base address.
+	 */
+	mask = 0;
+	if (hcd->rsrc_start == 0x69000000) {
+		val = GEMINI_MISC_USB1_VBUS_ON;
+		if (mini_b)
+			val |= GEMINI_MISC_USB1_MINI_B;
+		else
+			mask |= GEMINI_MISC_USB1_MINI_B;
+		if (wakeup)
+			val |= GEMINI_MISC_USB1_WAKEUP;
+		else
+			mask |= GEMINI_MISC_USB1_WAKEUP;
+	} else {
+		val = GEMINI_MISC_USB0_VBUS_ON;
+		if (mini_b)
+			val |= GEMINI_MISC_USB0_MINI_B;
+		else
+			mask |= GEMINI_MISC_USB0_MINI_B;
+		if (wakeup)
+			val |= GEMINI_MISC_USB0_WAKEUP;
+		else
+			mask |= GEMINI_MISC_USB0_WAKEUP;
+	}
+
+	ret = regmap_update_bits(map, GEMINI_GLOBAL_MISC_CTRL, mask, val);
+	if (ret) {
+		dev_err(dev, "failed to initialize Gemini PHY\n");
+		return ret;
+	}
+
+	dev_info(dev, "initialized Gemini PHY\n");
+	return 0;
+}
+
 /**
  * fotg210_hcd_probe - initialize faraday FOTG210 HCDs
  *
@@ -5631,6 +5701,12 @@ static int fotg210_hcd_probe(struct platform_device *pdev)
 
 	fotg210_init(fotg210);
 
+	if (of_device_is_compatible(dev->of_node, "cortina,gemini-usb")) {
+		retval = fotg210_gemini_init(dev, hcd);
+		if (retval)
+			goto failed_dis_clk;
+	}
+
 	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (retval) {
 		dev_err(dev, "failed to add hcd with err %d\n", retval);
-- 
2.19.2