]>
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 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 | |
522 | get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf) | |
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 | |
530 | set_a_bus_req(struct device *dev, struct device_attribute *attr, | |
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 | ||
562 | static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, | |
563 | set_a_bus_req); | |
564 | ||
565 | static ssize_t | |
566 | set_a_clr_err(struct device *dev, struct device_attribute *attr, | |
567 | const char *buf, size_t count) | |
568 | { | |
569 | struct mv_otg *mvotg = dev_get_drvdata(dev); | |
b1c711d6 | 570 | if (!mvotg->phy.otg->default_a) |
277164f0 NZ |
571 | return -1; |
572 | ||
573 | if (count > 2) | |
574 | return -1; | |
575 | ||
576 | if (buf[0] == '1') { | |
577 | mvotg->otg_ctrl.a_clr_err = 1; | |
578 | dev_dbg(&mvotg->pdev->dev, | |
579 | "User request: a_clr_err = 1\n"); | |
580 | } | |
581 | ||
582 | if (spin_trylock(&mvotg->wq_lock)) { | |
583 | mv_otg_run_state_machine(mvotg, 0); | |
584 | spin_unlock(&mvotg->wq_lock); | |
585 | } | |
586 | ||
587 | return count; | |
588 | } | |
589 | ||
590 | static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err); | |
591 | ||
592 | static ssize_t | |
593 | get_a_bus_drop(struct device *dev, struct device_attribute *attr, | |
594 | char *buf) | |
595 | { | |
596 | struct mv_otg *mvotg = dev_get_drvdata(dev); | |
597 | return scnprintf(buf, PAGE_SIZE, "%d\n", | |
598 | mvotg->otg_ctrl.a_bus_drop); | |
599 | } | |
600 | ||
601 | static ssize_t | |
602 | set_a_bus_drop(struct device *dev, struct device_attribute *attr, | |
603 | const char *buf, size_t count) | |
604 | { | |
605 | struct mv_otg *mvotg = dev_get_drvdata(dev); | |
b1c711d6 | 606 | if (!mvotg->phy.otg->default_a) |
277164f0 NZ |
607 | return -1; |
608 | ||
609 | if (count > 2) | |
610 | return -1; | |
611 | ||
612 | if (buf[0] == '0') { | |
613 | mvotg->otg_ctrl.a_bus_drop = 0; | |
614 | dev_dbg(&mvotg->pdev->dev, | |
615 | "User request: a_bus_drop = 0\n"); | |
616 | } else if (buf[0] == '1') { | |
617 | mvotg->otg_ctrl.a_bus_drop = 1; | |
618 | mvotg->otg_ctrl.a_bus_req = 0; | |
619 | dev_dbg(&mvotg->pdev->dev, | |
620 | "User request: a_bus_drop = 1\n"); | |
621 | dev_dbg(&mvotg->pdev->dev, | |
622 | "User request: and a_bus_req = 0\n"); | |
623 | } | |
624 | ||
625 | if (spin_trylock(&mvotg->wq_lock)) { | |
626 | mv_otg_run_state_machine(mvotg, 0); | |
627 | spin_unlock(&mvotg->wq_lock); | |
628 | } | |
629 | ||
630 | return count; | |
631 | } | |
632 | ||
633 | static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, | |
634 | get_a_bus_drop, set_a_bus_drop); | |
635 | ||
636 | static struct attribute *inputs_attrs[] = { | |
637 | &dev_attr_a_bus_req.attr, | |
638 | &dev_attr_a_clr_err.attr, | |
639 | &dev_attr_a_bus_drop.attr, | |
640 | NULL, | |
641 | }; | |
642 | ||
1cefc269 | 643 | static const struct attribute_group inputs_attr_group = { |
277164f0 NZ |
644 | .name = "inputs", |
645 | .attrs = inputs_attrs, | |
646 | }; | |
647 | ||
d07f4a82 | 648 | static int mv_otg_remove(struct platform_device *pdev) |
277164f0 NZ |
649 | { |
650 | struct mv_otg *mvotg = platform_get_drvdata(pdev); | |
277164f0 NZ |
651 | |
652 | sysfs_remove_group(&mvotg->pdev->dev.kobj, &inputs_attr_group); | |
653 | ||
277164f0 NZ |
654 | if (mvotg->qwork) { |
655 | flush_workqueue(mvotg->qwork); | |
656 | destroy_workqueue(mvotg->qwork); | |
657 | } | |
658 | ||
659 | mv_otg_disable(mvotg); | |
660 | ||
662dca54 | 661 | usb_remove_phy(&mvotg->phy); |
277164f0 | 662 | |
277164f0 NZ |
663 | return 0; |
664 | } | |
665 | ||
666 | static int mv_otg_probe(struct platform_device *pdev) | |
667 | { | |
19f9e188 | 668 | struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); |
277164f0 | 669 | struct mv_otg *mvotg; |
b1c711d6 | 670 | struct usb_otg *otg; |
277164f0 | 671 | struct resource *r; |
df18feda | 672 | int retval = 0, i; |
277164f0 NZ |
673 | |
674 | if (pdata == NULL) { | |
675 | dev_err(&pdev->dev, "failed to get platform data\n"); | |
676 | return -ENODEV; | |
677 | } | |
678 | ||
df18feda | 679 | mvotg = devm_kzalloc(&pdev->dev, sizeof(*mvotg), GFP_KERNEL); |
aa10c7b0 | 680 | if (!mvotg) |
277164f0 | 681 | return -ENOMEM; |
277164f0 | 682 | |
fb3dfe13 CX |
683 | otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); |
684 | if (!otg) | |
b1c711d6 | 685 | return -ENOMEM; |
b1c711d6 | 686 | |
277164f0 NZ |
687 | platform_set_drvdata(pdev, mvotg); |
688 | ||
689 | mvotg->pdev = pdev; | |
690 | mvotg->pdata = pdata; | |
691 | ||
df18feda CX |
692 | mvotg->clk = devm_clk_get(&pdev->dev, NULL); |
693 | if (IS_ERR(mvotg->clk)) | |
694 | return PTR_ERR(mvotg->clk); | |
277164f0 NZ |
695 | |
696 | mvotg->qwork = create_singlethread_workqueue("mv_otg_queue"); | |
697 | if (!mvotg->qwork) { | |
698 | dev_dbg(&pdev->dev, "cannot create workqueue for OTG\n"); | |
fb3dfe13 | 699 | return -ENOMEM; |
277164f0 NZ |
700 | } |
701 | ||
702 | INIT_DELAYED_WORK(&mvotg->work, mv_otg_work); | |
703 | ||
704 | /* OTG common part */ | |
705 | mvotg->pdev = pdev; | |
b1c711d6 HK |
706 | mvotg->phy.dev = &pdev->dev; |
707 | mvotg->phy.otg = otg; | |
708 | mvotg->phy.label = driver_name; | |
b1c711d6 | 709 | |
e47d9254 | 710 | otg->state = OTG_STATE_UNDEFINED; |
19c1eac2 | 711 | otg->usb_phy = &mvotg->phy; |
b1c711d6 HK |
712 | otg->set_host = mv_otg_set_host; |
713 | otg->set_peripheral = mv_otg_set_peripheral; | |
714 | otg->set_vbus = mv_otg_set_vbus; | |
277164f0 NZ |
715 | |
716 | for (i = 0; i < OTG_TIMER_NUM; i++) | |
9718756f KC |
717 | timer_setup(&mvotg->otg_ctrl.timer[i], |
718 | mv_otg_timer_await_bcon, 0); | |
277164f0 NZ |
719 | |
720 | r = platform_get_resource_byname(mvotg->pdev, | |
721 | IORESOURCE_MEM, "phyregs"); | |
722 | if (r == NULL) { | |
723 | dev_err(&pdev->dev, "no phy I/O memory resource defined\n"); | |
724 | retval = -ENODEV; | |
725 | goto err_destroy_workqueue; | |
726 | } | |
727 | ||
fb3dfe13 | 728 | mvotg->phy_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r)); |
277164f0 NZ |
729 | if (mvotg->phy_regs == NULL) { |
730 | dev_err(&pdev->dev, "failed to map phy I/O memory\n"); | |
731 | retval = -EFAULT; | |
732 | goto err_destroy_workqueue; | |
733 | } | |
734 | ||
735 | r = platform_get_resource_byname(mvotg->pdev, | |
736 | IORESOURCE_MEM, "capregs"); | |
737 | if (r == NULL) { | |
738 | dev_err(&pdev->dev, "no I/O memory resource defined\n"); | |
739 | retval = -ENODEV; | |
fb3dfe13 | 740 | goto err_destroy_workqueue; |
277164f0 NZ |
741 | } |
742 | ||
fb3dfe13 | 743 | mvotg->cap_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r)); |
277164f0 NZ |
744 | if (mvotg->cap_regs == NULL) { |
745 | dev_err(&pdev->dev, "failed to map I/O memory\n"); | |
746 | retval = -EFAULT; | |
fb3dfe13 | 747 | goto err_destroy_workqueue; |
277164f0 NZ |
748 | } |
749 | ||
750 | /* we will acces controller register, so enable the udc controller */ | |
751 | retval = mv_otg_enable_internal(mvotg); | |
752 | if (retval) { | |
753 | dev_err(&pdev->dev, "mv otg enable error %d\n", retval); | |
fb3dfe13 | 754 | goto err_destroy_workqueue; |
277164f0 NZ |
755 | } |
756 | ||
757 | mvotg->op_regs = | |
758 | (struct mv_otg_regs __iomem *) ((unsigned long) mvotg->cap_regs | |
759 | + (readl(mvotg->cap_regs) & CAPLENGTH_MASK)); | |
760 | ||
761 | if (pdata->id) { | |
fb3dfe13 CX |
762 | retval = devm_request_threaded_irq(&pdev->dev, pdata->id->irq, |
763 | NULL, mv_otg_inputs_irq, | |
764 | IRQF_ONESHOT, "id", mvotg); | |
277164f0 NZ |
765 | if (retval) { |
766 | dev_info(&pdev->dev, | |
767 | "Failed to request irq for ID\n"); | |
768 | pdata->id = NULL; | |
769 | } | |
770 | } | |
771 | ||
772 | if (pdata->vbus) { | |
773 | mvotg->clock_gating = 1; | |
fb3dfe13 CX |
774 | retval = devm_request_threaded_irq(&pdev->dev, pdata->vbus->irq, |
775 | NULL, mv_otg_inputs_irq, | |
776 | IRQF_ONESHOT, "vbus", mvotg); | |
277164f0 NZ |
777 | if (retval) { |
778 | dev_info(&pdev->dev, | |
779 | "Failed to request irq for VBUS, " | |
780 | "disable clock gating\n"); | |
781 | mvotg->clock_gating = 0; | |
782 | pdata->vbus = NULL; | |
783 | } | |
784 | } | |
785 | ||
786 | if (pdata->disable_otg_clock_gating) | |
787 | mvotg->clock_gating = 0; | |
788 | ||
789 | mv_otg_reset(mvotg); | |
790 | mv_otg_init_irq(mvotg); | |
791 | ||
792 | r = platform_get_resource(mvotg->pdev, IORESOURCE_IRQ, 0); | |
793 | if (r == NULL) { | |
794 | dev_err(&pdev->dev, "no IRQ resource defined\n"); | |
795 | retval = -ENODEV; | |
796 | goto err_disable_clk; | |
797 | } | |
798 | ||
799 | mvotg->irq = r->start; | |
fb3dfe13 | 800 | if (devm_request_irq(&pdev->dev, mvotg->irq, mv_otg_irq, IRQF_SHARED, |
277164f0 NZ |
801 | driver_name, mvotg)) { |
802 | dev_err(&pdev->dev, "Request irq %d for OTG failed\n", | |
803 | mvotg->irq); | |
804 | mvotg->irq = 0; | |
805 | retval = -ENODEV; | |
806 | goto err_disable_clk; | |
807 | } | |
808 | ||
662dca54 | 809 | retval = usb_add_phy(&mvotg->phy, USB_PHY_TYPE_USB2); |
277164f0 NZ |
810 | if (retval < 0) { |
811 | dev_err(&pdev->dev, "can't register transceiver, %d\n", | |
812 | retval); | |
fb3dfe13 | 813 | goto err_disable_clk; |
277164f0 NZ |
814 | } |
815 | ||
816 | retval = sysfs_create_group(&pdev->dev.kobj, &inputs_attr_group); | |
817 | if (retval < 0) { | |
818 | dev_dbg(&pdev->dev, | |
819 | "Can't register sysfs attr group: %d\n", retval); | |
fb3dfe13 | 820 | goto err_remove_phy; |
277164f0 NZ |
821 | } |
822 | ||
823 | spin_lock_init(&mvotg->wq_lock); | |
824 | if (spin_trylock(&mvotg->wq_lock)) { | |
825 | mv_otg_run_state_machine(mvotg, 2 * HZ); | |
826 | spin_unlock(&mvotg->wq_lock); | |
827 | } | |
828 | ||
829 | dev_info(&pdev->dev, | |
830 | "successful probe OTG device %s clock gating.\n", | |
831 | mvotg->clock_gating ? "with" : "without"); | |
832 | ||
833 | return 0; | |
834 | ||
fb3dfe13 | 835 | err_remove_phy: |
662dca54 | 836 | usb_remove_phy(&mvotg->phy); |
277164f0 | 837 | err_disable_clk: |
277164f0 | 838 | mv_otg_disable_internal(mvotg); |
277164f0 NZ |
839 | err_destroy_workqueue: |
840 | flush_workqueue(mvotg->qwork); | |
841 | destroy_workqueue(mvotg->qwork); | |
277164f0 | 842 | |
277164f0 NZ |
843 | return retval; |
844 | } | |
845 | ||
846 | #ifdef CONFIG_PM | |
847 | static int mv_otg_suspend(struct platform_device *pdev, pm_message_t state) | |
848 | { | |
849 | struct mv_otg *mvotg = platform_get_drvdata(pdev); | |
850 | ||
90bdf403 | 851 | if (mvotg->phy.otg->state != OTG_STATE_B_IDLE) { |
277164f0 NZ |
852 | dev_info(&pdev->dev, |
853 | "OTG state is not B_IDLE, it is %d!\n", | |
90bdf403 | 854 | mvotg->phy.otg->state); |
277164f0 NZ |
855 | return -EAGAIN; |
856 | } | |
857 | ||
858 | if (!mvotg->clock_gating) | |
859 | mv_otg_disable_internal(mvotg); | |
860 | ||
861 | return 0; | |
862 | } | |
863 | ||
864 | static int mv_otg_resume(struct platform_device *pdev) | |
865 | { | |
866 | struct mv_otg *mvotg = platform_get_drvdata(pdev); | |
867 | u32 otgsc; | |
868 | ||
869 | if (!mvotg->clock_gating) { | |
870 | mv_otg_enable_internal(mvotg); | |
871 | ||
872 | otgsc = readl(&mvotg->op_regs->otgsc); | |
873 | otgsc |= mvotg->irq_en; | |
874 | writel(otgsc, &mvotg->op_regs->otgsc); | |
875 | ||
876 | if (spin_trylock(&mvotg->wq_lock)) { | |
877 | mv_otg_run_state_machine(mvotg, 0); | |
878 | spin_unlock(&mvotg->wq_lock); | |
879 | } | |
880 | } | |
881 | return 0; | |
882 | } | |
883 | #endif | |
884 | ||
885 | static struct platform_driver mv_otg_driver = { | |
886 | .probe = mv_otg_probe, | |
d07f4a82 | 887 | .remove = mv_otg_remove, |
277164f0 | 888 | .driver = { |
277164f0 NZ |
889 | .name = driver_name, |
890 | }, | |
891 | #ifdef CONFIG_PM | |
892 | .suspend = mv_otg_suspend, | |
893 | .resume = mv_otg_resume, | |
894 | #endif | |
895 | }; | |
ca21dda6 | 896 | module_platform_driver(mv_otg_driver); |