Peter Chen <peter.c...@freescale.com> 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to