Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/phy/tegra/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 100 kB image not shown  

Quelle  xusb-tegra210.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2014-2020, NVIDIA CORPORATION.  All rights reserved.
 * Copyright (C) 2015 Google, Inc.
 */


#include <linux/clk.h>
#include <linux/clk/tegra.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/mailbox_client.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>

#include <soc/tegra/fuse.h>

#include "xusb.h"

#define FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(x) \
     ((x) ? (11 + ((x) - 1) * 6) : 0)
#define FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK 0x3f
#define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT 7
#define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK 0xf

#define FUSE_USB_CALIB_EXT_RPD_CTRL_SHIFT 0
#define FUSE_USB_CALIB_EXT_RPD_CTRL_MASK 0x1f

#define XUSB_PADCTL_USB2_PAD_MUX 0x004
#define XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT 16
#define XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_MASK 0x3
#define XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_XUSB 0x1
#define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT 18
#define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK 0x3
#define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB 0x1

#define XUSB_PADCTL_USB2_PORT_CAP 0x008
#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DISABLED(x) (0x0 << ((x) * 4))
#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(x) (0x1 << ((x) * 4))
#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DEVICE(x) (0x2 << ((x) * 4))
#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_OTG(x) (0x3 << ((x) * 4))
#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(x) (0x3 << ((x) * 4))

#define XUSB_PADCTL_SS_PORT_MAP 0x014
#define XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(x) (1 << (((x) * 5) + 4))
#define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_SHIFT(x) ((x) * 5)
#define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(x) (0x7 << ((x) * 5))
#define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(x, v) (((v) & 0x7) << ((x) * 5))
#define XUSB_PADCTL_SS_PORT_MAP_PORT_DISABLED 0x7

#define XUSB_PADCTL_ELPG_PROGRAM_0 0x20
#define   USB2_PORT_WAKE_INTERRUPT_ENABLE(x)      BIT((x))
#define   USB2_PORT_WAKEUP_EVENT(x)               BIT((x) + 7)
#define   SS_PORT_WAKE_INTERRUPT_ENABLE(x)        BIT((x) + 14)
#define   SS_PORT_WAKEUP_EVENT(x)                 BIT((x) + 21)
#define   USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 28)
#define   USB2_HSIC_PORT_WAKEUP_EVENT(x)          BIT((x) + 30)
#define   ALL_WAKE_EVENTS ( \
  USB2_PORT_WAKEUP_EVENT(0) | USB2_PORT_WAKEUP_EVENT(1) | \
  USB2_PORT_WAKEUP_EVENT(2) | USB2_PORT_WAKEUP_EVENT(3) | \
  SS_PORT_WAKEUP_EVENT(0) | SS_PORT_WAKEUP_EVENT(1) | \
  SS_PORT_WAKEUP_EVENT(2) | SS_PORT_WAKEUP_EVENT(3) | \
  USB2_HSIC_PORT_WAKEUP_EVENT(0))

#define XUSB_PADCTL_ELPG_PROGRAM1 0x024
#define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN (1 << 31)
#define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 30)
#define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN (1 << 29)
#define XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(x) (1 << (2 + (x) * 3))
#define XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(x) \
       (1 << (1 + (x) * 3))
#define XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(x) (1 << ((x) * 3))

#define XUSB_PADCTL_USB3_PAD_MUX 0x028
#define XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(x) (1 << (1 + (x)))
#define XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(x) (1 << (8 + (x)))

#define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL0(x) (0x080 + (x) * 0x40)
#define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIP (1 << 18)
#define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIN (1 << 22)

#define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(x) (0x084 + (x) * 0x40)
#define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT 7
#define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_MASK 0x3
#define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_VAL 0x1
#define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18 (1 << 6)

#define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x088 + (x) * 0x40)
#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI (1 << 29)
#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 (1 << 27)
#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD (1 << 26)
#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT 0
#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK 0x3f

#define XUSB_PADCTL_USB2_OTG_PADX_CTL1(x) (0x08c + (x) * 0x40)
#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT 26
#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_MASK 0x1f
#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT 3
#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK 0xf
#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2)
#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD (1 << 1)
#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD (1 << 0)
#define   RPD_CTRL(x)                      (((x) & 0x1f) << 26)
#define   RPD_CTRL_VALUE(x)                (((x) >> 26) & 0x1f)

#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x284
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 11)
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT 3
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK 0x7
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL 0x7
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT 0
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK 0x7
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_VAL 0x2

#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1 0x288
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_PD_TRK (1 << 26)
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT 19
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_MASK 0x7f
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_VAL 0x0a
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT 12
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK 0x7f
#define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL 0x1e
#define   TCTRL_VALUE(x)                (((x) & 0x3f) >> 0)
#define   PCTRL_VALUE(x)                (((x) >> 6) & 0x3f)

#define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x300 + (x) * 0x20)
#define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE (1 << 18)
#define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA1 (1 << 17)
#define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA0 (1 << 16)
#define XUSB_PADCTL_HSIC_PAD_CTL0_RPD_STROBE (1 << 15)
#define XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 (1 << 14)
#define XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 (1 << 13)
#define XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE (1 << 9)
#define XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 (1 << 8)
#define XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 (1 << 7)
#define XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE (1 << 6)
#define XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 (1 << 5)
#define XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 (1 << 4)
#define XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE (1 << 3)
#define XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 (1 << 2)
#define XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 (1 << 1)

#define XUSB_PADCTL_HSIC_PADX_CTL1(x) (0x304 + (x) * 0x20)
#define XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT 0
#define XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_MASK 0xf

#define XUSB_PADCTL_HSIC_PADX_CTL2(x) (0x308 + (x) * 0x20)
#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT 8
#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK 0xf
#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT 0
#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK 0xff

#define XUSB_PADCTL_HSIC_PAD_TRK_CTL 0x340
#define XUSB_PADCTL_HSIC_PAD_TRK_CTL_PD_TRK (1 << 19)
#define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT 12
#define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_MASK 0x7f
#define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_VAL 0x0a
#define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT 5
#define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_MASK 0x7f
#define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_VAL 0x1e

#define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL 0x344

#define XUSB_PADCTL_UPHY_PLL_P0_CTL1 0x360
#define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT 20
#define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_MASK 0xff
#define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_USB_VAL 0x19
#define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SATA_VAL 0x1e
#define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_SHIFT 16
#define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK 0x3
#define XUSB_PADCTL_UPHY_PLL_CTL1_LOCKDET_STATUS (1 << 15)
#define XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD (1 << 4)
#define XUSB_PADCTL_UPHY_PLL_CTL1_ENABLE (1 << 3)
#define XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_SHIFT 1
#define XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_MASK 0x3
#define XUSB_PADCTL_UPHY_PLL_CTL1_IDDQ (1 << 0)

#define XUSB_PADCTL_UPHY_PLL_P0_CTL2 0x364
#define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT 4
#define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK 0xffffff
#define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_VAL 0x136
#define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD (1 << 2)
#define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE (1 << 1)
#define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN (1 << 0)

