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