mediatek: backport upstream mediatek patches
[openwrt/openwrt.git] / target / linux / mediatek / patches-4.14 / 0188-usb-mtu3-supports-remote-wakeup-for-mt2712-with-two-.patch
1 From 354655aaf0f71ce2b567cbc02afb0664c99e434e Mon Sep 17 00:00:00 2001
2 From: Chunfeng Yun <chunfeng.yun@mediatek.com>
3 Date: Wed, 3 Jan 2018 16:53:18 +0800
4 Subject: [PATCH 188/224] usb: mtu3: supports remote wakeup for mt2712 with two
5 SSUSB IPs
6
7 The old way of usb wakeup only supports platform with single SSUSB IP,
8 such as mt8173, but mt2712 has two SSUSB IPs, so rebuild its flow and
9 also supports the new glue layer of usb wakeup on mt2712 which is
10 different from mt8173.
11
12 Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
13 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
14 ---
15 drivers/usb/mtu3/mtu3.h | 11 +++--
16 drivers/usb/mtu3/mtu3_dr.h | 3 +-
17 drivers/usb/mtu3/mtu3_host.c | 115 +++++++++++++++++++++----------------------
18 drivers/usb/mtu3/mtu3_plat.c | 8 +--
19 4 files changed, 70 insertions(+), 67 deletions(-)
20
21 diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
22 index d80e4e813248..ed3aec46eda1 100644
23 --- a/drivers/usb/mtu3/mtu3.h
24 +++ b/drivers/usb/mtu3/mtu3.h
25 @@ -238,7 +238,10 @@ struct otg_switch_mtk {
26 * @u3p_dis_msk: mask of disabling usb3 ports, for example, bit0==1 to
27 * disable u3port0, bit1==1 to disable u3port1,... etc
28 * @dbgfs_root: only used when supports manual dual-role switch via debugfs
29 - * @wakeup_en: it's true when supports remote wakeup in host mode
30 + * @uwk_en: it's true when supports remote wakeup in host mode
31 + * @uwk: syscon including usb wakeup glue layer between SSUSB IP and SPM
32 + * @uwk_reg_base: the base address of the wakeup glue layer in @uwk
33 + * @uwk_vers: the version of the wakeup glue layer
34 */
35 struct ssusb_mtk {
36 struct device *dev;
37 @@ -262,8 +265,10 @@ struct ssusb_mtk {
38 int u3p_dis_msk;
39 struct dentry *dbgfs_root;
40 /* usb wakeup for host mode */
41 - bool wakeup_en;
42 - struct regmap *pericfg;
43 + bool uwk_en;
44 + struct regmap *uwk;
45 + u32 uwk_reg_base;
46 + u32 uwk_vers;
47 };
48
49 /**
50 diff --git a/drivers/usb/mtu3/mtu3_dr.h b/drivers/usb/mtu3/mtu3_dr.h
51 index 0f0cbac00192..1fa62ce136b6 100644
52 --- a/drivers/usb/mtu3/mtu3_dr.h
53 +++ b/drivers/usb/mtu3/mtu3_dr.h
54 @@ -27,8 +27,7 @@ int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
55 struct device_node *dn);
56 int ssusb_host_enable(struct ssusb_mtk *ssusb);
57 int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend);
58 -int ssusb_wakeup_enable(struct ssusb_mtk *ssusb);
59 -void ssusb_wakeup_disable(struct ssusb_mtk *ssusb);
60 +void ssusb_wakeup_set(struct ssusb_mtk *ssusb, bool enable);
61
62 #else
63
64 diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c
65 index ec76b86dd887..1a1b6cf432a1 100644
66 --- a/drivers/usb/mtu3/mtu3_host.c
67 +++ b/drivers/usb/mtu3/mtu3_host.c
68 @@ -27,66 +27,77 @@
69 #include "mtu3.h"
70 #include "mtu3_dr.h"
71
72 -#define PERI_WK_CTRL1 0x404
73 -#define UWK_CTL1_IS_C(x) (((x) & 0xf) << 26)
74 -#define UWK_CTL1_IS_E BIT(25)
75 -#define UWK_CTL1_IDDIG_C(x) (((x) & 0xf) << 11) /* cycle debounce */
76 -#define UWK_CTL1_IDDIG_E BIT(10) /* enable debounce */
77 -#define UWK_CTL1_IDDIG_P BIT(9) /* polarity */
78 -#define UWK_CTL1_IS_P BIT(6) /* polarity for ip sleep */
79 +/* mt8173 etc */
80 +#define PERI_WK_CTRL1 0x4
81 +#define WC1_IS_C(x) (((x) & 0xf) << 26) /* cycle debounce */
82 +#define WC1_IS_EN BIT(25)
83 +#define WC1_IS_P BIT(6) /* polarity for ip sleep */
84 +
85 +/* mt2712 etc */
86 +#define PERI_SSUSB_SPM_CTRL 0x0
87 +#define SSC_IP_SLEEP_EN BIT(4)
88 +#define SSC_SPM_INT_EN BIT(1)
89 +
90 +enum ssusb_uwk_vers {
91 + SSUSB_UWK_V1 = 1,
92 + SSUSB_UWK_V2,
93 +};
94
95 /*
96 * ip-sleep wakeup mode:
97 * all clocks can be turn off, but power domain should be kept on
98 */
99 -static void ssusb_wakeup_ip_sleep_en(struct ssusb_mtk *ssusb)
100 +static void ssusb_wakeup_ip_sleep_set(struct ssusb_mtk *ssusb, bool enable)
101 {
102 - u32 tmp;
103 - struct regmap *pericfg = ssusb->pericfg;
104 -
105 - regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
106 - tmp &= ~UWK_CTL1_IS_P;
107 - tmp &= ~(UWK_CTL1_IS_C(0xf));
108 - tmp |= UWK_CTL1_IS_C(0x8);
109 - regmap_write(pericfg, PERI_WK_CTRL1, tmp);
110 - regmap_write(pericfg, PERI_WK_CTRL1, tmp | UWK_CTL1_IS_E);
111 -
112 - regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
113 - dev_dbg(ssusb->dev, "%s(): WK_CTRL1[P6,E25,C26:29]=%#x\n",
114 - __func__, tmp);
115 -}
116 -
117 -static void ssusb_wakeup_ip_sleep_dis(struct ssusb_mtk *ssusb)
118 -{
119 - u32 tmp;
120 -
121 - regmap_read(ssusb->pericfg, PERI_WK_CTRL1, &tmp);
122 - tmp &= ~UWK_CTL1_IS_E;
123 - regmap_write(ssusb->pericfg, PERI_WK_CTRL1, tmp);
124 + u32 reg, msk, val;
125 +
126 + switch (ssusb->uwk_vers) {
127 + case SSUSB_UWK_V1:
128 + reg = ssusb->uwk_reg_base + PERI_WK_CTRL1;
129 + msk = WC1_IS_EN | WC1_IS_C(0xf) | WC1_IS_P;
130 + val = enable ? (WC1_IS_EN | WC1_IS_C(0x8)) : 0;
131 + break;
132 + case SSUSB_UWK_V2:
133 + reg = ssusb->uwk_reg_base + PERI_SSUSB_SPM_CTRL;
134 + msk = SSC_IP_SLEEP_EN | SSC_SPM_INT_EN;
135 + val = enable ? msk : 0;
136 + break;
137 + default:
138 + return;
139 + };
140 + regmap_update_bits(ssusb->uwk, reg, msk, val);
141 }
142
143 int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
144 struct device_node *dn)
145 {
146 - struct device *dev = ssusb->dev;
147 + struct of_phandle_args args;
148 + int ret;
149
150 - /*
151 - * Wakeup function is optional, so it is not an error if this property
152 - * does not exist, and in such case, no need to get relative
153 - * properties anymore.
154 - */
155 - ssusb->wakeup_en = of_property_read_bool(dn, "mediatek,enable-wakeup");
156 - if (!ssusb->wakeup_en)
157 + /* wakeup function is optional */
158 + ssusb->uwk_en = of_property_read_bool(dn, "wakeup-source");
159 + if (!ssusb->uwk_en)
160 return 0;
161
162 - ssusb->pericfg = syscon_regmap_lookup_by_phandle(dn,
163 - "mediatek,syscon-wakeup");
164 - if (IS_ERR(ssusb->pericfg)) {
165 - dev_err(dev, "fail to get pericfg regs\n");
166 - return PTR_ERR(ssusb->pericfg);
167 - }
168 + ret = of_parse_phandle_with_fixed_args(dn,
169 + "mediatek,syscon-wakeup", 2, 0, &args);
170 + if (ret)
171 + return ret;
172
173 - return 0;
174 + ssusb->uwk_reg_base = args.args[0];
175 + ssusb->uwk_vers = args.args[1];
176 + ssusb->uwk = syscon_node_to_regmap(args.np);
177 + of_node_put(args.np);
178 + dev_info(ssusb->dev, "uwk - reg:0x%x, version:%d\n",
179 + ssusb->uwk_reg_base, ssusb->uwk_vers);
180 +
181 + return PTR_ERR_OR_ZERO(ssusb->uwk);
182 +}
183 +
184 +void ssusb_wakeup_set(struct ssusb_mtk *ssusb, bool enable)
185 +{
186 + if (ssusb->uwk_en)
187 + ssusb_wakeup_ip_sleep_set(ssusb, enable);
188 }
189
190 static void host_ports_num_get(struct ssusb_mtk *ssusb)
191 @@ -244,17 +255,3 @@ void ssusb_host_exit(struct ssusb_mtk *ssusb)
192 of_platform_depopulate(ssusb->dev);
193 ssusb_host_cleanup(ssusb);
194 }
195 -
196 -int ssusb_wakeup_enable(struct ssusb_mtk *ssusb)
197 -{
198 - if (ssusb->wakeup_en)
199 - ssusb_wakeup_ip_sleep_en(ssusb);
200 -
201 - return 0;
202 -}
203 -
204 -void ssusb_wakeup_disable(struct ssusb_mtk *ssusb)
205 -{
206 - if (ssusb->wakeup_en)
207 - ssusb_wakeup_ip_sleep_dis(ssusb);
208 -}
209 diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
210 index a2523ead46cf..4cafd4ca8457 100644
211 --- a/drivers/usb/mtu3/mtu3_plat.c
212 +++ b/drivers/usb/mtu3/mtu3_plat.c
213 @@ -291,8 +291,10 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
214
215 /* if host role is supported */
216 ret = ssusb_wakeup_of_property_parse(ssusb, node);
217 - if (ret)
218 + if (ret) {
219 + dev_err(dev, "failed to parse uwk property\n");
220 return ret;
221 + }
222
223 /* optional property, ignore the error if it does not exist */
224 of_property_read_u32(node, "mediatek,u3p-dis-msk",
225 @@ -466,7 +468,7 @@ static int __maybe_unused mtu3_suspend(struct device *dev)
226 ssusb_host_disable(ssusb, true);
227 ssusb_phy_power_off(ssusb);
228 ssusb_clks_disable(ssusb);
229 - ssusb_wakeup_enable(ssusb);
230 + ssusb_wakeup_set(ssusb, true);
231
232 return 0;
233 }
234 @@ -482,7 +484,7 @@ static int __maybe_unused mtu3_resume(struct device *dev)
235 if (!ssusb->is_host)
236 return 0;
237
238 - ssusb_wakeup_disable(ssusb);
239 + ssusb_wakeup_set(ssusb, false);
240 ret = ssusb_clks_enable(ssusb);
241 if (ret)
242 goto clks_err;
243 --
244 2.11.0
245