#define XUSB_PADCTL_UPHY_PLL_P0_CTL4 0x36c
#define XUSB_PADCTL_UPHY_PLL_CTL4_XDIGCLK_EN (1 << 19)
#define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN (1 << 15)
#define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT 12
#define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK 0x3
#define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_USB_VAL 0x2
#define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SATA_VAL 0x0
#define XUSB_PADCTL_UPHY_PLL_CTL4_REFCLKBUF_EN (1 << 8)
#define XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_SHIFT 4
#define XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_MASK 0xf

#define XUSB_PADCTL_UPHY_PLL_P0_CTL5 0x370
#define XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT 16
#define XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_MASK 0xff
#define XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_VAL 0x2a

#define XUSB_PADCTL_UPHY_PLL_P0_CTL8 0x37c
#define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE (1 << 31)
#define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD (1 << 15)
#define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN (1 << 13)
#define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN (1 << 12)

#define XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL1(x) (0x460 + (x) * 0x40)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT 20
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_MASK 0x3
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_VAL 0x1
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN BIT(18)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD BIT(13)

#define XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(x) (0x464 + (x) * 0x40)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ BIT(0)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD BIT(1)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK GENMASK(5, 4)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL GENMASK(5, 4)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD BIT(24)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ BIT(8)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD BIT(9)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK GENMASK(13, 12)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL GENMASK(13, 12)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD BIT(25)

#define XUSB_PADCTL_UPHY_PLL_S0_CTL1 0x860

#define XUSB_PADCTL_UPHY_PLL_S0_CTL2 0x864

#define XUSB_PADCTL_UPHY_PLL_S0_CTL4 0x86c

#define XUSB_PADCTL_UPHY_PLL_S0_CTL5 0x870

#define XUSB_PADCTL_UPHY_PLL_S0_CTL8 0x87c

#define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1 0x960
#define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2 0x964

#define XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(x) (0xa60 + (x) * 0x40)
#define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT 16
#define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_MASK 0x3
#define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_VAL 0x2

#define XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(x) (0xa64 + (x) * 0x40)
#define XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT 0
#define XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_MASK 0xffff
#define XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_VAL 0x00fc

#define XUSB_PADCTL_UPHY_USB3_PADX_ECTL3(x) (0xa68 + (x) * 0x40)
#define XUSB_PADCTL_UPHY_USB3_PAD_ECTL3_RX_DFE_VAL 0xc0077f1f

#define XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(x) (0xa6c + (x) * 0x40)
#define XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT 16
#define XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_MASK 0xffff
#define XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_VAL 0x01c7

#define XUSB_PADCTL_UPHY_USB3_PADX_ECTL6(x) (0xa74 + (x) * 0x40)
#define XUSB_PADCTL_UPHY_USB3_PAD_ECTL6_RX_EQ_CTRL_H_VAL 0xfcf01368

#define XUSB_PADCTL_USB2_VBUS_ID 0xc60
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON (1 << 14)
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT 18
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK 0xf
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING 8
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED 0

/* USB2 SLEEPWALK registers */
#define UTMIP(_port, _offset1, _offset2) \
  (((_port) <= 2) ? (_offset1) : (_offset2))

#define PMC_UTMIP_UHSIC_SLEEP_CFG(x) UTMIP(x, 0x1fc, 0x4d0)
#define   UTMIP_MASTER_ENABLE(x)  UTMIP(x, BIT(8 * (x)), BIT(0))
#define   UTMIP_FSLS_USE_PMC(x)   UTMIP(x, BIT(8 * (x) + 1), \
       BIT(1))
#define   UTMIP_PCTRL_USE_PMC(x)  UTMIP(x, BIT(8 * (x) + 2), \
       BIT(2))
#define   UTMIP_TCTRL_USE_PMC(x)  UTMIP(x, BIT(8 * (x) + 3), \
       BIT(3))
#define   UTMIP_WAKE_VAL(_port, _value)  (((_value) & 0xf) << \
     (UTMIP(_port, 8 * (_port) + 4, 4)))
#define   UTMIP_WAKE_VAL_NONE(_port)  UTMIP_WAKE_VAL(_port, 12)
#define   UTMIP_WAKE_VAL_ANY(_port)  UTMIP_WAKE_VAL(_port, 15)

#define PMC_UTMIP_UHSIC_SLEEP_CFG1 (0x4d0)
#define   UTMIP_RPU_SWITC_LOW_USE_PMC_PX(x) BIT((x) + 8)
#define   UTMIP_RPD_CTRL_USE_PMC_PX(x)  BIT((x) + 16)

#define PMC_UTMIP_MASTER_CONFIG  (0x274)
#define   UTMIP_PWR(x)    UTMIP(x, BIT(x), BIT(4))
#define   UHSIC_PWR    BIT(3)

#define PMC_USB_DEBOUNCE_DEL  (0xec)
#define   DEBOUNCE_VAL(x)   (((x) & 0xffff) << 0)
#define   UTMIP_LINE_DEB_CNT(x)   (((x) & 0xf) << 16)
#define   UHSIC_LINE_DEB_CNT(x)   (((x) & 0xf) << 20)

#define PMC_UTMIP_UHSIC_FAKE(x)  UTMIP(x, 0x218, 0x294)
#define   UTMIP_FAKE_USBOP_VAL(x)  UTMIP(x, BIT(4 * (x)), BIT(8))
#define   UTMIP_FAKE_USBON_VAL(x)  UTMIP(x, BIT(4 * (x) + 1), \
       BIT(9))
#define   UTMIP_FAKE_USBOP_EN(x)  UTMIP(x, BIT(4 * (x) + 2), \
       BIT(10))
#define   UTMIP_FAKE_USBON_EN(x)  UTMIP(x, BIT(4 * (x) + 3), \
       BIT(11))

#define PMC_UTMIP_UHSIC_SLEEPWALK_CFG(x) UTMIP(x, 0x200, 0x288)
#define   UTMIP_LINEVAL_WALK_EN(x)  UTMIP(x, BIT(8 * (x) + 7), \
       BIT(15))

#define PMC_USB_AO   (0xf0)
#define   USBOP_VAL_PD(x)   UTMIP(x, BIT(4 * (x)), BIT(20))
#define   USBON_VAL_PD(x)   UTMIP(x, BIT(4 * (x) + 1), \
       BIT(21))
#define   STROBE_VAL_PD    BIT(12)
#define   DATA0_VAL_PD    BIT(13)
#define   DATA1_VAL_PD    BIT(24)

#define PMC_UTMIP_UHSIC_SAVED_STATE(x) UTMIP(x, 0x1f0, 0x280)
#define   SPEED(_port, _value)   (((_value) & 0x3) << \
      (UTMIP(_port, 8 * (_port), 8)))
#define   UTMI_HS(_port)   SPEED(_port, 0)
#define   UTMI_FS(_port)   SPEED(_port, 1)
#define   UTMI_LS(_port)   SPEED(_port, 2)
#define   UTMI_RST(_port)   SPEED(_port, 3)

