From patchwork Thu Dec 27 07:34:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Min Guo X-Patchwork-Id: 10743547 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5A37B13B5 for ; Thu, 27 Dec 2018 07:35:14 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3DF142877F for ; Thu, 27 Dec 2018 07:35:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 31934287B3; Thu, 27 Dec 2018 07:35:14 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 438E32878C for ; Thu, 27 Dec 2018 07:35:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729850AbeL0He7 (ORCPT ); Thu, 27 Dec 2018 02:34:59 -0500 Received: from mailgw02.mediatek.com ([1.203.163.81]:54143 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1728625AbeL0He6 (ORCPT ); Thu, 27 Dec 2018 02:34:58 -0500 X-UUID: e30c9c35426e45f794f99bde7381183f-20181227 X-UUID: e30c9c35426e45f794f99bde7381183f-20181227 Received: from mtkcas34.mediatek.inc [(172.27.4.250)] by mailgw02.mediatek.com (envelope-from ) (mailgw01.mediatek.com ESMTP with TLS) with ESMTP id 692165439; Thu, 27 Dec 2018 15:34:47 +0800 Received: from mtkcas09.mediatek.inc (172.21.101.178) by MTKMBS31N2.mediatek.inc (172.27.4.87) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Thu, 27 Dec 2018 15:34:45 +0800 Received: from localhost.localdomain (10.17.3.153) by mtkcas09.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Thu, 27 Dec 2018 15:34:45 +0800 From: To: Bin Liu , Rob Herring CC: Greg Kroah-Hartman , Mark Rutland , Matthias Brugger , Alan Stern , , , , , , , Min Guo Subject: [PATCH 1/4] dt-bindings: usb: musb: Add support for MediaTek musb controller Date: Thu, 27 Dec 2018 15:34:23 +0800 Message-ID: <1545896066-897-2-git-send-email-min.guo@mediatek.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1545896066-897-1-git-send-email-min.guo@mediatek.com> References: <1545896066-897-1-git-send-email-min.guo@mediatek.com> MIME-Version: 1.0 X-MTK: N Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Min Guo This adds support for MediaTek musb controller in host, peripheral and otg mode Signed-off-by: Min Guo --- .../devicetree/bindings/usb/mediatek,musb.txt | 49 ++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/mediatek,musb.txt diff --git a/Documentation/devicetree/bindings/usb/mediatek,musb.txt b/Documentation/devicetree/bindings/usb/mediatek,musb.txt new file mode 100644 index 0000000..e899c9b --- /dev/null +++ b/Documentation/devicetree/bindings/usb/mediatek,musb.txt @@ -0,0 +1,49 @@ +MediaTek musb DRC/OTG controller +------------------------------------------- + +Required properties: + - compatible : should be "mediatek,-musb", + "mediatek,mtk-musb", soc-model is the name of SoC, such as + mt2701, when using "mediatek,mtk-musb" compatible string, you + need SoC specific ones in addition, one of: + - "mediatek,mt2701-musb" + - reg : specifies physical base address and size of + the registers + - interrupts : interrupt used by musb controller + - interrupt-names : must be "mc" + - phys : PHY specifier for the OTG phy + - phy-names : should be "usb2-phy" + - dr_mode : should be one of "host", "peripheral" or "otg", + refer to usb/generic.txt + - clocks : a list of phandle + clock-specifier pairs, one for + each entry in clock-names + - clock-names : must contain "main","mcu","univpll" + for clocks of controller + +Optional properties: + - extcon : external connector for VBUS and IDPIN changes detection, + needed when supports dual-role mode. + - vbus-supply : reference to the VBUS regulator, needed when supports + dual-role mode. + - power-domains : a phandle to USB power domain node to control USB's + MTCMOS + +Example: + +usb2: usb@11200000 { + compatible = "mediatek,mt2701-musb"; + "mediatek,mtk-musb"; + reg = <0 0x11200000 0 0x1000>; + interrupts = ; + interrupt-names = "mc"; + phys = <&u2port2 PHY_TYPE_USB2>; + phy-names = "usb2-phy"; + vbus-supply = <&usb_vbus>; + extcon = <&extcon_usb>; + dr_mode = "otg"; + clocks = <&pericfg CLK_PERI_USB0>, + <&pericfg CLK_PERI_USB0_MCU>, + <&pericfg CLK_PERI_USB_SLV>; + clock-names = "main","mcu","univpll"; + power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>; +}; From patchwork Thu Dec 27 07:34:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Min Guo X-Patchwork-Id: 10743551 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 835AA1708 for ; Thu, 27 Dec 2018 07:35:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 71C8D2877F for ; Thu, 27 Dec 2018 07:35:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 661F1287B3; Thu, 27 Dec 2018 07:35:18 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7662A2877F for ; Thu, 27 Dec 2018 07:35:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728949AbeL0He4 (ORCPT ); Thu, 27 Dec 2018 02:34:56 -0500 Received: from mailgw02.mediatek.com ([1.203.163.81]:17512 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1727950AbeL0Hez (ORCPT ); Thu, 27 Dec 2018 02:34:55 -0500 X-UUID: b650fc18a28d48beb3a896ae640f8ca3-20181227 X-UUID: b650fc18a28d48beb3a896ae640f8ca3-20181227 Received: from mtkcas34.mediatek.inc [(172.27.4.250)] by mailgw02.mediatek.com (envelope-from ) (mailgw01.mediatek.com ESMTP with TLS) with ESMTP id 1110584122; Thu, 27 Dec 2018 15:34:48 +0800 Received: from mtkcas09.mediatek.inc (172.21.101.178) by MTKMBS31N1.mediatek.inc (172.27.4.69) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Thu, 27 Dec 2018 15:34:47 +0800 Received: from localhost.localdomain (10.17.3.153) by mtkcas09.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Thu, 27 Dec 2018 15:34:46 +0800 From: To: Bin Liu , Rob Herring CC: Greg Kroah-Hartman , Mark Rutland , Matthias Brugger , Alan Stern , , , , , , , Min Guo Subject: [PATCH 2/4] arm: dts: mt2701: Add usb2 device nodes Date: Thu, 27 Dec 2018 15:34:24 +0800 Message-ID: <1545896066-897-3-git-send-email-min.guo@mediatek.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1545896066-897-1-git-send-email-min.guo@mediatek.com> References: <1545896066-897-1-git-send-email-min.guo@mediatek.com> MIME-Version: 1.0 X-MTK: N Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Min Guo Add musb nodes and usb2 phy nodes for MT2701 Signed-off-by: Min Guo --- arch/arm/boot/dts/mt2701-evb.dts | 21 +++++++++++++++++++++ arch/arm/boot/dts/mt2701.dtsi | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/arch/arm/boot/dts/mt2701-evb.dts b/arch/arm/boot/dts/mt2701-evb.dts index be0edb3..2635911 100644 --- a/arch/arm/boot/dts/mt2701-evb.dts +++ b/arch/arm/boot/dts/mt2701-evb.dts @@ -6,6 +6,7 @@ */ /dts-v1/; +#include #include "mt2701.dtsi" / { @@ -60,6 +61,20 @@ >; default-brightness-level = <9>; }; + + extcon_usb: extcon_iddig { + compatible = "linux,extcon-usb-gpio"; + id-gpio = <&pio 44 GPIO_ACTIVE_HIGH>; + }; + + usb_vbus: regulator@0 { + compatible = "regulator-fixed"; + regulator-name = "usb_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&pio 45 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; }; &auxadc { @@ -229,3 +244,9 @@ &uart0 { status = "okay"; }; + +&usb2 { + vbus-supply = <&usb_vbus>; + extcon = <&extcon_usb>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi index 180377e..495ece9 100644 --- a/arch/arm/boot/dts/mt2701.dtsi +++ b/arch/arm/boot/dts/mt2701.dtsi @@ -670,6 +670,40 @@ }; }; + usb2: usb@11200000 { + compatible = "mediatek,mt2701-musb", + "mediatek,mtk-musb"; + reg = <0 0x11200000 0 0x1000>; + interrupts = ; + interrupt-names = "mc"; + phys = <&u2port2 PHY_TYPE_USB2>; + phy-names = "usb2-phy"; + dr_mode = "otg"; + clocks = <&pericfg CLK_PERI_USB0>, + <&pericfg CLK_PERI_USB0_MCU>, + <&pericfg CLK_PERI_USB_SLV>; + clock-names = "main","mcu","univpll"; + power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>; + status = "disabled"; + }; + + u2phy0: usb-phy@11210000 { + compatible = "mediatek,generic-tphy-v1"; + reg = <0 0x11210000 0 0x0800>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "okay"; + + u2port2: usb-phy@1a1c4800 { + reg = <0 0x11210800 0 0x0100>; + clocks = <&topckgen CLK_TOP_USB_PHY48M>; + clock-names = "ref"; + #phy-cells = <1>; + status = "okay"; + }; + }; + ethsys: syscon@1b000000 { compatible = "mediatek,mt2701-ethsys", "syscon"; reg = <0 0x1b000000 0 0x1000>; From patchwork Thu Dec 27 07:34:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Min Guo X-Patchwork-Id: 10743555 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 815256C2 for ; Thu, 27 Dec 2018 07:35:34 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6FE892877F for ; Thu, 27 Dec 2018 07:35:34 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 63A6D2879E; Thu, 27 Dec 2018 07:35:34 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 78BFA2877F for ; Thu, 27 Dec 2018 07:35:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730273AbeL0HfY (ORCPT ); Thu, 27 Dec 2018 02:35:24 -0500 Received: from Mailgw01.mediatek.com ([1.203.163.78]:61038 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1728900AbeL0HfX (ORCPT ); Thu, 27 Dec 2018 02:35:23 -0500 X-UUID: ce4a430f9fce4327b15afbcec40d852c-20181227 X-UUID: ce4a430f9fce4327b15afbcec40d852c-20181227 Received: from mtkcas36.mediatek.inc [(172.27.4.250)] by mailgw01.mediatek.com (envelope-from ) (mailgw01.mediatek.com ESMTP with TLS) with ESMTP id 829140371; Thu, 27 Dec 2018 15:34:50 +0800 Received: from mtkcas09.mediatek.inc (172.21.101.178) by MTKMBS31DR.mediatek.inc (172.27.6.102) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Thu, 27 Dec 2018 15:34:48 +0800 Received: from localhost.localdomain (10.17.3.153) by mtkcas09.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Thu, 27 Dec 2018 15:34:47 +0800 From: To: Bin Liu , Rob Herring CC: Greg Kroah-Hartman , Mark Rutland , Matthias Brugger , Alan Stern , , , , , , , Min Guo Subject: [PATCH 3/4] usb: musb: Move musbhsdma macro definition to musb_dma.h Date: Thu, 27 Dec 2018 15:34:25 +0800 Message-ID: <1545896066-897-4-git-send-email-min.guo@mediatek.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1545896066-897-1-git-send-email-min.guo@mediatek.com> References: <1545896066-897-1-git-send-email-min.guo@mediatek.com> MIME-Version: 1.0 X-MTK: N Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Min Guo Because the MediaTek musb controller dose not have a separate DMA interrupt, these macros are required to access the dma registers Signed-off-by: Min Guo --- drivers/usb/musb/musb_dma.h | 6 ++++++ drivers/usb/musb/musbhsdma.c | 7 +------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h index 8f60271..281e75d3 100644 --- a/drivers/usb/musb/musb_dma.h +++ b/drivers/usb/musb/musb_dma.h @@ -35,6 +35,12 @@ * whether shared with the Inventra core or separate. */ +#define MUSB_HSDMA_BASE 0x200 +#define MUSB_HSDMA_INTR (MUSB_HSDMA_BASE + 0) +#define MUSB_HSDMA_CONTROL 0x4 +#define MUSB_HSDMA_ADDRESS 0x8 +#define MUSB_HSDMA_COUNT 0xc + #define DMA_ADDR_INVALID (~(dma_addr_t)0) #ifdef CONFIG_MUSB_PIO_ONLY diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index a688f7f..824adcb 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -10,12 +10,7 @@ #include #include #include "musb_core.h" - -#define MUSB_HSDMA_BASE 0x200 -#define MUSB_HSDMA_INTR (MUSB_HSDMA_BASE + 0) -#define MUSB_HSDMA_CONTROL 0x4 -#define MUSB_HSDMA_ADDRESS 0x8 -#define MUSB_HSDMA_COUNT 0xc +#include "musb_dma.h" #define MUSB_HSDMA_CHANNEL_OFFSET(_bchannel, _offset) \ (MUSB_HSDMA_BASE + (_bchannel << 4) + _offset) From patchwork Thu Dec 27 07:34:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Min Guo X-Patchwork-Id: 10743553 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 198346C2 for ; Thu, 27 Dec 2018 07:35:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F2F912877F for ; Thu, 27 Dec 2018 07:35:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E3EAB2879E; Thu, 27 Dec 2018 07:35:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BEDC12877F for ; Thu, 27 Dec 2018 07:35:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729243AbeL0HfQ (ORCPT ); Thu, 27 Dec 2018 02:35:16 -0500 Received: from Mailgw01.mediatek.com ([1.203.163.78]:48218 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1728847AbeL0HfP (ORCPT ); Thu, 27 Dec 2018 02:35:15 -0500 X-UUID: 467acc640b33434aad14abc7b83a0510-20181227 X-UUID: 467acc640b33434aad14abc7b83a0510-20181227 Received: from mtkcas35.mediatek.inc [(172.27.4.250)] by mailgw01.mediatek.com (envelope-from ) (mailgw01.mediatek.com ESMTP with TLS) with ESMTP id 28097431; Thu, 27 Dec 2018 15:34:51 +0800 Received: from mtkcas09.mediatek.inc (172.21.101.178) by MTKMBS31N2.mediatek.inc (172.27.4.87) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Thu, 27 Dec 2018 15:34:49 +0800 Received: from localhost.localdomain (10.17.3.153) by mtkcas09.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Thu, 27 Dec 2018 15:34:48 +0800 From: To: Bin Liu , Rob Herring CC: Greg Kroah-Hartman , Mark Rutland , Matthias Brugger , Alan Stern , , , , , , , Min Guo , Yonglong Wu Subject: [PATCH 4/4] usb: musb: Add support for MediaTek musb controller Date: Thu, 27 Dec 2018 15:34:26 +0800 Message-ID: <1545896066-897-5-git-send-email-min.guo@mediatek.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1545896066-897-1-git-send-email-min.guo@mediatek.com> References: <1545896066-897-1-git-send-email-min.guo@mediatek.com> MIME-Version: 1.0 X-MTK: N Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Min Guo This adds support for MediaTek musb controller in host, peripheral and otg mode Signed-off-by: Min Guo Signed-off-by: Yonglong Wu --- drivers/usb/musb/Kconfig | 8 +- drivers/usb/musb/Makefile | 1 + drivers/usb/musb/mediatek.c | 562 +++++++++++++++++++++++++++++++++++++++++++ drivers/usb/musb/musb_core.c | 10 + drivers/usb/musb/musb_core.h | 1 + drivers/usb/musb/musb_dma.h | 1 + drivers/usb/musb/musb_host.c | 79 ++++-- drivers/usb/musb/musb_regs.h | 6 + drivers/usb/musb/musbhsdma.c | 34 ++- 9 files changed, 671 insertions(+), 31 deletions(-) create mode 100644 drivers/usb/musb/mediatek.c diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index ad08895..540fc9f 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -115,6 +115,12 @@ config USB_MUSB_JZ4740 depends on USB_MUSB_GADGET depends on USB_OTG_BLACKLIST_HUB +config USB_MUSB_MEDIATEK + tristate "MediaTek platforms" + depends on ARCH_MEDIATEK + depends on NOP_USB_XCEIV + depends on GENERIC_PHY + config USB_MUSB_AM335X_CHILD tristate @@ -141,7 +147,7 @@ config USB_UX500_DMA config USB_INVENTRA_DMA bool 'Inventra' - depends on USB_MUSB_OMAP2PLUS + depends on USB_MUSB_OMAP2PLUS || USB_MUSB_MEDIATEK help Enable DMA transfers using Mentor's engine. diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index 3a88c79..63d82d0 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o obj-$(CONFIG_USB_MUSB_UX500) += ux500.o obj-$(CONFIG_USB_MUSB_JZ4740) += jz4740.o obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o +obj-$(CONFIG_USB_MUSB_MEDIATEK) += mediatek.o obj-$(CONFIG_USB_MUSB_AM335X_CHILD) += musb_am335x.o diff --git a/drivers/usb/musb/mediatek.c b/drivers/usb/musb/mediatek.c new file mode 100644 index 0000000..15a6460 --- /dev/null +++ b/drivers/usb/musb/mediatek.c @@ -0,0 +1,562 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 MediaTek Inc. + * + * Author: + * Min Guo + * Yonglong Wu + */ + +#include +#include +#include +#include +#include +#include "musb_core.h" +#include "musb_dma.h" + +#define USB_L1INTS 0x00a0 +#define USB_L1INTM 0x00a4 +#define MTK_MUSB_TXFUNCADDR 0x0480 + +#define TX_INT_STATUS BIT(0) +#define RX_INT_STATUS BIT(1) +#define USBCOM_INT_STATUS BIT(2) +#define DMA_INT_STATUS BIT(3) + +#define DMA_INTR_STATUS_MSK GENMASK(7, 0) +#define DMA_INTR_UNMASK_SET_MSK GENMASK(31, 24) + +enum mtk_vbus_id_state { + MTK_ID_FLOAT = 1, + MTK_ID_GROUND, + MTK_VBUS_OFF, + MTK_VBUS_VALID, +}; + +struct mtk_glue { + struct device *dev; + struct musb *musb; + struct platform_device *musb_pdev; + struct platform_device *usb_phy; + struct phy *phy; + struct usb_phy *xceiv; + enum phy_mode phy_mode; + struct clk *main; + struct clk *mcu; + struct clk *univpll; + struct regulator *vbus; + struct extcon_dev *edev; + struct notifier_block vbus_nb; + struct notifier_block id_nb; +}; + +static int mtk_musb_clks_get(struct mtk_glue *glue) +{ + struct device *dev = glue->dev; + + glue->main = devm_clk_get(dev, "main"); + if (IS_ERR(glue->main)) { + dev_err(dev, "fail to get main clock\n"); + return PTR_ERR(glue->main); + } + + glue->mcu = devm_clk_get(dev, "mcu"); + if (IS_ERR(glue->mcu)) { + dev_err(dev, "fail to get mcu clock\n"); + return PTR_ERR(glue->mcu); + } + + glue->univpll = devm_clk_get(dev, "univpll"); + if (IS_ERR(glue->univpll)) { + dev_err(dev, "fail to get univpll clock\n"); + return PTR_ERR(glue->univpll); + } + + return 0; +} + +static int mtk_musb_clks_enable(struct mtk_glue *glue) +{ + int ret; + + ret = clk_prepare_enable(glue->main); + if (ret) { + dev_err(glue->dev, "failed to enable main clock\n"); + goto err_main_clk; + } + + ret = clk_prepare_enable(glue->mcu); + if (ret) { + dev_err(glue->dev, "failed to enable mcu clock\n"); + goto err_mcu_clk; + } + + ret = clk_prepare_enable(glue->univpll); + if (ret) { + dev_err(glue->dev, "failed to enable univpll clock\n"); + goto err_univpll_clk; + } + + return 0; + +err_univpll_clk: + clk_disable_unprepare(glue->mcu); +err_mcu_clk: + clk_disable_unprepare(glue->main); +err_main_clk: + return ret; +} + +static void mtk_musb_clks_disable(struct mtk_glue *glue) +{ + clk_disable_unprepare(glue->univpll); + clk_disable_unprepare(glue->mcu); + clk_disable_unprepare(glue->main); +} + +static void mtk_musb_set_vbus(struct musb *musb, int is_on) +{ + struct device *dev = musb->controller; + struct mtk_glue *glue = dev_get_drvdata(dev->parent); + int ret; + + /* vbus is optional */ + if (!glue->vbus) + return; + + dev_dbg(musb->controller, "%s, is_on=%d\r\n", __func__, is_on); + if (is_on) { + ret = regulator_enable(glue->vbus); + if (ret) { + dev_err(glue->dev, "fail to enable vbus regulator\n"); + return; + } + } else { + regulator_disable(glue->vbus); + } +} + +/* + * switch to host: -> MTK_VBUS_OFF --> MTK_ID_GROUND + * switch to device: -> MTK_ID_FLOAT --> MTK_VBUS_VALID + */ +static void mtk_musb_set_mailbox(struct mtk_glue *glue, + enum mtk_vbus_id_state status) +{ + struct musb *musb = glue->musb; + u8 devctl = 0; + + dev_dbg(glue->dev, "mailbox state(%d)\n", status); + switch (status) { + case MTK_ID_GROUND: + phy_power_on(glue->phy); + devctl = readb(musb->mregs + MUSB_DEVCTL); + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; + mtk_musb_set_vbus(musb, 1); + glue->phy_mode = PHY_MODE_USB_HOST; + phy_set_mode(glue->phy, glue->phy_mode); + devctl |= MUSB_DEVCTL_SESSION; + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); + MUSB_HST_MODE(musb); + break; + /* + * MTK_ID_FLOAT process is the same as MTK_VBUS_VALID + * except that turn off VBUS + */ + case MTK_ID_FLOAT: + mtk_musb_set_vbus(musb, 0); + /* fall through */ + case MTK_VBUS_OFF: + musb->xceiv->otg->state = OTG_STATE_B_IDLE; + devctl &= ~MUSB_DEVCTL_SESSION; + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); + phy_power_off(glue->phy); + break; + case MTK_VBUS_VALID: + phy_power_on(glue->phy); + glue->phy_mode = PHY_MODE_USB_DEVICE; + phy_set_mode(glue->phy, glue->phy_mode); + MUSB_DEV_MODE(musb); + break; + default: + dev_err(glue->dev, "invalid state\n"); + } +} + +static int mtk_musb_id_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct mtk_glue *glue = container_of(nb, struct mtk_glue, id_nb); + + if (event) + mtk_musb_set_mailbox(glue, MTK_ID_GROUND); + else + mtk_musb_set_mailbox(glue, MTK_ID_FLOAT); + + return NOTIFY_DONE; +} + +static int mtk_musb_vbus_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct mtk_glue *glue = container_of(nb, struct mtk_glue, vbus_nb); + + if (event) + mtk_musb_set_mailbox(glue, MTK_VBUS_VALID); + else + mtk_musb_set_mailbox(glue, MTK_VBUS_OFF); + + return NOTIFY_DONE; +} + +static void mtk_otg_switch_init(struct mtk_glue *glue) +{ + int ret; + + /* extcon is optional */ + if (!glue->edev) + return; + + glue->vbus_nb.notifier_call = mtk_musb_vbus_notifier; + ret = devm_extcon_register_notifier(glue->dev, glue->edev, EXTCON_USB, + &glue->vbus_nb); + if (ret < 0) + dev_err(glue->dev, "failed to register notifier for USB\n"); + + glue->id_nb.notifier_call = mtk_musb_id_notifier; + ret = devm_extcon_register_notifier(glue->dev, glue->edev, + EXTCON_USB_HOST, &glue->id_nb); + if (ret < 0) + dev_err(glue->dev, "failed to register notifier for USB-HOST\n"); + + dev_dbg(glue->dev, "EXTCON_USB: %d, EXTCON_USB_HOST: %d\n", + extcon_get_state(glue->edev, EXTCON_USB), + extcon_get_state(glue->edev, EXTCON_USB_HOST)); + + /* default as host, switch to device mode if needed */ + if (extcon_get_state(glue->edev, EXTCON_USB_HOST) == false) + mtk_musb_set_mailbox(glue, MTK_ID_FLOAT); + if (extcon_get_state(glue->edev, EXTCON_USB) == true) + mtk_musb_set_mailbox(glue, MTK_VBUS_VALID); +} + +static irqreturn_t generic_interrupt(int irq, void *__hci) +{ + unsigned long flags; + irqreturn_t retval = IRQ_NONE; + struct musb *musb = __hci; + + spin_lock_irqsave(&musb->lock, flags); + musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB) & + musb_readb(musb->mregs, MUSB_INTRUSBE); + musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX) + & musb_readw(musb->mregs, MUSB_INTRTXE); + musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX) + & musb_readw(musb->mregs, MUSB_INTRRXE); + /* MediaTek controller interrupt status is W1C */ + musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx); + musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx); + musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb); + + if (musb->int_usb || musb->int_tx || musb->int_rx) + retval = musb_interrupt(musb); + + spin_unlock_irqrestore(&musb->lock, flags); + + return retval; +} + +static irqreturn_t mtk_musb_interrupt(int irq, void *dev_id) +{ + irqreturn_t retval = IRQ_NONE; + struct musb *musb = (struct musb *)dev_id; + u32 l1_ints; + + l1_ints = musb_readl(musb->mregs, USB_L1INTS) & + musb_readl(musb->mregs, USB_L1INTM); + + if (l1_ints & (TX_INT_STATUS | RX_INT_STATUS | USBCOM_INT_STATUS)) + retval = generic_interrupt(irq, musb); + +#if defined(CONFIG_USB_INVENTRA_DMA) + if (l1_ints & DMA_INT_STATUS) + retval = dma_controller_irq(irq, musb->dma_controller); +#endif + return retval; +} + +static u32 mtk_musb_busctl_offset(u8 epnum, u16 offset) +{ + return MTK_MUSB_TXFUNCADDR + offset + 8 * epnum; +} + +static int mtk_musb_init(struct musb *musb) +{ + struct device *dev = musb->controller; + struct mtk_glue *glue = dev_get_drvdata(dev->parent); + int ret; + + glue->musb = musb; + musb->phy = glue->phy; + musb->xceiv = glue->xceiv; + musb->is_host = false; + musb->isr = mtk_musb_interrupt; + ret = phy_init(glue->phy); + if (ret) + return ret; + + ret = phy_power_on(glue->phy); + if (ret) { + phy_exit(glue->phy); + return ret; + } + + phy_set_mode(glue->phy, glue->phy_mode); + +#if defined(CONFIG_USB_INVENTRA_DMA) + musb_writel(musb->mregs, MUSB_HSDMA_INTR, + DMA_INTR_STATUS_MSK | DMA_INTR_UNMASK_SET_MSK); +#endif + musb_writel(musb->mregs, USB_L1INTM, TX_INT_STATUS | RX_INT_STATUS | + USBCOM_INT_STATUS | DMA_INT_STATUS); + return 0; +} + +static int mtk_musb_set_mode(struct musb *musb, u8 mode) +{ + struct device *dev = musb->controller; + struct mtk_glue *glue = dev_get_drvdata(dev->parent); + enum phy_mode new_mode; + + switch (mode) { + case MUSB_HOST: + new_mode = PHY_MODE_USB_HOST; + mtk_musb_set_vbus(musb, 1); + break; + case MUSB_PERIPHERAL: + new_mode = PHY_MODE_USB_DEVICE; + break; + case MUSB_OTG: + new_mode = PHY_MODE_USB_HOST; + break; + default: + dev_err(musb->controller->parent, + "Error requested mode not supported by this kernel\n"); + return -EINVAL; + } + if (glue->phy_mode == new_mode) + return 0; + + mtk_musb_set_mailbox(glue, MTK_ID_GROUND); + return 0; +} + +static int mtk_musb_exit(struct musb *musb) +{ + struct device *dev = musb->controller; + struct mtk_glue *glue = dev_get_drvdata(dev->parent); + + phy_power_off(glue->phy); + phy_exit(glue->phy); + mtk_musb_clks_disable(glue); + + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); + return 0; +} + +static const struct musb_platform_ops mtk_musb_ops = { + .quirks = MUSB_DMA_INVENTRA | MUSB_MTK_QUIRKS, + .init = mtk_musb_init, + .exit = mtk_musb_exit, +#ifdef CONFIG_USB_INVENTRA_DMA + .dma_init = musbhs_dma_controller_create, + .dma_exit = musbhs_dma_controller_destroy, +#endif + .busctl_offset = mtk_musb_busctl_offset, + .set_mode = mtk_musb_set_mode, + .set_vbus = mtk_musb_set_vbus, +}; + +#define MTK_MUSB_MAX_EP_NUM 8 +#define MTK_MUSB_RAM_BITS 11 + +static struct musb_fifo_cfg mtk_musb_mode_cfg[] = { + { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, + { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, + { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, + { .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, + { .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, }, + { .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, }, + { .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, }, + { .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, }, + { .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, }, + { .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, }, + { .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 1024, }, + { .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 1024, }, + { .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 512, }, + { .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 64, }, +}; + +static const struct musb_hdrc_config mtk_musb_hdrc_config = { + .fifo_cfg = mtk_musb_mode_cfg, + .fifo_cfg_size = ARRAY_SIZE(mtk_musb_mode_cfg), + .multipoint = true, + .dyn_fifo = true, + .num_eps = MTK_MUSB_MAX_EP_NUM, + .ram_bits = MTK_MUSB_RAM_BITS, +}; + +static const struct platform_device_info mtk_dev_info = { + .name = "musb-hdrc", + .id = PLATFORM_DEVID_AUTO, + .dma_mask = DMA_BIT_MASK(32), +}; + +static int mtk_musb_probe(struct platform_device *pdev) +{ + struct musb_hdrc_platform_data *pdata; + struct mtk_glue *glue; + struct platform_device_info pinfo; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + int ret = -ENOMEM; + + glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); + if (!glue) + return -ENOMEM; + + glue->dev = dev; + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + ret = mtk_musb_clks_get(glue); + if (ret) + return ret; + + glue->vbus = devm_regulator_get(dev, "vbus"); + if (IS_ERR(glue->vbus)) { + dev_err(dev, "fail to get vbus\n"); + return PTR_ERR(glue->vbus); + } + + pdata->config = &mtk_musb_hdrc_config; + pdata->platform_ops = &mtk_musb_ops; + if (of_property_read_bool(np, "extcon")) { + glue->edev = extcon_get_edev_by_phandle(dev, 0); + if (IS_ERR(glue->edev)) { + dev_err(dev, "fail to get extcon\n"); + return PTR_ERR(glue->edev); + } + } + + pdata->mode = usb_get_dr_mode(dev); + switch (pdata->mode) { + case USB_DR_MODE_HOST: + glue->phy_mode = PHY_MODE_USB_HOST; + break; + case USB_DR_MODE_PERIPHERAL: + glue->phy_mode = PHY_MODE_USB_DEVICE; + break; + default: + pdata->mode = USB_DR_MODE_OTG; + /* FALL THROUGH */ + case USB_DR_MODE_OTG: + glue->phy_mode = PHY_MODE_USB_OTG; + break; + } + + glue->phy = devm_phy_get(dev, "usb2-phy"); + if (IS_ERR(glue->phy)) { + dev_err(dev, "fail to getting phy %ld\n", + PTR_ERR(glue->phy)); + return PTR_ERR(glue->phy); + } + + glue->usb_phy = usb_phy_generic_register(); + if (IS_ERR(glue->usb_phy)) { + dev_err(dev, "fail to registering usb-phy %ld\n", + PTR_ERR(glue->usb_phy)); + return PTR_ERR(glue->usb_phy); + } + + glue->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); + if (IS_ERR(glue->xceiv)) { + dev_err(dev, "fail to getting usb-phy %d\n", ret); + ret = PTR_ERR(glue->xceiv); + goto err_unregister_usb_phy; + } + + platform_set_drvdata(pdev, glue); + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + + ret = mtk_musb_clks_enable(glue); + if (ret) + goto err_enable_clk; + + pinfo = mtk_dev_info; + pinfo.parent = dev; + pinfo.res = pdev->resource; + pinfo.num_res = pdev->num_resources; + pinfo.data = pdata; + pinfo.size_data = sizeof(*pdata); + + glue->musb_pdev = platform_device_register_full(&pinfo); + if (IS_ERR(glue->musb_pdev)) { + ret = PTR_ERR(glue->musb_pdev); + dev_err(dev, "failed to register musb device: %d\n", ret); + goto err_device_register; + } + + if (pdata->mode == USB_DR_MODE_OTG) + mtk_otg_switch_init(glue); + + dev_info(dev, "USB probe done!\n"); + return 0; + +err_device_register: + mtk_musb_clks_disable(glue); +err_enable_clk: + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); +err_unregister_usb_phy: + usb_phy_generic_unregister(glue->usb_phy); + return ret; +} + +static int mtk_musb_remove(struct platform_device *pdev) +{ + struct mtk_glue *glue = platform_get_drvdata(pdev); + struct platform_device *usb_phy = glue->usb_phy; + + platform_device_unregister(glue->musb_pdev); + usb_phy_generic_unregister(usb_phy); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id mtk_musb_match[] = { + {.compatible = "mediatek,mtk-musb",}, + {}, +}; +MODULE_DEVICE_TABLE(of, mtk_musb_match); +#endif + +static struct platform_driver mtk_musb_driver = { + .probe = mtk_musb_probe, + .remove = mtk_musb_remove, + .driver = { + .name = "musb-mtk", + .of_match_table = of_match_ptr(mtk_musb_match), + }, +}; + +module_platform_driver(mtk_musb_driver); + +MODULE_DESCRIPTION("MediaTek MUSB Glue Layer"); +MODULE_AUTHOR("Min Guo "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index b7d5627..d60f76f 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1028,6 +1028,16 @@ static void musb_disable_interrupts(struct musb *musb) temp = musb_readb(mbase, MUSB_INTRUSB); temp = musb_readw(mbase, MUSB_INTRTX); temp = musb_readw(mbase, MUSB_INTRRX); + + /* MediaTek controller interrupt status is W1C */ + if (musb->ops->quirks & MUSB_MTK_QUIRKS) { + musb_writeb(mbase, MUSB_INTRUSB, + musb_readb(mbase, MUSB_INTRUSB)); + musb_writew(mbase, MUSB_INTRRX, + musb_readw(mbase, MUSB_INTRRX)); + musb_writew(mbase, MUSB_INTRTX, + musb_readw(mbase, MUSB_INTRTX)); + } } static void musb_enable_interrupts(struct musb *musb) diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 04203b7..1bf4e9a 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -138,6 +138,7 @@ enum musb_g_ep0_state { */ struct musb_platform_ops { +#define MUSB_MTK_QUIRKS BIT(10) #define MUSB_G_NO_SKB_RESERVE BIT(9) #define MUSB_DA8XX BIT(8) #define MUSB_PRESERVE_SESSION BIT(7) diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h index 281e75d3..b218210 100644 --- a/drivers/usb/musb/musb_dma.h +++ b/drivers/usb/musb/musb_dma.h @@ -197,6 +197,7 @@ static inline void musb_dma_controller_destroy(struct dma_controller *d) { } extern struct dma_controller * musbhs_dma_controller_create(struct musb *musb, void __iomem *base); extern void musbhs_dma_controller_destroy(struct dma_controller *c); +extern irqreturn_t dma_controller_irq(int irq, void *private_data); extern struct dma_controller * tusb_dma_controller_create(struct musb *musb, void __iomem *base); diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index b59ce9a..b1b0216 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -292,20 +292,73 @@ static inline void musb_save_toggle(struct musb_qh *qh, int is_in, { void __iomem *epio = qh->hw_ep->regs; u16 csr; + struct musb *musb = qh->hw_ep->musb; /* * FIXME: the current Mentor DMA code seems to have * problems getting toggle correct. */ - if (is_in) - csr = musb_readw(epio, MUSB_RXCSR) & MUSB_RXCSR_H_DATATOGGLE; - else - csr = musb_readw(epio, MUSB_TXCSR) & MUSB_TXCSR_H_DATATOGGLE; + /* MediaTek controller has private toggle register */ + if (musb->ops->quirks & MUSB_MTK_QUIRKS) { + u16 toggle; + u8 epnum = qh->hw_ep->epnum; + + if (is_in) + toggle = musb_readl(musb->mregs, MUSB_RXTOG); + else + toggle = musb_readl(musb->mregs, MUSB_TXTOG); + + csr = toggle & (1 << epnum); + } else { + if (is_in) + csr = musb_readw(epio, MUSB_RXCSR) + & MUSB_RXCSR_H_DATATOGGLE; + else + csr = musb_readw(epio, MUSB_TXCSR) + & MUSB_TXCSR_H_DATATOGGLE; + } usb_settoggle(urb->dev, qh->epnum, !is_in, csr ? 1 : 0); } +static inline u16 musb_set_toggle(struct musb_qh *qh, int is_in, + struct urb *urb) +{ + u16 csr = 0; + u16 toggle = 0; + struct musb *musb = qh->hw_ep->musb; + u8 epnum = qh->hw_ep->epnum; + + toggle = usb_gettoggle(urb->dev, qh->epnum, !is_in); + + /* MediaTek controller has private toggle register */ + if (musb->ops->quirks & MUSB_MTK_QUIRKS) { + if (is_in) { + musb_writel(musb->mregs, MUSB_RXTOGEN, (1 << epnum)); + musb_writel(musb->mregs, MUSB_RXTOG, (toggle << epnum)); + } else { + musb_writel(musb->mregs, MUSB_TXTOGEN, (1 << epnum)); + musb_writel(musb->mregs, MUSB_TXTOG, (toggle << epnum)); + } + } else { + if (is_in) { + if (toggle) + csr = MUSB_RXCSR_H_WR_DATATOGGLE + | MUSB_RXCSR_H_DATATOGGLE; + else + csr = 0; + } else { + if (toggle) + csr |= MUSB_TXCSR_H_WR_DATATOGGLE + | MUSB_TXCSR_H_DATATOGGLE; + else + csr |= MUSB_TXCSR_CLRDATATOG; + } + } + return csr; +} + /* * Advance this hardware endpoint's queue, completing the specified URB and * advancing to either the next URB queued to that qh, or else invalidating @@ -772,13 +825,8 @@ static void musb_ep_program(struct musb *musb, u8 epnum, ); csr |= MUSB_TXCSR_MODE; - if (!hw_ep->tx_double_buffered) { - if (usb_gettoggle(urb->dev, qh->epnum, 1)) - csr |= MUSB_TXCSR_H_WR_DATATOGGLE - | MUSB_TXCSR_H_DATATOGGLE; - else - csr |= MUSB_TXCSR_CLRDATATOG; - } + if (!hw_ep->tx_double_buffered) + csr |= musb_set_toggle(qh, !is_out, urb); musb_writew(epio, MUSB_TXCSR, csr); /* REVISIT may need to clear FLUSHFIFO ... */ @@ -860,17 +908,12 @@ static void musb_ep_program(struct musb *musb, u8 epnum, /* IN/receive */ } else { - u16 csr; + u16 csr = 0; if (hw_ep->rx_reinit) { musb_rx_reinit(musb, qh, epnum); + csr |= musb_set_toggle(qh, !is_out, urb); - /* init new state: toggle and NYET, maybe DMA later */ - if (usb_gettoggle(urb->dev, qh->epnum, 0)) - csr = MUSB_RXCSR_H_WR_DATATOGGLE - | MUSB_RXCSR_H_DATATOGGLE; - else - csr = 0; if (qh->type == USB_ENDPOINT_XFER_INT) csr |= MUSB_RXCSR_DISNYET; diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h index 5cd7264..ffbe267 100644 --- a/drivers/usb/musb/musb_regs.h +++ b/drivers/usb/musb/musb_regs.h @@ -273,6 +273,12 @@ #define MUSB_RXHUBADDR 0x06 #define MUSB_RXHUBPORT 0x07 +/* MediaTek controller toggle enable and status reg */ +#define MUSB_RXTOG 0x80 +#define MUSB_RXTOGEN 0x82 +#define MUSB_TXTOG 0x84 +#define MUSB_TXTOGEN 0x86 + static inline u8 musb_read_configdata(void __iomem *mbase) { musb_writeb(mbase, MUSB_INDEX, 0); diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index 824adcb..c545475 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -263,7 +263,7 @@ static int dma_channel_abort(struct dma_channel *channel) return 0; } -static irqreturn_t dma_controller_irq(int irq, void *private_data) +irqreturn_t dma_controller_irq(int irq, void *private_data) { struct musb_dma_controller *controller = private_data; struct musb *musb = controller->private_data; @@ -285,6 +285,8 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data) spin_lock_irqsave(&musb->lock, flags); int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR); + if (musb->ops->quirks & MUSB_MTK_QUIRKS) + musb_writeb(musb->mregs, MUSB_HSDMA_INTR, int_hsdma); if (!int_hsdma) { musb_dbg(musb, "spurious DMA irq"); @@ -377,15 +379,17 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data) spin_unlock_irqrestore(&musb->lock, flags); return retval; } +EXPORT_SYMBOL_GPL(dma_controller_irq); void musbhs_dma_controller_destroy(struct dma_controller *c) { struct musb_dma_controller *controller = container_of(c, struct musb_dma_controller, controller); + struct musb *musb = controller->private_data; dma_controller_stop(controller); - if (controller->irq) + if (!(musb->ops->quirks & MUSB_MTK_QUIRKS) && controller->irq) free_irq(controller->irq, c); kfree(controller); @@ -398,11 +402,15 @@ struct dma_controller *musbhs_dma_controller_create(struct musb *musb, struct musb_dma_controller *controller; struct device *dev = musb->controller; struct platform_device *pdev = to_platform_device(dev); - int irq = platform_get_irq_byname(pdev, "dma"); + int irq = -1; - if (irq <= 0) { - dev_err(dev, "No DMA interrupt line!\n"); - return NULL; + if (!(musb->ops->quirks & MUSB_MTK_QUIRKS)) { + irq = platform_get_irq_byname(pdev, "dma"); + + if (irq < 0) { + dev_err(dev, "No DMA interrupt line!\n"); + return NULL; + } } controller = kzalloc(sizeof(*controller), GFP_KERNEL); @@ -418,15 +426,17 @@ struct dma_controller *musbhs_dma_controller_create(struct musb *musb, controller->controller.channel_program = dma_channel_program; controller->controller.channel_abort = dma_channel_abort; - if (request_irq(irq, dma_controller_irq, 0, + if (!(musb->ops->quirks & MUSB_MTK_QUIRKS)) { + if (request_irq(irq, dma_controller_irq, 0, dev_name(musb->controller), &controller->controller)) { - dev_err(dev, "request_irq %d failed!\n", irq); - musb_dma_controller_destroy(&controller->controller); + dev_err(dev, "request_irq %d failed!\n", irq); + musb_dma_controller_destroy(&controller->controller); - return NULL; - } + return NULL; + } - controller->irq = irq; + controller->irq = irq; + } return &controller->controller; }