summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorDan Willemsen <dwillemsen@nvidia.com>2013-02-22 10:55:25 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 12:52:22 -0700
commitdeb4354e83e9ea6df0466bd2fd821647ff9bf870 (patch)
treebdba6fce80d164e6cb79e80e7a7852ed1df8dac9 /drivers/usb
parent765599c2dd43b526b820cb5e5a4929b6a41f36f2 (diff)
fixup usb move to drivers/usb/phy
Signed-off-by: Dan Willemsen <dwillemsen@nvidia.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/phy/Makefile8
-rw-r--r--drivers/usb/phy/phy-tegra-usb.c2
-rw-r--r--drivers/usb/phy/tegra11x_usb_phy.c3179
-rw-r--r--drivers/usb/phy/tegra2_usb_phy.c2078
-rw-r--r--drivers/usb/phy/tegra3_usb_phy.c3178
-rw-r--r--drivers/usb/phy/tegra_usb_phy.h120
6 files changed, 8563 insertions, 2 deletions
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index 4b4f7f81e68f..2bb1a3656387 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -24,7 +24,13 @@ obj-$(CONFIG_SAMSUNG_USB2PHY) += phy-samsung-usb2.o
obj-$(CONFIG_SAMSUNG_USB3PHY) += phy-samsung-usb3.o
obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o
obj-$(CONFIG_TWL6030_USB) += phy-twl6030-usb.o
-obj-$(CONFIG_USB_EHCI_TEGRA) += phy-tegra-usb.o
+ifeq ($(CONFIG_USB_EHCI_TEGRA),y)
+obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra3_usb_phy.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_usb_phy.o
+obj-$(CONFIG_ARCH_TEGRA_11x_SOC) += tegra11x_usb_phy.o
+obj-$(CONFIG_ARCH_TEGRA_14x_SOC) += tegra11x_usb_phy.o
+endif
obj-$(CONFIG_USB_GPIO_VBUS) += phy-gpio-vbus-usb.o
obj-$(CONFIG_USB_ISP1301) += phy-isp1301.o
obj-$(CONFIG_USB_MSM_OTG) += phy-msm-usb.o
diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index 83a369783ef4..e7895087842e 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -37,7 +37,7 @@
#include "../../../arch/arm/mach-tegra/iomap.h"
#include "../../../arch/arm/mach-tegra/clock.h"
-#include "../../../arch/arm/mach-tegra/tegra_usb_phy.h"
+#include "tegra_usb_phy.h"
#include "../../../arch/arm/mach-tegra/fuse.h"
#include "../../../arch/arm/mach-tegra/common.h"
diff --git a/drivers/usb/phy/tegra11x_usb_phy.c b/drivers/usb/phy/tegra11x_usb_phy.c
new file mode 100644
index 000000000000..a0a7cf0996df
--- /dev/null
+++ b/drivers/usb/phy/tegra11x_usb_phy.c
@@ -0,0 +1,3179 @@
+/*
+ * arch/arm/mach-tegra/tegra11x_usb_phy.c
+ *
+ * Copyright (C) 2012-2013 NVIDIA Corporation
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/resource.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/usb/ulpi.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/platform_data/tegra_usb.h>
+#include <mach/clk.h>
+#include <mach/iomap.h>
+#include <mach/pinmux.h>
+#ifdef CONFIG_ARCH_TEGRA_14x_SOC
+#include <mach/pinmux-t14.h>
+#else
+#include <mach/pinmux-t11.h>
+#endif
+#include <asm/mach-types.h>
+#include "tegra_usb_phy.h"
+#include "gpio-names.h"
+#include "fuse.h"
+
+#define USB_USBCMD 0x130
+#define USB_USBCMD_RS (1 << 0)
+#define USB_CMD_RESET (1<<1)
+
+#define USB_USBSTS 0x134
+#define USB_USBSTS_PCI (1 << 2)
+#define USB_USBSTS_SRI (1 << 7)
+#define USB_USBSTS_HCH (1 << 12)
+
+#define USB_TXFILLTUNING 0x154
+#define USB_FIFO_TXFILL_THRES(x) (((x) & 0x1f) << 16)
+#define USB_FIFO_TXFILL_MASK 0x1f0000
+
+#define ULPI_VIEWPORT 0x170
+#define ULPI_WAKEUP (1 << 31)
+#define ULPI_RUN (1 << 30)
+#define ULPI_RD_WR (1 << 29)
+
+#define USB_ASYNCLISTADDR 0x148
+
+#define ICUSB_CTRL 0x15c
+
+#define USB_PORTSC 0x174
+#define USB_PORTSC_PHCD (1 << 23)
+#define USB_PORTSC_WKOC (1 << 22)
+#define USB_PORTSC_WKDS (1 << 21)
+#define USB_PORTSC_WKCN (1 << 20)
+#define USB_PORTSC_PTC(x) (((x) & 0xf) << 16)
+#define USB_PORTSC_PP (1 << 12)
+#define USB_PORTSC_LS(x) (((x) & 0x3) << 10)
+#define USB_PORTSC_SUSP (1 << 7)
+#define USB_PORTSC_RESUME (1 << 6)
+#define USB_PORTSC_OCC (1 << 5)
+#define USB_PORTSC_PEC (1 << 3)
+#define USB_PORTSC_PE (1 << 2)
+#define USB_PORTSC_CSC (1 << 1)
+#define USB_PORTSC_CCS (1 << 0)
+#define USB_PORTSC_RWC_BITS (USB_PORTSC_CSC | USB_PORTSC_PEC | USB_PORTSC_OCC)
+#define USB_PORTSC_PSPD_MASK 3
+
+#define HOSTPC1_DEVLC 0x1b4
+#define HOSTPC1_DEVLC_PHCD (1 << 22)
+#define HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29)
+#define HOSTPC1_DEVLC_PTS_MASK 7
+#define HOSTPC1_DEVLC_PTS_HSIC 4
+#define HOSTPC1_DEVLC_STS (1 << 28)
+#define HOSTPC1_DEVLC_PSPD(x) (((x) & 0x3) << 25)
+#define HOSTPC1_DEVLC_PSPD_MASK 3
+#define HOSTPC1_DEVLC_PSPD_HIGH_SPEED 2
+#define HOSTPC1_DEVLC_NYT_ASUS 1
+
+#define USB_USBMODE 0x1f8
+#define USB_USBMODE_MASK (3 << 0)
+#define USB_USBMODE_HOST (3 << 0)
+#define USB_USBMODE_DEVICE (2 << 0)
+
+#define USB_SUSP_CTRL 0x400
+#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3)
+#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4)
+#define USB_SUSP_CLR (1 << 5)
+#define USB_CLKEN (1 << 6)
+#define USB_PHY_CLK_VALID (1 << 7)
+#define USB_PHY_CLK_VALID_INT_ENB (1 << 9)
+#define USB_PHY_CLK_VALID_INT_STS (1 << 8)
+#define UTMIP_RESET (1 << 11)
+#define UTMIP_PHY_ENABLE (1 << 12)
+#define ULPI_PHY_ENABLE (1 << 13)
+#define UHSIC_RESET (1 << 14)
+#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
+#define UHSIC_PHY_ENABLE (1 << 19)
+#define ULPIS2S_SLV0_RESET (1 << 20)
+#define ULPIS2S_SLV1_RESET (1 << 21)
+#define ULPIS2S_LINE_RESET (1 << 22)
+#define ULPI_PADS_RESET (1 << 23)
+#define ULPI_PADS_CLKEN_RESET (1 << 24)
+
+#define USB_PHY_VBUS_WAKEUP_ID 0x408
+#define VDAT_DET_INT_EN (1 << 16)
+#define VDAT_DET_CHG_DET (1 << 17)
+#define VDAT_DET_STS (1 << 18)
+#define USB_ID_STATUS (1 << 2)
+
+#define ULPIS2S_CTRL 0x418
+#define ULPIS2S_ENA (1 << 0)
+#define ULPIS2S_SUPPORT_DISCONNECT (1 << 2)
+#define ULPIS2S_PLLU_MASTER_BLASTER60 (1 << 3)
+#define ULPIS2S_SPARE(x) (((x) & 0xF) << 8)
+#define ULPIS2S_FORCE_ULPI_CLK_OUT (1 << 12)
+#define ULPIS2S_DISCON_DONT_CHECK_SE0 (1 << 13)
+#define ULPIS2S_SUPPORT_HS_KEEP_ALIVE (1 << 14)
+#define ULPIS2S_DISABLE_STP_PU (1 << 15)
+#define ULPIS2S_SLV0_CLAMP_XMIT (1 << 16)
+
+#define ULPI_TIMING_CTRL_0 0x424
+#define ULPI_CLOCK_OUT_DELAY(x) ((x) & 0x1F)
+#define ULPI_OUTPUT_PINMUX_BYP (1 << 10)
+#define ULPI_CLKOUT_PINMUX_BYP (1 << 11)
+#define ULPI_SHADOW_CLK_LOOPBACK_EN (1 << 12)
+#define ULPI_SHADOW_CLK_SEL (1 << 13)
+#define ULPI_CORE_CLK_SEL (1 << 14)
+#define ULPI_SHADOW_CLK_DELAY(x) (((x) & 0x1F) << 16)
+#define ULPI_LBK_PAD_EN (1 << 26)
+#define ULPI_LBK_PAD_E_INPUT_OR (1 << 27)
+#define ULPI_CLK_OUT_ENA (1 << 28)
+#define ULPI_CLK_PADOUT_ENA (1 << 29)
+
+#define ULPI_TIMING_CTRL_1 0x428
+#define ULPI_DATA_TRIMMER_LOAD (1 << 0)
+#define ULPI_DATA_TRIMMER_SEL(x) (((x) & 0x7) << 1)
+#define ULPI_STPDIRNXT_TRIMMER_LOAD (1 << 16)
+#define ULPI_STPDIRNXT_TRIMMER_SEL(x) (((x) & 0x7) << 17)
+#define ULPI_DIR_TRIMMER_LOAD (1 << 24)
+#define ULPI_DIR_TRIMMER_SEL(x) (((x) & 0x7) << 25)
+
+#define USB_IF_SPARE 0x498
+#define USB_HS_RSM_EOP_EN (1 << 4)
+#define USB_PORT_SUSPEND_EN (1 << 5)
+
+#define USB_NEW_CONTROL 0x4c0
+#define USB_COHRENCY_EN (1 << 0)
+#define USB_MEM_ALLIGNMENT_MUX_EN (1 << 1)
+
+#define UTMIP_XCVR_CFG0 0x808
+#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0)
+#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8)
+#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10)
+#define UTMIP_FORCE_PD_POWERDOWN (1 << 14)
+#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16)
+#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18)
+#define UTMIP_XCVR_LSBIAS_SEL (1 << 21)
+#define UTMIP_XCVR_SETUP_MSB(x) (((x) & 0x7) << 22)
+#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25)
+#define UTMIP_XCVR_MAX_OFFSET 2
+#define UTMIP_XCVR_SETUP_MAX_VALUE 0x7f
+#define UTMIP_XCVR_SETUP_MIN_VALUE 0
+#define XCVR_SETUP_MSB_CALIB(x) ((x) >> 4)
+
+#define UTMIP_BIAS_CFG0 0x80c
+#define UTMIP_OTGPD (1 << 11)
+#define UTMIP_BIASPD (1 << 10)
+#define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0)
+#define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2)
+#define UTMIP_HSDISCON_LEVEL_MSB (1 << 24)
+
+#define UTMIP_HSRX_CFG0 0x810
+#define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10)
+#define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15)
+
+#define UTMIP_HSRX_CFG1 0x814
+#define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
+
+#define UTMIP_TX_CFG0 0x820
+#define UTMIP_FS_PREABMLE_J (1 << 19)
+#define UTMIP_HS_DISCON_DISABLE (1 << 8)
+
+#define UTMIP_DEBOUNCE_CFG0 0x82c
+#define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0)
+
+#define UTMIP_BAT_CHRG_CFG0 0x830
+#define UTMIP_PD_CHRG (1 << 0)
+#define UTMIP_ON_SINK_EN (1 << 2)
+#define UTMIP_OP_SRC_EN (1 << 3)
+
+#define UTMIP_XCVR_CFG1 0x838
+#define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0)
+#define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2)
+#define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4)
+#define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18)
+
+#define UTMIP_BIAS_CFG1 0x83c
+#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3)
+#define UTMIP_BIAS_PDTRK_POWERDOWN (1 << 0)
+#define UTMIP_BIAS_PDTRK_POWERUP (1 << 1)
+
+#define UTMIP_MISC_CFG0 0x824
+#define UTMIP_DPDM_OBSERVE (1 << 26)
+#define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_J UTMIP_DPDM_OBSERVE_SEL(0xf)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_K UTMIP_DPDM_OBSERVE_SEL(0xe)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc)
+#define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22)
+#define FORCE_PULLDN_DM (1 << 8)
+#define FORCE_PULLDN_DP (1 << 9)
+#define COMB_TERMS (1 << 0)
+#define ALWAYS_FREE_RUNNING_TERMS (1 << 1)
+
+#define UTMIP_SPARE_CFG0 0x834
+#define FUSE_SETUP_SEL (1 << 3)
+#define FUSE_ATERM_SEL (1 << 4)
+
+#define UTMIP_PMC_WAKEUP0 0x84c
+#define UHSIC_PMC_WAKEUP0 0xc34
+#define EVENT_INT_ENB (1 << 0)
+
+#define UTMIP_BIAS_STS0 0x840
+#define UTMIP_RCTRL_VAL(x) (((x) & 0xffff) << 0)
+#define UTMIP_TCTRL_VAL(x) (((x) & (0xffff << 16)) >> 16)
+
+#define UTMIPLL_HW_PWRDN_CFG0 0x52c
+#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE (1<<1)
+
+#define UHSIC_INST(inst, x, y) ((inst == 1) ? x : y)
+
+#define UHSIC_PLL_CFG1 0xc04
+#define UHSIC_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+#define UHSIC_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 14)
+
+#define UHSIC_HSRX_CFG0 0xc08
+#define UHSIC_ELASTIC_UNDERRUN_LIMIT(x) (((x) & 0x1f) << 2)
+#define UHSIC_ELASTIC_OVERRUN_LIMIT(x) (((x) & 0x1f) << 8)
+#define UHSIC_IDLE_WAIT(x) (((x) & 0x1f) << 13)
+
+#define UHSIC_HSRX_CFG1 0xc0c
+#define UHSIC_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
+
+#define UHSIC_TX_CFG0 0xc10
+#define UHSIC_HS_READY_WAIT_FOR_VALID (1 << 9)
+
+#define UHSIC_MISC_CFG0 0xc14
+#define UHSIC_SUSPEND_EXIT_ON_EDGE (1 << 7)
+#define UHSIC_DETECT_SHORT_CONNECT (1 << 8)
+#define UHSIC_FORCE_XCVR_MODE (1 << 15)
+#define UHSIC_DISABLE_BUSRESET (1 << 20)
+
+#define UHSIC_MISC_CFG1 0xc18
+#define UHSIC_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 2)
+
+#define UHSIC_PADS_CFG0 0xc1c
+#define UHSIC_TX_RTUNEN 0xf000
+#define UHSIC_TX_RTUNE(x) (((x) & 0xf) << 12)
+#define UHSIC_TX_SLEWP (0xf << 16)
+#define UHSIC_TX_SLEWN (0xf << 20)
+
+#define UHSIC_PADS_CFG1 0xc20
+#define UHSIC_PD_BG (1 << 2)
+#define UHSIC_PD_TX (1 << 3)
+#define UHSIC_PD_TRK (1 << 4)
+#define UHSIC_PD_RX (1 << 5)
+#define UHSIC_PD_ZI (1 << 6)
+#define UHSIC_RX_SEL (1 << 7)
+#define UHSIC_RPD_DATA (1 << 9)
+#define UHSIC_RPD_STROBE (1 << 10)
+#define UHSIC_RPU_DATA (1 << 11)
+#define UHSIC_RPU_STROBE (1 << 12)
+
+#define UHSIC_SPARE_CFG0 0xc2c
+#define FORCE_BK_ON (1 << 12)
+
+#define UHSIC_STAT_CFG0 0xc28
+#define UHSIC_CONNECT_DETECT (1 << 0)
+
+#define PMC_UHSIC_TRIGGERS(inst) UHSIC_INST(inst, 0x1ec, 0x27c)
+#define UHSIC_CLR_WALK_PTR(inst) (1 << UHSIC_INST(inst, 3, 0))
+#define UHSIC_CLR_WAKE_ALARM(inst) (1 << UHSIC_INST(inst, 15, 3))
+
+#define PMC_UHSIC_SLEEPWALK_CFG(inst) UHSIC_INST(inst, 0x200, 0x288)
+#define UHSIC_LINEVAL_WALK_EN(inst) (1 << UHSIC_INST(inst, 31, 7))
+
+#define UHSIC_STATUS(inst) UHSIC_INST(inst, 0x214, 0x290)
+#define UHSIC_WAKE_ALARM(inst) (1 << UHSIC_INST(inst, 19, 4))
+#define UHSIC_WALK_PTR_VAL(inst) (0x3 << UHSIC_INST(inst, 6, 0))
+#define UHSIC_DATA_VAL(inst) (1 << UHSIC_INST(inst, 15, 3))
+#define UHSIC_STROBE_VAL(inst) (1 << UHSIC_INST(inst, 14, 2))
+
+#define UHSIC_CMD_CFG0 0xc24
+#define UHSIC_PRETEND_CONNECT_DETECT (1 << 5)
+
+#define PMC_UHSIC_SLEEP_CFG(inst) UHSIC_INST(inst, 0x1fc, 0x284)
+#define UHSIC_MASTER_ENABLE(inst) (1 << UHSIC_INST(inst, 24, 0))
+#define UHSIC_WAKE_VAL(inst, x) (((x) & 0xf) << UHSIC_INST(inst, 28, 4))
+#define WAKE_VAL_SD10 0x2
+
+#define USB_USBINTR 0x138
+
+#define PMC_UHSIC_MASTER_CONFIG(inst) UHSIC_INST(inst, 0x274, 0x29c)
+#define UHSIC_PWR(inst) (1 << UHSIC_INST(inst, 3, 0))
+
+#define PMC_UHSIC_FAKE(inst) UHSIC_INST(inst, 0x218, 0x294)
+#define UHSIC_FAKE_STROBE_VAL(inst) (1 << UHSIC_INST(inst, 12, 0))
+#define UHSIC_FAKE_DATA_VAL(inst) (1 << UHSIC_INST(inst, 13, 1))
+
+#define PMC_SLEEPWALK_UHSIC(inst) UHSIC_INST(inst, 0x210, 0x28c)
+#define UHSIC_STROBE_RPD_A (1 << 0)
+#define UHSIC_DATA_RPD_A (1 << 1)
+#define UHSIC_STROBE_RPU_A (1 << 2)
+#define UHSIC_DATA_RPU_A (1 << 3)
+#define UHSIC_STROBE_RPD_B (1 << 8)
+#define UHSIC_DATA_RPD_B (1 << 9)
+#define UHSIC_STROBE_RPU_B (1 << 10)
+#define UHSIC_DATA_RPU_B (1 << 11)
+#define UHSIC_STROBE_RPD_C (1 << 16)
+#define UHSIC_DATA_RPD_C (1 << 17)
+#define UHSIC_STROBE_RPU_C (1 << 18)
+#define UHSIC_DATA_RPU_C (1 << 19)
+#define UHSIC_STROBE_RPD_D (1 << 24)
+#define UHSIC_DATA_RPD_D (1 << 25)
+#define UHSIC_STROBE_RPU_D (1 << 26)
+#define UHSIC_DATA_RPU_D (1 << 27)
+#define UHSIC_LINE_DEB_CNT(x) (((x) & 0xf) << 20)
+
+#define PMC_USB_DEBOUNCE 0xec
+#define UTMIP_LINE_DEB_CNT(x) (((x) & 0xf) << 16)
+#define PMC_USB_DEBOUNCE_VAL(x) ((x) & 0xffff)
+
+#define PMC_USB_AO 0xf0
+#define HSIC_RESERVED(inst) (3 << UHSIC_INST(inst, 14, 18))
+#define STROBE_VAL_PD(inst) (1 << UHSIC_INST(inst, 12, 16))
+#define DATA_VAL_PD(inst) (1 << UHSIC_INST(inst, 13, 17))
+#define PMC_POWER_DOWN_MASK 0xffff
+#define USB_ID_PD(inst) (1 << ((4*(inst))+3))
+#define VBUS_WAKEUP_PD(inst) (1 << ((4*(inst))+2))
+#define USBON_VAL_PD(inst) (1 << ((4*(inst))+1))
+#define USBON_VAL_PD_P2 (1 << 9)
+#define USBON_VAL_PD_P1 (1 << 5)
+#define USBON_VAL_PD_P0 (1 << 1)
+#define USBOP_VAL_PD(inst) (1 << (4*(inst)))
+#define USBOP_VAL_PD_P2 (1 << 8)
+#define USBOP_VAL_PD_P1 (1 << 4)
+#define USBOP_VAL_PD_P0 (1 << 0)
+#define PMC_USB_AO_ID_PD_P0 (1 << 3)
+#define PMC_USB_AO_VBUS_WAKEUP_PD_P0 (1 << 2)
+
+#define PMC_TRIGGERS 0x1ec
+#define UTMIP_CLR_WALK_PTR(inst) (1 << (inst))
+#define UTMIP_CLR_WALK_PTR_P2 (1 << 2)
+#define UTMIP_CLR_WALK_PTR_P1 (1 << 1)
+#define UTMIP_CLR_WALK_PTR_P0 (1 << 0)
+#define UTMIP_CAP_CFG(inst) (1 << ((inst)+4))
+#define UTMIP_CAP_CFG_P2 (1 << 6)
+#define UTMIP_CAP_CFG_P1 (1 << 5)
+#define UTMIP_CAP_CFG_P0 (1 << 4)
+#define UTMIP_CLR_WAKE_ALARM(inst) (1 << ((inst)+12))
+#define UTMIP_CLR_WAKE_ALARM_P2 (1 << 14)
+
+#define PMC_PAD_CFG (0x1f4)
+
+#define PMC_UTMIP_TERM_PAD_CFG 0x1f8
+#define PMC_TCTRL_VAL(x) (((x) & 0x1f) << 5)
+#define PMC_RCTRL_VAL(x) (((x) & 0x1f) << 0)
+
+#define PMC_SLEEP_CFG 0x1fc
+#define UTMIP_TCTRL_USE_PMC(inst) (1 << ((8*(inst))+3))
+#define UTMIP_TCTRL_USE_PMC_P2 (1 << 19)
+#define UTMIP_TCTRL_USE_PMC_P1 (1 << 11)
+#define UTMIP_TCTRL_USE_PMC_P0 (1 << 3)
+#define UTMIP_RCTRL_USE_PMC(inst) (1 << ((8*(inst))+2))
+#define UTMIP_RCTRL_USE_PMC_P2 (1 << 18)
+#define UTMIP_RCTRL_USE_PMC_P1 (1 << 10)
+#define UTMIP_RCTRL_USE_PMC_P0 (1 << 2)
+#define UTMIP_FSLS_USE_PMC(inst) (1 << ((8*(inst))+1))
+#define UTMIP_FSLS_USE_PMC_P2 (1 << 17)
+#define UTMIP_FSLS_USE_PMC_P1 (1 << 9)
+#define UTMIP_FSLS_USE_PMC_P0 (1 << 1)
+#define UTMIP_MASTER_ENABLE(inst) (1 << (8*(inst)))
+#define UTMIP_MASTER_ENABLE_P2 (1 << 16)
+#define UTMIP_MASTER_ENABLE_P1 (1 << 8)
+#define UTMIP_MASTER_ENABLE_P0 (1 << 0)
+
+#define PMC_SLEEPWALK_CFG 0x200
+#define UTMIP_LINEVAL_WALK_EN(inst) (1 << ((8*(inst))+7))
+#define UTMIP_LINEVAL_WALK_EN_P2 (1 << 23)
+#define UTMIP_LINEVAL_WALK_EN_P1 (1 << 15)
+#define UTMIP_LINEVAL_WALK_EN_P0 (1 << 7)
+#define UTMIP_WAKE_VAL(inst, x) (((x) & 0xf) << ((8*(inst))+4))
+#define UTMIP_WAKE_VAL_P2(x) (((x) & 0xf) << 20)
+#define UTMIP_WAKE_VAL_P1(x) (((x) & 0xf) << 12)
+#define UTMIP_WAKE_VAL_P0(x) (((x) & 0xf) << 4)
+#define WAKE_VAL_NONE 0xc
+#define WAKE_VAL_ANY 0xF
+#define WAKE_VAL_FSJ 0x2
+#define WAKE_VAL_FSK 0x1
+#define WAKE_VAL_SE0 0x0
+
+#define PMC_SLEEPWALK_REG(inst) (0x204 + (4*(inst)))
+#define UTMIP_USBOP_RPD_A (1 << 0)
+#define UTMIP_USBON_RPD_A (1 << 1)
+#define UTMIP_AP_A (1 << 4)
+#define UTMIP_AN_A (1 << 5)
+#define UTMIP_HIGHZ_A (1 << 6)
+#define UTMIP_USBOP_RPD_B (1 << 8)
+#define UTMIP_USBON_RPD_B (1 << 9)
+#define UTMIP_AP_B (1 << 12)
+#define UTMIP_AN_B (1 << 13)
+#define UTMIP_HIGHZ_B (1 << 14)
+#define UTMIP_USBOP_RPD_C (1 << 16)
+#define UTMIP_USBON_RPD_C (1 << 17)
+#define UTMIP_AP_C (1 << 20)
+#define UTMIP_AN_C (1 << 21)
+#define UTMIP_HIGHZ_C (1 << 22)
+#define UTMIP_USBOP_RPD_D (1 << 24)
+#define UTMIP_USBON_RPD_D (1 << 25)
+#define UTMIP_AP_D (1 << 28)
+#define UTMIP_AN_D (1 << 29)
+#define UTMIP_HIGHZ_D (1 << 30)
+
+#define UTMIP_STATUS 0x214
+#define UTMIP_WALK_PTR_VAL(inst) (0x3 << ((inst)*2))
+#define UTMIP_USBOP_VAL(inst) (1 << ((2*(inst)) + 8))
+#define UTMIP_USBOP_VAL_P2 (1 << 12)
+#define UTMIP_USBOP_VAL_P1 (1 << 10)
+#define UTMIP_USBOP_VAL_P0 (1 << 8)
+#define UTMIP_USBON_VAL(inst) (1 << ((2*(inst)) + 9))
+#define UTMIP_USBON_VAL_P2 (1 << 13)
+#define UTMIP_USBON_VAL_P1 (1 << 11)
+#define UTMIP_USBON_VAL_P0 (1 << 9)
+#define UTMIP_WAKE_ALARM(inst) (1 << ((inst) + 16))
+#define UTMIP_WAKE_ALARM_P2 (1 << 18)
+#define UTMIP_WAKE_ALARM_P1 (1 << 17)
+#define UTMIP_WAKE_ALARM_P0 (1 << 16)
+#define UTMIP_WALK_PTR(inst) (1 << ((inst)*2))
+#define UTMIP_WALK_PTR_P2 (1 << 4)
+#define UTMIP_WALK_PTR_P1 (1 << 2)
+#define UTMIP_WALK_PTR_P0 (1 << 0)
+
+#define USB1_PREFETCH_ID 6
+#define USB2_PREFETCH_ID 18
+#define USB3_PREFETCH_ID 17
+
+#define PMC_UTMIP_FAKE 0x218
+#define USBON_VAL(inst) (1 << ((4*(inst))+1))
+#define USBON_VAL_P2 (1 << 9)
+#define USBON_VAL_P1 (1 << 5)
+#define USBON_VAL_P0 (1 << 1)
+#define USBOP_VAL(inst) (1 << (4*(inst)))
+#define USBOP_VAL_P2 (1 << 8)
+#define USBOP_VAL_P1 (1 << 4)
+#define USBOP_VAL_P0 (1 << 0)
+
+#define PMC_UTMIP_BIAS_MASTER_CNTRL 0x270
+#define BIAS_MASTER_PROG_VAL (1 << 1)
+
+#define PMC_UTMIP_MASTER_CONFIG 0x274
+#define UTMIP_PWR(inst) (1 << (inst))
+
+#define FUSE_USB_CALIB_0 0x1F0
+#define XCVR_SETUP(x) (((x) & 0x7F) << 0)
+#define XCVR_SETUP_LSB_MASK 0xF
+#define XCVR_SETUP_MSB_MASK 0x70
+#define XCVR_SETUP_LSB_MAX_VAL 0xF
+
+#define APB_MISC_GP_OBSCTRL_0 0x818
+#define APB_MISC_GP_OBSDATA_0 0x81c
+
+#define PADCTL_SNPS_OC_MAP 0xC
+#define CONTROLLER_OC(inst, x) (((x) & 0x7) << (3 * (inst)))
+#define CONTROLLER_OC_P0(x) (((x) & 0x7) << 0)
+#define CONTROLLER_OC_P1(x) (((x) & 0x7) << 3)
+#define CONTROLLER_OC_P2(x) (((x) & 0x7) << 6)
+
+#define PADCTL_OC_DET 0x18
+#define ENABLE0_OC_MAP(x) (((x) & 0x7) << 10)
+#define ENABLE1_OC_MAP(x) (((x) & 0x7) << 13)
+
+/* ULPI GPIO */
+#define ULPI_STP TEGRA_GPIO_PY3
+#define ULPI_DIR TEGRA_GPIO_PY1
+#define ULPI_D0 TEGRA_GPIO_PO1
+#define ULPI_D1 TEGRA_GPIO_PO2
+
+#define TEGRA_STREAM_DISABLE 0x1f8
+#define TEGRA_STREAM_DISABLE_OFFSET (1 << 4)
+
+/* These values (in milli second) are taken from the battery charging spec */
+#define TDP_SRC_ON_MS 100
+#define TDPSRC_CON_MS 40
+
+/* Force port resume wait time in micro second on remote resume */
+#define FPR_WAIT_TIME_US 25000
+
+#ifdef DEBUG
+#define DBG(stuff...) pr_info("tegra11x_usb_phy: " stuff)
+#else
+#define DBG(stuff...) do {} while (0)
+#endif
+
+#if 0
+#define PHY_DBG(stuff...) pr_info("tegra11x_usb_phy: " stuff)
+#else
+#define PHY_DBG(stuff...) do {} while (0)
+#endif
+
+/* define HSIC phy params */
+#define HSIC_SYNC_START_DELAY 9
+#define HSIC_IDLE_WAIT_DELAY 17
+#define HSIC_ELASTIC_UNDERRUN_LIMIT 16
+#define HSIC_ELASTIC_OVERRUN_LIMIT 16
+
+static u32 utmip_rctrl_val, utmip_tctrl_val;
+static DEFINE_SPINLOCK(utmip_pad_lock);
+static int utmip_pad_count;
+
+static struct tegra_xtal_freq utmip_freq_table[] = {
+ {
+ .freq = 12000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x2F,
+ .active_delay = 0x04,
+ .xtal_freq_count = 0x76,
+ .debounce = 0x7530,
+ .pdtrk_count = 5,
+ },
+ {
+ .freq = 13000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x33,
+ .active_delay = 0x05,
+ .xtal_freq_count = 0x7F,
+ .debounce = 0x7EF4,
+ .pdtrk_count = 5,
+ },
+ {
+ .freq = 19200000,
+ .enable_delay = 0x03,
+ .stable_count = 0x4B,
+ .active_delay = 0x06,
+ .xtal_freq_count = 0xBB,
+ .debounce = 0xBB80,
+ .pdtrk_count = 7,
+ },
+ {
+ .freq = 26000000,
+ .enable_delay = 0x04,
+ .stable_count = 0x66,
+ .active_delay = 0x09,
+ .xtal_freq_count = 0xFE,
+ .debounce = 0xFDE8,
+ .pdtrk_count = 9,
+ },
+};
+
+static struct tegra_xtal_freq uhsic_freq_table[] = {
+ {
+ .freq = 12000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x2F,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x1CA,
+ },
+ {
+ .freq = 13000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x33,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x1F0,
+ },
+ {
+ .freq = 19200000,
+ .enable_delay = 0x03,
+ .stable_count = 0x4B,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x2DD,
+ },
+ {
+ .freq = 26000000,
+ .enable_delay = 0x04,
+ .stable_count = 0x66,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x3E0,
+ },
+};
+
+static int _usb_phy_init(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_STS;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ val = readl(base + USB_IF_SPARE);
+ val |= USB_HS_RSM_EOP_EN;
+ val |= USB_PORT_SUSPEND_EN;
+ writel(val, base + USB_IF_SPARE);
+
+ val = readl(base + TEGRA_STREAM_DISABLE);
+#if !defined(CONFIG_TEGRA_SILICON_PLATFORM)
+ val |= TEGRA_STREAM_DISABLE_OFFSET;
+#else
+ val &= ~TEGRA_STREAM_DISABLE_OFFSET;
+#endif
+ writel(val , base + TEGRA_STREAM_DISABLE);
+
+ return 0;
+}
+
+static void usb_phy_fence_read(struct tegra_usb_phy *phy)
+{
+ /* Fence read for coherency of AHB master intiated writes */
+ if (phy->inst == 0)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB1_PREFETCH_ID));
+ else if (phy->inst == 1)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB2_PREFETCH_ID));
+ else if (phy->inst == 2)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB3_PREFETCH_ID));
+ return;
+}
+
+static int usb_phy_reset(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+#if !defined(CONFIG_TEGRA_SILICON_PLATFORM)
+ val = readl(base + TEGRA_STREAM_DISABLE);
+ val |= TEGRA_STREAM_DISABLE_OFFSET;
+ writel(val , base + TEGRA_STREAM_DISABLE);
+#endif
+ val = readl(base + USB_TXFILLTUNING);
+ if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) {
+ val = USB_FIFO_TXFILL_THRES(0x10);
+ writel(val, base + USB_TXFILLTUNING);
+ }
+
+return 0;
+}
+
+static void utmip_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val, pmc_pad_cfg_val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+ void __iomem *base = phy->regs;
+ enum usb_phy_port_speed port_speed;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
+ HOSTPC1_DEVLC_PSPD_MASK;
+ /*Set PMC MASTER bits to do the following
+ * a. Take over the UTMI drivers
+ * b. set up such that it will take over resume
+ * if remote wakeup is detected
+ * Prepare PMC to take over suspend-wake detect-drive resume until USB
+ * controller ready
+ */
+
+ /* disable master enable in PMC */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_MASTER_ENABLE(inst);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* UTMIP_PWR_PX=1 for power savings mode */
+ val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG);
+ val |= UTMIP_PWR(inst);
+ writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG);
+
+ /* config debouncer */
+ val = readl(pmc_base + PMC_USB_DEBOUNCE);
+ val &= ~UTMIP_LINE_DEB_CNT(~0);
+ val |= UTMIP_LINE_DEB_CNT(1);
+ val |= PMC_USB_DEBOUNCE_VAL(2);
+ writel(val, pmc_base + PMC_USB_DEBOUNCE);
+
+ /* Make sure nothing is happening on the line with respect to PMC */
+ val = readl(pmc_base + PMC_UTMIP_FAKE);
+ val &= ~USBOP_VAL(inst);
+ val &= ~USBON_VAL(inst);
+ writel(val, pmc_base + PMC_UTMIP_FAKE);
+
+ /* Make sure wake value for line is none */
+ val = readl(pmc_base + PMC_SLEEPWALK_CFG);
+ val &= ~UTMIP_LINEVAL_WALK_EN(inst);
+ writel(val, pmc_base + PMC_SLEEPWALK_CFG);
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(inst, ~0);
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* turn off pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val |= (USBOP_VAL_PD(inst) | USBON_VAL_PD(inst));
+ writel(val, pmc_base + PMC_USB_AO);
+
+ /* Remove fake values and make synchronizers work a bit */
+ val = readl(pmc_base + PMC_UTMIP_FAKE);
+ val &= ~USBOP_VAL(inst);
+ val &= ~USBON_VAL(inst);
+ writel(val, pmc_base + PMC_UTMIP_FAKE);
+
+ /* Enable which type of event can trigger a walk,
+ * in this case usb_line_wake */
+ val = readl(pmc_base + PMC_SLEEPWALK_CFG);
+ val |= UTMIP_LINEVAL_WALK_EN(inst);
+ writel(val, pmc_base + PMC_SLEEPWALK_CFG);
+
+ /* Capture FS/LS pad configurations */
+ pmc_pad_cfg_val = readl(pmc_base + PMC_PAD_CFG);
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UTMIP_CAP_CFG(inst);
+ writel(val, pmc_base + PMC_TRIGGERS);
+ udelay(1);
+ pmc_pad_cfg_val = readl(pmc_base + PMC_PAD_CFG);
+
+ /* BIAS MASTER_ENABLE=0 */
+ val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+ val &= ~BIAS_MASTER_PROG_VAL;
+ writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+
+ /* program walk sequence for remote or hotplug wakeup */
+ if (phy->port_speed < USB_PHY_PORT_SPEED_UNKNOWN) {
+ /* program walk sequence, maintain a J, followed by a driven K
+ * to signal a resume once an wake event is detected */
+ val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
+ val &= ~UTMIP_AP_A;
+ val |= UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_HIGHZ_A |
+ UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_AP_B |
+ UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_AP_C |
+ UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_AP_D |
+ UTMIP_AN_A | UTMIP_AN_C | UTMIP_AN_B | UTMIP_AN_D ;
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
+
+ if (port_speed == USB_PHY_PORT_SPEED_LOW) {
+ val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
+ val &= ~(UTMIP_AN_B | UTMIP_HIGHZ_B | UTMIP_AN_C |
+ UTMIP_HIGHZ_C | UTMIP_AN_D | UTMIP_HIGHZ_D);
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
+ } else {
+ val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
+ val &= ~(UTMIP_AN_A | UTMIP_AP_B | UTMIP_HIGHZ_B |
+ UTMIP_AP_C | UTMIP_HIGHZ_C | UTMIP_AP_D |
+ UTMIP_HIGHZ_D);
+ val |= UTMIP_AP_A;
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
+ }
+ phy->pmc_remote_wakeup = false;
+ } else {
+ /* program walk sequence, pull down both dp and dn lines,
+ * tristate lines once an hotplug-in wake event is detected */
+ val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
+ val |= UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_HIGHZ_A;
+ val &= ~UTMIP_AP_A;
+ val &= ~UTMIP_AN_A;
+ val |= UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_HIGHZ_B;
+ val &= ~UTMIP_AP_B;
+ val &= ~UTMIP_AN_B;
+ val |= UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_HIGHZ_C;
+ val &= ~UTMIP_AP_C;
+ val &= ~UTMIP_AN_C;
+ val |= UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_HIGHZ_D;
+ val &= ~UTMIP_AP_D;
+ val &= ~UTMIP_AN_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
+ phy->pmc_hotplug_wakeup = false;
+ }
+
+ /* turn on pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val &= ~(USBOP_VAL_PD(inst) | USBON_VAL_PD(inst));
+ writel(val, pmc_base + PMC_USB_AO);
+
+ /* Add small delay before usb detectors provide stable line values */
+ mdelay(1);
+
+ /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */
+ val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+ val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val);
+ writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+
+ /* Turn over pad configuration to PMC for line wake events*/
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(inst, ~0);
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_ANY);
+ val |= UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst);
+ val |= UTMIP_MASTER_ENABLE(inst) | UTMIP_FSLS_USE_PMC(inst);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(base + UTMIP_PMC_WAKEUP0);
+ val |= EVENT_INT_ENB;
+ writel(val, base + UTMIP_PMC_WAKEUP0);
+ PHY_DBG("%s ENABLE_PMC inst = %d\n", __func__, inst);
+}
+
+static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(inst, 0xF);
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(base + UTMIP_PMC_WAKEUP0);
+ val &= ~EVENT_INT_ENB;
+ writel(val, base + UTMIP_PMC_WAKEUP0);
+
+ /* Disable PMC master mode by clearing MASTER_EN */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~(UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) |
+ UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst));
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val &= ~UTMIP_CAP_CFG(inst);
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ /* turn off pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val |= (USBOP_VAL_PD(inst) | USBON_VAL_PD(inst));
+ writel(val, pmc_base + PMC_USB_AO);
+
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UTMIP_CLR_WALK_PTR(inst);
+ val |= UTMIP_CLR_WAKE_ALARM(inst);
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ phy->pmc_remote_wakeup = false;
+ phy->pmc_hotplug_wakeup = false;
+ PHY_DBG("%s DISABLE_PMC inst = %d\n", __func__, inst);
+}
+
+static bool utmi_phy_pmc_wake_detected(struct tegra_usb_phy *phy)
+{
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+ unsigned int inst = phy->inst;
+ u32 val;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(base + UTMIP_PMC_WAKEUP0);
+ if (val & EVENT_INT_ENB) {
+ val = readl(pmc_base + UTMIP_STATUS);
+ if (UTMIP_WAKE_ALARM(inst) & val) {
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(inst, 0xF);
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UTMIP_CLR_WAKE_ALARM(inst);
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ val = readl(base + UTMIP_PMC_WAKEUP0);
+ val &= ~EVENT_INT_ENB;
+ writel(val, base + UTMIP_PMC_WAKEUP0);
+
+ val = readl(pmc_base + UTMIP_STATUS);
+ if (phy->port_speed < USB_PHY_PORT_SPEED_UNKNOWN) {
+ pr_info("%s: utmip remote wake detected\n",
+ __func__);
+ phy->pmc_remote_wakeup = true;
+ } else {
+ phy->pmc_hotplug_wakeup = true;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+static void utmi_phy_enable_trking_data(struct tegra_usb_phy *phy)
+{
+ void __iomem *base = IO_ADDRESS(TEGRA_USB_BASE);
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ static bool init_done = false;
+ u32 val;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ /* Should be done only once after system boot */
+ if (init_done)
+ return;
+
+ clk_enable(phy->utmi_pad_clk);
+ /* Bias pad MASTER_ENABLE=1 */
+ val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+ val |= BIAS_MASTER_PROG_VAL;
+ writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+
+ /* Setting the tracking length time */
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
+ val |= UTMIP_BIAS_PDTRK_COUNT(5);
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ /* Bias PDTRK is Shared and MUST be done from USB1 ONLY, PD_TRK=0 */
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val &= ~UTMIP_BIAS_PDTRK_POWERDOWN;
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val |= UTMIP_BIAS_PDTRK_POWERUP;
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ /* Wait for 25usec */
+ udelay(25);
+
+ /* Bias pad MASTER_ENABLE=0 */
+ val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+ val &= ~BIAS_MASTER_PROG_VAL;
+ writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+
+ /* Wait for 1usec */
+ udelay(1);
+
+ /* Bias pad MASTER_ENABLE=1 */
+ val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+ val |= BIAS_MASTER_PROG_VAL;
+ writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+
+ /* Read RCTRL and TCTRL from UTMIP space */
+ val = readl(base + UTMIP_BIAS_STS0);
+ utmip_rctrl_val = ffz(UTMIP_RCTRL_VAL(val));
+ utmip_tctrl_val = ffz(UTMIP_TCTRL_VAL(val));
+
+ /* PD_TRK=1 */
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val |= UTMIP_BIAS_PDTRK_POWERDOWN;
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */
+ val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+ val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val);
+ writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+ clk_disable(phy->utmi_pad_clk);
+ init_done = true;
+}
+
+static void utmip_powerdown_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+
+ /* power down UTMIP interfaces */
+ val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG);
+ val |= UTMIP_PWR(inst);
+ writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG);
+
+ /* setup sleep walk usb controller */
+ val = UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_HIGHZ_A |
+ UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_HIGHZ_B |
+ UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_HIGHZ_C |
+ UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_HIGHZ_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
+
+ /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */
+ val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+ val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val);
+ writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+
+ /* Turn over pad configuration to PMC */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(inst, ~0);
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE) |
+ UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) |
+ UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+ PHY_DBG("%s ENABLE_PMC inst = %d\n", __func__, inst);
+}
+
+static void utmip_powerup_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+
+ /* Disable PMC master mode by clearing MASTER_EN */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~(UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) |
+ UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst));
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+ mdelay(1);
+ PHY_DBG("%s DISABLE_PMC inst = %d\n", __func__, inst);
+}
+
+
+
+static int usb_phy_bringup_host_controller(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ PHY_DBG("[%d] USB_USBSTS[0x%x] USB_PORTSC[0x%x] port_speed[%d]\n",
+ __LINE__, readl(base + USB_USBSTS), readl(base + USB_PORTSC),
+ phy->port_speed);
+
+ /* Device is plugged in when system is in LP0 */
+ /* Bring up the controller from LP0*/
+ val = readl(base + USB_USBCMD);
+ val |= USB_CMD_RESET;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_CMD_RESET, 0, 2500) < 0) {
+ pr_err("%s: timeout waiting for reset\n", __func__);
+ }
+
+ val = readl(base + USB_USBMODE);
+ val &= ~USB_USBMODE_MASK;
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE);
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PTS(~0);
+
+ if (phy->pdata->phy_intf == TEGRA_USB_PHY_INTF_HSIC)
+ val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
+ else
+ val |= HOSTPC1_DEVLC_STS;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ /* Enable Port Power */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PP;
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ /* Check if the phy resume from LP0. When the phy resume from LP0
+ * USB register will be reset.to zero */
+ if (!readl(base + USB_ASYNCLISTADDR)) {
+ /* Program the field PTC based on the saved speed mode */
+ val = readl(base + USB_PORTSC);
+ val &= ~USB_PORTSC_PTC(~0);
+ if ((phy->port_speed == USB_PHY_PORT_SPEED_HIGH) ||
+ (phy->pdata->phy_intf == TEGRA_USB_PHY_INTF_HSIC))
+ val |= USB_PORTSC_PTC(5);
+ else if (phy->port_speed == USB_PHY_PORT_SPEED_FULL)
+ val |= USB_PORTSC_PTC(6);
+ else if (phy->port_speed == USB_PHY_PORT_SPEED_LOW)
+ val |= USB_PORTSC_PTC(7);
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ /* Disable test mode by setting PTC field to NORMAL_OP */
+ val = readl(base + USB_PORTSC);
+ val &= ~USB_PORTSC_PTC(~0);
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+ }
+
+ /* Poll until CCS is enabled */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_CCS,
+ USB_PORTSC_CCS, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_CCS\n", __func__);
+ }
+
+ /* Poll until PE is enabled */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_PE,
+ USB_PORTSC_PE, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_PE\n", __func__);
+ }
+
+ /* Clear the PCI status, to avoid an interrupt taken upon resume */
+ val = readl(base + USB_USBSTS);
+ val |= USB_USBSTS_PCI;
+ writel(val, base + USB_USBSTS);
+
+ phy->ctrlr_suspended = false;
+ if (!phy->pmc_remote_wakeup) {
+ /* Put controller in suspend mode by writing 1
+ * to SUSP bit of PORTSC */
+ val = readl(base + USB_PORTSC);
+ if ((val & USB_PORTSC_PP) && (val & USB_PORTSC_PE)) {
+ val |= USB_PORTSC_SUSP;
+ writel(val, base + USB_PORTSC);
+ phy->ctrlr_suspended = true;
+ /* Wait until port suspend completes */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC,
+ USB_PORTSC_SUSP, USB_PORTSC_SUSP, 4000)) {
+ pr_err("%s: timeout waiting for PORT_SUSPEND\n",
+ __func__);
+ }
+ }
+ }
+ PHY_DBG("[%d] USB_USBSTS[0x%x] USB_PORTSC[0x%x] port_speed[%d]\n",
+ __LINE__, readl(base + USB_USBSTS), readl(base + USB_PORTSC),
+ phy->port_speed);
+
+ DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n",
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC));
+ return 0;
+}
+
+static unsigned int utmi_phy_xcvr_setup_value(struct tegra_usb_phy *phy)
+{
+ struct tegra_utmi_config *cfg = &phy->pdata->u_cfg.utmi;
+ signed long val;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ if (cfg->xcvr_use_fuses) {
+ val = XCVR_SETUP(tegra_fuse_readl(FUSE_USB_CALIB_0));
+ if (cfg->xcvr_use_lsb) {
+ val = min((unsigned int) ((val & XCVR_SETUP_LSB_MASK)
+ + cfg->xcvr_setup_offset),
+ (unsigned int) XCVR_SETUP_LSB_MAX_VAL);
+ val |= (cfg->xcvr_setup & XCVR_SETUP_MSB_MASK);
+ } else {
+ if (cfg->xcvr_setup_offset <= UTMIP_XCVR_MAX_OFFSET)
+ val = val + cfg->xcvr_setup_offset;
+
+ if (val > UTMIP_XCVR_SETUP_MAX_VALUE) {
+ val = UTMIP_XCVR_SETUP_MAX_VALUE;
+ pr_info("%s: reset XCVR_SETUP to max value\n",
+ __func__);
+ } else if (val < UTMIP_XCVR_SETUP_MIN_VALUE) {
+ val = UTMIP_XCVR_SETUP_MIN_VALUE;
+ pr_info("%s: reset XCVR_SETUP to min value\n",
+ __func__);
+ }
+ }
+ } else {
+ val = cfg->xcvr_setup;
+ }
+
+ return (unsigned int) val;
+}
+
+static int utmi_phy_open(struct tegra_usb_phy *phy)
+{
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned long parent_rate, val;
+ int i;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ phy->utmi_pad_clk = clk_get_sys("utmip-pad", NULL);
+ if (IS_ERR(phy->utmi_pad_clk)) {
+ pr_err("%s: can't get utmip pad clock\n", __func__);
+ return PTR_ERR(phy->utmi_pad_clk);
+ }
+
+ phy->utmi_xcvr_setup = utmi_phy_xcvr_setup_value(phy);
+
+ parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk));
+ for (i = 0; i < ARRAY_SIZE(utmip_freq_table); i++) {
+ if (utmip_freq_table[i].freq == parent_rate) {
+ phy->freq = &utmip_freq_table[i];
+ break;
+ }
+ }
+ if (!phy->freq) {
+ pr_err("invalid pll_u parent rate %ld\n", parent_rate);
+ return -EINVAL;
+ }
+
+ /* Power-up the VBUS detector for UTMIP PHY */
+ val = readl(pmc_base + PMC_USB_AO);
+ val &= ~(PMC_USB_AO_VBUS_WAKEUP_PD_P0);
+ if (phy->pdata->builtin_host_disabled)
+ val |= PMC_USB_AO_ID_PD_P0;
+ else
+ val &= ~PMC_USB_AO_ID_PD_P0;
+ writel(val, (pmc_base + PMC_USB_AO));
+
+ utmip_powerup_pmc_wake_detect(phy);
+
+ return 0;
+}
+
+static void utmi_phy_close(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+
+ DBG("%s inst:[%d]\n", __func__, phy->inst);
+
+ /* Disable PHY clock valid interrupts while going into suspend*/
+ if (phy->hot_plug) {
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_PHY_CLK_VALID_INT_ENB;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ if (val & UTMIP_MASTER_ENABLE(phy->inst))
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+
+ clk_put(phy->utmi_pad_clk);
+}
+
+static int utmi_phy_pad_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val, flags;
+ void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE);
+ void __iomem *clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ val &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
+ writel(val, clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+ clk_enable(phy->utmi_pad_clk);
+
+ spin_lock_irqsave(&utmip_pad_lock, flags);
+ utmip_pad_count++;
+
+ val = readl(pad_base + UTMIP_BIAS_CFG0);
+ val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
+ val |= UTMIP_HSSQUELCH_LEVEL(0x2) | UTMIP_HSDISCON_LEVEL(0x1) |
+ UTMIP_HSDISCON_LEVEL_MSB;
+ writel(val, pad_base + UTMIP_BIAS_CFG0);
+
+ spin_unlock_irqrestore(&utmip_pad_lock, flags);
+
+ clk_disable(phy->utmi_pad_clk);
+
+ return 0;
+}
+
+static int utmi_phy_pad_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val, flags;
+ void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE);
+ void __iomem *clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ clk_enable(phy->utmi_pad_clk);
+ spin_lock_irqsave(&utmip_pad_lock, flags);
+
+ if (!utmip_pad_count) {
+ pr_err("%s: utmip pad already powered off\n", __func__);
+ goto out;
+ }
+ if (--utmip_pad_count == 0) {
+ val = readl(pad_base + UTMIP_BIAS_CFG0);
+ val |= UTMIP_OTGPD | UTMIP_BIASPD;
+ val &= ~(UTMIP_HSSQUELCH_LEVEL(~0) | UTMIP_HSDISCON_LEVEL(~0) |
+ UTMIP_HSDISCON_LEVEL_MSB);
+ writel(val, pad_base + UTMIP_BIAS_CFG0);
+
+ val = readl(clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ val |= UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
+ writel(val, clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ }
+out:
+ spin_unlock_irqrestore(&utmip_pad_lock, flags);
+ clk_disable(phy->utmi_pad_clk);
+
+ return 0;
+}
+
+static int utmi_phy_irq(struct tegra_usb_phy *phy)
+{
+ void __iomem *base = phy->regs;
+ unsigned long val = 0;
+ bool remote_wakeup = false;
+ int irq_status = IRQ_HANDLED;
+
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n",
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC));
+ DBG("USB_USBMODE[0x%x] USB_USBCMD[0x%x]\n",
+ readl(base + USB_USBMODE), readl(base + USB_USBCMD));
+ }
+
+ usb_phy_fence_read(phy);
+ /* check if it is pmc wake event */
+ if (utmi_phy_pmc_wake_detected(phy))
+ remote_wakeup = phy->pmc_remote_wakeup;
+
+ if (phy->hot_plug) {
+ val = readl(base + USB_SUSP_CTRL);
+ if ((val & USB_PHY_CLK_VALID_INT_STS) &&
+ (val & USB_PHY_CLK_VALID_INT_ENB)) {
+ val &= ~USB_PHY_CLK_VALID_INT_ENB |
+ USB_PHY_CLK_VALID_INT_STS;
+ writel(val , (base + USB_SUSP_CTRL));
+
+ /* In case of remote wakeup PHY clock will not up
+ * immediately, so should not access any controller
+ * register but normal plug-in/plug-out should be
+ * executed
+ */
+ if (!remote_wakeup) {
+ val = readl(base + USB_USBSTS);
+ if (!(val & USB_USBSTS_PCI)) {
+ irq_status = IRQ_NONE;
+ goto exit;
+ }
+
+ val = readl(base + USB_PORTSC);
+ if (val & USB_PORTSC_CCS)
+ val &= ~USB_PORTSC_WKCN;
+ else
+ val &= ~USB_PORTSC_WKDS;
+ val &= ~USB_PORTSC_RWC_BITS;
+ writel(val , (base + USB_PORTSC));
+ }
+ } else if (!phy->phy_clk_on) {
+ if (remote_wakeup)
+ irq_status = IRQ_HANDLED;
+ else
+ irq_status = IRQ_NONE;
+ goto exit;
+ }
+ }
+exit:
+ return irq_status;
+}
+
+static int utmi_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ if (val & UTMIP_MASTER_ENABLE(inst)) {
+ if (!remote_wakeup)
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+ }
+
+ return 0;
+}
+
+static int utmi_phy_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ PHY_DBG("%s(%d) inst:[%d] BEGIN\n", __func__, __LINE__, phy->inst);
+ if (!phy->phy_clk_on) {
+ PHY_DBG("%s(%d) inst:[%d] phy clk is already off\n",
+ __func__, __LINE__, phy->inst);
+ return 0;
+ }
+
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
+ utmip_powerdown_pmc_wake_detect(phy);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
+ val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ } else {
+ phy->port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
+ HOSTPC1_DEVLC_PSPD_MASK;
+
+ /* Disable interrupts */
+ writel(0, base + USB_USBINTR);
+
+ /* Clear the run bit to stop SOFs when USB is suspended */
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_HCH,
+ USB_USBSTS_HCH, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBSTS_HCH\n"
+ , __func__);
+ }
+ utmip_setup_pmc_wake_detect(phy);
+ }
+
+ if (!phy->hot_plug) {
+ val = readl(base + UTMIP_XCVR_CFG0);
+ val |= (UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
+ UTMIP_FORCE_PDZI_POWERDOWN);
+ writel(val, base + UTMIP_XCVR_CFG0);
+ }
+
+ val = readl(base + UTMIP_XCVR_CFG1);
+ val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
+ UTMIP_FORCE_PDDR_POWERDOWN;
+ writel(val, base + UTMIP_XCVR_CFG1);
+
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ if (phy->hot_plug) {
+ bool enable_hotplug = true;
+ /* if it is OTG port then make sure to enable hot-plug feature
+ only if host adaptor is connected, i.e id is low */
+ if (phy->pdata->port_otg) {
+ val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+ enable_hotplug = (val & USB_ID_STATUS) ? false : true;
+ }
+ if (enable_hotplug) {
+ /* Enable wakeup event of device plug-in/plug-out */
+ val = readl(base + USB_PORTSC);
+ if (val & USB_PORTSC_CCS)
+ val |= USB_PORTSC_WKDS;
+ else
+ val |= USB_PORTSC_WKCN;
+ writel(val, base + USB_PORTSC);
+
+ if (val & USB_PORTSC_CCS) {
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_PHY_CLK_VALID_INT_ENB;
+ } else {
+ val = readl(base + USB_SUSP_CTRL);
+ val |= USB_PHY_CLK_VALID_INT_ENB;
+ }
+ writel(val, base + USB_SUSP_CTRL);
+ } else {
+ /* Disable PHY clock valid interrupts while going into suspend*/
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_PHY_CLK_VALID_INT_ENB;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+ }
+
+ utmi_phy_pad_power_off(phy);
+
+ /* Disable PHY clock */
+ val = readl(base + HOSTPC1_DEVLC);
+ val |= HOSTPC1_DEVLC_PHCD;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ if (!phy->hot_plug) {
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+
+ PHY_DBG("%s(%d) inst:[%d] END\n", __func__, __LINE__, phy->inst);
+
+ return 0;
+}
+
+
+static int utmi_phy_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+ void __iomem *padctl_base = IO_ADDRESS(TEGRA_XUSB_PADCTL_BASE);
+#endif
+ struct tegra_utmi_config *config = &phy->pdata->u_cfg.utmi;
+
+ PHY_DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->phy_clk_on) {
+ PHY_DBG("%s(%d) inst:[%d] phy clk is already On\n",
+ __func__, __LINE__, phy->inst);
+ return 0;
+ }
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_TX_CFG0);
+ val |= UTMIP_FS_PREABMLE_J;
+ writel(val, base + UTMIP_TX_CFG0);
+
+ val = readl(base + USB_USBMODE);
+ val &= ~USB_USBMODE_MASK;
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST)
+ val |= USB_USBMODE_HOST;
+ else
+ val |= USB_USBMODE_DEVICE;
+ writel(val, base + USB_USBMODE);
+
+ val = readl(base + UTMIP_HSRX_CFG0);
+ val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0));
+ val |= UTMIP_IDLE_WAIT(config->idle_wait_delay);
+ val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit);
+ writel(val, base + UTMIP_HSRX_CFG0);
+
+ val = readl(base + UTMIP_HSRX_CFG1);
+ val &= ~UTMIP_HS_SYNC_START_DLY(~0);
+ val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay);
+ writel(val, base + UTMIP_HSRX_CFG1);
+
+ val = readl(base + UTMIP_DEBOUNCE_CFG0);
+ val &= ~UTMIP_BIAS_DEBOUNCE_A(~0);
+ val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce);
+ writel(val, base + UTMIP_DEBOUNCE_CFG0);
+
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val &= ~UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ } else {
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ }
+
+ utmi_phy_pad_power_on(phy);
+
+ val = readl(base + UTMIP_XCVR_CFG0);
+ val &= ~(UTMIP_XCVR_LSBIAS_SEL | UTMIP_FORCE_PD_POWERDOWN |
+ UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN |
+ UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_LSFSLEW(~0) |
+ UTMIP_XCVR_LSRSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0));
+ val |= UTMIP_XCVR_SETUP(phy->utmi_xcvr_setup);
+ val |= UTMIP_XCVR_SETUP_MSB(XCVR_SETUP_MSB_CALIB(phy->utmi_xcvr_setup));
+ val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
+ val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
+ if (!config->xcvr_use_lsb)
+ val |= UTMIP_XCVR_HSSLEW_MSB(0x3);
+ writel(val, base + UTMIP_XCVR_CFG0);
+
+ val = readl(base + UTMIP_XCVR_CFG1);
+ val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
+ UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0));
+ val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
+ writel(val, base + UTMIP_XCVR_CFG1);
+
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
+ val |= UTMIP_BIAS_PDTRK_COUNT(phy->freq->pdtrk_count);
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ val = readl(base + UTMIP_SPARE_CFG0);
+ val &= ~FUSE_SETUP_SEL;
+ val |= FUSE_ATERM_SEL;
+ writel(val, base + UTMIP_SPARE_CFG0);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PHCD;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500))
+ pr_warn("%s: timeout waiting for phy to stabilize\n", __func__);
+
+ utmi_phy_enable_trking_data(phy);
+
+ if (phy->inst == 2)
+ writel(0, base + ICUSB_CTRL);
+
+ val = readl(base + USB_USBMODE);
+ val &= ~USB_USBMODE_MASK;
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST)
+ val |= USB_USBMODE_HOST;
+ else
+ val |= USB_USBMODE_DEVICE;
+ writel(val, base + USB_USBMODE);
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PTS(~0);
+ val |= HOSTPC1_DEVLC_STS;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE)
+ utmip_powerup_pmc_wake_detect(phy);
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+ val = readl(padctl_base + PADCTL_SNPS_OC_MAP);
+ val |= CONTROLLER_OC(phy->inst, 0x4);
+ writel(val, padctl_base + PADCTL_SNPS_OC_MAP);
+
+ val = readl(padctl_base + PADCTL_OC_DET);
+ if (phy->inst == 0)
+ val |= ENABLE0_OC_MAP(config->vbus_oc_map);
+ if (phy->inst == 2)
+ val |= ENABLE1_OC_MAP(config->vbus_oc_map);
+ writel(val, padctl_base + PADCTL_OC_DET);
+#endif
+
+ PHY_DBG("%s(%d) End inst:[%d]\n", __func__, __LINE__, phy->inst);
+ return 0;
+}
+
+static void utmi_phy_restore_start(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ int inst = phy->inst;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(pmc_base + UTMIP_STATUS);
+ /* Check whether we wake up from the remote resume.
+ For lp1 case, pmc is not responsible for waking the
+ system, it's the flow controller and hence
+ UTMIP_WALK_PTR_VAL(inst) will return 0.
+ Also, for lp1 case phy->pmc_remote_wakeup will already be set
+ to true by utmi_phy_irq() when the remote wakeup happens.
+ Hence change the logic in the else part to enter only
+ if phy->pmc_remote_wakeup is not set to true by the
+ utmi_phy_irq(). */
+ if (UTMIP_WALK_PTR_VAL(inst) & val) {
+ phy->pmc_remote_wakeup = true;
+ }
+}
+
+static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
+{
+ unsigned long val, flags = 0;
+ void __iomem *base = phy->regs;
+ int wait_time_us = 25000; /* FPR should be set by this time */
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ /* check whether we wake up from the remote resume */
+ if (phy->pmc_remote_wakeup) {
+ /* wait until SUSPEND and RESUME bit
+ * is cleared on remote resume */
+ do {
+ val = readl(base + USB_PORTSC);
+ udelay(1);
+ if (wait_time_us == 0) {
+ PHY_DBG("%s PMC FPR" \
+ "timeout val = 0x%lx instance = %d\n", \
+ __func__, val, phy->inst);
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+ return;
+ }
+ wait_time_us--;
+ } while (val & (USB_PORTSC_RESUME | USB_PORTSC_SUSP));
+
+ local_irq_save(flags);
+ /* disable PMC master control */
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ local_irq_restore(flags);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS,
+ USB_USBCMD_RS, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBCMD_RS\n",\
+ __func__);
+ }
+
+ /* Clear PCI and SRI bits to avoid an interrupt upon resume */
+ val = readl(base + USB_USBSTS);
+ writel(val, base + USB_USBSTS);
+ /* wait to avoid SOF if there is any */
+ if (usb_phy_reg_status_wait(base + USB_USBSTS,
+ USB_USBSTS_SRI, USB_USBSTS_SRI, 2500) < 0) {
+ pr_err("%s: timeout waiting for SOF\n", __func__);
+ }
+ } else {
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+ }
+}
+
+static int utmi_phy_resume(struct tegra_usb_phy *phy)
+{
+ int status = 0;
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) {
+ if (readl(base + USB_ASYNCLISTADDR) &&
+ !phy->pdata->u_data.host.power_off_on_suspend)
+ return 0;
+
+ if (phy->port_speed < USB_PHY_PORT_SPEED_UNKNOWN) {
+ utmi_phy_restore_start(phy);
+ usb_phy_bringup_host_controller(phy);
+ utmi_phy_restore_end(phy);
+ } else {
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+
+ /* bring up the controller from suspend*/
+ val = readl(base + USB_USBCMD);
+ val |= USB_CMD_RESET;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_CMD_RESET, 0, 2500) < 0) {
+ pr_err("%s: timeout waiting for reset\n", __func__);
+ }
+
+ val = readl(base + USB_USBMODE);
+ val &= ~USB_USBMODE_MASK;
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE);
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PTS(~0);
+ val |= HOSTPC1_DEVLC_STS;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ writel(USB_USBCMD_RS, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_USBCMD_RS, USB_USBCMD_RS, 2500) < 0) {
+ pr_err("%s: timeout waiting for run bit\n", __func__);
+ }
+
+ /* Enable Port Power */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PP;
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n",
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC));
+ }
+ }
+
+ return status;
+}
+
+static bool utmi_phy_charger_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ bool status;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->pdata->op_mode != TEGRA_USB_OPMODE_DEVICE) {
+ /* Charger detection is not there for ULPI
+ * return Charger not available */
+ return false;
+ }
+
+ /* Enable charger detection logic */
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+ /* Source should be on for 100 ms as per USB charging spec */
+ msleep(TDP_SRC_ON_MS);
+
+ val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+ /* If charger is not connected disable the interrupt */
+ val &= ~VDAT_DET_INT_EN;
+ val |= VDAT_DET_CHG_DET;
+ writel(val, base + USB_PHY_VBUS_WAKEUP_ID);
+
+ val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+ if (val & VDAT_DET_STS)
+ status = true;
+ else
+ status = false;
+
+ /* Disable charger detection logic */
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val &= ~(UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN);
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+ /* Delay of 40 ms before we pull the D+ as per battery charger spec */
+ msleep(TDPSRC_CON_MS);
+
+ return status;
+}
+
+static void uhsic_powerup_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+
+ DBG("%s:%d\n", __func__, __LINE__);
+
+ /* turn on pad detectors for HSIC*/
+ val = readl(pmc_base + PMC_USB_AO);
+ val &= ~(HSIC_RESERVED(inst) | STROBE_VAL_PD(inst) | DATA_VAL_PD(inst));
+ writel(val, pmc_base + PMC_USB_AO);
+
+ /* Disable PMC master mode by clearing MASTER_EN */
+ val = readl(pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+ val &= ~(UHSIC_MASTER_ENABLE(inst));
+ writel(val, pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+ mdelay(1);
+}
+
+static void uhsic_powerdown_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+
+ DBG("%s:%d\n", __func__, __LINE__);
+
+ /* turn off pad detectors for HSIC*/
+ val = readl(pmc_base + PMC_USB_AO);
+ val |= (HSIC_RESERVED(inst) | STROBE_VAL_PD(inst) | DATA_VAL_PD(inst));
+ writel(val, pmc_base + PMC_USB_AO);
+
+ /* enable pull downs on HSIC PMC */
+ val = UHSIC_STROBE_RPD_A | UHSIC_DATA_RPD_A | UHSIC_STROBE_RPD_B |
+ UHSIC_DATA_RPD_B | UHSIC_STROBE_RPD_C | UHSIC_DATA_RPD_C |
+ UHSIC_STROBE_RPD_D | UHSIC_DATA_RPD_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC(inst));
+
+ /* Turn over pad configuration to PMC */
+ val = readl(pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+ val &= ~UHSIC_WAKE_VAL(inst, ~0);
+ val |= UHSIC_WAKE_VAL(inst, WAKE_VAL_NONE) | UHSIC_MASTER_ENABLE(inst);
+ writel(val, pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+}
+
+static void uhsic_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+ bool port_connected;
+ unsigned int inst = phy->inst;
+
+ DBG("%s:%d\n", __func__, __LINE__);
+
+ /* check for port connect status */
+ val = readl(base + USB_PORTSC);
+ port_connected = val & USB_PORTSC_CCS;
+
+ if (!port_connected)
+ return;
+
+ /*Set PMC MASTER bits to do the following
+ * a. Take over the hsic drivers
+ * b. set up such that it will take over resume
+ * if remote wakeup is detected
+ * Prepare PMC to take over suspend-wake detect-drive resume until USB
+ * controller ready
+ */
+
+ /* disable master enable in PMC */
+ val = readl(pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+ val &= ~UHSIC_MASTER_ENABLE(inst);
+ writel(val, pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+
+ /* UTMIP_PWR_PX=1 for power savings mode */
+ val = readl(pmc_base + PMC_UHSIC_MASTER_CONFIG(inst));
+ val |= UHSIC_PWR(inst);
+ writel(val, pmc_base + PMC_UHSIC_MASTER_CONFIG(inst));
+
+ /* config debouncer */
+ val = readl(pmc_base + PMC_USB_DEBOUNCE);
+ val |= PMC_USB_DEBOUNCE_VAL(2);
+ writel(val, pmc_base + PMC_USB_DEBOUNCE);
+
+ /* Make sure nothing is happening on the line with respect to PMC */
+ val = readl(pmc_base + PMC_UHSIC_FAKE(inst));
+ val &= ~UHSIC_FAKE_STROBE_VAL(inst);
+ val &= ~UHSIC_FAKE_DATA_VAL(inst);
+ writel(val, pmc_base + PMC_UHSIC_FAKE(inst));
+
+ /* Clear walk enable */
+ val = readl(pmc_base + PMC_UHSIC_SLEEPWALK_CFG(inst));
+ val &= ~UHSIC_LINEVAL_WALK_EN(inst);
+ writel(val, pmc_base + PMC_UHSIC_SLEEPWALK_CFG(inst));
+
+ /* Make sure wake value for line is none */
+ val = readl(pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+ val &= ~UHSIC_WAKE_VAL(inst, WAKE_VAL_ANY);
+ val |= UHSIC_WAKE_VAL(inst, WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+
+ /* turn on pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val &= ~(STROBE_VAL_PD(inst) | DATA_VAL_PD(inst));
+ writel(val, pmc_base + PMC_USB_AO);
+
+ /* Add small delay before usb detectors provide stable line values */
+ udelay(1);
+
+ /* Enable which type of event can trigger a walk,
+ * in this case usb_line_wake */
+ val = readl(pmc_base + PMC_UHSIC_SLEEPWALK_CFG(inst));
+ val |= UHSIC_LINEVAL_WALK_EN(inst);
+ writel(val, pmc_base + PMC_UHSIC_SLEEPWALK_CFG(inst));
+
+ /* program walk sequence, maintain a J, followed by a driven K
+ * to signal a resume once an wake event is detected */
+
+ val = readl(pmc_base + PMC_SLEEPWALK_UHSIC(inst));
+
+ val &= ~UHSIC_DATA_RPU_A;
+ val |= UHSIC_DATA_RPD_A;
+ val &= ~UHSIC_STROBE_RPD_A;
+ val |= UHSIC_STROBE_RPU_A;
+
+ val &= ~UHSIC_DATA_RPD_B;
+ val |= UHSIC_DATA_RPU_B;
+ val &= ~UHSIC_STROBE_RPU_B;
+ val |= UHSIC_STROBE_RPD_B;
+
+ val &= ~UHSIC_DATA_RPD_C;
+ val |= UHSIC_DATA_RPU_C;
+ val &= ~UHSIC_STROBE_RPU_C;
+ val |= UHSIC_STROBE_RPD_C;
+
+ val &= ~UHSIC_DATA_RPD_D;
+ val |= UHSIC_DATA_RPU_D;
+ val &= ~UHSIC_STROBE_RPU_D;
+ val |= UHSIC_STROBE_RPD_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC(inst));
+
+ phy->pmc_remote_wakeup = false;
+
+ /* Setting Wake event*/
+ val = readl(pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+ val &= ~UHSIC_WAKE_VAL(inst, WAKE_VAL_ANY);
+ val |= UHSIC_WAKE_VAL(inst, WAKE_VAL_SD10);
+ writel(val, pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+
+ /* Clear the walk pointers and wake alarm */
+ val = readl(pmc_base + PMC_UHSIC_TRIGGERS(inst));
+ val |= UHSIC_CLR_WAKE_ALARM(inst) | UHSIC_CLR_WALK_PTR(inst);
+ writel(val, pmc_base + PMC_UHSIC_TRIGGERS(inst));
+
+ /* Turn over pad configuration to PMC for line wake events*/
+ val = readl(pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+ val |= UHSIC_MASTER_ENABLE(inst);
+ writel(val, pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+
+ val = readl(base + UHSIC_PMC_WAKEUP0);
+ val |= EVENT_INT_ENB;
+ writel(val, base + UHSIC_PMC_WAKEUP0);
+
+ DBG("%s:PMC enabled for HSIC remote wakeup\n", __func__);
+}
+
+static void uhsic_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+ unsigned int inst = phy->inst;
+
+ DBG("%s (%d)\n", __func__, __LINE__);
+ val = readl(pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+ val &= ~UHSIC_WAKE_VAL(inst, WAKE_VAL_ANY);
+ val |= UHSIC_WAKE_VAL(inst, WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+
+ val = readl(base + UHSIC_PMC_WAKEUP0);
+ val &= ~EVENT_INT_ENB;
+ writel(val, base + UHSIC_PMC_WAKEUP0);
+
+ /*
+ * If pmc wakeup is detected after putting controller in suspend
+ * in usb_phy_bringup_host_cotroller, restart bringing up host
+ * controller as in case of only pmc wakeup.
+ */
+ if (phy->pmc_remote_wakeup && phy->ctrlr_suspended) {
+ usb_phy_bringup_host_controller(phy);
+ if (usb_phy_reg_status_wait(base + USB_PORTSC,
+ (USB_PORTSC_RESUME | USB_PORTSC_SUSP), 0,
+ FPR_WAIT_TIME_US) < 0)
+ pr_err("%s: timeout waiting for SUSPEND to clear\n",
+ __func__);
+ phy->ctrlr_suspended = false;
+ }
+
+ /* Disable PMC master mode by clearing MASTER_EN */
+ val = readl(pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+ val &= ~(UHSIC_MASTER_ENABLE(inst));
+ writel(val, pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+
+ /* turn off pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val |= (STROBE_VAL_PD(inst) | DATA_VAL_PD(inst));
+ writel(val, pmc_base + PMC_USB_AO);
+
+ val = readl(pmc_base + PMC_UHSIC_TRIGGERS(inst));
+ val |= (UHSIC_CLR_WALK_PTR(inst) | UHSIC_CLR_WAKE_ALARM(inst));
+ writel(val, pmc_base + PMC_UHSIC_TRIGGERS(inst));
+
+ phy->pmc_remote_wakeup = false;
+}
+
+static bool uhsic_phy_remotewake_detected(struct tegra_usb_phy *phy)
+{
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+ u32 val;
+ unsigned int inst = phy->inst;
+
+ val = readl(base + UHSIC_PMC_WAKEUP0);
+ if (!(val & EVENT_INT_ENB))
+ return false;
+ val = readl(pmc_base + UHSIC_STATUS(inst));
+ if (!(UHSIC_WAKE_ALARM(inst) & val))
+ return false;
+ val = readl(pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+ val &= ~UHSIC_WAKE_VAL(inst, WAKE_VAL_ANY);
+ val |= UHSIC_WAKE_VAL(inst, WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
+
+ val = readl(pmc_base + PMC_UHSIC_TRIGGERS(inst));
+ val |= UHSIC_CLR_WAKE_ALARM(inst);
+ writel(val, pmc_base + PMC_UHSIC_TRIGGERS(inst));
+
+ val = readl(base + UHSIC_PMC_WAKEUP0);
+ val &= ~EVENT_INT_ENB;
+ writel(val, base + UHSIC_PMC_WAKEUP0);
+ phy->pmc_remote_wakeup = true;
+ DBG("%s:PMC remote wakeup detected for HSIC\n", __func__);
+ return true;
+}
+
+static int uhsic_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ if (remote_wakeup) {
+ /* Set RUN bit */
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ }
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ return 0;
+}
+
+static void uhsic_phy_restore_start(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+ unsigned int inst = phy->inst;
+
+ val = readl(pmc_base + UHSIC_STATUS(inst));
+
+ /* check whether we wake up from the remote resume */
+ if (UHSIC_WALK_PTR_VAL(inst) & val) {
+ phy->pmc_remote_wakeup = true;
+ DBG("%s: uhsic remote wakeup detected\n", __func__);
+ } else {
+ if (!((UHSIC_STROBE_VAL(inst) | UHSIC_DATA_VAL(inst)) & val)) {
+ uhsic_phy_disable_pmc_bus_ctrl(phy);
+ } else {
+ DBG("%s(%d): setting pretend connect\n", __func__, __LINE__);
+ val = readl(base + UHSIC_CMD_CFG0);
+ val |= UHSIC_PRETEND_CONNECT_DETECT;
+ writel(val, base + UHSIC_CMD_CFG0);
+ }
+ }
+}
+
+static void uhsic_phy_restore_end(struct tegra_usb_phy *phy)
+{
+
+ unsigned long val, flags = 0;
+ void __iomem *base = phy->regs;
+ int wait_time_us = FPR_WAIT_TIME_US; /* FPR should be set by this time */
+ bool irq_disabled = false;
+
+ DBG("%s(%d)\n", __func__, __LINE__);
+
+ /*
+ * check whether we wake up from the remote wake detected before putting
+ * controller in suspend in usb_phy_bringup_host_controller.
+ */
+ if (!phy->ctrlr_suspended) {
+ /* wait until FPR bit is set automatically on remote resume */
+ do {
+ val = readl(base + USB_PORTSC);
+ udelay(1);
+ if (wait_time_us == 0) {
+ uhsic_phy_disable_pmc_bus_ctrl(phy);
+ return;
+ }
+ wait_time_us--;
+ } while (val & (USB_PORTSC_RESUME | USB_PORTSC_SUSP));
+ /* In case of remote wakeup, disable local irq to prevent
+ * context switch b/t disable PMC and set RUN bit ops */
+ local_irq_save(flags);
+ irq_disabled = true;
+ }
+ /* disable PMC master control */
+ uhsic_phy_disable_pmc_bus_ctrl(phy);
+
+ /* Set RUN bit */
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ /* Restore local irq if disabled before */
+ if (irq_disabled)
+ local_irq_restore(flags);
+ if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS,
+ USB_USBCMD_RS, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__);
+ return;
+ }
+}
+
+static int uhsic_rail_enable(struct tegra_usb_phy *phy)
+{
+ int ret;
+
+ if (phy->hsic_reg == NULL) {
+ phy->hsic_reg = regulator_get(&phy->pdev->dev, "vddio_hsic");
+ if (IS_ERR_OR_NULL(phy->hsic_reg)) {
+ pr_err("UHSIC: Could not get regulator vddio_hsic\n");
+ ret = PTR_ERR(phy->hsic_reg);
+ phy->hsic_reg = NULL;
+ return ret;
+ }
+ }
+
+ ret = regulator_enable(phy->hsic_reg);
+ if (ret < 0) {
+ pr_err("%s vddio_hsic could not be enabled\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int uhsic_rail_disable(struct tegra_usb_phy *phy)
+{
+ int ret;
+
+ if (phy->hsic_reg == NULL) {
+ pr_warn("%s: unbalanced disable\n", __func__);
+ return -EIO;
+ }
+
+ ret = regulator_disable(phy->hsic_reg);
+ if (ret < 0) {
+ pr_err("HSIC regulator vddio_hsic cannot be disabled\n");
+ return ret;
+ }
+ regulator_put(phy->hsic_reg);
+ phy->hsic_reg = NULL;
+ return 0;
+}
+
+static int uhsic_phy_open(struct tegra_usb_phy *phy)
+{
+ unsigned long parent_rate;
+ int i;
+ int ret;
+
+ phy->hsic_reg = NULL;
+ ret = uhsic_rail_enable(phy);
+ if (ret < 0) {
+ pr_err("%s vddio_hsic could not be enabled\n", __func__);
+ return ret;
+ }
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk));
+ for (i = 0; i < ARRAY_SIZE(uhsic_freq_table); i++) {
+ if (uhsic_freq_table[i].freq == parent_rate) {
+ phy->freq = &uhsic_freq_table[i];
+ break;
+ }
+ }
+ if (!phy->freq) {
+ pr_err("invalid pll_u parent rate %ld\n", parent_rate);
+ return -EINVAL;
+ }
+
+ uhsic_powerup_pmc_wake_detect(phy);
+
+ return 0;
+}
+
+static void uhsic_phy_close(struct tegra_usb_phy *phy)
+{
+ int ret;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ uhsic_powerdown_pmc_wake_detect(phy);
+
+ ret = uhsic_rail_disable(phy);
+ if (ret < 0)
+ pr_err("%s vddio_hsic could not be disabled\n", __func__);
+}
+
+static int uhsic_phy_irq(struct tegra_usb_phy *phy)
+{
+ /* check if there is any remote wake event */
+ usb_phy_fence_read(phy);
+ if (uhsic_phy_remotewake_detected(phy))
+ DBG("%s: uhsic remote wake detected\n", __func__);
+ return IRQ_HANDLED;
+}
+
+static int uhsic_phy_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+ void __iomem *padctl_base = IO_ADDRESS(TEGRA_XUSB_PADCTL_BASE);
+#endif
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already On\n",
+ __func__, __LINE__, phy->inst);
+ return 0;
+ }
+
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+ val = readl(padctl_base + PADCTL_SNPS_OC_MAP);
+ val |= CONTROLLER_OC(phy->inst, 0x7);
+ writel(val, padctl_base + PADCTL_SNPS_OC_MAP);
+#endif
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~(UHSIC_PD_BG | UHSIC_PD_RX |
+ UHSIC_PD_ZI | UHSIC_RPD_DATA | UHSIC_RPD_STROBE);
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ val |= (UHSIC_RX_SEL | UHSIC_PD_TX);
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(1);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UHSIC_HSRX_CFG0);
+ val |= UHSIC_IDLE_WAIT(HSIC_IDLE_WAIT_DELAY);
+ val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(HSIC_ELASTIC_UNDERRUN_LIMIT);
+ val |= UHSIC_ELASTIC_OVERRUN_LIMIT(HSIC_ELASTIC_OVERRUN_LIMIT);
+ writel(val, base + UHSIC_HSRX_CFG0);
+
+ val = readl(base + UHSIC_HSRX_CFG1);
+ val |= UHSIC_HS_SYNC_START_DLY(HSIC_SYNC_START_DELAY);
+ writel(val, base + UHSIC_HSRX_CFG1);
+
+ /* WAR HSIC TX */
+ val = readl(base + UHSIC_TX_CFG0);
+ val &= ~UHSIC_HS_READY_WAIT_FOR_VALID;
+ writel(val, base + UHSIC_TX_CFG0);
+
+ val = readl(base + UHSIC_MISC_CFG0);
+ val |= UHSIC_SUSPEND_EXIT_ON_EDGE;
+ writel(val, base + UHSIC_MISC_CFG0);
+
+ val = readl(base + UHSIC_MISC_CFG1);
+ val |= UHSIC_PLLU_STABLE_COUNT(phy->freq->stable_count);
+ writel(val, base + UHSIC_MISC_CFG1);
+
+ val = readl(base + UHSIC_PLL_CFG1);
+ val |= UHSIC_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
+ val |= UHSIC_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count);
+ writel(val, base + UHSIC_PLL_CFG1);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~(UHSIC_RESET);
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(1);
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~(UHSIC_PD_TX);
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ /* HSIC pad tracking circuit power down sequence */
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~(UHSIC_PD_TRK);
+ writel(val, base + UHSIC_PADS_CFG1);
+ /* Wait for 25usec */
+ udelay(25);
+ val |= UHSIC_PD_TRK;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ /* Enable bus keepers always */
+ val = readl(base + UHSIC_SPARE_CFG0);
+ val |= FORCE_BK_ON;
+ writel(val, base + UHSIC_SPARE_CFG0);
+
+ /*SUSP_CTRL has to be toggled to enable host PHY clock */
+ val = readl(base + USB_SUSP_CTRL);
+ val |= USB_SUSP_CLR;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_SUSP_CLR;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + USB_USBMODE);
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE);
+
+ /* Change the USB controller PHY type to HSIC */
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK);
+ val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
+ val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK);
+ val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED);
+ val &= ~HOSTPC1_DEVLC_STS;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_WKOC | USB_PORTSC_WKDS | USB_PORTSC_WKCN);
+ writel(val, base + USB_PORTSC);
+
+ val = readl(base + UHSIC_PADS_CFG0);
+ /* Clear RTUNEN, SLEWP & SLEWN bit fields */
+ val &= ~(UHSIC_TX_RTUNEN | UHSIC_TX_SLEWP | UHSIC_TX_SLEWN);
+ /* set Rtune impedance to 50 ohm */
+ val |= UHSIC_TX_RTUNE(0xC);
+ writel(val, base + UHSIC_PADS_CFG0);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500)) {
+ pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+
+ if (phy->pmc_sleepwalk) {
+ DBG("%s(%d) inst:[%d] restore phy\n", __func__, __LINE__,
+ phy->inst);
+ uhsic_phy_restore_start(phy);
+ usb_phy_bringup_host_controller(phy);
+ uhsic_phy_restore_end(phy);
+ phy->pmc_sleepwalk = false;
+ }
+
+ val = readl(base + USB_TXFILLTUNING);
+ if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) {
+ val = USB_FIFO_TXFILL_THRES(0x10);
+ writel(val, base + USB_TXFILLTUNING);
+ }
+
+ return 0;
+}
+
+static int uhsic_phy_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (!phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already off\n",
+ __func__, __LINE__, phy->inst);
+ return 0;
+ }
+
+ /* Disable interrupts */
+ writel(0, base + USB_USBINTR);
+
+ if (phy->pmc_sleepwalk == false) {
+ uhsic_setup_pmc_wake_detect(phy);
+ phy->pmc_sleepwalk = true;
+ }
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val |= HOSTPC1_DEVLC_PHCD;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ /* Enable power downs for HSIC from PADS CFG1 register */
+ val = readl(base + UHSIC_PADS_CFG1);
+ val |= (UHSIC_PD_BG | UHSIC_PD_TRK |
+ UHSIC_PD_ZI | UHSIC_PD_TX);
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PHY_CLK_VALID, 0, 2500))
+ pr_warn("%s: timeout waiting for phy to disable\n", __func__);
+
+ DBG("%s(%d) inst:[%d] End\n", __func__, __LINE__, phy->inst);
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+
+ return 0;
+}
+
+static int uhsic_phy_bus_port_power(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(base + USB_USBMODE);
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE);
+
+ /* Change the USB controller PHY type to HSIC */
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~(HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK));
+ val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
+ val &= ~(HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK));
+ val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED);
+ writel(val, base + HOSTPC1_DEVLC);
+
+ val = readl(base + UHSIC_MISC_CFG0);
+ val |= UHSIC_DETECT_SHORT_CONNECT;
+ writel(val, base + UHSIC_MISC_CFG0);
+ udelay(1);
+ if (phy->pdata->ops && phy->pdata->ops->port_power)
+ phy->pdata->ops->port_power();
+
+ return 0;
+}
+
+static void ulpi_set_trimmer(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ void __iomem *base = phy->regs;
+ unsigned long val;
+
+ val = ULPI_DATA_TRIMMER_SEL(config->data_trimmer);
+ val |= ULPI_STPDIRNXT_TRIMMER_SEL(config->stpdirnxt_trimmer);
+ val |= ULPI_DIR_TRIMMER_SEL(config->dir_trimmer);
+ writel(val, base + ULPI_TIMING_CTRL_1);
+ udelay(10);
+
+ val |= ULPI_DATA_TRIMMER_LOAD;
+ val |= ULPI_STPDIRNXT_TRIMMER_LOAD;
+ val |= ULPI_DIR_TRIMMER_LOAD;
+ writel(val, base + ULPI_TIMING_CTRL_1);
+}
+
+static int ulpi_link_phy_open(struct tegra_usb_phy *phy)
+{
+#if defined(CONFIG_TEGRA_SILICON_PLATFORM)
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+#endif
+ int err = 0;
+
+ phy->ulpi_clk = NULL;
+ DBG("%s inst:[%d]\n", __func__, phy->inst);
+
+#if defined(CONFIG_TEGRA_SILICON_PLATFORM)
+ if (config->clk) {
+ phy->ulpi_clk = clk_get_sys(NULL, config->clk);
+ if (IS_ERR(phy->ulpi_clk)) {
+ pr_err("%s: can't get ulpi clock\n", __func__);
+ err = -ENXIO;
+ }
+ }
+#endif
+ phy->ulpi_vp = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
+ phy->ulpi_vp->io_priv = phy->regs + ULPI_VIEWPORT;
+
+ return err;
+}
+
+static void ulpi_link_phy_close(struct tegra_usb_phy *phy)
+{
+ DBG("%s inst:[%d]\n", __func__, phy->inst);
+ if (phy->ulpi_clk)
+ clk_put(phy->ulpi_clk);
+}
+
+static int ulpi_link_phy_irq(struct tegra_usb_phy *phy)
+{
+ DBG("%s inst:[%d]\n", __func__, phy->inst);
+ return IRQ_HANDLED;
+}
+
+static int ulpi_link_phy_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ int ret;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (!phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already off\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ /* Disable VbusValid, SessEnd comparators */
+ ret = usb_phy_io_write(phy->ulpi_vp, 0x00, 0x0D);
+ if (ret)
+ pr_err("%s: ulpi write 0x0D failed\n", __func__);
+
+ ret = usb_phy_io_write(phy->ulpi_vp, 0x00, 0x10);
+ if (ret)
+ pr_err("%s: ulpi write 0x10 failed\n", __func__);
+
+ /* Disable IdFloat comparator */
+ ret = usb_phy_io_write(phy->ulpi_vp, 0x00, 0x19);
+ if (ret)
+ pr_err("%s: ulpi write 0x19 failed\n", __func__);
+
+ ret = usb_phy_io_write(phy->ulpi_vp, 0x00, 0x1D);
+ if (ret)
+ pr_err("%s: ulpi write 0x1D failed\n", __func__);
+
+ phy->port_speed = (readl(base + USB_PORTSC) >> 26) &
+ USB_PORTSC_PSPD_MASK;
+
+ /* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB
+ * Controller to immediately bring the ULPI PHY out of low power
+ */
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_WKOC | USB_PORTSC_WKDS | USB_PORTSC_WKCN);
+ writel(val, base + USB_PORTSC);
+
+ /* Put the PHY in the low power mode */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PHCD;
+ writel(val, base + USB_PORTSC);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ 0, 2500)) {
+ pr_err("%s: timeout waiting for phy to stop\n", __func__);
+ }
+
+ if (phy->ulpi_clk)
+ clk_disable(phy->ulpi_clk);
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+
+ return 0;
+}
+
+static int ulpi_link_phy_power_on(struct tegra_usb_phy *phy)
+{
+ int ret;
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already On\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ if (phy->ulpi_clk) {
+ clk_enable(phy->ulpi_clk);
+ mdelay(1);
+ }
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= ULPI_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= USB_SUSP_CLR;
+ writel(val, base + USB_SUSP_CTRL);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ USB_PHY_CLK_VALID, 2500))
+ pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_CLKEN,
+ USB_CLKEN, 2500))
+ pr_err("%s: timeout waiting for AHB clock\n", __func__);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_SUSP_CLR;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = 0;
+ writel(val, base + ULPI_TIMING_CTRL_1);
+
+ ulpi_set_trimmer(phy);
+
+ /* Fix VbusInvalid due to floating VBUS */
+ ret = usb_phy_io_write(phy->ulpi_vp, 0x40, 0x08);
+ if (ret) {
+ pr_err("%s: ulpi write failed\n", __func__);
+ return ret;
+ }
+
+ ret = usb_phy_io_write(phy->ulpi_vp, 0x80, 0x0B);
+ if (ret) {
+ pr_err("%s: ulpi write failed\n", __func__);
+ return ret;
+ }
+
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_WKOC | USB_PORTSC_WKDS | USB_PORTSC_WKCN;
+ writel(val, base + USB_PORTSC);
+
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+
+ return 0;
+}
+
+static inline void ulpi_link_phy_set_tristate(bool enable)
+{
+
+}
+
+static void ulpi_link_phy_restore_start(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ /*Tristate ulpi interface before USB controller resume*/
+ ulpi_link_phy_set_tristate(true);
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val &= ~ULPI_OUTPUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+}
+
+static void ulpi_link_phy_restore_end(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_OUTPUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ ulpi_link_phy_set_tristate(false);
+}
+
+static int ulpi_link_phy_resume(struct tegra_usb_phy *phy)
+{
+ int status = 0;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->pdata->u_data.host.power_off_on_suspend) {
+ status = ulpi_link_phy_power_on(phy);
+ if (phy->port_speed < USB_PHY_PORT_SPEED_UNKNOWN) {
+ ulpi_link_phy_restore_start(phy);
+ usb_phy_bringup_host_controller(phy);
+ ulpi_link_phy_restore_end(phy);
+ }
+ }
+
+ return status;
+}
+
+static void reset_utmip_uhsic(void __iomem *base)
+{
+ unsigned long val;
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+}
+
+static void ulpi_set_host(void __iomem *base)
+{
+ unsigned long val;
+
+ val = readl(base + USB_USBMODE);
+ val &= ~USB_USBMODE_MASK;
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE);
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val |= HOSTPC1_DEVLC_PTS(2);
+ writel(val, base + HOSTPC1_DEVLC);
+}
+
+static inline void ulpi_pinmux_bypass(struct tegra_usb_phy *phy, bool enable)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+
+ if (enable)
+ val |= ULPI_OUTPUT_PINMUX_BYP;
+ else
+ val &= ~ULPI_OUTPUT_PINMUX_BYP;
+
+ writel(val, base + ULPI_TIMING_CTRL_0);
+}
+
+static inline void ulpi_null_phy_set_tristate(bool enable)
+{
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+ int tristate = (enable) ? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL;
+ DBG("%s(%d) inst:[%s] FIXME enable pin group +++\n", __func__,
+ __LINE__, enable ? "TRISTATE" : "NORMAL");
+
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA0, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA1, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA2, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA3, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA4, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA5, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA6, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA7, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_NXT, tristate);
+
+ if (enable)
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR, tristate);
+#endif
+}
+
+static void ulpi_null_phy_obs_read(void)
+{
+ static void __iomem *apb_misc;
+ unsigned slv0_obs, s2s_obs;
+
+ if (!apb_misc)
+ apb_misc = ioremap(TEGRA_APB_MISC_BASE, TEGRA_APB_MISC_SIZE);
+
+ writel(0x80d1003c, apb_misc + APB_MISC_GP_OBSCTRL_0);
+ slv0_obs = readl(apb_misc + APB_MISC_GP_OBSDATA_0);
+
+ writel(0x80d10040, apb_misc + APB_MISC_GP_OBSCTRL_0);
+ s2s_obs = readl(apb_misc + APB_MISC_GP_OBSDATA_0);
+
+ pr_debug("slv0 obs: %08x\ns2s obs: %08x\n", slv0_obs, s2s_obs);
+}
+
+static const struct gpio ulpi_gpios[] = {
+ {ULPI_STP, GPIOF_IN, "ULPI_STP"},
+ {ULPI_DIR, GPIOF_OUT_INIT_LOW, "ULPI_DIR"},
+ {ULPI_D0, GPIOF_OUT_INIT_LOW, "ULPI_D0"},
+ {ULPI_D1, GPIOF_OUT_INIT_LOW, "ULPI_D1"},
+};
+
+static int ulpi_null_phy_open(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ int ret;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ ret = gpio_request_array(ulpi_gpios, ARRAY_SIZE(ulpi_gpios));
+ if (ret)
+ return ret;
+
+ if (gpio_is_valid(config->phy_restore_gpio)) {
+ ret = gpio_request(config->phy_restore_gpio, "phy_restore");
+ if (ret)
+ goto err_gpio_free;
+
+ gpio_direction_input(config->phy_restore_gpio);
+ }
+
+ tegra_periph_reset_assert(phy->ctrlr_clk);
+ udelay(10);
+ tegra_periph_reset_deassert(phy->ctrlr_clk);
+
+ return 0;
+
+err_gpio_free:
+ gpio_free_array(ulpi_gpios, ARRAY_SIZE(ulpi_gpios));
+ return ret;
+}
+
+static void ulpi_null_phy_close(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ if (gpio_is_valid(config->phy_restore_gpio))
+ gpio_free(config->phy_restore_gpio);
+
+ gpio_free_array(ulpi_gpios, ARRAY_SIZE(ulpi_gpios));
+}
+
+static int ulpi_null_phy_power_off(struct tegra_usb_phy *phy)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ if (!phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already off\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+ ulpi_null_phy_set_tristate(true);
+ return 0;
+}
+
+/* NOTE: this function must be called before ehci reset */
+static int ulpi_null_phy_init(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ _usb_phy_init(phy);
+ val = readl(base + ULPIS2S_CTRL);
+ val |= ULPIS2S_SLV0_CLAMP_XMIT;
+ writel(val, base + ULPIS2S_CTRL);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= ULPIS2S_SLV0_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(10);
+
+ return 0;
+}
+
+static int ulpi_null_phy_irq(struct tegra_usb_phy *phy)
+{
+ return IRQ_HANDLED;
+}
+
+/* NOTE: this function must be called after ehci reset */
+static int ulpi_null_phy_cmd_reset(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ ulpi_set_host(base);
+
+ /* remove slave0 reset */
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~ULPIS2S_SLV0_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + ULPIS2S_CTRL);
+ val &= ~ULPIS2S_SLV0_CLAMP_XMIT;
+ writel(val, base + ULPIS2S_CTRL);
+ udelay(10);
+
+ return 0;
+}
+
+static int ulpi_null_phy_restore(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ unsigned long timeout;
+ int ulpi_stp = ULPI_STP;
+
+ if (gpio_is_valid(config->phy_restore_gpio))
+ ulpi_stp = config->phy_restore_gpio;
+
+ /* disable ULPI pinmux bypass */
+ ulpi_pinmux_bypass(phy, false);
+
+ /* driving linstate by GPIO */
+ gpio_set_value(ULPI_D0, 0);
+ gpio_set_value(ULPI_D1, 0);
+
+ /* driving DIR high */
+ gpio_set_value(ULPI_DIR, 1);
+
+ /* remove ULPI tristate */
+ ulpi_null_phy_set_tristate(false);
+
+ /* wait for STP high */
+ timeout = jiffies + msecs_to_jiffies(25);
+
+ while (!gpio_get_value(ulpi_stp)) {
+ if (time_after(jiffies, timeout)) {
+ pr_warn("phy restore timeout\n");
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int ulpi_null_phy_lp0_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ ulpi_null_phy_init(phy);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_CMD_RESET;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_CMD_RESET, 0, 2500) < 0) {
+ pr_err("%s: timeout waiting for reset\n", __func__);
+ }
+
+ ulpi_null_phy_cmd_reset(phy);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS,
+ USB_USBCMD_RS, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ /* Enable Port Power */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PP;
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ ulpi_null_phy_restore(phy);
+
+ return 0;
+}
+
+static int ulpi_null_phy_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already On\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+ reset_utmip_uhsic(base);
+
+ /* remove ULPI PADS CLKEN reset */
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~ULPI_PADS_CLKEN_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(10);
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= ULPI_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(10);
+
+ /* set timming parameters */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_SHADOW_CLK_LOOPBACK_EN;
+ val &= ~ULPI_SHADOW_CLK_SEL;
+ val &= ~ULPI_LBK_PAD_EN;
+ val |= ULPI_SHADOW_CLK_DELAY(config->shadow_clk_delay);
+ val |= ULPI_CLOCK_OUT_DELAY(config->clock_out_delay);
+ val |= ULPI_LBK_PAD_E_INPUT_OR;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ writel(0, base + ULPI_TIMING_CTRL_1);
+ udelay(10);
+
+ /* start internal 60MHz clock */
+ val = readl(base + ULPIS2S_CTRL);
+ val |= ULPIS2S_ENA;
+ val |= ULPIS2S_SUPPORT_DISCONNECT;
+ val |= ULPIS2S_SPARE((phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) ? 3 : 1);
+ val |= ULPIS2S_PLLU_MASTER_BLASTER60;
+ writel(val, base + ULPIS2S_CTRL);
+
+ /* select ULPI_CORE_CLK_SEL to SHADOW_CLK */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CORE_CLK_SEL;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+ udelay(10);
+
+ /* enable ULPI null phy clock - can't set the trimmers before this */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_OUT_ENA;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+ udelay(10);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ USB_PHY_CLK_VALID, 2500)) {
+ pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ /* set ULPI trimmers */
+ ulpi_set_trimmer(phy);
+
+ ulpi_set_host(base);
+
+ /* remove slave0 reset */
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~ULPIS2S_SLV0_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ /* remove slave1 and line reset */
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~ULPIS2S_SLV1_RESET;
+ val &= ~ULPIS2S_LINE_RESET;
+
+ /* remove ULPI PADS reset */
+ val &= ~ULPI_PADS_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ if (!phy->ulpi_clk_padout_ena) {
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_PADOUT_ENA;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+ phy->ulpi_clk_padout_ena = true;
+ } else {
+ if (!readl(base + USB_ASYNCLISTADDR))
+ ulpi_null_phy_lp0_resume(phy);
+ }
+ udelay(10);
+
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+
+ return 0;
+}
+
+static int ulpi_null_phy_pre_resume(struct tegra_usb_phy *phy,
+ bool remote_wakeup)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ ulpi_null_phy_obs_read();
+ return 0;
+}
+
+static int ulpi_null_phy_post_resume(struct tegra_usb_phy *phy)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ ulpi_null_phy_obs_read();
+ return 0;
+}
+
+static int ulpi_null_phy_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ if (!readl(base + USB_ASYNCLISTADDR)) {
+ /* enable ULPI CLK output pad */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_PADOUT_ENA;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ /* enable ULPI pinmux bypass */
+ ulpi_pinmux_bypass(phy, true);
+ udelay(5);
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+ /* remove DIR tristate */
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR,
+ TEGRA_TRI_NORMAL);
+#endif
+ }
+ return 0;
+}
+
+static struct tegra_usb_phy_ops utmi_phy_ops = {
+ .init = _usb_phy_init,
+ .reset = usb_phy_reset,
+ .open = utmi_phy_open,
+ .close = utmi_phy_close,
+ .irq = utmi_phy_irq,
+ .power_on = utmi_phy_power_on,
+ .power_off = utmi_phy_power_off,
+ .pre_resume = utmi_phy_pre_resume,
+ .resume = utmi_phy_resume,
+ .charger_detect = utmi_phy_charger_detect,
+};
+
+static struct tegra_usb_phy_ops uhsic_phy_ops = {
+ .init = _usb_phy_init,
+ .open = uhsic_phy_open,
+ .close = uhsic_phy_close,
+ .irq = uhsic_phy_irq,
+ .power_on = uhsic_phy_power_on,
+ .power_off = uhsic_phy_power_off,
+ .pre_resume = uhsic_phy_pre_resume,
+ .port_power = uhsic_phy_bus_port_power,
+};
+
+static struct tegra_usb_phy_ops ulpi_link_phy_ops = {
+ .init = _usb_phy_init,
+ .reset = usb_phy_reset,
+ .open = ulpi_link_phy_open,
+ .close = ulpi_link_phy_close,
+ .irq = ulpi_link_phy_irq,
+ .power_on = ulpi_link_phy_power_on,
+ .power_off = ulpi_link_phy_power_off,
+ .resume = ulpi_link_phy_resume,
+};
+
+static struct tegra_usb_phy_ops ulpi_null_phy_ops = {
+ .open = ulpi_null_phy_open,
+ .close = ulpi_null_phy_close,
+ .init = ulpi_null_phy_init,
+ .irq = ulpi_null_phy_irq,
+ .power_on = ulpi_null_phy_power_on,
+ .power_off = ulpi_null_phy_power_off,
+ .pre_resume = ulpi_null_phy_pre_resume,
+ .resume = ulpi_null_phy_resume,
+ .post_resume = ulpi_null_phy_post_resume,
+ .reset = ulpi_null_phy_cmd_reset,
+};
+
+static struct tegra_usb_phy_ops icusb_phy_ops;
+
+static struct tegra_usb_phy_ops *phy_ops[] = {
+ [TEGRA_USB_PHY_INTF_UTMI] = &utmi_phy_ops,
+ [TEGRA_USB_PHY_INTF_ULPI_LINK] = &ulpi_link_phy_ops,
+ [TEGRA_USB_PHY_INTF_ULPI_NULL] = &ulpi_null_phy_ops,
+ [TEGRA_USB_PHY_INTF_HSIC] = &uhsic_phy_ops,
+ [TEGRA_USB_PHY_INTF_ICUSB] = &icusb_phy_ops,
+};
+
+int tegra11x_usb_phy_init_ops(struct tegra_usb_phy *phy)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ phy->ops = phy_ops[phy->pdata->phy_intf];
+
+ /* FIXME: uncommenting below line to make USB host mode fail*/
+ /* usb_phy_power_down_pmc(); */
+
+ return 0;
+}
diff --git a/drivers/usb/phy/tegra2_usb_phy.c b/drivers/usb/phy/tegra2_usb_phy.c
new file mode 100644
index 000000000000..1f77be206f2b
--- /dev/null
+++ b/drivers/usb/phy/tegra2_usb_phy.c
@@ -0,0 +1,2078 @@
+/*
+ * arch/arm/mach-tegra/tegra2_usb_phy.c
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/resource.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/platform_data/tegra_usb.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/clk.h>
+#include <mach/iomap.h>
+#include <mach/pinmux.h>
+#include <mach/pinmux-tegra20.h>
+#include <mach/usb_phy.h>
+
+#include "tegra_usb_phy.h"
+#include "gpio-names.h"
+#include "fuse.h"
+
+#define USB_USBCMD 0x140
+#define USB_USBCMD_RS (1 << 0)
+#define USB_USBCMD_RESET (1 << 1)
+
+#define USB_USBSTS 0x144
+#define USB_USBSTS_PCI (1 << 2)
+#define USB_USBSTS_SRI (1 << 7)
+#define USB_USBSTS_HCH (1 << 12)
+
+#define USB_USBINTR 0x148
+
+#define USB_ASYNCLISTADDR 0x158
+
+#define USB_TXFILLTUNING 0x164
+#define USB_FIFO_TXFILL_THRES(x) (((x) & 0x1f) << 16)
+#define USB_FIFO_TXFILL_MASK 0x3f0000
+
+#define ULPI_VIEWPORT 0x170
+#define ULPI_WAKEUP (1 << 31)
+#define ULPI_RUN (1 << 30)
+#define ULPI_RD_WR (1 << 29)
+
+#define USB_PORTSC 0x184
+#define USB_PORTSC_PTS(x) (((x) & 0x3) << 30)
+#define USB_PORTSC_PSPD(x) (((x) & 0x3) << 26)
+#define USB_PORTSC_PHCD (1 << 23)
+#define USB_PORTSC_WKOC (1 << 22)
+#define USB_PORTSC_WKDS (1 << 21)
+#define USB_PORTSC_WKCN (1 << 20)
+#define USB_PORTSC_PTC(x) (((x) & 0xf) << 16)
+#define USB_PORTSC_PP (1 << 12)
+#define USB_PORTSC_LS(x) (((x) & 0x3) << 10)
+#define USB_PORTSC_SUSP (1 << 7)
+#define USB_PORTSC_RESUME (1 << 6)
+#define USB_PORTSC_OCC (1 << 5)
+#define USB_PORTSC_PEC (1 << 3)
+#define USB_PORTSC_PE (1 << 2)
+#define USB_PORTSC_CSC (1 << 1)
+#define USB_PORTSC_CCS (1 << 0)
+#define USB_PORTSC_RWC_BITS (USB_PORTSC_CSC | USB_PORTSC_PEC | USB_PORTSC_OCC)
+#define USB_PORTSC_PSPD_MASK 3
+
+#define USB_USBMODE_REG_OFFSET 0x1a8
+#define USB_USBMODE_MASK (3 << 0)
+#define USB_USBMODE_HOST (3 << 0)
+#define USB_USBMODE_DEVICE (2 << 0)
+
+#define USB_SUSP_CTRL 0x400
+#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3)
+#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4)
+#define USB_SUSP_CLR (1 << 5)
+#define USB_CLKEN (1 << 6)
+#define USB_PHY_CLK_VALID (1 << 7)
+#define USB_PHY_CLK_VALID_INT_ENB (1 << 9)
+#define UTMIP_RESET (1 << 11)
+#define UHSIC_RESET (1 << 11)
+#define UTMIP_PHY_ENABLE (1 << 12)
+#define UHSIC_PHY_ENABLE (1 << 12)
+#define ULPI_PHY_ENABLE (1 << 13)
+#define USB_SUSP_SET (1 << 14)
+#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
+#define USB_PHY_CLK_VALID_INT_STS (1 << 8)
+
+#define USB_PHY_VBUS_WAKEUP_ID 0x408
+#define VDAT_DET_INT_EN (1 << 16)
+#define VDAT_DET_CHG_DET (1 << 17)
+#define VDAT_DET_STS (1 << 18)
+#define USB_ID_STATUS (1 << 2)
+
+#define USB1_LEGACY_CTRL 0x410
+#define USB1_NO_LEGACY_MODE (1 << 0)
+#define USB1_VBUS_SENSE_CTL_MASK (3 << 1)
+#define USB1_VBUS_SENSE_CTL_VBUS_WAKEUP (0 << 1)
+#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP \
+ (1 << 1)
+#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD (2 << 1)
+#define USB1_VBUS_SENSE_CTL_A_SESS_VLD (3 << 1)
+
+#define ULPIS2S_CTRL 0x418
+#define ULPIS2S_ENA (1 << 0)
+#define ULPIS2S_SUPPORT_DISCONNECT (1 << 2)
+#define ULPIS2S_PLLU_MASTER_BLASTER60 (1 << 3)
+#define ULPIS2S_SPARE(x) (((x) & 0xF) << 8)
+#define ULPIS2S_FORCE_ULPI_CLK_OUT (1 << 12)
+#define ULPIS2S_DISCON_DONT_CHECK_SE0 (1 << 13)
+#define ULPIS2S_SUPPORT_HS_KEEP_ALIVE (1 << 14)
+#define ULPIS2S_DISABLE_STP_PU (1 << 15)
+#define ULPIS2S_SLV0_CLAMP_XMIT (1 << 16)
+
+#define ULPI_TIMING_CTRL_0 0x424
+#define ULPI_CLOCK_OUT_DELAY(x) ((x) & 0x1F)
+#define ULPI_OUTPUT_PINMUX_BYP (1 << 10)
+#define ULPI_CLKOUT_PINMUX_BYP (1 << 11)
+#define ULPI_SHADOW_CLK_LOOPBACK_EN (1 << 12)
+#define ULPI_SHADOW_CLK_SEL (1 << 13)
+#define ULPI_CORE_CLK_SEL (1 << 14)
+#define ULPI_SHADOW_CLK_DELAY(x) (((x) & 0x1F) << 16)
+#define ULPI_LBK_PAD_EN (1 << 26)
+#define ULPI_LBK_PAD_E_INPUT_OR (1 << 27)
+#define ULPI_CLK_OUT_ENA (1 << 28)
+#define ULPI_CLK_PADOUT_ENA (1 << 29)
+
+#define ULPI_TIMING_CTRL_1 0x428
+#define ULPI_DATA_TRIMMER_LOAD (1 << 0)
+#define ULPI_DATA_TRIMMER_SEL(x) (((x) & 0x7) << 1)
+#define ULPI_STPDIRNXT_TRIMMER_LOAD (1 << 16)
+#define ULPI_STPDIRNXT_TRIMMER_SEL(x) (((x) & 0x7) << 17)
+#define ULPI_DIR_TRIMMER_LOAD (1 << 24)
+#define ULPI_DIR_TRIMMER_SEL(x) (((x) & 0x7) << 25)
+
+#define UTMIP_PLL_CFG1 0x804
+#define UHSIC_PLL_CFG1 0x804
+#define UTMIP_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+#define UTMIP_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
+#define UHSIC_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+#define UHSIC_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 14)
+
+#define UTMIP_XCVR_UHSIC_HSRX_CFG0 0x808
+#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0)
+#define UHSIC_ELASTIC_UNDERRUN_LIMIT(x) (((x) & 0x1f) << 2)
+#define UHSIC_ELASTIC_OVERRUN_LIMIT(x) (((x) & 0x1f) << 8)
+#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8)
+#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10)
+#define UHSIC_IDLE_WAIT(x) (((x) & 0x1f) << 13)
+#define UTMIP_FORCE_PD_POWERDOWN (1 << 14)
+#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16)
+#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18)
+#define UTMIP_XCVR_LSBIAS_SEL (1 << 21)
+#define UTMIP_XCVR_SETUP_MSB(x) (((x) & 0x7) << 22)
+#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25)
+#define UTMIP_XCVR_MAX_OFFSET 2
+#define UTMIP_XCVR_SETUP_MAX_VALUE 0x7f
+#define UTMIP_XCVR_SETUP_MIN_VALUE 0
+#define XCVR_SETUP_MSB_CALIB(x) ((x) >> 4)
+
+#define UTMIP_BIAS_CFG0 0x80c
+#define UTMIP_OTGPD (1 << 11)
+#define UTMIP_BIASPD (1 << 10)
+
+#define UHSIC_HSRX_CFG1 0x80c
+#define UHSIC_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
+
+#define UTMIP_HSRX_CFG0 0x810
+#define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10)
+#define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15)
+
+#define UTMIP_HSRX_CFG1 0x814
+#define UHSIC_MISC_CFG0 0x814
+#define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
+#define UHSIC_SUSPEND_EXIT_ON_EDGE (1 << 7)
+#define UHSIC_DETECT_SHORT_CONNECT (1 << 8)
+#define UHSIC_FORCE_XCVR_MODE (1 << 15)
+
+#define UHSIC_MISC_CFG1 0x818
+#define UHSIC_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 2)
+
+#define UHSIC_PADS_CFG0 0x81c
+#define UHSIC_TX_RTUNEN 0xf000
+#define UHSIC_TX_RTUNE(x) (((x) & 0xf) << 12)
+
+#define UTMIP_TX_CFG0 0x820
+#define UHSIC_PADS_CFG1 0x820
+#define UHSIC_PD_BG (1 << 2)
+#define UHSIC_PD_TX (1 << 3)
+#define UHSIC_PD_TRK (1 << 4)
+#define UHSIC_PD_RX (1 << 5)
+#define UHSIC_PD_ZI (1 << 6)
+#define UHSIC_RX_SEL (1 << 7)
+#define UHSIC_RPD_DATA (1 << 9)
+#define UHSIC_RPD_STROBE (1 << 10)
+#define UHSIC_RPU_DATA (1 << 11)
+#define UHSIC_RPU_STROBE (1 << 12)
+#define UTMIP_FS_PREABMLE_J (1 << 19)
+#define UTMIP_HS_DISCON_DISABLE (1 << 8)
+
+#define UTMIP_MISC_CFG0 0x824
+#define UTMIP_DPDM_OBSERVE (1 << 26)
+#define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_J UTMIP_DPDM_OBSERVE_SEL(0xf)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_K UTMIP_DPDM_OBSERVE_SEL(0xe)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc)
+#define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22)
+#define FORCE_PULLDN_DM (1 << 8)
+#define FORCE_PULLDN_DP (1 << 9)
+#define COMB_TERMS (1 << 0)
+#define ALWAYS_FREE_RUNNING_TERMS (1 << 1)
+
+#define USB1_PREFETCH_ID 6
+#define USB2_PREFETCH_ID 18
+#define USB3_PREFETCH_ID 17
+
+#define UTMIP_MISC_CFG1 0x828
+#define UTMIP_PLL_ACTIVE_DLY_COUNT(x) (((x) & 0x1f) << 18)
+#define UTMIP_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 6)
+
+#define UHSIC_STAT_CFG0 0x828
+#define UHSIC_CONNECT_DETECT (1 << 0)
+
+#define UTMIP_DEBOUNCE_CFG0 0x82c
+#define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0)
+
+#define UTMIP_BAT_CHRG_CFG0 0x830
+#define UTMIP_PD_CHRG (1 << 0)
+#define UTMIP_ON_SINK_EN (1 << 2)
+#define UTMIP_OP_SRC_EN (1 << 3)
+
+#define UTMIP_SPARE_CFG0 0x834
+#define FUSE_SETUP_SEL (1 << 3)
+#define FUSE_ATERM_SEL (1 << 4)
+
+#define UTMIP_XCVR_CFG1 0x838
+#define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0)
+#define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2)
+#define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4)
+#define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18)
+
+#define UTMIP_BIAS_CFG1 0x83c
+#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3)
+
+#define FUSE_USB_CALIB_0 0x1F0
+#define FUSE_USB_CALIB_XCVR_SETUP(x) (((x) & 0x7F) << 0)
+
+#define APB_MISC_GP_OBSCTRL_0 0x818
+#define APB_MISC_GP_OBSDATA_0 0x81c
+
+/* ULPI GPIO */
+#define ULPI_STP TEGRA_GPIO_PY3
+#define ULPI_DIR TEGRA_GPIO_PY1
+#define ULPI_D0 TEGRA_GPIO_PO1
+#define ULPI_D1 TEGRA_GPIO_PO2
+
+/* These values (in milli second) are taken from the battery charging spec */
+#define TDP_SRC_ON_MS 100
+#define TDPSRC_CON_MS 40
+
+#ifdef DEBUG
+#define DBG(stuff...) pr_info("tegra2_usb_phy: " stuff)
+#else
+#define DBG(stuff...) do {} while (0)
+#endif
+
+/* define HSIC phy params */
+#define HSIC_SYNC_START_DELAY 9
+#define HSIC_IDLE_WAIT_DELAY 17
+#define HSIC_ELASTIC_UNDERRUN_LIMIT 16
+#define HSIC_ELASTIC_OVERRUN_LIMIT 16
+
+static DEFINE_SPINLOCK(utmip_pad_lock);
+static int utmip_pad_count;
+static int utmip_pad_state_on;
+
+static struct tegra_xtal_freq utmip_freq_table[] = {
+ {
+ .freq = 12000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x2F,
+ .active_delay = 0x04,
+ .xtal_freq_count = 0x76,
+ .debounce = 0x7530,
+ .pdtrk_count = 5,
+ },
+ {
+ .freq = 13000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x33,
+ .active_delay = 0x05,
+ .xtal_freq_count = 0x7F,
+ .debounce = 0x7EF4,
+ .pdtrk_count = 5,
+ },
+ {
+ .freq = 19200000,
+ .enable_delay = 0x03,
+ .stable_count = 0x4B,
+ .active_delay = 0x06,
+ .xtal_freq_count = 0xBB,
+ .debounce = 0xBB80,
+ .pdtrk_count = 7,
+ },
+ {
+ .freq = 26000000,
+ .enable_delay = 0x04,
+ .stable_count = 0x66,
+ .active_delay = 0x09,
+ .xtal_freq_count = 0xFE,
+ .debounce = 0xFDE8,
+ .pdtrk_count = 9,
+ },
+};
+
+static struct tegra_xtal_freq uhsic_freq_table[] = {
+ {
+ .freq = 12000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x2F,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x1CA,
+ },
+ {
+ .freq = 13000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x33,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x1F0,
+ },
+ {
+ .freq = 19200000,
+ .enable_delay = 0x03,
+ .stable_count = 0x4B,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x2DD,
+ },
+ {
+ .freq = 26000000,
+ .enable_delay = 0x04,
+ .stable_count = 0x66,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x3E0,
+ },
+};
+
+static void usb_phy_fence_read(struct tegra_usb_phy *phy)
+{
+ /* Fence read for coherency of AHB master intiated writes */
+ if (phy->inst == 0)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB1_PREFETCH_ID));
+ else if (phy->inst == 1)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB2_PREFETCH_ID));
+ else if (phy->inst == 2)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB3_PREFETCH_ID));
+
+ return;
+}
+
+static int usb_phy_bringup_host_controller(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x] port_speed[%d] - 0\n",
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC),
+ phy->port_speed);
+
+ /* enable host mode */
+ val = readl(base + USB_USBMODE_REG_OFFSET);
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE_REG_OFFSET);
+
+ /* Enable Port Power */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PP;
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ /* Check if the phy resume from LP0. When the phy resume from LP0
+ * USB register will be reset.to zero */
+ if (!readl(base + USB_ASYNCLISTADDR)) {
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ /* Program the field PTC based on the saved speed mode */
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_PTC(~0));
+ if (phy->port_speed == USB_PHY_PORT_SPEED_HIGH)
+ val |= USB_PORTSC_PTC(5);
+ else if (phy->port_speed == USB_PHY_PORT_SPEED_FULL)
+ val |= USB_PORTSC_PTC(6);
+ else if (phy->port_speed == USB_PHY_PORT_SPEED_LOW)
+ val |= USB_PORTSC_PTC(7);
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ /* Disable test mode by setting PTC field to NORMAL_OP */
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_PTC(~0));
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+ }
+
+ /* Poll until CCS is enabled */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_CCS,
+ USB_PORTSC_CCS, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_CCS\n", __func__);
+ }
+
+ /* Poll until PE is enabled */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_PE,
+ USB_PORTSC_PE, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_PE\n", __func__);
+ }
+
+ /* Clear the PCI status, to avoid an interrupt taken upon resume */
+ val = readl(base + USB_USBSTS);
+ val |= USB_USBSTS_PCI;
+ writel(val, base + USB_USBSTS);
+
+ /* Put controller in suspend mode by writing 1 to SUSP bit of PORTSC */
+ val = readl(base + USB_PORTSC);
+ if ((val & USB_PORTSC_PP) && (val & USB_PORTSC_PE)) {
+ val |= USB_PORTSC_SUSP;
+ writel(val, base + USB_PORTSC);
+ /* Need a 4ms delay before the controller goes to suspend */
+ mdelay(4);
+
+ /* Wait until port suspend completes */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_SUSP,
+ USB_PORTSC_SUSP, 1000)) {
+ pr_err("%s: timeout waiting for PORT_SUSPEND\n",
+ __func__);
+ }
+ }
+
+ DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n",
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC));
+
+ return 0;
+}
+
+static void usb_phy_wait_for_sof(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(base + USB_USBSTS);
+ writel(val, base + USB_USBSTS);
+ udelay(20);
+ /* wait for two SOFs */
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI,
+ USB_USBSTS_SRI, 2500))
+ pr_err("%s: timeout waiting for SOF\n", __func__);
+
+ val = readl(base + USB_USBSTS);
+ writel(val, base + USB_USBSTS);
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI, 0, 2500))
+ pr_err("%s: timeout waiting for SOF\n", __func__);
+
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI,
+ USB_USBSTS_SRI, 2500))
+ pr_err("%s: timeout waiting for SOF\n", __func__);
+
+ udelay(20);
+}
+
+static unsigned int utmi_phy_xcvr_setup_value(struct tegra_usb_phy *phy)
+{
+ struct tegra_utmi_config *cfg = &phy->pdata->u_cfg.utmi;
+ signed long val;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (cfg->xcvr_use_fuses) {
+ val = FUSE_USB_CALIB_XCVR_SETUP(
+ tegra_fuse_readl(FUSE_USB_CALIB_0));
+ if (cfg->xcvr_setup_offset <= UTMIP_XCVR_MAX_OFFSET)
+ val = val + cfg->xcvr_setup_offset;
+
+ if (val > UTMIP_XCVR_SETUP_MAX_VALUE) {
+ val = UTMIP_XCVR_SETUP_MAX_VALUE;
+ pr_info("%s: reset XCVR_SETUP to max value\n",
+ __func__);
+ } else if (val < UTMIP_XCVR_SETUP_MIN_VALUE) {
+ val = UTMIP_XCVR_SETUP_MIN_VALUE;
+ pr_info("%s: reset XCVR_SETUP to min value\n",
+ __func__);
+ }
+ } else {
+ val = cfg->xcvr_setup;
+ }
+
+ return (unsigned int) val;
+}
+
+
+static int utmi_phy_open(struct tegra_usb_phy *phy)
+{
+ unsigned long parent_rate;
+ int i;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ phy->utmi_pad_clk = clk_get_sys("utmip-pad", NULL);
+ if (IS_ERR(phy->utmi_pad_clk)) {
+ pr_err("%s: can't get utmip pad clock\n", __func__);
+ return PTR_ERR(phy->utmi_pad_clk);
+ }
+
+ phy->utmi_xcvr_setup = utmi_phy_xcvr_setup_value(phy);
+
+ parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk));
+ for (i = 0; i < ARRAY_SIZE(utmip_freq_table); i++) {
+ if (utmip_freq_table[i].freq == parent_rate) {
+ phy->freq = &utmip_freq_table[i];
+ break;
+ }
+ }
+ if (!phy->freq) {
+ pr_err("invalid pll_u parent rate %ld\n", parent_rate);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void utmi_phy_close(struct tegra_usb_phy *phy)
+{
+ DBG("%s inst:[%d]\n", __func__, phy->inst);
+
+ clk_put(phy->utmi_pad_clk);
+}
+
+static int utmi_phy_pad_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val, flags;
+ void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE);
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ clk_enable(phy->utmi_pad_clk);
+
+ spin_lock_irqsave(&utmip_pad_lock, flags);
+
+ utmip_pad_count++;
+ val = readl(pad_base + UTMIP_BIAS_CFG0);
+ val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
+ writel(val, pad_base + UTMIP_BIAS_CFG0);
+ utmip_pad_state_on = true;
+
+ spin_unlock_irqrestore(&utmip_pad_lock, flags);
+
+ clk_disable(phy->utmi_pad_clk);
+
+ return 0;
+}
+
+static int utmi_phy_pad_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val, flags;
+ void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE);
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ clk_enable(phy->utmi_pad_clk);
+ spin_lock_irqsave(&utmip_pad_lock, flags);
+
+ if (!utmip_pad_count) {
+ pr_err("%s: utmip pad already powered off\n", __func__);
+ goto out;
+ }
+ if (--utmip_pad_count == 0) {
+ val = readl(pad_base + UTMIP_BIAS_CFG0);
+ val |= UTMIP_OTGPD | UTMIP_BIASPD;
+ writel(val, pad_base + UTMIP_BIAS_CFG0);
+ utmip_pad_state_on = false;
+ }
+out:
+ spin_unlock_irqrestore(&utmip_pad_lock, flags);
+ clk_disable(phy->utmi_pad_clk);
+
+ return 0;
+}
+
+static int utmi_phy_irq(struct tegra_usb_phy *phy)
+{
+ void __iomem *base = phy->regs;
+ unsigned long val = 0;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ usb_phy_fence_read(phy);
+ if (phy->hot_plug) {
+ val = readl(base + USB_SUSP_CTRL);
+ if ((val & USB_PHY_CLK_VALID_INT_STS)) {
+ val &= ~USB_PHY_CLK_VALID_INT_ENB |
+ USB_PHY_CLK_VALID_INT_STS;
+ writel(val , (base + USB_SUSP_CTRL));
+
+ val = readl(base + USB_USBSTS);
+ if (!(val & USB_USBSTS_PCI))
+ return IRQ_NONE;
+
+ val = readl(base + USB_PORTSC);
+ if (val & USB_PORTSC_CCS)
+ val &= ~USB_PORTSC_WKCN;
+ else
+ val &= ~USB_PORTSC_WKDS;
+ val &= ~USB_PORTSC_RWC_BITS;
+ writel(val , (base + USB_PORTSC));
+
+ } else if (!phy->phy_clk_on) {
+ return IRQ_NONE;
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int phy_post_suspend(struct tegra_usb_phy *phy)
+{
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ /* Need a 4ms delay for controller to suspend */
+ mdelay(4);
+ return 0;
+}
+
+static int utmi_phy_post_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(base + UTMIP_TX_CFG0);
+ val &= ~UTMIP_HS_DISCON_DISABLE;
+ writel(val, base + UTMIP_TX_CFG0);
+ return 0;
+}
+
+static int utmi_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(base + UTMIP_TX_CFG0);
+ val |= UTMIP_HS_DISCON_DISABLE;
+ writel(val, base + UTMIP_TX_CFG0);
+
+ usb_phy_wait_for_sof(phy);
+
+ return 0;
+}
+
+static int utmi_phy_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (!phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already off\n",
+ __func__, __LINE__, phy->inst);
+ return 0;
+ }
+
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~(USB_WAKEUP_DEBOUNCE_COUNT(~0));
+ val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ }
+
+ if (!phy->hot_plug) {
+ val = readl(base + UTMIP_XCVR_UHSIC_HSRX_CFG0);
+ val |= (UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
+ UTMIP_FORCE_PDZI_POWERDOWN);
+ writel(val, base + UTMIP_XCVR_UHSIC_HSRX_CFG0);
+ }
+
+ val = readl(base + UTMIP_XCVR_CFG1);
+ val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
+ UTMIP_FORCE_PDDR_POWERDOWN;
+ writel(val, base + UTMIP_XCVR_CFG1);
+
+ if (phy->inst != 0) {
+ val = readl(base + UTMIP_BIAS_CFG0);
+ val |= UTMIP_OTGPD;
+ writel(val, base + UTMIP_BIAS_CFG0);
+ }
+
+ phy->port_speed = (readl(base + USB_PORTSC) >> 26) &
+ USB_PORTSC_PSPD_MASK;
+
+ if (phy->hot_plug) {
+ bool enable_hotplug = true;
+ /* if it is OTG port then make sure to enable hot-plug feature
+ only if host adaptor is connected, i.e id is low */
+ if (phy->pdata->port_otg) {
+ val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+ enable_hotplug = (val & USB_ID_STATUS) ? false : true;
+ }
+ if (enable_hotplug) {
+ /* Enable wakeup event of device plug-in/plug-out */
+ val = readl(base + USB_PORTSC);
+ if (val & USB_PORTSC_CCS)
+ val |= USB_PORTSC_WKDS;
+ else
+ val |= USB_PORTSC_WKCN;
+ writel(val, base + USB_PORTSC);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= USB_PHY_CLK_VALID_INT_ENB;
+ writel(val, base + USB_SUSP_CTRL);
+ } else {
+ /* Disable PHY clock valid interrupts
+ while going into suspend*/
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_PHY_CLK_VALID_INT_ENB;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+ }
+
+ /* Disable PHY clock */
+ if (phy->inst == 2) {
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PHCD;
+ writel(val, base + USB_PORTSC);
+ } else {
+ val = readl(base + USB_SUSP_CTRL);
+ val |= USB_SUSP_SET;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(10);
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_SUSP_SET;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ 0, 2500))
+ pr_warn("%s: timeout waiting for phy to stabilize\n", __func__);
+
+ utmi_phy_pad_power_off(phy);
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+
+ DBG("%s(%d) inst:[%d]END\n", __func__, __LINE__, phy->inst);
+
+ return 0;
+}
+
+static int utmi_phy_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ struct tegra_utmi_config *config = &phy->pdata->u_cfg.utmi;
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already on\n",
+ __func__, __LINE__, phy->inst);
+ return 0;
+ }
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_TX_CFG0);
+ val |= UTMIP_FS_PREABMLE_J;
+ writel(val, base + UTMIP_TX_CFG0);
+
+ val = readl(base + UTMIP_HSRX_CFG0);
+ val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0));
+ val |= UTMIP_IDLE_WAIT(config->idle_wait_delay);
+ val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit);
+ writel(val, base + UTMIP_HSRX_CFG0);
+
+ val = readl(base + UTMIP_HSRX_CFG1);
+ val &= ~(UTMIP_HS_SYNC_START_DLY(~0));
+ val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay);
+ writel(val, base + UTMIP_HSRX_CFG1);
+
+ val = readl(base + UTMIP_DEBOUNCE_CFG0);
+ val &= ~UTMIP_BIAS_DEBOUNCE_A(~0);
+ val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce);
+ writel(val, base + UTMIP_DEBOUNCE_CFG0);
+
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ val = readl(base + UTMIP_MISC_CFG1);
+ val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0));
+ val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
+ UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
+ writel(val, base + UTMIP_MISC_CFG1);
+
+ val = readl(base + UTMIP_PLL_CFG1);
+ val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
+ val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
+ UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
+ writel(val, base + UTMIP_PLL_CFG1);
+
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val &= ~UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ } else {
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ }
+
+ utmi_phy_pad_power_on(phy);
+
+ val = readl(base + UTMIP_XCVR_UHSIC_HSRX_CFG0);
+ val &= ~(UTMIP_XCVR_LSBIAS_SEL | UTMIP_FORCE_PD_POWERDOWN |
+ UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN |
+ UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_LSFSLEW(~0) |
+ UTMIP_XCVR_LSRSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0));
+ val |= UTMIP_XCVR_SETUP(phy->utmi_xcvr_setup);
+ val |= UTMIP_XCVR_SETUP_MSB(XCVR_SETUP_MSB_CALIB(phy->utmi_xcvr_setup));
+ val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
+ val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
+
+ writel(val, base + UTMIP_XCVR_UHSIC_HSRX_CFG0);
+
+ val = readl(base + UTMIP_XCVR_CFG1);
+ val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
+ UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0));
+ val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
+ writel(val, base + UTMIP_XCVR_CFG1);
+
+
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val &= ~(UTMIP_BIAS_PDTRK_COUNT(~0));
+ val |= UTMIP_BIAS_PDTRK_COUNT(phy->freq->pdtrk_count);
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ val = readl(base + UTMIP_SPARE_CFG0);
+ val &= ~FUSE_SETUP_SEL;
+ writel(val, base + UTMIP_SPARE_CFG0);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ if (phy->inst == 0) {
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_SUSP_SET;
+ writel(val, base + USB_SUSP_CTRL);
+ } else {
+ val = readl(base + USB_PORTSC);
+ val &= ~USB_PORTSC_PHCD;
+ writel(val, base + USB_PORTSC);
+ }
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500))
+ pr_warn("%s: timeout waiting for phy to stabilize\n", __func__);
+
+ if (phy->inst == 2) {
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_PTS(~0));
+ writel(val, base + USB_PORTSC);
+ }
+
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+
+ return 0;
+}
+
+static void utmi_phy_restore_start(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~(UTMIP_DPDM_OBSERVE_SEL(~0));
+
+ if (phy->port_speed == USB_PHY_PORT_SPEED_LOW)
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
+ else
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(1);
+
+ val = readl(base + UTMIP_MISC_CFG0);
+ val |= UTMIP_DPDM_OBSERVE;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(10);
+}
+
+static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_DPDM_OBSERVE;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(10);
+}
+
+
+static int utmi_phy_resume(struct tegra_usb_phy *phy)
+{
+ int status = 0;
+ unsigned long val, flags;
+ void __iomem *base = phy->regs;
+ void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE);
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) {
+ if (readl(base + USB_ASYNCLISTADDR) &&
+ !phy->pdata->u_data.host.power_off_on_suspend)
+ return 0;
+
+ if (phy->port_speed < USB_PHY_PORT_SPEED_UNKNOWN) {
+ utmi_phy_restore_start(phy);
+ usb_phy_bringup_host_controller(phy);
+ utmi_phy_restore_end(phy);
+ } else {
+ /* device is plugged in when system is in LP0 */
+ /* bring up the controller from LP0*/
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RESET;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_USBCMD_RESET, 0, 2500) < 0) {
+ pr_err("%s: timeout waiting for reset\n",
+ __func__);
+ }
+
+ val = readl(base + USB_USBMODE_REG_OFFSET);
+ val &= ~USB_USBMODE_MASK;
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE_REG_OFFSET);
+
+ if (phy->inst == 2) {
+ val = readl(base + USB_PORTSC);
+ val &= ~USB_PORTSC_PTS(~0);
+ writel(val, base + USB_PORTSC);
+ }
+ writel(USB_USBCMD_RS, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_USBCMD_RS, USB_USBCMD_RS, 2500) < 0) {
+ pr_err("%s: timeout waiting for run bit\n",
+ __func__);
+ }
+
+ /* Enable Port Power */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PP;
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n",
+ readl(base + USB_USBSTS),
+ readl(base + USB_PORTSC));
+ }
+ } else {
+ /* Restoring the pad powers */
+ clk_enable(phy->utmi_pad_clk);
+
+ spin_lock_irqsave(&utmip_pad_lock, flags);
+
+ val = readl(pad_base + UTMIP_BIAS_CFG0);
+ if (utmip_pad_state_on)
+ val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
+ else
+ val |= (UTMIP_OTGPD | UTMIP_BIASPD);
+ writel(val, pad_base + UTMIP_BIAS_CFG0);
+
+ spin_unlock_irqrestore(&utmip_pad_lock, flags);
+ clk_disable(phy->utmi_pad_clk);
+ }
+
+ return status;
+}
+
+static bool utmi_phy_charger_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ bool status;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ /* Enable charger detection logic */
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+ /* Source should be on for 100 ms as per USB charging spec */
+ msleep(TDP_SRC_ON_MS);
+
+ val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+ /* If charger is not connected disable the interrupt */
+ val &= ~VDAT_DET_INT_EN;
+ val |= VDAT_DET_CHG_DET;
+ writel(val, base + USB_PHY_VBUS_WAKEUP_ID);
+
+ val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+ if (val & VDAT_DET_STS)
+ status = true;
+ else
+ status = false;
+
+ /* Disable charger detection logic */
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val &= ~(UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN);
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+ /* Delay of 40 ms before we pull the D+ as per battery charger spec */
+ msleep(TDPSRC_CON_MS);
+
+ return status;
+}
+
+
+static int uhsic_phy_open(struct tegra_usb_phy *phy)
+{
+ unsigned long parent_rate;
+ int i;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk));
+ for (i = 0; i < ARRAY_SIZE(uhsic_freq_table); i++) {
+ if (uhsic_freq_table[i].freq == parent_rate) {
+ phy->freq = &uhsic_freq_table[i];
+ break;
+ }
+ }
+ if (!phy->freq) {
+ pr_err("invalid pll_u parent rate %ld\n", parent_rate);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int uhsic_phy_irq(struct tegra_usb_phy *phy)
+{
+ usb_phy_fence_read(phy);
+ return IRQ_HANDLED;
+}
+
+static int uhsic_phy_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already On\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~(UHSIC_PD_BG | UHSIC_PD_TX | UHSIC_PD_TRK | UHSIC_PD_RX |
+ UHSIC_PD_ZI | UHSIC_RPD_DATA | UHSIC_RPD_STROBE);
+ val |= UHSIC_RX_SEL;
+ writel(val, base + UHSIC_PADS_CFG1);
+ udelay(2);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(30);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_XCVR_UHSIC_HSRX_CFG0);
+ val |= UHSIC_IDLE_WAIT(HSIC_IDLE_WAIT_DELAY);
+ val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(HSIC_ELASTIC_UNDERRUN_LIMIT);
+ val |= UHSIC_ELASTIC_OVERRUN_LIMIT(HSIC_ELASTIC_OVERRUN_LIMIT);
+ writel(val, base + UTMIP_XCVR_UHSIC_HSRX_CFG0);
+
+ val = readl(base + UHSIC_HSRX_CFG1);
+ val |= UHSIC_HS_SYNC_START_DLY(HSIC_SYNC_START_DELAY);
+ writel(val, base + UHSIC_HSRX_CFG1);
+
+ val = readl(base + UHSIC_MISC_CFG0);
+ val |= UHSIC_SUSPEND_EXIT_ON_EDGE;
+ writel(val, base + UHSIC_MISC_CFG0);
+
+ val = readl(base + UHSIC_MISC_CFG1);
+ val |= UHSIC_PLLU_STABLE_COUNT(phy->freq->stable_count);
+ writel(val, base + UHSIC_MISC_CFG1);
+
+ val = readl(base + UHSIC_PLL_CFG1);
+ val |= UHSIC_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
+ val |= UHSIC_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count);
+ writel(val, base + UHSIC_PLL_CFG1);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~(UHSIC_RESET);
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(2);
+
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_PTS(~0));
+ writel(val, base + USB_PORTSC);
+
+ val = readl(base + USB_TXFILLTUNING);
+ if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) {
+ val = USB_FIFO_TXFILL_THRES(0x10);
+ writel(val, base + USB_TXFILLTUNING);
+ }
+
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_WKOC | USB_PORTSC_WKDS | USB_PORTSC_WKCN);
+ writel(val, base + USB_PORTSC);
+
+ val = readl(base + UHSIC_PADS_CFG0);
+ val &= ~(UHSIC_TX_RTUNEN);
+ /* set Rtune impedance to 40 ohm */
+ val |= UHSIC_TX_RTUNE(0);
+ writel(val, base + UHSIC_PADS_CFG0);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ USB_PHY_CLK_VALID, 2500)) {
+ pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+
+ return 0;
+}
+
+static int uhsic_phy_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (!phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already off\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPU_STROBE;
+ val |= UHSIC_RPD_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(30);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~UHSIC_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+
+ return 0;
+}
+
+static int uhsic_phy_bus_port_power(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ val = readl(base + UHSIC_MISC_CFG0);
+ val |= UHSIC_DETECT_SHORT_CONNECT;
+ writel(val, base + UHSIC_MISC_CFG0);
+ udelay(1);
+
+ val = readl(base + UHSIC_MISC_CFG0);
+ val |= UHSIC_FORCE_XCVR_MODE;
+ writel(val, base + UHSIC_MISC_CFG0);
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPD_STROBE;
+ val |= UHSIC_RPU_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ if (phy->pdata->ops && phy->pdata->ops->port_power)
+ phy->pdata->ops->port_power();
+
+ if (usb_phy_reg_status_wait(base + UHSIC_STAT_CFG0,
+ UHSIC_CONNECT_DETECT, UHSIC_CONNECT_DETECT, 2000)) {
+ pr_err("%s: timeout waiting for UHSIC_CONNECT_DETECT\n",
+ __func__);
+ return -ETIMEDOUT;
+ }
+
+/* FIXME : need to check whether this piece is required or not
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_LS(2),
+ USB_PORTSC_LS(2), 2000)) {
+ pr_err("%s: timeout waiting for dplus state\n", __func__);
+ return -ETIMEDOUT;
+ }
+*/
+ return 0;
+}
+
+
+static int uhsic_phy_bus_reset(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PTC(5);
+ writel(val, base + USB_PORTSC);
+ udelay(2);
+
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_PTC(~0));
+ writel(val, base + USB_PORTSC);
+ udelay(2);
+
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_LS(0),
+ 0, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_LS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ /* Poll until CCS is enabled */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_CCS,
+ USB_PORTSC_CCS, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_CCS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_PSPD(2),
+ USB_PORTSC_PSPD(2), 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_PSPD\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_HCH,
+ USB_USBSTS_HCH, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBSTS_HCH\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPU_STROBE;
+ val |= UHSIC_RPD_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ mdelay(50);
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPD_STROBE;
+ val |= UHSIC_RPU_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPU_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS,
+ USB_USBCMD_RS, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+
+static int uhsic_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ usb_phy_wait_for_sof(phy);
+
+ return 0;
+}
+
+static int uhsic_phy_resume(struct tegra_usb_phy *phy)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ uhsic_phy_bus_port_power(phy);
+
+ return 0;
+}
+
+
+static int uhsic_phy_post_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(base + USB_TXFILLTUNING);
+ if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) {
+ val = USB_FIFO_TXFILL_THRES(0x10);
+ writel(val, base + USB_TXFILLTUNING);
+ }
+
+ return 0;
+}
+
+static void ulpi_set_trimmer(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ void __iomem *base = phy->regs;
+ unsigned long val;
+
+ val = ULPI_DATA_TRIMMER_SEL(config->data_trimmer);
+ val |= ULPI_STPDIRNXT_TRIMMER_SEL(config->stpdirnxt_trimmer);
+ val |= ULPI_DIR_TRIMMER_SEL(config->dir_trimmer);
+ writel(val, base + ULPI_TIMING_CTRL_1);
+ udelay(10);
+
+ val |= ULPI_DATA_TRIMMER_LOAD;
+ val |= ULPI_STPDIRNXT_TRIMMER_LOAD;
+ val |= ULPI_DIR_TRIMMER_LOAD;
+ writel(val, base + ULPI_TIMING_CTRL_1);
+}
+
+
+static int ulpi_link_phy_open(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ int err = 0;
+
+ phy->ulpi_clk = NULL;
+
+ if (config->clk) {
+ phy->ulpi_clk = clk_get_sys(NULL, config->clk);
+ if (IS_ERR(phy->ulpi_clk)) {
+ pr_err("%s: can't get ulpi clock\n", __func__);
+ err = -ENXIO;
+ }
+ }
+
+ phy->ulpi_vp = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
+ phy->ulpi_vp->io_priv = phy->regs + ULPI_VIEWPORT;
+ phy->linkphy_init = true;
+ return err;
+}
+
+static void ulpi_link_phy_close(struct tegra_usb_phy *phy)
+{
+ DBG("%s inst:[%d]\n", __func__, phy->inst);
+ if (phy->ulpi_clk)
+ clk_put(phy->ulpi_clk);
+}
+
+static int ulpi_link_phy_irq(struct tegra_usb_phy *phy)
+{
+ usb_phy_fence_read(phy);
+ return IRQ_HANDLED;
+}
+
+static int ulpi_link_phy_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ int ret;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (!phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already off\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ /* Disable VbusValid, SessEnd comparators */
+ ret = usb_phy_io_write(phy->ulpi_vp, 0x00, 0x0D);
+ if (ret)
+ pr_err("%s: ulpi write 0x0D failed\n", __func__);
+
+ ret = usb_phy_io_write(phy->ulpi_vp, 0x00, 0x10);
+ if (ret)
+ pr_err("%s: ulpi write 0x10 failed\n", __func__);
+
+ /* Disable IdFloat comparator */
+ ret = usb_phy_io_write(phy->ulpi_vp, 0x00, 0x19);
+ if (ret)
+ pr_err("%s: ulpi write 0x19 failed\n", __func__);
+
+ ret = usb_phy_io_write(phy->ulpi_vp, 0x00, 0x1D);
+ if (ret)
+ pr_err("%s: ulpi write 0x1D failed\n", __func__);
+
+ phy->port_speed = (readl(base + USB_PORTSC) >> 26) &
+ USB_PORTSC_PSPD_MASK;
+
+ /* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB
+ * Controller to immediately bring the ULPI PHY out of low power
+ */
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_WKOC | USB_PORTSC_WKDS | USB_PORTSC_WKCN);
+ writel(val, base + USB_PORTSC);
+
+ /* Put the PHY in the low power mode */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PHCD;
+ writel(val, base + USB_PORTSC);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ 0, 2500)) {
+ pr_err("%s: timeout waiting for phy to stop\n", __func__);
+ }
+
+ if (phy->ulpi_clk)
+ clk_disable(phy->ulpi_clk);
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+
+ return 0;
+}
+
+static int ulpi_link_phy_power_on(struct tegra_usb_phy *phy)
+{
+ int ret;
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already On\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ if (phy->ulpi_clk) {
+ clk_enable(phy->ulpi_clk);
+ mdelay(1);
+ }
+
+ val = readl(base + USB_SUSP_CTRL);
+
+ /* Case for lp0 */
+ if (!(val & UHSIC_RESET)) {
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = 0;
+ writel(val, base + ULPI_TIMING_CTRL_1);
+
+ ulpi_set_trimmer(phy);
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, TEGRA_TRI_NORMAL);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, TEGRA_TRI_NORMAL);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, TEGRA_TRI_NORMAL);
+#endif
+ val = readl(base + USB_SUSP_CTRL);
+ val |= ULPI_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500) < 0)
+ pr_err("%s: timeout waiting for phy" \
+ "to stabilize\n", __func__);
+
+ val = readl(base + USB_TXFILLTUNING);
+ if ((val & USB_FIFO_TXFILL_MASK) !=
+ USB_FIFO_TXFILL_THRES(0x10)) {
+ val = USB_FIFO_TXFILL_THRES(0x10);
+ writel(val, base + USB_TXFILLTUNING);
+ }
+ } else {
+ /* Case for auto resume*/
+ val = readl(base + USB_SUSP_CTRL);
+ val |= USB_SUSP_CLR;
+ writel(val, base + USB_SUSP_CTRL);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500) < 0)
+ pr_err("%s: timeout waiting for phy" \
+ "to stabilize\n", __func__);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_CLKEN, USB_CLKEN, 2500) < 0)
+ pr_err("%s: timeout waiting for AHB clock\n", __func__);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_SUSP_CLR;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+ if (phy->linkphy_init) {
+ /* To be done only incase of coldboot*/
+ /* Fix VbusInvalid due to floating VBUS */
+ ret = usb_phy_io_write(phy->ulpi_vp, 0x40, 0x08);
+ if (ret) {
+ pr_err("%s: ulpi write failed\n", __func__);
+ return ret;
+ }
+
+ ret = usb_phy_io_write(phy->ulpi_vp, 0x80, 0x0B);
+ if (ret) {
+ pr_err("%s: ulpi write failed\n", __func__);
+ return ret;
+ }
+ phy->linkphy_init = false;
+ }
+
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_WKOC | USB_PORTSC_WKDS | USB_PORTSC_WKCN;
+ writel(val, base + USB_PORTSC);
+
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+
+ return 0;
+}
+
+static inline void ulpi_link_phy_set_tristate(bool enable)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ int tristate = (enable) ? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL;
+
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_CDEV2, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, tristate);
+#endif
+}
+
+static void ulpi_link_phy_restore_start(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ /*Tristate ulpi interface before USB controller resume*/
+ ulpi_link_phy_set_tristate(true);
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val &= ~ULPI_OUTPUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+}
+
+static void ulpi_link_phy_restore_end(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ int ret;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_OUTPUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ ulpi_link_phy_set_tristate(false);
+
+ udelay(10);
+ ret = usb_phy_io_write(phy->ulpi_vp, 0x55, 0x04);
+ if (ret) {
+ pr_err("%s: ulpi write failed\n", __func__);
+ return;
+ }
+}
+
+static int ulpi_link_phy_resume(struct tegra_usb_phy *phy)
+{
+ int status = 0;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->pdata->u_data.host.power_off_on_suspend) {
+ status = ulpi_link_phy_power_on(phy);
+ if (phy->port_speed < USB_PHY_PORT_SPEED_UNKNOWN) {
+ ulpi_link_phy_restore_start(phy);
+ usb_phy_bringup_host_controller(phy);
+ ulpi_link_phy_restore_end(phy);
+ }
+ }
+
+ return status;
+}
+
+static int ulpi_link_phy_pre_resume(struct tegra_usb_phy *phy,
+ bool remote_wakeup)
+{
+ int status = 0;
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(base + USB_PORTSC);
+ if (val & USB_PORTSC_RESUME) {
+
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ /* detect remote wakeup */
+ msleep(20);
+
+ val = readl(base + USB_PORTSC);
+
+ /* Poll until the controller clears RESUME and SUSPEND */
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PORTSC_RESUME, 0, 2500))
+ pr_err("%s: timeout waiting for RESUME\n", __func__);
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PORTSC_SUSP, 0, 2500))
+ pr_err("%s: timeout waiting for SUSPEND\n", __func__);
+
+ /* Since we skip remote wakeup event,
+ put controller in suspend again and
+ resume port later */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_SUSP;
+ writel(val, base + USB_PORTSC);
+ mdelay(4);
+ /* Wait until port suspend completes */
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PORTSC_SUSP, USB_PORTSC_SUSP, 2500))
+ pr_err("%s: timeout waiting for" \
+ "PORT_SUSPEND\n", __func__);
+
+ /* Disable interrupts */
+ writel(0, base + USB_USBINTR);
+ /* Clear the run bit to stop SOFs - 2LS WAR */
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ if (usb_phy_reg_status_wait(base + USB_USBSTS,
+ USB_USBSTS_HCH, USB_USBSTS_HCH, 2000)) {
+ pr_err("%s: timeout waiting for" \
+ "USB_USBSTS_HCH\n", __func__);
+ }
+ usb_phy_wait_for_sof(phy);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ }
+ return status;
+}
+
+
+static inline void ulpi_pinmux_bypass(struct tegra_usb_phy *phy,
+ bool enable)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+
+ if (enable)
+ val |= ULPI_OUTPUT_PINMUX_BYP;
+ else
+ val &= ~ULPI_OUTPUT_PINMUX_BYP;
+
+ writel(val, base + ULPI_TIMING_CTRL_0);
+}
+
+static inline void ulpi_null_phy_set_tristate(bool enable)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ int tristate = (enable) ? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL;
+
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, tristate);
+#endif
+}
+
+static void ulpi_null_phy_obs_read(void)
+{
+ static void __iomem *apb_misc;
+ unsigned slv0_obs, s2s_obs;
+
+ if (!apb_misc)
+ apb_misc = ioremap(TEGRA_APB_MISC_BASE, TEGRA_APB_MISC_SIZE);
+
+ writel(0x80b10034, apb_misc + APB_MISC_GP_OBSCTRL_0);
+ slv0_obs = readl(apb_misc + APB_MISC_GP_OBSDATA_0);
+
+ writel(0x80b10038, apb_misc + APB_MISC_GP_OBSCTRL_0);
+ s2s_obs = readl(apb_misc + APB_MISC_GP_OBSDATA_0);
+
+ pr_debug("slv0 obs: %08x\ns2s obs: %08x\n", slv0_obs, s2s_obs);
+}
+
+static const struct gpio ulpi_gpios[] = {
+ {ULPI_STP, GPIOF_IN, "ULPI_STP"},
+ {ULPI_DIR, GPIOF_OUT_INIT_LOW, "ULPI_DIR"},
+ {ULPI_D0, GPIOF_OUT_INIT_LOW, "ULPI_D0"},
+ {ULPI_D1, GPIOF_OUT_INIT_LOW, "ULPI_D1"},
+};
+
+static int ulpi_null_phy_open(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ int ret;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ ret = gpio_request_array(ulpi_gpios, ARRAY_SIZE(ulpi_gpios));
+ if (ret)
+ return ret;
+
+ if (gpio_is_valid(config->phy_restore_gpio)) {
+ ret = gpio_request(config->phy_restore_gpio, "phy_restore");
+ if (ret)
+ goto err_gpio_free;
+
+ gpio_direction_input(config->phy_restore_gpio);
+ }
+
+ tegra_periph_reset_assert(phy->ctrlr_clk);
+ udelay(10);
+ tegra_periph_reset_deassert(phy->ctrlr_clk);
+
+ return 0;
+
+err_gpio_free:
+ gpio_free_array(ulpi_gpios, ARRAY_SIZE(ulpi_gpios));
+ return ret;
+}
+
+static void ulpi_null_phy_close(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ if (gpio_is_valid(config->phy_restore_gpio))
+ gpio_free(config->phy_restore_gpio);
+
+ gpio_free_array(ulpi_gpios, ARRAY_SIZE(ulpi_gpios));
+}
+
+static int ulpi_null_phy_power_off(struct tegra_usb_phy *phy)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ if (!phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already off\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+ ulpi_null_phy_set_tristate(true);
+ return 0;
+}
+
+static int ulpi_null_phy_irq(struct tegra_usb_phy *phy)
+{
+ usb_phy_fence_read(phy);
+ return IRQ_HANDLED;
+}
+
+static int ulpi_null_phy_restore(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ unsigned long timeout;
+ int ulpi_stp = ULPI_STP;
+
+ if (gpio_is_valid(config->phy_restore_gpio))
+ ulpi_stp = config->phy_restore_gpio;
+
+ /* disable ULPI pinmux bypass */
+ ulpi_pinmux_bypass(phy, false);
+
+ /* driving linstate by GPIO */
+ gpio_set_value(ULPI_D0, 0);
+ gpio_set_value(ULPI_D1, 0);
+
+ /* driving DIR high */
+ gpio_set_value(ULPI_DIR, 1);
+
+ /* remove ULPI tristate */
+ ulpi_null_phy_set_tristate(false);
+
+ /* wait for STP high */
+ timeout = jiffies + msecs_to_jiffies(25);
+
+ while (!gpio_get_value(ulpi_stp)) {
+ if (time_after(jiffies, timeout)) {
+ pr_warn("phy restore timeout\n");
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int ulpi_null_phy_lp0_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RESET;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_USBCMD_RESET, 0, 2500) < 0) {
+ pr_err("%s: timeout waiting for reset\n", __func__);
+ }
+
+ val = readl(base + USB_USBMODE_REG_OFFSET);
+ val &= ~USB_USBMODE_MASK;
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE_REG_OFFSET);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS,
+ USB_USBCMD_RS, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ /* Enable Port Power */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PP;
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ ulpi_null_phy_restore(phy);
+
+ return 0;
+}
+
+static int ulpi_null_phy_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already On\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= ULPI_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(10);
+
+ /* set timming parameters */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_SHADOW_CLK_LOOPBACK_EN;
+ val |= ULPI_SHADOW_CLK_SEL;
+ val |= ULPI_LBK_PAD_EN;
+ val |= ULPI_SHADOW_CLK_DELAY(config->shadow_clk_delay);
+ val |= ULPI_CLOCK_OUT_DELAY(config->clock_out_delay);
+ val |= ULPI_LBK_PAD_E_INPUT_OR;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ writel(0, base + ULPI_TIMING_CTRL_1);
+ udelay(10);
+
+ /* start internal 60MHz clock */
+ val = readl(base + ULPIS2S_CTRL);
+ val |= ULPIS2S_ENA;
+ val |= ULPIS2S_SUPPORT_DISCONNECT;
+ val |= ULPIS2S_SPARE((phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST)
+ ? 3 : 1);
+ val |= ULPIS2S_PLLU_MASTER_BLASTER60;
+ writel(val, base + ULPIS2S_CTRL);
+
+ /* select ULPI_CORE_CLK_SEL to SHADOW_CLK */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CORE_CLK_SEL;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+ udelay(10);
+
+ /* enable ULPI null phy clock - can't set the trimmers before this */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_OUT_ENA;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+ udelay(10);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ USB_PHY_CLK_VALID, 2500)) {
+ pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ /* set ULPI trimmers */
+ ulpi_set_trimmer(phy);
+
+ if (!phy->ulpi_clk_padout_ena) {
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_PADOUT_ENA;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+ phy->ulpi_clk_padout_ena = true;
+ } else {
+ if (!readl(base + USB_ASYNCLISTADDR))
+ ulpi_null_phy_lp0_resume(phy);
+ }
+ udelay(10);
+
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+
+ return 0;
+}
+
+static int ulpi_null_phy_pre_resume(struct tegra_usb_phy *phy,
+ bool remote_wakeup)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ ulpi_null_phy_obs_read();
+ usb_phy_wait_for_sof(phy);
+ ulpi_null_phy_obs_read();
+ return 0;
+}
+
+static int ulpi_null_phy_post_resume(struct tegra_usb_phy *phy)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ ulpi_null_phy_obs_read();
+ return 0;
+}
+
+static int ulpi_null_phy_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ if (!readl(base + USB_ASYNCLISTADDR)) {
+ /* enable ULPI CLK output pad */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_PADOUT_ENA;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ /* enable ULPI pinmux bypass */
+ ulpi_pinmux_bypass(phy, true);
+ udelay(5);
+ }
+
+ return 0;
+}
+
+
+
+static struct tegra_usb_phy_ops utmi_phy_ops = {
+ .open = utmi_phy_open,
+ .close = utmi_phy_close,
+ .irq = utmi_phy_irq,
+ .power_on = utmi_phy_power_on,
+ .power_off = utmi_phy_power_off,
+ .pre_resume = utmi_phy_pre_resume,
+ .resume = utmi_phy_resume,
+ .post_resume = utmi_phy_post_resume,
+ .charger_detect = utmi_phy_charger_detect,
+ .post_suspend = phy_post_suspend,
+};
+
+static struct tegra_usb_phy_ops uhsic_phy_ops = {
+ .open = uhsic_phy_open,
+ .irq = uhsic_phy_irq,
+ .power_on = uhsic_phy_power_on,
+ .power_off = uhsic_phy_power_off,
+ .pre_resume = uhsic_phy_pre_resume,
+ .resume = uhsic_phy_resume,
+ .post_resume = uhsic_phy_post_resume,
+ .port_power = uhsic_phy_bus_port_power,
+ .bus_reset = uhsic_phy_bus_reset,
+ .post_suspend = phy_post_suspend,
+};
+
+static struct tegra_usb_phy_ops ulpi_link_phy_ops = {
+ .open = ulpi_link_phy_open,
+ .close = ulpi_link_phy_close,
+ .irq = ulpi_link_phy_irq,
+ .power_on = ulpi_link_phy_power_on,
+ .power_off = ulpi_link_phy_power_off,
+ .resume = ulpi_link_phy_resume,
+ .post_suspend = phy_post_suspend,
+ .pre_resume = ulpi_link_phy_pre_resume,
+};
+
+static struct tegra_usb_phy_ops ulpi_null_phy_ops = {
+ .open = ulpi_null_phy_open,
+ .close = ulpi_null_phy_close,
+ .irq = ulpi_null_phy_irq,
+ .power_on = ulpi_null_phy_power_on,
+ .power_off = ulpi_null_phy_power_off,
+ .pre_resume = ulpi_null_phy_pre_resume,
+ .resume = ulpi_null_phy_resume,
+ .post_suspend = phy_post_suspend,
+ .post_resume = ulpi_null_phy_post_resume,
+};
+
+static struct tegra_usb_phy_ops icusb_phy_ops;
+
+
+static struct tegra_usb_phy_ops *phy_ops[] = {
+ [TEGRA_USB_PHY_INTF_UTMI] = &utmi_phy_ops,
+ [TEGRA_USB_PHY_INTF_ULPI_LINK] = &ulpi_link_phy_ops,
+ [TEGRA_USB_PHY_INTF_ULPI_NULL] = &ulpi_null_phy_ops,
+ [TEGRA_USB_PHY_INTF_HSIC] = &uhsic_phy_ops,
+ [TEGRA_USB_PHY_INTF_ICUSB] = &icusb_phy_ops,
+};
+
+int tegra2_usb_phy_init_ops(struct tegra_usb_phy *phy)
+{
+ phy->ops = phy_ops[phy->pdata->phy_intf];
+
+ return 0;
+}
diff --git a/drivers/usb/phy/tegra3_usb_phy.c b/drivers/usb/phy/tegra3_usb_phy.c
new file mode 100644
index 000000000000..db5f23cf6e68
--- /dev/null
+++ b/drivers/usb/phy/tegra3_usb_phy.c
@@ -0,0 +1,3178 @@
+/*
+ * arch/arm/mach-tegra/tegra3_usb_phy.c
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/resource.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/platform_data/tegra_usb.h>
+#include <mach/clk.h>
+#include <mach/iomap.h>
+#include <mach/pinmux.h>
+#include <mach/pinmux-tegra30.h>
+#include "tegra_usb_phy.h"
+#include "gpio-names.h"
+#include "fuse.h"
+#include "clock.h"
+
+#define USB_USBCMD 0x130
+#define USB_USBCMD_RS (1 << 0)
+#define USB_CMD_RESET (1<<1)
+
+#define USB_USBSTS 0x134
+#define USB_USBSTS_PCI (1 << 2)
+#define USB_USBSTS_SRI (1 << 7)
+#define USB_USBSTS_HCH (1 << 12)
+
+#define USB_USBINTR 0x138
+
+#define USB_TXFILLTUNING 0x154
+#define USB_FIFO_TXFILL_THRES(x) (((x) & 0x1f) << 16)
+#define USB_FIFO_TXFILL_MASK 0x1f0000
+
+#define USB_ASYNCLISTADDR 0x148
+
+#define ICUSB_CTRL 0x15c
+
+#define USB_PORTSC 0x174
+#define USB_PORTSC_WKOC (1 << 22)
+#define USB_PORTSC_WKDS (1 << 21)
+#define USB_PORTSC_WKCN (1 << 20)
+#define USB_PORTSC_PTC(x) (((x) & 0xf) << 16)
+#define USB_PORTSC_PP (1 << 12)
+#define USB_PORTSC_LS(x) (((x) & 0x3) << 10)
+#define USB_PORTSC_SUSP (1 << 7)
+#define USB_PORTSC_RESUME (1 << 6)
+#define USB_PORTSC_OCC (1 << 5)
+#define USB_PORTSC_PEC (1 << 3)
+#define USB_PORTSC_PE (1 << 2)
+#define USB_PORTSC_CSC (1 << 1)
+#define USB_PORTSC_CCS (1 << 0)
+#define USB_PORTSC_RWC_BITS (USB_PORTSC_CSC | USB_PORTSC_PEC | USB_PORTSC_OCC)
+
+#define HOSTPC1_DEVLC 0x1b4
+#define HOSTPC1_DEVLC_PHCD (1 << 22)
+#define HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29)
+#define HOSTPC1_DEVLC_PTS_MASK 7
+#define HOSTPC1_DEVLC_PTS_HSIC 4
+#define HOSTPC1_DEVLC_STS (1 << 28)
+#define HOSTPC1_DEVLC_PSPD(x) (((x) & 0x3) << 25)
+#define HOSTPC1_DEVLC_PSPD_MASK 3
+#define HOSTPC1_DEVLC_PSPD_HIGH_SPEED 2
+
+#define USB_USBMODE 0x1f8
+#define USB_USBMODE_MASK (3 << 0)
+#define USB_USBMODE_HOST (3 << 0)
+#define USB_USBMODE_DEVICE (2 << 0)
+
+#define USB_SUSP_CTRL 0x400
+#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3)
+#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4)
+#define USB_SUSP_CLR (1 << 5)
+#define USB_PHY_CLK_VALID (1 << 7)
+#define USB_PHY_CLK_VALID_INT_ENB (1 << 9)
+#define USB_PHY_CLK_VALID_INT_STS (1 << 8)
+#define UTMIP_RESET (1 << 11)
+#define UTMIP_PHY_ENABLE (1 << 12)
+#define ULPI_PHY_ENABLE (1 << 13)
+#define UHSIC_RESET (1 << 14)
+#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
+#define UHSIC_PHY_ENABLE (1 << 19)
+#define ULPIS2S_SLV0_RESET (1 << 20)
+#define ULPIS2S_SLV1_RESET (1 << 21)
+#define ULPIS2S_LINE_RESET (1 << 22)
+#define ULPI_PADS_RESET (1 << 23)
+#define ULPI_PADS_CLKEN_RESET (1 << 24)
+
+#define USB_PHY_VBUS_WAKEUP_ID 0x408
+#define VDAT_DET_INT_EN (1 << 16)
+#define VDAT_DET_CHG_DET (1 << 17)
+#define VDAT_DET_STS (1 << 18)
+#define USB_ID_STATUS (1 << 2)
+
+#define ULPIS2S_CTRL 0x418
+#define ULPIS2S_ENA (1 << 0)
+#define ULPIS2S_SUPPORT_DISCONNECT (1 << 2)
+#define ULPIS2S_PLLU_MASTER_BLASTER60 (1 << 3)
+#define ULPIS2S_SPARE(x) (((x) & 0xF) << 8)
+#define ULPIS2S_FORCE_ULPI_CLK_OUT (1 << 12)
+#define ULPIS2S_DISCON_DONT_CHECK_SE0 (1 << 13)
+#define ULPIS2S_SUPPORT_HS_KEEP_ALIVE (1 << 14)
+#define ULPIS2S_DISABLE_STP_PU (1 << 15)
+#define ULPIS2S_SLV0_CLAMP_XMIT (1 << 16)
+
+#define ULPI_TIMING_CTRL_0 0x424
+#define ULPI_CLOCK_OUT_DELAY(x) ((x) & 0x1F)
+#define ULPI_OUTPUT_PINMUX_BYP (1 << 10)
+#define ULPI_CLKOUT_PINMUX_BYP (1 << 11)
+#define ULPI_SHADOW_CLK_LOOPBACK_EN (1 << 12)
+#define ULPI_SHADOW_CLK_SEL (1 << 13)
+#define ULPI_CORE_CLK_SEL (1 << 14)
+#define ULPI_SHADOW_CLK_DELAY(x) (((x) & 0x1F) << 16)
+#define ULPI_LBK_PAD_EN (1 << 26)
+#define ULPI_LBK_PAD_E_INPUT_OR (1 << 27)
+#define ULPI_CLK_OUT_ENA (1 << 28)
+#define ULPI_CLK_PADOUT_ENA (1 << 29)
+
+#define ULPI_TIMING_CTRL_1 0x428
+#define ULPI_DATA_TRIMMER_LOAD (1 << 0)
+#define ULPI_DATA_TRIMMER_SEL(x) (((x) & 0x7) << 1)
+#define ULPI_STPDIRNXT_TRIMMER_LOAD (1 << 16)
+#define ULPI_STPDIRNXT_TRIMMER_SEL(x) (((x) & 0x7) << 17)
+#define ULPI_DIR_TRIMMER_LOAD (1 << 24)
+#define ULPI_DIR_TRIMMER_SEL(x) (((x) & 0x7) << 25)
+
+#define UTMIP_XCVR_CFG0 0x808
+#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0)
+#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8)
+#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10)
+#define UTMIP_FORCE_PD_POWERDOWN (1 << 14)
+#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16)
+#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18)
+#define UTMIP_XCVR_LSBIAS_SEL (1 << 21)
+#define UTMIP_XCVR_SETUP_MSB(x) (((x) & 0x7) << 22)
+#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25)
+#define UTMIP_XCVR_MAX_OFFSET 2
+#define UTMIP_XCVR_SETUP_MAX_VALUE 0x7f
+#define UTMIP_XCVR_SETUP_MIN_VALUE 0
+#define XCVR_SETUP_MSB_CALIB(x) ((x) >> 4)
+
+#define UTMIP_BIAS_CFG0 0x80c
+#define UTMIP_OTGPD (1 << 11)
+#define UTMIP_BIASPD (1 << 10)
+#define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0)
+#define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2)
+#define UTMIP_HSDISCON_LEVEL_MSB (1 << 24)
+
+#define UTMIP_HSRX_CFG0 0x810
+#define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10)
+#define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15)
+
+#define UTMIP_HSRX_CFG1 0x814
+#define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
+
+#define UTMIP_TX_CFG0 0x820
+#define UTMIP_FS_PREABMLE_J (1 << 19)
+#define UTMIP_HS_DISCON_DISABLE (1 << 8)
+
+#define UTMIP_DEBOUNCE_CFG0 0x82c
+#define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0)
+
+#define UTMIP_BAT_CHRG_CFG0 0x830
+#define UTMIP_PD_CHRG (1 << 0)
+#define UTMIP_ON_SINK_EN (1 << 2)
+#define UTMIP_OP_SRC_EN (1 << 3)
+
+#define UTMIP_XCVR_CFG1 0x838
+#define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0)
+#define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2)
+#define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4)
+#define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18)
+
+#define UTMIP_BIAS_CFG1 0x83c
+#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3)
+#define UTMIP_BIAS_PDTRK_POWERDOWN (1 << 0)
+#define UTMIP_BIAS_PDTRK_POWERUP (1 << 1)
+
+#define UTMIP_MISC_CFG0 0x824
+#define UTMIP_DPDM_OBSERVE (1 << 26)
+#define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_J UTMIP_DPDM_OBSERVE_SEL(0xf)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_K UTMIP_DPDM_OBSERVE_SEL(0xe)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc)
+#define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22)
+#define FORCE_PULLDN_DM (1 << 8)
+#define FORCE_PULLDN_DP (1 << 9)
+#define COMB_TERMS (1 << 0)
+#define ALWAYS_FREE_RUNNING_TERMS (1 << 1)
+
+#define UTMIP_SPARE_CFG0 0x834
+#define FUSE_SETUP_SEL (1 << 3)
+#define FUSE_ATERM_SEL (1 << 4)
+
+#define UTMIP_PMC_WAKEUP0 0x84c
+#define EVENT_INT_ENB (1 << 0)
+
+#define UHSIC_PMC_WAKEUP0 0xc34
+
+#define UTMIP_BIAS_STS0 0x840
+#define UTMIP_RCTRL_VAL(x) (((x) & 0xffff) << 0)
+#define UTMIP_TCTRL_VAL(x) (((x) & (0xffff << 16)) >> 16)
+
+#define UHSIC_PLL_CFG1 0xc04
+#define UHSIC_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+#define UHSIC_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 14)
+
+#define UHSIC_HSRX_CFG0 0xc08
+#define UHSIC_ELASTIC_UNDERRUN_LIMIT(x) (((x) & 0x1f) << 2)
+#define UHSIC_ELASTIC_OVERRUN_LIMIT(x) (((x) & 0x1f) << 8)
+#define UHSIC_IDLE_WAIT(x) (((x) & 0x1f) << 13)
+
+#define UHSIC_HSRX_CFG1 0xc0c
+#define UHSIC_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
+
+#define UHSIC_TX_CFG0 0xc10
+#define UHSIC_HS_READY_WAIT_FOR_VALID (1 << 9)
+#define UHSIC_MISC_CFG0 0xc14
+#define UHSIC_SUSPEND_EXIT_ON_EDGE (1 << 7)
+#define UHSIC_DETECT_SHORT_CONNECT (1 << 8)
+#define UHSIC_FORCE_XCVR_MODE (1 << 15)
+#define UHSIC_DISABLE_BUSRESET (1 << 20)
+#define UHSIC_MISC_CFG1 0xc18
+#define UHSIC_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 2)
+
+#define UHSIC_PADS_CFG0 0xc1c
+#define UHSIC_TX_RTUNEN 0xf000
+#define UHSIC_TX_RTUNE(x) (((x) & 0xf) << 12)
+
+#define UHSIC_PADS_CFG1 0xc20
+#define UHSIC_PD_BG (1 << 2)
+#define UHSIC_PD_TX (1 << 3)
+#define UHSIC_PD_TRK (1 << 4)
+#define UHSIC_PD_RX (1 << 5)
+#define UHSIC_PD_ZI (1 << 6)
+#define UHSIC_RX_SEL (1 << 7)
+#define UHSIC_RPD_DATA (1 << 9)
+#define UHSIC_RPD_STROBE (1 << 10)
+#define UHSIC_RPU_DATA (1 << 11)
+#define UHSIC_RPU_STROBE (1 << 12)
+
+#define UHSIC_CMD_CFG0 0xc24
+#define UHSIC_PRETEND_CONNECT_DETECT (1 << 5)
+
+#define UHSIC_STAT_CFG0 0xc28
+#define UHSIC_CONNECT_DETECT (1 << 0)
+
+#define PMC_USB_DEBOUNCE 0xec
+#define UTMIP_LINE_DEB_CNT(x) (((x) & 0xf) << 16)
+#define UHSIC_LINE_DEB_CNT(x) (((x) & 0xf) << 20)
+#define PMC_USB_DEBOUNCE_VAL(x) ((x) & 0xffff)
+
+#define PMC_USB_AO 0xf0
+
+#define PMC_POWER_DOWN_MASK 0xffff
+#define HSIC_RESERVED_P0 (3 << 14)
+#define STROBE_VAL_PD_P0 (1 << 12)
+#define DATA_VAL_PD_P0 (1 << 13)
+
+#define USB_ID_PD(inst) (1 << ((4*(inst))+3))
+#define VBUS_WAKEUP_PD(inst) (1 << ((4*(inst))+2))
+#define USBON_VAL_PD(inst) (1 << ((4*(inst))+1))
+#define USBON_VAL_PD_P2 (1 << 9)
+#define USBON_VAL_PD_P1 (1 << 5)
+#define USBON_VAL_PD_P0 (1 << 1)
+#define USBOP_VAL_PD(inst) (1 << (4*(inst)))
+#define USBOP_VAL_PD_P2 (1 << 8)
+#define USBOP_VAL_PD_P1 (1 << 4)
+#define USBOP_VAL_PD_P0 (1 << 0)
+#define PMC_USB_AO_ID_PD_P0 (1 << 3)
+#define PMC_USB_AO_VBUS_WAKEUP_PD_P0 (1 << 2)
+
+#define PMC_TRIGGERS 0x1ec
+
+#define UHSIC_CLR_WALK_PTR_P0 (1 << 3)
+#define UTMIP_CLR_WALK_PTR(inst) (1 << (inst))
+#define UTMIP_CLR_WALK_PTR_P2 (1 << 2)
+#define UTMIP_CLR_WALK_PTR_P1 (1 << 1)
+#define UTMIP_CLR_WALK_PTR_P0 (1 << 0)
+#define UTMIP_CAP_CFG(inst) (1 << ((inst)+4))
+#define UTMIP_CAP_CFG_P2 (1 << 6)
+#define UTMIP_CAP_CFG_P1 (1 << 5)
+#define UTMIP_CAP_CFG_P0 (1 << 4)
+#define UTMIP_CLR_WAKE_ALARM(inst) (1 << ((inst)+12))
+#define UHSIC_CLR_WAKE_ALARM_P0 (1 << 15)
+#define UTMIP_CLR_WAKE_ALARM_P2 (1 << 14)
+
+#define PMC_PAD_CFG (0x1f4)
+
+#define PMC_UTMIP_TERM_PAD_CFG 0x1f8
+#define PMC_TCTRL_VAL(x) (((x) & 0x1f) << 5)
+#define PMC_RCTRL_VAL(x) (((x) & 0x1f) << 0)
+
+#define PMC_SLEEP_CFG 0x1fc
+
+#define UHSIC_MASTER_ENABLE (1 << 24)
+#define UHSIC_WAKE_VAL(x) (((x) & 0xf) << 28)
+#define WAKE_VAL_SD10 0x2
+#define UTMIP_TCTRL_USE_PMC(inst) (1 << ((8*(inst))+3))
+#define UTMIP_TCTRL_USE_PMC_P2 (1 << 19)
+#define UTMIP_TCTRL_USE_PMC_P1 (1 << 11)
+#define UTMIP_TCTRL_USE_PMC_P0 (1 << 3)
+#define UTMIP_RCTRL_USE_PMC(inst) (1 << ((8*(inst))+2))
+#define UTMIP_RCTRL_USE_PMC_P2 (1 << 18)
+#define UTMIP_RCTRL_USE_PMC_P1 (1 << 10)
+#define UTMIP_RCTRL_USE_PMC_P0 (1 << 2)
+#define UTMIP_FSLS_USE_PMC(inst) (1 << ((8*(inst))+1))
+#define UTMIP_FSLS_USE_PMC_P2 (1 << 17)
+#define UTMIP_FSLS_USE_PMC_P1 (1 << 9)
+#define UTMIP_FSLS_USE_PMC_P0 (1 << 1)
+#define UTMIP_MASTER_ENABLE(inst) (1 << (8*(inst)))
+#define UTMIP_MASTER_ENABLE_P2 (1 << 16)
+#define UTMIP_MASTER_ENABLE_P1 (1 << 8)
+#define UTMIP_MASTER_ENABLE_P0 (1 << 0)
+#define UHSIC_MASTER_ENABLE_P0 (1 << 24)
+#define UHSIC_WAKE_VAL_P0(x) (((x) & 0xf) << 28)
+
+#define PMC_SLEEPWALK_CFG 0x200
+
+#define UHSIC_WAKE_WALK_EN_P0 (1 << 30)
+#define UHSIC_LINEVAL_WALK_EN (1 << 31)
+#define UTMIP_LINEVAL_WALK_EN(inst) (1 << ((8*(inst))+7))
+#define UTMIP_LINEVAL_WALK_EN_P2 (1 << 23)
+#define UTMIP_LINEVAL_WALK_EN_P1 (1 << 15)
+#define UTMIP_LINEVAL_WALK_EN_P0 (1 << 7)
+#define UTMIP_WAKE_VAL(inst, x) (((x) & 0xf) << ((8*(inst))+4))
+#define UTMIP_WAKE_VAL_P2(x) (((x) & 0xf) << 20)
+#define UTMIP_WAKE_VAL_P1(x) (((x) & 0xf) << 12)
+#define UTMIP_WAKE_VAL_P0(x) (((x) & 0xf) << 4)
+#define WAKE_VAL_NONE 0xc
+#define WAKE_VAL_ANY 0xF
+#define WAKE_VAL_FSJ 0x2
+#define WAKE_VAL_FSK 0x1
+#define WAKE_VAL_SE0 0x0
+
+#define PMC_SLEEPWALK_REG(inst) (0x204 + (4*(inst)))
+#define UTMIP_USBOP_RPD_A (1 << 0)
+#define UTMIP_USBON_RPD_A (1 << 1)
+#define UTMIP_AP_A (1 << 4)
+#define UTMIP_AN_A (1 << 5)
+#define UTMIP_HIGHZ_A (1 << 6)
+#define UTMIP_USBOP_RPD_B (1 << 8)
+#define UTMIP_USBON_RPD_B (1 << 9)
+#define UTMIP_AP_B (1 << 12)
+#define UTMIP_AN_B (1 << 13)
+#define UTMIP_HIGHZ_B (1 << 14)
+#define UTMIP_USBOP_RPD_C (1 << 16)
+#define UTMIP_USBON_RPD_C (1 << 17)
+#define UTMIP_AP_C (1 << 20)
+#define UTMIP_AN_C (1 << 21)
+#define UTMIP_HIGHZ_C (1 << 22)
+#define UTMIP_USBOP_RPD_D (1 << 24)
+#define UTMIP_USBON_RPD_D (1 << 25)
+#define UTMIP_AP_D (1 << 28)
+#define UTMIP_AN_D (1 << 29)
+#define UTMIP_HIGHZ_D (1 << 30)
+
+#define PMC_SLEEPWALK_UHSIC 0x210
+
+#define UHSIC_STROBE_RPD_A (1 << 0)
+#define UHSIC_DATA_RPD_A (1 << 1)
+#define UHSIC_STROBE_RPU_A (1 << 2)
+#define UHSIC_DATA_RPU_A (1 << 3)
+#define UHSIC_STROBE_RPD_B (1 << 8)
+#define UHSIC_DATA_RPD_B (1 << 9)
+#define UHSIC_STROBE_RPU_B (1 << 10)
+#define UHSIC_DATA_RPU_B (1 << 11)
+#define UHSIC_STROBE_RPD_C (1 << 16)
+#define UHSIC_DATA_RPD_C (1 << 17)
+#define UHSIC_STROBE_RPU_C (1 << 18)
+#define UHSIC_DATA_RPU_C (1 << 19)
+#define UHSIC_STROBE_RPD_D (1 << 24)
+#define UHSIC_DATA_RPD_D (1 << 25)
+#define UHSIC_STROBE_RPU_D (1 << 26)
+#define UHSIC_DATA_RPU_D (1 << 27)
+
+#define UTMIP_UHSIC_STATUS 0x214
+
+#define UTMIP_USBOP_VAL(inst) (1 << ((2*(inst)) + 8))
+#define UTMIP_USBOP_VAL_P2 (1 << 12)
+#define UTMIP_USBOP_VAL_P1 (1 << 10)
+#define UTMIP_USBOP_VAL_P0 (1 << 8)
+#define UTMIP_USBON_VAL(inst) (1 << ((2*(inst)) + 9))
+#define UTMIP_USBON_VAL_P2 (1 << 13)
+#define UTMIP_USBON_VAL_P1 (1 << 11)
+#define UTMIP_USBON_VAL_P0 (1 << 9)
+#define UHSIC_WAKE_ALARM (1 << 19)
+#define UTMIP_WAKE_ALARM(inst) (1 << ((inst) + 16))
+#define UTMIP_WAKE_ALARM_P2 (1 << 18)
+#define UTMIP_WAKE_ALARM_P1 (1 << 17)
+#define UTMIP_WAKE_ALARM_P0 (1 << 16)
+#define UHSIC_DATA_VAL_P0 (1 << 15)
+#define UHSIC_STROBE_VAL_P0 (1 << 14)
+#define UTMIP_WALK_PTR_VAL(inst) (0x3 << ((inst)*2))
+#define UHSIC_WALK_PTR_VAL (0x3 << 6)
+#define UTMIP_WALK_PTR(inst) (1 << ((inst)*2))
+#define UTMIP_WALK_PTR_P2 (1 << 4)
+#define UTMIP_WALK_PTR_P1 (1 << 2)
+#define UTMIP_WALK_PTR_P0 (1 << 0)
+
+#define USB1_PREFETCH_ID 6
+#define USB2_PREFETCH_ID 18
+#define USB3_PREFETCH_ID 17
+
+#define PMC_UTMIP_UHSIC_FAKE 0x218
+
+#define UHSIC_STROBE_VAL (1 << 12)
+#define UHSIC_DATA_VAL (1 << 13)
+#define UHSIC_STROBE_ENB (1 << 14)
+#define UHSIC_DATA_ENB (1 << 15)
+#define USBON_VAL(inst) (1 << ((4*(inst))+1))
+#define USBON_VAL_P2 (1 << 9)
+#define USBON_VAL_P1 (1 << 5)
+#define USBON_VAL_P0 (1 << 1)
+#define USBOP_VAL(inst) (1 << (4*(inst)))
+#define USBOP_VAL_P2 (1 << 8)
+#define USBOP_VAL_P1 (1 << 4)
+#define USBOP_VAL_P0 (1 << 0)
+
+#define PMC_UTMIP_BIAS_MASTER_CNTRL 0x30c
+#define BIAS_MASTER_PROG_VAL (1 << 1)
+
+#define PMC_UTMIP_MASTER_CONFIG 0x310
+
+#define UTMIP_PWR(inst) (1 << (inst))
+#define UHSIC_PWR (1 << 3)
+
+#define FUSE_USB_CALIB_0 0x1F0
+#define XCVR_SETUP(x) (((x) & 0x7F) << 0)
+#define XCVR_SETUP_LSB_MASK 0xF
+#define XCVR_SETUP_MSB_MASK 0x70
+#define XCVR_SETUP_LSB_MAX_VAL 0xF
+
+#define APB_MISC_GP_OBSCTRL_0 0x818
+#define APB_MISC_GP_OBSDATA_0 0x81c
+
+/* ULPI GPIO */
+#define ULPI_STP TEGRA_GPIO_PY3
+#define ULPI_DIR TEGRA_GPIO_PY1
+#define ULPI_D0 TEGRA_GPIO_PO1
+#define ULPI_D1 TEGRA_GPIO_PO2
+
+/* These values (in milli second) are taken from the battery charging spec */
+#define TDP_SRC_ON_MS 100
+#define TDPSRC_CON_MS 40
+
+#ifdef DEBUG
+#define DBG(stuff...) pr_info("tegra3_usb_phy: " stuff)
+#else
+#define DBG(stuff...) do {} while (0)
+#endif
+
+#if 0
+#define PHY_DBG(stuff...) pr_info("tegra3_usb_phy: " stuff)
+#else
+#define PHY_DBG(stuff...) do {} while (0)
+#endif
+
+/* define HSIC phy params */
+#define HSIC_SYNC_START_DELAY 9
+#define HSIC_IDLE_WAIT_DELAY 17
+#define HSIC_ELASTIC_UNDERRUN_LIMIT 16
+#define HSIC_ELASTIC_OVERRUN_LIMIT 16
+
+static u32 utmip_rctrl_val, utmip_tctrl_val;
+static DEFINE_SPINLOCK(utmip_pad_lock);
+static int utmip_pad_count;
+
+static struct tegra_xtal_freq utmip_freq_table[] = {
+ {
+ .freq = 12000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x2F,
+ .active_delay = 0x04,
+ .xtal_freq_count = 0x76,
+ .debounce = 0x7530,
+ .pdtrk_count = 5,
+ },
+ {
+ .freq = 13000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x33,
+ .active_delay = 0x05,
+ .xtal_freq_count = 0x7F,
+ .debounce = 0x7EF4,
+ .pdtrk_count = 5,
+ },
+ {
+ .freq = 19200000,
+ .enable_delay = 0x03,
+ .stable_count = 0x4B,
+ .active_delay = 0x06,
+ .xtal_freq_count = 0xBB,
+ .debounce = 0xBB80,
+ .pdtrk_count = 7,
+ },
+ {
+ .freq = 26000000,
+ .enable_delay = 0x04,
+ .stable_count = 0x66,
+ .active_delay = 0x09,
+ .xtal_freq_count = 0xFE,
+ .debounce = 0xFDE8,
+ .pdtrk_count = 9,
+ },
+};
+
+static struct tegra_xtal_freq uhsic_freq_table[] = {
+ {
+ .freq = 12000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x2F,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x1CA,
+ },
+ {
+ .freq = 13000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x33,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x1F0,
+ },
+ {
+ .freq = 19200000,
+ .enable_delay = 0x03,
+ .stable_count = 0x4B,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x2DD,
+ },
+ {
+ .freq = 26000000,
+ .enable_delay = 0x04,
+ .stable_count = 0x66,
+ .active_delay = 0x0,
+ .xtal_freq_count = 0x3E0,
+ },
+};
+
+static void usb_phy_fence_read(struct tegra_usb_phy *phy)
+{
+ /* Fence read for coherency of AHB master intiated writes */
+ if (phy->inst == 0)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB1_PREFETCH_ID));
+ else if (phy->inst == 1)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB2_PREFETCH_ID));
+ else if (phy->inst == 2)
+ readb(IO_ADDRESS(IO_PPCS_PHYS + USB3_PREFETCH_ID));
+
+ return;
+}
+
+static void utmip_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val, pmc_pad_cfg_val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+ void __iomem *base = phy->regs;
+ bool port_connected;
+ enum usb_phy_port_speed port_speed;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ /* check for port connect status */
+ val = readl(base + USB_PORTSC);
+ port_connected = val & USB_PORTSC_CCS;
+
+ if (!port_connected)
+ return;
+
+ port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
+ HOSTPC1_DEVLC_PSPD_MASK;
+ /*Set PMC MASTER bits to do the following
+ * a. Take over the UTMI drivers
+ * b. set up such that it will take over resume
+ * if remote wakeup is detected
+ * Prepare PMC to take over suspend-wake detect-drive resume until USB
+ * controller ready
+ */
+
+ /* disable master enable in PMC */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_MASTER_ENABLE(inst);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* UTMIP_PWR_PX=1 for power savings mode */
+ val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG);
+ val |= UTMIP_PWR(inst);
+ writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG);
+
+ /* config debouncer */
+ val = readl(pmc_base + PMC_USB_DEBOUNCE);
+ val &= ~UTMIP_LINE_DEB_CNT(~0);
+ val |= UTMIP_LINE_DEB_CNT(4);
+ val |= PMC_USB_DEBOUNCE_VAL(2);
+ writel(val, pmc_base + PMC_USB_DEBOUNCE);
+
+ /* Make sure nothing is happening on the line with respect to PMC */
+ val = readl(pmc_base + PMC_UTMIP_UHSIC_FAKE);
+ val &= ~USBOP_VAL(inst);
+ val &= ~USBON_VAL(inst);
+ writel(val, pmc_base + PMC_UTMIP_UHSIC_FAKE);
+
+ /* Make sure wake value for line is none */
+ val = readl(pmc_base + PMC_SLEEPWALK_CFG);
+ val &= ~UTMIP_LINEVAL_WALK_EN(inst);
+ writel(val, pmc_base + PMC_SLEEPWALK_CFG);
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(inst, ~0);
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* turn off pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val |= (USBOP_VAL_PD(inst) | USBON_VAL_PD(inst));
+ writel(val, pmc_base + PMC_USB_AO);
+
+ /* Remove fake values and make synchronizers work a bit */
+ val = readl(pmc_base + PMC_UTMIP_UHSIC_FAKE);
+ val &= ~USBOP_VAL(inst);
+ val &= ~USBON_VAL(inst);
+ writel(val, pmc_base + PMC_UTMIP_UHSIC_FAKE);
+
+ /* Enable which type of event can trigger a walk,
+ * in this case usb_line_wake */
+ val = readl(pmc_base + PMC_SLEEPWALK_CFG);
+ val |= UTMIP_LINEVAL_WALK_EN(inst);
+ writel(val, pmc_base + PMC_SLEEPWALK_CFG);
+
+ /* Capture FS/LS pad configurations */
+ pmc_pad_cfg_val = readl(pmc_base + PMC_PAD_CFG);
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UTMIP_CAP_CFG(inst);
+ writel(val, pmc_base + PMC_TRIGGERS);
+ udelay(1);
+ pmc_pad_cfg_val = readl(pmc_base + PMC_PAD_CFG);
+
+ /* BIAS MASTER_ENABLE=0 */
+ val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+ val &= ~BIAS_MASTER_PROG_VAL;
+ writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+
+ /* program walk sequence, maintain a J, followed by a driven K
+ * to signal a resume once an wake event is detected */
+ val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
+ val &= ~UTMIP_AP_A;
+ val |= UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_AN_A |UTMIP_HIGHZ_A |
+ UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_AP_B | UTMIP_AN_B |
+ UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_AP_C | UTMIP_AN_C |
+ UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_AP_D | UTMIP_AN_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
+
+ if (port_speed == USB_PHY_PORT_SPEED_LOW) {
+ val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
+ val &= ~(UTMIP_AN_B | UTMIP_HIGHZ_B | UTMIP_AN_C |
+ UTMIP_HIGHZ_C | UTMIP_AN_D | UTMIP_HIGHZ_D);
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
+ } else {
+ val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
+ val &= ~(UTMIP_AP_B | UTMIP_HIGHZ_B | UTMIP_AP_C |
+ UTMIP_HIGHZ_C | UTMIP_AP_D | UTMIP_HIGHZ_D);
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
+ }
+
+ /* turn on pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val &= ~(USBOP_VAL_PD(inst) | USBON_VAL_PD(inst));
+ writel(val, pmc_base + PMC_USB_AO);
+
+ /* Add small delay before usb detectors provide stable line values */
+ mdelay(1);
+
+ /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */
+ val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+ val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val);
+ writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+
+ phy->pmc_remote_wakeup = false;
+
+ /* Turn over pad configuration to PMC for line wake events*/
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(inst, ~0);
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_ANY);
+ val |= UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst);
+ val |= UTMIP_MASTER_ENABLE(inst) | UTMIP_FSLS_USE_PMC(inst);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(base + UTMIP_PMC_WAKEUP0);
+ val |= EVENT_INT_ENB;
+ writel(val, base + UTMIP_PMC_WAKEUP0);
+ PHY_DBG("%s ENABLE_PMC inst = %d\n", __func__, inst);
+}
+
+static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(inst, 0xF);
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(base + UTMIP_PMC_WAKEUP0);
+ val &= ~EVENT_INT_ENB;
+ writel(val, base + UTMIP_PMC_WAKEUP0);
+
+ /* Disable PMC master mode by clearing MASTER_EN */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~(UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) |
+ UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst));
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val &= ~UTMIP_CAP_CFG(inst);
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ /* turn off pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val |= (USBOP_VAL_PD(inst) | USBON_VAL_PD(inst));
+ writel(val, pmc_base + PMC_USB_AO);
+
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UTMIP_CLR_WALK_PTR(inst);
+ val |= UTMIP_CLR_WAKE_ALARM(inst);
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ phy->pmc_remote_wakeup = false;
+ PHY_DBG("%s DISABLE_PMC inst = %d\n", __func__, inst);
+}
+
+static bool utmi_phy_remotewake_detected(struct tegra_usb_phy *phy)
+{
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+ unsigned int inst = phy->inst;
+ u32 val;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(base + UTMIP_PMC_WAKEUP0);
+ if (val & EVENT_INT_ENB) {
+ val = readl(pmc_base + UTMIP_UHSIC_STATUS);
+ if (UTMIP_WAKE_ALARM(inst) & val) {
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(inst, 0xF);
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UTMIP_CLR_WAKE_ALARM(inst);
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ val = readl(base + UTMIP_PMC_WAKEUP0);
+ val &= ~EVENT_INT_ENB;
+ writel(val, base + UTMIP_PMC_WAKEUP0);
+ phy->pmc_remote_wakeup = true;
+ return true;
+ }
+ }
+ return false;
+}
+
+static void utmi_phy_enable_trking_data(struct tegra_usb_phy *phy)
+{
+ void __iomem *base = IO_ADDRESS(TEGRA_USB_BASE);
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ static bool init_done = false;
+ u32 val;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ /* Should be done only once after system boot */
+ if (init_done)
+ return;
+
+ tegra_clk_prepare_enable(phy->utmi_pad_clk);
+ /* Bias pad MASTER_ENABLE=1 */
+ val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+ val |= BIAS_MASTER_PROG_VAL;
+ writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+
+ /* Setting the tracking length time */
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
+ val |= UTMIP_BIAS_PDTRK_COUNT(5);
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ /* Bias PDTRK is Shared and MUST be done from USB1 ONLY, PD_TRK=0 */
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val &= ~UTMIP_BIAS_PDTRK_POWERDOWN;
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val |= UTMIP_BIAS_PDTRK_POWERUP;
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ /* Wait for 25usec */
+ udelay(25);
+
+ /* Bias pad MASTER_ENABLE=0 */
+ val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+ val &= ~BIAS_MASTER_PROG_VAL;
+ writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+
+ /* Wait for 1usec */
+ udelay(1);
+
+ /* Bias pad MASTER_ENABLE=1 */
+ val = readl(pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+ val |= BIAS_MASTER_PROG_VAL;
+ writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
+
+ /* Read RCTRL and TCTRL from UTMIP space */
+ val = readl(base + UTMIP_BIAS_STS0);
+ utmip_rctrl_val = ffz(UTMIP_RCTRL_VAL(val));
+ utmip_tctrl_val = ffz(UTMIP_TCTRL_VAL(val));
+
+ /* PD_TRK=1 */
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val |= UTMIP_BIAS_PDTRK_POWERDOWN;
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */
+ val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+ val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val);
+ writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+ tegra_clk_disable_unprepare(phy->utmi_pad_clk);
+ init_done = true;
+}
+
+static void utmip_powerdown_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+
+ /* power down UTMIP interfaces */
+ val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG);
+ val |= UTMIP_PWR(inst);
+ writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG);
+
+ /* setup sleep walk usb controller */
+ val = UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_HIGHZ_A |
+ UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_HIGHZ_B |
+ UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_HIGHZ_C |
+ UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_HIGHZ_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
+
+ /* Program thermally encoded RCTRL_VAL, TCTRL_VAL into PMC space */
+ val = readl(pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+ val = PMC_TCTRL_VAL(utmip_tctrl_val) | PMC_RCTRL_VAL(utmip_rctrl_val);
+ writel(val, pmc_base + PMC_UTMIP_TERM_PAD_CFG);
+
+ /* Turn over pad configuration to PMC */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(inst, ~0);
+ val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE) |
+ UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) |
+ UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+ PHY_DBG("%s ENABLE_PMC inst = %d\n", __func__, inst);
+}
+
+static void utmip_powerup_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+
+ /* Disable PMC master mode by clearing MASTER_EN */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~(UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) |
+ UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst));
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+ mdelay(1);
+ PHY_DBG("%s DISABLE_PMC inst = %d\n", __func__, inst);
+}
+
+
+#ifdef KERNEL_WARNING
+static void usb_phy_power_down_pmc(void)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+
+ /* power down all 3 UTMIP interfaces */
+ val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG);
+ val |= UTMIP_PWR(0) | UTMIP_PWR(1) | UTMIP_PWR(2);
+ writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG);
+
+ /* turn on pad detectors */
+ writel(PMC_POWER_DOWN_MASK, pmc_base + PMC_USB_AO);
+
+ /* setup sleep walk fl all 3 usb controllers */
+ val = UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_HIGHZ_A |
+ UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_HIGHZ_B |
+ UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_HIGHZ_C |
+ UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_HIGHZ_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(0));
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(1));
+ writel(val, pmc_base + PMC_SLEEPWALK_REG(2));
+
+ /* enable pull downs on HSIC PMC */
+ val = UHSIC_STROBE_RPD_A | UHSIC_DATA_RPD_A | UHSIC_STROBE_RPD_B |
+ UHSIC_DATA_RPD_B | UHSIC_STROBE_RPD_C | UHSIC_DATA_RPD_C |
+ UHSIC_STROBE_RPD_D | UHSIC_DATA_RPD_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ /* Turn over pad configuration to PMC */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UTMIP_WAKE_VAL(0, ~0);
+ val &= ~UTMIP_WAKE_VAL(1, ~0);
+ val &= ~UTMIP_WAKE_VAL(2, ~0);
+ val &= ~UHSIC_WAKE_VAL_P0(~0);
+ val |= UTMIP_WAKE_VAL(0, WAKE_VAL_NONE) | UHSIC_WAKE_VAL_P0(WAKE_VAL_NONE) |
+ UTMIP_WAKE_VAL(1, WAKE_VAL_NONE) | UTMIP_WAKE_VAL(2, WAKE_VAL_NONE) |
+ UTMIP_RCTRL_USE_PMC(0) | UTMIP_RCTRL_USE_PMC(1) | UTMIP_RCTRL_USE_PMC(2) |
+ UTMIP_TCTRL_USE_PMC(0) | UTMIP_TCTRL_USE_PMC(1) | UTMIP_TCTRL_USE_PMC(2) |
+ UTMIP_FSLS_USE_PMC(0) | UTMIP_FSLS_USE_PMC(1) | UTMIP_FSLS_USE_PMC(2) |
+ UTMIP_MASTER_ENABLE(0) | UTMIP_MASTER_ENABLE(1) | UTMIP_MASTER_ENABLE(2) |
+ UHSIC_MASTER_ENABLE_P0;
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+}
+#endif
+
+static int usb_phy_bringup_host_controller(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ PHY_DBG("[%d] USB_USBSTS[0x%x] USB_PORTSC[0x%x] port_speed[%d]\n", __LINE__,
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC),
+ phy->port_speed);
+
+ /* Device is plugged in when system is in LP0 */
+ /* Bring up the controller from LP0*/
+ val = readl(base + USB_USBCMD);
+ val |= USB_CMD_RESET;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_CMD_RESET, 0, 2500) < 0) {
+ pr_err("%s: timeout waiting for reset\n", __func__);
+ }
+
+ val = readl(base + USB_USBMODE);
+ val &= ~USB_USBMODE_MASK;
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE);
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PTS(~0);
+
+ if (phy->pdata->phy_intf == TEGRA_USB_PHY_INTF_HSIC)
+ val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
+ else
+ val |= HOSTPC1_DEVLC_STS;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ /* Enable Port Power */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PP;
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ /* Check if the phy resume from LP0. When the phy resume from LP0
+ * USB register will be reset.to zero */
+ if (!readl(base + USB_ASYNCLISTADDR)) {
+ /* Program the field PTC based on the saved speed mode */
+ val = readl(base + USB_PORTSC);
+ val &= ~USB_PORTSC_PTC(~0);
+ if ((phy->port_speed == USB_PHY_PORT_SPEED_HIGH) ||
+ (phy->pdata->phy_intf == TEGRA_USB_PHY_INTF_HSIC))
+ val |= USB_PORTSC_PTC(5);
+ else if (phy->port_speed == USB_PHY_PORT_SPEED_FULL)
+ val |= USB_PORTSC_PTC(6);
+ else if (phy->port_speed == USB_PHY_PORT_SPEED_LOW)
+ val |= USB_PORTSC_PTC(7);
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ /* Disable test mode by setting PTC field to NORMAL_OP */
+ val = readl(base + USB_PORTSC);
+ val &= ~USB_PORTSC_PTC(~0);
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+ }
+
+ /* Poll until CCS is enabled */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_CCS,
+ USB_PORTSC_CCS, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_CCS\n", __func__);
+ }
+
+ /* Poll until PE is enabled */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_PE,
+ USB_PORTSC_PE, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_PE\n", __func__);
+ }
+
+ /* Clear the PCI status, to avoid an interrupt taken upon resume */
+ val = readl(base + USB_USBSTS);
+ val |= USB_USBSTS_PCI;
+ writel(val, base + USB_USBSTS);
+
+ if (!phy->pmc_remote_wakeup) {
+ /* Put controller in suspend mode by writing 1 to SUSP bit of PORTSC */
+ val = readl(base + USB_PORTSC);
+ if ((val & USB_PORTSC_PP) && (val & USB_PORTSC_PE)) {
+ val |= USB_PORTSC_SUSP;
+ writel(val, base + USB_PORTSC);
+ /* Need a 4ms delay before the controller goes to suspend */
+ mdelay(4);
+
+ /* Wait until port suspend completes */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_SUSP,
+ USB_PORTSC_SUSP, 1000)) {
+ pr_err("%s: timeout waiting for PORT_SUSPEND\n",
+ __func__);
+ }
+ }
+ }
+ PHY_DBG("[%d] USB_USBSTS[0x%x] USB_PORTSC[0x%x] port_speed[%d]\n", __LINE__,
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC),
+ phy->port_speed);
+
+ DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n",
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC));
+ return 0;
+}
+
+static void usb_phy_wait_for_sof(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(base + USB_USBSTS);
+ writel(val, base + USB_USBSTS);
+ udelay(20);
+ /* wait for two SOFs */
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI,
+ USB_USBSTS_SRI, 2500))
+ pr_err("%s: timeout waiting for SOF\n", __func__);
+
+ val = readl(base + USB_USBSTS);
+ writel(val, base + USB_USBSTS);
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI, 0, 2500))
+ pr_err("%s: timeout waiting for SOF\n", __func__);
+
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_SRI,
+ USB_USBSTS_SRI, 2500))
+ pr_err("%s: timeout waiting for SOF\n", __func__);
+
+ udelay(20);
+}
+
+static unsigned int utmi_phy_xcvr_setup_value(struct tegra_usb_phy *phy)
+{
+ struct tegra_utmi_config *cfg = &phy->pdata->u_cfg.utmi;
+ signed long val;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ if (cfg->xcvr_use_fuses) {
+ val = XCVR_SETUP(tegra_fuse_readl(FUSE_USB_CALIB_0));
+ if (cfg->xcvr_use_lsb) {
+ val = min((unsigned int) ((val & XCVR_SETUP_LSB_MASK)
+ + cfg->xcvr_setup_offset),
+ (unsigned int) XCVR_SETUP_LSB_MAX_VAL);
+ val |= (cfg->xcvr_setup & XCVR_SETUP_MSB_MASK);
+ } else {
+ if (cfg->xcvr_setup_offset <= UTMIP_XCVR_MAX_OFFSET)
+ val = val + cfg->xcvr_setup_offset;
+
+ if (val > UTMIP_XCVR_SETUP_MAX_VALUE) {
+ val = UTMIP_XCVR_SETUP_MAX_VALUE;
+ pr_info("%s: reset XCVR_SETUP to max value\n",
+ __func__);
+ } else if (val < UTMIP_XCVR_SETUP_MIN_VALUE) {
+ val = UTMIP_XCVR_SETUP_MIN_VALUE;
+ pr_info("%s: reset XCVR_SETUP to min value\n",
+ __func__);
+ }
+ }
+ } else {
+ val = cfg->xcvr_setup;
+ }
+
+ return (unsigned int) val;
+}
+
+static int utmi_phy_open(struct tegra_usb_phy *phy)
+{
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned long parent_rate, val;
+ int i;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ phy->utmi_pad_clk = clk_get_sys("utmip-pad", NULL);
+ if (IS_ERR(phy->utmi_pad_clk)) {
+ pr_err("%s: can't get utmip pad clock\n", __func__);
+ return PTR_ERR(phy->utmi_pad_clk);
+ }
+
+ phy->utmi_xcvr_setup = utmi_phy_xcvr_setup_value(phy);
+
+ parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk));
+ for (i = 0; i < ARRAY_SIZE(utmip_freq_table); i++) {
+ if (utmip_freq_table[i].freq == parent_rate) {
+ phy->freq = &utmip_freq_table[i];
+ break;
+ }
+ }
+ if (!phy->freq) {
+ pr_err("invalid pll_u parent rate %ld\n", parent_rate);
+ return -EINVAL;
+ }
+
+ /* Power-up the VBUS detector for UTMIP PHY */
+ val = readl(pmc_base + PMC_USB_AO);
+ val &= ~(PMC_USB_AO_VBUS_WAKEUP_PD_P0 | PMC_USB_AO_ID_PD_P0);
+ writel(val, (pmc_base + PMC_USB_AO));
+
+ utmip_powerup_pmc_wake_detect(phy);
+
+ return 0;
+}
+
+static void utmi_phy_close(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s inst:[%d]\n", __func__, phy->inst);
+
+ /* Disable PHY clock valid interrupts while going into suspend*/
+ if (phy->hot_plug) {
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_PHY_CLK_VALID_INT_ENB;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+
+ clk_put(phy->utmi_pad_clk);
+}
+
+static int utmi_phy_pad_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val, flags;
+ void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE);
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ tegra_clk_prepare_enable(phy->utmi_pad_clk);
+
+ spin_lock_irqsave(&utmip_pad_lock, flags);
+ utmip_pad_count++;
+
+ val = readl(pad_base + UTMIP_BIAS_CFG0);
+ val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
+ val |= UTMIP_HSSQUELCH_LEVEL(0x2) | UTMIP_HSDISCON_LEVEL(0x1) |
+ UTMIP_HSDISCON_LEVEL_MSB;
+ writel(val, pad_base + UTMIP_BIAS_CFG0);
+
+ spin_unlock_irqrestore(&utmip_pad_lock, flags);
+
+ tegra_clk_disable_unprepare(phy->utmi_pad_clk);
+
+ return 0;
+}
+
+static int utmi_phy_pad_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val, flags;
+ void __iomem *pad_base = IO_ADDRESS(TEGRA_USB_BASE);
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ tegra_clk_prepare_enable(phy->utmi_pad_clk);
+ spin_lock_irqsave(&utmip_pad_lock, flags);
+
+ if (!utmip_pad_count) {
+ pr_err("%s: utmip pad already powered off\n", __func__);
+ goto out;
+ }
+ if (--utmip_pad_count == 0) {
+ val = readl(pad_base + UTMIP_BIAS_CFG0);
+ val |= UTMIP_OTGPD | UTMIP_BIASPD;
+ val &= ~(UTMIP_HSSQUELCH_LEVEL(~0) | UTMIP_HSDISCON_LEVEL(~0) |
+ UTMIP_HSDISCON_LEVEL_MSB);
+ writel(val, pad_base + UTMIP_BIAS_CFG0);
+ }
+out:
+ spin_unlock_irqrestore(&utmip_pad_lock, flags);
+ tegra_clk_disable_unprepare(phy->utmi_pad_clk);
+
+ return 0;
+}
+
+static int utmi_phy_irq(struct tegra_usb_phy *phy)
+{
+ void __iomem *base = phy->regs;
+ unsigned long val = 0;
+ bool remote_wakeup = false;
+ int irq_status = IRQ_HANDLED;
+
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n",
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC));
+ DBG("USB_USBMODE[0x%x] USB_USBCMD[0x%x]\n",
+ readl(base + USB_USBMODE), readl(base + USB_USBCMD));
+ }
+
+ usb_phy_fence_read(phy);
+ /* check if there is any remote wake event */
+ if (utmi_phy_remotewake_detected(phy)) {
+ pr_info("%s: utmip remote wake detected\n", __func__);
+ remote_wakeup = true;
+ }
+
+ if (phy->hot_plug) {
+ val = readl(base + USB_SUSP_CTRL);
+ if ((val & USB_PHY_CLK_VALID_INT_STS)) {
+ val &= ~USB_PHY_CLK_VALID_INT_ENB |
+ USB_PHY_CLK_VALID_INT_STS;
+ writel(val , (base + USB_SUSP_CTRL));
+
+ /* In case of remote wakeup PHY clock will not up
+ immediately, so should not access any controller
+ register but normal plug-in/plug-out should be
+ executed */
+ if (!remote_wakeup) {
+ val = readl(base + USB_USBSTS);
+ if (!(val & USB_USBSTS_PCI)) {
+ irq_status = IRQ_NONE;
+ goto exit;
+ }
+
+ val = readl(base + USB_PORTSC);
+ if (val & USB_PORTSC_CCS)
+ val &= ~USB_PORTSC_WKCN;
+ else
+ val &= ~USB_PORTSC_WKDS;
+ val &= ~USB_PORTSC_RWC_BITS;
+ writel(val , (base + USB_PORTSC));
+ }
+ } else if (!phy->phy_clk_on) {
+ if (remote_wakeup)
+ irq_status = IRQ_HANDLED;
+ else
+ irq_status = IRQ_NONE;
+ goto exit;
+ }
+ }
+exit:
+ return irq_status;
+}
+
+static void utmi_phy_enable_obs_bus(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ /* (2LS WAR)is not required for LS and FS devices and is only for HS */
+ if ((phy->port_speed == USB_PHY_PORT_SPEED_LOW) ||
+ (phy->port_speed == USB_PHY_PORT_SPEED_FULL)) {
+ /* do not enable the OBS bus */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~(UTMIP_DPDM_OBSERVE_SEL(~0));
+ writel(val, base + UTMIP_MISC_CFG0);
+ DBG("%s(%d) Disable OBS bus\n", __func__, __LINE__);
+ return;
+ }
+ /* Force DP/DM pulldown active for Host mode */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val |= FORCE_PULLDN_DM | FORCE_PULLDN_DP |
+ COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS;
+ writel(val, base + UTMIP_MISC_CFG0);
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
+ if (phy->port_speed == USB_PHY_PORT_SPEED_LOW)
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
+ else
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(1);
+
+ val = readl(base + UTMIP_MISC_CFG0);
+ val |= UTMIP_DPDM_OBSERVE;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(10);
+ DBG("%s(%d) Enable OBS bus\n", __func__, __LINE__);
+ PHY_DBG("ENABLE_OBS_BUS\n");
+}
+
+static int utmi_phy_disable_obs_bus(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ unsigned long flags;
+
+ /* check if OBS bus is already enabled */
+ val = readl(base + UTMIP_MISC_CFG0);
+ if (val & UTMIP_DPDM_OBSERVE) {
+ PHY_DBG("DISABLE_OBS_BUS\n");
+
+ /* disable ALL interrupts on current CPU */
+ local_irq_save(flags);
+
+ /* Change the UTMIP OBS bus to drive SE0 */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_SE0;
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ /* Wait for 3us(2 LS bit times) */
+ udelay(3);
+
+ /* Release UTMIP OBS bus */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_DPDM_OBSERVE;
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ /* Release DP/DM pulldown for Host mode */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~(FORCE_PULLDN_DM | FORCE_PULLDN_DP |
+ COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS);
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ /* restore ALL interrupts on current CPU */
+ local_irq_restore(flags);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS,
+ USB_USBCMD_RS, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+ return 0;
+}
+
+static int utmi_phy_post_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->inst;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ /* if PMC is not disabled by now then disable it */
+ if (val & UTMIP_MASTER_ENABLE(inst)) {
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+ }
+
+ utmi_phy_disable_obs_bus(phy);
+
+ return 0;
+}
+
+static int phy_post_suspend(struct tegra_usb_phy *phy)
+{
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ /* Need a 4ms delay for controller to suspend */
+ mdelay(4);
+
+ return 0;
+
+}
+
+static int utmi_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+ unsigned int inst = phy->inst;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ phy->port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
+ HOSTPC1_DEVLC_PSPD_MASK;
+
+ if (phy->port_speed == USB_PHY_PORT_SPEED_HIGH) {
+ /* Disable interrupts */
+ writel(0, base + USB_USBINTR);
+ /* Clear the run bit to stop SOFs - 2LS WAR */
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_HCH,
+ USB_USBSTS_HCH, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBSTS_HCH\n", __func__);
+ }
+ }
+
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ if (val & UTMIP_MASTER_ENABLE(inst)) {
+ if (!remote_wakeup)
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+ } else {
+ utmi_phy_enable_obs_bus(phy);
+ }
+
+ return 0;
+}
+
+static int utmi_phy_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ PHY_DBG("%s(%d) inst:[%d] BEGIN\n", __func__, __LINE__, phy->inst);
+ if (!phy->phy_clk_on) {
+ PHY_DBG("%s(%d) inst:[%d] phy clk is already off\n",
+ __func__, __LINE__, phy->inst);
+ return 0;
+ }
+
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
+ utmip_powerdown_pmc_wake_detect(phy);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
+ val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ } else {
+ phy->port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
+ HOSTPC1_DEVLC_PSPD_MASK;
+
+ /* Disable interrupts */
+ writel(0, base + USB_USBINTR);
+
+ /* Clear the run bit to stop SOFs - 2LS WAR */
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_HCH,
+ USB_USBSTS_HCH, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBSTS_HCH\n", __func__);
+ }
+ utmip_setup_pmc_wake_detect(phy);
+ }
+
+ if (!phy->hot_plug) {
+ val = readl(base + UTMIP_XCVR_CFG0);
+ val |= (UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
+ UTMIP_FORCE_PDZI_POWERDOWN);
+ writel(val, base + UTMIP_XCVR_CFG0);
+ }
+
+ val = readl(base + UTMIP_XCVR_CFG1);
+ val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
+ UTMIP_FORCE_PDDR_POWERDOWN;
+ writel(val, base + UTMIP_XCVR_CFG1);
+
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ utmi_phy_pad_power_off(phy);
+
+ if (phy->hot_plug) {
+ bool enable_hotplug = true;
+ /* if it is OTG port then make sure to enable hot-plug feature
+ only if host adaptor is connected, i.e id is low */
+ if (phy->pdata->port_otg) {
+ val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+ enable_hotplug = (val & USB_ID_STATUS) ? false : true;
+ }
+ if (enable_hotplug) {
+ /* Enable wakeup event of device plug-in/plug-out */
+ val = readl(base + USB_PORTSC);
+ if (val & USB_PORTSC_CCS)
+ val |= USB_PORTSC_WKDS;
+ else
+ val |= USB_PORTSC_WKCN;
+ writel(val, base + USB_PORTSC);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= USB_PHY_CLK_VALID_INT_ENB;
+ writel(val, base + USB_SUSP_CTRL);
+ } else {
+ /* Disable PHY clock valid interrupts while going into suspend*/
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_PHY_CLK_VALID_INT_ENB;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+ }
+
+ /* Disable PHY clock */
+ val = readl(base + HOSTPC1_DEVLC);
+ val |= HOSTPC1_DEVLC_PHCD;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ if (!phy->hot_plug) {
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+
+ PHY_DBG("%s(%d) inst:[%d] END\n", __func__, __LINE__, phy->inst);
+
+ return 0;
+}
+
+
+static int utmi_phy_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ struct tegra_utmi_config *config = &phy->pdata->u_cfg.utmi;
+
+ PHY_DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->phy_clk_on) {
+ PHY_DBG("%s(%d) inst:[%d] phy clk is already On\n",
+ __func__, __LINE__, phy->inst);
+ return 0;
+ }
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_TX_CFG0);
+ val |= UTMIP_FS_PREABMLE_J;
+ writel(val, base + UTMIP_TX_CFG0);
+
+ val = readl(base + UTMIP_HSRX_CFG0);
+ val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0));
+ val |= UTMIP_IDLE_WAIT(config->idle_wait_delay);
+ val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit);
+ writel(val, base + UTMIP_HSRX_CFG0);
+
+ val = readl(base + UTMIP_HSRX_CFG1);
+ val &= ~UTMIP_HS_SYNC_START_DLY(~0);
+ val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay);
+ writel(val, base + UTMIP_HSRX_CFG1);
+
+ val = readl(base + UTMIP_DEBOUNCE_CFG0);
+ val &= ~UTMIP_BIAS_DEBOUNCE_A(~0);
+ val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce);
+ writel(val, base + UTMIP_DEBOUNCE_CFG0);
+
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE) {
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val &= ~UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ } else {
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+ }
+
+ utmi_phy_pad_power_on(phy);
+
+ val = readl(base + UTMIP_XCVR_CFG0);
+ val &= ~(UTMIP_XCVR_LSBIAS_SEL | UTMIP_FORCE_PD_POWERDOWN |
+ UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN |
+ UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_LSFSLEW(~0) |
+ UTMIP_XCVR_LSRSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0));
+ val |= UTMIP_XCVR_SETUP(phy->utmi_xcvr_setup);
+ val |= UTMIP_XCVR_SETUP_MSB(XCVR_SETUP_MSB_CALIB(phy->utmi_xcvr_setup));
+ val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
+ val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
+ if (!config->xcvr_use_lsb)
+ val |= UTMIP_XCVR_HSSLEW_MSB(0x8);
+ writel(val, base + UTMIP_XCVR_CFG0);
+
+ val = readl(base + UTMIP_XCVR_CFG1);
+ val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
+ UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0));
+ val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
+ writel(val, base + UTMIP_XCVR_CFG1);
+
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
+ val |= UTMIP_BIAS_PDTRK_COUNT(phy->freq->pdtrk_count);
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ val = readl(base + UTMIP_SPARE_CFG0);
+ val &= ~FUSE_SETUP_SEL;
+ val |= FUSE_ATERM_SEL;
+ writel(val, base + UTMIP_SPARE_CFG0);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PHCD;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500))
+ pr_warn("%s: timeout waiting for phy to stabilize\n", __func__);
+
+ utmi_phy_enable_trking_data(phy);
+
+ if (phy->inst == 2)
+ writel(0, base + ICUSB_CTRL);
+
+ val = readl(base + USB_USBMODE);
+ val &= ~USB_USBMODE_MASK;
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST)
+ val |= USB_USBMODE_HOST;
+ else
+ val |= USB_USBMODE_DEVICE;
+ writel(val, base + USB_USBMODE);
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PTS(~0);
+ val |= HOSTPC1_DEVLC_STS;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE)
+ utmip_powerup_pmc_wake_detect(phy);
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+ PHY_DBG("%s(%d) End inst:[%d]\n", __func__, __LINE__, phy->inst);
+ return 0;
+}
+
+static void utmi_phy_restore_start(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ int inst = phy->inst;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(pmc_base + UTMIP_UHSIC_STATUS);
+ /* Check whether we wake up from the remote resume.
+ For lp1 case, pmc is not responsible for waking the
+ system, it's the flow controller and hence
+ UTMIP_WALK_PTR_VAL(inst) will return 0.
+ Also, for lp1 case phy->pmc_remote_wakeup will already be set
+ to true by utmi_phy_irq() when the remote wakeup happens.
+ Hence change the logic in the else part to enter only
+ if phy->pmc_remote_wakeup is not set to true by the
+ utmi_phy_irq(). */
+ if (UTMIP_WALK_PTR_VAL(inst) & val) {
+ phy->pmc_remote_wakeup = true;
+ } else if (!phy->pmc_remote_wakeup) {
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ if (val & UTMIP_MASTER_ENABLE(inst))
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+ }
+
+ utmi_phy_enable_obs_bus(phy);
+}
+
+static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ int wait_time_us = 25000; /* FPR should be set by this time */
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ /* check whether we wake up from the remote resume */
+ if (phy->pmc_remote_wakeup) {
+ /* wait until SUSPEND and RESUME bit is cleared on remote resume */
+ do {
+ val = readl(base + USB_PORTSC);
+ udelay(1);
+ if (wait_time_us == 0) {
+ PHY_DBG("%s PMC FPR timeout val = 0x%lx ",
+ __func__, val);
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+ utmi_phy_post_resume(phy);
+ return;
+ }
+ wait_time_us--;
+ } while (val & (USB_PORTSC_RESUME | USB_PORTSC_SUSP));
+
+ /* wait for 25 ms to port resume complete */
+ msleep(25);
+ /* disable PMC master control */
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+
+ /* Clear PCI and SRI bits to avoid an interrupt upon resume */
+ val = readl(base + USB_USBSTS);
+ writel(val, base + USB_USBSTS);
+ /* wait to avoid SOF if there is any */
+ if (usb_phy_reg_status_wait(base + USB_USBSTS,
+ USB_USBSTS_SRI, USB_USBSTS_SRI, 2500) < 0) {
+ pr_err("%s: timeout waiting for SOF\n", __func__);
+ }
+ utmi_phy_post_resume(phy);
+ }
+}
+
+static int utmi_phy_resume(struct tegra_usb_phy *phy)
+{
+ int status = 0;
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) {
+ if (readl(base + USB_ASYNCLISTADDR) &&
+ !phy->pdata->u_data.host.power_off_on_suspend)
+ return 0;
+
+ if (phy->port_speed < USB_PHY_PORT_SPEED_UNKNOWN) {
+ utmi_phy_restore_start(phy);
+ usb_phy_bringup_host_controller(phy);
+ utmi_phy_restore_end(phy);
+ } else {
+ /* device is plugged in when system is in LP0 */
+ /* bring up the controller from LP0*/
+ val = readl(base + USB_USBCMD);
+ val |= USB_CMD_RESET;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_CMD_RESET, 0, 2500) < 0) {
+ pr_err("%s: timeout waiting for reset\n", __func__);
+ }
+
+ val = readl(base + USB_USBMODE);
+ val &= ~USB_USBMODE_MASK;
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE);
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PTS(~0);
+ val |= HOSTPC1_DEVLC_STS;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ writel(USB_USBCMD_RS, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_USBCMD_RS, USB_USBCMD_RS, 2500) < 0) {
+ pr_err("%s: timeout waiting for run bit\n", __func__);
+ }
+
+ /* Enable Port Power */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PP;
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n",
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC));
+ }
+ }
+
+ return status;
+}
+
+static bool utmi_phy_charger_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ bool status;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->pdata->op_mode != TEGRA_USB_OPMODE_DEVICE) {
+ /* Charger detection is not there for ULPI
+ * return Charger not available */
+ return false;
+ }
+
+ /* Enable charger detection logic */
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+ /* Source should be on for 100 ms as per USB charging spec */
+ msleep(TDP_SRC_ON_MS);
+
+ val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+ /* If charger is not connected disable the interrupt */
+ val &= ~VDAT_DET_INT_EN;
+ val |= VDAT_DET_CHG_DET;
+ writel(val, base + USB_PHY_VBUS_WAKEUP_ID);
+
+ val = readl(base + USB_PHY_VBUS_WAKEUP_ID);
+ if (val & VDAT_DET_STS)
+ status = true;
+ else
+ status = false;
+
+ /* Disable charger detection logic */
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val &= ~(UTMIP_OP_SRC_EN | UTMIP_ON_SINK_EN);
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+ /* Delay of 40 ms before we pull the D+ as per battery charger spec */
+ msleep(TDPSRC_CON_MS);
+
+ return status;
+}
+
+static void uhsic_powerup_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+
+ /* turn on pad detectors for HSIC*/
+ val = readl(pmc_base + PMC_USB_AO);
+ val &= ~(HSIC_RESERVED_P0 | STROBE_VAL_PD_P0 | DATA_VAL_PD_P0);
+ writel(val, pmc_base + PMC_USB_AO);
+
+ /* Disable PMC master mode by clearing MASTER_EN */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~(UHSIC_MASTER_ENABLE_P0);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+ mdelay(1);
+}
+
+static void uhsic_powerdown_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+
+ DBG("%s:%d\n", __func__, __LINE__);
+
+ /* turn off pad detectors for HSIC*/
+ val = readl(pmc_base + PMC_USB_AO);
+ val |= (HSIC_RESERVED_P0 | STROBE_VAL_PD_P0 | DATA_VAL_PD_P0);
+ writel(val, pmc_base + PMC_USB_AO);
+
+ /* enable pull downs on HSIC PMC */
+ val = UHSIC_STROBE_RPD_A | UHSIC_DATA_RPD_A | UHSIC_STROBE_RPD_B |
+ UHSIC_DATA_RPD_B | UHSIC_STROBE_RPD_C | UHSIC_DATA_RPD_C |
+ UHSIC_STROBE_RPD_D | UHSIC_DATA_RPD_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ /* Turn over pad configuration to PMC */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_WAKE_VAL_P0(~0);
+ val |= UHSIC_WAKE_VAL_P0(WAKE_VAL_NONE) | UHSIC_MASTER_ENABLE_P0;
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+}
+
+static void uhsic_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+ bool port_connected;
+
+ DBG("%s:%d\n", __func__, __LINE__);
+
+ /* check for port connect status */
+ val = readl(base + USB_PORTSC);
+ port_connected = val & USB_PORTSC_CCS;
+
+ if (!port_connected)
+ return;
+
+ /*Set PMC MASTER bits to do the following
+ * a. Take over the hsic drivers
+ * b. set up such that it will take over resume
+ * if remote wakeup is detected
+ * Prepare PMC to take over suspend-wake detect-drive resume until USB
+ * controller ready
+ */
+
+ /* disable master enable in PMC */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_MASTER_ENABLE_P0;
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* UTMIP_PWR_PX=1 for power savings mode */
+ val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG);
+ val |= UHSIC_PWR;
+ writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG);
+
+ /* config debouncer */
+ val = readl(pmc_base + PMC_USB_DEBOUNCE);
+ val |= PMC_USB_DEBOUNCE_VAL(2);
+ writel(val, pmc_base + PMC_USB_DEBOUNCE);
+
+ /* Make sure nothing is happening on the line with respect to PMC */
+ val = readl(pmc_base + PMC_UTMIP_UHSIC_FAKE);
+ val &= ~UHSIC_STROBE_VAL;
+ val &= ~UHSIC_DATA_VAL;
+ writel(val, pmc_base + PMC_UTMIP_UHSIC_FAKE);
+
+ /* Clear walk enable */
+ val = readl(pmc_base + PMC_SLEEPWALK_CFG);
+ val &= ~UHSIC_LINEVAL_WALK_EN;
+ writel(val, pmc_base + PMC_SLEEPWALK_CFG);
+
+ /* Make sure wake value for line is none */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_WAKE_VAL(WAKE_VAL_ANY);
+ val |= UHSIC_WAKE_VAL(WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* turn on pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val &= ~(STROBE_VAL_PD_P0 | DATA_VAL_PD_P0);
+ writel(val, pmc_base + PMC_USB_AO);
+
+ /* Add small delay before usb detectors provide stable line values */
+ udelay(1);
+
+ /* Enable which type of event can trigger a walk,
+ * in this case usb_line_wake */
+ val = readl(pmc_base + PMC_SLEEPWALK_CFG);
+ val |= UHSIC_LINEVAL_WALK_EN;
+ writel(val, pmc_base + PMC_SLEEPWALK_CFG);
+
+ /* program walk sequence, maintain a J, followed by a driven K
+ * to signal a resume once an wake event is detected */
+
+ val = readl(pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ val &= ~UHSIC_DATA_RPU_A;
+ val |= UHSIC_DATA_RPD_A;
+ val &= ~UHSIC_STROBE_RPD_A;
+ val |= UHSIC_STROBE_RPU_A;
+
+ val &= ~UHSIC_DATA_RPD_B;
+ val |= UHSIC_DATA_RPU_B;
+ val &= ~UHSIC_STROBE_RPU_B;
+ val |= UHSIC_STROBE_RPD_B;
+
+ val &= ~UHSIC_DATA_RPD_C;
+ val |= UHSIC_DATA_RPU_C;
+ val &= ~UHSIC_STROBE_RPU_C;
+ val |= UHSIC_STROBE_RPD_C;
+
+ val &= ~UHSIC_DATA_RPD_D;
+ val |= UHSIC_DATA_RPU_D;
+ val &= ~UHSIC_STROBE_RPU_D;
+ val |= UHSIC_STROBE_RPD_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ phy->pmc_remote_wakeup = false;
+
+ /* Setting Wake event*/
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_WAKE_VAL(WAKE_VAL_ANY);
+ val |= UHSIC_WAKE_VAL(WAKE_VAL_SD10);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* Clear the walk pointers and wake alarm */
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UHSIC_CLR_WAKE_ALARM_P0 | UHSIC_CLR_WALK_PTR_P0;
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ /* Turn over pad configuration to PMC for line wake events*/
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val |= UHSIC_MASTER_ENABLE;
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(base + UHSIC_PMC_WAKEUP0);
+ val |= EVENT_INT_ENB;
+ writel(val, base + UHSIC_PMC_WAKEUP0);
+
+ PHY_DBG("%s ENABLE_PMC\n", __func__);
+}
+
+static void uhsic_phy_pmc_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+ bool port_connected;
+
+ DBG("%s:%d\n", __func__, __LINE__);
+
+ /* check for port connect status */
+ val = readl(base + USB_PORTSC);
+ port_connected = val & USB_PORTSC_CCS;
+
+ if (!port_connected)
+ return;
+
+ /* Make sure wake value for line is none */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_WAKE_VAL(WAKE_VAL_ANY);
+ val |= UHSIC_WAKE_VAL(WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+
+ /* turn on pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val &= ~(STROBE_VAL_PD_P0 | DATA_VAL_PD_P0);
+ writel(val, pmc_base + PMC_USB_AO);
+
+ /* Add small delay before usb detectors provide stable line values */
+ udelay(1);
+
+ /* If it is during remote wakeup, set resume state on the BUS.
+ If it is during AP resume, set suspend state on the BUS. */
+ val = readl(pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ if (remote_wakeup) {
+ /* Switching PMC from SUSPEND to resume.*/
+ val &= ~UHSIC_DATA_RPD_A;
+ val |= UHSIC_DATA_RPU_A;
+ val &= ~UHSIC_STROBE_RPU_A;
+ val |= UHSIC_STROBE_RPD_A;
+ } else {
+ val &= ~UHSIC_DATA_RPU_A;
+ val |= UHSIC_DATA_RPD_A;
+ val &= ~UHSIC_STROBE_RPD_A;
+ val |= UHSIC_STROBE_RPU_A;
+ }
+
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ /* Turn over pad configuration to PMC for line wake events*/
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val |= UHSIC_MASTER_ENABLE;
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+}
+
+static void uhsic_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+
+ DBG("%s (%d)\n", __func__, __LINE__);
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_WAKE_VAL(WAKE_VAL_ANY);
+ val |= UHSIC_WAKE_VAL(WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(base + UHSIC_PMC_WAKEUP0);
+ val &= ~EVENT_INT_ENB;
+ writel(val, base + UHSIC_PMC_WAKEUP0);
+
+ /* Disable PMC master mode by clearing MASTER_EN */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~(UHSIC_MASTER_ENABLE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* turn off pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val |= (STROBE_VAL_PD_P0 | DATA_VAL_PD_P0);
+ writel(val, pmc_base + PMC_USB_AO);
+
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= (UHSIC_CLR_WALK_PTR_P0 | UHSIC_CLR_WAKE_ALARM_P0);
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ phy->pmc_remote_wakeup = false;
+}
+
+static bool uhsic_phy_remotewake_detected(struct tegra_usb_phy *phy)
+{
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+ u32 val;
+
+ val = readl(base + UHSIC_PMC_WAKEUP0);
+ if (val & EVENT_INT_ENB) {
+ val = readl(pmc_base + UTMIP_UHSIC_STATUS);
+ if (UHSIC_WAKE_ALARM & val) {
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_WAKE_VAL(WAKE_VAL_ANY);
+ val |= UHSIC_WAKE_VAL(WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UHSIC_CLR_WAKE_ALARM_P0;
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ val = readl(base + UHSIC_PMC_WAKEUP0);
+ val &= ~EVENT_INT_ENB;
+ writel(val, base + UHSIC_PMC_WAKEUP0);
+ phy->pmc_remote_wakeup = true;
+ DBG("%s:PMC remote wakeup detected for HSIC\n", __func__);
+ return true;
+ }
+ }
+ return false;
+}
+
+static int uhsic_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
+{
+ void __iomem *base = phy->regs;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned long val;
+
+ DBG("%s(%d)\n", __func__, __LINE__);
+
+ /* Clear the run bit to stop SOFs - 2LS WAR */
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_HCH,
+ USB_USBSTS_HCH, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBSTS_HCH\n", __func__);
+ }
+
+ /* disable USB interrupts */
+ writel(0, base + USB_USBINTR);
+
+ /* If PMC is not enabled, enable it. */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ if (!(val & UHSIC_MASTER_ENABLE_P0)) {
+ /** set PMC lines in suspend and enable the master */
+ uhsic_phy_pmc_resume(phy, remote_wakeup);
+ } else {
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_WAKE_VAL(WAKE_VAL_ANY);
+ val |= UHSIC_WAKE_VAL(WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+ }
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val |= UHSIC_PD_TX;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ /* Driving Resume using PMC */
+ val = readl(pmc_base + PMC_SLEEPWALK_UHSIC);
+ val &= ~UHSIC_DATA_RPD_A;
+ val |= UHSIC_DATA_RPU_A;
+ val &= ~UHSIC_STROBE_RPU_A;
+ val |= UHSIC_STROBE_RPD_A;
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC);
+ return 0;
+}
+
+static int uhsic_phy_post_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned long flags;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ local_irq_save(flags);
+ val = readl(pmc_base + PMC_SLEEPWALK_UHSIC);
+ val &= ~(UHSIC_DATA_RPU_A | UHSIC_STROBE_RPD_A);
+ val |= (UHSIC_DATA_RPD_A | UHSIC_STROBE_RPU_A);
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ udelay(3);
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_PD_TX;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~(UHSIC_MASTER_ENABLE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* clear pending SRI, PCI interrupts. ehci will enable interrupts */
+ val = readl(base + USB_USBSTS);
+ writel(val, base + USB_USBSTS);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ local_irq_restore(flags);
+
+ uhsic_phy_disable_pmc_bus_ctrl(phy);
+
+ val = readl(base + USB_TXFILLTUNING);
+ if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) {
+ val = USB_FIFO_TXFILL_THRES(0x10);
+ writel(val, base + USB_TXFILLTUNING);
+ }
+ return 0;
+}
+
+static void uhsic_phy_restore_start(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+
+ val = readl(pmc_base + UTMIP_UHSIC_STATUS);
+
+ /* check whether we wake up from the remote resume */
+ if (UHSIC_WALK_PTR_VAL & val) {
+ phy->pmc_remote_wakeup = true;
+ } else {
+ DBG("%s(%d): setting pretend connect\n", __func__, __LINE__);
+ val = readl(base + UHSIC_CMD_CFG0);
+ val |= UHSIC_PRETEND_CONNECT_DETECT;
+ writel(val, base + UHSIC_CMD_CFG0);
+ }
+}
+
+static void uhsic_phy_restore_end(struct tegra_usb_phy *phy)
+{
+
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ int wait_time_us = 25000; /* FPR should be set by this time */
+
+ DBG("%s(%d)\n", __func__, __LINE__);
+
+ /* check whether we wake up from the remote resume */
+ if (phy->pmc_remote_wakeup) {
+ /* wait until FPR bit is set automatically on remote resume */
+ do {
+ val = readl(base + USB_PORTSC);
+ udelay(1);
+ if (wait_time_us == 0) {
+ uhsic_phy_disable_pmc_bus_ctrl(phy);
+ uhsic_phy_post_resume(phy);
+ return;
+ }
+ wait_time_us--;
+ } while (val & (USB_PORTSC_RESUME | USB_PORTSC_SUSP));
+
+ /* Clear PCI and SRI bits to avoid an interrupt upon resume */
+ val = readl(base + USB_USBSTS);
+ writel(val, base + USB_USBSTS);
+ /* wait to avoid SOF if there is any */
+ if (usb_phy_reg_status_wait(base + USB_USBSTS,
+ USB_USBSTS_SRI, USB_USBSTS_SRI, 2500)) {
+ pr_warn("%s: timeout waiting for SOF\n", __func__);
+ }
+ uhsic_phy_post_resume(phy);
+ }
+}
+
+static int hsic_rail_enable(struct tegra_usb_phy *phy)
+{
+ int ret;
+
+ if (phy->hsic_reg == NULL) {
+ phy->hsic_reg = regulator_get(&phy->pdev->dev, "avdd_hsic");
+ if (IS_ERR_OR_NULL(phy->hsic_reg)) {
+ pr_err("HSIC: Could not get regulator avdd_hsic\n");
+ ret = PTR_ERR(phy->hsic_reg);
+ phy->hsic_reg = NULL;
+ return ret;
+ }
+ }
+
+ ret = regulator_enable(phy->hsic_reg);
+ if (ret < 0) {
+ pr_err("%s avdd_hsic could not be enabled\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hsic_rail_disable(struct tegra_usb_phy *phy)
+{
+ int ret;
+
+ if (phy->hsic_reg == NULL) {
+ pr_warn("%s: unbalanced disable\n", __func__);
+ return -EIO;
+ }
+
+ ret = regulator_disable(phy->hsic_reg);
+ if (ret < 0) {
+ pr_err("HSIC regulator avdd_hsic cannot be disabled\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int uhsic_phy_open(struct tegra_usb_phy *phy)
+{
+ unsigned long parent_rate;
+ int i;
+ int ret;
+
+ phy->hsic_reg = NULL;
+ ret = hsic_rail_enable(phy);
+ if (ret < 0) {
+ pr_err("%s avdd_hsic could not be enabled\n", __func__);
+ return ret;
+ }
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk));
+ for (i = 0; i < ARRAY_SIZE(uhsic_freq_table); i++) {
+ if (uhsic_freq_table[i].freq == parent_rate) {
+ phy->freq = &uhsic_freq_table[i];
+ break;
+ }
+ }
+ if (!phy->freq) {
+ pr_err("invalid pll_u parent rate %ld\n", parent_rate);
+ return -EINVAL;
+ }
+
+ /* reset controller for reenumerating hsic device */
+ tegra_periph_reset_assert(phy->ctrlr_clk);
+ udelay(2);
+ tegra_periph_reset_deassert(phy->ctrlr_clk);
+ udelay(2);
+
+ uhsic_powerup_pmc_wake_detect(phy);
+
+ return 0;
+}
+
+static void uhsic_phy_close(struct tegra_usb_phy *phy)
+{
+ int ret;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ uhsic_powerdown_pmc_wake_detect(phy);
+
+ ret = hsic_rail_disable(phy);
+ if (ret < 0)
+ pr_err("%s avdd_hsic could not be disabled\n", __func__);
+}
+
+static int uhsic_phy_irq(struct tegra_usb_phy *phy)
+{
+ usb_phy_fence_read(phy);
+ /* check if there is any remote wake event */
+ if (uhsic_phy_remotewake_detected(phy))
+ pr_info("%s: uhsic remote wake detected\n", __func__);
+ return IRQ_HANDLED;
+}
+
+static int uhsic_phy_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already On\n",
+ __func__, __LINE__, phy->inst);
+ return 0;
+ }
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~(UHSIC_PD_BG | UHSIC_PD_TRK | UHSIC_PD_RX |
+ UHSIC_PD_ZI | UHSIC_RPD_DATA | UHSIC_RPD_STROBE);
+ val |= (UHSIC_RX_SEL | UHSIC_PD_TX);
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(1);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UHSIC_HSRX_CFG0);
+ val |= UHSIC_IDLE_WAIT(HSIC_IDLE_WAIT_DELAY);
+ val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(HSIC_ELASTIC_UNDERRUN_LIMIT);
+ val |= UHSIC_ELASTIC_OVERRUN_LIMIT(HSIC_ELASTIC_OVERRUN_LIMIT);
+ writel(val, base + UHSIC_HSRX_CFG0);
+
+ val = readl(base + UHSIC_HSRX_CFG1);
+ val |= UHSIC_HS_SYNC_START_DLY(HSIC_SYNC_START_DELAY);
+ writel(val, base + UHSIC_HSRX_CFG1);
+
+ /* WAR HSIC TX */
+ val = readl(base + UHSIC_TX_CFG0);
+ val &= ~UHSIC_HS_READY_WAIT_FOR_VALID;
+ writel(val, base + UHSIC_TX_CFG0);
+
+ val = readl(base + UHSIC_MISC_CFG0);
+ val |= UHSIC_SUSPEND_EXIT_ON_EDGE;
+ /* Disable generic bus reset, to allow AP30 specific bus reset*/
+ val |= UHSIC_DISABLE_BUSRESET;
+ writel(val, base + UHSIC_MISC_CFG0);
+
+ val = readl(base + UHSIC_MISC_CFG1);
+ val |= UHSIC_PLLU_STABLE_COUNT(phy->freq->stable_count);
+ writel(val, base + UHSIC_MISC_CFG1);
+
+ val = readl(base + UHSIC_PLL_CFG1);
+ val |= UHSIC_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
+ val |= UHSIC_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count);
+ writel(val, base + UHSIC_PLL_CFG1);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~(UHSIC_RESET);
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(1);
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~(UHSIC_PD_TX);
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ val = readl(base + USB_USBMODE);
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE);
+
+ /* Change the USB controller PHY type to HSIC */
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK);
+ val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
+ val &= ~HOSTPC1_DEVLC_STS;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ val = readl(base + USB_TXFILLTUNING);
+ if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) {
+ val = USB_FIFO_TXFILL_THRES(0x10);
+ writel(val, base + USB_TXFILLTUNING);
+ }
+
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_WKOC | USB_PORTSC_WKDS | USB_PORTSC_WKCN);
+ writel(val, base + USB_PORTSC);
+
+ val = readl(base + UHSIC_PADS_CFG0);
+ val &= ~(UHSIC_TX_RTUNEN);
+ /* set Rtune impedance to 50 ohm */
+ val |= UHSIC_TX_RTUNE(8);
+ writel(val, base + UHSIC_PADS_CFG0);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500)) {
+ pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+
+ if (phy->pmc_sleepwalk) {
+ DBG("%s(%d) inst:[%d] restore phy\n", __func__, __LINE__,
+ phy->inst);
+ uhsic_phy_restore_start(phy);
+ usb_phy_bringup_host_controller(phy);
+ uhsic_phy_restore_end(phy);
+ phy->pmc_sleepwalk = false;
+ }
+
+ return 0;
+}
+
+static int uhsic_phy_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (!phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already off\n",
+ __func__, __LINE__, phy->inst);
+ return 0;
+ }
+
+ /* Disable interrupts */
+ writel(0, base + USB_USBINTR);
+
+ if (phy->pmc_sleepwalk == false) {
+ uhsic_setup_pmc_wake_detect(phy);
+ phy->pmc_sleepwalk = true;
+ }
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val |= HOSTPC1_DEVLC_PHCD;
+ writel(val, base + HOSTPC1_DEVLC);
+
+ /* Remove power downs for HSIC from PADS CFG1 register */
+ val = readl(base + UHSIC_PADS_CFG1);
+ val |= (UHSIC_PD_BG |UHSIC_PD_TRK | UHSIC_PD_RX |
+ UHSIC_PD_ZI | UHSIC_PD_TX);
+ writel(val, base + UHSIC_PADS_CFG1);
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+
+ return 0;
+}
+
+static int uhsic_phy_bus_port_power(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(base + USB_USBMODE);
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE);
+
+ /* Change the USB controller PHY type to HSIC */
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~(HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK));
+ val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
+ writel(val, base + HOSTPC1_DEVLC);
+
+ val = readl(base + UHSIC_MISC_CFG0);
+ val |= UHSIC_DETECT_SHORT_CONNECT;
+ writel(val, base + UHSIC_MISC_CFG0);
+ udelay(1);
+
+ val = readl(base + UHSIC_MISC_CFG0);
+ val |= UHSIC_FORCE_XCVR_MODE;
+ writel(val, base + UHSIC_MISC_CFG0);
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPD_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ if (phy->pdata->ops && phy->pdata->ops->port_power)
+ phy->pdata->ops->port_power();
+
+ if (usb_phy_reg_status_wait(base + UHSIC_STAT_CFG0,
+ UHSIC_CONNECT_DETECT, UHSIC_CONNECT_DETECT, 25000)) {
+ pr_err("%s: timeout waiting for UHSIC_CONNECT_DETECT\n",
+ __func__);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int uhsic_phy_bus_reset(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ /* Change the USB controller PHY type to HSIC */
+ val = readl(base + HOSTPC1_DEVLC);
+ val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK);
+ val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
+ val &= ~HOSTPC1_DEVLC_STS;
+ writel(val, base + HOSTPC1_DEVLC);
+ /* wait here, otherwise HOSTPC1_DEVLC_PSPD will timeout */
+ mdelay(5);
+
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PTC(5);
+ writel(val, base + USB_PORTSC);
+ udelay(2);
+
+ val = readl(base + USB_PORTSC);
+ val &= ~(USB_PORTSC_PTC(~0));
+ writel(val, base + USB_PORTSC);
+ udelay(2);
+
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_LS(0),
+ 0, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_LS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ /* Poll until CCS is enabled */
+ if (usb_phy_reg_status_wait(base + USB_PORTSC, USB_PORTSC_CCS,
+ USB_PORTSC_CCS, 2000)) {
+ pr_err("%s: timeout waiting for USB_PORTSC_CCS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ if (usb_phy_reg_status_wait(base + HOSTPC1_DEVLC,
+ HOSTPC1_DEVLC_PSPD(2),
+ HOSTPC1_DEVLC_PSPD(2), 2000) < 0) {
+ pr_err("%s: timeout waiting hsic high speed configuration\n",
+ __func__);
+ return -ETIMEDOUT;
+ }
+
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBSTS, USB_USBSTS_HCH,
+ USB_USBSTS_HCH, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBSTS_HCH\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPU_STROBE;
+ val |= UHSIC_RPD_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ mdelay(50);
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPD_STROBE;
+ val |= UHSIC_RPU_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ val = readl(base + UHSIC_PADS_CFG1);
+ val &= ~UHSIC_RPU_STROBE;
+ writel(val, base + UHSIC_PADS_CFG1);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS,
+ USB_USBCMD_RS, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+int uhsic_phy_resume(struct tegra_usb_phy *phy)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ return 0;
+}
+
+static void ulpi_set_trimmer(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ void __iomem *base = phy->regs;
+ unsigned long val;
+
+ val = ULPI_DATA_TRIMMER_SEL(config->data_trimmer);
+ val |= ULPI_STPDIRNXT_TRIMMER_SEL(config->stpdirnxt_trimmer);
+ val |= ULPI_DIR_TRIMMER_SEL(config->dir_trimmer);
+ writel(val, base + ULPI_TIMING_CTRL_1);
+ udelay(10);
+
+ val |= ULPI_DATA_TRIMMER_LOAD;
+ val |= ULPI_STPDIRNXT_TRIMMER_LOAD;
+ val |= ULPI_DIR_TRIMMER_LOAD;
+ writel(val, base + ULPI_TIMING_CTRL_1);
+}
+
+static void reset_utmip_uhsic(void __iomem *base)
+{
+ unsigned long val;
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+}
+
+static void ulpi_set_host(void __iomem *base)
+{
+ unsigned long val;
+
+ val = readl(base + USB_USBMODE);
+ val &= ~USB_USBMODE_MASK;
+ val |= USB_USBMODE_HOST;
+ writel(val, base + USB_USBMODE);
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val |= HOSTPC1_DEVLC_PTS(2);
+ writel(val, base + HOSTPC1_DEVLC);
+}
+
+static inline void ulpi_pinmux_bypass(struct tegra_usb_phy *phy, bool enable)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+
+ if (enable)
+ val |= ULPI_OUTPUT_PINMUX_BYP;
+ else
+ val &= ~ULPI_OUTPUT_PINMUX_BYP;
+
+ writel(val, base + ULPI_TIMING_CTRL_0);
+}
+
+static inline void ulpi_null_phy_set_tristate(bool enable)
+{
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ int tristate = (enable) ? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL;
+
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA0, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA1, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA2, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA3, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA4, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA5, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA6, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DATA7, tristate);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_NXT, tristate);
+
+ if (enable)
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR, tristate);
+#endif
+}
+
+static void ulpi_null_phy_obs_read(void)
+{
+ static void __iomem *apb_misc;
+ unsigned slv0_obs, s2s_obs;
+
+ if (!apb_misc)
+ apb_misc = ioremap(TEGRA_APB_MISC_BASE, TEGRA_APB_MISC_SIZE);
+
+ writel(0x80d1003c, apb_misc + APB_MISC_GP_OBSCTRL_0);
+ slv0_obs = readl(apb_misc + APB_MISC_GP_OBSDATA_0);
+
+ writel(0x80d10040, apb_misc + APB_MISC_GP_OBSCTRL_0);
+ s2s_obs = readl(apb_misc + APB_MISC_GP_OBSDATA_0);
+
+ pr_debug("slv0 obs: %08x\ns2s obs: %08x\n", slv0_obs, s2s_obs);
+}
+
+static const struct gpio ulpi_gpios[] = {
+ {ULPI_STP, GPIOF_IN, "ULPI_STP"},
+ {ULPI_DIR, GPIOF_OUT_INIT_LOW, "ULPI_DIR"},
+ {ULPI_D0, GPIOF_OUT_INIT_LOW, "ULPI_D0"},
+ {ULPI_D1, GPIOF_OUT_INIT_LOW, "ULPI_D1"},
+};
+
+static int ulpi_null_phy_open(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ int ret;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ ret = gpio_request_array(ulpi_gpios, ARRAY_SIZE(ulpi_gpios));
+ if (ret)
+ return ret;
+
+ if (gpio_is_valid(config->phy_restore_gpio)) {
+ ret = gpio_request(config->phy_restore_gpio, "phy_restore");
+ if (ret)
+ goto err_gpio_free;
+
+ gpio_direction_input(config->phy_restore_gpio);
+ }
+
+ tegra_periph_reset_assert(phy->ctrlr_clk);
+ udelay(10);
+ tegra_periph_reset_deassert(phy->ctrlr_clk);
+
+ return 0;
+
+err_gpio_free:
+ gpio_free_array(ulpi_gpios, ARRAY_SIZE(ulpi_gpios));
+ return ret;
+}
+
+static void ulpi_null_phy_close(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ if (gpio_is_valid(config->phy_restore_gpio))
+ gpio_free(config->phy_restore_gpio);
+
+ gpio_free_array(ulpi_gpios, ARRAY_SIZE(ulpi_gpios));
+}
+
+static int ulpi_null_phy_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned int val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ if (!phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already off\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+
+ phy->phy_clk_on = false;
+ phy->hw_accessible = false;
+ ulpi_null_phy_set_tristate(true);
+ val = readl(base + ULPIS2S_CTRL);
+ val &= ~ULPIS2S_PLLU_MASTER_BLASTER60;
+ writel(val, base + ULPIS2S_CTRL);
+ return 0;
+}
+
+/* NOTE: this function must be called before ehci reset */
+static int ulpi_null_phy_init(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ val = readl(base + ULPIS2S_CTRL);
+ val |= ULPIS2S_SLV0_CLAMP_XMIT;
+ writel(val, base + ULPIS2S_CTRL);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= ULPIS2S_SLV0_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(10);
+
+ return 0;
+}
+
+static int ulpi_null_phy_irq(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ usb_phy_fence_read(phy);
+ if (phy->bus_reseting){
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ phy->bus_reseting = false;
+ }
+ return IRQ_HANDLED;
+}
+
+/* NOTE: this function must be called after ehci reset */
+static int ulpi_null_phy_cmd_reset(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ ulpi_set_host(base);
+
+ /* remove slave0 reset */
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~ULPIS2S_SLV0_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + ULPIS2S_CTRL);
+ val &= ~ULPIS2S_SLV0_CLAMP_XMIT;
+ writel(val, base + ULPIS2S_CTRL);
+ udelay(10);
+
+ return 0;
+}
+
+static int ulpi_phy_bus_reset(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ /*DISABLE RUN BIT */
+
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ phy->bus_reseting = true;
+
+ return 0;
+}
+
+static int ulpi_null_phy_restore(struct tegra_usb_phy *phy)
+{
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+ unsigned long timeout;
+ int ulpi_stp = ULPI_STP;
+
+ if (gpio_is_valid(config->phy_restore_gpio))
+ ulpi_stp = config->phy_restore_gpio;
+
+ /* disable ULPI pinmux bypass */
+ ulpi_pinmux_bypass(phy, false);
+
+ /* driving linstate by GPIO */
+ gpio_set_value(ULPI_D0, 0);
+ gpio_set_value(ULPI_D1, 0);
+
+ /* driving DIR high */
+ gpio_set_value(ULPI_DIR, 1);
+
+ /* remove ULPI tristate */
+ ulpi_null_phy_set_tristate(false);
+
+ /* wait for STP high */
+ timeout = jiffies + msecs_to_jiffies(25);
+
+ while (!gpio_get_value(ulpi_stp)) {
+ if (time_after(jiffies, timeout)) {
+ pr_warn("phy restore timeout\n");
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int ulpi_null_phy_lp0_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ ulpi_null_phy_init(phy);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_CMD_RESET;
+ writel(val, base + USB_USBCMD);
+
+ if (usb_phy_reg_status_wait(base + USB_USBCMD,
+ USB_CMD_RESET, 0, 2500) < 0) {
+ pr_err("%s: timeout waiting for reset\n", __func__);
+ }
+
+ ulpi_null_phy_cmd_reset(phy);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS,
+ USB_USBCMD_RS, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ /* Enable Port Power */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_PP;
+ writel(val, base + USB_PORTSC);
+ udelay(10);
+
+ ulpi_null_phy_restore(phy);
+
+ return 0;
+}
+
+static int ulpi_null_phy_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ if (phy->phy_clk_on) {
+ DBG("%s(%d) inst:[%d] phy clk is already On\n", __func__,
+ __LINE__, phy->inst);
+ return 0;
+ }
+ reset_utmip_uhsic(base);
+
+ /* remove ULPI PADS CLKEN reset */
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~ULPI_PADS_CLKEN_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(10);
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= ULPI_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(10);
+
+ /* set timming parameters */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_SHADOW_CLK_LOOPBACK_EN;
+ val &= ~ULPI_SHADOW_CLK_SEL;
+ val &= ~ULPI_LBK_PAD_EN;
+ val |= ULPI_SHADOW_CLK_DELAY(config->shadow_clk_delay);
+ val |= ULPI_CLOCK_OUT_DELAY(config->clock_out_delay);
+ val |= ULPI_LBK_PAD_E_INPUT_OR;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ writel(0, base + ULPI_TIMING_CTRL_1);
+ udelay(10);
+
+ /* start internal 60MHz clock */
+ val = readl(base + ULPIS2S_CTRL);
+ val |= ULPIS2S_ENA;
+ val |= ULPIS2S_SUPPORT_DISCONNECT;
+ val |= ULPIS2S_SPARE((phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) ? 3 : 1);
+ val |= ULPIS2S_PLLU_MASTER_BLASTER60;
+ writel(val, base + ULPIS2S_CTRL);
+
+ /* select ULPI_CORE_CLK_SEL to SHADOW_CLK */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CORE_CLK_SEL;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+ udelay(10);
+
+ /* enable ULPI null phy clock - can't set the trimmers before this */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_OUT_ENA;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+ udelay(10);
+
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ USB_PHY_CLK_VALID, 2500)) {
+ pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ /* set ULPI trimmers */
+ ulpi_set_trimmer(phy);
+
+ ulpi_set_host(base);
+
+ /* remove slave0 reset */
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~ULPIS2S_SLV0_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ /* remove slave1 and line reset */
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~ULPIS2S_SLV1_RESET;
+ val &= ~ULPIS2S_LINE_RESET;
+
+ /* remove ULPI PADS reset */
+ val &= ~ULPI_PADS_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ if (!phy->ulpi_clk_padout_ena) {
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_PADOUT_ENA;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+ phy->ulpi_clk_padout_ena = true;
+ } else {
+ if (!readl(base + USB_ASYNCLISTADDR))
+ ulpi_null_phy_lp0_resume(phy);
+ }
+ udelay(10);
+
+ phy->bus_reseting = false;
+ phy->phy_clk_on = true;
+ phy->hw_accessible = true;
+
+ return 0;
+}
+
+static int ulpi_null_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ ulpi_null_phy_obs_read();
+ usb_phy_wait_for_sof(phy);
+ ulpi_null_phy_obs_read();
+ return 0;
+}
+
+static int ulpi_null_phy_post_resume(struct tegra_usb_phy *phy)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ ulpi_null_phy_obs_read();
+ return 0;
+}
+
+static int ulpi_null_phy_resume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ if (!readl(base + USB_ASYNCLISTADDR)) {
+ /* enable ULPI CLK output pad */
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_CLK_PADOUT_ENA;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ /* enable ULPI pinmux bypass */
+ ulpi_pinmux_bypass(phy, true);
+ udelay(5);
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ /* remove DIR tristate */
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_ULPI_DIR,
+ TEGRA_TRI_NORMAL);
+#endif
+ }
+ return 0;
+}
+
+
+
+static struct tegra_usb_phy_ops utmi_phy_ops = {
+ .open = utmi_phy_open,
+ .close = utmi_phy_close,
+ .irq = utmi_phy_irq,
+ .power_on = utmi_phy_power_on,
+ .power_off = utmi_phy_power_off,
+ .pre_resume = utmi_phy_pre_resume,
+ .resume = utmi_phy_resume,
+ .post_resume = utmi_phy_post_resume,
+ .charger_detect = utmi_phy_charger_detect,
+ .post_suspend = phy_post_suspend,
+};
+
+static struct tegra_usb_phy_ops uhsic_phy_ops = {
+ .open = uhsic_phy_open,
+ .close = uhsic_phy_close,
+ .irq = uhsic_phy_irq,
+ .power_on = uhsic_phy_power_on,
+ .power_off = uhsic_phy_power_off,
+ .pre_resume = uhsic_phy_pre_resume,
+ .resume = uhsic_phy_resume,
+ .post_resume = uhsic_phy_post_resume,
+ .port_power = uhsic_phy_bus_port_power,
+ .bus_reset = uhsic_phy_bus_reset,
+ .post_suspend = phy_post_suspend,
+};
+
+static struct tegra_usb_phy_ops ulpi_null_phy_ops = {
+ .open = ulpi_null_phy_open,
+ .close = ulpi_null_phy_close,
+ .init = ulpi_null_phy_init,
+ .irq = ulpi_null_phy_irq,
+ .power_on = ulpi_null_phy_power_on,
+ .power_off = ulpi_null_phy_power_off,
+ .pre_resume = ulpi_null_phy_pre_resume,
+ .resume = ulpi_null_phy_resume,
+ .post_resume = ulpi_null_phy_post_resume,
+ .reset = ulpi_null_phy_cmd_reset,
+ .post_suspend = phy_post_suspend,
+ .bus_reset = ulpi_phy_bus_reset,
+};
+
+static struct tegra_usb_phy_ops ulpi_link_phy_ops;
+static struct tegra_usb_phy_ops icusb_phy_ops;
+
+static struct tegra_usb_phy_ops *phy_ops[] = {
+ [TEGRA_USB_PHY_INTF_UTMI] = &utmi_phy_ops,
+ [TEGRA_USB_PHY_INTF_ULPI_LINK] = &ulpi_link_phy_ops,
+ [TEGRA_USB_PHY_INTF_ULPI_NULL] = &ulpi_null_phy_ops,
+ [TEGRA_USB_PHY_INTF_HSIC] = &uhsic_phy_ops,
+ [TEGRA_USB_PHY_INTF_ICUSB] = &icusb_phy_ops,
+};
+
+int tegra3_usb_phy_init_ops(struct tegra_usb_phy *phy)
+{
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ phy->ops = phy_ops[phy->pdata->phy_intf];
+
+ /* FIXME: uncommenting below line to make USB host mode fail*/
+ /* usb_phy_power_down_pmc(); */
+
+ return 0;
+}
diff --git a/drivers/usb/phy/tegra_usb_phy.h b/drivers/usb/phy/tegra_usb_phy.h
new file mode 100644
index 000000000000..ef7fd79a08b1
--- /dev/null
+++ b/drivers/usb/phy/tegra_usb_phy.h
@@ -0,0 +1,120 @@
+/*
+ * arch/arm/mach-tegra/include/mach/tegra_usb_phy.h
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_USB_PHY_H
+#define __MACH_TEGRA_USB_PHY_H
+
+#include <linux/usb/otg.h>
+
+/**
+ * defines USB port speeds supported in USB2.0
+ */
+enum usb_phy_port_speed {
+ USB_PHY_PORT_SPEED_FULL = 0,
+ USB_PHY_PORT_SPEED_LOW,
+ USB_PHY_PORT_SPEED_HIGH,
+ USB_PHY_PORT_SPEED_UNKNOWN,
+};
+
+/**
+ * defines structure for oscillator dependent parameters
+ */
+struct tegra_xtal_freq {
+ int freq;
+ u8 enable_delay;
+ u8 stable_count;
+ u8 active_delay;
+ u16 xtal_freq_count;
+ u16 debounce;
+ u8 pdtrk_count;
+};
+
+/**
+ * pre decleration of the usb phy data structure
+ */
+struct tegra_usb_phy;
+
+/**
+ * defines function pointers used for differnt phy interfaces
+ */
+struct tegra_usb_phy_ops {
+ int (*open)(struct tegra_usb_phy *phy);
+ void (*close)(struct tegra_usb_phy *phy);
+ int (*irq)(struct tegra_usb_phy *phy);
+ int (*init)(struct tegra_usb_phy *phy);
+ int (*reset)(struct tegra_usb_phy *phy);
+ int (*pre_suspend)(struct tegra_usb_phy *phy);
+ int (*suspend)(struct tegra_usb_phy *phy);
+ int (*post_suspend)(struct tegra_usb_phy *phy);
+ int (*pre_resume)(struct tegra_usb_phy *phy, bool remote_wakeup);
+ int (*resume)(struct tegra_usb_phy *phy);
+ int (*post_resume)(struct tegra_usb_phy *phy);
+ int (*port_power)(struct tegra_usb_phy *phy);
+ int (*bus_reset)(struct tegra_usb_phy *phy);
+ int (*power_off)(struct tegra_usb_phy *phy);
+ int (*power_on)(struct tegra_usb_phy *phy);
+ bool (*charger_detect)(struct tegra_usb_phy *phy);
+};
+
+/**
+ * defines usb phy data structure
+ */
+struct tegra_usb_phy {
+ /* Don't move below variable 'phy', from first place*/
+ struct usb_phy phy;
+ struct platform_device *pdev;
+ struct tegra_usb_platform_data *pdata;
+ struct clk *pllu_clk;
+ struct clk *ctrlr_clk;
+ struct clk *ulpi_clk;
+ struct clk *utmi_pad_clk;
+ struct clk *emc_clk;
+ struct clk *sys_clk;
+ struct regulator *vdd_reg;
+ struct regulator *hsic_reg;
+ struct regulator *vbus_reg;
+ struct regulator *pllu_reg;
+ struct tegra_usb_phy_ops *ops;
+ struct tegra_xtal_freq *freq;
+ struct usb_phy *ulpi_vp;
+ enum usb_phy_port_speed port_speed;
+ signed char utmi_xcvr_setup;
+ void __iomem *regs;
+ int inst;
+ bool phy_clk_on;
+ bool ctrl_clk_on;
+ bool vdd_reg_on;
+ bool phy_power_on;
+ bool pmc_remote_wakeup;
+ bool pmc_hotplug_wakeup;
+ bool hw_accessible;
+ bool ulpi_clk_padout_ena;
+ bool pmc_sleepwalk;
+ bool bus_reseting;
+ bool linkphy_init;
+ bool hot_plug;
+ bool ctrlr_suspended;
+};
+
+int usb_phy_reg_status_wait(void __iomem *reg, u32 mask,
+ u32 result, u32 timeout);
+
+int tegra3_usb_phy_init_ops(struct tegra_usb_phy *phy);
+int tegra2_usb_phy_init_ops(struct tegra_usb_phy *phy);
+int tegra11x_usb_phy_init_ops(struct tegra_usb_phy *phy);
+
+
+#endif /* __MACH_TEGRA_USB_PHY_H */