#define PMC_UTMIP_UHSIC_TRIGGERS  (0x1ec)
#define   UTMIP_CLR_WALK_PTR(x)   UTMIP(x, BIT(x), BIT(16))
#define   UTMIP_CAP_CFG(x)   UTMIP(x, BIT((x) + 4), BIT(17))
#define   UTMIP_CLR_WAKE_ALARM(x)  UTMIP(x, BIT((x) + 12), \
       BIT(19))
#define   UHSIC_CLR_WALK_PTR   BIT(3)
#define   UHSIC_CLR_WAKE_ALARM   BIT(15)

#define PMC_UTMIP_SLEEPWALK_PX(x) UTMIP(x, 0x204 + (4 * (x)), \
       0x4e0)
/* phase A */
#define   UTMIP_USBOP_RPD_A   BIT(0)
#define   UTMIP_USBON_RPD_A   BIT(1)
#define   UTMIP_AP_A    BIT(4)
#define   UTMIP_AN_A    BIT(5)
#define   UTMIP_HIGHZ_A    BIT(6)
/* phase B */
#define   UTMIP_USBOP_RPD_B   BIT(8)
#define   UTMIP_USBON_RPD_B   BIT(9)
#define   UTMIP_AP_B    BIT(12)
#define   UTMIP_AN_B    BIT(13)
#define   UTMIP_HIGHZ_B    BIT(14)
/* phase C */
#define   UTMIP_USBOP_RPD_C   BIT(16)
#define   UTMIP_USBON_RPD_C   BIT(17)
#define   UTMIP_AP_C    BIT(20)
#define   UTMIP_AN_C    BIT(21)
#define   UTMIP_HIGHZ_C    BIT(22)
/* phase D */
#define   UTMIP_USBOP_RPD_D   BIT(24)
#define   UTMIP_USBON_RPD_D   BIT(25)
#define   UTMIP_AP_D    BIT(28)
#define   UTMIP_AN_D    BIT(29)
#define   UTMIP_HIGHZ_D    BIT(30)

#define PMC_UTMIP_UHSIC_LINE_WAKEUP (0x26c)
#define   UTMIP_LINE_WAKEUP_EN(x)  UTMIP(x, BIT(x), BIT(4))
#define   UHSIC_LINE_WAKEUP_EN   BIT(3)

#define PMC_UTMIP_TERM_PAD_CFG  (0x1f8)
#define   PCTRL_VAL(x)    (((x) & 0x3f) << 1)
#define   TCTRL_VAL(x)    (((x) & 0x3f) << 7)

#define PMC_UTMIP_PAD_CFGX(x)  (0x4c0 + (4 * (x)))
#define   RPD_CTRL_PX(x)   (((x) & 0x1f) << 22)

#define PMC_UHSIC_SLEEP_CFG PMC_UTMIP_UHSIC_SLEEP_CFG(0)
#define   UHSIC_MASTER_ENABLE   BIT(24)
#define   UHSIC_WAKE_VAL(_value)  (((_value) & 0xf) << 28)
#define   UHSIC_WAKE_VAL_SD10   UHSIC_WAKE_VAL(2)
#define   UHSIC_WAKE_VAL_NONE   UHSIC_WAKE_VAL(12)

#define PMC_UHSIC_FAKE   PMC_UTMIP_UHSIC_FAKE(0)
#define   UHSIC_FAKE_STROBE_VAL   BIT(12)
#define   UHSIC_FAKE_DATA_VAL   BIT(13)
#define   UHSIC_FAKE_STROBE_EN   BIT(14)
#define   UHSIC_FAKE_DATA_EN   BIT(15)

#define PMC_UHSIC_SAVED_STATE  PMC_UTMIP_UHSIC_SAVED_STATE(0)
#define   UHSIC_MODE(_value)   (((_value) & 0x1) << 24)
#define   UHSIC_HS    UHSIC_MODE(0)
#define   UHSIC_RST    UHSIC_MODE(1)

#define PMC_UHSIC_SLEEPWALK_CFG  PMC_UTMIP_UHSIC_SLEEPWALK_CFG(0)
#define   UHSIC_WAKE_WALK_EN   BIT(30)
#define   UHSIC_LINEVAL_WALK_EN   BIT(31)

#define PMC_UHSIC_SLEEPWALK_P0  (0x210)
#define   UHSIC_DATA0_RPD_A   BIT(1)
#define   UHSIC_DATA0_RPU_B   BIT(11)
#define   UHSIC_DATA0_RPU_C   BIT(19)
#define   UHSIC_DATA0_RPU_D   BIT(27)
#define   UHSIC_STROBE_RPU_A   BIT(2)
#define   UHSIC_STROBE_RPD_B   BIT(8)
#define   UHSIC_STROBE_RPD_C   BIT(16)
#define   UHSIC_STROBE_RPD_D   BIT(24)

struct tegra210_xusb_fuse_calibration {
 u32 hs_curr_level[4];
 u32 hs_term_range_adj;
 u32 rpd_ctrl;
};

struct tegra210_xusb_padctl_context {
 u32 usb2_pad_mux;
 u32 usb2_port_cap;
 u32 ss_port_map;
 u32 usb3_pad_mux;
};

struct tegra210_xusb_padctl {
 struct tegra_xusb_padctl base;
 struct regmap *regmap;

 struct tegra210_xusb_fuse_calibration fuse;
 struct tegra210_xusb_padctl_context context;
};

static inline struct tegra210_xusb_padctl *
to_tegra210_xusb_padctl(struct tegra_xusb_padctl *padctl)
{
 return container_of(padctl, struct tegra210_xusb_padctl, base);
}

static const struct tegra_xusb_lane_map tegra210_usb3_map[] = {
 { 0, "pcie", 6 },
 { 1, "pcie", 5 },
 { 2, "pcie", 0 },
 { 2, "pcie", 3 },
 { 3, "pcie", 4 },
 { 3, "sata", 0 },
 { 0, NULL,   0 }
};

static int tegra210_usb3_lane_map(struct tegra_xusb_lane *lane)
{
 const struct tegra_xusb_lane_map *map;

 for (map = tegra210_usb3_map; map->type; map++) {
  if (map->index == lane->index &&
      strcmp(map->type, lane->pad->soc->name) == 0) {
   dev_dbg(lane->pad->padctl->dev, "lane = %s map to port = usb3-%d\n",
    lane->pad->soc->lanes[lane->index].name, map->port);
   return map->port;
  }
 }

 return -EINVAL;
}

