Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1cee6b8d authored by Sylvain Rochet's avatar Sylvain Rochet Committed by Greg Kroah-Hartman
Browse files

USB: host: ohci-at91: Fix wake-up support



This device needs to be continuously clocked to provide wake up support,
previously, if STANDBY target were chosen the device were
enable_irq_wake()-prepared and clock still active and if MEM target were
chosen the device were also enable_irq_wake()-prepared but not clocked
anymore, which is wrong.

Now, if STANDBY target is chosen the device is still clocked with wake
up support enabled, which were the previous default and if MEM target is
chosen the device is declocked with wake up support disabled.

Signed-off-by: default avatarSylvain Rochet <sylvain.rochet@finsecur.com>
Acked-by: default avatarBoris Brezillon <boris.brezillon@free-electrons.com>
Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Acked-by: default avatarNicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3b3394af
Loading
Loading
Loading
Loading
+19 −8
Original line number Original line Diff line number Diff line
@@ -42,6 +42,7 @@ struct ohci_at91_priv {
	struct clk *uclk;
	struct clk *uclk;
	struct clk *hclk;
	struct clk *hclk;
	bool clocked;
	bool clocked;
	bool wakeup;		/* Saved wake-up state for resume */
};
};
/* interface and function clocks; sometimes also an AHB clock */
/* interface and function clocks; sometimes also an AHB clock */


@@ -61,6 +62,8 @@ extern int usb_disabled(void);


static void at91_start_clock(struct ohci_at91_priv *ohci_at91)
static void at91_start_clock(struct ohci_at91_priv *ohci_at91)
{
{
	if (ohci_at91->clocked)
		return;
	if (IS_ENABLED(CONFIG_COMMON_CLK)) {
	if (IS_ENABLED(CONFIG_COMMON_CLK)) {
		clk_set_rate(ohci_at91->uclk, 48000000);
		clk_set_rate(ohci_at91->uclk, 48000000);
		clk_prepare_enable(ohci_at91->uclk);
		clk_prepare_enable(ohci_at91->uclk);
@@ -73,6 +76,8 @@ static void at91_start_clock(struct ohci_at91_priv *ohci_at91)


static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
{
{
	if (!ohci_at91->clocked)
		return;
	clk_disable_unprepare(ohci_at91->fclk);
	clk_disable_unprepare(ohci_at91->fclk);
	clk_disable_unprepare(ohci_at91->iclk);
	clk_disable_unprepare(ohci_at91->iclk);
	clk_disable_unprepare(ohci_at91->hclk);
	clk_disable_unprepare(ohci_at91->hclk);
@@ -616,14 +621,21 @@ ohci_hcd_at91_drv_suspend(struct device *dev)
	struct usb_hcd	*hcd = dev_get_drvdata(dev);
	struct usb_hcd	*hcd = dev_get_drvdata(dev);
	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
	struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
	struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
	bool		do_wakeup = device_may_wakeup(dev);
	int		ret;
	int		ret;


	if (do_wakeup)
	/*
	 * Disable wakeup if we are going to sleep with slow clock mode
	 * enabled.
	 */
	ohci_at91->wakeup = device_may_wakeup(dev)
			&& !at91_suspend_entering_slow_clock();

	if (ohci_at91->wakeup)
		enable_irq_wake(hcd->irq);
		enable_irq_wake(hcd->irq);


	ret = ohci_suspend(hcd, do_wakeup);
	ret = ohci_suspend(hcd, ohci_at91->wakeup);
	if (ret) {
	if (ret) {
		if (ohci_at91->wakeup)
			disable_irq_wake(hcd->irq);
			disable_irq_wake(hcd->irq);
		return ret;
		return ret;
	}
	}
@@ -634,7 +646,7 @@ ohci_hcd_at91_drv_suspend(struct device *dev)
	 *
	 *
	 * REVISIT: some boards will be able to turn VBUS off...
	 * REVISIT: some boards will be able to turn VBUS off...
	 */
	 */
	if (at91_suspend_entering_slow_clock()) {
	if (!ohci_at91->wakeup) {
		ohci->hc_control = ohci_readl(ohci, &ohci->regs->control);
		ohci->hc_control = ohci_readl(ohci, &ohci->regs->control);
		ohci->hc_control &= OHCI_CTRL_RWC;
		ohci->hc_control &= OHCI_CTRL_RWC;
		ohci_writel(ohci, ohci->hc_control, &ohci->regs->control);
		ohci_writel(ohci, ohci->hc_control, &ohci->regs->control);
@@ -653,10 +665,9 @@ static int ohci_hcd_at91_drv_resume(struct device *dev)
	struct usb_hcd	*hcd = dev_get_drvdata(dev);
	struct usb_hcd	*hcd = dev_get_drvdata(dev);
	struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
	struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);


	if (device_may_wakeup(dev))
	if (ohci_at91->wakeup)
		disable_irq_wake(hcd->irq);
		disable_irq_wake(hcd->irq);


	if (!ohci_at91->clocked)
	at91_start_clock(ohci_at91);
	at91_start_clock(ohci_at91);


	ohci_resume(hcd, false);
	ohci_resume(hcd, false);