xref: /linux/drivers/phy/tegra/xusb-tegra210.c (revision 0baabcbedd9ef2381636a36f669187a46380de19)
12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
287d66f28SThierry Reding /*
323d5ec3fSJC Kuo  * Copyright (c) 2014-2020, NVIDIA CORPORATION.  All rights reserved.
487d66f28SThierry Reding  * Copyright (C) 2015 Google, Inc.
587d66f28SThierry Reding  */
687d66f28SThierry Reding 
787d66f28SThierry Reding #include <linux/clk.h>
887d66f28SThierry Reding #include <linux/clk/tegra.h>
987d66f28SThierry Reding #include <linux/delay.h>
1087d66f28SThierry Reding #include <linux/io.h>
1187d66f28SThierry Reding #include <linux/mailbox_client.h>
1287d66f28SThierry Reding #include <linux/module.h>
1387d66f28SThierry Reding #include <linux/of.h>
142d102148SJC Kuo #include <linux/of_platform.h>
1587d66f28SThierry Reding #include <linux/phy/phy.h>
1687d66f28SThierry Reding #include <linux/platform_device.h>
172d102148SJC Kuo #include <linux/regmap.h>
1887d66f28SThierry Reding #include <linux/regulator/consumer.h>
1987d66f28SThierry Reding #include <linux/reset.h>
2087d66f28SThierry Reding #include <linux/slab.h>
2187d66f28SThierry Reding 
2287d66f28SThierry Reding #include <soc/tegra/fuse.h>
2387d66f28SThierry Reding 
2487d66f28SThierry Reding #include "xusb.h"
2587d66f28SThierry Reding 
2687d66f28SThierry Reding #define FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(x) \
2787d66f28SThierry Reding 					((x) ? (11 + ((x) - 1) * 6) : 0)
2887d66f28SThierry Reding #define FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK 0x3f
2987d66f28SThierry Reding #define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT 7
3087d66f28SThierry Reding #define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK 0xf
3187d66f28SThierry Reding 
3287d66f28SThierry Reding #define FUSE_USB_CALIB_EXT_RPD_CTRL_SHIFT 0
3387d66f28SThierry Reding #define FUSE_USB_CALIB_EXT_RPD_CTRL_MASK 0x1f
3487d66f28SThierry Reding 
3587d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX 0x004
3687d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT 16
3787d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_MASK 0x3
3887d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_XUSB 0x1
3987d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT 18
4087d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK 0x3
4187d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB 0x1
4287d66f28SThierry Reding 
4387d66f28SThierry Reding #define XUSB_PADCTL_USB2_PORT_CAP 0x008
44ac25b6e9SNagarjuna Kristam #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DISABLED(x) (0x0 << ((x) * 4))
4587d66f28SThierry Reding #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(x) (0x1 << ((x) * 4))
46ac25b6e9SNagarjuna Kristam #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DEVICE(x) (0x2 << ((x) * 4))
47ac25b6e9SNagarjuna Kristam #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_OTG(x) (0x3 << ((x) * 4))
4887d66f28SThierry Reding #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(x) (0x3 << ((x) * 4))
4987d66f28SThierry Reding 
5087d66f28SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP 0x014
5187d66f28SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(x) (1 << (((x) * 5) + 4))
5287d66f28SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_SHIFT(x) ((x) * 5)
5387d66f28SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(x) (0x7 << ((x) * 5))
5487d66f28SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(x, v) (((v) & 0x7) << ((x) * 5))
55a5be28c3SNagarjuna Kristam #define XUSB_PADCTL_SS_PORT_MAP_PORT_DISABLED 0x7
5687d66f28SThierry Reding 
572d102148SJC Kuo #define XUSB_PADCTL_ELPG_PROGRAM_0 0x20
582d102148SJC Kuo #define   USB2_PORT_WAKE_INTERRUPT_ENABLE(x)      BIT((x))
592d102148SJC Kuo #define   USB2_PORT_WAKEUP_EVENT(x)               BIT((x) + 7)
602d102148SJC Kuo #define   SS_PORT_WAKE_INTERRUPT_ENABLE(x)        BIT((x) + 14)
612d102148SJC Kuo #define   SS_PORT_WAKEUP_EVENT(x)                 BIT((x) + 21)
622d102148SJC Kuo #define   USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 28)
632d102148SJC Kuo #define   USB2_HSIC_PORT_WAKEUP_EVENT(x)          BIT((x) + 30)
642d102148SJC Kuo #define   ALL_WAKE_EVENTS ( \
652d102148SJC Kuo 		USB2_PORT_WAKEUP_EVENT(0) | USB2_PORT_WAKEUP_EVENT(1) | \
662d102148SJC Kuo 		USB2_PORT_WAKEUP_EVENT(2) | USB2_PORT_WAKEUP_EVENT(3) | \
672d102148SJC Kuo 		SS_PORT_WAKEUP_EVENT(0) | SS_PORT_WAKEUP_EVENT(1) | \
682d102148SJC Kuo 		SS_PORT_WAKEUP_EVENT(2) | SS_PORT_WAKEUP_EVENT(3) | \
692d102148SJC Kuo 		USB2_HSIC_PORT_WAKEUP_EVENT(0))
702d102148SJC Kuo 
7187d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1 0x024
7287d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN (1 << 31)
7387d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 30)
7487d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN (1 << 29)
7587d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(x) (1 << (2 + (x) * 3))
7687d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(x) \
7787d66f28SThierry Reding 							(1 << (1 + (x) * 3))
7887d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(x) (1 << ((x) * 3))
7987d66f28SThierry Reding 
8087d66f28SThierry Reding #define XUSB_PADCTL_USB3_PAD_MUX 0x028
8187d66f28SThierry Reding #define XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(x) (1 << (1 + (x)))
8287d66f28SThierry Reding #define XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(x) (1 << (8 + (x)))
8387d66f28SThierry Reding 
8490767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL0(x) (0x080 + (x) * 0x40)
8590767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIP (1 << 18)
8690767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIN (1 << 22)
8790767cdfSNagarjuna Kristam 
8887d66f28SThierry Reding #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(x) (0x084 + (x) * 0x40)
8987d66f28SThierry Reding #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT 7
9087d66f28SThierry Reding #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_MASK 0x3
91ac25b6e9SNagarjuna Kristam #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_VAL 0x1
9287d66f28SThierry Reding #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18 (1 << 6)
9387d66f28SThierry Reding 
9487d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x088 + (x) * 0x40)
9587d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI (1 << 29)
9687d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 (1 << 27)
9787d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD (1 << 26)
9887d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT 0
9987d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK 0x3f
10087d66f28SThierry Reding 
10187d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PADX_CTL1(x) (0x08c + (x) * 0x40)
10287d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT 26
10387d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_MASK 0x1f
10487d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT 3
10587d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK 0xf
10687d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2)
10787d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD (1 << 1)
10887d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD (1 << 0)
1092d102148SJC Kuo #define   RPD_CTRL(x)                      (((x) & 0x1f) << 26)
1102d102148SJC Kuo #define   RPD_CTRL_VALUE(x)                (((x) >> 26) & 0x1f)
11187d66f28SThierry Reding 
11287d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x284
11387d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 11)
11487d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT 3
11587d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK 0x7
11687d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL 0x7
11787d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT 0
11887d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK 0x7
11987d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_VAL 0x2
12087d66f28SThierry Reding 
12187d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1 0x288
12287d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_PD_TRK (1 << 26)
12387d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT 19
12487d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_MASK 0x7f
12587d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_VAL 0x0a
12687d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT 12
12787d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK 0x7f
12887d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL 0x1e
1292d102148SJC Kuo #define   TCTRL_VALUE(x)                (((x) & 0x3f) >> 0)
1302d102148SJC Kuo #define   PCTRL_VALUE(x)                (((x) >> 6) & 0x3f)
13187d66f28SThierry Reding 
13287d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x300 + (x) * 0x20)
13387d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE (1 << 18)
13487d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA1 (1 << 17)
13587d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA0 (1 << 16)
13687d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPD_STROBE (1 << 15)
13787d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 (1 << 14)
13887d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 (1 << 13)
13987d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE (1 << 9)
14087d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 (1 << 8)
14187d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 (1 << 7)
14287d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE (1 << 6)
14387d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 (1 << 5)
14487d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 (1 << 4)
14587d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE (1 << 3)
14687d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 (1 << 2)
14787d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 (1 << 1)
14887d66f28SThierry Reding 
14987d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PADX_CTL1(x) (0x304 + (x) * 0x20)
15087d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT 0
15187d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_MASK 0xf
15287d66f28SThierry Reding 
15387d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PADX_CTL2(x) (0x308 + (x) * 0x20)
15487d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT 8
15587d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK 0xf
15687d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT 0
15787d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK 0xff
15887d66f28SThierry Reding 
15987d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL 0x340
16087d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_PD_TRK (1 << 19)
16187d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT 12
16287d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_MASK 0x7f
16387d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_VAL 0x0a
16487d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT 5
16587d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_MASK 0x7f
16687d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_VAL 0x1e
16787d66f28SThierry Reding 
16887d66f28SThierry Reding #define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL 0x344
16987d66f28SThierry Reding 
17087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_P0_CTL1 0x360
17187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT 20
17287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_MASK 0xff
17387d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_USB_VAL 0x19
17487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SATA_VAL 0x1e
17587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_SHIFT 16
17687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK 0x3
17787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_LOCKDET_STATUS (1 << 15)
17887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD (1 << 4)
17987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_ENABLE (1 << 3)
18087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_SHIFT 1
18187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_MASK 0x3
18287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_IDDQ (1 << 0)
18387d66f28SThierry Reding 
18487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_P0_CTL2 0x364
18587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT 4
18687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK 0xffffff
18787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_VAL 0x136
18887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD (1 << 2)
18987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE (1 << 1)
19087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN (1 << 0)
19187d66f28SThierry Reding 
19287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_P0_CTL4 0x36c
193e7f4da4cSThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_XDIGCLK_EN (1 << 19)
19487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN (1 << 15)
19587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT 12
19687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK 0x3
19787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_USB_VAL 0x2
19887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SATA_VAL 0x0
19987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_REFCLKBUF_EN (1 << 8)
20087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_SHIFT 4
20187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_MASK 0xf
20287d66f28SThierry Reding 
20387d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_P0_CTL5 0x370
20487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT 16
20587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_MASK 0xff
20687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_VAL 0x2a
20787d66f28SThierry Reding 
20887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_P0_CTL8 0x37c
20987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE (1 << 31)
21087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD (1 << 15)
21187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN (1 << 13)
21287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN (1 << 12)
21387d66f28SThierry Reding 
21487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL1(x) (0x460 + (x) * 0x40)
21587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT 20
21687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_MASK 0x3
21787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_VAL 0x1
21887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN BIT(18)
21987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD BIT(13)
22087d66f28SThierry Reding 
221c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(x) (0x464 + (x) * 0x40)
222c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ BIT(0)
223c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD BIT(1)
224c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK GENMASK(5, 4)
225c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL GENMASK(5, 4)
226c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD BIT(24)
227c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ BIT(8)
228c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD BIT(9)
229c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK GENMASK(13, 12)
230c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL GENMASK(13, 12)
231c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD BIT(25)
232c339605cSJC Kuo 
23387d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_S0_CTL1 0x860
23487d66f28SThierry Reding 
23587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_S0_CTL2 0x864
23687d66f28SThierry Reding 
23787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_S0_CTL4 0x86c
23887d66f28SThierry Reding 
23987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_S0_CTL5 0x870
24087d66f28SThierry Reding 
24187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_S0_CTL8 0x87c
24287d66f28SThierry Reding 
24387d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1 0x960
244c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2 0x964
24587d66f28SThierry Reding 
24687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(x) (0xa60 + (x) * 0x40)
24787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT 16
24887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_MASK 0x3
24987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_VAL 0x2
25087d66f28SThierry Reding 
25187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(x) (0xa64 + (x) * 0x40)
25287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT 0
25387d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_MASK 0xffff
25487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_VAL 0x00fc
25587d66f28SThierry Reding 
25687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL3(x) (0xa68 + (x) * 0x40)
25787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL3_RX_DFE_VAL 0xc0077f1f
25887d66f28SThierry Reding 
25987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(x) (0xa6c + (x) * 0x40)
26087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT 16
26187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_MASK 0xffff
26287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_VAL 0x01c7
26387d66f28SThierry Reding 
26487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL6(x) (0xa74 + (x) * 0x40)
26587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL6_RX_EQ_CTRL_H_VAL 0xfcf01368
26687d66f28SThierry Reding 
26790767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID 0xc60
26890767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON (1 << 14)
26990767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT 18
27090767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK 0xf
27190767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING 8
272de792a6dSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED 0
27390767cdfSNagarjuna Kristam 
2742d102148SJC Kuo /* USB2 SLEEPWALK registers */
2752d102148SJC Kuo #define UTMIP(_port, _offset1, _offset2) \
2762d102148SJC Kuo 		(((_port) <= 2) ? (_offset1) : (_offset2))
2772d102148SJC Kuo 
2782d102148SJC Kuo #define PMC_UTMIP_UHSIC_SLEEP_CFG(x)	UTMIP(x, 0x1fc, 0x4d0)
2792d102148SJC Kuo #define   UTMIP_MASTER_ENABLE(x)		UTMIP(x, BIT(8 * (x)), BIT(0))
2802d102148SJC Kuo #define   UTMIP_FSLS_USE_PMC(x)			UTMIP(x, BIT(8 * (x) + 1), \
2812d102148SJC Kuo 							BIT(1))
2822d102148SJC Kuo #define   UTMIP_PCTRL_USE_PMC(x)		UTMIP(x, BIT(8 * (x) + 2), \
2832d102148SJC Kuo 							BIT(2))
2842d102148SJC Kuo #define   UTMIP_TCTRL_USE_PMC(x)		UTMIP(x, BIT(8 * (x) + 3), \
2852d102148SJC Kuo 							BIT(3))
2862d102148SJC Kuo #define   UTMIP_WAKE_VAL(_port, _value)		(((_value) & 0xf) << \
2872d102148SJC Kuo 					(UTMIP(_port, 8 * (_port) + 4, 4)))
2882d102148SJC Kuo #define   UTMIP_WAKE_VAL_NONE(_port)		UTMIP_WAKE_VAL(_port, 12)
2892d102148SJC Kuo #define   UTMIP_WAKE_VAL_ANY(_port)		UTMIP_WAKE_VAL(_port, 15)
2902d102148SJC Kuo 
2912d102148SJC Kuo #define PMC_UTMIP_UHSIC_SLEEP_CFG1	(0x4d0)
2922d102148SJC Kuo #define   UTMIP_RPU_SWITC_LOW_USE_PMC_PX(x)	BIT((x) + 8)
2932d102148SJC Kuo #define   UTMIP_RPD_CTRL_USE_PMC_PX(x)		BIT((x) + 16)
2942d102148SJC Kuo 
2952d102148SJC Kuo #define PMC_UTMIP_MASTER_CONFIG		(0x274)
2962d102148SJC Kuo #define   UTMIP_PWR(x)				UTMIP(x, BIT(x), BIT(4))
2972d102148SJC Kuo #define   UHSIC_PWR				BIT(3)
2982d102148SJC Kuo 
2992d102148SJC Kuo #define PMC_USB_DEBOUNCE_DEL		(0xec)
3002d102148SJC Kuo #define   DEBOUNCE_VAL(x)			(((x) & 0xffff) << 0)
3012d102148SJC Kuo #define   UTMIP_LINE_DEB_CNT(x)			(((x) & 0xf) << 16)
3022d102148SJC Kuo #define   UHSIC_LINE_DEB_CNT(x)			(((x) & 0xf) << 20)
3032d102148SJC Kuo 
3042d102148SJC Kuo #define PMC_UTMIP_UHSIC_FAKE(x)		UTMIP(x, 0x218, 0x294)
3052d102148SJC Kuo #define   UTMIP_FAKE_USBOP_VAL(x)		UTMIP(x, BIT(4 * (x)), BIT(8))
3062d102148SJC Kuo #define   UTMIP_FAKE_USBON_VAL(x)		UTMIP(x, BIT(4 * (x) + 1), \
3072d102148SJC Kuo 							BIT(9))
3082d102148SJC Kuo #define   UTMIP_FAKE_USBOP_EN(x)		UTMIP(x, BIT(4 * (x) + 2), \
3092d102148SJC Kuo 							BIT(10))
3102d102148SJC Kuo #define   UTMIP_FAKE_USBON_EN(x)		UTMIP(x, BIT(4 * (x) + 3), \
3112d102148SJC Kuo 							BIT(11))
3122d102148SJC Kuo 
3132d102148SJC Kuo #define PMC_UTMIP_UHSIC_SLEEPWALK_CFG(x)	UTMIP(x, 0x200, 0x288)
3142d102148SJC Kuo #define   UTMIP_LINEVAL_WALK_EN(x)		UTMIP(x, BIT(8 * (x) + 7), \
3152d102148SJC Kuo 							BIT(15))
3162d102148SJC Kuo 
3172d102148SJC Kuo #define PMC_USB_AO			(0xf0)
3182d102148SJC Kuo #define   USBOP_VAL_PD(x)			UTMIP(x, BIT(4 * (x)), BIT(20))
3192d102148SJC Kuo #define   USBON_VAL_PD(x)			UTMIP(x, BIT(4 * (x) + 1), \
3202d102148SJC Kuo 							BIT(21))
3212d102148SJC Kuo #define   STROBE_VAL_PD				BIT(12)
3222d102148SJC Kuo #define   DATA0_VAL_PD				BIT(13)
3232d102148SJC Kuo #define   DATA1_VAL_PD				BIT(24)
3242d102148SJC Kuo 
3252d102148SJC Kuo #define PMC_UTMIP_UHSIC_SAVED_STATE(x)	UTMIP(x, 0x1f0, 0x280)
3262d102148SJC Kuo #define   SPEED(_port, _value)			(((_value) & 0x3) << \
3272d102148SJC Kuo 						(UTMIP(_port, 8 * (_port), 8)))
3282d102148SJC Kuo #define   UTMI_HS(_port)			SPEED(_port, 0)
3292d102148SJC Kuo #define   UTMI_FS(_port)			SPEED(_port, 1)
3302d102148SJC Kuo #define   UTMI_LS(_port)			SPEED(_port, 2)
3312d102148SJC Kuo #define   UTMI_RST(_port)			SPEED(_port, 3)
3322d102148SJC Kuo 
3332d102148SJC Kuo #define PMC_UTMIP_UHSIC_TRIGGERS		(0x1ec)
3342d102148SJC Kuo #define   UTMIP_CLR_WALK_PTR(x)			UTMIP(x, BIT(x), BIT(16))
3352d102148SJC Kuo #define   UTMIP_CAP_CFG(x)			UTMIP(x, BIT((x) + 4), BIT(17))
3362d102148SJC Kuo #define   UTMIP_CLR_WAKE_ALARM(x)		UTMIP(x, BIT((x) + 12), \
3372d102148SJC Kuo 							BIT(19))
3382d102148SJC Kuo #define   UHSIC_CLR_WALK_PTR			BIT(3)
3392d102148SJC Kuo #define   UHSIC_CLR_WAKE_ALARM			BIT(15)
3402d102148SJC Kuo 
3412d102148SJC Kuo #define PMC_UTMIP_SLEEPWALK_PX(x)	UTMIP(x, 0x204 + (4 * (x)), \
3422d102148SJC Kuo 							0x4e0)
3432d102148SJC Kuo /* phase A */
3442d102148SJC Kuo #define   UTMIP_USBOP_RPD_A			BIT(0)
3452d102148SJC Kuo #define   UTMIP_USBON_RPD_A			BIT(1)
3462d102148SJC Kuo #define   UTMIP_AP_A				BIT(4)
3472d102148SJC Kuo #define   UTMIP_AN_A				BIT(5)
3482d102148SJC Kuo #define   UTMIP_HIGHZ_A				BIT(6)
3492d102148SJC Kuo /* phase B */
3502d102148SJC Kuo #define   UTMIP_USBOP_RPD_B			BIT(8)
3512d102148SJC Kuo #define   UTMIP_USBON_RPD_B			BIT(9)
3522d102148SJC Kuo #define   UTMIP_AP_B				BIT(12)
3532d102148SJC Kuo #define   UTMIP_AN_B				BIT(13)
3542d102148SJC Kuo #define   UTMIP_HIGHZ_B				BIT(14)
3552d102148SJC Kuo /* phase C */
3562d102148SJC Kuo #define   UTMIP_USBOP_RPD_C			BIT(16)
3572d102148SJC Kuo #define   UTMIP_USBON_RPD_C			BIT(17)
3582d102148SJC Kuo #define   UTMIP_AP_C				BIT(20)
3592d102148SJC Kuo #define   UTMIP_AN_C				BIT(21)
3602d102148SJC Kuo #define   UTMIP_HIGHZ_C				BIT(22)
3612d102148SJC Kuo /* phase D */
3622d102148SJC Kuo #define   UTMIP_USBOP_RPD_D			BIT(24)
3632d102148SJC Kuo #define   UTMIP_USBON_RPD_D			BIT(25)
3642d102148SJC Kuo #define   UTMIP_AP_D				BIT(28)
3652d102148SJC Kuo #define   UTMIP_AN_D				BIT(29)
3662d102148SJC Kuo #define   UTMIP_HIGHZ_D				BIT(30)
3672d102148SJC Kuo 
3682d102148SJC Kuo #define PMC_UTMIP_UHSIC_LINE_WAKEUP	(0x26c)
3692d102148SJC Kuo #define   UTMIP_LINE_WAKEUP_EN(x)		UTMIP(x, BIT(x), BIT(4))
3702d102148SJC Kuo #define   UHSIC_LINE_WAKEUP_EN			BIT(3)
3712d102148SJC Kuo 
3722d102148SJC Kuo #define PMC_UTMIP_TERM_PAD_CFG		(0x1f8)
3732d102148SJC Kuo #define   PCTRL_VAL(x)				(((x) & 0x3f) << 1)
3742d102148SJC Kuo #define   TCTRL_VAL(x)				(((x) & 0x3f) << 7)
3752d102148SJC Kuo 
3762d102148SJC Kuo #define PMC_UTMIP_PAD_CFGX(x)		(0x4c0 + (4 * (x)))
3772d102148SJC Kuo #define   RPD_CTRL_PX(x)			(((x) & 0x1f) << 22)
3782d102148SJC Kuo 
3792d102148SJC Kuo #define PMC_UHSIC_SLEEP_CFG	PMC_UTMIP_UHSIC_SLEEP_CFG(0)
3802d102148SJC Kuo #define   UHSIC_MASTER_ENABLE			BIT(24)
3812d102148SJC Kuo #define   UHSIC_WAKE_VAL(_value)		(((_value) & 0xf) << 28)
3822d102148SJC Kuo #define   UHSIC_WAKE_VAL_SD10			UHSIC_WAKE_VAL(2)
3832d102148SJC Kuo #define   UHSIC_WAKE_VAL_NONE			UHSIC_WAKE_VAL(12)
3842d102148SJC Kuo 
3852d102148SJC Kuo #define PMC_UHSIC_FAKE			PMC_UTMIP_UHSIC_FAKE(0)
3862d102148SJC Kuo #define   UHSIC_FAKE_STROBE_VAL			BIT(12)
3872d102148SJC Kuo #define   UHSIC_FAKE_DATA_VAL			BIT(13)
3882d102148SJC Kuo #define   UHSIC_FAKE_STROBE_EN			BIT(14)
3892d102148SJC Kuo #define   UHSIC_FAKE_DATA_EN			BIT(15)
3902d102148SJC Kuo 
3912d102148SJC Kuo #define PMC_UHSIC_SAVED_STATE		PMC_UTMIP_UHSIC_SAVED_STATE(0)
3922d102148SJC Kuo #define   UHSIC_MODE(_value)			(((_value) & 0x1) << 24)
3932d102148SJC Kuo #define   UHSIC_HS				UHSIC_MODE(0)
3942d102148SJC Kuo #define   UHSIC_RST				UHSIC_MODE(1)
3952d102148SJC Kuo 
3962d102148SJC Kuo #define PMC_UHSIC_SLEEPWALK_CFG		PMC_UTMIP_UHSIC_SLEEPWALK_CFG(0)
3972d102148SJC Kuo #define   UHSIC_WAKE_WALK_EN			BIT(30)
3982d102148SJC Kuo #define   UHSIC_LINEVAL_WALK_EN			BIT(31)
3992d102148SJC Kuo 
4002d102148SJC Kuo #define PMC_UHSIC_SLEEPWALK_P0		(0x210)
4012d102148SJC Kuo #define   UHSIC_DATA0_RPD_A			BIT(1)
4022d102148SJC Kuo #define   UHSIC_DATA0_RPU_B			BIT(11)
4032d102148SJC Kuo #define   UHSIC_DATA0_RPU_C			BIT(19)
4042d102148SJC Kuo #define   UHSIC_DATA0_RPU_D			BIT(27)
4052d102148SJC Kuo #define   UHSIC_STROBE_RPU_A			BIT(2)
4062d102148SJC Kuo #define   UHSIC_STROBE_RPD_B			BIT(8)
4072d102148SJC Kuo #define   UHSIC_STROBE_RPD_C			BIT(16)
4082d102148SJC Kuo #define   UHSIC_STROBE_RPD_D			BIT(24)
4092d102148SJC Kuo 
41087d66f28SThierry Reding struct tegra210_xusb_fuse_calibration {
41187d66f28SThierry Reding 	u32 hs_curr_level[4];
41287d66f28SThierry Reding 	u32 hs_term_range_adj;
41387d66f28SThierry Reding 	u32 rpd_ctrl;
41487d66f28SThierry Reding };
41587d66f28SThierry Reding 
4162d102148SJC Kuo struct tegra210_xusb_padctl_context {
4172d102148SJC Kuo 	u32 usb2_pad_mux;
4182d102148SJC Kuo 	u32 usb2_port_cap;
4192d102148SJC Kuo 	u32 ss_port_map;
4202d102148SJC Kuo 	u32 usb3_pad_mux;
4212d102148SJC Kuo };
4222d102148SJC Kuo 
42387d66f28SThierry Reding struct tegra210_xusb_padctl {
42487d66f28SThierry Reding 	struct tegra_xusb_padctl base;
4252d102148SJC Kuo 	struct regmap *regmap;
42687d66f28SThierry Reding 
42787d66f28SThierry Reding 	struct tegra210_xusb_fuse_calibration fuse;
4282d102148SJC Kuo 	struct tegra210_xusb_padctl_context context;
42987d66f28SThierry Reding };
43087d66f28SThierry Reding 
43187d66f28SThierry Reding static inline struct tegra210_xusb_padctl *
43287d66f28SThierry Reding to_tegra210_xusb_padctl(struct tegra_xusb_padctl *padctl)
43387d66f28SThierry Reding {
43487d66f28SThierry Reding 	return container_of(padctl, struct tegra210_xusb_padctl, base);
43587d66f28SThierry Reding }
43687d66f28SThierry Reding 
43723d5ec3fSJC Kuo static const struct tegra_xusb_lane_map tegra210_usb3_map[] = {
43823d5ec3fSJC Kuo 	{ 0, "pcie", 6 },
43923d5ec3fSJC Kuo 	{ 1, "pcie", 5 },
44023d5ec3fSJC Kuo 	{ 2, "pcie", 0 },
44123d5ec3fSJC Kuo 	{ 2, "pcie", 3 },
44223d5ec3fSJC Kuo 	{ 3, "pcie", 4 },
44323d5ec3fSJC Kuo 	{ 3, "sata", 0 },
44423d5ec3fSJC Kuo 	{ 0, NULL,   0 }
44523d5ec3fSJC Kuo };
44623d5ec3fSJC Kuo 
44723d5ec3fSJC Kuo static int tegra210_usb3_lane_map(struct tegra_xusb_lane *lane)
44823d5ec3fSJC Kuo {
44923d5ec3fSJC Kuo 	const struct tegra_xusb_lane_map *map;
45023d5ec3fSJC Kuo 
45123d5ec3fSJC Kuo 	for (map = tegra210_usb3_map; map->type; map++) {
45223d5ec3fSJC Kuo 		if (map->index == lane->index &&
45323d5ec3fSJC Kuo 		    strcmp(map->type, lane->pad->soc->name) == 0) {
45423d5ec3fSJC Kuo 			dev_dbg(lane->pad->padctl->dev, "lane = %s map to port = usb3-%d\n",
45523d5ec3fSJC Kuo 				lane->pad->soc->lanes[lane->index].name, map->port);
45623d5ec3fSJC Kuo 			return map->port;
45723d5ec3fSJC Kuo 		}
45823d5ec3fSJC Kuo 	}
45923d5ec3fSJC Kuo 
46023d5ec3fSJC Kuo 	return -EINVAL;
46123d5ec3fSJC Kuo }
46223d5ec3fSJC Kuo 
46387d66f28SThierry Reding /* must be called under padctl->lock */
46487d66f28SThierry Reding static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl)
46587d66f28SThierry Reding {
46687d66f28SThierry Reding 	struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(padctl->pcie);
46787d66f28SThierry Reding 	unsigned long timeout;
46887d66f28SThierry Reding 	u32 value;
4692352fdb0SJC Kuo 	unsigned int i;
47087d66f28SThierry Reding 	int err;
47187d66f28SThierry Reding 
4722352fdb0SJC Kuo 	if (pcie->enable)
47387d66f28SThierry Reding 		return 0;
47487d66f28SThierry Reding 
47587d66f28SThierry Reding 	err = clk_prepare_enable(pcie->pll);
47687d66f28SThierry Reding 	if (err < 0)
47787d66f28SThierry Reding 		return err;
47887d66f28SThierry Reding 
4792352fdb0SJC Kuo 	if (tegra210_plle_hw_sequence_is_enabled())
4802352fdb0SJC Kuo 		goto skip_pll_init;
4812352fdb0SJC Kuo 
48287d66f28SThierry Reding 	err = reset_control_deassert(pcie->rst);
48387d66f28SThierry Reding 	if (err < 0)
48487d66f28SThierry Reding 		goto disable;
48587d66f28SThierry Reding 
48687d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
48787d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK <<
48887d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT);
48987d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_VAL <<
49087d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT;
49187d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
49287d66f28SThierry Reding 
49387d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL5);
49487d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_MASK <<
49587d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT);
49687d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_VAL <<
49787d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT;
49887d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL5);
49987d66f28SThierry Reding 
50087d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
50187d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD;
50287d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
50387d66f28SThierry Reding 
50487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
50587d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD;
50687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
50787d66f28SThierry Reding 
50887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
50987d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD;
51087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
51187d66f28SThierry Reding 
51287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL4);
51387d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK <<
51487d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT) |
51587d66f28SThierry Reding 		   (XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_MASK <<
51687d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_SHIFT));
51787d66f28SThierry Reding 	value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_USB_VAL <<
51887d66f28SThierry Reding 		  XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT) |
51987d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN;
52087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL4);
52187d66f28SThierry Reding 
52287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
52387d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK <<
52487d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_SHIFT) |
52587d66f28SThierry Reding 		   (XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_MASK <<
52687d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT));
52787d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_USB_VAL <<
52887d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT;
52987d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
53087d66f28SThierry Reding 
53187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
53287d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_IDDQ;
53387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
53487d66f28SThierry Reding 
53587d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
53687d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_MASK <<
53787d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_SHIFT);
53887d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
53987d66f28SThierry Reding 
54087d66f28SThierry Reding 	usleep_range(10, 20);
54187d66f28SThierry Reding 
54287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL4);
54387d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL4_REFCLKBUF_EN;
54487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL4);
54587d66f28SThierry Reding 
54687d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
54787d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN;
54887d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
54987d66f28SThierry Reding 
55087d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
55187d66f28SThierry Reding 
55287d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
55387d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
55487d66f28SThierry Reding 		if (value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE)
55587d66f28SThierry Reding 			break;
55687d66f28SThierry Reding 
55787d66f28SThierry Reding 		usleep_range(10, 20);
55887d66f28SThierry Reding 	}
55987d66f28SThierry Reding 
56087d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
56187d66f28SThierry Reding 		err = -ETIMEDOUT;
56287d66f28SThierry Reding 		goto reset;
56387d66f28SThierry Reding 	}
56487d66f28SThierry Reding 
56587d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
56687d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN;
56787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
56887d66f28SThierry Reding 
56987d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
57087d66f28SThierry Reding 
57187d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
57287d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
57387d66f28SThierry Reding 		if (!(value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE))
57487d66f28SThierry Reding 			break;
57587d66f28SThierry Reding 
57687d66f28SThierry Reding 		usleep_range(10, 20);
57787d66f28SThierry Reding 	}
57887d66f28SThierry Reding 
57987d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
58087d66f28SThierry Reding 		err = -ETIMEDOUT;
58187d66f28SThierry Reding 		goto reset;
58287d66f28SThierry Reding 	}
58387d66f28SThierry Reding 
58487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
58587d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL1_ENABLE;
58687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
58787d66f28SThierry Reding 
58887d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
58987d66f28SThierry Reding 
59087d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
59187d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
59287d66f28SThierry Reding 		if (value & XUSB_PADCTL_UPHY_PLL_CTL1_LOCKDET_STATUS)
59387d66f28SThierry Reding 			break;
59487d66f28SThierry Reding 
59587d66f28SThierry Reding 		usleep_range(10, 20);
59687d66f28SThierry Reding 	}
59787d66f28SThierry Reding 
59887d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
59987d66f28SThierry Reding 		err = -ETIMEDOUT;
60087d66f28SThierry Reding 		goto reset;
60187d66f28SThierry Reding 	}
60287d66f28SThierry Reding 
60387d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
60487d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN |
60587d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN;
60687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
60787d66f28SThierry Reding 
60887d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
60987d66f28SThierry Reding 
61087d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
61187d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
61287d66f28SThierry Reding 		if (value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE)
61387d66f28SThierry Reding 			break;
61487d66f28SThierry Reding 
61587d66f28SThierry Reding 		usleep_range(10, 20);
61687d66f28SThierry Reding 	}
61787d66f28SThierry Reding 
61887d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
61987d66f28SThierry Reding 		err = -ETIMEDOUT;
62087d66f28SThierry Reding 		goto reset;
62187d66f28SThierry Reding 	}
62287d66f28SThierry Reding 
62387d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
62487d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN;
62587d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
62687d66f28SThierry Reding 
62787d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
62887d66f28SThierry Reding 
62987d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
63087d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
63187d66f28SThierry Reding 		if (!(value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE))
63287d66f28SThierry Reding 			break;
63387d66f28SThierry Reding 
63487d66f28SThierry Reding 		usleep_range(10, 20);
63587d66f28SThierry Reding 	}
63687d66f28SThierry Reding 
63787d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
63887d66f28SThierry Reding 		err = -ETIMEDOUT;
63987d66f28SThierry Reding 		goto reset;
64087d66f28SThierry Reding 	}
64187d66f28SThierry Reding 
64287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
64387d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN;
64487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
64587d66f28SThierry Reding 
64687d66f28SThierry Reding 	tegra210_xusb_pll_hw_control_enable();
64787d66f28SThierry Reding 
64887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
64987d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD;
65087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
65187d66f28SThierry Reding 
65287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
65387d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD;
65487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
65587d66f28SThierry Reding 
65687d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
65787d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD;
65887d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
65987d66f28SThierry Reding 
66087d66f28SThierry Reding 	usleep_range(10, 20);
66187d66f28SThierry Reding 
66287d66f28SThierry Reding 	tegra210_xusb_pll_hw_sequence_start();
66387d66f28SThierry Reding 
6642352fdb0SJC Kuo skip_pll_init:
6652352fdb0SJC Kuo 	pcie->enable = true;
6662352fdb0SJC Kuo 
6672352fdb0SJC Kuo 	for (i = 0; i < padctl->pcie->soc->num_lanes; i++) {
6682352fdb0SJC Kuo 		value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
6692352fdb0SJC Kuo 		value |= XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(i);
6702352fdb0SJC Kuo 		padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
6712352fdb0SJC Kuo 	}
67287d66f28SThierry Reding 
67387d66f28SThierry Reding 	return 0;
67487d66f28SThierry Reding 
67587d66f28SThierry Reding reset:
67687d66f28SThierry Reding 	reset_control_assert(pcie->rst);
67787d66f28SThierry Reding disable:
67887d66f28SThierry Reding 	clk_disable_unprepare(pcie->pll);
67987d66f28SThierry Reding 	return err;
68087d66f28SThierry Reding }
68187d66f28SThierry Reding 
68287d66f28SThierry Reding static void tegra210_pex_uphy_disable(struct tegra_xusb_padctl *padctl)
68387d66f28SThierry Reding {
68487d66f28SThierry Reding 	struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(padctl->pcie);
6852352fdb0SJC Kuo 	u32 value;
6862352fdb0SJC Kuo 	unsigned int i;
68787d66f28SThierry Reding 
6882352fdb0SJC Kuo 	if (WARN_ON(!pcie->enable))
68923d5ec3fSJC Kuo 		return;
69087d66f28SThierry Reding 
6912352fdb0SJC Kuo 	pcie->enable = false;
69287d66f28SThierry Reding 
6932352fdb0SJC Kuo 	for (i = 0; i < padctl->pcie->soc->num_lanes; i++) {
6942352fdb0SJC Kuo 		value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
6952352fdb0SJC Kuo 		value &= ~XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(i);
6962352fdb0SJC Kuo 		padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
6972352fdb0SJC Kuo 	}
6982352fdb0SJC Kuo 
69987d66f28SThierry Reding 	clk_disable_unprepare(pcie->pll);
70087d66f28SThierry Reding }
70187d66f28SThierry Reding 
70287d66f28SThierry Reding /* must be called under padctl->lock */
7032352fdb0SJC Kuo static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl)
70487d66f28SThierry Reding {
70587d66f28SThierry Reding 	struct tegra_xusb_sata_pad *sata = to_sata_pad(padctl->sata);
7062352fdb0SJC Kuo 	struct tegra_xusb_lane *lane = tegra_xusb_find_lane(padctl, "sata", 0);
70787d66f28SThierry Reding 	unsigned long timeout;
70887d66f28SThierry Reding 	u32 value;
7092352fdb0SJC Kuo 	unsigned int i;
71087d66f28SThierry Reding 	int err;
7112352fdb0SJC Kuo 	bool usb;
71287d66f28SThierry Reding 
7132352fdb0SJC Kuo 	if (sata->enable)
71487d66f28SThierry Reding 		return 0;
7152352fdb0SJC Kuo 
7162352fdb0SJC Kuo 	if (IS_ERR(lane))
7172352fdb0SJC Kuo 		return 0;
7182352fdb0SJC Kuo 
7192352fdb0SJC Kuo 	if (tegra210_plle_hw_sequence_is_enabled())
7202352fdb0SJC Kuo 		goto skip_pll_init;
7212352fdb0SJC Kuo 
7222352fdb0SJC Kuo 	usb = tegra_xusb_lane_check(lane, "usb3-ss");
72387d66f28SThierry Reding 
72487d66f28SThierry Reding 	err = clk_prepare_enable(sata->pll);
72587d66f28SThierry Reding 	if (err < 0)
72687d66f28SThierry Reding 		return err;
72787d66f28SThierry Reding 
72887d66f28SThierry Reding 	err = reset_control_deassert(sata->rst);
72987d66f28SThierry Reding 	if (err < 0)
73087d66f28SThierry Reding 		goto disable;
73187d66f28SThierry Reding 
73287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
73387d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK <<
73487d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT);
73587d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_VAL <<
73687d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT;
73787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
73887d66f28SThierry Reding 
73987d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL5);
74087d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_MASK <<
74187d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT);
74287d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_VAL <<
74387d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT;
74487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL5);
74587d66f28SThierry Reding 
74687d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
74787d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD;
74887d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
74987d66f28SThierry Reding 
75087d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
75187d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD;
75287d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
75387d66f28SThierry Reding 
75487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
75587d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD;
75687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
75787d66f28SThierry Reding 
75887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL4);
75987d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK <<
76087d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT) |
76187d66f28SThierry Reding 		   (XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_MASK <<
76287d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_SHIFT));
76387d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN;
76487d66f28SThierry Reding 
76587d66f28SThierry Reding 	if (usb)
76687d66f28SThierry Reding 		value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_USB_VAL <<
76787d66f28SThierry Reding 			  XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT);
76887d66f28SThierry Reding 	else
76987d66f28SThierry Reding 		value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SATA_VAL <<
77087d66f28SThierry Reding 			  XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT);
77187d66f28SThierry Reding 
772e7f4da4cSThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL4_XDIGCLK_EN;
77387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL4);
77487d66f28SThierry Reding 
77587d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
77687d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK <<
77787d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_SHIFT) |
77887d66f28SThierry Reding 		   (XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_MASK <<
77987d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT));
78087d66f28SThierry Reding 
78187d66f28SThierry Reding 	if (usb)
78287d66f28SThierry Reding 		value |= XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_USB_VAL <<
78387d66f28SThierry Reding 			 XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT;
78487d66f28SThierry Reding 	else
78587d66f28SThierry Reding 		value |= XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SATA_VAL <<
78687d66f28SThierry Reding 			 XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT;
78787d66f28SThierry Reding 
78887d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
78987d66f28SThierry Reding 
79087d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
79187d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_IDDQ;
79287d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
79387d66f28SThierry Reding 
79487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
79587d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_MASK <<
79687d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_SHIFT);
79787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
79887d66f28SThierry Reding 
79987d66f28SThierry Reding 	usleep_range(10, 20);
80087d66f28SThierry Reding 
80187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL4);
80287d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL4_REFCLKBUF_EN;
80387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL4);
80487d66f28SThierry Reding 
80587d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
80687d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN;
80787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
80887d66f28SThierry Reding 
80987d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
81087d66f28SThierry Reding 
81187d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
81287d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
81387d66f28SThierry Reding 		if (value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE)
81487d66f28SThierry Reding 			break;
81587d66f28SThierry Reding 
81687d66f28SThierry Reding 		usleep_range(10, 20);
81787d66f28SThierry Reding 	}
81887d66f28SThierry Reding 
81987d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
82087d66f28SThierry Reding 		err = -ETIMEDOUT;
82187d66f28SThierry Reding 		goto reset;
82287d66f28SThierry Reding 	}
82387d66f28SThierry Reding 
82487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
82587d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN;
82687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
82787d66f28SThierry Reding 
82887d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
82987d66f28SThierry Reding 
83087d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
83187d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
83287d66f28SThierry Reding 		if (!(value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE))
83387d66f28SThierry Reding 			break;
83487d66f28SThierry Reding 
83587d66f28SThierry Reding 		usleep_range(10, 20);
83687d66f28SThierry Reding 	}
83787d66f28SThierry Reding 
83887d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
83987d66f28SThierry Reding 		err = -ETIMEDOUT;
84087d66f28SThierry Reding 		goto reset;
84187d66f28SThierry Reding 	}
84287d66f28SThierry Reding 
84387d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
84487d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL1_ENABLE;
84587d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
84687d66f28SThierry Reding 
84787d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
84887d66f28SThierry Reding 
84987d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
85087d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
85187d66f28SThierry Reding 		if (value & XUSB_PADCTL_UPHY_PLL_CTL1_LOCKDET_STATUS)
85287d66f28SThierry Reding 			break;
85387d66f28SThierry Reding 
85487d66f28SThierry Reding 		usleep_range(10, 20);
85587d66f28SThierry Reding 	}
85687d66f28SThierry Reding 
85787d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
85887d66f28SThierry Reding 		err = -ETIMEDOUT;
85987d66f28SThierry Reding 		goto reset;
86087d66f28SThierry Reding 	}
86187d66f28SThierry Reding 
86287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
86387d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN |
86487d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN;
86587d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
86687d66f28SThierry Reding 
86787d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
86887d66f28SThierry Reding 
86987d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
87087d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
87187d66f28SThierry Reding 		if (value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE)
87287d66f28SThierry Reding 			break;
87387d66f28SThierry Reding 
87487d66f28SThierry Reding 		usleep_range(10, 20);
87587d66f28SThierry Reding 	}
87687d66f28SThierry Reding 
87787d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
87887d66f28SThierry Reding 		err = -ETIMEDOUT;
87987d66f28SThierry Reding 		goto reset;
88087d66f28SThierry Reding 	}
88187d66f28SThierry Reding 
88287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
88387d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN;
88487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
88587d66f28SThierry Reding 
88687d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
88787d66f28SThierry Reding 
88887d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
88987d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
89087d66f28SThierry Reding 		if (!(value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE))
89187d66f28SThierry Reding 			break;
89287d66f28SThierry Reding 
89387d66f28SThierry Reding 		usleep_range(10, 20);
89487d66f28SThierry Reding 	}
89587d66f28SThierry Reding 
89687d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
89787d66f28SThierry Reding 		err = -ETIMEDOUT;
89887d66f28SThierry Reding 		goto reset;
89987d66f28SThierry Reding 	}
90087d66f28SThierry Reding 
90187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
90287d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN;
90387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
90487d66f28SThierry Reding 
90587d66f28SThierry Reding 	tegra210_sata_pll_hw_control_enable();
90687d66f28SThierry Reding 
90787d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
90887d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD;
90987d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
91087d66f28SThierry Reding 
91187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
91287d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD;
91387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
91487d66f28SThierry Reding 
91587d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
91687d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD;
91787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
91887d66f28SThierry Reding 
91987d66f28SThierry Reding 	usleep_range(10, 20);
92087d66f28SThierry Reding 
92187d66f28SThierry Reding 	tegra210_sata_pll_hw_sequence_start();
92287d66f28SThierry Reding 
9232352fdb0SJC Kuo skip_pll_init:
9242352fdb0SJC Kuo 	sata->enable = true;
9252352fdb0SJC Kuo 
9262352fdb0SJC Kuo 	for (i = 0; i < padctl->sata->soc->num_lanes; i++) {
9272352fdb0SJC Kuo 		value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
9282352fdb0SJC Kuo 		value |= XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(i);
9292352fdb0SJC Kuo 		padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
9302352fdb0SJC Kuo 	}
93187d66f28SThierry Reding 
93287d66f28SThierry Reding 	return 0;
93387d66f28SThierry Reding 
93487d66f28SThierry Reding reset:
93587d66f28SThierry Reding 	reset_control_assert(sata->rst);
93687d66f28SThierry Reding disable:
93787d66f28SThierry Reding 	clk_disable_unprepare(sata->pll);
93887d66f28SThierry Reding 	return err;
93987d66f28SThierry Reding }
94087d66f28SThierry Reding 
94187d66f28SThierry Reding static void tegra210_sata_uphy_disable(struct tegra_xusb_padctl *padctl)
94287d66f28SThierry Reding {
94387d66f28SThierry Reding 	struct tegra_xusb_sata_pad *sata = to_sata_pad(padctl->sata);
9442352fdb0SJC Kuo 	u32 value;
9452352fdb0SJC Kuo 	unsigned int i;
94687d66f28SThierry Reding 
9472352fdb0SJC Kuo 	if (WARN_ON(!sata->enable))
94823d5ec3fSJC Kuo 		return;
94987d66f28SThierry Reding 
9502352fdb0SJC Kuo 	sata->enable = false;
95187d66f28SThierry Reding 
9522352fdb0SJC Kuo 	for (i = 0; i < padctl->sata->soc->num_lanes; i++) {
9532352fdb0SJC Kuo 		value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
9542352fdb0SJC Kuo 		value &= ~XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(i);
9552352fdb0SJC Kuo 		padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
9562352fdb0SJC Kuo 	}
9572352fdb0SJC Kuo 
95887d66f28SThierry Reding 	clk_disable_unprepare(sata->pll);
95987d66f28SThierry Reding }
96087d66f28SThierry Reding 
9612352fdb0SJC Kuo static void tegra210_aux_mux_lp0_clamp_disable(struct tegra_xusb_padctl *padctl)
96287d66f28SThierry Reding {
96387d66f28SThierry Reding 	u32 value;
96487d66f28SThierry Reding 
96587d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
96687d66f28SThierry Reding 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN;
96787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
96887d66f28SThierry Reding 
96987d66f28SThierry Reding 	usleep_range(100, 200);
97087d66f28SThierry Reding 
97187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
97287d66f28SThierry Reding 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY;
97387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
97487d66f28SThierry Reding 
97587d66f28SThierry Reding 	usleep_range(100, 200);
97687d66f28SThierry Reding 
97787d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
97887d66f28SThierry Reding 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN;
97987d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
98087d66f28SThierry Reding }
98187d66f28SThierry Reding 
9822352fdb0SJC Kuo static void tegra210_aux_mux_lp0_clamp_enable(struct tegra_xusb_padctl *padctl)
98387d66f28SThierry Reding {
98487d66f28SThierry Reding 	u32 value;
98587d66f28SThierry Reding 
98687d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
98787d66f28SThierry Reding 	value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN;
98887d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
98987d66f28SThierry Reding 
99087d66f28SThierry Reding 	usleep_range(100, 200);
99187d66f28SThierry Reding 
99287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
99387d66f28SThierry Reding 	value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY;
99487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
99587d66f28SThierry Reding 
99687d66f28SThierry Reding 	usleep_range(100, 200);
99787d66f28SThierry Reding 
99887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
99987d66f28SThierry Reding 	value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN;
100087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
10012352fdb0SJC Kuo }
100287d66f28SThierry Reding 
10032352fdb0SJC Kuo static int tegra210_uphy_init(struct tegra_xusb_padctl *padctl)
10042352fdb0SJC Kuo {
10052352fdb0SJC Kuo 	if (padctl->pcie)
10062352fdb0SJC Kuo 		tegra210_pex_uphy_enable(padctl);
10072352fdb0SJC Kuo 
10082352fdb0SJC Kuo 	if (padctl->sata)
10092352fdb0SJC Kuo 		tegra210_sata_uphy_enable(padctl);
10102352fdb0SJC Kuo 
10112352fdb0SJC Kuo 	if (!tegra210_plle_hw_sequence_is_enabled())
10122352fdb0SJC Kuo 		tegra210_plle_hw_sequence_start();
10132352fdb0SJC Kuo 	else
10142352fdb0SJC Kuo 		dev_dbg(padctl->dev, "PLLE is already in HW control\n");
10152352fdb0SJC Kuo 
10162352fdb0SJC Kuo 	tegra210_aux_mux_lp0_clamp_disable(padctl);
10172352fdb0SJC Kuo 
101887d66f28SThierry Reding 	return 0;
101987d66f28SThierry Reding }
102087d66f28SThierry Reding 
10212352fdb0SJC Kuo static void __maybe_unused
10222352fdb0SJC Kuo tegra210_uphy_deinit(struct tegra_xusb_padctl *padctl)
10232352fdb0SJC Kuo {
10242352fdb0SJC Kuo 	tegra210_aux_mux_lp0_clamp_enable(padctl);
10252352fdb0SJC Kuo 
10262352fdb0SJC Kuo 	if (padctl->sata)
10272352fdb0SJC Kuo 		tegra210_sata_uphy_disable(padctl);
10282352fdb0SJC Kuo 
10292352fdb0SJC Kuo 	if (padctl->pcie)
10302352fdb0SJC Kuo 		tegra210_pex_uphy_disable(padctl);
10312352fdb0SJC Kuo }
10322352fdb0SJC Kuo 
103387d66f28SThierry Reding static int tegra210_hsic_set_idle(struct tegra_xusb_padctl *padctl,
103487d66f28SThierry Reding 				  unsigned int index, bool idle)
103587d66f28SThierry Reding {
103687d66f28SThierry Reding 	u32 value;
103787d66f28SThierry Reding 
103887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index));
103987d66f28SThierry Reding 
104087d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA0 |
104187d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA1 |
104287d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_RPD_STROBE);
104387d66f28SThierry Reding 
104487d66f28SThierry Reding 	if (idle)
104587d66f28SThierry Reding 		value |= XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 |
104687d66f28SThierry Reding 			 XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 |
104787d66f28SThierry Reding 			 XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE;
104887d66f28SThierry Reding 	else
104987d66f28SThierry Reding 		value &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 |
105087d66f28SThierry Reding 			   XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 |
105187d66f28SThierry Reding 			   XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE);
105287d66f28SThierry Reding 
105387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL0(index));
105487d66f28SThierry Reding 
105587d66f28SThierry Reding 	return 0;
105687d66f28SThierry Reding }
105787d66f28SThierry Reding 
10582d102148SJC Kuo static int tegra210_usb3_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
10592d102148SJC Kuo 					      enum usb_device_speed speed)
10602d102148SJC Kuo {
10612d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
10622d102148SJC Kuo 	int port = tegra210_usb3_lane_map(lane);
10632d102148SJC Kuo 	struct device *dev = padctl->dev;
10642d102148SJC Kuo 	u32 value;
10652d102148SJC Kuo 
10662d102148SJC Kuo 	if (port < 0) {
10672d102148SJC Kuo 		dev_err(dev, "invalid usb3 port number\n");
10682d102148SJC Kuo 		return -EINVAL;
10692d102148SJC Kuo 	}
10702d102148SJC Kuo 
10712d102148SJC Kuo 	mutex_lock(&padctl->lock);
10722d102148SJC Kuo 
10732d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
10742d102148SJC Kuo 	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port);
10752d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
10762d102148SJC Kuo 
10772d102148SJC Kuo 	usleep_range(100, 200);
10782d102148SJC Kuo 
10792d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
10802d102148SJC Kuo 	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port);
10812d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
10822d102148SJC Kuo 
10832d102148SJC Kuo 	usleep_range(250, 350);
10842d102148SJC Kuo 
10852d102148SJC Kuo 	mutex_unlock(&padctl->lock);
10862d102148SJC Kuo 
10872d102148SJC Kuo 	return 0;
10882d102148SJC Kuo }
10892d102148SJC Kuo 
10902d102148SJC Kuo static int tegra210_usb3_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
10912d102148SJC Kuo {
10922d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
10932d102148SJC Kuo 	int port = tegra210_usb3_lane_map(lane);
10942d102148SJC Kuo 	struct device *dev = padctl->dev;
10952d102148SJC Kuo 	u32 value;
10962d102148SJC Kuo 
10972d102148SJC Kuo 	if (port < 0) {
10982d102148SJC Kuo 		dev_err(dev, "invalid usb3 port number\n");
10992d102148SJC Kuo 		return -EINVAL;
11002d102148SJC Kuo 	}
11012d102148SJC Kuo 
11022d102148SJC Kuo 	mutex_lock(&padctl->lock);
11032d102148SJC Kuo 
11042d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
11052d102148SJC Kuo 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port);
11062d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
11072d102148SJC Kuo 
11082d102148SJC Kuo 	usleep_range(100, 200);
11092d102148SJC Kuo 
11102d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
11112d102148SJC Kuo 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port);
11122d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
11132d102148SJC Kuo 
11142d102148SJC Kuo 	mutex_unlock(&padctl->lock);
11152d102148SJC Kuo 
11162d102148SJC Kuo 	return 0;
11172d102148SJC Kuo }
11182d102148SJC Kuo 
11192d102148SJC Kuo static int tegra210_usb3_enable_phy_wake(struct tegra_xusb_lane *lane)
11202d102148SJC Kuo {
11212d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
11222d102148SJC Kuo 	int port = tegra210_usb3_lane_map(lane);
11232d102148SJC Kuo 	struct device *dev = padctl->dev;
11242d102148SJC Kuo 	u32 value;
11252d102148SJC Kuo 
11262d102148SJC Kuo 	if (port < 0) {
11272d102148SJC Kuo 		dev_err(dev, "invalid usb3 port number\n");
11282d102148SJC Kuo 		return -EINVAL;
11292d102148SJC Kuo 	}
11302d102148SJC Kuo 
11312d102148SJC Kuo 	mutex_lock(&padctl->lock);
11322d102148SJC Kuo 
11332d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
11342d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
11352d102148SJC Kuo 	value |= SS_PORT_WAKEUP_EVENT(port);
11362d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
11372d102148SJC Kuo 
11382d102148SJC Kuo 	usleep_range(10, 20);
11392d102148SJC Kuo 
11402d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
11412d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
11422d102148SJC Kuo 	value |= SS_PORT_WAKE_INTERRUPT_ENABLE(port);
11432d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
11442d102148SJC Kuo 
11452d102148SJC Kuo 	mutex_unlock(&padctl->lock);
11462d102148SJC Kuo 
11472d102148SJC Kuo 	return 0;
11482d102148SJC Kuo }
11492d102148SJC Kuo 
11502d102148SJC Kuo static int tegra210_usb3_disable_phy_wake(struct tegra_xusb_lane *lane)
11512d102148SJC Kuo {
11522d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
11532d102148SJC Kuo 	int port = tegra210_usb3_lane_map(lane);
11542d102148SJC Kuo 	struct device *dev = padctl->dev;
11552d102148SJC Kuo 	u32 value;
11562d102148SJC Kuo 
11572d102148SJC Kuo 	if (port < 0) {
11582d102148SJC Kuo 		dev_err(dev, "invalid usb3 port number\n");
11592d102148SJC Kuo 		return -EINVAL;
11602d102148SJC Kuo 	}
11612d102148SJC Kuo 
11622d102148SJC Kuo 	mutex_lock(&padctl->lock);
11632d102148SJC Kuo 
11642d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
11652d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
11662d102148SJC Kuo 	value &= ~SS_PORT_WAKE_INTERRUPT_ENABLE(port);
11672d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
11682d102148SJC Kuo 
11692d102148SJC Kuo 	usleep_range(10, 20);
11702d102148SJC Kuo 
11712d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
11722d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
11732d102148SJC Kuo 	value |= SS_PORT_WAKEUP_EVENT(port);
11742d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
11752d102148SJC Kuo 
11762d102148SJC Kuo 	mutex_unlock(&padctl->lock);
11772d102148SJC Kuo 
11782d102148SJC Kuo 	return 0;
11792d102148SJC Kuo }
11802d102148SJC Kuo 
11812d102148SJC Kuo static bool tegra210_usb3_phy_remote_wake_detected(struct tegra_xusb_lane *lane)
11822d102148SJC Kuo {
11832d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
11842d102148SJC Kuo 	int index = tegra210_usb3_lane_map(lane);
11852d102148SJC Kuo 	u32 value;
11862d102148SJC Kuo 
11872d102148SJC Kuo 	if (index < 0)
11882d102148SJC Kuo 		return false;
11892d102148SJC Kuo 
11902d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
11912d102148SJC Kuo 	if ((value & SS_PORT_WAKE_INTERRUPT_ENABLE(index)) && (value & SS_PORT_WAKEUP_EVENT(index)))
11922d102148SJC Kuo 		return true;
11932d102148SJC Kuo 
11942d102148SJC Kuo 	return false;
11952d102148SJC Kuo }
11962d102148SJC Kuo 
11972d102148SJC Kuo static int tegra210_utmi_enable_phy_wake(struct tegra_xusb_lane *lane)
11982d102148SJC Kuo {
11992d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
12002d102148SJC Kuo 	unsigned int index = lane->index;
12012d102148SJC Kuo 	u32 value;
12022d102148SJC Kuo 
12032d102148SJC Kuo 	mutex_lock(&padctl->lock);
12042d102148SJC Kuo 
12052d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
12062d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
12072d102148SJC Kuo 	value |= USB2_PORT_WAKEUP_EVENT(index);
12082d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
12092d102148SJC Kuo 
12102d102148SJC Kuo 	usleep_range(10, 20);
12112d102148SJC Kuo 
12122d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
12132d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
12142d102148SJC Kuo 	value |= USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
12152d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
12162d102148SJC Kuo 
12172d102148SJC Kuo 	mutex_unlock(&padctl->lock);
12182d102148SJC Kuo 
12192d102148SJC Kuo 	return 0;
12202d102148SJC Kuo }
12212d102148SJC Kuo 
12222d102148SJC Kuo static int tegra210_utmi_disable_phy_wake(struct tegra_xusb_lane *lane)
12232d102148SJC Kuo {
12242d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
12252d102148SJC Kuo 	unsigned int index = lane->index;
12262d102148SJC Kuo 	u32 value;
12272d102148SJC Kuo 
12282d102148SJC Kuo 	mutex_lock(&padctl->lock);
12292d102148SJC Kuo 
12302d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
12312d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
12322d102148SJC Kuo 	value &= ~USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
12332d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
12342d102148SJC Kuo 
12352d102148SJC Kuo 	usleep_range(10, 20);
12362d102148SJC Kuo 
12372d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
12382d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
12392d102148SJC Kuo 	value |= USB2_PORT_WAKEUP_EVENT(index);
12402d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
12412d102148SJC Kuo 
12422d102148SJC Kuo 	mutex_unlock(&padctl->lock);
12432d102148SJC Kuo 
12442d102148SJC Kuo 	return 0;
12452d102148SJC Kuo }
12462d102148SJC Kuo 
12472d102148SJC Kuo static bool tegra210_utmi_phy_remote_wake_detected(struct tegra_xusb_lane *lane)
12482d102148SJC Kuo {
12492d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
12502d102148SJC Kuo 	unsigned int index = lane->index;
12512d102148SJC Kuo 	u32 value;
12522d102148SJC Kuo 
12532d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
12542d102148SJC Kuo 	if ((value & USB2_PORT_WAKE_INTERRUPT_ENABLE(index)) &&
12552d102148SJC Kuo 	    (value & USB2_PORT_WAKEUP_EVENT(index)))
12562d102148SJC Kuo 		return true;
12572d102148SJC Kuo 
12582d102148SJC Kuo 	return false;
12592d102148SJC Kuo }
12602d102148SJC Kuo 
12612d102148SJC Kuo static int tegra210_hsic_enable_phy_wake(struct tegra_xusb_lane *lane)
12622d102148SJC Kuo {
12632d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
12642d102148SJC Kuo 	unsigned int index = lane->index;
12652d102148SJC Kuo 	u32 value;
12662d102148SJC Kuo 
12672d102148SJC Kuo 	mutex_lock(&padctl->lock);
12682d102148SJC Kuo 
12692d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
12702d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
12712d102148SJC Kuo 	value |= USB2_HSIC_PORT_WAKEUP_EVENT(index);
12722d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
12732d102148SJC Kuo 
12742d102148SJC Kuo 	usleep_range(10, 20);
12752d102148SJC Kuo 
12762d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
12772d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
12782d102148SJC Kuo 	value |= USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index);
12792d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
12802d102148SJC Kuo 
12812d102148SJC Kuo 	mutex_unlock(&padctl->lock);
12822d102148SJC Kuo 
12832d102148SJC Kuo 	return 0;
12842d102148SJC Kuo }
12852d102148SJC Kuo 
12862d102148SJC Kuo static int tegra210_hsic_disable_phy_wake(struct tegra_xusb_lane *lane)
12872d102148SJC Kuo {
12882d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
12892d102148SJC Kuo 	unsigned int index = lane->index;
12902d102148SJC Kuo 	u32 value;
12912d102148SJC Kuo 
12922d102148SJC Kuo 	mutex_lock(&padctl->lock);
12932d102148SJC Kuo 
12942d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
12952d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
12962d102148SJC Kuo 	value &= ~USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index);
12972d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
12982d102148SJC Kuo 
12992d102148SJC Kuo 	usleep_range(10, 20);
13002d102148SJC Kuo 
13012d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
13022d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
13032d102148SJC Kuo 	value |= USB2_HSIC_PORT_WAKEUP_EVENT(index);
13042d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
13052d102148SJC Kuo 
13062d102148SJC Kuo 	mutex_unlock(&padctl->lock);
13072d102148SJC Kuo 
13082d102148SJC Kuo 	return 0;
13092d102148SJC Kuo }
13102d102148SJC Kuo 
13112d102148SJC Kuo static bool tegra210_hsic_phy_remote_wake_detected(struct tegra_xusb_lane *lane)
13122d102148SJC Kuo {
13132d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
13142d102148SJC Kuo 	unsigned int index = lane->index;
13152d102148SJC Kuo 	u32 value;
13162d102148SJC Kuo 
13172d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
13182d102148SJC Kuo 	if ((value & USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index)) &&
13192d102148SJC Kuo 	    (value & USB2_HSIC_PORT_WAKEUP_EVENT(index)))
13202d102148SJC Kuo 		return true;
13212d102148SJC Kuo 
13222d102148SJC Kuo 	return false;
13232d102148SJC Kuo }
13242d102148SJC Kuo 
13252d102148SJC Kuo #define padctl_pmc_readl(_priv, _offset)						\
13262d102148SJC Kuo ({											\
13272d102148SJC Kuo 	u32 value;									\
13282d102148SJC Kuo 	WARN(regmap_read(_priv->regmap, _offset, &value), "read %s failed\n", #_offset);\
13292d102148SJC Kuo 	value;										\
13302d102148SJC Kuo })
13312d102148SJC Kuo 
13322d102148SJC Kuo #define padctl_pmc_writel(_priv, _value, _offset)					\
13332d102148SJC Kuo 	WARN(regmap_write(_priv->regmap, _offset, _value), "write %s failed\n", #_offset)
13342d102148SJC Kuo 
13352d102148SJC Kuo static int tegra210_pmc_utmi_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
13362d102148SJC Kuo 						  enum usb_device_speed speed)
13372d102148SJC Kuo {
13382d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
13392d102148SJC Kuo 	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
13402d102148SJC Kuo 	unsigned int port = lane->index;
13412d102148SJC Kuo 	u32 value, tctrl, pctrl, rpd_ctrl;
13422d102148SJC Kuo 
13432d102148SJC Kuo 	if (!priv->regmap)
13442d102148SJC Kuo 		return -EOPNOTSUPP;
13452d102148SJC Kuo 
13462d102148SJC Kuo 	if (speed > USB_SPEED_HIGH)
13472d102148SJC Kuo 		return -EINVAL;
13482d102148SJC Kuo 
13492d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
13502d102148SJC Kuo 	tctrl = TCTRL_VALUE(value);
13512d102148SJC Kuo 	pctrl = PCTRL_VALUE(value);
13522d102148SJC Kuo 
13532d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port));
13542d102148SJC Kuo 	rpd_ctrl = RPD_CTRL_VALUE(value);
13552d102148SJC Kuo 
13562d102148SJC Kuo 	/* ensure sleepwalk logic is disabled */
13572d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
13582d102148SJC Kuo 	value &= ~UTMIP_MASTER_ENABLE(port);
13592d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
13602d102148SJC Kuo 
13612d102148SJC Kuo 	/* ensure sleepwalk logics are in low power mode */
13622d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG);
13632d102148SJC Kuo 	value |= UTMIP_PWR(port);
13642d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_MASTER_CONFIG);
13652d102148SJC Kuo 
13662d102148SJC Kuo 	/* set debounce time */
13672d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL);
13682d102148SJC Kuo 	value &= ~UTMIP_LINE_DEB_CNT(~0);
13692d102148SJC Kuo 	value |= UTMIP_LINE_DEB_CNT(0x1);
13702d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_USB_DEBOUNCE_DEL);
13712d102148SJC Kuo 
13722d102148SJC Kuo 	/* ensure fake events of sleepwalk logic are desiabled */
13732d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_FAKE(port));
13742d102148SJC Kuo 	value &= ~(UTMIP_FAKE_USBOP_VAL(port) | UTMIP_FAKE_USBON_VAL(port) |
13752d102148SJC Kuo 		   UTMIP_FAKE_USBOP_EN(port) | UTMIP_FAKE_USBON_EN(port));
13762d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_FAKE(port));
13772d102148SJC Kuo 
13782d102148SJC Kuo 	/* ensure wake events of sleepwalk logic are not latched */
13792d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
13802d102148SJC Kuo 	value &= ~UTMIP_LINE_WAKEUP_EN(port);
13812d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
13822d102148SJC Kuo 
13832d102148SJC Kuo 	/* disable wake event triggers of sleepwalk logic */
13842d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
13852d102148SJC Kuo 	value &= ~UTMIP_WAKE_VAL(port, ~0);
13862d102148SJC Kuo 	value |= UTMIP_WAKE_VAL_NONE(port);
13872d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
13882d102148SJC Kuo 
13892d102148SJC Kuo 	/* power down the line state detectors of the pad */
13902d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_USB_AO);
13912d102148SJC Kuo 	value |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port));
13922d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_USB_AO);
13932d102148SJC Kuo 
13942d102148SJC Kuo 	/* save state per speed */
13952d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SAVED_STATE(port));
13962d102148SJC Kuo 	value &= ~SPEED(port, ~0);
13972d102148SJC Kuo 
13982d102148SJC Kuo 	switch (speed) {
13992d102148SJC Kuo 	case USB_SPEED_HIGH:
14002d102148SJC Kuo 		value |= UTMI_HS(port);
14012d102148SJC Kuo 		break;
14022d102148SJC Kuo 
14032d102148SJC Kuo 	case USB_SPEED_FULL:
14042d102148SJC Kuo 		value |= UTMI_FS(port);
14052d102148SJC Kuo 		break;
14062d102148SJC Kuo 
14072d102148SJC Kuo 	case USB_SPEED_LOW:
14082d102148SJC Kuo 		value |= UTMI_LS(port);
14092d102148SJC Kuo 		break;
14102d102148SJC Kuo 
14112d102148SJC Kuo 	default:
14122d102148SJC Kuo 		value |= UTMI_RST(port);
14132d102148SJC Kuo 		break;
14142d102148SJC Kuo 	}
14152d102148SJC Kuo 
14162d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SAVED_STATE(port));
14172d102148SJC Kuo 
14182d102148SJC Kuo 	/* enable the trigger of the sleepwalk logic */
14192d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));
14202d102148SJC Kuo 	value |= UTMIP_LINEVAL_WALK_EN(port);
14212d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));
14222d102148SJC Kuo 
14232d102148SJC Kuo 	/*
14242d102148SJC Kuo 	 * Reset the walk pointer and clear the alarm of the sleepwalk logic,
14252d102148SJC Kuo 	 * as well as capture the configuration of the USB2.0 pad.
14262d102148SJC Kuo 	 */
14272d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
14282d102148SJC Kuo 	value |= UTMIP_CLR_WALK_PTR(port) | UTMIP_CLR_WAKE_ALARM(port) | UTMIP_CAP_CFG(port);
14292d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
14302d102148SJC Kuo 
14312d102148SJC Kuo 	/* program electrical parameters read from XUSB PADCTL */
14322d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_TERM_PAD_CFG);
14332d102148SJC Kuo 	value &= ~(TCTRL_VAL(~0) | PCTRL_VAL(~0));
14342d102148SJC Kuo 	value |= (TCTRL_VAL(tctrl) | PCTRL_VAL(pctrl));
14352d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_TERM_PAD_CFG);
14362d102148SJC Kuo 
14372d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_PAD_CFGX(port));
14382d102148SJC Kuo 	value &= ~RPD_CTRL_PX(~0);
14392d102148SJC Kuo 	value |= RPD_CTRL_PX(rpd_ctrl);
14402d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_PAD_CFGX(port));
14412d102148SJC Kuo 
14422d102148SJC Kuo 	/*
14432d102148SJC Kuo 	 * Set up the pull-ups and pull-downs of the signals during the four
14442d102148SJC Kuo 	 * stages of sleepwalk. If a device is connected, program sleepwalk
14452d102148SJC Kuo 	 * logic to maintain a J and keep driving K upon seeing remote wake.
14462d102148SJC Kuo 	 */
14472d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_SLEEPWALK_PX(port));
14482d102148SJC Kuo 	value = UTMIP_USBOP_RPD_A | UTMIP_USBOP_RPD_B | UTMIP_USBOP_RPD_C | UTMIP_USBOP_RPD_D;
14492d102148SJC Kuo 	value |= UTMIP_USBON_RPD_A | UTMIP_USBON_RPD_B | UTMIP_USBON_RPD_C | UTMIP_USBON_RPD_D;
14502d102148SJC Kuo 
14512d102148SJC Kuo 	switch (speed) {
14522d102148SJC Kuo 	case USB_SPEED_HIGH:
14532d102148SJC Kuo 	case USB_SPEED_FULL:
14542d102148SJC Kuo 		/* J state: D+/D- = high/low, K state: D+/D- = low/high */
14552d102148SJC Kuo 		value |= UTMIP_HIGHZ_A;
14562d102148SJC Kuo 		value |= UTMIP_AP_A;
14572d102148SJC Kuo 		value |= UTMIP_AN_B | UTMIP_AN_C | UTMIP_AN_D;
14582d102148SJC Kuo 		break;
14592d102148SJC Kuo 
14602d102148SJC Kuo 	case USB_SPEED_LOW:
14612d102148SJC Kuo 		/* J state: D+/D- = low/high, K state: D+/D- = high/low */
14622d102148SJC Kuo 		value |= UTMIP_HIGHZ_A;
14632d102148SJC Kuo 		value |= UTMIP_AN_A;
14642d102148SJC Kuo 		value |= UTMIP_AP_B | UTMIP_AP_C | UTMIP_AP_D;
14652d102148SJC Kuo 		break;
14662d102148SJC Kuo 
14672d102148SJC Kuo 	default:
14682d102148SJC Kuo 		value |= UTMIP_HIGHZ_A | UTMIP_HIGHZ_B | UTMIP_HIGHZ_C | UTMIP_HIGHZ_D;
14692d102148SJC Kuo 		break;
14702d102148SJC Kuo 	}
14712d102148SJC Kuo 
14722d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_SLEEPWALK_PX(port));
14732d102148SJC Kuo 
14742d102148SJC Kuo 	/* power up the line state detectors of the pad */
14752d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_USB_AO);
14762d102148SJC Kuo 	value &= ~(USBOP_VAL_PD(port) | USBON_VAL_PD(port));
14772d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_USB_AO);
14782d102148SJC Kuo 
14792d102148SJC Kuo 	usleep_range(50, 100);
14802d102148SJC Kuo 
14812d102148SJC Kuo 	/* switch the electric control of the USB2.0 pad to PMC */
14822d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
14832d102148SJC Kuo 	value |= UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) | UTMIP_TCTRL_USE_PMC(port);
14842d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
14852d102148SJC Kuo 
14862d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1);
14872d102148SJC Kuo 	value |= UTMIP_RPD_CTRL_USE_PMC_PX(port) | UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port);
14882d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG1);
14892d102148SJC Kuo 
14902d102148SJC Kuo 	/* set the wake signaling trigger events */
14912d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
14922d102148SJC Kuo 	value &= ~UTMIP_WAKE_VAL(port, ~0);
14932d102148SJC Kuo 	value |= UTMIP_WAKE_VAL_ANY(port);
14942d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
14952d102148SJC Kuo 
14962d102148SJC Kuo 	/* enable the wake detection */
14972d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
14982d102148SJC Kuo 	value |= UTMIP_MASTER_ENABLE(port);
14992d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
15002d102148SJC Kuo 
15012d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
15022d102148SJC Kuo 	value |= UTMIP_LINE_WAKEUP_EN(port);
15032d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
15042d102148SJC Kuo 
15052d102148SJC Kuo 	return 0;
15062d102148SJC Kuo }
15072d102148SJC Kuo 
15082d102148SJC Kuo static int tegra210_pmc_utmi_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
15092d102148SJC Kuo {
15102d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
15112d102148SJC Kuo 	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
15122d102148SJC Kuo 	unsigned int port = lane->index;
15132d102148SJC Kuo 	u32 value;
15142d102148SJC Kuo 
15152d102148SJC Kuo 	if (!priv->regmap)
15162d102148SJC Kuo 		return -EOPNOTSUPP;
15172d102148SJC Kuo 
15182d102148SJC Kuo 	/* disable the wake detection */
15192d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
15202d102148SJC Kuo 	value &= ~UTMIP_MASTER_ENABLE(port);
15212d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
15222d102148SJC Kuo 
15232d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
15242d102148SJC Kuo 	value &= ~UTMIP_LINE_WAKEUP_EN(port);
15252d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
15262d102148SJC Kuo 
15272d102148SJC Kuo 	/* switch the electric control of the USB2.0 pad to XUSB or USB2 */
15282d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
15292d102148SJC Kuo 	value &= ~(UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) |
15302d102148SJC Kuo 		   UTMIP_TCTRL_USE_PMC(port));
15312d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
15322d102148SJC Kuo 
15332d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1);
15342d102148SJC Kuo 	value &= ~(UTMIP_RPD_CTRL_USE_PMC_PX(port) | UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port));
15352d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG1);
15362d102148SJC Kuo 
15372d102148SJC Kuo 	/* disable wake event triggers of sleepwalk logic */
15382d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
15392d102148SJC Kuo 	value &= ~UTMIP_WAKE_VAL(port, ~0);
15402d102148SJC Kuo 	value |= UTMIP_WAKE_VAL_NONE(port);
15412d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
15422d102148SJC Kuo 
15432d102148SJC Kuo 	/* power down the line state detectors of the port */
15442d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_USB_AO);
15452d102148SJC Kuo 	value |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port));
15462d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_USB_AO);
15472d102148SJC Kuo 
15482d102148SJC Kuo 	/* clear alarm of the sleepwalk logic */
15492d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
15502d102148SJC Kuo 	value |= UTMIP_CLR_WAKE_ALARM(port);
15512d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
15522d102148SJC Kuo 
15532d102148SJC Kuo 	return 0;
15542d102148SJC Kuo }
15552d102148SJC Kuo 
15562d102148SJC Kuo static int tegra210_pmc_hsic_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
15572d102148SJC Kuo 						  enum usb_device_speed speed)
15582d102148SJC Kuo {
15592d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
15602d102148SJC Kuo 	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
15612d102148SJC Kuo 	u32 value;
15622d102148SJC Kuo 
15632d102148SJC Kuo 	if (!priv->regmap)
15642d102148SJC Kuo 		return -EOPNOTSUPP;
15652d102148SJC Kuo 
15662d102148SJC Kuo 	/* ensure sleepwalk logic is disabled */
15672d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
15682d102148SJC Kuo 	value &= ~UHSIC_MASTER_ENABLE;
15692d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
15702d102148SJC Kuo 
15712d102148SJC Kuo 	/* ensure sleepwalk logics are in low power mode */
15722d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG);
15732d102148SJC Kuo 	value |= UHSIC_PWR;
15742d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_MASTER_CONFIG);
15752d102148SJC Kuo 
15762d102148SJC Kuo 	/* set debounce time */
15772d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL);
15782d102148SJC Kuo 	value &= ~UHSIC_LINE_DEB_CNT(~0);
15792d102148SJC Kuo 	value |= UHSIC_LINE_DEB_CNT(0x1);
15802d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_USB_DEBOUNCE_DEL);
15812d102148SJC Kuo 
15822d102148SJC Kuo 	/* ensure fake events of sleepwalk logic are desiabled */
15832d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_FAKE);
15842d102148SJC Kuo 	value &= ~(UHSIC_FAKE_STROBE_VAL | UHSIC_FAKE_DATA_VAL |
15852d102148SJC Kuo 		   UHSIC_FAKE_STROBE_EN | UHSIC_FAKE_DATA_EN);
15862d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_FAKE);
15872d102148SJC Kuo 
15882d102148SJC Kuo 	/* ensure wake events of sleepwalk logic are not latched */
15892d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
15902d102148SJC Kuo 	value &= ~UHSIC_LINE_WAKEUP_EN;
15912d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
15922d102148SJC Kuo 
15932d102148SJC Kuo 	/* disable wake event triggers of sleepwalk logic */
15942d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
15952d102148SJC Kuo 	value &= ~UHSIC_WAKE_VAL(~0);
15962d102148SJC Kuo 	value |= UHSIC_WAKE_VAL_NONE;
15972d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
15982d102148SJC Kuo 
15992d102148SJC Kuo 	/* power down the line state detectors of the port */
16002d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_USB_AO);
16012d102148SJC Kuo 	value |= STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD;
16022d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_USB_AO);
16032d102148SJC Kuo 
16042d102148SJC Kuo 	/* save state, HSIC always comes up as HS */
16052d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SAVED_STATE);
16062d102148SJC Kuo 	value &= ~UHSIC_MODE(~0);
16072d102148SJC Kuo 	value |= UHSIC_HS;
16082d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SAVED_STATE);
16092d102148SJC Kuo 
16102d102148SJC Kuo 	/* enable the trigger of the sleepwalk logic */
16112d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_CFG);
16122d102148SJC Kuo 	value |= UHSIC_WAKE_WALK_EN | UHSIC_LINEVAL_WALK_EN;
16132d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_CFG);
16142d102148SJC Kuo 
16152d102148SJC Kuo 	/*
16162d102148SJC Kuo 	 * Reset the walk pointer and clear the alarm of the sleepwalk logic,
16172d102148SJC Kuo 	 * as well as capture the configuration of the USB2.0 port.
16182d102148SJC Kuo 	 */
16192d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
16202d102148SJC Kuo 	value |= UHSIC_CLR_WALK_PTR | UHSIC_CLR_WAKE_ALARM;
16212d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
16222d102148SJC Kuo 
16232d102148SJC Kuo 	/*
16242d102148SJC Kuo 	 * Set up the pull-ups and pull-downs of the signals during the four
16252d102148SJC Kuo 	 * stages of sleepwalk. Maintain a HSIC IDLE and keep driving HSIC
16262d102148SJC Kuo 	 * RESUME upon remote wake.
16272d102148SJC Kuo 	 */
16282d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_P0);
16292d102148SJC Kuo 	value = UHSIC_DATA0_RPD_A | UHSIC_DATA0_RPU_B | UHSIC_DATA0_RPU_C | UHSIC_DATA0_RPU_D |
16302d102148SJC Kuo 		UHSIC_STROBE_RPU_A | UHSIC_STROBE_RPD_B | UHSIC_STROBE_RPD_C | UHSIC_STROBE_RPD_D;
16312d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_P0);
16322d102148SJC Kuo 
16332d102148SJC Kuo 	/* power up the line state detectors of the port */
16342d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_USB_AO);
16352d102148SJC Kuo 	value &= ~(STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD);
16362d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_USB_AO);
16372d102148SJC Kuo 
16382d102148SJC Kuo 	usleep_range(50, 100);
16392d102148SJC Kuo 
16402d102148SJC Kuo 	/* set the wake signaling trigger events */
16412d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
16422d102148SJC Kuo 	value &= ~UHSIC_WAKE_VAL(~0);
16432d102148SJC Kuo 	value |= UHSIC_WAKE_VAL_SD10;
16442d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
16452d102148SJC Kuo 
16462d102148SJC Kuo 	/* enable the wake detection */
16472d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
16482d102148SJC Kuo 	value |= UHSIC_MASTER_ENABLE;
16492d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
16502d102148SJC Kuo 
16512d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
16522d102148SJC Kuo 	value |= UHSIC_LINE_WAKEUP_EN;
16532d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
16542d102148SJC Kuo 
16552d102148SJC Kuo 	return 0;
16562d102148SJC Kuo }
16572d102148SJC Kuo 
16582d102148SJC Kuo static int tegra210_pmc_hsic_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
16592d102148SJC Kuo {
16602d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
16612d102148SJC Kuo 	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
16622d102148SJC Kuo 	u32 value;
16632d102148SJC Kuo 
16642d102148SJC Kuo 	if (!priv->regmap)
16652d102148SJC Kuo 		return -EOPNOTSUPP;
16662d102148SJC Kuo 
16672d102148SJC Kuo 	/* disable the wake detection */
16682d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
16692d102148SJC Kuo 	value &= ~UHSIC_MASTER_ENABLE;
16702d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
16712d102148SJC Kuo 
16722d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
16732d102148SJC Kuo 	value &= ~UHSIC_LINE_WAKEUP_EN;
16742d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
16752d102148SJC Kuo 
16762d102148SJC Kuo 	/* disable wake event triggers of sleepwalk logic */
16772d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
16782d102148SJC Kuo 	value &= ~UHSIC_WAKE_VAL(~0);
16792d102148SJC Kuo 	value |= UHSIC_WAKE_VAL_NONE;
16802d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
16812d102148SJC Kuo 
16822d102148SJC Kuo 	/* power down the line state detectors of the port */
16832d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_USB_AO);
16842d102148SJC Kuo 	value |= STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD;
16852d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_USB_AO);
16862d102148SJC Kuo 
16872d102148SJC Kuo 	/* clear alarm of the sleepwalk logic */
16882d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
16892d102148SJC Kuo 	value |= UHSIC_CLR_WAKE_ALARM;
16902d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
16912d102148SJC Kuo 
16922d102148SJC Kuo 	return 0;
16932d102148SJC Kuo }
16942d102148SJC Kuo 
169587d66f28SThierry Reding static int tegra210_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl,
169687d66f28SThierry Reding 					 unsigned int index, bool enable)
169787d66f28SThierry Reding {
169887d66f28SThierry Reding 	struct tegra_xusb_port *port;
169987d66f28SThierry Reding 	struct tegra_xusb_lane *lane;
170087d66f28SThierry Reding 	u32 value, offset;
170187d66f28SThierry Reding 
170287d66f28SThierry Reding 	port = tegra_xusb_find_port(padctl, "usb3", index);
170387d66f28SThierry Reding 	if (!port)
170487d66f28SThierry Reding 		return -ENODEV;
170587d66f28SThierry Reding 
170687d66f28SThierry Reding 	lane = port->lane;
170787d66f28SThierry Reding 
170887d66f28SThierry Reding 	if (lane->pad == padctl->pcie)
170987d66f28SThierry Reding 		offset = XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL1(lane->index);
171087d66f28SThierry Reding 	else
171187d66f28SThierry Reding 		offset = XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1;
171287d66f28SThierry Reding 
171387d66f28SThierry Reding 	value = padctl_readl(padctl, offset);
171487d66f28SThierry Reding 
171587d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_MASK <<
171687d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT) |
171787d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN |
171887d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD);
171987d66f28SThierry Reding 
172087d66f28SThierry Reding 	if (!enable) {
172187d66f28SThierry Reding 		value |= (XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_VAL <<
172287d66f28SThierry Reding 			  XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT) |
172387d66f28SThierry Reding 			 XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN |
172487d66f28SThierry Reding 			 XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD;
172587d66f28SThierry Reding 	}
172687d66f28SThierry Reding 
172787d66f28SThierry Reding 	padctl_writel(padctl, value, offset);
172887d66f28SThierry Reding 
172987d66f28SThierry Reding 	return 0;
173087d66f28SThierry Reding }
173187d66f28SThierry Reding 
173287d66f28SThierry Reding #define TEGRA210_LANE(_name, _offset, _shift, _mask, _type)		\
173387d66f28SThierry Reding 	{								\
173487d66f28SThierry Reding 		.name = _name,						\
173587d66f28SThierry Reding 		.offset = _offset,					\
173687d66f28SThierry Reding 		.shift = _shift,					\
173787d66f28SThierry Reding 		.mask = _mask,						\
173887d66f28SThierry Reding 		.num_funcs = ARRAY_SIZE(tegra210_##_type##_functions),	\
173987d66f28SThierry Reding 		.funcs = tegra210_##_type##_functions,			\
174087d66f28SThierry Reding 	}
174187d66f28SThierry Reding 
174287d66f28SThierry Reding static const char *tegra210_usb2_functions[] = {
174387d66f28SThierry Reding 	"snps",
174487d66f28SThierry Reding 	"xusb",
174587d66f28SThierry Reding 	"uart"
174687d66f28SThierry Reding };
174787d66f28SThierry Reding 
174887d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_usb2_lanes[] = {
174987d66f28SThierry Reding 	TEGRA210_LANE("usb2-0", 0x004,  0, 0x3, usb2),
175087d66f28SThierry Reding 	TEGRA210_LANE("usb2-1", 0x004,  2, 0x3, usb2),
175187d66f28SThierry Reding 	TEGRA210_LANE("usb2-2", 0x004,  4, 0x3, usb2),
175287d66f28SThierry Reding 	TEGRA210_LANE("usb2-3", 0x004,  6, 0x3, usb2),
175387d66f28SThierry Reding };
175487d66f28SThierry Reding 
175587d66f28SThierry Reding static struct tegra_xusb_lane *
175687d66f28SThierry Reding tegra210_usb2_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
175787d66f28SThierry Reding 			 unsigned int index)
175887d66f28SThierry Reding {
175987d66f28SThierry Reding 	struct tegra_xusb_usb2_lane *usb2;
176087d66f28SThierry Reding 	int err;
176187d66f28SThierry Reding 
176287d66f28SThierry Reding 	usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
176387d66f28SThierry Reding 	if (!usb2)
176487d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
176587d66f28SThierry Reding 
176687d66f28SThierry Reding 	INIT_LIST_HEAD(&usb2->base.list);
176787d66f28SThierry Reding 	usb2->base.soc = &pad->soc->lanes[index];
176887d66f28SThierry Reding 	usb2->base.index = index;
176987d66f28SThierry Reding 	usb2->base.pad = pad;
177087d66f28SThierry Reding 	usb2->base.np = np;
177187d66f28SThierry Reding 
177287d66f28SThierry Reding 	err = tegra_xusb_lane_parse_dt(&usb2->base, np);
177387d66f28SThierry Reding 	if (err < 0) {
177487d66f28SThierry Reding 		kfree(usb2);
177587d66f28SThierry Reding 		return ERR_PTR(err);
177687d66f28SThierry Reding 	}
177787d66f28SThierry Reding 
177887d66f28SThierry Reding 	return &usb2->base;
177987d66f28SThierry Reding }
178087d66f28SThierry Reding 
178187d66f28SThierry Reding static void tegra210_usb2_lane_remove(struct tegra_xusb_lane *lane)
178287d66f28SThierry Reding {
178387d66f28SThierry Reding 	struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane);
178487d66f28SThierry Reding 
178587d66f28SThierry Reding 	kfree(usb2);
178687d66f28SThierry Reding }
178787d66f28SThierry Reding 
178887d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_usb2_lane_ops = {
178987d66f28SThierry Reding 	.probe = tegra210_usb2_lane_probe,
179087d66f28SThierry Reding 	.remove = tegra210_usb2_lane_remove,
17912d102148SJC Kuo 	.enable_phy_sleepwalk = tegra210_pmc_utmi_enable_phy_sleepwalk,
17922d102148SJC Kuo 	.disable_phy_sleepwalk = tegra210_pmc_utmi_disable_phy_sleepwalk,
17932d102148SJC Kuo 	.enable_phy_wake = tegra210_utmi_enable_phy_wake,
17942d102148SJC Kuo 	.disable_phy_wake = tegra210_utmi_disable_phy_wake,
17952d102148SJC Kuo 	.remote_wake_detected = tegra210_utmi_phy_remote_wake_detected,
179687d66f28SThierry Reding };
179787d66f28SThierry Reding 
179887d66f28SThierry Reding static int tegra210_usb2_phy_init(struct phy *phy)
179987d66f28SThierry Reding {
180087d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
180187d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1802*0baabcbeSJC Kuo 	unsigned int index = lane->index;
1803*0baabcbeSJC Kuo 	struct tegra_xusb_usb2_port *port;
1804*0baabcbeSJC Kuo 	int err;
180587d66f28SThierry Reding 	u32 value;
180687d66f28SThierry Reding 
1807*0baabcbeSJC Kuo 	port = tegra_xusb_find_usb2_port(padctl, index);
1808*0baabcbeSJC Kuo 	if (!port) {
1809*0baabcbeSJC Kuo 		dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
1810*0baabcbeSJC Kuo 		return -ENODEV;
1811*0baabcbeSJC Kuo 	}
1812*0baabcbeSJC Kuo 
1813*0baabcbeSJC Kuo 	if (port->supply && port->mode == USB_DR_MODE_HOST) {
1814*0baabcbeSJC Kuo 		err = regulator_enable(port->supply);
1815*0baabcbeSJC Kuo 		if (err)
1816*0baabcbeSJC Kuo 			return err;
1817*0baabcbeSJC Kuo 	}
1818*0baabcbeSJC Kuo 
1819*0baabcbeSJC Kuo 	mutex_lock(&padctl->lock);
1820*0baabcbeSJC Kuo 
182187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
182287d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK <<
182387d66f28SThierry Reding 		   XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT);
182487d66f28SThierry Reding 	value |= XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB <<
182587d66f28SThierry Reding 		 XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT;
182687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX);
182787d66f28SThierry Reding 
1828*0baabcbeSJC Kuo 	mutex_unlock(&padctl->lock);
1829*0baabcbeSJC Kuo 
18302352fdb0SJC Kuo 	return 0;
183187d66f28SThierry Reding }
183287d66f28SThierry Reding 
183387d66f28SThierry Reding static int tegra210_usb2_phy_exit(struct phy *phy)
183487d66f28SThierry Reding {
1835*0baabcbeSJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
1836*0baabcbeSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1837*0baabcbeSJC Kuo 	struct tegra_xusb_usb2_port *port;
1838*0baabcbeSJC Kuo 	int err;
1839*0baabcbeSJC Kuo 
1840*0baabcbeSJC Kuo 	port = tegra_xusb_find_usb2_port(padctl, lane->index);
1841*0baabcbeSJC Kuo 	if (!port) {
1842*0baabcbeSJC Kuo 		dev_err(&phy->dev, "no port found for USB2 lane %u\n", lane->index);
1843*0baabcbeSJC Kuo 		return -ENODEV;
1844*0baabcbeSJC Kuo 	}
1845*0baabcbeSJC Kuo 
1846*0baabcbeSJC Kuo 	if (port->supply && port->mode == USB_DR_MODE_HOST) {
1847*0baabcbeSJC Kuo 		err = regulator_disable(port->supply);
1848*0baabcbeSJC Kuo 		if (err)
1849*0baabcbeSJC Kuo 			return err;
1850*0baabcbeSJC Kuo 	}
1851*0baabcbeSJC Kuo 
18522352fdb0SJC Kuo 	return 0;
185387d66f28SThierry Reding }
185487d66f28SThierry Reding 
1855de792a6dSNagarjuna Kristam static int tegra210_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
1856de792a6dSNagarjuna Kristam 					      bool status)
1857de792a6dSNagarjuna Kristam {
1858de792a6dSNagarjuna Kristam 	u32 value;
1859de792a6dSNagarjuna Kristam 
1860de792a6dSNagarjuna Kristam 	dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
1861de792a6dSNagarjuna Kristam 
1862de792a6dSNagarjuna Kristam 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
1863de792a6dSNagarjuna Kristam 
1864de792a6dSNagarjuna Kristam 	if (status) {
1865de792a6dSNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
1866de792a6dSNagarjuna Kristam 		value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
1867de792a6dSNagarjuna Kristam 			   XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
1868de792a6dSNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING <<
1869de792a6dSNagarjuna Kristam 			 XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
1870de792a6dSNagarjuna Kristam 	} else {
1871de792a6dSNagarjuna Kristam 		value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
1872de792a6dSNagarjuna Kristam 	}
1873de792a6dSNagarjuna Kristam 
1874de792a6dSNagarjuna Kristam 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
1875de792a6dSNagarjuna Kristam 
1876de792a6dSNagarjuna Kristam 	return 0;
1877de792a6dSNagarjuna Kristam }
1878de792a6dSNagarjuna Kristam 
1879de792a6dSNagarjuna Kristam static int tegra210_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl,
1880de792a6dSNagarjuna Kristam 					    bool status)
1881de792a6dSNagarjuna Kristam {
1882de792a6dSNagarjuna Kristam 	u32 value;
1883de792a6dSNagarjuna Kristam 
1884de792a6dSNagarjuna Kristam 	dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear");
1885de792a6dSNagarjuna Kristam 
1886de792a6dSNagarjuna Kristam 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
1887de792a6dSNagarjuna Kristam 
1888de792a6dSNagarjuna Kristam 	if (status) {
1889de792a6dSNagarjuna Kristam 		if (value & XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON) {
1890de792a6dSNagarjuna Kristam 			value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
1891de792a6dSNagarjuna Kristam 			padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
1892de792a6dSNagarjuna Kristam 			usleep_range(1000, 2000);
1893de792a6dSNagarjuna Kristam 
1894de792a6dSNagarjuna Kristam 			value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
1895de792a6dSNagarjuna Kristam 		}
1896de792a6dSNagarjuna Kristam 
1897de792a6dSNagarjuna Kristam 		value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
1898de792a6dSNagarjuna Kristam 			   XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
1899de792a6dSNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED <<
1900de792a6dSNagarjuna Kristam 			 XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
1901de792a6dSNagarjuna Kristam 	} else {
1902de792a6dSNagarjuna Kristam 		value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
1903de792a6dSNagarjuna Kristam 			   XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
1904de792a6dSNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING <<
1905de792a6dSNagarjuna Kristam 			 XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
1906de792a6dSNagarjuna Kristam 	}
1907de792a6dSNagarjuna Kristam 
1908de792a6dSNagarjuna Kristam 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
1909de792a6dSNagarjuna Kristam 
1910de792a6dSNagarjuna Kristam 	return 0;
1911de792a6dSNagarjuna Kristam }
1912de792a6dSNagarjuna Kristam 
1913de792a6dSNagarjuna Kristam static int tegra210_usb2_phy_set_mode(struct phy *phy, enum phy_mode mode,
1914de792a6dSNagarjuna Kristam 				      int submode)
1915de792a6dSNagarjuna Kristam {
1916de792a6dSNagarjuna Kristam 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
1917de792a6dSNagarjuna Kristam 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1918de792a6dSNagarjuna Kristam 	struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl,
1919de792a6dSNagarjuna Kristam 								lane->index);
1920de792a6dSNagarjuna Kristam 	int err = 0;
1921de792a6dSNagarjuna Kristam 
1922de792a6dSNagarjuna Kristam 	mutex_lock(&padctl->lock);
1923de792a6dSNagarjuna Kristam 
1924de792a6dSNagarjuna Kristam 	dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode);
1925de792a6dSNagarjuna Kristam 
1926de792a6dSNagarjuna Kristam 	if (mode == PHY_MODE_USB_OTG) {
1927de792a6dSNagarjuna Kristam 		if (submode == USB_ROLE_HOST) {
1928de792a6dSNagarjuna Kristam 			tegra210_xusb_padctl_id_override(padctl, true);
1929de792a6dSNagarjuna Kristam 
1930de792a6dSNagarjuna Kristam 			err = regulator_enable(port->supply);
1931de792a6dSNagarjuna Kristam 		} else if (submode == USB_ROLE_DEVICE) {
1932de792a6dSNagarjuna Kristam 			tegra210_xusb_padctl_vbus_override(padctl, true);
1933de792a6dSNagarjuna Kristam 		} else if (submode == USB_ROLE_NONE) {
1934de792a6dSNagarjuna Kristam 			/*
1935de792a6dSNagarjuna Kristam 			 * When port is peripheral only or role transitions to
1936de792a6dSNagarjuna Kristam 			 * USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not
1937de792a6dSNagarjuna Kristam 			 * be enabled.
1938de792a6dSNagarjuna Kristam 			 */
1939de792a6dSNagarjuna Kristam 			if (regulator_is_enabled(port->supply))
1940de792a6dSNagarjuna Kristam 				regulator_disable(port->supply);
1941de792a6dSNagarjuna Kristam 
1942de792a6dSNagarjuna Kristam 			tegra210_xusb_padctl_id_override(padctl, false);
1943de792a6dSNagarjuna Kristam 			tegra210_xusb_padctl_vbus_override(padctl, false);
1944de792a6dSNagarjuna Kristam 		}
1945de792a6dSNagarjuna Kristam 	}
1946de792a6dSNagarjuna Kristam 
1947de792a6dSNagarjuna Kristam 	mutex_unlock(&padctl->lock);
1948de792a6dSNagarjuna Kristam 
1949de792a6dSNagarjuna Kristam 	return err;
1950de792a6dSNagarjuna Kristam }
1951de792a6dSNagarjuna Kristam 
195287d66f28SThierry Reding static int tegra210_usb2_phy_power_on(struct phy *phy)
195387d66f28SThierry Reding {
195487d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
195587d66f28SThierry Reding 	struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane);
195687d66f28SThierry Reding 	struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad);
195787d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
195887d66f28SThierry Reding 	struct tegra210_xusb_padctl *priv;
195987d66f28SThierry Reding 	struct tegra_xusb_usb2_port *port;
196087d66f28SThierry Reding 	unsigned int index = lane->index;
196187d66f28SThierry Reding 	u32 value;
196287d66f28SThierry Reding 	int err;
196387d66f28SThierry Reding 
196487d66f28SThierry Reding 	port = tegra_xusb_find_usb2_port(padctl, index);
196587d66f28SThierry Reding 	if (!port) {
196687d66f28SThierry Reding 		dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
196787d66f28SThierry Reding 		return -ENODEV;
196887d66f28SThierry Reding 	}
196987d66f28SThierry Reding 
197087d66f28SThierry Reding 	priv = to_tegra210_xusb_padctl(padctl);
197187d66f28SThierry Reding 
1972*0baabcbeSJC Kuo 	mutex_lock(&padctl->lock);
1973*0baabcbeSJC Kuo 
1974a5be28c3SNagarjuna Kristam 	if (port->usb3_port_fake != -1) {
1975a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
1976a5be28c3SNagarjuna Kristam 		value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(
1977a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
1978a5be28c3SNagarjuna Kristam 		value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(
1979a5be28c3SNagarjuna Kristam 					port->usb3_port_fake, index);
1980a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP);
1981a5be28c3SNagarjuna Kristam 
1982a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
1983a5be28c3SNagarjuna Kristam 		value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(
1984a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
1985a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
1986a5be28c3SNagarjuna Kristam 
1987a5be28c3SNagarjuna Kristam 		usleep_range(100, 200);
1988a5be28c3SNagarjuna Kristam 
1989a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
1990a5be28c3SNagarjuna Kristam 		value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(
1991a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
1992a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
1993a5be28c3SNagarjuna Kristam 
1994a5be28c3SNagarjuna Kristam 		usleep_range(100, 200);
1995a5be28c3SNagarjuna Kristam 
1996a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
1997a5be28c3SNagarjuna Kristam 		value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(
1998a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
1999a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
2000a5be28c3SNagarjuna Kristam 	}
2001a5be28c3SNagarjuna Kristam 
200287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
200387d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK <<
200487d66f28SThierry Reding 		    XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) |
200587d66f28SThierry Reding 		   (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK <<
200687d66f28SThierry Reding 		    XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT));
200787d66f28SThierry Reding 	value |= (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL <<
200887d66f28SThierry Reding 		  XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT);
200987d66f28SThierry Reding 
201087d66f28SThierry Reding 	if (tegra_sku_info.revision < TEGRA_REVISION_A02)
201187d66f28SThierry Reding 		value |=
201287d66f28SThierry Reding 			(XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_VAL <<
201387d66f28SThierry Reding 			XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT);
201487d66f28SThierry Reding 
201587d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
201687d66f28SThierry Reding 
201787d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
201887d66f28SThierry Reding 	value &= ~XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(index);
2019ac25b6e9SNagarjuna Kristam 	if (port->mode == USB_DR_MODE_UNKNOWN)
2020ac25b6e9SNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DISABLED(index);
2021ac25b6e9SNagarjuna Kristam 	else if (port->mode == USB_DR_MODE_PERIPHERAL)
2022ac25b6e9SNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DEVICE(index);
2023ac25b6e9SNagarjuna Kristam 	else if (port->mode == USB_DR_MODE_HOST)
202487d66f28SThierry Reding 		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(index);
2025ac25b6e9SNagarjuna Kristam 	else if (port->mode == USB_DR_MODE_OTG)
2026ac25b6e9SNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_OTG(index);
202787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP);
202887d66f28SThierry Reding 
202987d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
203087d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK <<
203187d66f28SThierry Reding 		    XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT) |
203287d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD |
203387d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 |
203487d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI);
203587d66f28SThierry Reding 	value |= (priv->fuse.hs_curr_level[index] +
203687d66f28SThierry Reding 		  usb2->hs_curr_level_offset) <<
203787d66f28SThierry Reding 		 XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT;
203887d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
203987d66f28SThierry Reding 
204087d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
204187d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK <<
204287d66f28SThierry Reding 		    XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) |
204387d66f28SThierry Reding 		   (XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_MASK <<
204487d66f28SThierry Reding 		    XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT) |
204587d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR |
204687d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD |
204787d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD);
204887d66f28SThierry Reding 	value |= (priv->fuse.hs_term_range_adj <<
204987d66f28SThierry Reding 		  XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) |
205087d66f28SThierry Reding 		 (priv->fuse.rpd_ctrl <<
205187d66f28SThierry Reding 		  XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT);
205287d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
205387d66f28SThierry Reding 
205487d66f28SThierry Reding 	value = padctl_readl(padctl,
205587d66f28SThierry Reding 			     XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
205687d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_MASK <<
205787d66f28SThierry Reding 		   XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT);
2058ac25b6e9SNagarjuna Kristam 	if (port->mode == USB_DR_MODE_HOST)
205987d66f28SThierry Reding 		value |= XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18;
2060ac25b6e9SNagarjuna Kristam 	else
2061ac25b6e9SNagarjuna Kristam 		value |=
2062ac25b6e9SNagarjuna Kristam 		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_VAL <<
2063ac25b6e9SNagarjuna Kristam 		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT;
206487d66f28SThierry Reding 	padctl_writel(padctl, value,
206587d66f28SThierry Reding 		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
206687d66f28SThierry Reding 
206787d66f28SThierry Reding 	if (pad->enable > 0) {
206887d66f28SThierry Reding 		pad->enable++;
206987d66f28SThierry Reding 		mutex_unlock(&padctl->lock);
207087d66f28SThierry Reding 		return 0;
207187d66f28SThierry Reding 	}
207287d66f28SThierry Reding 
207387d66f28SThierry Reding 	err = clk_prepare_enable(pad->clk);
207487d66f28SThierry Reding 	if (err)
2075*0baabcbeSJC Kuo 		goto out;
207687d66f28SThierry Reding 
207787d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
207887d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK <<
207987d66f28SThierry Reding 		    XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT) |
208087d66f28SThierry Reding 		   (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_MASK <<
208187d66f28SThierry Reding 		    XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT));
208287d66f28SThierry Reding 	value |= (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL <<
208387d66f28SThierry Reding 		  XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT) |
208487d66f28SThierry Reding 		 (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_VAL <<
208587d66f28SThierry Reding 		  XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT);
208687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
208787d66f28SThierry Reding 
208887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
208987d66f28SThierry Reding 	value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
209087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
209187d66f28SThierry Reding 
209287d66f28SThierry Reding 	udelay(1);
209387d66f28SThierry Reding 
209487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
209587d66f28SThierry Reding 	value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL1_PD_TRK;
209687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
209787d66f28SThierry Reding 
209887d66f28SThierry Reding 	udelay(50);
209987d66f28SThierry Reding 
210087d66f28SThierry Reding 	clk_disable_unprepare(pad->clk);
210187d66f28SThierry Reding 
210287d66f28SThierry Reding 	pad->enable++;
210387d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
210487d66f28SThierry Reding 
210587d66f28SThierry Reding 	return 0;
210687d66f28SThierry Reding 
2107*0baabcbeSJC Kuo out:
210887d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
210987d66f28SThierry Reding 	return err;
211087d66f28SThierry Reding }
211187d66f28SThierry Reding 
211287d66f28SThierry Reding static int tegra210_usb2_phy_power_off(struct phy *phy)
211387d66f28SThierry Reding {
211487d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
211587d66f28SThierry Reding 	struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad);
211687d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
211787d66f28SThierry Reding 	struct tegra_xusb_usb2_port *port;
211887d66f28SThierry Reding 	u32 value;
211987d66f28SThierry Reding 
212087d66f28SThierry Reding 	port = tegra_xusb_find_usb2_port(padctl, lane->index);
212187d66f28SThierry Reding 	if (!port) {
212287d66f28SThierry Reding 		dev_err(&phy->dev, "no port found for USB2 lane %u\n",
212387d66f28SThierry Reding 			lane->index);
212487d66f28SThierry Reding 		return -ENODEV;
212587d66f28SThierry Reding 	}
212687d66f28SThierry Reding 
212787d66f28SThierry Reding 	mutex_lock(&padctl->lock);
212887d66f28SThierry Reding 
2129a5be28c3SNagarjuna Kristam 	if (port->usb3_port_fake != -1) {
2130a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
2131a5be28c3SNagarjuna Kristam 		value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(
2132a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
2133a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
2134a5be28c3SNagarjuna Kristam 
2135a5be28c3SNagarjuna Kristam 		usleep_range(100, 200);
2136a5be28c3SNagarjuna Kristam 
2137a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
2138a5be28c3SNagarjuna Kristam 		value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(
2139a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
2140a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
2141a5be28c3SNagarjuna Kristam 
2142a5be28c3SNagarjuna Kristam 		usleep_range(250, 350);
2143a5be28c3SNagarjuna Kristam 
2144a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
2145a5be28c3SNagarjuna Kristam 		value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(
2146a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
2147a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
2148a5be28c3SNagarjuna Kristam 
2149a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
2150a5be28c3SNagarjuna Kristam 		value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(port->usb3_port_fake,
2151a5be28c3SNagarjuna Kristam 					XUSB_PADCTL_SS_PORT_MAP_PORT_DISABLED);
2152a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP);
2153a5be28c3SNagarjuna Kristam 	}
2154a5be28c3SNagarjuna Kristam 
215587d66f28SThierry Reding 	if (WARN_ON(pad->enable == 0))
215687d66f28SThierry Reding 		goto out;
215787d66f28SThierry Reding 
215887d66f28SThierry Reding 	if (--pad->enable > 0)
215987d66f28SThierry Reding 		goto out;
216087d66f28SThierry Reding 
216187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
216287d66f28SThierry Reding 	value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
216387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
216487d66f28SThierry Reding 
216587d66f28SThierry Reding out:
216687d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
216787d66f28SThierry Reding 	return 0;
216887d66f28SThierry Reding }
216987d66f28SThierry Reding 
217087d66f28SThierry Reding static const struct phy_ops tegra210_usb2_phy_ops = {
217187d66f28SThierry Reding 	.init = tegra210_usb2_phy_init,
217287d66f28SThierry Reding 	.exit = tegra210_usb2_phy_exit,
217387d66f28SThierry Reding 	.power_on = tegra210_usb2_phy_power_on,
217487d66f28SThierry Reding 	.power_off = tegra210_usb2_phy_power_off,
2175de792a6dSNagarjuna Kristam 	.set_mode = tegra210_usb2_phy_set_mode,
217687d66f28SThierry Reding 	.owner = THIS_MODULE,
217787d66f28SThierry Reding };
217887d66f28SThierry Reding 
217987d66f28SThierry Reding static struct tegra_xusb_pad *
218087d66f28SThierry Reding tegra210_usb2_pad_probe(struct tegra_xusb_padctl *padctl,
218187d66f28SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
218287d66f28SThierry Reding 			struct device_node *np)
218387d66f28SThierry Reding {
218487d66f28SThierry Reding 	struct tegra_xusb_usb2_pad *usb2;
218587d66f28SThierry Reding 	struct tegra_xusb_pad *pad;
218687d66f28SThierry Reding 	int err;
218787d66f28SThierry Reding 
218887d66f28SThierry Reding 	usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
218987d66f28SThierry Reding 	if (!usb2)
219087d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
219187d66f28SThierry Reding 
219287d66f28SThierry Reding 	pad = &usb2->base;
219387d66f28SThierry Reding 	pad->ops = &tegra210_usb2_lane_ops;
219487d66f28SThierry Reding 	pad->soc = soc;
219587d66f28SThierry Reding 
219687d66f28SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
219787d66f28SThierry Reding 	if (err < 0) {
219887d66f28SThierry Reding 		kfree(usb2);
219987d66f28SThierry Reding 		goto out;
220087d66f28SThierry Reding 	}
220187d66f28SThierry Reding 
220287d66f28SThierry Reding 	usb2->clk = devm_clk_get(&pad->dev, "trk");
220387d66f28SThierry Reding 	if (IS_ERR(usb2->clk)) {
220487d66f28SThierry Reding 		err = PTR_ERR(usb2->clk);
220587d66f28SThierry Reding 		dev_err(&pad->dev, "failed to get trk clock: %d\n", err);
220687d66f28SThierry Reding 		goto unregister;
220787d66f28SThierry Reding 	}
220887d66f28SThierry Reding 
220987d66f28SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra210_usb2_phy_ops);
221087d66f28SThierry Reding 	if (err < 0)
221187d66f28SThierry Reding 		goto unregister;
221287d66f28SThierry Reding 
221387d66f28SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
221487d66f28SThierry Reding 
221587d66f28SThierry Reding 	return pad;
221687d66f28SThierry Reding 
221787d66f28SThierry Reding unregister:
221887d66f28SThierry Reding 	device_unregister(&pad->dev);
221987d66f28SThierry Reding out:
222087d66f28SThierry Reding 	return ERR_PTR(err);
222187d66f28SThierry Reding }
222287d66f28SThierry Reding 
222387d66f28SThierry Reding static void tegra210_usb2_pad_remove(struct tegra_xusb_pad *pad)
222487d66f28SThierry Reding {
222587d66f28SThierry Reding 	struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad);
222687d66f28SThierry Reding 
222787d66f28SThierry Reding 	kfree(usb2);
222887d66f28SThierry Reding }
222987d66f28SThierry Reding 
223087d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_usb2_ops = {
223187d66f28SThierry Reding 	.probe = tegra210_usb2_pad_probe,
223287d66f28SThierry Reding 	.remove = tegra210_usb2_pad_remove,
223387d66f28SThierry Reding };
223487d66f28SThierry Reding 
223587d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_usb2_pad = {
223687d66f28SThierry Reding 	.name = "usb2",
223787d66f28SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra210_usb2_lanes),
223887d66f28SThierry Reding 	.lanes = tegra210_usb2_lanes,
223987d66f28SThierry Reding 	.ops = &tegra210_usb2_ops,
224087d66f28SThierry Reding };
224187d66f28SThierry Reding 
224287d66f28SThierry Reding static const char *tegra210_hsic_functions[] = {
224387d66f28SThierry Reding 	"snps",
224487d66f28SThierry Reding 	"xusb",
224587d66f28SThierry Reding };
224687d66f28SThierry Reding 
224787d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_hsic_lanes[] = {
224887d66f28SThierry Reding 	TEGRA210_LANE("hsic-0", 0x004, 14, 0x1, hsic),
224987d66f28SThierry Reding };
225087d66f28SThierry Reding 
225187d66f28SThierry Reding static struct tegra_xusb_lane *
225287d66f28SThierry Reding tegra210_hsic_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
225387d66f28SThierry Reding 			 unsigned int index)
225487d66f28SThierry Reding {
225587d66f28SThierry Reding 	struct tegra_xusb_hsic_lane *hsic;
225687d66f28SThierry Reding 	int err;
225787d66f28SThierry Reding 
225887d66f28SThierry Reding 	hsic = kzalloc(sizeof(*hsic), GFP_KERNEL);
225987d66f28SThierry Reding 	if (!hsic)
226087d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
226187d66f28SThierry Reding 
226287d66f28SThierry Reding 	INIT_LIST_HEAD(&hsic->base.list);
226387d66f28SThierry Reding 	hsic->base.soc = &pad->soc->lanes[index];
226487d66f28SThierry Reding 	hsic->base.index = index;
226587d66f28SThierry Reding 	hsic->base.pad = pad;
226687d66f28SThierry Reding 	hsic->base.np = np;
226787d66f28SThierry Reding 
226887d66f28SThierry Reding 	err = tegra_xusb_lane_parse_dt(&hsic->base, np);
226987d66f28SThierry Reding 	if (err < 0) {
227087d66f28SThierry Reding 		kfree(hsic);
227187d66f28SThierry Reding 		return ERR_PTR(err);
227287d66f28SThierry Reding 	}
227387d66f28SThierry Reding 
227487d66f28SThierry Reding 	return &hsic->base;
227587d66f28SThierry Reding }
227687d66f28SThierry Reding 
227787d66f28SThierry Reding static void tegra210_hsic_lane_remove(struct tegra_xusb_lane *lane)
227887d66f28SThierry Reding {
227987d66f28SThierry Reding 	struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane);
228087d66f28SThierry Reding 
228187d66f28SThierry Reding 	kfree(hsic);
228287d66f28SThierry Reding }
228387d66f28SThierry Reding 
228487d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_hsic_lane_ops = {
228587d66f28SThierry Reding 	.probe = tegra210_hsic_lane_probe,
228687d66f28SThierry Reding 	.remove = tegra210_hsic_lane_remove,
22872d102148SJC Kuo 	.enable_phy_sleepwalk = tegra210_pmc_hsic_enable_phy_sleepwalk,
22882d102148SJC Kuo 	.disable_phy_sleepwalk = tegra210_pmc_hsic_disable_phy_sleepwalk,
22892d102148SJC Kuo 	.enable_phy_wake = tegra210_hsic_enable_phy_wake,
22902d102148SJC Kuo 	.disable_phy_wake = tegra210_hsic_disable_phy_wake,
22912d102148SJC Kuo 	.remote_wake_detected = tegra210_hsic_phy_remote_wake_detected,
229287d66f28SThierry Reding };
229387d66f28SThierry Reding 
229487d66f28SThierry Reding static int tegra210_hsic_phy_init(struct phy *phy)
229587d66f28SThierry Reding {
229687d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
229787d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
229887d66f28SThierry Reding 	u32 value;
229987d66f28SThierry Reding 
230087d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
230187d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_MASK <<
230287d66f28SThierry Reding 		   XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT);
230387d66f28SThierry Reding 	value |= XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_XUSB <<
230487d66f28SThierry Reding 		 XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT;
230587d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX);
230687d66f28SThierry Reding 
23072352fdb0SJC Kuo 	return 0;
230887d66f28SThierry Reding }
230987d66f28SThierry Reding 
231087d66f28SThierry Reding static int tegra210_hsic_phy_exit(struct phy *phy)
231187d66f28SThierry Reding {
23122352fdb0SJC Kuo 	return 0;
231387d66f28SThierry Reding }
231487d66f28SThierry Reding 
231587d66f28SThierry Reding static int tegra210_hsic_phy_power_on(struct phy *phy)
231687d66f28SThierry Reding {
231787d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
231887d66f28SThierry Reding 	struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane);
231987d66f28SThierry Reding 	struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad);
232087d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
232187d66f28SThierry Reding 	unsigned int index = lane->index;
232287d66f28SThierry Reding 	u32 value;
232387d66f28SThierry Reding 	int err;
232487d66f28SThierry Reding 
232587d66f28SThierry Reding 	err = regulator_enable(pad->supply);
232687d66f28SThierry Reding 	if (err)
232787d66f28SThierry Reding 		return err;
232887d66f28SThierry Reding 
232987d66f28SThierry Reding 	padctl_writel(padctl, hsic->strobe_trim,
233087d66f28SThierry Reding 		      XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL);
233187d66f28SThierry Reding 
233287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index));
233387d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_MASK <<
233487d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT);
233587d66f28SThierry Reding 	value |= (hsic->tx_rtune_p <<
233687d66f28SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT);
233787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index));
233887d66f28SThierry Reding 
233987d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(index));
234087d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK <<
234187d66f28SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) |
234287d66f28SThierry Reding 		   (XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK <<
234387d66f28SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT));
234487d66f28SThierry Reding 	value |= (hsic->rx_strobe_trim <<
234587d66f28SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) |
234687d66f28SThierry Reding 		 (hsic->rx_data_trim <<
234787d66f28SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT);
234887d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL2(index));
234987d66f28SThierry Reding 
235087d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index));
235187d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA0 |
235287d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA1 |
235387d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE |
235487d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 |
235587d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 |
235687d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE |
235787d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 |
235887d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 |
235987d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE |
236087d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 |
236187d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 |
236287d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE);
236387d66f28SThierry Reding 	value |= XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 |
236487d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 |
236587d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_RPD_STROBE;
236687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL0(index));
236787d66f28SThierry Reding 
236887d66f28SThierry Reding 	err = clk_prepare_enable(pad->clk);
236987d66f28SThierry Reding 	if (err)
237087d66f28SThierry Reding 		goto disable;
237187d66f28SThierry Reding 
237287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PAD_TRK_CTL);
237387d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_MASK <<
237487d66f28SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT) |
237587d66f28SThierry Reding 		   (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_MASK <<
237687d66f28SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT));
237787d66f28SThierry Reding 	value |= (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_VAL <<
237887d66f28SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT) |
237987d66f28SThierry Reding 		 (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_VAL <<
238087d66f28SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT);
238187d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PAD_TRK_CTL);
238287d66f28SThierry Reding 
238387d66f28SThierry Reding 	udelay(1);
238487d66f28SThierry Reding 
238587d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PAD_TRK_CTL);
238687d66f28SThierry Reding 	value &= ~XUSB_PADCTL_HSIC_PAD_TRK_CTL_PD_TRK;
238787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PAD_TRK_CTL);
238887d66f28SThierry Reding 
238987d66f28SThierry Reding 	udelay(50);
239087d66f28SThierry Reding 
239187d66f28SThierry Reding 	clk_disable_unprepare(pad->clk);
239287d66f28SThierry Reding 
239387d66f28SThierry Reding 	return 0;
239487d66f28SThierry Reding 
239587d66f28SThierry Reding disable:
239687d66f28SThierry Reding 	regulator_disable(pad->supply);
239787d66f28SThierry Reding 	return err;
239887d66f28SThierry Reding }
239987d66f28SThierry Reding 
240087d66f28SThierry Reding static int tegra210_hsic_phy_power_off(struct phy *phy)
240187d66f28SThierry Reding {
240287d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
240387d66f28SThierry Reding 	struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad);
240487d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
240587d66f28SThierry Reding 	unsigned int index = lane->index;
240687d66f28SThierry Reding 	u32 value;
240787d66f28SThierry Reding 
240887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index));
240987d66f28SThierry Reding 	value |= XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 |
241087d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 |
241187d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE |
241287d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 |
241387d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 |
241487d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE |
241587d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 |
241687d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 |
241787d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE;
241887d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index));
241987d66f28SThierry Reding 
242087d66f28SThierry Reding 	regulator_disable(pad->supply);
242187d66f28SThierry Reding 
242287d66f28SThierry Reding 	return 0;
242387d66f28SThierry Reding }
242487d66f28SThierry Reding 
242587d66f28SThierry Reding static const struct phy_ops tegra210_hsic_phy_ops = {
242687d66f28SThierry Reding 	.init = tegra210_hsic_phy_init,
242787d66f28SThierry Reding 	.exit = tegra210_hsic_phy_exit,
242887d66f28SThierry Reding 	.power_on = tegra210_hsic_phy_power_on,
242987d66f28SThierry Reding 	.power_off = tegra210_hsic_phy_power_off,
243087d66f28SThierry Reding 	.owner = THIS_MODULE,
243187d66f28SThierry Reding };
243287d66f28SThierry Reding 
243387d66f28SThierry Reding static struct tegra_xusb_pad *
243487d66f28SThierry Reding tegra210_hsic_pad_probe(struct tegra_xusb_padctl *padctl,
243587d66f28SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
243687d66f28SThierry Reding 			struct device_node *np)
243787d66f28SThierry Reding {
243887d66f28SThierry Reding 	struct tegra_xusb_hsic_pad *hsic;
243987d66f28SThierry Reding 	struct tegra_xusb_pad *pad;
244087d66f28SThierry Reding 	int err;
244187d66f28SThierry Reding 
244287d66f28SThierry Reding 	hsic = kzalloc(sizeof(*hsic), GFP_KERNEL);
244387d66f28SThierry Reding 	if (!hsic)
244487d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
244587d66f28SThierry Reding 
244687d66f28SThierry Reding 	pad = &hsic->base;
244787d66f28SThierry Reding 	pad->ops = &tegra210_hsic_lane_ops;
244887d66f28SThierry Reding 	pad->soc = soc;
244987d66f28SThierry Reding 
245087d66f28SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
245187d66f28SThierry Reding 	if (err < 0) {
245287d66f28SThierry Reding 		kfree(hsic);
245387d66f28SThierry Reding 		goto out;
245487d66f28SThierry Reding 	}
245587d66f28SThierry Reding 
245687d66f28SThierry Reding 	hsic->clk = devm_clk_get(&pad->dev, "trk");
245787d66f28SThierry Reding 	if (IS_ERR(hsic->clk)) {
245887d66f28SThierry Reding 		err = PTR_ERR(hsic->clk);
245987d66f28SThierry Reding 		dev_err(&pad->dev, "failed to get trk clock: %d\n", err);
246087d66f28SThierry Reding 		goto unregister;
246187d66f28SThierry Reding 	}
246287d66f28SThierry Reding 
246387d66f28SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra210_hsic_phy_ops);
246487d66f28SThierry Reding 	if (err < 0)
246587d66f28SThierry Reding 		goto unregister;
246687d66f28SThierry Reding 
246787d66f28SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
246887d66f28SThierry Reding 
246987d66f28SThierry Reding 	return pad;
247087d66f28SThierry Reding 
247187d66f28SThierry Reding unregister:
247287d66f28SThierry Reding 	device_unregister(&pad->dev);
247387d66f28SThierry Reding out:
247487d66f28SThierry Reding 	return ERR_PTR(err);
247587d66f28SThierry Reding }
247687d66f28SThierry Reding 
247787d66f28SThierry Reding static void tegra210_hsic_pad_remove(struct tegra_xusb_pad *pad)
247887d66f28SThierry Reding {
247987d66f28SThierry Reding 	struct tegra_xusb_hsic_pad *hsic = to_hsic_pad(pad);
248087d66f28SThierry Reding 
248187d66f28SThierry Reding 	kfree(hsic);
248287d66f28SThierry Reding }
248387d66f28SThierry Reding 
248487d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_hsic_ops = {
248587d66f28SThierry Reding 	.probe = tegra210_hsic_pad_probe,
248687d66f28SThierry Reding 	.remove = tegra210_hsic_pad_remove,
248787d66f28SThierry Reding };
248887d66f28SThierry Reding 
248987d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_hsic_pad = {
249087d66f28SThierry Reding 	.name = "hsic",
249187d66f28SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra210_hsic_lanes),
249287d66f28SThierry Reding 	.lanes = tegra210_hsic_lanes,
249387d66f28SThierry Reding 	.ops = &tegra210_hsic_ops,
249487d66f28SThierry Reding };
249587d66f28SThierry Reding 
2496c339605cSJC Kuo static void tegra210_uphy_lane_iddq_enable(struct tegra_xusb_lane *lane)
2497c339605cSJC Kuo {
2498c339605cSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
2499c339605cSJC Kuo 	u32 value;
2500c339605cSJC Kuo 
2501c339605cSJC Kuo 	value = padctl_readl(padctl, lane->soc->regs.misc_ctl2);
2502c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD;
2503c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD;
2504c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD;
2505c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD;
2506c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ;
2507c339605cSJC Kuo 	value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK;
2508c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL;
2509c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ;
2510c339605cSJC Kuo 	value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK;
2511c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL;
2512c339605cSJC Kuo 	padctl_writel(padctl, value, lane->soc->regs.misc_ctl2);
2513c339605cSJC Kuo }
2514c339605cSJC Kuo 
2515c339605cSJC Kuo static void tegra210_uphy_lane_iddq_disable(struct tegra_xusb_lane *lane)
2516c339605cSJC Kuo {
2517c339605cSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
2518c339605cSJC Kuo 	u32 value;
2519c339605cSJC Kuo 
2520c339605cSJC Kuo 	value = padctl_readl(padctl, lane->soc->regs.misc_ctl2);
2521c339605cSJC Kuo 	value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD;
2522c339605cSJC Kuo 	value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD;
2523c339605cSJC Kuo 	value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD;
2524c339605cSJC Kuo 	value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD;
2525c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ;
2526c339605cSJC Kuo 	value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK;
2527c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL;
2528c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ;
2529c339605cSJC Kuo 	value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK;
2530c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL;
2531c339605cSJC Kuo 	padctl_writel(padctl, value, lane->soc->regs.misc_ctl2);
2532c339605cSJC Kuo }
2533c339605cSJC Kuo 
2534c339605cSJC Kuo #define TEGRA210_UPHY_LANE(_name, _offset, _shift, _mask, _type, _misc)	\
2535c339605cSJC Kuo 	{								\
2536c339605cSJC Kuo 		.name = _name,						\
2537c339605cSJC Kuo 		.offset = _offset,					\
2538c339605cSJC Kuo 		.shift = _shift,					\
2539c339605cSJC Kuo 		.mask = _mask,						\
2540c339605cSJC Kuo 		.num_funcs = ARRAY_SIZE(tegra210_##_type##_functions),	\
2541c339605cSJC Kuo 		.funcs = tegra210_##_type##_functions,			\
2542c339605cSJC Kuo 		.regs.misc_ctl2 = _misc,				\
2543c339605cSJC Kuo 	}
2544c339605cSJC Kuo 
254587d66f28SThierry Reding static const char *tegra210_pcie_functions[] = {
254687d66f28SThierry Reding 	"pcie-x1",
254787d66f28SThierry Reding 	"usb3-ss",
254887d66f28SThierry Reding 	"sata",
254987d66f28SThierry Reding 	"pcie-x4",
255087d66f28SThierry Reding };
255187d66f28SThierry Reding 
255287d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_pcie_lanes[] = {
2553c339605cSJC Kuo 	TEGRA210_UPHY_LANE("pcie-0", 0x028, 12, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)),
2554c339605cSJC Kuo 	TEGRA210_UPHY_LANE("pcie-1", 0x028, 14, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(1)),
2555c339605cSJC Kuo 	TEGRA210_UPHY_LANE("pcie-2", 0x028, 16, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(2)),
2556c339605cSJC Kuo 	TEGRA210_UPHY_LANE("pcie-3", 0x028, 18, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(3)),
2557c339605cSJC Kuo 	TEGRA210_UPHY_LANE("pcie-4", 0x028, 20, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(4)),
2558c339605cSJC Kuo 	TEGRA210_UPHY_LANE("pcie-5", 0x028, 22, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(5)),
2559c339605cSJC Kuo 	TEGRA210_UPHY_LANE("pcie-6", 0x028, 24, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(6)),
256087d66f28SThierry Reding };
256187d66f28SThierry Reding 
256223d5ec3fSJC Kuo static struct tegra_xusb_usb3_port *
256323d5ec3fSJC Kuo tegra210_lane_to_usb3_port(struct tegra_xusb_lane *lane)
256423d5ec3fSJC Kuo {
256523d5ec3fSJC Kuo 	int port;
256623d5ec3fSJC Kuo 
256723d5ec3fSJC Kuo 	if (!lane || !lane->pad || !lane->pad->padctl)
256823d5ec3fSJC Kuo 		return NULL;
256923d5ec3fSJC Kuo 
257023d5ec3fSJC Kuo 	port = tegra210_usb3_lane_map(lane);
257123d5ec3fSJC Kuo 	if (port < 0)
257223d5ec3fSJC Kuo 		return NULL;
257323d5ec3fSJC Kuo 
257423d5ec3fSJC Kuo 	return tegra_xusb_find_usb3_port(lane->pad->padctl, port);
257523d5ec3fSJC Kuo }
257623d5ec3fSJC Kuo 
257723d5ec3fSJC Kuo static int tegra210_usb3_phy_power_on(struct phy *phy)
257823d5ec3fSJC Kuo {
257923d5ec3fSJC Kuo 	struct device *dev = &phy->dev;
258023d5ec3fSJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
258123d5ec3fSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
258223d5ec3fSJC Kuo 	struct tegra_xusb_usb3_port *usb3 = tegra210_lane_to_usb3_port(lane);
258323d5ec3fSJC Kuo 	unsigned int index;
258423d5ec3fSJC Kuo 	u32 value;
258523d5ec3fSJC Kuo 
258623d5ec3fSJC Kuo 	if (!usb3) {
258723d5ec3fSJC Kuo 		dev_err(dev, "no USB3 port found for lane %u\n", lane->index);
258823d5ec3fSJC Kuo 		return -ENODEV;
258923d5ec3fSJC Kuo 	}
259023d5ec3fSJC Kuo 
259123d5ec3fSJC Kuo 	index = usb3->base.index;
259223d5ec3fSJC Kuo 
259323d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
259423d5ec3fSJC Kuo 
259523d5ec3fSJC Kuo 	if (!usb3->internal)
259623d5ec3fSJC Kuo 		value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index);
259723d5ec3fSJC Kuo 	else
259823d5ec3fSJC Kuo 		value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index);
259923d5ec3fSJC Kuo 
260023d5ec3fSJC Kuo 	value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(index);
260123d5ec3fSJC Kuo 	value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(index, usb3->port);
260223d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP);
260323d5ec3fSJC Kuo 
260423d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(index));
260523d5ec3fSJC Kuo 	value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_MASK <<
260623d5ec3fSJC Kuo 		   XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT);
260723d5ec3fSJC Kuo 	value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_VAL <<
260823d5ec3fSJC Kuo 		 XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT;
260923d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(index));
261023d5ec3fSJC Kuo 
261123d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(index));
261223d5ec3fSJC Kuo 	value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_MASK <<
261323d5ec3fSJC Kuo 		   XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT);
261423d5ec3fSJC Kuo 	value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_VAL <<
261523d5ec3fSJC Kuo 		 XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT;
261623d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(index));
261723d5ec3fSJC Kuo 
261823d5ec3fSJC Kuo 	padctl_writel(padctl, XUSB_PADCTL_UPHY_USB3_PAD_ECTL3_RX_DFE_VAL,
261923d5ec3fSJC Kuo 		      XUSB_PADCTL_UPHY_USB3_PADX_ECTL3(index));
262023d5ec3fSJC Kuo 
262123d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(index));
262223d5ec3fSJC Kuo 	value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_MASK <<
262323d5ec3fSJC Kuo 		   XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT);
262423d5ec3fSJC Kuo 	value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_VAL <<
262523d5ec3fSJC Kuo 		 XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT;
262623d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(index));
262723d5ec3fSJC Kuo 
262823d5ec3fSJC Kuo 	padctl_writel(padctl, XUSB_PADCTL_UPHY_USB3_PAD_ECTL6_RX_EQ_CTRL_H_VAL,
262923d5ec3fSJC Kuo 		      XUSB_PADCTL_UPHY_USB3_PADX_ECTL6(index));
263023d5ec3fSJC Kuo 
263123d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
263223d5ec3fSJC Kuo 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(index);
263323d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
263423d5ec3fSJC Kuo 
263523d5ec3fSJC Kuo 	usleep_range(100, 200);
263623d5ec3fSJC Kuo 
263723d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
263823d5ec3fSJC Kuo 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(index);
263923d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
264023d5ec3fSJC Kuo 
264123d5ec3fSJC Kuo 	usleep_range(100, 200);
264223d5ec3fSJC Kuo 
264323d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
264423d5ec3fSJC Kuo 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(index);
264523d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
264623d5ec3fSJC Kuo 
264723d5ec3fSJC Kuo 	return 0;
264823d5ec3fSJC Kuo }
264923d5ec3fSJC Kuo 
265023d5ec3fSJC Kuo static int tegra210_usb3_phy_power_off(struct phy *phy)
265123d5ec3fSJC Kuo {
265223d5ec3fSJC Kuo 	struct device *dev = &phy->dev;
265323d5ec3fSJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
265423d5ec3fSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
265523d5ec3fSJC Kuo 	struct tegra_xusb_usb3_port *usb3 = tegra210_lane_to_usb3_port(lane);
265623d5ec3fSJC Kuo 	unsigned int index;
265723d5ec3fSJC Kuo 	u32 value;
265823d5ec3fSJC Kuo 
265923d5ec3fSJC Kuo 	if (!usb3) {
266023d5ec3fSJC Kuo 		dev_err(dev, "no USB3 port found for lane %u\n", lane->index);
266123d5ec3fSJC Kuo 		return -ENODEV;
266223d5ec3fSJC Kuo 	}
266323d5ec3fSJC Kuo 
266423d5ec3fSJC Kuo 	index = usb3->base.index;
266523d5ec3fSJC Kuo 
266623d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
266723d5ec3fSJC Kuo 	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(index);
266823d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
266923d5ec3fSJC Kuo 
267023d5ec3fSJC Kuo 	usleep_range(100, 200);
267123d5ec3fSJC Kuo 
267223d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
267323d5ec3fSJC Kuo 	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(index);
267423d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
267523d5ec3fSJC Kuo 
267623d5ec3fSJC Kuo 	usleep_range(250, 350);
267723d5ec3fSJC Kuo 
267823d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
267923d5ec3fSJC Kuo 	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(index);
268023d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
268123d5ec3fSJC Kuo 
268223d5ec3fSJC Kuo 	return 0;
268323d5ec3fSJC Kuo }
268487d66f28SThierry Reding static struct tegra_xusb_lane *
268587d66f28SThierry Reding tegra210_pcie_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
268687d66f28SThierry Reding 			 unsigned int index)
268787d66f28SThierry Reding {
268887d66f28SThierry Reding 	struct tegra_xusb_pcie_lane *pcie;
268987d66f28SThierry Reding 	int err;
269087d66f28SThierry Reding 
269187d66f28SThierry Reding 	pcie = kzalloc(sizeof(*pcie), GFP_KERNEL);
269287d66f28SThierry Reding 	if (!pcie)
269387d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
269487d66f28SThierry Reding 
269587d66f28SThierry Reding 	INIT_LIST_HEAD(&pcie->base.list);
269687d66f28SThierry Reding 	pcie->base.soc = &pad->soc->lanes[index];
269787d66f28SThierry Reding 	pcie->base.index = index;
269887d66f28SThierry Reding 	pcie->base.pad = pad;
269987d66f28SThierry Reding 	pcie->base.np = np;
270087d66f28SThierry Reding 
270187d66f28SThierry Reding 	err = tegra_xusb_lane_parse_dt(&pcie->base, np);
270287d66f28SThierry Reding 	if (err < 0) {
270387d66f28SThierry Reding 		kfree(pcie);
270487d66f28SThierry Reding 		return ERR_PTR(err);
270587d66f28SThierry Reding 	}
270687d66f28SThierry Reding 
270787d66f28SThierry Reding 	return &pcie->base;
270887d66f28SThierry Reding }
270987d66f28SThierry Reding 
271087d66f28SThierry Reding static void tegra210_pcie_lane_remove(struct tegra_xusb_lane *lane)
271187d66f28SThierry Reding {
271287d66f28SThierry Reding 	struct tegra_xusb_pcie_lane *pcie = to_pcie_lane(lane);
271387d66f28SThierry Reding 
271487d66f28SThierry Reding 	kfree(pcie);
271587d66f28SThierry Reding }
271687d66f28SThierry Reding 
271787d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_pcie_lane_ops = {
271887d66f28SThierry Reding 	.probe = tegra210_pcie_lane_probe,
271987d66f28SThierry Reding 	.remove = tegra210_pcie_lane_remove,
2720c339605cSJC Kuo 	.iddq_enable = tegra210_uphy_lane_iddq_enable,
2721c339605cSJC Kuo 	.iddq_disable = tegra210_uphy_lane_iddq_disable,
27222d102148SJC Kuo 	.enable_phy_sleepwalk = tegra210_usb3_enable_phy_sleepwalk,
27232d102148SJC Kuo 	.disable_phy_sleepwalk = tegra210_usb3_disable_phy_sleepwalk,
27242d102148SJC Kuo 	.enable_phy_wake = tegra210_usb3_enable_phy_wake,
27252d102148SJC Kuo 	.disable_phy_wake = tegra210_usb3_disable_phy_wake,
27262d102148SJC Kuo 	.remote_wake_detected = tegra210_usb3_phy_remote_wake_detected,
272787d66f28SThierry Reding };
272887d66f28SThierry Reding 
272987d66f28SThierry Reding static int tegra210_pcie_phy_init(struct phy *phy)
273087d66f28SThierry Reding {
273187d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
27322352fdb0SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
273387d66f28SThierry Reding 
27342352fdb0SJC Kuo 	mutex_lock(&padctl->lock);
273587d66f28SThierry Reding 
27362352fdb0SJC Kuo 	tegra210_uphy_init(padctl);
273787d66f28SThierry Reding 
27382352fdb0SJC Kuo 	mutex_unlock(&padctl->lock);
27392352fdb0SJC Kuo 
27402352fdb0SJC Kuo 	return 0;
274187d66f28SThierry Reding }
274287d66f28SThierry Reding 
274387d66f28SThierry Reding static int tegra210_pcie_phy_power_on(struct phy *phy)
274487d66f28SThierry Reding {
274587d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
274687d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
27472352fdb0SJC Kuo 	int err = 0;
274887d66f28SThierry Reding 
274987d66f28SThierry Reding 	mutex_lock(&padctl->lock);
275087d66f28SThierry Reding 
275123d5ec3fSJC Kuo 	if (tegra_xusb_lane_check(lane, "usb3-ss"))
275223d5ec3fSJC Kuo 		err = tegra210_usb3_phy_power_on(phy);
275323d5ec3fSJC Kuo 
275487d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
275587d66f28SThierry Reding 	return err;
275687d66f28SThierry Reding }
275787d66f28SThierry Reding 
275887d66f28SThierry Reding static int tegra210_pcie_phy_power_off(struct phy *phy)
275987d66f28SThierry Reding {
276087d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
276187d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
276223d5ec3fSJC Kuo 	int err = 0;
276387d66f28SThierry Reding 
276423d5ec3fSJC Kuo 	mutex_lock(&padctl->lock);
276523d5ec3fSJC Kuo 
276623d5ec3fSJC Kuo 	if (tegra_xusb_lane_check(lane, "usb3-ss"))
276723d5ec3fSJC Kuo 		err = tegra210_usb3_phy_power_off(phy);
276823d5ec3fSJC Kuo 
276923d5ec3fSJC Kuo 	mutex_unlock(&padctl->lock);
277023d5ec3fSJC Kuo 	return err;
277187d66f28SThierry Reding }
277287d66f28SThierry Reding 
277387d66f28SThierry Reding static const struct phy_ops tegra210_pcie_phy_ops = {
277487d66f28SThierry Reding 	.init = tegra210_pcie_phy_init,
277587d66f28SThierry Reding 	.power_on = tegra210_pcie_phy_power_on,
277687d66f28SThierry Reding 	.power_off = tegra210_pcie_phy_power_off,
277787d66f28SThierry Reding 	.owner = THIS_MODULE,
277887d66f28SThierry Reding };
277987d66f28SThierry Reding 
278087d66f28SThierry Reding static struct tegra_xusb_pad *
278187d66f28SThierry Reding tegra210_pcie_pad_probe(struct tegra_xusb_padctl *padctl,
278287d66f28SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
278387d66f28SThierry Reding 			struct device_node *np)
278487d66f28SThierry Reding {
278587d66f28SThierry Reding 	struct tegra_xusb_pcie_pad *pcie;
278687d66f28SThierry Reding 	struct tegra_xusb_pad *pad;
278787d66f28SThierry Reding 	int err;
278887d66f28SThierry Reding 
278987d66f28SThierry Reding 	pcie = kzalloc(sizeof(*pcie), GFP_KERNEL);
279087d66f28SThierry Reding 	if (!pcie)
279187d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
279287d66f28SThierry Reding 
279387d66f28SThierry Reding 	pad = &pcie->base;
279487d66f28SThierry Reding 	pad->ops = &tegra210_pcie_lane_ops;
279587d66f28SThierry Reding 	pad->soc = soc;
279687d66f28SThierry Reding 
279787d66f28SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
279887d66f28SThierry Reding 	if (err < 0) {
279987d66f28SThierry Reding 		kfree(pcie);
280087d66f28SThierry Reding 		goto out;
280187d66f28SThierry Reding 	}
280287d66f28SThierry Reding 
280387d66f28SThierry Reding 	pcie->pll = devm_clk_get(&pad->dev, "pll");
280487d66f28SThierry Reding 	if (IS_ERR(pcie->pll)) {
280587d66f28SThierry Reding 		err = PTR_ERR(pcie->pll);
280687d66f28SThierry Reding 		dev_err(&pad->dev, "failed to get PLL: %d\n", err);
280787d66f28SThierry Reding 		goto unregister;
280887d66f28SThierry Reding 	}
280987d66f28SThierry Reding 
281087d66f28SThierry Reding 	pcie->rst = devm_reset_control_get(&pad->dev, "phy");
281187d66f28SThierry Reding 	if (IS_ERR(pcie->rst)) {
281287d66f28SThierry Reding 		err = PTR_ERR(pcie->rst);
281387d66f28SThierry Reding 		dev_err(&pad->dev, "failed to get PCIe pad reset: %d\n", err);
281487d66f28SThierry Reding 		goto unregister;
281587d66f28SThierry Reding 	}
281687d66f28SThierry Reding 
281787d66f28SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra210_pcie_phy_ops);
281887d66f28SThierry Reding 	if (err < 0)
281987d66f28SThierry Reding 		goto unregister;
282087d66f28SThierry Reding 
282187d66f28SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
282287d66f28SThierry Reding 
282387d66f28SThierry Reding 	return pad;
282487d66f28SThierry Reding 
282587d66f28SThierry Reding unregister:
282687d66f28SThierry Reding 	device_unregister(&pad->dev);
282787d66f28SThierry Reding out:
282887d66f28SThierry Reding 	return ERR_PTR(err);
282987d66f28SThierry Reding }
283087d66f28SThierry Reding 
283187d66f28SThierry Reding static void tegra210_pcie_pad_remove(struct tegra_xusb_pad *pad)
283287d66f28SThierry Reding {
283387d66f28SThierry Reding 	struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(pad);
283487d66f28SThierry Reding 
283587d66f28SThierry Reding 	kfree(pcie);
283687d66f28SThierry Reding }
283787d66f28SThierry Reding 
283887d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_pcie_ops = {
283987d66f28SThierry Reding 	.probe = tegra210_pcie_pad_probe,
284087d66f28SThierry Reding 	.remove = tegra210_pcie_pad_remove,
284187d66f28SThierry Reding };
284287d66f28SThierry Reding 
284387d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_pcie_pad = {
284487d66f28SThierry Reding 	.name = "pcie",
284587d66f28SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra210_pcie_lanes),
284687d66f28SThierry Reding 	.lanes = tegra210_pcie_lanes,
284787d66f28SThierry Reding 	.ops = &tegra210_pcie_ops,
284887d66f28SThierry Reding };
284987d66f28SThierry Reding 
285087d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_sata_lanes[] = {
2851c339605cSJC Kuo 	TEGRA210_UPHY_LANE("sata-0", 0x028, 30, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2),
285287d66f28SThierry Reding };
285387d66f28SThierry Reding 
285487d66f28SThierry Reding static struct tegra_xusb_lane *
285587d66f28SThierry Reding tegra210_sata_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
285687d66f28SThierry Reding 			 unsigned int index)
285787d66f28SThierry Reding {
285887d66f28SThierry Reding 	struct tegra_xusb_sata_lane *sata;
285987d66f28SThierry Reding 	int err;
286087d66f28SThierry Reding 
286187d66f28SThierry Reding 	sata = kzalloc(sizeof(*sata), GFP_KERNEL);
286287d66f28SThierry Reding 	if (!sata)
286387d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
286487d66f28SThierry Reding 
286587d66f28SThierry Reding 	INIT_LIST_HEAD(&sata->base.list);
286687d66f28SThierry Reding 	sata->base.soc = &pad->soc->lanes[index];
286787d66f28SThierry Reding 	sata->base.index = index;
286887d66f28SThierry Reding 	sata->base.pad = pad;
286987d66f28SThierry Reding 	sata->base.np = np;
287087d66f28SThierry Reding 
287187d66f28SThierry Reding 	err = tegra_xusb_lane_parse_dt(&sata->base, np);
287287d66f28SThierry Reding 	if (err < 0) {
287387d66f28SThierry Reding 		kfree(sata);
287487d66f28SThierry Reding 		return ERR_PTR(err);
287587d66f28SThierry Reding 	}
287687d66f28SThierry Reding 
287787d66f28SThierry Reding 	return &sata->base;
287887d66f28SThierry Reding }
287987d66f28SThierry Reding 
288087d66f28SThierry Reding static void tegra210_sata_lane_remove(struct tegra_xusb_lane *lane)
288187d66f28SThierry Reding {
288287d66f28SThierry Reding 	struct tegra_xusb_sata_lane *sata = to_sata_lane(lane);
288387d66f28SThierry Reding 
288487d66f28SThierry Reding 	kfree(sata);
288587d66f28SThierry Reding }
288687d66f28SThierry Reding 
288787d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_sata_lane_ops = {
288887d66f28SThierry Reding 	.probe = tegra210_sata_lane_probe,
288987d66f28SThierry Reding 	.remove = tegra210_sata_lane_remove,
2890c339605cSJC Kuo 	.iddq_enable = tegra210_uphy_lane_iddq_enable,
2891c339605cSJC Kuo 	.iddq_disable = tegra210_uphy_lane_iddq_disable,
28922d102148SJC Kuo 	.enable_phy_sleepwalk = tegra210_usb3_enable_phy_sleepwalk,
28932d102148SJC Kuo 	.disable_phy_sleepwalk = tegra210_usb3_disable_phy_sleepwalk,
28942d102148SJC Kuo 	.enable_phy_wake = tegra210_usb3_enable_phy_wake,
28952d102148SJC Kuo 	.disable_phy_wake = tegra210_usb3_disable_phy_wake,
28962d102148SJC Kuo 	.remote_wake_detected = tegra210_usb3_phy_remote_wake_detected,
289787d66f28SThierry Reding };
289887d66f28SThierry Reding 
289987d66f28SThierry Reding static int tegra210_sata_phy_init(struct phy *phy)
290087d66f28SThierry Reding {
290187d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
29022352fdb0SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
290387d66f28SThierry Reding 
29042352fdb0SJC Kuo 	mutex_lock(&padctl->lock);
290587d66f28SThierry Reding 
29062352fdb0SJC Kuo 	tegra210_uphy_init(padctl);
290787d66f28SThierry Reding 
29082352fdb0SJC Kuo 	mutex_unlock(&padctl->lock);
29092352fdb0SJC Kuo 	return 0;
291087d66f28SThierry Reding }
291187d66f28SThierry Reding 
291287d66f28SThierry Reding static int tegra210_sata_phy_power_on(struct phy *phy)
291387d66f28SThierry Reding {
291487d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
291587d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
29162352fdb0SJC Kuo 	int err = 0;
291787d66f28SThierry Reding 
291887d66f28SThierry Reding 	mutex_lock(&padctl->lock);
291987d66f28SThierry Reding 
292023d5ec3fSJC Kuo 	if (tegra_xusb_lane_check(lane, "usb3-ss"))
292123d5ec3fSJC Kuo 		err = tegra210_usb3_phy_power_on(phy);
292223d5ec3fSJC Kuo 
292387d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
292487d66f28SThierry Reding 	return err;
292587d66f28SThierry Reding }
292687d66f28SThierry Reding 
292787d66f28SThierry Reding static int tegra210_sata_phy_power_off(struct phy *phy)
292887d66f28SThierry Reding {
292987d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
293087d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
293123d5ec3fSJC Kuo 	int err = 0;
293287d66f28SThierry Reding 
293323d5ec3fSJC Kuo 	mutex_lock(&padctl->lock);
293423d5ec3fSJC Kuo 
293523d5ec3fSJC Kuo 	if (tegra_xusb_lane_check(lane, "usb3-ss"))
293623d5ec3fSJC Kuo 		err = tegra210_usb3_phy_power_off(phy);
293723d5ec3fSJC Kuo 
293823d5ec3fSJC Kuo 	mutex_unlock(&padctl->lock);
293923d5ec3fSJC Kuo 	return err;
294087d66f28SThierry Reding }
294187d66f28SThierry Reding 
294287d66f28SThierry Reding static const struct phy_ops tegra210_sata_phy_ops = {
294387d66f28SThierry Reding 	.init = tegra210_sata_phy_init,
294487d66f28SThierry Reding 	.power_on = tegra210_sata_phy_power_on,
294587d66f28SThierry Reding 	.power_off = tegra210_sata_phy_power_off,
294687d66f28SThierry Reding 	.owner = THIS_MODULE,
294787d66f28SThierry Reding };
294887d66f28SThierry Reding 
294987d66f28SThierry Reding static struct tegra_xusb_pad *
295087d66f28SThierry Reding tegra210_sata_pad_probe(struct tegra_xusb_padctl *padctl,
295187d66f28SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
295287d66f28SThierry Reding 			struct device_node *np)
295387d66f28SThierry Reding {
295487d66f28SThierry Reding 	struct tegra_xusb_sata_pad *sata;
295587d66f28SThierry Reding 	struct tegra_xusb_pad *pad;
295687d66f28SThierry Reding 	int err;
295787d66f28SThierry Reding 
295887d66f28SThierry Reding 	sata = kzalloc(sizeof(*sata), GFP_KERNEL);
295987d66f28SThierry Reding 	if (!sata)
296087d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
296187d66f28SThierry Reding 
296287d66f28SThierry Reding 	pad = &sata->base;
296387d66f28SThierry Reding 	pad->ops = &tegra210_sata_lane_ops;
296487d66f28SThierry Reding 	pad->soc = soc;
296587d66f28SThierry Reding 
296687d66f28SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
296787d66f28SThierry Reding 	if (err < 0) {
296887d66f28SThierry Reding 		kfree(sata);
296987d66f28SThierry Reding 		goto out;
297087d66f28SThierry Reding 	}
297187d66f28SThierry Reding 
297287d66f28SThierry Reding 	sata->rst = devm_reset_control_get(&pad->dev, "phy");
297387d66f28SThierry Reding 	if (IS_ERR(sata->rst)) {
297487d66f28SThierry Reding 		err = PTR_ERR(sata->rst);
297587d66f28SThierry Reding 		dev_err(&pad->dev, "failed to get SATA pad reset: %d\n", err);
297687d66f28SThierry Reding 		goto unregister;
297787d66f28SThierry Reding 	}
297887d66f28SThierry Reding 
297987d66f28SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra210_sata_phy_ops);
298087d66f28SThierry Reding 	if (err < 0)
298187d66f28SThierry Reding 		goto unregister;
298287d66f28SThierry Reding 
298387d66f28SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
298487d66f28SThierry Reding 
298587d66f28SThierry Reding 	return pad;
298687d66f28SThierry Reding 
298787d66f28SThierry Reding unregister:
298887d66f28SThierry Reding 	device_unregister(&pad->dev);
298987d66f28SThierry Reding out:
299087d66f28SThierry Reding 	return ERR_PTR(err);
299187d66f28SThierry Reding }
299287d66f28SThierry Reding 
299387d66f28SThierry Reding static void tegra210_sata_pad_remove(struct tegra_xusb_pad *pad)
299487d66f28SThierry Reding {
299587d66f28SThierry Reding 	struct tegra_xusb_sata_pad *sata = to_sata_pad(pad);
299687d66f28SThierry Reding 
299787d66f28SThierry Reding 	kfree(sata);
299887d66f28SThierry Reding }
299987d66f28SThierry Reding 
300087d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_sata_ops = {
300187d66f28SThierry Reding 	.probe = tegra210_sata_pad_probe,
300287d66f28SThierry Reding 	.remove = tegra210_sata_pad_remove,
300387d66f28SThierry Reding };
300487d66f28SThierry Reding 
300587d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_sata_pad = {
300687d66f28SThierry Reding 	.name = "sata",
300787d66f28SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra210_sata_lanes),
300887d66f28SThierry Reding 	.lanes = tegra210_sata_lanes,
300987d66f28SThierry Reding 	.ops = &tegra210_sata_ops,
301087d66f28SThierry Reding };
301187d66f28SThierry Reding 
301287d66f28SThierry Reding static const struct tegra_xusb_pad_soc * const tegra210_pads[] = {
301387d66f28SThierry Reding 	&tegra210_usb2_pad,
301487d66f28SThierry Reding 	&tegra210_hsic_pad,
301587d66f28SThierry Reding 	&tegra210_pcie_pad,
301687d66f28SThierry Reding 	&tegra210_sata_pad,
301787d66f28SThierry Reding };
301887d66f28SThierry Reding 
301987d66f28SThierry Reding static int tegra210_usb2_port_enable(struct tegra_xusb_port *port)
302087d66f28SThierry Reding {
302187d66f28SThierry Reding 	return 0;
302287d66f28SThierry Reding }
302387d66f28SThierry Reding 
302487d66f28SThierry Reding static void tegra210_usb2_port_disable(struct tegra_xusb_port *port)
302587d66f28SThierry Reding {
302687d66f28SThierry Reding }
302787d66f28SThierry Reding 
302887d66f28SThierry Reding static struct tegra_xusb_lane *
302987d66f28SThierry Reding tegra210_usb2_port_map(struct tegra_xusb_port *port)
303087d66f28SThierry Reding {
303187d66f28SThierry Reding 	return tegra_xusb_find_lane(port->padctl, "usb2", port->index);
303287d66f28SThierry Reding }
303387d66f28SThierry Reding 
303487d66f28SThierry Reding static const struct tegra_xusb_port_ops tegra210_usb2_port_ops = {
3035e78fdbadSThierry Reding 	.release = tegra_xusb_usb2_port_release,
30362f8da84dSThierry Reding 	.remove = tegra_xusb_usb2_port_remove,
303787d66f28SThierry Reding 	.enable = tegra210_usb2_port_enable,
303887d66f28SThierry Reding 	.disable = tegra210_usb2_port_disable,
303987d66f28SThierry Reding 	.map = tegra210_usb2_port_map,
304087d66f28SThierry Reding };
304187d66f28SThierry Reding 
304287d66f28SThierry Reding static int tegra210_hsic_port_enable(struct tegra_xusb_port *port)
304387d66f28SThierry Reding {
304487d66f28SThierry Reding 	return 0;
304587d66f28SThierry Reding }
304687d66f28SThierry Reding 
304787d66f28SThierry Reding static void tegra210_hsic_port_disable(struct tegra_xusb_port *port)
304887d66f28SThierry Reding {
304987d66f28SThierry Reding }
305087d66f28SThierry Reding 
305187d66f28SThierry Reding static struct tegra_xusb_lane *
305287d66f28SThierry Reding tegra210_hsic_port_map(struct tegra_xusb_port *port)
305387d66f28SThierry Reding {
305487d66f28SThierry Reding 	return tegra_xusb_find_lane(port->padctl, "hsic", port->index);
305587d66f28SThierry Reding }
305687d66f28SThierry Reding 
305787d66f28SThierry Reding static const struct tegra_xusb_port_ops tegra210_hsic_port_ops = {
3058e78fdbadSThierry Reding 	.release = tegra_xusb_hsic_port_release,
305987d66f28SThierry Reding 	.enable = tegra210_hsic_port_enable,
306087d66f28SThierry Reding 	.disable = tegra210_hsic_port_disable,
306187d66f28SThierry Reding 	.map = tegra210_hsic_port_map,
306287d66f28SThierry Reding };
306387d66f28SThierry Reding 
306487d66f28SThierry Reding static int tegra210_usb3_port_enable(struct tegra_xusb_port *port)
306587d66f28SThierry Reding {
306687d66f28SThierry Reding 	return 0;
306787d66f28SThierry Reding }
306887d66f28SThierry Reding 
306987d66f28SThierry Reding static void tegra210_usb3_port_disable(struct tegra_xusb_port *port)
307087d66f28SThierry Reding {
307187d66f28SThierry Reding }
307287d66f28SThierry Reding 
307387d66f28SThierry Reding static struct tegra_xusb_lane *
307487d66f28SThierry Reding tegra210_usb3_port_map(struct tegra_xusb_port *port)
307587d66f28SThierry Reding {
307687d66f28SThierry Reding 	return tegra_xusb_port_find_lane(port, tegra210_usb3_map, "usb3-ss");
307787d66f28SThierry Reding }
307887d66f28SThierry Reding 
307987d66f28SThierry Reding static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = {
3080e78fdbadSThierry Reding 	.release = tegra_xusb_usb3_port_release,
30812f8da84dSThierry Reding 	.remove = tegra_xusb_usb3_port_remove,
308287d66f28SThierry Reding 	.enable = tegra210_usb3_port_enable,
308387d66f28SThierry Reding 	.disable = tegra210_usb3_port_disable,
308487d66f28SThierry Reding 	.map = tegra210_usb3_port_map,
308587d66f28SThierry Reding };
308687d66f28SThierry Reding 
308790767cdfSNagarjuna Kristam static int tegra210_utmi_port_reset(struct phy *phy)
308890767cdfSNagarjuna Kristam {
308990767cdfSNagarjuna Kristam 	struct tegra_xusb_padctl *padctl;
309090767cdfSNagarjuna Kristam 	struct tegra_xusb_lane *lane;
309190767cdfSNagarjuna Kristam 	u32 value;
309290767cdfSNagarjuna Kristam 
309390767cdfSNagarjuna Kristam 	lane = phy_get_drvdata(phy);
309490767cdfSNagarjuna Kristam 	padctl = lane->pad->padctl;
309590767cdfSNagarjuna Kristam 
309690767cdfSNagarjuna Kristam 	value = padctl_readl(padctl,
309790767cdfSNagarjuna Kristam 		     XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL0(lane->index));
309890767cdfSNagarjuna Kristam 
309990767cdfSNagarjuna Kristam 	if ((value & XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIP) ||
310090767cdfSNagarjuna Kristam 	    (value & XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIN)) {
310190767cdfSNagarjuna Kristam 		tegra210_xusb_padctl_vbus_override(padctl, false);
310290767cdfSNagarjuna Kristam 		tegra210_xusb_padctl_vbus_override(padctl, true);
310390767cdfSNagarjuna Kristam 		return 1;
310490767cdfSNagarjuna Kristam 	}
310590767cdfSNagarjuna Kristam 
310690767cdfSNagarjuna Kristam 	return 0;
310790767cdfSNagarjuna Kristam }
310890767cdfSNagarjuna Kristam 
310987d66f28SThierry Reding static int
311087d66f28SThierry Reding tegra210_xusb_read_fuse_calibration(struct tegra210_xusb_fuse_calibration *fuse)
311187d66f28SThierry Reding {
311287d66f28SThierry Reding 	unsigned int i;
311387d66f28SThierry Reding 	u32 value;
311487d66f28SThierry Reding 	int err;
311587d66f28SThierry Reding 
311687d66f28SThierry Reding 	err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value);
311787d66f28SThierry Reding 	if (err < 0)
311887d66f28SThierry Reding 		return err;
311987d66f28SThierry Reding 
312087d66f28SThierry Reding 	for (i = 0; i < ARRAY_SIZE(fuse->hs_curr_level); i++) {
312187d66f28SThierry Reding 		fuse->hs_curr_level[i] =
312287d66f28SThierry Reding 			(value >> FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(i)) &
312387d66f28SThierry Reding 			FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK;
312487d66f28SThierry Reding 	}
312587d66f28SThierry Reding 
312687d66f28SThierry Reding 	fuse->hs_term_range_adj =
312787d66f28SThierry Reding 		(value >> FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT) &
312887d66f28SThierry Reding 		FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK;
312987d66f28SThierry Reding 
313087d66f28SThierry Reding 	err = tegra_fuse_readl(TEGRA_FUSE_USB_CALIB_EXT_0, &value);
313187d66f28SThierry Reding 	if (err < 0)
313287d66f28SThierry Reding 		return err;
313387d66f28SThierry Reding 
313487d66f28SThierry Reding 	fuse->rpd_ctrl =
313587d66f28SThierry Reding 		(value >> FUSE_USB_CALIB_EXT_RPD_CTRL_SHIFT) &
313687d66f28SThierry Reding 		FUSE_USB_CALIB_EXT_RPD_CTRL_MASK;
313787d66f28SThierry Reding 
313887d66f28SThierry Reding 	return 0;
313987d66f28SThierry Reding }
314087d66f28SThierry Reding 
314187d66f28SThierry Reding static struct tegra_xusb_padctl *
314287d66f28SThierry Reding tegra210_xusb_padctl_probe(struct device *dev,
314387d66f28SThierry Reding 			   const struct tegra_xusb_padctl_soc *soc)
314487d66f28SThierry Reding {
314587d66f28SThierry Reding 	struct tegra210_xusb_padctl *padctl;
31462d102148SJC Kuo 	struct platform_device *pdev;
31472d102148SJC Kuo 	struct device_node *np;
314887d66f28SThierry Reding 	int err;
314987d66f28SThierry Reding 
315087d66f28SThierry Reding 	padctl = devm_kzalloc(dev, sizeof(*padctl), GFP_KERNEL);
315187d66f28SThierry Reding 	if (!padctl)
315287d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
315387d66f28SThierry Reding 
315487d66f28SThierry Reding 	padctl->base.dev = dev;
315587d66f28SThierry Reding 	padctl->base.soc = soc;
315687d66f28SThierry Reding 
315787d66f28SThierry Reding 	err = tegra210_xusb_read_fuse_calibration(&padctl->fuse);
315887d66f28SThierry Reding 	if (err < 0)
315987d66f28SThierry Reding 		return ERR_PTR(err);
316087d66f28SThierry Reding 
31612d102148SJC Kuo 	np = of_parse_phandle(dev->of_node, "nvidia,pmc", 0);
31622d102148SJC Kuo 	if (!np) {
31632d102148SJC Kuo 		dev_warn(dev, "nvidia,pmc property is missing\n");
31642d102148SJC Kuo 		goto out;
31652d102148SJC Kuo 	}
31662d102148SJC Kuo 
31672d102148SJC Kuo 	pdev = of_find_device_by_node(np);
31682d102148SJC Kuo 	if (!pdev) {
31692d102148SJC Kuo 		dev_warn(dev, "PMC device is not available\n");
31702d102148SJC Kuo 		goto out;
31712d102148SJC Kuo 	}
31722d102148SJC Kuo 
31732d102148SJC Kuo 	if (!platform_get_drvdata(pdev))
31742d102148SJC Kuo 		return ERR_PTR(-EPROBE_DEFER);
31752d102148SJC Kuo 
31762d102148SJC Kuo 	padctl->regmap = dev_get_regmap(&pdev->dev, "usb_sleepwalk");
31772d102148SJC Kuo 	if (!padctl->regmap)
31782d102148SJC Kuo 		dev_info(dev, "failed to find PMC regmap\n");
31792d102148SJC Kuo 
31802d102148SJC Kuo out:
318187d66f28SThierry Reding 	return &padctl->base;
318287d66f28SThierry Reding }
318387d66f28SThierry Reding 
318487d66f28SThierry Reding static void tegra210_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
318587d66f28SThierry Reding {
318687d66f28SThierry Reding }
318787d66f28SThierry Reding 
31882d102148SJC Kuo static void tegra210_xusb_padctl_save(struct tegra_xusb_padctl *padctl)
31892d102148SJC Kuo {
31902d102148SJC Kuo 	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
31912d102148SJC Kuo 
31922d102148SJC Kuo 	priv->context.usb2_pad_mux =
31932d102148SJC Kuo 		padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
31942d102148SJC Kuo 	priv->context.usb2_port_cap =
31952d102148SJC Kuo 		padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
31962d102148SJC Kuo 	priv->context.ss_port_map =
31972d102148SJC Kuo 		padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
31982d102148SJC Kuo 	priv->context.usb3_pad_mux =
31992d102148SJC Kuo 		padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
32002d102148SJC Kuo }
32012d102148SJC Kuo 
32022d102148SJC Kuo static void tegra210_xusb_padctl_restore(struct tegra_xusb_padctl *padctl)
32032d102148SJC Kuo {
32042d102148SJC Kuo 	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
32052d102148SJC Kuo 	struct tegra_xusb_lane *lane;
32062d102148SJC Kuo 
32072d102148SJC Kuo 	padctl_writel(padctl, priv->context.usb2_pad_mux,
32082d102148SJC Kuo 		XUSB_PADCTL_USB2_PAD_MUX);
32092d102148SJC Kuo 	padctl_writel(padctl, priv->context.usb2_port_cap,
32102d102148SJC Kuo 		XUSB_PADCTL_USB2_PORT_CAP);
32112d102148SJC Kuo 	padctl_writel(padctl, priv->context.ss_port_map,
32122d102148SJC Kuo 		XUSB_PADCTL_SS_PORT_MAP);
32132d102148SJC Kuo 
32142d102148SJC Kuo 	list_for_each_entry(lane, &padctl->lanes, list) {
32152d102148SJC Kuo 		if (lane->pad->ops->iddq_enable)
32162d102148SJC Kuo 			tegra210_uphy_lane_iddq_enable(lane);
32172d102148SJC Kuo 	}
32182d102148SJC Kuo 
32192d102148SJC Kuo 	padctl_writel(padctl, priv->context.usb3_pad_mux,
32202d102148SJC Kuo 		XUSB_PADCTL_USB3_PAD_MUX);
32212d102148SJC Kuo 
32222d102148SJC Kuo 	list_for_each_entry(lane, &padctl->lanes, list) {
32232d102148SJC Kuo 		if (lane->pad->ops->iddq_disable)
32242d102148SJC Kuo 			tegra210_uphy_lane_iddq_disable(lane);
32252d102148SJC Kuo 	}
32262d102148SJC Kuo }
32272d102148SJC Kuo 
32282d102148SJC Kuo static int tegra210_xusb_padctl_suspend_noirq(struct tegra_xusb_padctl *padctl)
32292d102148SJC Kuo {
32302d102148SJC Kuo 	mutex_lock(&padctl->lock);
32312d102148SJC Kuo 
32322d102148SJC Kuo 	tegra210_uphy_deinit(padctl);
32332d102148SJC Kuo 
32342d102148SJC Kuo 	tegra210_xusb_padctl_save(padctl);
32352d102148SJC Kuo 
32362d102148SJC Kuo 	mutex_unlock(&padctl->lock);
32372d102148SJC Kuo 	return 0;
32382d102148SJC Kuo }
32392d102148SJC Kuo 
32402d102148SJC Kuo static int tegra210_xusb_padctl_resume_noirq(struct tegra_xusb_padctl *padctl)
32412d102148SJC Kuo {
32422d102148SJC Kuo 	mutex_lock(&padctl->lock);
32432d102148SJC Kuo 
32442d102148SJC Kuo 	tegra210_xusb_padctl_restore(padctl);
32452d102148SJC Kuo 
32462d102148SJC Kuo 	tegra210_uphy_init(padctl);
32472d102148SJC Kuo 
32482d102148SJC Kuo 	mutex_unlock(&padctl->lock);
32492d102148SJC Kuo 	return 0;
32502d102148SJC Kuo }
32512d102148SJC Kuo 
325287d66f28SThierry Reding static const struct tegra_xusb_padctl_ops tegra210_xusb_padctl_ops = {
325387d66f28SThierry Reding 	.probe = tegra210_xusb_padctl_probe,
325487d66f28SThierry Reding 	.remove = tegra210_xusb_padctl_remove,
32552d102148SJC Kuo 	.suspend_noirq = tegra210_xusb_padctl_suspend_noirq,
32562d102148SJC Kuo 	.resume_noirq = tegra210_xusb_padctl_resume_noirq,
325787d66f28SThierry Reding 	.usb3_set_lfps_detect = tegra210_usb3_set_lfps_detect,
325887d66f28SThierry Reding 	.hsic_set_idle = tegra210_hsic_set_idle,
325990767cdfSNagarjuna Kristam 	.vbus_override = tegra210_xusb_padctl_vbus_override,
326090767cdfSNagarjuna Kristam 	.utmi_port_reset = tegra210_utmi_port_reset,
326187d66f28SThierry Reding };
326287d66f28SThierry Reding 
3263e3888cdaSThierry Reding static const char * const tegra210_xusb_padctl_supply_names[] = {
3264e3888cdaSThierry Reding 	"avdd-pll-utmip",
3265e3888cdaSThierry Reding 	"avdd-pll-uerefe",
3266e3888cdaSThierry Reding 	"dvdd-pex-pll",
3267e3888cdaSThierry Reding 	"hvdd-pex-pll-e",
3268e3888cdaSThierry Reding };
3269e3888cdaSThierry Reding 
327087d66f28SThierry Reding const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc = {
327187d66f28SThierry Reding 	.num_pads = ARRAY_SIZE(tegra210_pads),
327287d66f28SThierry Reding 	.pads = tegra210_pads,
327387d66f28SThierry Reding 	.ports = {
327487d66f28SThierry Reding 		.usb2 = {
327587d66f28SThierry Reding 			.ops = &tegra210_usb2_port_ops,
327687d66f28SThierry Reding 			.count = 4,
327787d66f28SThierry Reding 		},
327887d66f28SThierry Reding 		.hsic = {
327987d66f28SThierry Reding 			.ops = &tegra210_hsic_port_ops,
328087d66f28SThierry Reding 			.count = 1,
328187d66f28SThierry Reding 		},
328287d66f28SThierry Reding 		.usb3 = {
328387d66f28SThierry Reding 			.ops = &tegra210_usb3_port_ops,
328487d66f28SThierry Reding 			.count = 4,
328587d66f28SThierry Reding 		},
328687d66f28SThierry Reding 	},
328787d66f28SThierry Reding 	.ops = &tegra210_xusb_padctl_ops,
3288e3888cdaSThierry Reding 	.supply_names = tegra210_xusb_padctl_supply_names,
3289e3888cdaSThierry Reding 	.num_supplies = ARRAY_SIZE(tegra210_xusb_padctl_supply_names),
3290a5be28c3SNagarjuna Kristam 	.need_fake_usb3_port = true,
329187d66f28SThierry Reding };
329287d66f28SThierry Reding EXPORT_SYMBOL_GPL(tegra210_xusb_padctl_soc);
329387d66f28SThierry Reding 
329487d66f28SThierry Reding MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>");
329587d66f28SThierry Reding MODULE_DESCRIPTION("NVIDIA Tegra 210 XUSB Pad Controller driver");
329687d66f28SThierry Reding MODULE_LICENSE("GPL v2");
3297