/* must be called under padctl->lock */
static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl)
{
 struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(padctl->pcie);
 unsigned long timeout;
 u32 value;
 unsigned int i;
 int err;

 if (pcie->enable)
  return 0;

 err = clk_prepare_enable(pcie->pll);
 if (err < 0)
  return err;

 if (tegra210_plle_hw_sequence_is_enabled())
  goto skip_pll_init;

 err = reset_control_deassert(pcie->rst);
 if (err < 0)
  goto disable;

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
 value &= ~(XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK <<
     XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT);
 value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_VAL <<
   XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL5);
 value &= ~(XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_MASK <<
     XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT);
 value |= XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_VAL <<
   XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL5);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
 value |= XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
 value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
 value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL4);
 value &= ~((XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK <<
      XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT) |
     (XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_MASK <<
      XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_SHIFT));
 value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_USB_VAL <<
    XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT) |
   XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL4);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
 value &= ~((XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK <<
      XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_SHIFT) |
     (XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_MASK <<
      XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT));
 value |= XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_USB_VAL <<
   XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
 value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_IDDQ;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
 value &= ~(XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_MASK <<
     XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_SHIFT);
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);

 usleep_range(10, 20);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL4);
 value |= XUSB_PADCTL_UPHY_PLL_CTL4_REFCLKBUF_EN;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL4);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
 value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2);

 timeout = jiffies + msecs_to_jiffies(100);

 while (time_before(jiffies, timeout)) {
  value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
  if (value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE)
   break;

  usleep_range(10, 20);
 }

 if (time_after_eq(jiffies, timeout)) {
  err = -ETIMEDOUT;
  goto reset;
 }

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
 value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2);

 timeout = jiffies + msecs_to_jiffies(100);

 while (time_before(jiffies, timeout)) {
  value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
  if (!(value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE))
   break;

  usleep_range(10, 20);
 }

 if (time_after_eq(jiffies, timeout)) {
  err = -ETIMEDOUT;
  goto reset;
 }

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
 value |= XUSB_PADCTL_UPHY_PLL_CTL1_ENABLE;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);

 timeout = jiffies + msecs_to_jiffies(100);

 while (time_before(jiffies, timeout)) {
  value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
  if (value & XUSB_PADCTL_UPHY_PLL_CTL1_LOCKDET_STATUS)
   break;

  usleep_range(10, 20);
 }

 if (time_after_eq(jiffies, timeout)) {
  err = -ETIMEDOUT;
  goto reset;
 }

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
 value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN |
   XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8);

 timeout = jiffies + msecs_to_jiffies(100);

 while (time_before(jiffies, timeout)) {
  value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
  if (value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE)
   break;

  usleep_range(10, 20);
 }

 if (time_after_eq(jiffies, timeout)) {
  err = -ETIMEDOUT;
  goto reset;
 }

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
 value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8);

 timeout = jiffies + msecs_to_jiffies(100);

 while (time_before(jiffies, timeout)) {
  value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
  if (!(value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE))
   break;

  usleep_range(10, 20);
 }

 if (time_after_eq(jiffies, timeout)) {
  err = -ETIMEDOUT;
  goto reset;
 }

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
 value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8);

 tegra210_xusb_pll_hw_control_enable();

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
 value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
 value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
 value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8);

 usleep_range(10, 20);

 tegra210_xusb_pll_hw_sequence_start();

skip_pll_init:
 pcie->enable = true;

 for (i = 0; i < padctl->pcie->soc->num_lanes; i++) {
  value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
  value |= XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(i);
  padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
 }

 return 0;

reset:
 reset_control_assert(pcie->rst);
disable:
 clk_disable_unprepare(pcie->pll);
 return err;
}

static void tegra210_pex_uphy_disable(struct tegra_xusb_padctl *padctl)
{
 struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(padctl->pcie);
 u32 value;
 unsigned int i;

 if (WARN_ON(!pcie->enable))
  return;

 pcie->enable = false;

 for (i = 0; i < padctl->pcie->soc->num_lanes; i++) {
  value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
  value &= ~XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(i);
  padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
 }

 clk_disable_unprepare(pcie->pll);
}

/* must be called under padctl->lock */
static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl)
{
 struct tegra_xusb_sata_pad *sata = to_sata_pad(padctl->sata);
 struct tegra_xusb_lane *lane = tegra_xusb_find_lane(padctl, "sata", 0);
 unsigned long timeout;
 u32 value;
 unsigned int i;
 int err;
 bool usb;

 if (sata->enable)
  return 0;

 if (IS_ERR(lane))
  return 0;

 if (tegra210_plle_hw_sequence_is_enabled())
  goto skip_pll_init;

 usb = tegra_xusb_lane_check(lane, "usb3-ss");

 err = clk_prepare_enable(sata->pll);
 if (err < 0)
  return err;

 err = reset_control_deassert(sata->rst);
 if (err < 0)
  goto disable;

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
 value &= ~(XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK <<
     XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT);
 value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_VAL <<
   XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL5);
 value &= ~(XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_MASK <<
     XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT);
 value |= XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_VAL <<
   XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL5);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
 value |= XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
 value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
 value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL4);
 value &= ~((XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK <<
      XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT) |
     (XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_MASK <<
      XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_SHIFT));
 value |= XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN;

 if (usb)
  value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_USB_VAL <<
     XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT);
 else
  value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SATA_VAL <<
     XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT);

 value &= ~XUSB_PADCTL_UPHY_PLL_CTL4_XDIGCLK_EN;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL4);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
 value &= ~((XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK <<
      XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_SHIFT) |
     (XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_MASK <<
      XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT));

 if (usb)
  value |= XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_USB_VAL <<
    XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT;
 else
  value |= XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SATA_VAL <<
    XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT;

 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
 value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_IDDQ;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
 value &= ~(XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_MASK <<
     XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_SHIFT);
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);

 usleep_range(10, 20);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL4);
 value |= XUSB_PADCTL_UPHY_PLL_CTL4_REFCLKBUF_EN;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL4);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
 value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2);

 timeout = jiffies + msecs_to_jiffies(100);

 while (time_before(jiffies, timeout)) {
  value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
  if (value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE)
   break;

  usleep_range(10, 20);
 }

 if (time_after_eq(jiffies, timeout)) {
  err = -ETIMEDOUT;
  goto reset;
 }

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
 value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2);

 timeout = jiffies + msecs_to_jiffies(100);

 while (time_before(jiffies, timeout)) {
  value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
  if (!(value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE))
   break;

  usleep_range(10, 20);
 }

 if (time_after_eq(jiffies, timeout)) {
  err = -ETIMEDOUT;
  goto reset;
 }

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
 value |= XUSB_PADCTL_UPHY_PLL_CTL1_ENABLE;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);

 timeout = jiffies + msecs_to_jiffies(100);

 while (time_before(jiffies, timeout)) {
  value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
  if (value & XUSB_PADCTL_UPHY_PLL_CTL1_LOCKDET_STATUS)
   break;

  usleep_range(10, 20);
 }

 if (time_after_eq(jiffies, timeout)) {
  err = -ETIMEDOUT;
  goto reset;
 }

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
 value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN |
   XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8);

 timeout = jiffies + msecs_to_jiffies(100);

 while (time_before(jiffies, timeout)) {
  value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
  if (value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE)
   break;

  usleep_range(10, 20);
 }

 if (time_after_eq(jiffies, timeout)) {
  err = -ETIMEDOUT;
  goto reset;
 }

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
 value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8);

 timeout = jiffies + msecs_to_jiffies(100);

 while (time_before(jiffies, timeout)) {
  value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
  if (!(value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE))
   break;

  usleep_range(10, 20);
 }

 if (time_after_eq(jiffies, timeout)) {
  err = -ETIMEDOUT;
  goto reset;
 }

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
 value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8);

 tegra210_sata_pll_hw_control_enable();

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
 value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
 value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2);

 value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
 value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD;
 padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8);

 usleep_range(10, 20);

 tegra210_sata_pll_hw_sequence_start();

