Commit 22fa84455a2a80566ead8efe4b5e629f2375da60
Committed by
Greg Kroah-Hartman
1 parent
a107f8c505
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
usb: chipidea: add wait vbus lower than OTGSC_BSV before role starts
When the gadget role starts, we need to make sure the vbus is lower than OTGSC_BSV, or there will be an vbus interrupt since we use B_SESSION_VALID as vbus interrupt to indicate connect and disconnect. When the host role starts, it may not be useful to wait vbus to lower than OTGSC_BSV, but it can indicate some hardware problems like the vbus is still higher than OTGSC_BSV after we disconnect to host some time later (5000 milliseconds currently), which is obvious not correct. Tested-by: Marek Vasut <marex@denx.de> Signed-off-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 3 changed files with 39 additions and 0 deletions Side-by-side Diff
drivers/usb/chipidea/ci.h
drivers/usb/chipidea/core.c
... | ... | @@ -294,6 +294,38 @@ |
294 | 294 | return 0; |
295 | 295 | } |
296 | 296 | |
297 | +/** | |
298 | + * hw_wait_reg: wait the register value | |
299 | + * | |
300 | + * Sometimes, it needs to wait register value before going on. | |
301 | + * Eg, when switch to device mode, the vbus value should be lower | |
302 | + * than OTGSC_BSV before connects to host. | |
303 | + * | |
304 | + * @ci: the controller | |
305 | + * @reg: register index | |
306 | + * @mask: mast bit | |
307 | + * @value: the bit value to wait | |
308 | + * @timeout_ms: timeout in millisecond | |
309 | + * | |
310 | + * This function returns an error code if timeout | |
311 | + */ | |
312 | +int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask, | |
313 | + u32 value, unsigned int timeout_ms) | |
314 | +{ | |
315 | + unsigned long elapse = jiffies + msecs_to_jiffies(timeout_ms); | |
316 | + | |
317 | + while (hw_read(ci, reg, mask) != value) { | |
318 | + if (time_after(jiffies, elapse)) { | |
319 | + dev_err(ci->dev, "timeout waiting for %08x in %d\n", | |
320 | + mask, reg); | |
321 | + return -ETIMEDOUT; | |
322 | + } | |
323 | + msleep(20); | |
324 | + } | |
325 | + | |
326 | + return 0; | |
327 | +} | |
328 | + | |
297 | 329 | static irqreturn_t ci_irq(int irq, void *data) |
298 | 330 | { |
299 | 331 | struct ci_hdrc *ci = data; |
drivers/usb/chipidea/otg.c
... | ... | @@ -52,6 +52,7 @@ |
52 | 52 | usb_gadget_vbus_disconnect(&ci->gadget); |
53 | 53 | } |
54 | 54 | |
55 | +#define CI_VBUS_STABLE_TIMEOUT_MS 5000 | |
55 | 56 | static void ci_handle_id_switch(struct ci_hdrc *ci) |
56 | 57 | { |
57 | 58 | enum ci_role role = ci_otg_role(ci); |
... | ... | @@ -61,6 +62,9 @@ |
61 | 62 | ci_role(ci)->name, ci->roles[role]->name); |
62 | 63 | |
63 | 64 | ci_role_stop(ci); |
65 | + /* wait vbus lower than OTGSC_BSV */ | |
66 | + hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0, | |
67 | + CI_VBUS_STABLE_TIMEOUT_MS); | |
64 | 68 | ci_role_start(ci, role); |
65 | 69 | } |
66 | 70 | } |