sunxi: 6.6: set testing kernel
[openwrt/openwrt.git] / target / linux / mediatek / patches-4.14 / 0108-usb-mtu3-use-FORCE-RG_IDDIG-to-implement-manual-DRD-.patch
1 From 6c4995c9a8ba8841ba640201636954c84f494587 Mon Sep 17 00:00:00 2001
2 From: Chunfeng Yun <chunfeng.yun@mediatek.com>
3 Date: Fri, 13 Oct 2017 17:10:42 +0800
4 Subject: [PATCH 108/224] usb: mtu3: use FORCE/RG_IDDIG to implement manual DRD
5 switch
6
7 In order to keep manual DRD switch independent on IDDIG interrupt,
8 make use of FORCE/RG_IDDIG instead of IDDIG EINT interrupt to
9 implement manual DRD switch function.
10
11 Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
12 Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
13 ---
14 drivers/usb/mtu3/mtu3.h | 18 ++++++++----
15 drivers/usb/mtu3/mtu3_dr.c | 61 ++++++++++++++++++++++++++++++-----------
16 drivers/usb/mtu3/mtu3_dr.h | 6 ++++
17 drivers/usb/mtu3/mtu3_host.c | 5 ++++
18 drivers/usb/mtu3/mtu3_hw_regs.h | 2 ++
19 drivers/usb/mtu3/mtu3_plat.c | 38 ++-----------------------
20 6 files changed, 74 insertions(+), 56 deletions(-)
21
22 --- a/drivers/usb/mtu3/mtu3.h
23 +++ b/drivers/usb/mtu3/mtu3.h
24 @@ -115,6 +115,19 @@ enum mtu3_g_ep0_state {
25 };
26
27 /**
28 + * MTU3_DR_FORCE_NONE: automatically switch host and periperal mode
29 + * by IDPIN signal.
30 + * MTU3_DR_FORCE_HOST: force to enter host mode and override OTG
31 + * IDPIN signal.
32 + * MTU3_DR_FORCE_DEVICE: force to enter peripheral mode.
33 + */
34 +enum mtu3_dr_force_mode {
35 + MTU3_DR_FORCE_NONE = 0,
36 + MTU3_DR_FORCE_HOST,
37 + MTU3_DR_FORCE_DEVICE,
38 +};
39 +
40 +/**
41 * @base: the base address of fifo
42 * @limit: the bitmap size in bits
43 * @bitmap: fifo bitmap in unit of @MTU3_EP_FIFO_UNIT
44 @@ -196,7 +209,6 @@ struct mtu3_gpd_ring {
45 * xHCI driver initialization, it's necessary for system bootup
46 * as device.
47 * @is_u3_drd: whether port0 supports usb3.0 dual-role device or not
48 -* @id_*: used to maually switch between host and device modes by idpin
49 * @manual_drd_enabled: it's true when supports dual-role device by debugfs
50 * to switch host/device modes depending on user input.
51 */
52 @@ -207,10 +219,6 @@ struct otg_switch_mtk {
53 struct notifier_block id_nb;
54 struct delayed_work extcon_reg_dwork;
55 bool is_u3_drd;
56 - /* dual-role switch by debugfs */
57 - struct pinctrl *id_pinctrl;
58 - struct pinctrl_state *id_float;
59 - struct pinctrl_state *id_ground;
60 bool manual_drd_enabled;
61 };
62
63 --- a/drivers/usb/mtu3/mtu3_dr.c
64 +++ b/drivers/usb/mtu3/mtu3_dr.c
65 @@ -261,21 +261,22 @@ static void extcon_register_dwork(struct
66 * depending on user input.
67 * This is useful in special cases, such as uses TYPE-A receptacle but also
68 * wants to support dual-role mode.
69 - * It generates cable state changes by pulling up/down IDPIN and
70 - * notifies driver to switch mode by "extcon-usb-gpio".
71 - * NOTE: when use MICRO receptacle, should not enable this interface.
72 */
73 static void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host)
74 {
75 struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
76
77 - if (to_host)
78 - pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_ground);
79 - else
80 - pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_float);
81 + if (to_host) {
82 + ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
83 + ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
84 + ssusb_set_mailbox(otg_sx, MTU3_ID_GROUND);
85 + } else {
86 + ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_DEVICE);
87 + ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
88 + ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
89 + }
90 }
91
92 -
93 static int ssusb_mode_show(struct seq_file *sf, void *unused)
94 {
95 struct ssusb_mtk *ssusb = sf->private;
96 @@ -388,17 +389,45 @@ static void ssusb_debugfs_exit(struct ss
97 debugfs_remove_recursive(ssusb->dbgfs_root);
98 }
99
100 +void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
101 + enum mtu3_dr_force_mode mode)
102 +{
103 + u32 value;
104 +
105 + value = mtu3_readl(ssusb->ippc_base, SSUSB_U2_CTRL(0));
106 + switch (mode) {
107 + case MTU3_DR_FORCE_DEVICE:
108 + value |= SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG;
109 + break;
110 + case MTU3_DR_FORCE_HOST:
111 + value |= SSUSB_U2_PORT_FORCE_IDDIG;
112 + value &= ~SSUSB_U2_PORT_RG_IDDIG;
113 + break;
114 + case MTU3_DR_FORCE_NONE:
115 + value &= ~(SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG);
116 + break;
117 + default:
118 + return;
119 + }
120 + mtu3_writel(ssusb->ippc_base, SSUSB_U2_CTRL(0), value);
121 +}
122 +
123 int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
124 {
125 struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
126
127 - INIT_DELAYED_WORK(&otg_sx->extcon_reg_dwork, extcon_register_dwork);
128 -
129 - if (otg_sx->manual_drd_enabled)
130 + if (otg_sx->manual_drd_enabled) {
131 ssusb_debugfs_init(ssusb);
132 + } else {
133 + INIT_DELAYED_WORK(&otg_sx->extcon_reg_dwork,
134 + extcon_register_dwork);
135
136 - /* It is enough to delay 1s for waiting for host initialization */
137 - schedule_delayed_work(&otg_sx->extcon_reg_dwork, HZ);
138 + /*
139 + * It is enough to delay 1s for waiting for
140 + * host initialization
141 + */
142 + schedule_delayed_work(&otg_sx->extcon_reg_dwork, HZ);
143 + }
144
145 return 0;
146 }
147 @@ -407,8 +436,8 @@ void ssusb_otg_switch_exit(struct ssusb_
148 {
149 struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
150
151 - cancel_delayed_work(&otg_sx->extcon_reg_dwork);
152 -
153 if (otg_sx->manual_drd_enabled)
154 ssusb_debugfs_exit(ssusb);
155 + else
156 + cancel_delayed_work(&otg_sx->extcon_reg_dwork);
157 }
158 --- a/drivers/usb/mtu3/mtu3_dr.h
159 +++ b/drivers/usb/mtu3/mtu3_dr.h
160 @@ -87,6 +87,8 @@ static inline void ssusb_gadget_exit(str
161 int ssusb_otg_switch_init(struct ssusb_mtk *ssusb);
162 void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb);
163 int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on);
164 +void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
165 + enum mtu3_dr_force_mode mode);
166
167 #else
168
169 @@ -103,6 +105,10 @@ static inline int ssusb_set_vbus(struct
170 return 0;
171 }
172
173 +static inline void
174 +ssusb_set_force_mode(struct ssusb_mtk *ssusb, enum mtu3_dr_force_mode mode)
175 +{}
176 +
177 #endif
178
179 #endif /* _MTU3_DR_H_ */
180 --- a/drivers/usb/mtu3/mtu3_host.c
181 +++ b/drivers/usb/mtu3/mtu3_host.c
182 @@ -189,6 +189,8 @@ int ssusb_host_disable(struct ssusb_mtk
183
184 static void ssusb_host_setup(struct ssusb_mtk *ssusb)
185 {
186 + struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
187 +
188 host_ports_num_get(ssusb);
189
190 /*
191 @@ -197,6 +199,9 @@ static void ssusb_host_setup(struct ssus
192 */
193 ssusb_host_enable(ssusb);
194
195 + if (otg_sx->manual_drd_enabled)
196 + ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
197 +
198 /* if port0 supports dual-role, works as host mode by default */
199 ssusb_set_vbus(&ssusb->otg_switch, 1);
200 }
201 --- a/drivers/usb/mtu3/mtu3_hw_regs.h
202 +++ b/drivers/usb/mtu3/mtu3_hw_regs.h
203 @@ -472,6 +472,8 @@
204 #define SSUSB_U3_PORT_DIS BIT(0)
205
206 /* U3D_SSUSB_U2_CTRL_0P */
207 +#define SSUSB_U2_PORT_RG_IDDIG BIT(12)
208 +#define SSUSB_U2_PORT_FORCE_IDDIG BIT(11)
209 #define SSUSB_U2_PORT_VBUSVALID BIT(9)
210 #define SSUSB_U2_PORT_OTG_SEL BIT(7)
211 #define SSUSB_U2_PORT_HOST BIT(2)
212 --- a/drivers/usb/mtu3/mtu3_plat.c
213 +++ b/drivers/usb/mtu3/mtu3_plat.c
214 @@ -21,7 +21,6 @@
215 #include <linux/module.h>
216 #include <linux/of_address.h>
217 #include <linux/of_irq.h>
218 -#include <linux/pinctrl/consumer.h>
219 #include <linux/platform_device.h>
220
221 #include "mtu3.h"
222 @@ -212,33 +211,6 @@ static void ssusb_ip_sw_reset(struct ssu
223 mtu3_clrbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
224 }
225
226 -static int get_iddig_pinctrl(struct ssusb_mtk *ssusb)
227 -{
228 - struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
229 -
230 - otg_sx->id_pinctrl = devm_pinctrl_get(ssusb->dev);
231 - if (IS_ERR(otg_sx->id_pinctrl)) {
232 - dev_err(ssusb->dev, "Cannot find id pinctrl!\n");
233 - return PTR_ERR(otg_sx->id_pinctrl);
234 - }
235 -
236 - otg_sx->id_float =
237 - pinctrl_lookup_state(otg_sx->id_pinctrl, "id_float");
238 - if (IS_ERR(otg_sx->id_float)) {
239 - dev_err(ssusb->dev, "Cannot find pinctrl id_float!\n");
240 - return PTR_ERR(otg_sx->id_float);
241 - }
242 -
243 - otg_sx->id_ground =
244 - pinctrl_lookup_state(otg_sx->id_pinctrl, "id_ground");
245 - if (IS_ERR(otg_sx->id_ground)) {
246 - dev_err(ssusb->dev, "Cannot find pinctrl id_ground!\n");
247 - return PTR_ERR(otg_sx->id_ground);
248 - }
249 -
250 - return 0;
251 -}
252 -
253 /* ignore the error if the clock does not exist */
254 static struct clk *get_optional_clk(struct device *dev, const char *id)
255 {
256 @@ -349,15 +321,11 @@ static int get_ssusb_rscs(struct platfor
257 dev_err(ssusb->dev, "couldn't get extcon device\n");
258 return -EPROBE_DEFER;
259 }
260 - if (otg_sx->manual_drd_enabled) {
261 - ret = get_iddig_pinctrl(ssusb);
262 - if (ret)
263 - return ret;
264 - }
265 }
266
267 - dev_info(dev, "dr_mode: %d, is_u3_dr: %d, u3p_dis_msk:%x\n",
268 - ssusb->dr_mode, otg_sx->is_u3_drd, ssusb->u3p_dis_msk);
269 + dev_info(dev, "dr_mode: %d, is_u3_dr: %d, u3p_dis_msk: %x, drd: %s\n",
270 + ssusb->dr_mode, otg_sx->is_u3_drd, ssusb->u3p_dis_msk,
271 + otg_sx->manual_drd_enabled ? "manual" : "auto");
272
273 return 0;
274 }