Commit | Line | Data |
---|---|---|
5fd54ace | 1 | // SPDX-License-Identifier: GPL-2.0+ |
277164f0 NZ |
2 | /* |
3 | * Copyright (C) 2011 Marvell International Ltd. All rights reserved. | |
4 | * Author: Chao Xie <chao.xie@marvell.com> | |
5 | * Neil Zhang <zhangwm@marvell.com> | |
277164f0 NZ |
6 | */ |
7 | ||
8 | #include <linux/module.h> | |
9 | #include <linux/kernel.h> | |
277164f0 NZ |
10 | #include <linux/io.h> |
11 | #include <linux/uaccess.h> | |
12 | #include <linux/device.h> | |
13 | #include <linux/proc_fs.h> | |
14 | #include <linux/clk.h> | |
15 | #include <linux/workqueue.h> | |
16 | #include <linux/platform_device.h> | |
17 | ||
18 | #include <linux/usb.h> | |
19 | #include <linux/usb/ch9.h> | |
20 | #include <linux/usb/otg.h> | |
21 | #include <linux/usb/gadget.h> | |
22 | #include <linux/usb/hcd.h> | |
23 | #include <linux/platform_data/mv_usb.h> | |
24 | ||
94ae9843 | 25 | #include "phy-mv-usb.h" |
277164f0 NZ |
26 | |
27 | #define DRIVER_DESC "Marvell USB OTG transceiver driver" | |
277164f0 NZ |
28 | |
29 | MODULE_DESCRIPTION(DRIVER_DESC); | |
277164f0 NZ |
30 | MODULE_LICENSE("GPL"); |
31 | ||
32 | static const char driver_name[] = "mv-otg"; | |
33 | ||
34 | static char *state_string[] = { | |
35 | "undefined", | |
36 | "b_idle", | |
37 | "b_srp_init", | |
38 | "b_peripheral", | |
39 | "b_wait_acon", | |
40 | "b_host", | |
41 | "a_idle", | |
42 | "a_wait_vrise", | |
43 | "a_wait_bcon", | |
44 | "a_host", | |
45 | "a_suspend", | |
46 | "a_peripheral", | |
47 | "a_wait_vfall", | |
48 | "a_vbus_err" | |
49 | }; | |
50 | ||
b1c711d6 | 51 | static int mv_otg_set_vbus(struct usb_otg *otg, bool on) |
277164f0 | 52 | { |
19c1eac2 | 53 | struct mv_otg *mvotg = container_of(otg->usb_phy, struct mv_otg, phy); |
277164f0 NZ |
54 | if (mvotg->pdata->set_vbus == NULL) |
55 | return -ENODEV; | |
56 | ||
57 | return mvotg->pdata->set_vbus(on); | |
58 | } | |
59 | ||
b1c711d6 | 60 | static int mv_otg_set_host(struct usb_otg *otg, |
277164f0 NZ |
61 | struct usb_bus *host) |
62 | { | |
63 | otg->host = host; | |
64 | ||
65 | return 0; | |
66 | } | |
67 | ||
b1c711d6 | 68 | static int mv_otg_set_peripheral(struct usb_otg *otg, |
277164f0 NZ |
69 | struct usb_gadget *gadget) |
70 | { | |
71 | otg->gadget = gadget; | |
72 | ||
73 | return 0; | |
74 | } | |
75 | ||
76 | static void mv_otg_run_state_machine(struct mv_otg *mvotg, | |
77 | unsigned long delay) | |
78 | { | |
79 | dev_dbg(&mvotg->pdev->dev, "transceiver is updated\n"); | |
80 | if (!mvotg->qwork) | |
81 | return; | |
82 | ||
83 | queue_delayed_work(mvotg->qwork, &mvotg->work, delay); | |
84 | } | |
85 | ||
9718756f | 86 | static void mv_otg_timer_await_bcon(struct timer_list *t) |
277164f0 | 87 | { |
9718756f KC |
88 | struct mv_otg *mvotg = from_timer(mvotg, t, |
89 | otg_ctrl.timer[A_WAIT_BCON_TIMER]); | |
277164f0 NZ |
90 | |
91 | mvotg->otg_ctrl.a_wait_bcon_timeout = 1; | |
92 | ||
93 | dev_info(&mvotg->pdev->dev, "B Device No Response!\n"); | |
94 | ||
95 | if (spin_trylock(&mvotg->wq_lock)) { | |
96 | mv_otg_run_state_machine(mvotg, 0); | |
97 | spin_unlock(&mvotg->wq_lock); | |
98 | } | |
99 | } | |
100 | ||
101 | static int mv_otg_cancel_timer(struct mv_otg *mvotg, unsigned int id) | |
102 | { | |
103 | struct timer_list *timer; | |
104 | ||
105 | if (id >= OTG_TIMER_NUM) | |
106 | return -EINVAL; | |
107 | ||
108 | timer = &mvotg->otg_ctrl.timer[id]; | |
109 | ||
110 | if (timer_pending(timer)) | |
111 | del_timer(timer); | |
112 | ||
113 | return 0; | |
114 | } | |
115 | ||
116 | static int mv_otg_set_timer(struct mv_otg *mvotg, unsigned int id, | |
9718756f | 117 | unsigned long interval) |
277164f0 NZ |
118 | { |
119 | struct timer_list *timer; | |
120 | ||
121 | if (id >= OTG_TIMER_NUM) | |
122 | return -EINVAL; | |
123 | ||
124 | timer = &mvotg->otg_ctrl.timer[id]; | |
125 | if (timer_pending(timer)) { | |
126 | dev_err(&mvotg->pdev->dev, "Timer%d is already running\n", id); | |
127 | return -EBUSY; | |
128 | } | |
129 | ||
277164f0 NZ |
130 | timer->expires = jiffies + interval; |
131 | add_timer(timer); | |
132 | ||
133 | return 0; | |
134 | } | |
135 | ||
136 | static int mv_otg_reset(struct mv_otg *mvotg) | |
137 | { | |
138 | unsigned int loops; | |
139 | u32 tmp; | |
140 | ||
141 | /* Stop the controller */ | |
142 | tmp = readl(&mvotg->op_regs->usbcmd); | |
143 | tmp &= ~USBCMD_RUN_STOP; | |
144 | writel(tmp, &mvotg->op_regs->usbcmd); | |
145 | ||
146 | /* Reset the controller to get default values */ | |
147 | writel(USBCMD_CTRL_RESET, &mvotg->op_regs->usbcmd); | |
148 | ||
149 | loops = 500; | |
150 | while (readl(&mvotg->op_regs->usbcmd) & USBCMD_CTRL_RESET) { | |
151 | if (loops == 0) { | |
152 | dev_err(&mvotg->pdev->dev, | |
153 | "Wait for RESET completed TIMEOUT\n"); | |
154 | return -ETIMEDOUT; | |
155 | } | |
156 | loops--; | |
157 | udelay(20); | |
158 | } | |
159 | ||
160 | writel(0x0, &mvotg->op_regs->usbintr); | |
161 | tmp = readl(&mvotg->op_regs->usbsts); | |
162 | writel(tmp, &mvotg->op_regs->usbsts); | |
163 | ||
164 | return 0; | |
165 | } | |
166 | ||
167 | static void mv_otg_init_irq(struct mv_otg *mvotg) | |
168 | { | |
169 | u32 otgsc; | |
170 | ||
171 | mvotg->irq_en = OTGSC_INTR_A_SESSION_VALID | |
172 | | OTGSC_INTR_A_VBUS_VALID; | |
173 | mvotg->irq_status = OTGSC_INTSTS_A_SESSION_VALID | |
174 | | OTGSC_INTSTS_A_VBUS_VALID; | |
175 | ||
176 | if (mvotg->pdata->vbus == NULL) { | |
177 | mvotg->irq_en |= OTGSC_INTR_B_SESSION_VALID | |
178 | | OTGSC_INTR_B_SESSION_END; | |
179 | mvotg->irq_status |= OTGSC_INTSTS_B_SESSION_VALID | |
180 | | OTGSC_INTSTS_B_SESSION_END; | |
181 | } | |
182 | ||
183 | if (mvotg->pdata->id == NULL) { | |
184 | mvotg->irq_en |= OTGSC_INTR_USB_ID; | |
185 | mvotg->irq_status |= OTGSC_INTSTS_USB_ID; | |
186 | } | |
187 | ||
188 | otgsc = readl(&mvotg->op_regs->otgsc); | |
189 | otgsc |= mvotg->irq_en; | |
190 | writel(otgsc, &mvotg->op_regs->otgsc); | |
191 | } | |
192 | ||
193 | static void mv_otg_start_host(struct mv_otg *mvotg, int on) | |
194 | { | |
2053c2d1 | 195 | #ifdef CONFIG_USB |
b1c711d6 | 196 | struct usb_otg *otg = mvotg->phy.otg; |
277164f0 NZ |
197 | struct usb_hcd *hcd; |
198 | ||
199 | if (!otg->host) | |
200 | return; | |
201 | ||
202 | dev_info(&mvotg->pdev->dev, "%s host\n", on ? "start" : "stop"); | |
203 | ||
204 | hcd = bus_to_hcd(otg->host); | |
205 | ||
3c9740a1 | 206 | if (on) { |
277164f0 | 207 | usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); |
3c9740a1 PC |
208 | device_wakeup_enable(hcd->self.controller); |
209 | } else { | |
277164f0 | 210 | usb_remove_hcd(hcd); |
3c9740a1 | 211 | } |
2053c2d1 | 212 | #endif /* CONFIG_USB */ |
277164f0 NZ |
213 | } |
214 | ||
215 | static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on) | |
216 | { | |
b1c711d6 | 217 | struct usb_otg *otg = mvotg->phy.otg; |
277164f0 NZ |
218 | |
219 | if (!otg->gadget) | |
220 | return; | |
221 | ||
b1c711d6 | 222 | dev_info(mvotg->phy.dev, "gadget %s\n", on ? "on" : "off"); |
277164f0 NZ |
223 | |
224 | if (on) | |
225 | usb_gadget_vbus_connect(otg->gadget); | |
226 | else | |
227 | usb_gadget_vbus_disconnect(otg->gadget); | |
228 | } | |
229 | ||
230 | static void otg_clock_enable(struct mv_otg *mvotg) | |
231 | { | |
df18feda | 232 | clk_prepare_enable(mvotg->clk); |
277164f0 NZ |
233 | } |
234 | ||
235 | static void otg_clock_disable(struct mv_otg *mvotg) | |
236 | { | |
df18feda | 237 | clk_disable_unprepare(mvotg->clk); |
277164f0 NZ |
238 | } |
239 | ||
240 | static int mv_otg_enable_internal(struct mv_otg *mvotg) | |
241 | { | |
242 | int retval = 0; | |
243 | ||
244 | if (mvotg->active) | |
245 | return 0; | |
246 | ||
247 | dev_dbg(&mvotg->pdev->dev, "otg enabled\n"); | |
248 | ||
249 | otg_clock_enable(mvotg); | |
250 | if (mvotg->pdata->phy_init) { | |
251 | retval = mvotg->pdata->phy_init(mvotg->phy_regs); | |
252 | if (retval) { | |
253 | dev_err(&mvotg->pdev->dev, | |
254 | "init phy error %d\n", retval); | |
255 | otg_clock_disable(mvotg); | |
256 | return retval; | |
257 | } | |
258 | } | |
259 | mvotg->active = 1; | |
260 | ||
261 | return 0; | |
262 | ||
263 | } | |
264 | ||
265 | static int mv_otg_enable(struct mv_otg *mvotg) | |
266 | { | |
267 | if (mvotg->clock_gating) | |
268 | return mv_otg_enable_internal(mvotg); | |
269 | ||
270 | return 0; | |
271 | } | |
272 | ||
273 | static void mv_otg_disable_internal(struct mv_otg *mvotg) | |
274 | { | |
275 | if (mvotg->active) { | |
276 | dev_dbg(&mvotg->pdev->dev, "otg disabled\n"); | |
277 | if (mvotg->pdata->phy_deinit) | |
278 | mvotg->pdata->phy_deinit(mvotg->phy_regs); | |
279 | otg_clock_disable(mvotg); | |
280 | mvotg->active = 0; | |
281 | } | |
282 | } | |
283 | ||
284 | static void mv_otg_disable(struct mv_otg *mvotg) | |
285 | { | |
286 | if (mvotg->clock_gating) | |
287 | mv_otg_disable_internal(mvotg); | |
288 | } | |
289 | ||
290 | static void mv_otg_update_inputs(struct mv_otg *mvotg) | |
291 | { | |
292 | struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl; | |
293 | u32 otgsc; | |
294 | ||
295 | otgsc = readl(&mvotg->op_regs->otgsc); | |
296 | ||
297 | if (mvotg->pdata->vbus) { | |
298 | if (mvotg->pdata->vbus->poll() == VBUS_HIGH) { | |
299 | otg_ctrl->b_sess_vld = 1; | |
300 | otg_ctrl->b_sess_end = 0; | |
301 | } else { | |
302 | otg_ctrl->b_sess_vld = 0; | |
303 | otg_ctrl->b_sess_end = 1; | |
304 | } | |
305 | } else { | |
306 | otg_ctrl->b_sess_vld = !!(otgsc & OTGSC_STS_B_SESSION_VALID); | |
307 | otg_ctrl->b_sess_end = !!(otgsc & OTGSC_STS_B_SESSION_END); | |
308 | } | |
309 | ||
310 | if (mvotg->pdata->id) | |
311 | otg_ctrl->id = !!mvotg->pdata->id->poll(); | |
312 | else | |
313 | otg_ctrl->id = !!(otgsc & OTGSC_STS_USB_ID); | |
314 | ||
315 | if (mvotg->pdata->otg_force_a_bus_req && !otg_ctrl->id) | |
316 | otg_ctrl->a_bus_req = 1; | |
317 | ||
318 | otg_ctrl->a_sess_vld = !!(otgsc & OTGSC_STS_A_SESSION_VALID); | |
319 | otg_ctrl->a_vbus_vld = !!(otgsc & OTGSC_STS_A_VBUS_VALID); | |
320 | ||
321 | dev_dbg(&mvotg->pdev->dev, "%s: ", __func__); | |
322 | dev_dbg(&mvotg->pdev->dev, "id %d\n", otg_ctrl->id); | |
323 | dev_dbg(&mvotg->pdev->dev, "b_sess_vld %d\n", otg_ctrl->b_sess_vld); | |
324 | dev_dbg(&mvotg->pdev->dev, "b_sess_end %d\n", otg_ctrl->b_sess_end); | |
325 | dev_dbg(&mvotg->pdev->dev, "a_vbus_vld %d\n", otg_ctrl->a_vbus_vld); | |
326 | dev_dbg(&mvotg->pdev->dev, "a_sess_vld %d\n", otg_ctrl->a_sess_vld); | |
327 | } | |
328 | ||
329 | static void mv_otg_update_state(struct mv_otg *mvotg) | |
330 | { | |
331 | struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl; | |
e47d9254 | 332 | int old_state = mvotg->phy.otg->state; |
277164f0 NZ |
333 | |
334 | switch (old_state) { | |
335 | case OTG_STATE_UNDEFINED: | |
e47d9254 | 336 | mvotg->phy.otg->state = OTG_STATE_B_IDLE; |
277164f0 NZ |
337 | /* FALL THROUGH */ |
338 | case OTG_STATE_B_IDLE: | |
339 | if (otg_ctrl->id == 0) | |
e47d9254 | 340 | mvotg->phy.otg->state = OTG_STATE_A_IDLE; |
277164f0 | 341 | else if (otg_ctrl->b_sess_vld) |
e47d9254 | 342 | mvotg->phy.otg->state = OTG_STATE_B_PERIPHERAL; |
277164f0 NZ |
343 | break; |
344 | case OTG_STATE_B_PERIPHERAL: | |
345 | if (!otg_ctrl->b_sess_vld || otg_ctrl->id == 0) | |
e47d9254 | 346 | mvotg->phy.otg->state = OTG_STATE_B_IDLE; |
277164f0 NZ |
347 | break; |
348 | case OTG_STATE_A_IDLE: | |
349 | if (otg_ctrl->id) | |
e47d9254 | 350 | mvotg->phy.otg->state = OTG_STATE_B_IDLE; |
277164f0 NZ |
351 | else if (!(otg_ctrl->a_bus_drop) && |
352 | (otg_ctrl->a_bus_req || otg_ctrl->a_srp_det)) | |
e47d9254 | 353 | mvotg->phy.otg->state = OTG_STATE_A_WAIT_VRISE; |
277164f0 NZ |
354 | break; |
355 | case OTG_STATE_A_WAIT_VRISE: | |
356 | if (otg_ctrl->a_vbus_vld) | |
e47d9254 | 357 | mvotg->phy.otg->state = OTG_STATE_A_WAIT_BCON; |
277164f0 NZ |
358 | break; |
359 | case OTG_STATE_A_WAIT_BCON: | |
360 | if (otg_ctrl->id || otg_ctrl->a_bus_drop | |
361 | || otg_ctrl->a_wait_bcon_timeout) { | |
362 | mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER); | |
363 | mvotg->otg_ctrl.a_wait_bcon_timeout = 0; | |
e47d9254 | 364 | mvotg->phy.otg->state = OTG_STATE_A_WAIT_VFALL; |
277164f0 NZ |
365 | otg_ctrl->a_bus_req = 0; |
366 | } else if (!otg_ctrl->a_vbus_vld) { | |
367 | mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER); | |
368 | mvotg->otg_ctrl.a_wait_bcon_timeout = 0; | |
e47d9254 | 369 | mvotg->phy.otg->state = OTG_STATE_A_VBUS_ERR; |
277164f0 NZ |
370 | } else if (otg_ctrl->b_conn) { |
371 | mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER); | |
372 | mvotg->otg_ctrl.a_wait_bcon_timeout = 0; | |
e47d9254 | 373 | mvotg->phy.otg->state = OTG_STATE_A_HOST; |
277164f0 NZ |
374 | } |
375 | break; | |
376 | case OTG_STATE_A_HOST: | |
377 | if (otg_ctrl->id || !otg_ctrl->b_conn | |
378 | || otg_ctrl->a_bus_drop) | |
e47d9254 | 379 | mvotg->phy.otg->state = OTG_STATE_A_WAIT_BCON; |
277164f0 | 380 | else if (!otg_ctrl->a_vbus_vld) |
e47d9254 | 381 | mvotg->phy.otg->state = OTG_STATE_A_VBUS_ERR; |
277164f0 NZ |
382 | break; |
383 | case OTG_STATE_A_WAIT_VFALL: | |
384 | if (otg_ctrl->id | |
385 | || (!otg_ctrl->b_conn && otg_ctrl->a_sess_vld) | |
386 | || otg_ctrl->a_bus_req) | |
e47d9254 | 387 | mvotg->phy.otg->state = OTG_STATE_A_IDLE; |
277164f0 NZ |
388 | break; |
389 | case OTG_STATE_A_VBUS_ERR: | |
390 | if (otg_ctrl->id || otg_ctrl->a_clr_err | |
391 | || otg_ctrl->a_bus_drop) { | |
392 | otg_ctrl->a_clr_err = 0; | |
e47d9254 | 393 | mvotg->phy.otg->state = OTG_STATE_A_WAIT_VFALL; |
277164f0 NZ |
394 | } |
395 | break; | |
396 | default: | |
397 | break; | |
398 | } | |
399 | } | |
400 | ||
401 | static void mv_otg_work(struct work_struct *work) | |
402 | { | |
403 | struct mv_otg *mvotg; | |
b1c711d6 | 404 | struct usb_otg *otg; |
277164f0 NZ |
405 | int old_state; |
406 | ||
63a13079 | 407 | mvotg = container_of(to_delayed_work(work), struct mv_otg, work); |
277164f0 NZ |
408 | |
409 | run: | |
410 | /* work queue is single thread, or we need spin_lock to protect */ | |
e47d9254 AT |
411 | otg = mvotg->phy.otg; |
412 | old_state = otg->state; | |
277164f0 NZ |
413 | |
414 | if (!mvotg->active) | |
415 | return; | |
416 | ||
417 | mv_otg_update_inputs(mvotg); | |
418 | mv_otg_update_state(mvotg); | |
419 | ||
e47d9254 | 420 | if (old_state != mvotg->phy.otg->state) { |
277164f0 NZ |
421 | dev_info(&mvotg->pdev->dev, "change from state %s to %s\n", |
422 | state_string[old_state], | |
e47d9254 | 423 | state_string[mvotg->phy.otg->state]); |
277164f0 | 424 | |
e47d9254 | 425 | switch (mvotg->phy.otg->state) { |
277164f0 | 426 | case OTG_STATE_B_IDLE: |
b1c711d6 | 427 | otg->default_a = 0; |
277164f0 NZ |
428 | if (old_state == OTG_STATE_B_PERIPHERAL) |
429 | mv_otg_start_periphrals(mvotg, 0); | |
430 | mv_otg_reset(mvotg); | |
431 | mv_otg_disable(mvotg); | |
b20f3f9e | 432 | usb_phy_set_event(&mvotg->phy, USB_EVENT_NONE); |
277164f0 NZ |
433 | break; |
434 | case OTG_STATE_B_PERIPHERAL: | |
435 | mv_otg_enable(mvotg); | |
436 | mv_otg_start_periphrals(mvotg, 1); | |
b20f3f9e | 437 | usb_phy_set_event(&mvotg->phy, USB_EVENT_ENUMERATED); |
277164f0 NZ |
438 | break; |
439 | case OTG_STATE_A_IDLE: | |
b1c711d6 | 440 | otg->default_a = 1; |
277164f0 NZ |
441 | mv_otg_enable(mvotg); |
442 | if (old_state == OTG_STATE_A_WAIT_VFALL) | |
443 | mv_otg_start_host(mvotg, 0); | |
444 | mv_otg_reset(mvotg); | |
445 | break; | |
446 | case OTG_STATE_A_WAIT_VRISE: | |
b1c711d6 | 447 | mv_otg_set_vbus(otg, 1); |
277164f0 NZ |
448 | break; |
449 | case OTG_STATE_A_WAIT_BCON: | |
450 | if (old_state != OTG_STATE_A_HOST) | |
451 | mv_otg_start_host(mvotg, 1); | |
452 | mv_otg_set_timer(mvotg, A_WAIT_BCON_TIMER, | |
9718756f | 453 | T_A_WAIT_BCON); |
277164f0 NZ |
454 | /* |
455 | * Now, we directly enter A_HOST. So set b_conn = 1 | |
456 | * here. In fact, it need host driver to notify us. | |
457 | */ | |
458 | mvotg->otg_ctrl.b_conn = 1; | |
459 | break; | |
460 | case OTG_STATE_A_HOST: | |
461 | break; | |
462 | case OTG_STATE_A_WAIT_VFALL: | |
463 | /* | |
464 | * Now, we has exited A_HOST. So set b_conn = 0 | |
465 | * here. In fact, it need host driver to notify us. | |
466 | */ | |
467 | mvotg->otg_ctrl.b_conn = 0; | |
b1c711d6 | 468 | mv_otg_set_vbus(otg, 0); |
277164f0 NZ |
469 | break; |
470 | case OTG_STATE_A_VBUS_ERR: | |
471 | break; | |
472 | default: | |
473 | break; | |
474 | } | |
475 | goto run; | |
476 | } | |
477 | } | |
478 | ||
479 | static irqreturn_t mv_otg_irq(int irq, void *dev) | |
480 | { | |
481 | struct mv_otg *mvotg = dev; | |
482 | u32 otgsc; | |
483 | ||
484 | otgsc = readl(&mvotg->op_regs->otgsc); | |
485 | writel(otgsc, &mvotg->op_regs->otgsc); | |
486 | ||
487 | /* | |
488 | * if we have vbus, then the vbus detection for B-device | |
489 | * will be done by mv_otg_inputs_irq(). | |
490 | */ | |
491 | if (mvotg->pdata->vbus) | |
492 | if ((otgsc & OTGSC_STS_USB_ID) && | |
493 | !(otgsc & OTGSC_INTSTS_USB_ID)) | |
494 | return IRQ_NONE; | |
495 | ||
496 | if ((otgsc & mvotg->irq_status) == 0) | |
497 | return IRQ_NONE; | |
498 | ||
499 | mv_otg_run_state_machine(mvotg, 0); | |
500 | ||
501 | return IRQ_HANDLED; | |
502 | } | |
503 | ||
504 | static irqreturn_t mv_otg_inputs_irq(int irq, void *dev) | |
505 | { | |
506 | struct mv_otg *mvotg = dev; | |
507 | ||
508 | /* The clock may disabled at this time */ | |
509 | if (!mvotg->active) { | |
510 | mv_otg_enable(mvotg); | |
511 | mv_otg_init_irq(mvotg); | |
512 | } | |
513 | ||
514 | mv_otg_run_state_machine(mvotg, 0); | |
515 | ||
516 | return IRQ_HANDLED; | |
517 | } | |
518 | ||
519 | static ssize_t | |
ed5bd7a4 | 520 | a_bus_req_show(struct device *dev, struct device_attribute *attr, char *buf) |
277164f0 NZ |
521 | { |
522 | struct mv_otg *mvotg = dev_get_drvdata(dev); | |
523 | return scnprintf(buf, PAGE_SIZE, "%d\n", | |
524 | mvotg->otg_ctrl.a_bus_req); | |
525 | } | |
526 | ||
527 | static ssize_t | |
ed5bd7a4 | 528 | a_bus_req_store(struct device *dev, struct device_attribute *attr, |
277164f0 NZ |
529 | const char *buf, size_t count) |
530 | { | |
531 | struct mv_otg *mvotg = dev_get_drvdata(dev); | |
532 | ||
533 | if (count > 2) | |
534 | return -1; | |
535 | ||
536 | /* We will use this interface to change to A device */ | |
e47d9254 AT |
537 | if (mvotg->phy.otg->state != OTG_STATE_B_IDLE |
538 | && mvotg->phy.otg->state != OTG_STATE_A_IDLE) | |
277164f0 NZ |
539 | return -1; |
540 | ||
541 | /* The clock may disabled and we need to set irq for ID detected */ | |
542 | mv_otg_enable(mvotg); | |
543 | mv_otg_init_irq(mvotg); | |
544 | ||
545 | if (buf[0] == '1') { | |
546 | mvotg->otg_ctrl.a_bus_req = 1; | |
547 | mvotg->otg_ctrl.a_bus_drop = 0; | |
548 | dev_dbg(&mvotg->pdev->dev, | |
549 | "User request: a_bus_req = 1\n"); | |
550 | ||
551 | if (spin_trylock(&mvotg->wq_lock)) { | |
552 | mv_otg_run_state_machine(mvotg, 0); | |
553 | spin_unlock(&mvotg->wq_lock); | |
554 | } | |
555 | } | |
556 | ||
557 | return count; | |
558 | } | |
559 | ||
ed5bd7a4 | 560 | static DEVICE_ATTR_RW(a_bus_req); |
277164f0 NZ |
561 | |
562 | static ssize_t | |
ca35910a | 563 | a_clr_err_store(struct device *dev, struct device_attribute *attr, |
277164f0 NZ |
564 | const char *buf, size_t count) |
565 | { | |
566 | struct mv_otg *mvotg = dev_get_drvdata(dev); | |
b1c711d6 | 567 | if (!mvotg->phy.otg->default_a) |
277164f0 NZ |
568 | return -1; |
569 | ||
570 | if (count > 2) | |
571 | return -1; | |
572 | ||
573 | if (buf[0] == '1') { | |
574 | mvotg->otg_ctrl.a_clr_err = 1; | |
575 | dev_dbg(&mvotg->pdev->dev, | |
576 | "User request: a_clr_err = 1\n"); | |
577 | } | |
578 | ||
579 | if (spin_trylock(&mvotg->wq_lock)) { | |
580 | mv_otg_run_state_machine(mvotg, 0); | |
581 | spin_unlock(&mvotg->wq_lock); | |
582 | } | |
583 | ||
584 | return count; | |
585 | } | |
586 | ||
ca35910a | 587 | static DEVICE_ATTR_WO(a_clr_err); |
277164f0 NZ |
588 | |
589 | static ssize_t | |
ed5bd7a4 | 590 | a_bus_drop_show(struct device *dev, struct device_attribute *attr, |
277164f0 NZ |
591 | char *buf) |
592 | { | |
593 | struct mv_otg *mvotg = dev_get_drvdata(dev); | |
594 | return scnprintf(buf, PAGE_SIZE, "%d\n", | |
595 | mvotg->otg_ctrl.a_bus_drop); | |
596 | } | |
597 | ||
598 | static ssize_t | |
ed5bd7a4 | 599 | a_bus_drop_store(struct device *dev, struct device_attribute *attr, |
277164f0 NZ |
600 | const char *buf, size_t count) |
601 | { | |
602 | struct mv_otg *mvotg = dev_get_drvdata(dev); | |
b1c711d6 | 603 | if (!mvotg->phy.otg->default_a) |
277164f0 NZ |
604 | return -1; |
605 | ||
606 | if (count > 2) | |
607 | return -1; | |
608 | ||
609 | if (buf[0] == '0') { | |
610 | mvotg->otg_ctrl.a_bus_drop = 0; | |
611 | dev_dbg(&mvotg->pdev->dev, | |
612 | "User request: a_bus_drop = 0\n"); | |
613 | } else if (buf[0] == '1') { | |
614 | mvotg->otg_ctrl.a_bus_drop = 1; | |
615 | mvotg->otg_ctrl.a_bus_req = 0; | |
616 | dev_dbg(&mvotg->pdev->dev, | |
617 | "User request: a_bus_drop = 1\n"); | |
618 | dev_dbg(&mvotg->pdev->dev, | |
619 | "User request: and a_bus_req = 0\n"); | |
620 | } | |
621 | ||
622 | if (spin_trylock(&mvotg->wq_lock)) { | |
623 | mv_otg_run_state_machine(mvotg, 0); | |
624 | spin_unlock(&mvotg->wq_lock); | |
625 | } | |
626 | ||
627 | return count; | |
628 | } | |
629 | ||
ed5bd7a4 | 630 | static DEVICE_ATTR_RW(a_bus_drop); |
277164f0 NZ |
631 | |
632 | static struct attribute *inputs_attrs[] = { | |
633 | &dev_attr_a_bus_req.attr, | |
634 | &dev_attr_a_clr_err.attr, | |
635 | &dev_attr_a_bus_drop.attr, | |
636 | NULL, | |
637 | }; | |
638 | ||
1cefc269 | 639 | static const struct attribute_group inputs_attr_group = { |
277164f0 NZ |
640 | .name = "inputs", |
641 | .attrs = inputs_attrs, | |
642 | }; | |
643 | ||
3e2cb866 GKH |
644 | static const struct attribute_group *mv_otg_groups[] = { |
645 | &inputs_attr_group, | |
646 | NULL, | |
647 | }; | |
648 | ||
d07f4a82 | 649 | static int mv_otg_remove(struct platform_device *pdev) |
277164f0 NZ |
650 | { |
651 | struct mv_otg *mvotg = platform_get_drvdata(pdev); | |
277164f0 | 652 | |
277164f0 NZ |
653 | if (mvotg->qwork) { |
654 | flush_workqueue(mvotg->qwork); | |
655 | destroy_workqueue(mvotg->qwork); | |
656 | } | |
657 | ||
658 | mv_otg_disable(mvotg); | |
659 | ||
662dca54 | 660 | usb_remove_phy(&mvotg->phy); |
277164f0 | 661 | |
277164f0 NZ |
662 | return 0; |
663 | } | |
664 | ||
665 | static int mv_otg_probe(struct platform_device *pdev) | |
666 | { | |
19f9e188 | 667 | struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); |
277164f0 | 668 | struct mv_otg *mvotg; |
b1c711d6 | 669 | struct usb_otg *otg; |
277164f0 | 670 | struct resource *r; |
df18feda | 671 | int retval = 0, i; |
277164f0 NZ |
672 | |
673 | if (pdata == NULL) { | |
674 | dev_err(&pdev->dev, "failed to get platform data\n"); | |
675 | return -ENODEV; | |
676 | } | |
677 | ||
df18feda | 678 | mvotg = devm_kzalloc(&pdev->dev, sizeof(*mvotg), GFP_KERNEL); |
aa10c7b0 | 679 | if (!mvotg) |
277164f0 | 680 | return -ENOMEM; |
277164f0 | 681 | |
fb3dfe13 CX |
682 | otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); |
683 | if (!otg) | |
b1c711d6 | 684 | return -ENOMEM; |
b1c711d6 | 685 | |
277164f0 NZ |
686 | platform_set_drvdata(pdev, mvotg); |
687 | ||
688 | mvotg->pdev = pdev; | |
689 | mvotg->pdata = pdata; | |
690 | ||
df18feda CX |
691 | mvotg->clk = devm_clk_get(&pdev->dev, NULL); |
692 | if (IS_ERR(mvotg->clk)) | |
693 | return PTR_ERR(mvotg->clk); | |
277164f0 NZ |
694 | |
695 | mvotg->qwork = create_singlethread_workqueue("mv_otg_queue"); | |
696 | if (!mvotg->qwork) { | |
697 | dev_dbg(&pdev->dev, "cannot create workqueue for OTG\n"); | |
fb3dfe13 | 698 | return -ENOMEM; |
277164f0 NZ |
699 | } |
700 | ||
701 | INIT_DELAYED_WORK(&mvotg->work, mv_otg_work); | |
702 | ||
703 | /* OTG common part */ | |
704 | mvotg->pdev = pdev; | |
b1c711d6 HK |
705 | mvotg->phy.dev = &pdev->dev; |
706 | mvotg->phy.otg = otg; | |
707 | mvotg->phy.label = driver_name; | |
b1c711d6 | 708 | |
e47d9254 | 709 | otg->state = OTG_STATE_UNDEFINED; |
19c1eac2 | 710 | otg->usb_phy = &mvotg->phy; |
b1c711d6 HK |
711 | otg->set_host = mv_otg_set_host; |
712 | otg->set_peripheral = mv_otg_set_peripheral; | |
713 | otg->set_vbus = mv_otg_set_vbus; | |
277164f0 NZ |
714 | |
715 | for (i = 0; i < OTG_TIMER_NUM; i++) | |
9718756f KC |
716 | timer_setup(&mvotg->otg_ctrl.timer[i], |
717 | mv_otg_timer_await_bcon, 0); | |
277164f0 NZ |
718 | |
719 | r = platform_get_resource_byname(mvotg->pdev, | |
720 | IORESOURCE_MEM, "phyregs"); | |
721 | if (r == NULL) { | |
722 | dev_err(&pdev->dev, "no phy I/O memory resource defined\n"); | |
723 | retval = -ENODEV; | |
724 | goto err_destroy_workqueue; | |
725 | } | |
726 | ||
fb3dfe13 | 727 | mvotg->phy_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r)); |
277164f0 NZ |
728 | if (mvotg->phy_regs == NULL) { |
729 | dev_err(&pdev->dev, "failed to map phy I/O memory\n"); | |
730 | retval = -EFAULT; | |
731 | goto err_destroy_workqueue; | |
732 | } | |
733 | ||
734 | r = platform_get_resource_byname(mvotg->pdev, | |
735 | IORESOURCE_MEM, "capregs"); | |
736 | if (r == NULL) { | |
737 | dev_err(&pdev->dev, "no I/O memory resource defined\n"); | |
738 | retval = -ENODEV; | |
fb3dfe13 | 739 | goto err_destroy_workqueue; |
277164f0 NZ |
740 | } |
741 | ||
fb3dfe13 | 742 | mvotg->cap_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r)); |
277164f0 NZ |
743 | if (mvotg->cap_regs == NULL) { |
744 | dev_err(&pdev->dev, "failed to map I/O memory\n"); | |
745 | retval = -EFAULT; | |
fb3dfe13 | 746 | goto err_destroy_workqueue; |
277164f0 NZ |
747 | } |
748 | ||
749 | /* we will acces controller register, so enable the udc controller */ | |
750 | retval = mv_otg_enable_internal(mvotg); | |
751 | if (retval) { | |
752 | dev_err(&pdev->dev, "mv otg enable error %d\n", retval); | |
fb3dfe13 | 753 | goto err_destroy_workqueue; |
277164f0 NZ |
754 | } |
755 | ||
756 | mvotg->op_regs = | |
757 | (struct mv_otg_regs __iomem *) ((unsigned long) mvotg->cap_regs | |
758 | + (readl(mvotg->cap_regs) & CAPLENGTH_MASK)); | |
759 | ||
760 | if (pdata->id) { | |
fb3dfe13 CX |
761 | retval = devm_request_threaded_irq(&pdev->dev, pdata->id->irq, |
762 | NULL, mv_otg_inputs_irq, | |
763 | IRQF_ONESHOT, "id", mvotg); | |
277164f0 NZ |
764 | if (retval) { |
765 | dev_info(&pdev->dev, | |
766 | "Failed to request irq for ID\n"); | |
767 | pdata->id = NULL; | |
768 | } | |
769 | } | |
770 | ||
771 | if (pdata->vbus) { | |
772 | mvotg->clock_gating = 1; | |
fb3dfe13 CX |
773 | retval = devm_request_threaded_irq(&pdev->dev, pdata->vbus->irq, |
774 | NULL, mv_otg_inputs_irq, | |
775 | IRQF_ONESHOT, "vbus", mvotg); | |
277164f0 NZ |
776 | if (retval) { |
777 | dev_info(&pdev->dev, | |
778 | "Failed to request irq for VBUS, " | |
779 | "disable clock gating\n"); | |
780 | mvotg->clock_gating = 0; | |
781 | pdata->vbus = NULL; | |
782 | } | |
783 | } | |
784 | ||
785 | if (pdata->disable_otg_clock_gating) | |
786 | mvotg->clock_gating = 0; | |
787 | ||
788 | mv_otg_reset(mvotg); | |
789 | mv_otg_init_irq(mvotg); | |
790 | ||
791 | r = platform_get_resource(mvotg->pdev, IORESOURCE_IRQ, 0); | |
792 | if (r == NULL) { | |
793 | dev_err(&pdev->dev, "no IRQ resource defined\n"); | |
794 | retval = -ENODEV; | |
795 | goto err_disable_clk; | |
796 | } | |
797 | ||
798 | mvotg->irq = r->start; | |
fb3dfe13 | 799 | if (devm_request_irq(&pdev->dev, mvotg->irq, mv_otg_irq, IRQF_SHARED, |
277164f0 NZ |
800 | driver_name, mvotg)) { |
801 | dev_err(&pdev->dev, "Request irq %d for OTG failed\n", | |
802 | mvotg->irq); | |
803 | mvotg->irq = 0; | |
804 | retval = -ENODEV; | |
805 | goto err_disable_clk; | |
806 | } | |
807 | ||
662dca54 | 808 | retval = usb_add_phy(&mvotg->phy, USB_PHY_TYPE_USB2); |
277164f0 NZ |
809 | if (retval < 0) { |
810 | dev_err(&pdev->dev, "can't register transceiver, %d\n", | |
811 | retval); | |
fb3dfe13 | 812 | goto err_disable_clk; |
277164f0 NZ |
813 | } |
814 | ||
277164f0 NZ |
815 | spin_lock_init(&mvotg->wq_lock); |
816 | if (spin_trylock(&mvotg->wq_lock)) { | |
817 | mv_otg_run_state_machine(mvotg, 2 * HZ); | |
818 | spin_unlock(&mvotg->wq_lock); | |
819 | } | |
820 | ||
821 | dev_info(&pdev->dev, | |
822 | "successful probe OTG device %s clock gating.\n", | |
823 | mvotg->clock_gating ? "with" : "without"); | |
824 | ||
825 | return 0; | |
826 | ||
277164f0 | 827 | err_disable_clk: |
277164f0 | 828 | mv_otg_disable_internal(mvotg); |
277164f0 NZ |
829 | err_destroy_workqueue: |
830 | flush_workqueue(mvotg->qwork); | |
831 | destroy_workqueue(mvotg->qwork); | |
277164f0 | 832 | |
277164f0 NZ |
833 | return retval; |
834 | } | |
835 | ||
836 | #ifdef CONFIG_PM | |
837 | static int mv_otg_suspend(struct platform_device *pdev, pm_message_t state) | |
838 | { | |
839 | struct mv_otg *mvotg = platform_get_drvdata(pdev); | |
840 | ||
90bdf403 | 841 | if (mvotg->phy.otg->state != OTG_STATE_B_IDLE) { |
277164f0 NZ |
842 | dev_info(&pdev->dev, |
843 | "OTG state is not B_IDLE, it is %d!\n", | |
90bdf403 | 844 | mvotg->phy.otg->state); |
277164f0 NZ |
845 | return -EAGAIN; |
846 | } | |
847 | ||
848 | if (!mvotg->clock_gating) | |
849 | mv_otg_disable_internal(mvotg); | |
850 | ||
851 | return 0; | |
852 | } | |
853 | ||
854 | static int mv_otg_resume(struct platform_device *pdev) | |
855 | { | |
856 | struct mv_otg *mvotg = platform_get_drvdata(pdev); | |
857 | u32 otgsc; | |
858 | ||
859 | if (!mvotg->clock_gating) { | |
860 | mv_otg_enable_internal(mvotg); | |
861 | ||
862 | otgsc = readl(&mvotg->op_regs->otgsc); | |
863 | otgsc |= mvotg->irq_en; | |
864 | writel(otgsc, &mvotg->op_regs->otgsc); | |
865 | ||
866 | if (spin_trylock(&mvotg->wq_lock)) { | |
867 | mv_otg_run_state_machine(mvotg, 0); | |
868 | spin_unlock(&mvotg->wq_lock); | |
869 | } | |
870 | } | |
871 | return 0; | |
872 | } | |
873 | #endif | |
874 | ||
875 | static struct platform_driver mv_otg_driver = { | |
876 | .probe = mv_otg_probe, | |
d07f4a82 | 877 | .remove = mv_otg_remove, |
277164f0 | 878 | .driver = { |
277164f0 | 879 | .name = driver_name, |
3e2cb866 | 880 | .dev_groups = mv_otg_groups, |
277164f0 NZ |
881 | }, |
882 | #ifdef CONFIG_PM | |
883 | .suspend = mv_otg_suspend, | |
884 | .resume = mv_otg_resume, | |
885 | #endif | |
886 | }; | |
ca21dda6 | 887 | module_platform_driver(mv_otg_driver); |