From patchwork Thu Mar 17 02:26:37 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lechner X-Patchwork-Id: 8606991 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 388939F6E1 for ; Thu, 17 Mar 2016 03:48:32 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id DF7732026F for ; Thu, 17 Mar 2016 03:48:30 +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 9EAD62026C for ; Thu, 17 Mar 2016 03:48:29 +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 1agOs0-0000wH-Kn; Thu, 17 Mar 2016 03:45:08 +0000 Received: from [50.115.127.205] (helo=vern.gendns.com) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1agOqT-0007cc-3V for linux-arm-kernel@lists.infradead.org; Thu, 17 Mar 2016 03:43:49 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lechnology.com; s=default; h=References:In-Reply-To:Message-Id:Date:Subject :Cc:To:From; bh=Gnr77KQf0Ow2n9L98niiZFJ1QQxKdxEJQOTbWPtvXyc=; b=oq1ghBlGP7j01 +cPDZtdgTgMHdeR2Jca5zeOsJvlNnZTs98QrQnns7tRYYu9aO/N2gkm+BplADMo0mQHodBk+r0/VQ Xipa8wX8fQKGC30bL9ce1uPhWHvtutC4kBVViS2Q44H67NPat2RtLuYVRvq18Ou354So+r0QVxfBx QXfjLBDNwjOi6ZLYNe1XMpAda8mQBpSFIAS4eU2KYaFtjPcR5zS8z9a1JJo0L+UU2suTJyaGCT9hl 63f0MqPl4gTeS5rM9u/puvrhsmdFFqr5d1KODEFZ6XrFr/sieoV59/YwUOaowjLrQvrdIX8yOmBl2 idwWbND94snFHk4XjzJRA==; Received: from 108-198-5-147.lightspeed.okcbok.sbcglobal.net ([108.198.5.147]:51099 helo=freyr.lechnology.com) by vern.gendns.com with esmtpsa (TLSv1.2:ECDHE-RSA-AES128-SHA256:128) (Exim 4.86_1) (envelope-from ) id 1agNgE-003yue-Og; Wed, 16 Mar 2016 22:28:54 -0400 From: David Lechner To: Subject: [PATCH v2 04/11] ARM: davinci: da8xx: add usb phy clocks Date: Wed, 16 Mar 2016 21:26:37 -0500 Message-Id: <1458181615-27782-5-git-send-email-david@lechnology.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1458181615-27782-1-git-send-email-david@lechnology.com> References: <1458181615-27782-1-git-send-email-david@lechnology.com> X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - vern.gendns.com X-AntiAbuse: Original Domain - lists.infradead.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - lechnology.com X-Get-Message-Sender-Via: vern.gendns.com: authenticated_id: davidmain+lechnology.com/only user confirmed/virtual account not confirmed X-Authenticated-Sender: vern.gendns.com: davidmain@lechnology.com X-Source: X-Source-Args: X-Source-Dir: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160316_204333_961237_97B2C056 X-CRM114-Status: GOOD ( 16.79 ) X-Spam-Score: -0.5 (/) 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: Mark Rutland , Tony Lindgren , Sekhar Nori , Robert Jarzmik , Russell King , Kevin Hilman , Kishon Vijay Abraham I , Alan Stern , devicetree@vger.kernel.org, David Lechner , Pawel Moll , Ian Campbell , Rob Herring , Bin Liu , linux-arm-kernel@lists.infradead.org, Sergei Shtylyov , Greg Kroah-Hartman , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Petr Kulhavy , Kumar Gala , =?UTF-8?q?Andreas=20F=C3=A4rber?= MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,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 Up to this point, the USB phy clock configuration was handled manually in the board files and in the usb drivers. This adds proper clocks so that the usb drivers can use clk_get and clk_enable and not have to worry about the details. Also, the related code is removed from the board files. Signed-off-by: David Lechner --- v2 changes: Move clock mux code to set_parent callback. Also fixed some other issues from feedback on the previous patch. arch/arm/mach-davinci/board-da830-evm.c | 12 --- arch/arm/mach-davinci/board-omapl138-hawk.c | 7 -- arch/arm/mach-davinci/da830.c | 143 ++++++++++++++++++++++++++++ arch/arm/mach-davinci/da850.c | 143 ++++++++++++++++++++++++++++ 4 files changed, 286 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index 3d8cf8c..f3a8cc9 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -115,18 +115,6 @@ static __init void da830_evm_usb_init(void) */ cfgchip2 = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); - /* USB2.0 PHY reference clock is 24 MHz */ - cfgchip2 &= ~CFGCHIP2_REFFREQ; - cfgchip2 |= CFGCHIP2_REFFREQ_24MHZ; - - /* - * Select internal reference clock for USB 2.0 PHY - * and use it as a clock source for USB 1.1 PHY - * (this is the default setting anyway). - */ - cfgchip2 &= ~CFGCHIP2_USB1PHYCLKMUX; - cfgchip2 |= CFGCHIP2_USB2PHYCLKMUX; - /* * We have to override VBUS/ID signals when MUSB is configured into the * host-only mode -- ID pin will float if no cable is connected, so the diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c index ee62486..d27e753 100644 --- a/arch/arm/mach-davinci/board-omapl138-hawk.c +++ b/arch/arm/mach-davinci/board-omapl138-hawk.c @@ -251,13 +251,6 @@ static __init void omapl138_hawk_usb_init(void) return; } - /* Setup the Ref. clock frequency for the HAWK at 24 MHz. */ - - cfgchip2 = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); - cfgchip2 &= ~CFGCHIP2_REFFREQ; - cfgchip2 |= CFGCHIP2_REFFREQ_24MHZ; - __raw_writel(cfgchip2, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); - ret = gpio_request_one(DA850_USB1_VBUS_PIN, GPIOF_DIR_OUT, "USB1 VBUS"); if (ret < 0) { diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c index 7187e7f..ee942b0 100644 --- a/arch/arm/mach-davinci/da830.c +++ b/arch/arm/mach-davinci/da830.c @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -346,6 +347,12 @@ static struct clk i2c1_clk = { .gpsc = 1, }; +static struct clk usb_ref_clk = { + .name = "usb_ref_clk", + .rate = 48000000, + .set_rate = davinci_simple_set_rate, +}; + static struct clk usb11_clk = { .name = "usb11", .parent = &pll0_sysclk4, @@ -353,6 +360,139 @@ static struct clk usb11_clk = { .gpsc = 1, }; +static void usb20_phy_clk_enable(struct clk *clk) +{ + u32 val; + + val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); + + /* + * Turn on the USB 2.0 PHY, but just the PLL, and not OTG. The USB 1.1 + * host may use the PLL clock without USB 2.0 OTG being used. + */ + val &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN); + val |= CFGCHIP2_PHY_PLLON; + + writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); + + pr_info("Waiting for USB 2.0 PHY clock good...\n"); + while (!(readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)) + & CFGCHIP2_PHYCLKGD)) + cpu_relax(); +} + +static void usb20_phy_clk_disable(struct clk *clk) +{ + u32 val; + + val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); + val |= CFGCHIP2_PHYPWRDN; + writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); +} + +static int usb20_phy_clk_set_parent(struct clk *clk, struct clk *parent) +{ + u32 __iomem *cfgchip2; + u32 val; + + /* + * Can't use DA8XX_SYSCFG0_VIRT() here since this can be called before + * da8xx_syscfg0_base is initialized. + */ + cfgchip2 = ioremap(DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP2_REG, 4); + val = readl(cfgchip2); + + /* Set the mux depending on the parent clock. */ + if (parent == &pll0_aux_clk) + val |= CFGCHIP2_USB2PHYCLKMUX; + else if (parent == &usb_ref_clk) + val &= ~CFGCHIP2_USB2PHYCLKMUX; + else { + pr_err("Bad parent on USB 2.0 PHY clock.\n"); + return -EINVAL; + } + + /* reference frequency also comes from parent clock */ + val &= ~CFGCHIP2_REFFREQ; + switch (clk_get_rate(parent)) { + case 12000000: + val |= CFGCHIP2_REFFREQ_12MHZ; + break; + case 13000000: + val |= CFGCHIP2_REFFREQ_13MHZ; + break; + case 19200000: + val |= CFGCHIP2_REFFREQ_19_2MHZ; + break; + case 20000000: + val |= CFGCHIP2_REFFREQ_20MHZ; + break; + case 24000000: + val |= CFGCHIP2_REFFREQ_24MHZ; + break; + case 26000000: + val |= CFGCHIP2_REFFREQ_26MHZ; + break; + case 38400000: + val |= CFGCHIP2_REFFREQ_38_4MHZ; + break; + case 40000000: + val |= CFGCHIP2_REFFREQ_40MHZ; + break; + case 48000000: + val |= CFGCHIP2_REFFREQ_48MHZ; + break; + default: + pr_err("Bad parent clock rate on USB 2.0 PHY clock.\n"); + return -EINVAL; + } + + writel(val, cfgchip2); + + return 0; +} + +static struct clk usb20_phy_clk = { + .name = "usb20_phy", + .parent = &pll0_aux_clk, + .clk_enable = usb20_phy_clk_enable, + .clk_disable = usb20_phy_clk_disable, + .set_parent = usb20_phy_clk_set_parent, +}; + +static int usb11_phy_clk_set_parent(struct clk *clk, struct clk *parent) +{ + u32 __iomem *cfgchip2; + u32 val; + + /* + * Can't use DA8XX_SYSCFG0_VIRT() here since this can be called before + * da8xx_syscfg0_base is initialized. + */ + cfgchip2 = ioremap(DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP2_REG, 4); + val = readl(cfgchip2); + + /* Set the USB 1.1 PHY clock mux based on the parent clock. */ + if (parent == &usb20_phy_clk) + val &= ~CFGCHIP2_USB1PHYCLKMUX; + else if (parent == &usb_ref_clk) + val |= CFGCHIP2_USB1PHYCLKMUX; + else { + pr_err("Bad parent on USB 1.1 PHY clock.\n"); + return -EINVAL; + } + + writel(val, cfgchip2); + + return 0; +} + +static struct clk usb11_phy_clk = { + .name = "usb11_phy", + .parent = &usb20_phy_clk, + .set_parent = usb11_phy_clk_set_parent, +}; + static struct clk emif3_clk = { .name = "emif3", .parent = &pll0_sysclk5, @@ -420,7 +560,10 @@ static struct clk_lookup da830_clks[] = { CLK("davinci_mdio.0", "fck", &emac_clk), CLK(NULL, "gpio", &gpio_clk), CLK("i2c_davinci.2", NULL, &i2c1_clk), + CLK(NULL, "usb_ref_clk", &usb_ref_clk), CLK(NULL, "usb11", &usb11_clk), + CLK(NULL, "usb20_phy", &usb20_phy_clk), + CLK(NULL, "usb11_phy", &usb11_phy_clk), CLK(NULL, "emif3", &emif3_clk), CLK(NULL, "arm", &arm_clk), CLK(NULL, "rmii", &rmii_clk), diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 8c8f31e..8089a82 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -360,6 +361,12 @@ static struct clk aemif_clk = { .flags = ALWAYS_ENABLED, }; +static struct clk usb_ref_clk = { + .name = "usb_ref_clk", + .rate = 48000000, + .set_rate = davinci_simple_set_rate, +}; + static struct clk usb11_clk = { .name = "usb11", .parent = &pll0_sysclk4, @@ -374,6 +381,139 @@ static struct clk usb20_clk = { .gpsc = 1, }; +static void usb20_phy_clk_enable(struct clk *clk) +{ + u32 val; + + val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); + + /* + * Turn on the USB 2.0 PHY, but just the PLL, and not OTG. The USB 1.1 + * host may use the PLL clock without USB 2.0 OTG being used. + */ + val &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN); + val |= CFGCHIP2_PHY_PLLON; + + writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); + + pr_info("Waiting for USB 2.0 PHY clock good...\n"); + while (!(readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)) + & CFGCHIP2_PHYCLKGD)) + cpu_relax(); +} + +static void usb20_phy_clk_disable(struct clk *clk) +{ + u32 val; + + val = readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); + val |= CFGCHIP2_PHYPWRDN; + writel(val, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)); +} + +static int usb20_phy_clk_set_parent(struct clk *clk, struct clk *parent) +{ + u32 __iomem *cfgchip2; + u32 val; + + /* + * Can't use DA8XX_SYSCFG0_VIRT() here since this can be called before + * da8xx_syscfg0_base is initialized. + */ + cfgchip2 = ioremap(DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP2_REG, 4); + val = readl(cfgchip2); + + /* Set the mux depending on the parent clock. */ + if (parent == &pll0_aux_clk) + val |= CFGCHIP2_USB2PHYCLKMUX; + else if (parent == &usb_ref_clk) + val &= ~CFGCHIP2_USB2PHYCLKMUX; + else { + pr_err("Bad parent on USB 2.0 PHY clock.\n"); + return -EINVAL; + } + + /* reference frequency also comes from parent clock */ + val &= ~CFGCHIP2_REFFREQ; + switch (clk_get_rate(parent)) { + case 12000000: + val |= CFGCHIP2_REFFREQ_12MHZ; + break; + case 13000000: + val |= CFGCHIP2_REFFREQ_13MHZ; + break; + case 19200000: + val |= CFGCHIP2_REFFREQ_19_2MHZ; + break; + case 20000000: + val |= CFGCHIP2_REFFREQ_20MHZ; + break; + case 24000000: + val |= CFGCHIP2_REFFREQ_24MHZ; + break; + case 26000000: + val |= CFGCHIP2_REFFREQ_26MHZ; + break; + case 38400000: + val |= CFGCHIP2_REFFREQ_38_4MHZ; + break; + case 40000000: + val |= CFGCHIP2_REFFREQ_40MHZ; + break; + case 48000000: + val |= CFGCHIP2_REFFREQ_48MHZ; + break; + default: + pr_err("Bad parent clock rate on USB 2.0 PHY clock.\n"); + return -EINVAL; + } + + writel(val, cfgchip2); + + return 0; +} + +static struct clk usb20_phy_clk = { + .name = "usb20_phy", + .parent = &pll0_aux_clk, + .clk_enable = usb20_phy_clk_enable, + .clk_disable = usb20_phy_clk_disable, + .set_parent = usb20_phy_clk_set_parent, +}; + +static int usb11_phy_clk_set_parent(struct clk *clk, struct clk *parent) +{ + u32 __iomem *cfgchip2; + u32 val; + + /* + * Can't use DA8XX_SYSCFG0_VIRT() here since this can be called before + * da8xx_syscfg0_base is initialized. + */ + cfgchip2 = ioremap(DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP2_REG, 4); + val = readl(cfgchip2); + + /* Set the USB 1.1 PHY clock mux based on the parent clock. */ + if (parent == &usb20_phy_clk) + val &= ~CFGCHIP2_USB1PHYCLKMUX; + else if (parent == &usb_ref_clk) + val |= CFGCHIP2_USB1PHYCLKMUX; + else { + pr_err("Bad parent on USB 1.1 PHY clock.\n"); + return -EINVAL; + } + + writel(val, cfgchip2); + + return 0; +} + +static struct clk usb11_phy_clk = { + .name = "usb11_phy", + .parent = &usb20_phy_clk, + .set_parent = usb11_phy_clk_set_parent, +}; + static struct clk spi0_clk = { .name = "spi0", .parent = &pll0_sysclk2, @@ -493,8 +633,11 @@ static struct clk_lookup da850_clks[] = { CLK("da830-mmc.0", NULL, &mmcsd0_clk), CLK("da830-mmc.1", NULL, &mmcsd1_clk), CLK(NULL, "aemif", &aemif_clk), + CLK(NULL, "usb_ref_clk", &usb_ref_clk), CLK(NULL, "usb11", &usb11_clk), CLK(NULL, "usb20", &usb20_clk), + CLK(NULL, "usb20_phy", &usb20_phy_clk), + CLK(NULL, "usb11_phy", &usb11_phy_clk), CLK("spi_davinci.0", NULL, &spi0_clk), CLK("spi_davinci.1", NULL, &spi1_clk), CLK("vpif", NULL, &vpif_clk),