skip_pll_init:
 sata->enable = true;

 for (i = 0; i < padctl->sata->soc->num_lanes; i++) {
  value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
  value |= XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(i);
  padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
 }

 return 0;

reset:
 reset_control_assert(sata->rst);
disable:
 clk_disable_unprepare(sata->pll);
 return err;
}

static void tegra210_sata_uphy_disable(struct tegra_xusb_padctl *padctl)
{
 struct tegra_xusb_sata_pad *sata = to_sata_pad(padctl->sata);
 u32 value;
 unsigned int i;

 if (WARN_ON(!sata->enable))
  return;

 sata->enable = false;

 for (i = 0; i < padctl->sata->soc->num_lanes; i++) {
  value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
  value &= ~XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(i);
  padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
 }

 clk_disable_unprepare(sata->pll);
}

static void tegra210_aux_mux_lp0_clamp_disable(struct tegra_xusb_padctl *padctl)
{
 u32 value;

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
 value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN;
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);

 usleep_range(100, 200);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
 value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY;
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);

 usleep_range(100, 200);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
 value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN;
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
}

static void tegra210_aux_mux_lp0_clamp_enable(struct tegra_xusb_padctl *padctl)
{
 u32 value;

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
 value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN;
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);

 usleep_range(100, 200);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
 value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY;
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);

 usleep_range(100, 200);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
 value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN;
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
}

static int tegra210_uphy_init(struct tegra_xusb_padctl *padctl)
{
 if (padctl->pcie)
  tegra210_pex_uphy_enable(padctl);

 if (padctl->sata)
  tegra210_sata_uphy_enable(padctl);

 if (!tegra210_plle_hw_sequence_is_enabled())
  tegra210_plle_hw_sequence_start();
 else
  dev_dbg(padctl->dev, "PLLE is already in HW control\n");

 tegra210_aux_mux_lp0_clamp_disable(padctl);

 return 0;
}

static void __maybe_unused
tegra210_uphy_deinit(struct tegra_xusb_padctl *padctl)
{
 tegra210_aux_mux_lp0_clamp_enable(padctl);

 if (padctl->sata)
  tegra210_sata_uphy_disable(padctl);

 if (padctl->pcie)
  tegra210_pex_uphy_disable(padctl);
}

static int tegra210_hsic_set_idle(struct tegra_xusb_padctl *padctl,
      unsigned int index, bool idle)
{
 u32 value;

 value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index));

 value &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA0 |
     XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA1 |
     XUSB_PADCTL_HSIC_PAD_CTL0_RPD_STROBE);

 if (idle)
  value |= XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 |
    XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 |
    XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE;
 else
  value &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 |
      XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 |
      XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE);

 padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL0(index));

 return 0;
}

static int tegra210_usb3_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
           enum usb_device_speed speed)
{
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 int port = tegra210_usb3_lane_map(lane);
 struct device *dev = padctl->dev;
 u32 value;

 if (port < 0) {
  dev_err(dev, "invalid usb3 port number\n");
  return -EINVAL;
 }

 mutex_lock(&padctl->lock);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
 value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port);
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);

 usleep_range(100, 200);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
 value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port);
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);

 usleep_range(250, 350);

 mutex_unlock(&padctl->lock);

 return 0;
}

static int tegra210_usb3_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
{
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 int port = tegra210_usb3_lane_map(lane);
 struct device *dev = padctl->dev;
 u32 value;

 if (port < 0) {
  dev_err(dev, "invalid usb3 port number\n");
  return -EINVAL;
 }

 mutex_lock(&padctl->lock);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
 value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port);
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);

 usleep_range(100, 200);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
 value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port);
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);

 mutex_unlock(&padctl->lock);

 return 0;
}

static int tegra210_usb3_enable_phy_wake(struct tegra_xusb_lane *lane)
{
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 int port = tegra210_usb3_lane_map(lane);
 struct device *dev = padctl->dev;
 u32 value;

 if (port < 0) {
  dev_err(dev, "invalid usb3 port number\n");
  return -EINVAL;
 }

 mutex_lock(&padctl->lock);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
 value &= ~ALL_WAKE_EVENTS;
 value |= SS_PORT_WAKEUP_EVENT(port);
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);

 usleep_range(10, 20);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
 value &= ~ALL_WAKE_EVENTS;
 value |= SS_PORT_WAKE_INTERRUPT_ENABLE(port);
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);

 mutex_unlock(&padctl->lock);

 return 0;
}

static int tegra210_usb3_disable_phy_wake(struct tegra_xusb_lane *lane)
{
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 int port = tegra210_usb3_lane_map(lane);
 struct device *dev = padctl->dev;
 u32 value;

 if (port < 0) {
  dev_err(dev, "invalid usb3 port number\n");
  return -EINVAL;
 }

 mutex_lock(&padctl->lock);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
 value &= ~ALL_WAKE_EVENTS;
 value &= ~SS_PORT_WAKE_INTERRUPT_ENABLE(port);
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);

 usleep_range(10, 20);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
 value &= ~ALL_WAKE_EVENTS;
 value |= SS_PORT_WAKEUP_EVENT(port);
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);

 mutex_unlock(&padctl->lock);

 return 0;
}

static bool tegra210_usb3_phy_remote_wake_detected(struct tegra_xusb_lane *lane)
{
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 int index = tegra210_usb3_lane_map(lane);
 u32 value;

 if (index < 0)
  return false;

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
 if ((value & SS_PORT_WAKE_INTERRUPT_ENABLE(index)) && (value & SS_PORT_WAKEUP_EVENT(index)))
  return true;

 return false;
}

static int tegra210_utmi_enable_phy_wake(struct tegra_xusb_lane *lane)
{
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 unsigned int index = lane->index;
 u32 value;

 mutex_lock(&padctl->lock);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
 value &= ~ALL_WAKE_EVENTS;
 value |= USB2_PORT_WAKEUP_EVENT(index);
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);

 usleep_range(10, 20);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
 value &= ~ALL_WAKE_EVENTS;
 value |= USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);

 mutex_unlock(&padctl->lock);

 return 0;
}

static int tegra210_utmi_disable_phy_wake(struct tegra_xusb_lane *lane)
{
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 unsigned int index = lane->index;
 u32 value;

 mutex_lock(&padctl->lock);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
 value &= ~ALL_WAKE_EVENTS;
 value &= ~USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);

 usleep_range(10, 20);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
 value &= ~ALL_WAKE_EVENTS;
 value |= USB2_PORT_WAKEUP_EVENT(index);
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);

 mutex_unlock(&padctl->lock);

 return 0;
}

