Received: by 2002:a25:e7d8:0:0:0:0:0 with SMTP id e207csp478063ybh; Wed, 18 Mar 2020 03:33:43 -0700 (PDT) X-Google-Smtp-Source: ADFU+vvJjx39+bqiYjTGmhd6ygmqtZP4dlZqMOKvV2xEmmPzM43Hpv324Lm2GJAuNpEGQTW5J1yh X-Received: by 2002:a9d:1eea:: with SMTP id n97mr3343164otn.139.1584527623332; Wed, 18 Mar 2020 03:33:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1584527623; cv=none; d=google.com; s=arc-20160816; b=vmYMEW3fZ+1zJNu4OvrH7vTfTXO/UrxIfeObCj39Lf3TgFgbGlwyWNLjT2GBOZAvYY 2p6ep6aax/s1P8brlWokWP9l5tMOg+OBTnFqE61ZfTlLMLf+iGBZ5XIiEdd+6ly3u3DO ye5BQl+PBPk/6TbZrwedW/6dDIULemekdgGwA8eZS/kWn90zNHyKQSszzBUStjMXb0GI nVgufdTyJfs0KyD+KHtdXNb8ihC1bsWYoIrZm37KtVUtKlenJsymfQeZCJmGClyVPZGd Q2yG3/76EJ9bk+k+3+cpv7dS/QoWeJCDuHYmRdhV46SQ+X5rDvaC0IM6GmKB611NyXqD nl5g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:dkim-signature:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from; bh=tEoOEHoqSMKBOPIlCwlXMu5sLKIef0sdU0dEXS+YRvg=; b=SgHKLYpnsfbhF/ZU1VCDPT0Dqg1Uuaoh7KBJy6gRkUBYZ0jmRGIG3vlat61nJtZTvY /ikrXFtfkvmIpdKAcsuFHCt8ClssOnHYaQmzYaaOyFzcH3X1NDucuDnkglEXr0Ygx7y+ 0wOeg4HW8s85jc5OFZUCT8iwNZhqvF+yYe9WhS2Qf0Vgrd9pUv119/is1Ec5cVKCpx0W 7ppaz4Mldn6W2vYz9icQE0TiT8cwvqQsy+DWhB54AZa4+9SQsUH3BhkZYLH2I+8nLtWX bgdr40nTM9Px8ovCPkSO1WE0lCXu2CzMk4gvloUkPKBCx++SopoFhM6H1J2EQNhwpt42 grIg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nvidia.com header.s=n1 header.b=A9PR2Pje; 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=nvidia.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m16si3136439otr.173.2020.03.18.03.33.25; Wed, 18 Mar 2020 03:33:43 -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=@nvidia.com header.s=n1 header.b=A9PR2Pje; 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=nvidia.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727825AbgCRKb5 (ORCPT + 99 others); Wed, 18 Mar 2020 06:31:57 -0400 Received: from hqnvemgate26.nvidia.com ([216.228.121.65]:7086 "EHLO hqnvemgate26.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727800AbgCRKby (ORCPT ); Wed, 18 Mar 2020 06:31:54 -0400 Received: from hqpgpgate101.nvidia.com (Not Verified[216.228.121.13]) by hqnvemgate26.nvidia.com (using TLS: TLSv1.2, DES-CBC3-SHA) id ; Wed, 18 Mar 2020 03:31:40 -0700 Received: from hqmail.nvidia.com ([172.20.161.6]) by hqpgpgate101.nvidia.com (PGP Universal service); Wed, 18 Mar 2020 03:31:53 -0700 X-PGP-Universal: processed; by hqpgpgate101.nvidia.com on Wed, 18 Mar 2020 03:31:53 -0700 Received: from HQMAIL111.nvidia.com (172.20.187.18) by HQMAIL111.nvidia.com (172.20.187.18) with Microsoft SMTP Server (TLS) id 15.0.1473.3; Wed, 18 Mar 2020 10:31:53 +0000 Received: from rnnvemgw01.nvidia.com (10.128.109.123) by HQMAIL111.nvidia.com (172.20.187.18) with Microsoft SMTP Server (TLS) id 15.0.1473.3 via Frontend Transport; Wed, 18 Mar 2020 10:31:53 +0000 Received: from nkristam-ubuntu.nvidia.com (Not Verified[10.19.67.128]) by rnnvemgw01.nvidia.com with Trustwave SEG (v7,5,8,10121) id ; Wed, 18 Mar 2020 03:31:52 -0700 From: Nagarjuna Kristam To: , , , , , CC: , , , , , Nagarjuna Kristam Subject: [PATCH V1 4/8] phy: tegra: xusb: Add USB2 pad power control support for Tegra210 Date: Wed, 18 Mar 2020 16:01:03 +0530 Message-ID: <1584527467-8058-5-git-send-email-nkristam@nvidia.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1584527467-8058-1-git-send-email-nkristam@nvidia.com> References: <1584527467-8058-1-git-send-email-nkristam@nvidia.com> X-NVConfidentiality: public MIME-Version: 1.0 Content-Type: text/plain DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1; t=1584527500; bh=tEoOEHoqSMKBOPIlCwlXMu5sLKIef0sdU0dEXS+YRvg=; h=X-PGP-Universal:From:To:CC:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:X-NVConfidentiality:MIME-Version: Content-Type; b=A9PR2Pjeeyv/r9rWLuSqTaDvorDmCFD2jUFnDPbUSnWFd+UsoZT2Xn/TOJny7iMkz wRR0o8RO+VKKWMcNyPu5imyXKs6JS48BI6YggMwhpIn4DlTZ1CAZu+uKO279Vx61SV cCGKWUWAHUsGLg+tHuWmgmG5h3D+YxpOV6OLfR/nVOt9Pe3RJpQeA+AmelWhvxc1D0 e1zS92w0DqaDh2PG5NjdY2ZN4YPDO61VCltCjQrPzjb4JyfTlL1EDwqpr9Gt1B6Lvl B5qyBJQKkpI0rBP1xU5aIwqjkvKR/GedRgDwsfeI+hYMeR5+6QvGcJ/cHOr3LAf9bA xjE7NiJ2AMoKA== Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add USB2 pad power on and off API's for TEgra210 and provide its control via soc ops. It can be used by operations like charger detect to power on and off USB2 pad if needed. Signed-off-by: Nagarjuna Kristam --- drivers/phy/tegra/xusb-tegra210.c | 190 ++++++++++++++++++++++++++------------ 1 file changed, 133 insertions(+), 57 deletions(-) diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c index 54d6826..0841564 100644 --- a/drivers/phy/tegra/xusb-tegra210.c +++ b/drivers/phy/tegra/xusb-tegra210.c @@ -994,6 +994,128 @@ static int tegra210_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl, return 0; } +static void tegra210_usb2_bias_pad_power_on(struct tegra_xusb_usb2_pad *pad) +{ + struct tegra_xusb_padctl *padctl = pad->base.padctl; + u32 value; + + if (pad->enable++ > 0) + return; + + dev_dbg(padctl->dev, "power on BIAS PAD & USB2 tracking\n"); + + if (clk_prepare_enable(pad->clk)) + dev_warn(padctl->dev, "failed to enable BIAS PAD & USB2 tracking\n"); + + value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); + value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK << + XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT) | + (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_MASK << + XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT)); + value |= (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL << + XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT) | + (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_VAL << + XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT); + padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); + + value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); + value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD; + padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); + + udelay(1); + + value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); + value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL1_PD_TRK; + padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); + + udelay(50); +} + +static void tegra210_usb2_bias_pad_power_off(struct tegra_xusb_usb2_pad *pad) +{ + struct tegra_xusb_padctl *padctl = pad->base.padctl; + u32 value; + + if (WARN_ON(pad->enable == 0)) + return; + + if (--pad->enable > 0) + return; + + dev_dbg(padctl->dev, "power off USB2 tracking\n"); + + value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); + value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD; + padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); + + clk_disable_unprepare(pad->clk); +} + +/* must be called under padctl->lock */ +void tegra210_usb2_pad_power_on(struct phy *phy) +{ + struct tegra_xusb_lane *lane = phy_get_drvdata(phy); + struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane); + struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad); + struct tegra_xusb_padctl *padctl = lane->pad->padctl; + unsigned int index = lane->index; + u32 value; + + if (!phy) + return; + + if (usb2->powered_on) + return; + + dev_info(padctl->dev, "power on UTMI pads %d\n", index); + + tegra210_usb2_bias_pad_power_on(pad); + + udelay(2); + + value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); + value &= ~XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD; + padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); + + value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); + value &= ~XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR; + padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); + + usb2->powered_on = true; +} + +/* must be called under padctl->lock */ +void tegra210_usb2_pad_power_down(struct phy *phy) +{ + struct tegra_xusb_lane *lane = phy_get_drvdata(phy); + struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane); + struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad); + struct tegra_xusb_padctl *padctl = lane->pad->padctl; + unsigned int index = lane->index; + u32 value; + + if (!phy) + return; + + if (!usb2->powered_on) + return; + + dev_info(padctl->dev, "power down UTMI pad %d\n", index); + + value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); + value |= XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD; + padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); + + value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); + value |= XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR; + padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); + + udelay(2); + + tegra210_usb2_bias_pad_power_off(pad); + usb2->powered_on = false; +} + static int tegra210_usb2_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) { @@ -1037,7 +1159,6 @@ static int tegra210_usb2_phy_power_on(struct phy *phy) { struct tegra_xusb_lane *lane = phy_get_drvdata(phy); struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane); - struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad); struct tegra_xusb_padctl *padctl = lane->pad->padctl; struct tegra210_xusb_padctl *priv; struct tegra_xusb_usb2_port *port; @@ -1053,6 +1174,8 @@ static int tegra210_usb2_phy_power_on(struct phy *phy) priv = to_tegra210_xusb_padctl(padctl); + mutex_lock(&padctl->lock); + if (port->usb3_port_fake != -1) { value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK( @@ -1148,62 +1271,21 @@ static int tegra210_usb2_phy_power_on(struct phy *phy) if (port->supply && port->mode == USB_DR_MODE_HOST) { err = regulator_enable(port->supply); - if (err) + if (err) { + mutex_unlock(&padctl->lock); return err; + } } - mutex_lock(&padctl->lock); - - if (pad->enable > 0) { - pad->enable++; - mutex_unlock(&padctl->lock); - return 0; - } - - err = clk_prepare_enable(pad->clk); - if (err) - goto disable_regulator; + tegra210_usb2_pad_power_on(phy); - value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); - value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK << - XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT) | - (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_MASK << - XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT)); - value |= (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL << - XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT) | - (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_VAL << - XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT); - padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); - - value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); - value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD; - padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); - - udelay(1); - - value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); - value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL1_PD_TRK; - padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); - - udelay(50); - - clk_disable_unprepare(pad->clk); - - pad->enable++; mutex_unlock(&padctl->lock); - return 0; - -disable_regulator: - regulator_disable(port->supply); - mutex_unlock(&padctl->lock); - return err; } static int tegra210_usb2_phy_power_off(struct phy *phy) { struct tegra_xusb_lane *lane = phy_get_drvdata(phy); - struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad); struct tegra_xusb_padctl *padctl = lane->pad->padctl; struct tegra_xusb_usb2_port *port; u32 value; @@ -1217,6 +1299,8 @@ static int tegra210_usb2_phy_power_off(struct phy *phy) mutex_lock(&padctl->lock); + tegra210_usb2_pad_power_down(phy); + if (port->usb3_port_fake != -1) { value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY( @@ -1243,18 +1327,8 @@ static int tegra210_usb2_phy_power_off(struct phy *phy) padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP); } - if (WARN_ON(pad->enable == 0)) - goto out; - - if (--pad->enable > 0) - goto out; - - value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); - value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD; - padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); - -out: regulator_disable(port->supply); + mutex_unlock(&padctl->lock); return 0; } @@ -2210,6 +2284,8 @@ static const struct tegra_xusb_padctl_ops tegra210_xusb_padctl_ops = { .hsic_set_idle = tegra210_hsic_set_idle, .vbus_override = tegra210_xusb_padctl_vbus_override, .utmi_port_reset = tegra210_utmi_port_reset, + .utmi_pad_power_on = tegra210_usb2_pad_power_on, + .utmi_pad_power_down = tegra210_usb2_pad_power_down, }; static const char * const tegra210_xusb_padctl_supply_names[] = { -- 2.7.4