From patchwork Mon Apr 3 12:20:30 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Quadros X-Patchwork-Id: 96627 Delivered-To: patch@linaro.org Received: by 10.140.89.233 with SMTP id v96csp72696qgd; Mon, 3 Apr 2017 05:21:43 -0700 (PDT) X-Received: by 10.99.101.132 with SMTP id z126mr4347588pgb.218.1491222102904; Mon, 03 Apr 2017 05:21:42 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a124si7883683pgc.127.2017.04.03.05.21.42; Mon, 03 Apr 2017 05:21:42 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@ti.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753161AbdDCMVa (ORCPT + 25 others); Mon, 3 Apr 2017 08:21:30 -0400 Received: from fllnx209.ext.ti.com ([198.47.19.16]:13243 "EHLO fllnx209.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752483AbdDCMV1 (ORCPT ); Mon, 3 Apr 2017 08:21:27 -0400 Received: from dlelxv90.itg.ti.com ([172.17.2.17]) by fllnx209.ext.ti.com (8.15.1/8.15.1) with ESMTP id v33CKiC7017167; Mon, 3 Apr 2017 07:20:44 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ti.com; s=ti-com-17Q1; t=1491222044; bh=4a5/yNgcuxeh2d/obCt1cjLyqIHtw/+kc4MosvH5yh0=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=tHbZP0YZDZMZ61oHyTLCEnMOPIJpOpZzZJaLnqcadV5LRVN0vLbqdbxkTLOpmNsJu y4dBKXDPFQb8ee4D36WGTNhJ4k605pDCj3uIr/kFrRZOKAJ0Ez5J9EbzWkZAz97mK3 mGQTc65hQZ6mNPO4nmSEpstUqmA2G+FqP025TGdw= Received: from DFLE73.ent.ti.com (dfle73.ent.ti.com [128.247.5.110]) by dlelxv90.itg.ti.com (8.14.3/8.13.8) with ESMTP id v33CKd14013376; Mon, 3 Apr 2017 07:20:39 -0500 Received: from dflp33.itg.ti.com (10.64.6.16) by DFLE73.ent.ti.com (128.247.5.110) with Microsoft SMTP Server id 14.3.294.0; Mon, 3 Apr 2017 07:20:39 -0500 Received: from lta0400828d.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp33.itg.ti.com (8.14.3/8.13.8) with ESMTP id v33CKXur010968; Mon, 3 Apr 2017 07:20:38 -0500 From: Roger Quadros To: CC: , , , Roger Quadros Subject: [PATCH v3 2/3] usb: dwc3: make role-switching work with debugfs/mode Date: Mon, 3 Apr 2017 15:20:30 +0300 Message-ID: <1491222031-18120-3-git-send-email-rogerq@ti.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1491222031-18120-1-git-send-email-rogerq@ti.com> References: <1491222031-18120-1-git-send-email-rogerq@ti.com> MIME-Version: 1.0 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org If dr_mode == "otg", we start by default in PERIPHERAL mode. Keep track of current role in "current_dr_role" whenever dwc3_set_mode() is called. When debugfs/mode is changed AND we're in dual-role mode, handle the switch by stopping and starting the respective host/gadget controllers. Signed-off-by: Roger Quadros --- drivers/usb/dwc3/core.c | 21 +++++++++++--------- drivers/usb/dwc3/core.h | 3 +++ drivers/usb/dwc3/debugfs.c | 49 +++++++++++++++++++++++++++++++++++++++------- 3 files changed, 57 insertions(+), 16 deletions(-) -- 2.7.4 diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 369bab1..bf917c2 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -108,6 +108,8 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode) reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); reg |= DWC3_GCTL_PRTCAPDIR(mode); dwc3_writel(dwc->regs, DWC3_GCTL, reg); + + dwc->current_dr_role = mode; } u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) @@ -277,7 +279,7 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) * * Returns 0 on success otherwise negative errno. */ -static int dwc3_event_buffers_setup(struct dwc3 *dwc) +int dwc3_event_buffers_setup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; @@ -862,13 +864,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) } break; case USB_DR_MODE_OTG: - ret = dwc3_host_init(dwc); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to initialize host\n"); - return ret; - } - + /* start in peripheral role by default */ + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) @@ -894,7 +891,13 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc) dwc3_host_exit(dwc); break; case USB_DR_MODE_OTG: - dwc3_host_exit(dwc); + /* role might have changed since start */ + if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST) { + dwc3_host_exit(dwc); + /* Add back UDC to match dwc3_gadget_exit() */ + usb_add_gadget_udc(dwc->dev, &dwc->gadget); + } + dwc3_gadget_exit(dwc); break; default: diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 7ffdee5..adb04af 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -785,6 +785,7 @@ struct dwc3_scratchpad_array { * @maximum_speed: maximum speed requested (mainly for testing purposes) * @revision: revision register contents * @dr_mode: requested mode of operation + * @current_dr_role: current role of operation when in dual-role mode * @hsphy_mode: UTMI phy mode, one of following: * - USBPHY_INTERFACE_MODE_UTMI * - USBPHY_INTERFACE_MODE_UTMIW @@ -901,6 +902,7 @@ struct dwc3 { size_t regs_size; enum usb_dr_mode dr_mode; + u32 current_dr_role; enum usb_phy_interface hsphy_mode; u32 fladj; @@ -1167,6 +1169,7 @@ struct dwc3_gadget_ep_cmd_params { /* prototypes */ void dwc3_set_mode(struct dwc3 *dwc, u32 mode); u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type); +int dwc3_event_buffers_setup(struct dwc3 *dwc); /* check whether we are on the DWC_usb3 core */ static inline bool dwc3_is_usb3(struct dwc3 *dwc) diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 31926dd..a74a83b 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -327,19 +327,54 @@ static ssize_t dwc3_mode_write(struct file *file, return -EFAULT; if (!strncmp(buf, "host", 4)) - mode |= DWC3_GCTL_PRTCAP_HOST; + mode = DWC3_GCTL_PRTCAP_HOST; if (!strncmp(buf, "device", 6)) - mode |= DWC3_GCTL_PRTCAP_DEVICE; + mode = DWC3_GCTL_PRTCAP_DEVICE; if (!strncmp(buf, "otg", 3)) - mode |= DWC3_GCTL_PRTCAP_OTG; + mode = DWC3_GCTL_PRTCAP_OTG; - if (mode) { - spin_lock_irqsave(&dwc->lock, flags); - dwc3_set_mode(dwc, mode); - spin_unlock_irqrestore(&dwc->lock, flags); + if (!mode) + return -EINVAL; + + if (mode == dwc->current_dr_role) + goto exit; + + /* prevent role switching if we're not dual-role */ + if (dwc->dr_mode != USB_DR_MODE_OTG) + return -EINVAL; + + /* stop old role */ + switch (dwc->current_dr_role) { + case DWC3_GCTL_PRTCAP_HOST: + dwc3_host_exit(dwc); + break; + case DWC3_GCTL_PRTCAP_DEVICE: + usb_del_gadget_udc(&dwc->gadget); + break; + default: + break; + } + + /* switch PRTCAP mode. updates current_dr_role */ + spin_lock_irqsave(&dwc->lock, flags); + dwc3_set_mode(dwc, mode); + spin_unlock_irqrestore(&dwc->lock, flags); + + /* start new role */ + switch (dwc->current_dr_role) { + case DWC3_GCTL_PRTCAP_HOST: + dwc3_host_init(dwc); + break; + case DWC3_GCTL_PRTCAP_DEVICE: + dwc3_event_buffers_setup(dwc); + usb_add_gadget_udc(dwc->dev, &dwc->gadget); + break; + default: + break; } +exit: return count; }