static bool tegra210_utmi_phy_remote_wake_detected(struct tegra_xusb_lane *lane)
{
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 unsigned int index = lane->index;
 u32 value;

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
 if ((value & USB2_PORT_WAKE_INTERRUPT_ENABLE(index)) &&
     (value & USB2_PORT_WAKEUP_EVENT(index)))
  return true;

 return false;
}

static int tegra210_hsic_enable_phy_wake(struct tegra_xusb_lane *lane)
{
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 unsigned int index = lane->index;
 u32 value;

 mutex_lock(&padctl->lock);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
 value &= ~ALL_WAKE_EVENTS;
 value |= USB2_HSIC_PORT_WAKEUP_EVENT(index);
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);

 usleep_range(10, 20);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
 value &= ~ALL_WAKE_EVENTS;
 value |= USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index);
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);

 mutex_unlock(&padctl->lock);

 return 0;
}

static int tegra210_hsic_disable_phy_wake(struct tegra_xusb_lane *lane)
{
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 unsigned int index = lane->index;
 u32 value;

 mutex_lock(&padctl->lock);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
 value &= ~ALL_WAKE_EVENTS;
 value &= ~USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index);
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);

 usleep_range(10, 20);

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
 value &= ~ALL_WAKE_EVENTS;
 value |= USB2_HSIC_PORT_WAKEUP_EVENT(index);
 padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);

 mutex_unlock(&padctl->lock);

 return 0;
}

static bool tegra210_hsic_phy_remote_wake_detected(struct tegra_xusb_lane *lane)
{
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 unsigned int index = lane->index;
 u32 value;

 value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
 if ((value & USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index)) &&
     (value & USB2_HSIC_PORT_WAKEUP_EVENT(index)))
  return true;

 return false;
}

#define padctl_pmc_readl(_priv, _offset)      \
({           \
 u32 value;         \
 WARN(regmap_read(_priv->regmap, _offset, &value), "read %s failed\n"#_offset);\
 value;          \
})

#define padctl_pmc_writel(_priv, _value, _offset)     \
 WARN(regmap_write(_priv->regmap, _offset, _value), "write %s failed\n"#_offset)

static int tegra210_pmc_utmi_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
        enum usb_device_speed speed)
{
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
 unsigned int port = lane->index;
 u32 value, tctrl, pctrl, rpd_ctrl;

 if (!priv->regmap)
  return -EOPNOTSUPP;

 if (speed > USB_SPEED_HIGH)
  return -EINVAL;

 value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
 tctrl = TCTRL_VALUE(value);
 pctrl = PCTRL_VALUE(value);

 value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port));
 rpd_ctrl = RPD_CTRL_VALUE(value);

 /* ensure sleepwalk logic is disabled */
 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
 value &= ~UTMIP_MASTER_ENABLE(port);
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));

 /* ensure sleepwalk logics are in low power mode */
 value = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG);
 value |= UTMIP_PWR(port);
 padctl_pmc_writel(priv, value, PMC_UTMIP_MASTER_CONFIG);

 /* set debounce time */
 value = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL);
 value &= ~UTMIP_LINE_DEB_CNT(~0);
 value |= UTMIP_LINE_DEB_CNT(0x1);
 padctl_pmc_writel(priv, value, PMC_USB_DEBOUNCE_DEL);

 /* ensure fake events of sleepwalk logic are desiabled */
 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_FAKE(port));
 value &= ~(UTMIP_FAKE_USBOP_VAL(port) | UTMIP_FAKE_USBON_VAL(port) |
     UTMIP_FAKE_USBOP_EN(port) | UTMIP_FAKE_USBON_EN(port));
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_FAKE(port));

 /* ensure wake events of sleepwalk logic are not latched */
 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
 value &= ~UTMIP_LINE_WAKEUP_EN(port);
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);

 /* disable wake event triggers of sleepwalk logic */
 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
 value &= ~UTMIP_WAKE_VAL(port, ~0);
 value |= UTMIP_WAKE_VAL_NONE(port);
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));

 /* power down the line state detectors of the pad */
 value = padctl_pmc_readl(priv, PMC_USB_AO);
 value |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port));
 padctl_pmc_writel(priv, value, PMC_USB_AO);

 /* save state per speed */
 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SAVED_STATE(port));
 value &= ~SPEED(port, ~0);

 switch (speed) {
 case USB_SPEED_HIGH:
  value |= UTMI_HS(port);
  break;

 case USB_SPEED_FULL:
  value |= UTMI_FS(port);
  break;

 case USB_SPEED_LOW:
  value |= UTMI_LS(port);
  break;

 default:
  value |= UTMI_RST(port);
  break;
 }

 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SAVED_STATE(port));

 /* enable the trigger of the sleepwalk logic */
 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));
 value |= UTMIP_LINEVAL_WALK_EN(port);
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));

 /*
 * Reset the walk pointer and clear the alarm of the sleepwalk logic,
 * as well as capture the configuration of the USB2.0 pad.
 */

 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
 value |= UTMIP_CLR_WALK_PTR(port) | UTMIP_CLR_WAKE_ALARM(port) | UTMIP_CAP_CFG(port);
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);

 /* program electrical parameters read from XUSB PADCTL */
 value = padctl_pmc_readl(priv, PMC_UTMIP_TERM_PAD_CFG);
 value &= ~(TCTRL_VAL(~0) | PCTRL_VAL(~0));
 value |= (TCTRL_VAL(tctrl) | PCTRL_VAL(pctrl));
 padctl_pmc_writel(priv, value, PMC_UTMIP_TERM_PAD_CFG);

 value = padctl_pmc_readl(priv, PMC_UTMIP_PAD_CFGX(port));
 value &= ~RPD_CTRL_PX(~0);
 value |= RPD_CTRL_PX(rpd_ctrl);
 padctl_pmc_writel(priv, value, PMC_UTMIP_PAD_CFGX(port));

 /*
 * Set up the pull-ups and pull-downs of the signals during the four
 * stages of sleepwalk. If a device is connected, program sleepwalk
 * logic to maintain a J and keep driving K upon seeing remote wake.
 */

 value = padctl_pmc_readl(priv, PMC_UTMIP_SLEEPWALK_PX(port));
 value = UTMIP_USBOP_RPD_A | UTMIP_USBOP_RPD_B | UTMIP_USBOP_RPD_C | UTMIP_USBOP_RPD_D;
 value |= UTMIP_USBON_RPD_A | UTMIP_USBON_RPD_B | UTMIP_USBON_RPD_C | UTMIP_USBON_RPD_D;

 switch (speed) {
 case USB_SPEED_HIGH:
 case USB_SPEED_FULL:
  /* J state: D+/D- = high/low, K state: D+/D- = low/high */
  value |= UTMIP_HIGHZ_A;
  value |= UTMIP_AP_A;
  value |= UTMIP_AN_B | UTMIP_AN_C | UTMIP_AN_D;
  break;

 case USB_SPEED_LOW:
  /* J state: D+/D- = low/high, K state: D+/D- = high/low */
  value |= UTMIP_HIGHZ_A;
  value |= UTMIP_AN_A;
  value |= UTMIP_AP_B | UTMIP_AP_C | UTMIP_AP_D;
  break;

 default:
  value |= UTMIP_HIGHZ_A | UTMIP_HIGHZ_B | UTMIP_HIGHZ_C | UTMIP_HIGHZ_D;
  break;
 }

 padctl_pmc_writel(priv, value, PMC_UTMIP_SLEEPWALK_PX(port));

 /* power up the line state detectors of the pad */
 value = padctl_pmc_readl(priv, PMC_USB_AO);
 value &= ~(USBOP_VAL_PD(port) | USBON_VAL_PD(port));
 padctl_pmc_writel(priv, value, PMC_USB_AO);

 usleep_range(50, 100);

 /* switch the electric control of the USB2.0 pad to PMC */
 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
 value |= UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) | UTMIP_TCTRL_USE_PMC(port);
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));

 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1);
 value |= UTMIP_RPD_CTRL_USE_PMC_PX(port) | UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port);
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG1);

 /* set the wake signaling trigger events */
 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
 value &= ~UTMIP_WAKE_VAL(port, ~0);
 value |= UTMIP_WAKE_VAL_ANY(port);
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));

 /* enable the wake detection */
 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
 value |= UTMIP_MASTER_ENABLE(port);
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));

 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
 value |= UTMIP_LINE_WAKEUP_EN(port);
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);

 return 0;
}

