On Fri, 2010-01-22 at 09:42 +0100, Mandy Arnaud.2 (EXT-Teleca/Helsinki)
wrote:

Hi,

> using a wrapper between the transceiver driver and the controller
> driver to signal the controller driver to turn on/off the controller
> when VBUS event is detected.

I think there is one register mismatch, please see below.

> based-on: Heikki Krogerus <[email protected]>
> Signed-off-by: Arnaud Mandy <[email protected]>
> ---
>  drivers/usb/musb/musb_core.c  |   30 +++++++++++++++++-
>  drivers/usb/musb/musb_core.h  |   17 +++++++++-
>  drivers/usb/musb/omap2430.c   |   66 
> ++++++++++++++++++++++++++++++++++++++++-
>  drivers/usb/otg/otg.c         |   16 ++++++++++
>  drivers/usb/otg/twl4030-usb.c |    2 +
>  include/linux/usb/otg.h       |   11 +++++++
>  6 files changed, 137 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
> index 2f59892..ab97a02 100644
> --- a/drivers/usb/musb/musb_core.c
> +++ b/drivers/usb/musb/musb_core.c
> @@ -965,6 +965,8 @@ void musb_start(struct musb *musb)
>       }
>       musb_platform_enable(musb);
>       musb_writeb(regs, MUSB_DEVCTL, devctl);
> +
> +     musb_save_context(musb);
>  }
>  
> 
> @@ -1948,6 +1950,25 @@ static void musb_free(struct musb *musb)
>  #endif
>  }
>  
> +int musb_power_controller(struct otg_controller *controller, bool vbus)
> +{
> +     struct musb *musb = dev_to_musb(controller->dev);
> +
> +     if (!musb->off_mode_support)
> +             return 0;
> +
> +     if (vbus)
> +             musb_power_on_controller(musb);
> +     else
> +             musb_power_off_controller(musb);
> +
> +     return 0;
> +}
> +
> +struct otg_controller musb_controller = {
> +     .power_controller = musb_power_controller,
> +};
> +
>  /*
>   * Perform generic per-controller initialization.
>   *
> @@ -2044,6 +2065,9 @@ bad_config:
>               goto fail2;
>       }
>  
> +     musb_controller.dev = dev;
> +     musb->xceiv->controller = &musb_controller;
> +
>  #ifndef CONFIG_MUSB_PIO_ONLY
>       if (use_dma && dev->dma_mask) {
>               struct dma_controller   *c;
> @@ -2313,7 +2337,8 @@ void musb_save_context(struct musb *musb)
>  
>       musb_writeb(musb_base, MUSB_INDEX, musb_context.index);
>  
> -     musb_platform_save_context(musb, &musb_context);
> +     if (!musb->off_mode)
> +             musb_platform_save_context(musb, &musb_context);
>  }
>  
>  void musb_restore_context(struct musb *musb)
> @@ -2322,7 +2347,8 @@ void musb_restore_context(struct musb *musb)
>       void __iomem *musb_base = musb->mregs;
>       void __iomem *ep_target_regs;
>  
> -     musb_platform_restore_context(musb, &musb_context);
> +     if (!musb->off_mode)
> +             musb_platform_restore_context(musb, &musb_context);
>  
>       if (is_host_enabled(musb)) {
>               musb_writew(musb_base, MUSB_FRAME, musb_context.frame);
> diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
> index 1e3da4e..8105a47 100644
> --- a/drivers/usb/musb/musb_core.h
> +++ b/drivers/usb/musb/musb_core.h
> @@ -448,6 +448,11 @@ struct musb {
>       struct usb_gadget       g;                      /* the gadget */
>       struct usb_gadget_driver *gadget_driver;        /* its driver */
>  #endif
> +     /* true if off-mode is supported */
> +     unsigned                off_mode_support:1;
> +
> +     /* true if off-mode is requested */
> +     unsigned                off_mode:1;
>  
>       /* true if we're using dma */
>       unsigned                use_dma:1;
> @@ -498,8 +503,16 @@ extern void musb_platform_restore_context(struct musb 
> *musb,
>  #define musb_platform_save_context(m, x)     do {} while (0)
>  #define musb_platform_restore_context(m, x)  do {} while (0)
>  #endif
> -
> -#endif
> +extern void musb_power_on_controller(struct musb *musb);
> +extern void musb_power_off_controller(struct musb *musb);
> +void musb_save_context(struct musb *musb);
> +void musb_restore_context(struct musb *musb);
> +#else
> +static inline void musb_power_on_controller(struct musb *musb) {};
> +static inline void musb_power_off_controller(struct musb *musb) {};
> +static inline void musb_save_context(struct musb *musb) {};
> +static inline void musb_restore_context(struct musb *musb) {};
> +#endif /* CONFIG_PM */
>  
>  static inline void musb_set_vbus(struct musb *musb, int is_on)
>  {
> diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
> index 21cff53..3cc894b 100644
> --- a/drivers/usb/musb/omap2430.c
> +++ b/drivers/usb/musb/omap2430.c
> @@ -220,6 +220,9 @@ int __init musb_platform_init(struct musb *musb)
>  
>       musb_platform_resume(musb);
>  
> +#ifdef CONFIG_PM
> +     musb->off_mode_support = 1;
> +#endif
>       l = musb_readl(musb->mregs, OTG_SYSCONFIG);
>       l &= ~ENABLEWAKEUP;     /* disable wakeup */
>       l &= ~NOSTDBY;          /* remove possible nostdby */
> @@ -271,7 +274,68 @@ void musb_platform_restore_context(struct musb *musb,
>       musb_writel(musb->mregs, OTG_SYSCONFIG, musb_context->otg_sysconfig);
>       musb_writel(musb->mregs, OTG_FORCESTDBY, 
> musb_context->otg_forcestandby);
>  }
> -#endif
> +
> +void musb_power_off_controller(struct musb *musb)
> +{
> +     u32 l;
> +
> +     DBG(3, "allow OFF-mode\n");
> +
> +     l = musb_readl(musb->mregs, OTG_FORCESTDBY);
> +     l |= ENABLEFORCE;       /* enable MSTANDBY */
> +     musb_writel(musb->mregs, OTG_FORCESTDBY, l);
> +
> +     l = musb_readl(musb->mregs, OTG_FORCESTDBY);
> +     l |= ENABLEWAKEUP;      /* enable wakeup */
> +     l &= ~NOSTDBY;          /* disable nostdby */
> +     l |= SMARTSTDBY;        /* enable smart standby */
> +
> +     l |= AUTOIDLE;          /* enable auto idle */
> +     l &= ~NOIDLE;           /* disable noidle */
> +     l |= SMARTIDLE;         /* enable smart idle */
> +
> +     musb_writel(musb->mregs, OTG_SYSCONFIG, l);

Here you read from OTG_FORCESTDBY, tweak bits and write to
OTG_SYSCONFIG? I guess the read should be from OTG_SYSCONFIG?

> +
> +     if (!cpu_is_omap3430())
> +             l |= AUTOIDLE;          /* enable auto idle */
> +     musb_writel(musb->mregs, OTG_SYSCONFIG, l);
> +}
> +EXPORT_SYMBOL_GPL(musb_power_off_controller);
> +
> +void musb_power_on_controller(struct musb *musb)
> +{
> +     u32 l;
> +
> +     DBG(3, "wake-up from OFF-mode\n");
> +
> +     l = musb_readl(musb->mregs, OTG_SYSCONFIG);
> +     l &= ~ENABLEWAKEUP;     /* disable wakeup */
> +     musb_writel(musb->mregs, OTG_SYSCONFIG, l);
> +
> +     l = musb_readl(musb->mregs, OTG_FORCESTDBY);
> +     l &= ~ENABLEFORCE;      /* disable MSTANDBY */
> +     musb_writel(musb->mregs, OTG_FORCESTDBY, l);
> +
> +     l = musb_readl(musb->mregs, OTG_SYSCONFIG);
> +     l |= NOSTDBY;           /* enable nostdby */
> +     l &= ~SMARTSTDBY;       /* disable smart standby */
> +
> +     l &= ~AUTOIDLE;         /* disable auto idle */
> +     l |= NOIDLE;            /* enable noidle */
> +     l &= ~SMARTIDLE;        /* disable smart idle */
> +     musb_writel(musb->mregs, OTG_SYSCONFIG, l);
> +
> +     l = musb_readl(musb->mregs, OTG_INTERFSEL);
> +     l |= ULPI_12PIN;
> +     musb_writel(musb->mregs, OTG_INTERFSEL, l);
> +
> +     /* Restore register context */
> +     musb->off_mode = 1;
> +     musb_restore_context(musb);
> +     musb->off_mode = 0;
> +}
> +EXPORT_SYMBOL_GPL(musb_power_on_controller);
> +#endif /* CONFIG_PM */
>  
>  int musb_platform_suspend(struct musb *musb)
>  {
> diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c
> index 0a43a7d..8ab45a7 100644
> --- a/drivers/usb/otg/otg.c
> +++ b/drivers/usb/otg/otg.c
> @@ -64,3 +64,19 @@ int otg_set_transceiver(struct otg_transceiver *x)
>       return 0;
>  }
>  EXPORT_SYMBOL(otg_set_transceiver);
> +
> +/**
> + * otg_power_controller - control power on/off of tranceiver.
> + * @x: the USB OTG transceiver to be used; or NULL
> + * @vbus: VBUS presence.
> + * This call is to save and power off the usb controller based on
> + * VBUS level detected by the transceiver.
> + */
> +int otg_power_controller(struct otg_transceiver *x, bool vbus)
> +{
> +     if (x->controller && x->controller->power_controller)
> +             x->controller->power_controller(x->controller, vbus);
> +     return 0;
> +}
> +EXPORT_SYMBOL(otg_power_controller);
> +
> diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
> index 488b0a3..3aa84ea 100644
> --- a/drivers/usb/otg/twl4030-usb.c
> +++ b/drivers/usb/otg/twl4030-usb.c
> @@ -503,6 +503,7 @@ static void twl4030_phy_suspend(struct twl4030_usb *twl, 
> int controller_off)
>  
>       twl4030_phy_power(twl, 0);
>       twl->asleep = 1;
> +     otg_power_controller(&twl->otg, 0);
>  }
>  
>  static void twl4030_phy_resume(struct twl4030_usb *twl)
> @@ -516,6 +517,7 @@ static void twl4030_phy_resume(struct twl4030_usb *twl)
>       if (twl->usb_mode == T2_USB_MODE_ULPI)
>               twl4030_i2c_access(twl, 0);
>       twl->asleep = 0;
> +     otg_power_controller(&twl->otg, 1);
>  }
>  
>  static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
> diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
> index e328a89..77c4bdc 100644
> --- a/include/linux/usb/otg.h
> +++ b/include/linux/usb/otg.h
> @@ -60,6 +60,14 @@ struct otg_io_access_ops {
>       int (*write)(struct otg_transceiver *otg, u32 val, u32 reg);
>  };
>  
> +/* the otg driver needs to inform the usb controller driver when vbus
> + * is present or not.
> + */
> +struct otg_controller {
> +     struct device *dev;
> +     int (*power_controller)(struct otg_controller *otg, bool vbus);
> +};
> +
>  /*
>   * the otg driver needs to interact with both device side and host side
>   * usb controllers.  it decides which controller is active at a given
> @@ -93,6 +101,8 @@ struct otg_transceiver {
>       u16                     port_status;
>       u16                     port_change;
>  
> +     struct otg_controller   *controller;
> +
>       /* initialize/shutdown the OTG controller */
>       int     (*init)(struct otg_transceiver *otg);
>       void    (*shutdown)(struct otg_transceiver *otg);
> @@ -171,6 +181,7 @@ otg_shutdown(struct otg_transceiver *otg)
>  /* for usb host and peripheral controller drivers */
>  extern struct otg_transceiver *otg_get_transceiver(void);
>  extern void otg_put_transceiver(struct otg_transceiver *);
> +extern int otg_power_controller(struct otg_transceiver *, bool);
>  
>  /* Context: can sleep */
>  static inline int

--
Ari

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to