> -----Original Message----- > From: Alexandre Belloni [mailto:alexandre.bell...@free-electrons.com] > Sent: 2016年5月12日 11:53 > To: Yang, Wenyou <wenyou.y...@atmel.com> > Cc: Alan Stern <st...@rowland.harvard.edu>; Greg Kroah-Hartman > <gre...@linuxfoundation.org>; Ferre, Nicolas <nicolas.fe...@atmel.com>; > linux-...@vger.kernel.org; linux-kernel@vger.kernel.org; linux-arm- > ker...@lists.infradead.org > Subject: Re: [PATCH] usb: ohci-at91: Suspend the ports while USB suspending > > Hi, > > On 12/05/2016 at 09:05:34 +0800, Wenyou Yang wrote : > > In order to get lower consumption, as a workaround, suspend the USB > > PORTA/B/C via set the SUSPEND_A/B/C bits of OHCI Interrupt > > Configuration Register while OHCI USB suspending. > > > > Why is that a workaround?
Because if these bits is not set as this patch, there is 5mA current left at VDDOSC rail during suspend. If apply this patch, this current will disappear. So, I think it is a workaround. > > > This suspend operation must be done before stopping the USB clock, > > resume after the USB clock enabled. > > > > Signed-off-by: Wenyou Yang <wenyou.y...@atmel.com> > > --- > > > > drivers/usb/host/ohci-at91.c | 63 > > ++++++++++++++++++++++++++++++++++++++++++++ > > 1 file changed, 63 insertions(+) > > > > diff --git a/drivers/usb/host/ohci-at91.c > > b/drivers/usb/host/ohci-at91.c index d177372..ce898e0 100644 > > --- a/drivers/usb/host/ohci-at91.c > > +++ b/drivers/usb/host/ohci-at91.c > > @@ -21,6 +21,8 @@ > > #include <linux/io.h> > > #include <linux/kernel.h> > > #include <linux/module.h> > > +#include <linux/mfd/syscon.h> > > +#include <linux/regmap.h> > > #include <linux/usb.h> > > #include <linux/usb/hcd.h> > > > > @@ -51,6 +53,7 @@ struct ohci_at91_priv { > > struct clk *hclk; > > bool clocked; > > bool wakeup; /* Saved wake-up state for resume */ > > + struct regmap *sfr_regmap; > > }; > > /* interface and function clocks; sometimes also an AHB clock */ > > > > @@ -132,6 +135,17 @@ static void at91_stop_hc(struct platform_device > > *pdev) > > > > > > /*-------------------------------------------------------------------- > > -----*/ > > > > +struct regmap *at91_dt_syscon_sfr(void) { > > + struct regmap *regmap; > > + > > + regmap = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); > > + if (IS_ERR(regmap)) > > + return NULL; > > + > > + return regmap; > > +} > > + > > static void usb_hcd_at91_remove (struct usb_hcd *, struct > > platform_device *); > > > > /* configure so an HC device and id are always provided */ @@ -197,6 > > +211,8 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, > > goto err; > > } > > > > + ohci_at91->sfr_regmap = at91_dt_syscon_sfr(); > > + > > board = hcd->self.controller->platform_data; > > ohci = hcd_to_ohci(hcd); > > ohci->num_ports = board->ports; > > @@ -581,6 +597,49 @@ static int ohci_hcd_at91_drv_remove(struct > platform_device *pdev) > > return 0; > > } > > > > +#define SFR_OHCIICR 0x10 > > +#define SFR_OHCIICR_SUSPEND_A BIT(8) > > +#define SFR_OHCIICR_SUSPEND_B BIT(9) > > +#define SFR_OHCIICR_SUSPEND_C BIT(10) > > + > > +#define SFR_OHCIICR_USB_SUSPEND (SFR_OHCIICR_SUSPEND_A | \ > > + SFR_OHCIICR_SUSPEND_B | \ > > + SFR_OHCIICR_SUSPEND_C) > > + > > Those defines should go in a header file either in include/soc/at91 or in > include/linux/mfd > > > +static int ohci_at91_port_ctrl(struct regmap *regmap, bool enable) { > > + u32 regval; > > + int ret; > > + > > + if (IS_ERR(regmap)) > > + return PTR_ERR(regmap); > > + > > + ret = regmap_read(regmap, SFR_OHCIICR, ®val); > > + if (ret) > > + return ret; > > + > > + if (enable) > > + regval &= ~SFR_OHCIICR_USB_SUSPEND; > > + else > > + regval |= SFR_OHCIICR_USB_SUSPEND; > > + > > + regmap_write(regmap, SFR_OHCIICR, regval); > > + > > + regmap_read(regmap, SFR_OHCIICR, ®val); > > + > > + return 0; > > +} > > + > > +static int ohci_at91_port_suspend(struct regmap *regmap) { > > + return ohci_at91_port_ctrl(regmap, false); } > > + > > +static int ohci_at91_port_resume(struct regmap *regmap) { > > + return ohci_at91_port_ctrl(regmap, true); } > > + > > static int __maybe_unused > > ohci_hcd_at91_drv_suspend(struct device *dev) { @@ -618,6 +677,8 @@ > > ohci_hcd_at91_drv_suspend(struct device *dev) > > ohci_writel(ohci, ohci->hc_control, &ohci->regs->control); > > ohci->rh_state = OHCI_RH_HALTED; > > > > + ohci_at91_port_suspend(ohci_at91->sfr_regmap); > > + > > The main issue I see here is that you will call that function for all SoCs > and it will > always fail unless it is running on a sama5d2. Maybe we could be smarter about > that. Can we use another compatible, such as "atmel,sama5d2-ohci" to differentiate it? Best Regards, Wenyou Yang