Peter Chen <peter.chen@xxxxxxxxxxxxx> writes: > diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h > index d738603..d32f932 100644 > --- a/drivers/usb/chipidea/ci.h > +++ b/drivers/usb/chipidea/ci.h > @@ -139,6 +139,7 @@ struct ci13xxx { > enum ci_role role; > bool is_otg; > struct work_struct work; > + struct delayed_work dwork; > struct workqueue_struct *wq; > > struct dma_pool *qh_pool; > @@ -164,6 +165,11 @@ struct ci13xxx { > bool global_phy; > struct usb_phy *transceiver; > struct usb_hcd *hcd; > + /* events handled at ci_role_work */ > +#define ID 0 > +#define B_SESS_VALID 1 > + unsigned long events; I would still like bools or ints here. > + struct usb_otg otg; > }; > > static inline struct ci_role_driver *ci_role(struct ci13xxx *ci) > diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c > index f69d029..87544ad 100644 > --- a/drivers/usb/chipidea/core.c > +++ b/drivers/usb/chipidea/core.c > @@ -73,6 +73,7 @@ > #include "bits.h" > #include "host.h" > #include "debug.h" > +#include "otg.h" > > /* Controller register map */ > static uintptr_t ci_regs_nolpm[] = { > @@ -264,25 +265,131 @@ static enum ci_role ci_otg_role(struct ci13xxx *ci) > return role; > } > > +#define CI_WAIT_VBUS_STABLE_TIMEOUT 500 > /** > - * ci_role_work - perform role changing based on ID pin > - * @work: work struct > + * ci_wait_vbus_stable > + * When usb role switches, we need to turn on/off internal vbus > + * regulaor, sometimes, the real vbus value may not lower fast > + * enough due to capacitance, and we do want the vbus lower > + * than 0.8v if it is device mode, and higher than 4.4v, if it > + * is host mode. > + * > + * @low: true, Wait vbus lower than OTGSC_BSV > + * : false, Wait vbus higher than OTGSC_AVV > */ > -static void ci_role_work(struct work_struct *work) > +static void ci_wait_vbus_stable(struct ci13xxx *ci, bool low) > +{ > + unsigned long timeout; > + u32 otgsc = hw_read(ci, OP_OTGSC, ~0); > + > + timeout = jiffies + CI_WAIT_VBUS_STABLE_TIMEOUT; > + > + if (low) { > + while (otgsc & OTGSC_BSV) { > + if (time_after(jiffies, timeout)) { > + dev_err(ci->dev, "wait vbus lower than\ > + OTGSC_BSV timeout!\n"); > + return; > + } > + msleep(20); > + otgsc = hw_read(ci, OP_OTGSC, ~0); > + } > + } else { > + while (!(otgsc & OTGSC_AVV)) { > + if (time_after(jiffies, timeout)) { > + dev_err(ci->dev, "wait vbus higher than\ > + OTGSC_AVV timeout!\n"); > + return; > + } > + msleep(20); > + otgsc = hw_read(ci, OP_OTGSC, ~0); > + } > + > + } > +} How about static int hw_wait_reg(struct ci13xxx *ci, enum ci13xxx_regs reg, u32 mask, unsigned long timeout) { unsigned long elapse = jiffies + timeout; while (hw_read(ci, reg, mask)) { if (time_after(jiffies, elapse)) { dev_err(ci->dev, "timeout waiting for %08x in %d\n", mask, reg); return -ETIMEDOUT; } msleep(20); } return 0; } and then also checking if we timed out or everything's fine. Regards, -- Alex -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html