]>
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 <[email protected]> | |
5 | * Neil Zhang <[email protected]> | |
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 HK |
404 | struct usb_phy *phy; |
405 | struct usb_otg *otg; | |
277164f0 NZ |
406 | int old_state; |
407 | ||
63a13079 | 408 | mvotg = container_of(to_delayed_work(work), struct mv_otg, work); |
277164f0 NZ |
409 | |
410 | run: | |
411 | /* work queue is single thread, or we need spin_lock to protect */ | |
b1c711d6 | 412 | phy = &mvotg->phy; |
e47d9254 AT |
413 | otg = mvotg->phy.otg; |
414 | old_state = otg->state; | |
277164f0 NZ |
415 | |
416 | if (!mvotg->active) | |
417 | return; | |
418 | ||
419 | mv_otg_update_inputs(mvotg); | |
420 | mv_otg_update_state(mvotg); | |
421 | ||
e47d9254 | 422 | if (old_state != mvotg->phy.otg->state) { |
277164f0 NZ |
423 | dev_info(&mvotg->pdev->dev, "change from state %s to %s\n", |
424 | state_string[old_state], | |
e47d9254 | 425 | state_string[mvotg->phy.otg->state]); |
277164f0 | 426 | |
e47d9254 | 427 | switch (mvotg->phy.otg->state) { |
277164f0 | 428 | case OTG_STATE_B_IDLE: |
b1c711d6 | 429 | otg->default_a = 0; |
277164f0 NZ |
430 | if (old_state == OTG_STATE_B_PERIPHERAL) |
431 | mv_otg_start_periphrals(mvotg, 0); | |
432 | mv_otg_reset(mvotg); | |
433 | mv_otg_disable(mvotg); | |
b20f3f9e | 434 | usb_phy_set_event(&mvotg->phy, USB_EVENT_NONE); |
277164f0 NZ |
435 | break; |
436 | case OTG_STATE_B_PERIPHERAL: | |
437 | mv_otg_enable(mvotg); | |
438 | mv_otg_start_periphrals(mvotg, 1); | |
b20f3f9e | 439 | usb_phy_set_event(&mvotg->phy, USB_EVENT_ENUMERATED); |
277164f0 NZ |
440 | break; |
441 | case OTG_STATE_A_IDLE: | |
b1c711d6 | 442 | otg->default_a = 1; |
277164f0 NZ |
443 | mv_otg_enable(mvotg); |
444 | if (old_state == OTG_STATE_A_WAIT_VFALL) | |
445 | mv_otg_start_host(mvotg, 0); | |
446 | mv_otg_reset(mvotg); | |
447 | break; | |
448 | case OTG_STATE_A_WAIT_VRISE: | |
b1c711d6 | 449 | mv_otg_set_vbus(otg, 1); |
277164f0 NZ |
450 | break; |
451 | case OTG_STATE_A_WAIT_BCON: | |
452 | if (old_state != OTG_STATE_A_HOST) | |
453 | mv_otg_start_host(mvotg, 1); | |
454 | mv_otg_set_timer(mvotg, A_WAIT_BCON_TIMER, | |
9718756f | 455 | T_A_WAIT_BCON); |
277164f0 NZ |
456 | /* |
457 | * Now, we directly enter A_HOST. So set b_conn = 1 | |
458 | * here. In fact, it need host driver to notify us. | |
459 | */ | |
460 | mvotg->otg_ctrl.b_conn = 1; | |
461 | break; | |
462 | case OTG_STATE_A_HOST: | |
463 | break; | |
464 | case OTG_STATE_A_WAIT_VFALL: | |
465 | /* | |
466 | * Now, we has exited A_HOST. So set b_conn = 0 | |
467 | * here. In fact, it need host driver to notify us. | |
468 | */ | |
469 | mvotg->otg_ctrl.b_conn = 0; | |
b1c711d6 | 470 | mv_otg_set_vbus(otg, 0); |
277164f0 NZ |
471 | break; |
472 | case OTG_STATE_A_VBUS_ERR: | |
473 | break; | |
474 | default: | |
475 | break; | |
476 | } | |
477 | goto run; | |
478 | } | |
479 | } | |
480 | ||
481 | static irqreturn_t mv_otg_irq(int irq, void *dev) | |
482 | { | |
483 | struct mv_otg *mvotg = dev; | |
484 | u32 otgsc; | |
485 | ||
486 | otgsc = readl(&mvotg->op_regs->otgsc); | |
487 | writel(otgsc, &mvotg->op_regs->otgsc); | |
488 | ||
489 | /* | |
490 | * if we have vbus, then the vbus detection for B-device | |
491 | * will be done by mv_otg_inputs_irq(). | |
492 | */ | |
493 | if (mvotg->pdata->vbus) | |
494 | if ((otgsc & OTGSC_STS_USB_ID) && | |
495 | !(otgsc & OTGSC_INTSTS_USB_ID)) | |
496 | return IRQ_NONE; | |
497 | ||
498 | if ((otgsc & mvotg->irq_status) == 0) | |
499 | return IRQ_NONE; | |
500 | ||
501 | mv_otg_run_state_machine(mvotg, 0); | |
502 | ||
503 | return IRQ_HANDLED; | |
504 | } | |
505 | ||
506 | static irqreturn_t mv_otg_inputs_irq(int irq, void *dev) | |
507 | { | |
508 | struct mv_otg *mvotg = dev; | |
509 | ||
510 | /* The clock may disabled at this time */ | |
511 | if (!mvotg->active) { | |
512 | mv_otg_enable(mvotg); | |
513 | mv_otg_init_irq(mvotg); | |
514 | } | |
515 | ||
516 | mv_otg_run_state_machine(mvotg, 0); | |
517 | ||
518 | return IRQ_HANDLED; | |
519 | } | |
520 | ||
521 | static ssize_t | |
ed5bd7a4 | 522 | a_bus_req_show(struct device *dev, struct device_attribute *attr, char *buf) |
277164f0 NZ |
523 | { |
524 | struct mv_otg *mvotg = dev_get_drvdata(dev); | |
525 | return scnprintf(buf, PAGE_SIZE, "%d\n", | |
526 | mvotg->otg_ctrl.a_bus_req); | |
527 | } | |
528 | ||
529 | static ssize_t | |
ed5bd7a4 | 530 | a_bus_req_store(struct device *dev, struct device_attribute *attr, |
277164f0 NZ |
531 | const char *buf, size_t count) |
532 | { | |
533 | struct mv_otg *mvotg = dev_get_drvdata(dev); | |
534 | ||
535 | if (count > 2) | |
536 | return -1; | |
537 | ||
538 | /* We will use this interface to change to A device */ | |
e47d9254 AT |
539 | if (mvotg->phy.otg->state != OTG_STATE_B_IDLE |
540 | && mvotg->phy.otg->state != OTG_STATE_A_IDLE) | |
277164f0 NZ |
541 | return -1; |
542 | ||
543 | /* The clock may disabled and we need to set irq for ID detected */ | |
544 | mv_otg_enable(mvotg); | |
545 | mv_otg_init_irq(mvotg); | |
546 | ||
547 | if (buf[0] == '1') { | |
548 | mvotg->otg_ctrl.a_bus_req = 1; | |
549 | mvotg->otg_ctrl.a_bus_drop = 0; | |
550 | dev_dbg(&mvotg->pdev->dev, | |
551 | "User request: a_bus_req = 1\n"); | |
552 | ||
553 | if (spin_trylock(&mvotg->wq_lock)) { | |
554 | mv_otg_run_state_machine(mvotg, 0); | |
555 | spin_unlock(&mvotg->wq_lock); | |
556 | } | |
557 | } | |
558 | ||
559 | return count; | |
560 | } | |
561 | ||
ed5bd7a4 | 562 | static DEVICE_ATTR_RW(a_bus_req); |
277164f0 NZ |
563 | |
564 | static ssize_t | |
ca35910a | 565 | a_clr_err_store(struct device *dev, struct device_attribute *attr, |
277164f0 NZ |
566 | const char *buf, size_t count) |
567 | { | |
568 | struct mv_otg *mvotg = dev_get_drvdata(dev); | |
b1c711d6 | 569 | if (!mvotg->phy.otg->default_a) |
277164f0 NZ |
570 | return -1; |
571 | ||
572 | if (count > 2) | |
573 | return -1; | |
574 | ||
575 | if (buf[0] == '1') { | |
576 | mvotg->otg_ctrl.a_clr_err = 1; | |
577 | dev_dbg(&mvotg->pdev->dev, | |
578 | "User request: a_clr_err = 1\n"); | |
579 | } | |
580 | ||
581 | if (spin_trylock(&mvotg->wq_lock)) { | |
582 | mv_otg_run_state_machine(mvotg, 0); | |
583 | spin_unlock(&mvotg->wq_lock); | |
584 | } | |
585 | ||
586 | return count; | |
587 | } | |
588 | ||
ca35910a | 589 | static DEVICE_ATTR_WO(a_clr_err); |
277164f0 NZ |
590 | |
591 | static ssize_t | |
ed5bd7a4 | 592 | a_bus_drop_show(struct device *dev, struct device_attribute *attr, |
277164f0 NZ |
593 | char *buf) |
594 | { | |
595 | struct mv_otg *mvotg = dev_get_drvdata(dev); | |
596 | return scnprintf(buf, PAGE_SIZE, "%d\n", | |
597 | mvotg->otg_ctrl.a_bus_drop); | |
598 | } | |
599 | ||
600 | static ssize_t | |
ed5bd7a4 | 601 | a_bus_drop_store(struct device *dev, struct device_attribute *attr, |
277164f0 NZ |
602 | const char *buf, size_t count) |
603 | { | |
604 | struct mv_otg *mvotg = dev_get_drvdata(dev); | |
b1c711d6 | 605 | if (!mvotg->phy.otg->default_a) |
277164f0 NZ |
606 | return -1; |
607 | ||
608 | if (count > 2) | |
609 | return -1; | |
610 | ||
611 | if (buf[0] == '0') { | |
612 | mvotg->otg_ctrl.a_bus_drop = 0; | |
613 | dev_dbg(&mvotg->pdev->dev, | |
614 | "User request: a_bus_drop = 0\n"); | |
615 | } else if (buf[0] == '1') { | |
616 | mvotg->otg_ctrl.a_bus_drop = 1; | |
617 | mvotg->otg_ctrl.a_bus_req = 0; | |
618 | dev_dbg(&mvotg->pdev->dev, | |
619 | "User request: a_bus_drop = 1\n"); | |
620 | dev_dbg(&mvotg->pdev->dev, | |
621 | "User request: and a_bus_req = 0\n"); | |
622 | } | |
623 | ||
624 | if (spin_trylock(&mvotg->wq_lock)) { | |
625 | mv_otg_run_state_machine(mvotg, 0); | |
626 | spin_unlock(&mvotg->wq_lock); | |
627 | } | |
628 | ||
629 | return count; | |
630 | } | |
631 | ||
ed5bd7a4 | 632 | static DEVICE_ATTR_RW(a_bus_drop); |
277164f0 NZ |
633 | |
634 | static struct attribute *inputs_attrs[] = { | |
635 | &dev_attr_a_bus_req.attr, | |
636 | &dev_attr_a_clr_err.attr, | |
637 | &dev_attr_a_bus_drop.attr, | |
638 | NULL, | |
639 | }; | |
640 | ||
1cefc269 | 641 | static const struct attribute_group inputs_attr_group = { |
277164f0 NZ |
642 | .name = "inputs", |
643 | .attrs = inputs_attrs, | |
644 | }; | |
645 | ||
d07f4a82 | 646 | static int mv_otg_remove(struct platform_device *pdev) |
277164f0 NZ |
647 | { |
648 | struct mv_otg *mvotg = platform_get_drvdata(pdev); | |
277164f0 NZ |
649 | |
650 | sysfs_remove_group(&mvotg->pdev->dev.kobj, &inputs_attr_group); | |
651 | ||
277164f0 NZ |
652 | if (mvotg->qwork) { |
653 | flush_workqueue(mvotg->qwork); | |
654 | destroy_workqueue(mvotg->qwork); | |
655 | } | |
656 | ||
657 | mv_otg_disable(mvotg); | |
658 | ||
662dca54 | 659 | usb_remove_phy(&mvotg->phy); |
277164f0 | 660 | |
277164f0 NZ |
661 | return 0; |
662 | } | |
663 | ||
664 | static int mv_otg_probe(struct platform_device *pdev) | |
665 | { | |
19f9e188 | 666 | struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); |
277164f0 | 667 | struct mv_otg *mvotg; |
b1c711d6 | 668 | struct usb_otg *otg; |
277164f0 | 669 | struct resource *r; |
df18feda | 670 | int retval = 0, i; |
277164f0 NZ |
671 | |
672 | if (pdata == NULL) { | |
673 | dev_err(&pdev->dev, "failed to get platform data\n"); | |
674 | return -ENODEV; | |
675 | } | |
676 | ||
df18feda | 677 | mvotg = devm_kzalloc(&pdev->dev, sizeof(*mvotg), GFP_KERNEL); |
aa10c7b0 | 678 | if (!mvotg) |
277164f0 | 679 | return -ENOMEM; |
277164f0 | 680 | |
fb3dfe13 CX |
681 | otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); |
682 | if (!otg) | |
b1c711d6 | 683 | return -ENOMEM; |
b1c711d6 | 684 | |
277164f0 NZ |
685 | platform_set_drvdata(pdev, mvotg); |
686 | ||
687 | mvotg->pdev = pdev; | |
688 | mvotg->pdata = pdata; | |
689 | ||
df18feda CX |
690 | mvotg->clk = devm_clk_get(&pdev->dev, NULL); |
691 | if (IS_ERR(mvotg->clk)) | |
692 | return PTR_ERR(mvotg->clk); | |
277164f0 NZ |
693 | |
694 | mvotg->qwork = create_singlethread_workqueue("mv_otg_queue"); | |
695 | if (!mvotg->qwork) { | |
696 | dev_dbg(&pdev->dev, "cannot create workqueue for OTG\n"); | |
fb3dfe13 | 697 | return -ENOMEM; |
277164f0 NZ |
698 | } |
699 | ||
700 | INIT_DELAYED_WORK(&mvotg->work, mv_otg_work); | |
701 | ||
702 | /* OTG common part */ | |
703 | mvotg->pdev = pdev; | |
b1c711d6 HK |
704 | mvotg->phy.dev = &pdev->dev; |
705 | mvotg->phy.otg = otg; | |
706 | mvotg->phy.label = driver_name; | |
b1c711d6 | 707 | |
e47d9254 | 708 | otg->state = OTG_STATE_UNDEFINED; |
19c1eac2 | 709 | otg->usb_phy = &mvotg->phy; |
b1c711d6 HK |
710 | otg->set_host = mv_otg_set_host; |
711 | otg->set_peripheral = mv_otg_set_peripheral; | |
712 | otg->set_vbus = mv_otg_set_vbus; | |
277164f0 NZ |
713 | |
714 | for (i = 0; i < OTG_TIMER_NUM; i++) | |
9718756f KC |
715 | timer_setup(&mvotg->otg_ctrl.timer[i], |
716 | mv_otg_timer_await_bcon, 0); | |
277164f0 NZ |
717 | |
718 | r = platform_get_resource_byname(mvotg->pdev, | |
719 | IORESOURCE_MEM, "phyregs"); | |
720 | if (r == NULL) { | |
721 | dev_err(&pdev->dev, "no phy I/O memory resource defined\n"); | |
722 | retval = -ENODEV; | |
723 | goto err_destroy_workqueue; | |
724 | } | |
725 | ||
fb3dfe13 | 726 | mvotg->phy_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r)); |
277164f0 NZ |
727 | if (mvotg->phy_regs == NULL) { |
728 | dev_err(&pdev->dev, "failed to map phy I/O memory\n"); | |
729 | retval = -EFAULT; | |
730 | goto err_destroy_workqueue; | |
731 | } | |
732 | ||
733 | r = platform_get_resource_byname(mvotg->pdev, | |
734 | IORESOURCE_MEM, "capregs"); | |
735 | if (r == NULL) { | |
736 | dev_err(&pdev->dev, "no I/O memory resource defined\n"); | |
737 | retval = -ENODEV; | |
fb3dfe13 | 738 | goto err_destroy_workqueue; |
277164f0 NZ |
739 | } |
740 | ||
fb3dfe13 | 741 | mvotg->cap_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r)); |
277164f0 NZ |
742 | if (mvotg->cap_regs == NULL) { |
743 | dev_err(&pdev->dev, "failed to map I/O memory\n"); | |
744 | retval = -EFAULT; | |
fb3dfe13 | 745 | goto err_destroy_workqueue; |
277164f0 NZ |
746 | } |
747 | ||
748 | /* we will acces controller register, so enable the udc controller */ | |
749 | retval = mv_otg_enable_internal(mvotg); | |
750 | if (retval) { | |
751 | dev_err(&pdev->dev, "mv otg enable error %d\n", retval); | |
fb3dfe13 | 752 | goto err_destroy_workqueue; |
277164f0 NZ |
753 | } |
754 | ||
755 | mvotg->op_regs = | |
756 | (struct mv_otg_regs __iomem *) ((unsigned long) mvotg->cap_regs | |
757 | + (readl(mvotg->cap_regs) & CAPLENGTH_MASK)); | |
758 | ||
759 | if (pdata->id) { | |
fb3dfe13 CX |
760 | retval = devm_request_threaded_irq(&pdev->dev, pdata->id->irq, |
761 | NULL, mv_otg_inputs_irq, | |
762 | IRQF_ONESHOT, "id", mvotg); | |
277164f0 NZ |
763 | if (retval) { |
764 | dev_info(&pdev->dev, | |
765 | "Failed to request irq for ID\n"); | |
766 | pdata->id = NULL; | |
767 | } | |
768 | } | |
769 | ||
770 | if (pdata->vbus) { | |
771 | mvotg->clock_gating = 1; | |
fb3dfe13 CX |
772 | retval = devm_request_threaded_irq(&pdev->dev, pdata->vbus->irq, |
773 | NULL, mv_otg_inputs_irq, | |
774 | IRQF_ONESHOT, "vbus", mvotg); | |
277164f0 NZ |
775 | if (retval) { |
776 | dev_info(&pdev->dev, | |
777 | "Failed to request irq for VBUS, " | |
778 | "disable clock gating\n"); | |
779 | mvotg->clock_gating = 0; | |
780 | pdata->vbus = NULL; | |
781 | } | |
782 | } | |
783 | ||
784 | if (pdata->disable_otg_clock_gating) | |
785 | mvotg->clock_gating = 0; | |
786 | ||
787 | mv_otg_reset(mvotg); | |
788 | mv_otg_init_irq(mvotg); | |
789 | ||
790 | r = platform_get_resource(mvotg->pdev, IORESOURCE_IRQ, 0); | |
791 | if (r == NULL) { | |
792 | dev_err(&pdev->dev, "no IRQ resource defined\n"); | |
793 | retval = -ENODEV; | |
794 | goto err_disable_clk; | |
795 | } | |
796 | ||
797 | mvotg->irq = r->start; | |
fb3dfe13 | 798 | if (devm_request_irq(&pdev->dev, mvotg->irq, mv_otg_irq, IRQF_SHARED, |
277164f0 NZ |
799 | driver_name, mvotg)) { |
800 | dev_err(&pdev->dev, "Request irq %d for OTG failed\n", | |
801 | mvotg->irq); | |
802 | mvotg->irq = 0; | |
803 | retval = -ENODEV; | |
804 | goto err_disable_clk; | |
805 | } | |
806 | ||
662dca54 | 807 | retval = usb_add_phy(&mvotg->phy, USB_PHY_TYPE_USB2); |
277164f0 NZ |
808 | if (retval < 0) { |
809 | dev_err(&pdev->dev, "can't register transceiver, %d\n", | |
810 | retval); | |
fb3dfe13 | 811 | goto err_disable_clk; |
277164f0 NZ |
812 | } |
813 | ||
814 | retval = sysfs_create_group(&pdev->dev.kobj, &inputs_attr_group); | |
815 | if (retval < 0) { | |
816 | dev_dbg(&pdev->dev, | |
817 | "Can't register sysfs attr group: %d\n", retval); | |
fb3dfe13 | 818 | goto err_remove_phy; |
277164f0 NZ |
819 | } |
820 | ||
821 | spin_lock_init(&mvotg->wq_lock); | |
822 | if (spin_trylock(&mvotg->wq_lock)) { | |
823 | mv_otg_run_state_machine(mvotg, 2 * HZ); | |
824 | spin_unlock(&mvotg->wq_lock); | |
825 | } | |
826 | ||
827 | dev_info(&pdev->dev, | |
828 | "successful probe OTG device %s clock gating.\n", | |
829 | mvotg->clock_gating ? "with" : "without"); | |
830 | ||
831 | return 0; | |
832 | ||
fb3dfe13 | 833 | err_remove_phy: |
662dca54 | 834 | usb_remove_phy(&mvotg->phy); |
277164f0 | 835 | err_disable_clk: |
277164f0 | 836 | mv_otg_disable_internal(mvotg); |
277164f0 NZ |
837 | err_destroy_workqueue: |
838 | flush_workqueue(mvotg->qwork); | |
839 | destroy_workqueue(mvotg->qwork); | |
277164f0 | 840 | |
277164f0 NZ |
841 | return retval; |
842 | } | |
843 | ||
844 | #ifdef CONFIG_PM | |
845 | static int mv_otg_suspend(struct platform_device *pdev, pm_message_t state) | |
846 | { | |
847 | struct mv_otg *mvotg = platform_get_drvdata(pdev); | |
848 | ||
90bdf403 | 849 | if (mvotg->phy.otg->state != OTG_STATE_B_IDLE) { |
277164f0 NZ |
850 | dev_info(&pdev->dev, |
851 | "OTG state is not B_IDLE, it is %d!\n", | |
90bdf403 | 852 | mvotg->phy.otg->state); |
277164f0 NZ |
853 | return -EAGAIN; |
854 | } | |
855 | ||
856 | if (!mvotg->clock_gating) | |
857 | mv_otg_disable_internal(mvotg); | |
858 | ||
859 | return 0; | |
860 | } | |
861 | ||
862 | static int mv_otg_resume(struct platform_device *pdev) | |
863 | { | |
864 | struct mv_otg *mvotg = platform_get_drvdata(pdev); | |
865 | u32 otgsc; | |
866 | ||
867 | if (!mvotg->clock_gating) { | |
868 | mv_otg_enable_internal(mvotg); | |
869 | ||
870 | otgsc = readl(&mvotg->op_regs->otgsc); | |
871 | otgsc |= mvotg->irq_en; | |
872 | writel(otgsc, &mvotg->op_regs->otgsc); | |
873 | ||
874 | if (spin_trylock(&mvotg->wq_lock)) { | |
875 | mv_otg_run_state_machine(mvotg, 0); | |
876 | spin_unlock(&mvotg->wq_lock); | |
877 | } | |
878 | } | |
879 | return 0; | |
880 | } | |
881 | #endif | |
882 | ||
883 | static struct platform_driver mv_otg_driver = { | |
884 | .probe = mv_otg_probe, | |
d07f4a82 | 885 | .remove = mv_otg_remove, |
277164f0 | 886 | .driver = { |
277164f0 NZ |
887 | .name = driver_name, |
888 | }, | |
889 | #ifdef CONFIG_PM | |
890 | .suspend = mv_otg_suspend, | |
891 | .resume = mv_otg_resume, | |
892 | #endif | |
893 | }; | |
ca21dda6 | 894 | module_platform_driver(mv_otg_driver); |