static int tegra210_pmc_utmi_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
{
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
 unsigned int port = lane->index;
 u32 value;

 if (!priv->regmap)
  return -EOPNOTSUPP;

 /* disable the wake detection */
 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
 value &= ~UTMIP_MASTER_ENABLE(port);
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));

 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
 value &= ~UTMIP_LINE_WAKEUP_EN(port);
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);

 /* switch the electric control of the USB2.0 pad to XUSB or USB2 */
 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
 value &= ~(UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) |
     UTMIP_TCTRL_USE_PMC(port));
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));

 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1);
 value &= ~(UTMIP_RPD_CTRL_USE_PMC_PX(port) | UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port));
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG1);

 /* disable wake event triggers of sleepwalk logic */
 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
 value &= ~UTMIP_WAKE_VAL(port, ~0);
 value |= UTMIP_WAKE_VAL_NONE(port);
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));

 /* power down the line state detectors of the port */
 value = padctl_pmc_readl(priv, PMC_USB_AO);
 value |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port));
 padctl_pmc_writel(priv, value, PMC_USB_AO);

 /* clear alarm of the sleepwalk logic */
 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
 value |= UTMIP_CLR_WAKE_ALARM(port);
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);

 return 0;
}

static int tegra210_pmc_hsic_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
        enum usb_device_speed speed)
{
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
 u32 value;

 if (!priv->regmap)
  return -EOPNOTSUPP;

 /* ensure sleepwalk logic is disabled */
 value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
 value &= ~UHSIC_MASTER_ENABLE;
 padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);

 /* ensure sleepwalk logics are in low power mode */
 value = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG);
 value |= UHSIC_PWR;
 padctl_pmc_writel(priv, value, PMC_UTMIP_MASTER_CONFIG);

 /* set debounce time */
 value = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL);
 value &= ~UHSIC_LINE_DEB_CNT(~0);
 value |= UHSIC_LINE_DEB_CNT(0x1);
 padctl_pmc_writel(priv, value, PMC_USB_DEBOUNCE_DEL);

 /* ensure fake events of sleepwalk logic are desiabled */
 value = padctl_pmc_readl(priv, PMC_UHSIC_FAKE);
 value &= ~(UHSIC_FAKE_STROBE_VAL | UHSIC_FAKE_DATA_VAL |
     UHSIC_FAKE_STROBE_EN | UHSIC_FAKE_DATA_EN);
 padctl_pmc_writel(priv, value, PMC_UHSIC_FAKE);

 /* ensure wake events of sleepwalk logic are not latched */
 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
 value &= ~UHSIC_LINE_WAKEUP_EN;
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);

 /* disable wake event triggers of sleepwalk logic */
 value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
 value &= ~UHSIC_WAKE_VAL(~0);
 value |= UHSIC_WAKE_VAL_NONE;
 padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);

 /* power down the line state detectors of the port */
 value = padctl_pmc_readl(priv, PMC_USB_AO);
 value |= STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD;
 padctl_pmc_writel(priv, value, PMC_USB_AO);

 /* save state, HSIC always comes up as HS */
 value = padctl_pmc_readl(priv, PMC_UHSIC_SAVED_STATE);
 value &= ~UHSIC_MODE(~0);
 value |= UHSIC_HS;
 padctl_pmc_writel(priv, value, PMC_UHSIC_SAVED_STATE);

 /* enable the trigger of the sleepwalk logic */
 value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_CFG);
 value |= UHSIC_WAKE_WALK_EN | UHSIC_LINEVAL_WALK_EN;
 padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_CFG);

 /*
 * Reset the walk pointer and clear the alarm of the sleepwalk logic,
 * as well as capture the configuration of the USB2.0 port.
 */

 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
 value |= UHSIC_CLR_WALK_PTR | UHSIC_CLR_WAKE_ALARM;
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);

 /*
 * Set up the pull-ups and pull-downs of the signals during the four
 * stages of sleepwalk. Maintain a HSIC IDLE and keep driving HSIC
 * RESUME upon remote wake.
 */

 value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_P0);
 value = UHSIC_DATA0_RPD_A | UHSIC_DATA0_RPU_B | UHSIC_DATA0_RPU_C | UHSIC_DATA0_RPU_D |
  UHSIC_STROBE_RPU_A | UHSIC_STROBE_RPD_B | UHSIC_STROBE_RPD_C | UHSIC_STROBE_RPD_D;
 padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_P0);

 /* power up the line state detectors of the port */
 value = padctl_pmc_readl(priv, PMC_USB_AO);
 value &= ~(STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD);
 padctl_pmc_writel(priv, value, PMC_USB_AO);

 usleep_range(50, 100);

 /* set the wake signaling trigger events */
 value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
 value &= ~UHSIC_WAKE_VAL(~0);
 value |= UHSIC_WAKE_VAL_SD10;
 padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);

 /* enable the wake detection */
 value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
 value |= UHSIC_MASTER_ENABLE;
 padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);

 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
 value |= UHSIC_LINE_WAKEUP_EN;
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);

 return 0;
}

