From patchwork Thu May 12 01:05:34 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wenyou Yang X-Patchwork-Id: 9076401 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id D9575BF29F for ; Thu, 12 May 2016 01:15:12 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id EFD8A201B9 for ; Thu, 12 May 2016 01:15:11 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1916620155 for ; Thu, 12 May 2016 01:15:11 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1b0fCD-0002AD-PQ; Thu, 12 May 2016 01:13:45 +0000 Received: from eusmtp01.atmel.com ([212.144.249.242]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1b0fCB-00026C-Cp for linux-arm-kernel@lists.infradead.org; Thu, 12 May 2016 01:13:44 +0000 Received: from apsmtp01.atmel.com (10.168.254.31) by eusmtp01.atmel.com (10.161.101.30) with Microsoft SMTP Server id 14.3.235.1; Thu, 12 May 2016 03:13:17 +0200 Received: from shaarm01.corp.atmel.com (10.168.254.13) by apsmtp01.atmel.com (10.168.254.31) with Microsoft SMTP Server id 14.3.235.1; Thu, 12 May 2016 09:16:58 +0800 From: Wenyou Yang To: Alan Stern , Greg Kroah-Hartman , Nicolas Ferre Subject: [PATCH] usb: ohci-at91: Suspend the ports while USB suspending Date: Thu, 12 May 2016 09:05:34 +0800 Message-ID: <1463015134-32364-1-git-send-email-wenyou.yang@atmel.com> X-Mailer: git-send-email 2.7.4 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160511_181343_766602_A75BDDB5 X-CRM114-Status: GOOD ( 11.07 ) X-Spam-Score: -5.6 (-----) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Wenyou Yang Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-5.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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. This suspend operation must be done before stopping the USB clock, resume after the USB clock enabled. Signed-off-by: Wenyou Yang --- 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 #include #include +#include +#include #include #include @@ -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) + +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); + /* flush the writes */ (void) ohci_readl (ohci, &ohci->regs->control); at91_stop_clock(ohci_at91); @@ -637,6 +698,8 @@ ohci_hcd_at91_drv_resume(struct device *dev) at91_start_clock(ohci_at91); + ohci_at91_port_resume(ohci_at91->sfr_regmap); + ohci_resume(hcd, false); return 0; }