From patchwork Thu Nov 6 01:30:02 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kever Yang X-Patchwork-Id: 5238681 Return-Path: X-Original-To: patchwork-linux-rockchip@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 06EC5C11AC for ; Thu, 6 Nov 2014 01:30:47 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id EA95F20172 for ; Thu, 6 Nov 2014 01:30:45 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1A8F12015A for ; Thu, 6 Nov 2014 01:30:45 +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 1XmBuO-0007L3-1u; Thu, 06 Nov 2014 01:30:44 +0000 Received: from mail-pd0-x233.google.com ([2607:f8b0:400e:c02::233]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XmBuL-00079V-66 for linux-rockchip@lists.infradead.org; Thu, 06 Nov 2014 01:30:42 +0000 Received: by mail-pd0-f179.google.com with SMTP id g10so86293pdj.10 for ; Wed, 05 Nov 2014 17:30:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id; bh=m2PQpWH80z4AwEs3gJGZafBWdBsiaJZWy/CSLD+X+BQ=; b=S0hzXraJD293agBrG1HsB08S/jhwjXgA8diAZlvxrmTQWpYJDPMLMZaZGdVG1ISFWJ Fb1uXOpXoQzJe3y5HDmLCdvnTAaG8G9lRihbCLKOMXi9weitQJBj50Tfv1ryRw62/8gm JW+xNgVGAOZEjkUeU/46ip0OCbHZtVXrZiRH8uuVBEYpX+9Pi6H4KAtFAUiiLnc2lr2U mzi07iQPYjJaCq9Qd5+9dLf+GINV3E4hFhGMToWbP9QZCr/ynavF8aKz8qbEvcruX7Kg T3WtAVfXCeJPqg8GF8mFeBRi/yq7Sv9RHw90yMX3rmrXvNwesBj14a7AggwW3LRRvLoV 99RQ== X-Received: by 10.66.176.39 with SMTP id cf7mr903046pac.93.1415237418888; Wed, 05 Nov 2014 17:30:18 -0800 (PST) Received: from localhost.localdomain ([58.22.7.114]) by mx.google.com with ESMTPSA id o5sm4290387pdr.50.2014.11.05.17.30.09 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 05 Nov 2014 17:30:17 -0800 (PST) From: Kever Yang To: Paul Zimmerman , Felipe Balbi Subject: [PATCH v2] usb: dwc2: add bus suspend/resume for dwc2 Date: Thu, 6 Nov 2014 09:30:02 +0800 Message-Id: <1415237402-24665-1-git-send-email-kever.yang@rock-chips.com> X-Mailer: git-send-email 1.9.1 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20141105_173041_349547_D48349F9 X-CRM114-Status: GOOD ( 12.52 ) X-Spam-Score: -0.7 (/) Cc: huangtao@rock-chips.com, dkl@rock-chips.com, addy.ke@rock-chips.com, hj@rock-chips.com, Heiko Stuebner , Greg Kroah-Hartman , linux-usb@vger.kernel.org, dianders@chromium.org, Kever Yang , linux-rockchip@lists.infradead.org, xjq@rock-chips.com, cf@rock-chips.com, Dinh Nguyen , romain.perier@gmail.com, sonnyrao@chromium.org, linux-kernel@vger.kernel.org X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-2.4 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_NONE,RP_MATCHES_RCVD,T_DKIM_INVALID,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 Hcd controller needs bus_suspend/resume, dwc2 controller make root hub generate suspend/resume signal with hprt0 register when work in host mode. After the root hub enter suspend, we can make controller enter low power state with PCGCTL register. We also update the lx_state for hsotg state. This patch has tested on rk3288 with suspend/resume. Signed-off-by: Kever Yang --- Changes in v2: - update commit message - make dwc2 suspend/resume sourcecode work drivers/usb/dwc2/hcd.c | 78 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 11 deletions(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 0a0e6f0..01a415b 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -1471,6 +1471,30 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) } } +static void dwc2_port_resume(struct dwc2_hsotg *hsotg) +{ + u32 hprt0; + + /* After clear the Stop PHY clock bit, we should wait for a moment + * for PLL work stable with clock output. + */ + writel(0, hsotg->regs + PCGCTL); + usleep_range(2000, 4000); + + hprt0 = dwc2_read_hprt0(hsotg); + hprt0 |= HPRT0_RES; + writel(hprt0, hsotg->regs + HPRT0); + hprt0 &= ~HPRT0_SUSP; + /* according to USB2.0 Spec 7.1.7.7, the host must send the resume + * signal for at least 20ms + */ + usleep_range(20000, 25000); + + hprt0 &= ~HPRT0_RES; + writel(hprt0, hsotg->regs + HPRT0); + hsotg->lx_state = DWC2_L0; +} + /* Handles hub class-specific requests */ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, u16 wvalue, u16 windex, char *buf, u16 wlength) @@ -1516,17 +1540,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, case USB_PORT_FEAT_SUSPEND: dev_dbg(hsotg->dev, "ClearPortFeature USB_PORT_FEAT_SUSPEND\n"); - writel(0, hsotg->regs + PCGCTL); - usleep_range(20000, 40000); - - hprt0 = dwc2_read_hprt0(hsotg); - hprt0 |= HPRT0_RES; - writel(hprt0, hsotg->regs + HPRT0); - hprt0 &= ~HPRT0_SUSP; - usleep_range(100000, 150000); - - hprt0 &= ~HPRT0_RES; - writel(hprt0, hsotg->regs + HPRT0); + dwc2_port_resume(hsotg); break; case USB_PORT_FEAT_POWER: @@ -2299,6 +2313,44 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd) usleep_range(1000, 3000); } +static int _dwc2_hcd_suspend(struct usb_hcd *hcd) +{ + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + u32 hprt0; + + if (!((hsotg->op_state == OTG_STATE_B_HOST) || + (hsotg->op_state == OTG_STATE_A_HOST))) + return 0; + + if (hsotg->lx_state != DWC2_L0) + return 0; + + hprt0 = dwc2_read_hprt0(hsotg); + if (hprt0 & HPRT0_CONNSTS) + dwc2_port_suspend(hsotg, 1); + + return 0; +} + +static int _dwc2_hcd_resume(struct usb_hcd *hcd) +{ + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + u32 hprt0; + + if (!((hsotg->op_state == OTG_STATE_B_HOST) || + (hsotg->op_state == OTG_STATE_A_HOST))) + return 0; + + if (hsotg->lx_state != DWC2_L2) + return 0; + + hprt0 = dwc2_read_hprt0(hsotg); + if ((hprt0 & HPRT0_CONNSTS) && (hprt0 & HPRT0_SUSP)) + dwc2_port_resume(hsotg); + + return 0; +} + /* Returns the current frame number */ static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd) { @@ -2669,6 +2721,10 @@ static struct hc_driver dwc2_hc_driver = { .hub_status_data = _dwc2_hcd_hub_status_data, .hub_control = _dwc2_hcd_hub_control, .clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete, +#ifdef CONFIG_PM + .bus_suspend = _dwc2_hcd_suspend, + .bus_resume = _dwc2_hcd_resume, +#endif }; /*