static int tegra210_pmc_hsic_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
{
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
 u32 value;

 if (!priv->regmap)
  return -EOPNOTSUPP;

 /* disable the wake detection */
 value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
 value &= ~UHSIC_MASTER_ENABLE;
 padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);

 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
 value &= ~UHSIC_LINE_WAKEUP_EN;
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);

 /* disable wake event triggers of sleepwalk logic */
 value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
 value &= ~UHSIC_WAKE_VAL(~0);
 value |= UHSIC_WAKE_VAL_NONE;
 padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);

 /* power down the line state detectors of the port */
 value = padctl_pmc_readl(priv, PMC_USB_AO);
 value |= STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD;
 padctl_pmc_writel(priv, value, PMC_USB_AO);

 /* clear alarm of the sleepwalk logic */
 value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
 value |= UHSIC_CLR_WAKE_ALARM;
 padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);

 return 0;
}

static int tegra210_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl,
      unsigned int index, bool enable)
{
 struct tegra_xusb_port *port;
 struct tegra_xusb_lane *lane;
 u32 value, offset;

 port = tegra_xusb_find_port(padctl, "usb3", index);
 if (!port)
  return -ENODEV;

 lane = port->lane;

 if (lane->pad == padctl->pcie)
  offset = XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL1(lane->index);
 else
  offset = XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1;

 value = padctl_readl(padctl, offset);

 value &= ~((XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_MASK <<
      XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT) |
     XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN |
     XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD);

 if (!enable) {
  value |= (XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_VAL <<
     XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT) |
    XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN |
    XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD;
 }

 padctl_writel(padctl, value, offset);

 return 0;
}

#define TEGRA210_LANE(_name, _offset, _shift, _mask, _type)  \
 {        \
  .name = _name,      \
  .offset = _offset,     \
  .shift = _shift,     \
  .mask = _mask,      \
  .num_funcs = ARRAY_SIZE(tegra210_##_type##_functions), \
  .funcs = tegra210_##_type##_functions,   \
 }

static const char *tegra210_usb2_functions[] = {
 "snps",
 "xusb",
 "uart"
};

static const struct tegra_xusb_lane_soc tegra210_usb2_lanes[] = {
 TEGRA210_LANE("usb2-0", 0x004,  0, 0x3, usb2),
 TEGRA210_LANE("usb2-1", 0x004,  2, 0x3, usb2),
 TEGRA210_LANE("usb2-2", 0x004,  4, 0x3, usb2),
 TEGRA210_LANE("usb2-3", 0x004,  6, 0x3, usb2),
};

static struct tegra_xusb_lane *
tegra210_usb2_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
    unsigned int index)
{
 struct tegra_xusb_usb2_lane *usb2;
 int err;

 usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
 if (!usb2)
  return ERR_PTR(-ENOMEM);

 INIT_LIST_HEAD(&usb2->base.list);
 usb2->base.soc = &pad->soc->lanes[index];
 usb2->base.index = index;
 usb2->base.pad = pad;
 usb2->base.np = np;

 err = tegra_xusb_lane_parse_dt(&usb2->base, np);
 if (err < 0) {
  kfree(usb2);
  return ERR_PTR(err);
 }

 return &usb2->base;
}

static void tegra210_usb2_lane_remove(struct tegra_xusb_lane *lane)
{
 struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane);

 kfree(usb2);
}

static const struct tegra_xusb_lane_ops tegra210_usb2_lane_ops = {
 .probe = tegra210_usb2_lane_probe,
 .remove = tegra210_usb2_lane_remove,
 .enable_phy_sleepwalk = tegra210_pmc_utmi_enable_phy_sleepwalk,
 .disable_phy_sleepwalk = tegra210_pmc_utmi_disable_phy_sleepwalk,
 .enable_phy_wake = tegra210_utmi_enable_phy_wake,
 .disable_phy_wake = tegra210_utmi_disable_phy_wake,
 .remote_wake_detected = tegra210_utmi_phy_remote_wake_detected,
};

static int tegra210_usb2_phy_init(struct phy *phy)
{
 struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 unsigned int index = lane->index;
 struct tegra_xusb_usb2_port *port;
 int err;
 u32 value;

 port = tegra_xusb_find_usb2_port(padctl, index);
 if (!port) {
  dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
  return -ENODEV;
 }

 if (port->supply && port->mode == USB_DR_MODE_HOST) {
  err = regulator_enable(port->supply);
  if (err)
   return err;
 }

 mutex_lock(&padctl->lock);

 value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
 value &= ~(XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK <<
     XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT);
 value |= XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB <<
   XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT;
 padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX);

 mutex_unlock(&padctl->lock);

 return 0;
}

static int tegra210_usb2_phy_exit(struct phy *phy)
{
 struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 struct tegra_xusb_usb2_port *port;
 int err;

 port = tegra_xusb_find_usb2_port(padctl, lane->index);
 if (!port) {
  dev_err(&phy->dev, "no port found for USB2 lane %u\n", lane->index);
  return -ENODEV;
 }

 if (port->supply && port->mode == USB_DR_MODE_HOST) {
  err = regulator_disable(port->supply);
  if (err)
   return err;
 }

 return 0;
}

static int tegra210_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
           bool status)
{
 u32 value;

 dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");

 value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);

 if (status) {
  value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
  value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
      XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
  value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING <<
    XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
 } else {
  value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
 }

 padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);

 return 0;
}

static int tegra210_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl,
         bool status)
{
 u32 value;

 dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear");

 value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);

 if (status) {
  if (value & XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON) {
   value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
   padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
   usleep_range(1000, 2000);

   value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
  }

  value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
      XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
  value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED <<
    XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
 } else {
  value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
      XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
  value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING <<
    XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
 }

 padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);

 return 0;
}

static int tegra210_usb2_phy_set_mode(struct phy *phy, enum phy_mode mode,
          int submode)
{
 struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
 struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl,
        lane->index);
 int err = 0;

 mutex_lock(&padctl->lock);

 dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode);

 if (mode == PHY_MODE_USB_OTG) {
  if (submode == USB_ROLE_HOST) {
   tegra210_xusb_padctl_id_override(padctl, true);

   err = regulator_enable(port->supply);
  } else if (submode == USB_ROLE_DEVICE) {
   tegra210_xusb_padctl_vbus_override(padctl, true);
  } else if (submode == USB_ROLE_NONE) {
   /*
 * When port is peripheral only or role transitions to
 * USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not
 * be enabled.
 */

   if (regulator_is_enabled(port->supply))
    regulator_disable(port->supply);

   tegra210_xusb_padctl_id_override(padctl, false);
   tegra210_xusb_padctl_vbus_override(padctl, false);
  }
 }

 mutex_unlock(&padctl->lock);

 return err;
}

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;
 unsigned int index = lane->index;
 u32 value;
 int err;

 port = tegra_xusb_find_usb2_port(padctl, index);
 if (!port) {
  dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
  return -ENODEV;
 }

 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(
     port->usb3_port_fake);
  value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(
     port->usb3_port_fake, index);
  padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP);

  value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
  value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(
     port->usb3_port_fake);
  padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);

  usleep_range(100, 200);

  value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
  value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(
     port->usb3_port_fake);
  padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);

  usleep_range(100, 200);

  value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
  value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(
     port->usb3_port_fake);
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=96 H=89 G=92

¤ Dauer der Verarbeitung: 0.22 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.