aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/gemini/patches-4.14/0030-usb-host-fotg2-add-Gemini-specific-handling.patch
blob: 4b015367226e085cbc7a4446895a1af2eaea5133 (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
From e8ede0f62b39a3d3b06ae3dc04a74680a1f0a64b 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 30/31] 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(+)

--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -375,6 +375,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
--- a/drivers/usb/host/fotg210-hcd.c
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -46,6 +46,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>
@@ -5584,6 +5588,72 @@ static void fotg210_init(struct 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
  *
@@ -5663,6 +5733,12 @@ static int fotg210_hcd_probe(struct plat
 
 	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);