Commit 22fa84455a2a80566ead8efe4b5e629f2375da60

Authored by Peter Chen
Committed by Greg Kroah-Hartman
1 parent a107f8c505

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
... ... @@ -308,5 +308,8 @@
308 308  
309 309 u8 hw_port_test_get(struct ci_hdrc *ci);
310 310  
  311 +int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
  312 + u32 value, unsigned int timeout_ms);
  313 +
311 314 #endif /* __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 }