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>
14*2d102148SJC Kuo #include <linux/of_platform.h>
1587d66f28SThierry Reding #include <linux/phy/phy.h>
1687d66f28SThierry Reding #include <linux/platform_device.h>
17*2d102148SJC 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 
57*2d102148SJC Kuo #define XUSB_PADCTL_ELPG_PROGRAM_0 0x20
58*2d102148SJC Kuo #define   USB2_PORT_WAKE_INTERRUPT_ENABLE(x)      BIT((x))
59*2d102148SJC Kuo #define   USB2_PORT_WAKEUP_EVENT(x)               BIT((x) + 7)
60*2d102148SJC Kuo #define   SS_PORT_WAKE_INTERRUPT_ENABLE(x)        BIT((x) + 14)
61*2d102148SJC Kuo #define   SS_PORT_WAKEUP_EVENT(x)                 BIT((x) + 21)
62*2d102148SJC Kuo #define   USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 28)
63*2d102148SJC Kuo #define   USB2_HSIC_PORT_WAKEUP_EVENT(x)          BIT((x) + 30)
64*2d102148SJC Kuo #define   ALL_WAKE_EVENTS ( \
65*2d102148SJC Kuo 		USB2_PORT_WAKEUP_EVENT(0) | USB2_PORT_WAKEUP_EVENT(1) | \
66*2d102148SJC Kuo 		USB2_PORT_WAKEUP_EVENT(2) | USB2_PORT_WAKEUP_EVENT(3) | \
67*2d102148SJC Kuo 		SS_PORT_WAKEUP_EVENT(0) | SS_PORT_WAKEUP_EVENT(1) | \
68*2d102148SJC Kuo 		SS_PORT_WAKEUP_EVENT(2) | SS_PORT_WAKEUP_EVENT(3) | \
69*2d102148SJC Kuo 		USB2_HSIC_PORT_WAKEUP_EVENT(0))
70*2d102148SJC 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)
109*2d102148SJC Kuo #define   RPD_CTRL(x)                      (((x) & 0x1f) << 26)
110*2d102148SJC 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
129*2d102148SJC Kuo #define   TCTRL_VALUE(x)                (((x) & 0x3f) >> 0)
130*2d102148SJC 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 
274*2d102148SJC Kuo /* USB2 SLEEPWALK registers */
275*2d102148SJC Kuo #define UTMIP(_port, _offset1, _offset2) \
276*2d102148SJC Kuo 		(((_port) <= 2) ? (_offset1) : (_offset2))
277*2d102148SJC Kuo 
278*2d102148SJC Kuo #define PMC_UTMIP_UHSIC_SLEEP_CFG(x)	UTMIP(x, 0x1fc, 0x4d0)
279*2d102148SJC Kuo #define   UTMIP_MASTER_ENABLE(x)		UTMIP(x, BIT(8 * (x)), BIT(0))
280*2d102148SJC Kuo #define   UTMIP_FSLS_USE_PMC(x)			UTMIP(x, BIT(8 * (x) + 1), \
281*2d102148SJC Kuo 							BIT(1))
282*2d102148SJC Kuo #define   UTMIP_PCTRL_USE_PMC(x)		UTMIP(x, BIT(8 * (x) + 2), \
283*2d102148SJC Kuo 							BIT(2))
284*2d102148SJC Kuo #define   UTMIP_TCTRL_USE_PMC(x)		UTMIP(x, BIT(8 * (x) + 3), \
285*2d102148SJC Kuo 							BIT(3))
286*2d102148SJC Kuo #define   UTMIP_WAKE_VAL(_port, _value)		(((_value) & 0xf) << \
287*2d102148SJC Kuo 					(UTMIP(_port, 8 * (_port) + 4, 4)))
288*2d102148SJC Kuo #define   UTMIP_WAKE_VAL_NONE(_port)		UTMIP_WAKE_VAL(_port, 12)
289*2d102148SJC Kuo #define   UTMIP_WAKE_VAL_ANY(_port)		UTMIP_WAKE_VAL(_port, 15)
290*2d102148SJC Kuo 
291*2d102148SJC Kuo #define PMC_UTMIP_UHSIC_SLEEP_CFG1	(0x4d0)
292*2d102148SJC Kuo #define   UTMIP_RPU_SWITC_LOW_USE_PMC_PX(x)	BIT((x) + 8)
293*2d102148SJC Kuo #define   UTMIP_RPD_CTRL_USE_PMC_PX(x)		BIT((x) + 16)
294*2d102148SJC Kuo 
295*2d102148SJC Kuo #define PMC_UTMIP_MASTER_CONFIG		(0x274)
296*2d102148SJC Kuo #define   UTMIP_PWR(x)				UTMIP(x, BIT(x), BIT(4))
297*2d102148SJC Kuo #define   UHSIC_PWR				BIT(3)
298*2d102148SJC Kuo 
299*2d102148SJC Kuo #define PMC_USB_DEBOUNCE_DEL		(0xec)
300*2d102148SJC Kuo #define   DEBOUNCE_VAL(x)			(((x) & 0xffff) << 0)
301*2d102148SJC Kuo #define   UTMIP_LINE_DEB_CNT(x)			(((x) & 0xf) << 16)
302*2d102148SJC Kuo #define   UHSIC_LINE_DEB_CNT(x)			(((x) & 0xf) << 20)
303*2d102148SJC Kuo 
304*2d102148SJC Kuo #define PMC_UTMIP_UHSIC_FAKE(x)		UTMIP(x, 0x218, 0x294)
305*2d102148SJC Kuo #define   UTMIP_FAKE_USBOP_VAL(x)		UTMIP(x, BIT(4 * (x)), BIT(8))
306*2d102148SJC Kuo #define   UTMIP_FAKE_USBON_VAL(x)		UTMIP(x, BIT(4 * (x) + 1), \
307*2d102148SJC Kuo 							BIT(9))
308*2d102148SJC Kuo #define   UTMIP_FAKE_USBOP_EN(x)		UTMIP(x, BIT(4 * (x) + 2), \
309*2d102148SJC Kuo 							BIT(10))
310*2d102148SJC Kuo #define   UTMIP_FAKE_USBON_EN(x)		UTMIP(x, BIT(4 * (x) + 3), \
311*2d102148SJC Kuo 							BIT(11))
312*2d102148SJC Kuo 
313*2d102148SJC Kuo #define PMC_UTMIP_UHSIC_SLEEPWALK_CFG(x)	UTMIP(x, 0x200, 0x288)
314*2d102148SJC Kuo #define   UTMIP_LINEVAL_WALK_EN(x)		UTMIP(x, BIT(8 * (x) + 7), \
315*2d102148SJC Kuo 							BIT(15))
316*2d102148SJC Kuo 
317*2d102148SJC Kuo #define PMC_USB_AO			(0xf0)
318*2d102148SJC Kuo #define   USBOP_VAL_PD(x)			UTMIP(x, BIT(4 * (x)), BIT(20))
319*2d102148SJC Kuo #define   USBON_VAL_PD(x)			UTMIP(x, BIT(4 * (x) + 1), \
320*2d102148SJC Kuo 							BIT(21))
321*2d102148SJC Kuo #define   STROBE_VAL_PD				BIT(12)
322*2d102148SJC Kuo #define   DATA0_VAL_PD				BIT(13)
323*2d102148SJC Kuo #define   DATA1_VAL_PD				BIT(24)
324*2d102148SJC Kuo 
325*2d102148SJC Kuo #define PMC_UTMIP_UHSIC_SAVED_STATE(x)	UTMIP(x, 0x1f0, 0x280)
326*2d102148SJC Kuo #define   SPEED(_port, _value)			(((_value) & 0x3) << \
327*2d102148SJC Kuo 						(UTMIP(_port, 8 * (_port), 8)))
328*2d102148SJC Kuo #define   UTMI_HS(_port)			SPEED(_port, 0)
329*2d102148SJC Kuo #define   UTMI_FS(_port)			SPEED(_port, 1)
330*2d102148SJC Kuo #define   UTMI_LS(_port)			SPEED(_port, 2)
331*2d102148SJC Kuo #define   UTMI_RST(_port)			SPEED(_port, 3)
332*2d102148SJC Kuo 
333*2d102148SJC Kuo #define PMC_UTMIP_UHSIC_TRIGGERS		(0x1ec)
334*2d102148SJC Kuo #define   UTMIP_CLR_WALK_PTR(x)			UTMIP(x, BIT(x), BIT(16))
335*2d102148SJC Kuo #define   UTMIP_CAP_CFG(x)			UTMIP(x, BIT((x) + 4), BIT(17))
336*2d102148SJC Kuo #define   UTMIP_CLR_WAKE_ALARM(x)		UTMIP(x, BIT((x) + 12), \
337*2d102148SJC Kuo 							BIT(19))
338*2d102148SJC Kuo #define   UHSIC_CLR_WALK_PTR			BIT(3)
339*2d102148SJC Kuo #define   UHSIC_CLR_WAKE_ALARM			BIT(15)
340*2d102148SJC Kuo 
341*2d102148SJC Kuo #define PMC_UTMIP_SLEEPWALK_PX(x)	UTMIP(x, 0x204 + (4 * (x)), \
342*2d102148SJC Kuo 							0x4e0)
343*2d102148SJC Kuo /* phase A */
344*2d102148SJC Kuo #define   UTMIP_USBOP_RPD_A			BIT(0)
345*2d102148SJC Kuo #define   UTMIP_USBON_RPD_A			BIT(1)
346*2d102148SJC Kuo #define   UTMIP_AP_A				BIT(4)
347*2d102148SJC Kuo #define   UTMIP_AN_A				BIT(5)
348*2d102148SJC Kuo #define   UTMIP_HIGHZ_A				BIT(6)
349*2d102148SJC Kuo /* phase B */
350*2d102148SJC Kuo #define   UTMIP_USBOP_RPD_B			BIT(8)
351*2d102148SJC Kuo #define   UTMIP_USBON_RPD_B			BIT(9)
352*2d102148SJC Kuo #define   UTMIP_AP_B				BIT(12)
353*2d102148SJC Kuo #define   UTMIP_AN_B				BIT(13)
354*2d102148SJC Kuo #define   UTMIP_HIGHZ_B				BIT(14)
355*2d102148SJC Kuo /* phase C */
356*2d102148SJC Kuo #define   UTMIP_USBOP_RPD_C			BIT(16)
357*2d102148SJC Kuo #define   UTMIP_USBON_RPD_C			BIT(17)
358*2d102148SJC Kuo #define   UTMIP_AP_C				BIT(20)
359*2d102148SJC Kuo #define   UTMIP_AN_C				BIT(21)
360*2d102148SJC Kuo #define   UTMIP_HIGHZ_C				BIT(22)
361*2d102148SJC Kuo /* phase D */
362*2d102148SJC Kuo #define   UTMIP_USBOP_RPD_D			BIT(24)
363*2d102148SJC Kuo #define   UTMIP_USBON_RPD_D			BIT(25)
364*2d102148SJC Kuo #define   UTMIP_AP_D				BIT(28)
365*2d102148SJC Kuo #define   UTMIP_AN_D				BIT(29)
366*2d102148SJC Kuo #define   UTMIP_HIGHZ_D				BIT(30)
367*2d102148SJC Kuo 
368*2d102148SJC Kuo #define PMC_UTMIP_UHSIC_LINE_WAKEUP	(0x26c)
369*2d102148SJC Kuo #define   UTMIP_LINE_WAKEUP_EN(x)		UTMIP(x, BIT(x), BIT(4))
370*2d102148SJC Kuo #define   UHSIC_LINE_WAKEUP_EN			BIT(3)
371*2d102148SJC Kuo 
372*2d102148SJC Kuo #define PMC_UTMIP_TERM_PAD_CFG		(0x1f8)
373*2d102148SJC Kuo #define   PCTRL_VAL(x)				(((x) & 0x3f) << 1)
374*2d102148SJC Kuo #define   TCTRL_VAL(x)				(((x) & 0x3f) << 7)
375*2d102148SJC Kuo 
376*2d102148SJC Kuo #define PMC_UTMIP_PAD_CFGX(x)		(0x4c0 + (4 * (x)))
377*2d102148SJC Kuo #define   RPD_CTRL_PX(x)			(((x) & 0x1f) << 22)
378*2d102148SJC Kuo 
379*2d102148SJC Kuo #define PMC_UHSIC_SLEEP_CFG	PMC_UTMIP_UHSIC_SLEEP_CFG(0)
380*2d102148SJC Kuo #define   UHSIC_MASTER_ENABLE			BIT(24)
381*2d102148SJC Kuo #define   UHSIC_WAKE_VAL(_value)		(((_value) & 0xf) << 28)
382*2d102148SJC Kuo #define   UHSIC_WAKE_VAL_SD10			UHSIC_WAKE_VAL(2)
383*2d102148SJC Kuo #define   UHSIC_WAKE_VAL_NONE			UHSIC_WAKE_VAL(12)
384*2d102148SJC Kuo 
385*2d102148SJC Kuo #define PMC_UHSIC_FAKE			PMC_UTMIP_UHSIC_FAKE(0)
386*2d102148SJC Kuo #define   UHSIC_FAKE_STROBE_VAL			BIT(12)
387*2d102148SJC Kuo #define   UHSIC_FAKE_DATA_VAL			BIT(13)
388*2d102148SJC Kuo #define   UHSIC_FAKE_STROBE_EN			BIT(14)
389*2d102148SJC Kuo #define   UHSIC_FAKE_DATA_EN			BIT(15)
390*2d102148SJC Kuo 
391*2d102148SJC Kuo #define PMC_UHSIC_SAVED_STATE		PMC_UTMIP_UHSIC_SAVED_STATE(0)
392*2d102148SJC Kuo #define   UHSIC_MODE(_value)			(((_value) & 0x1) << 24)
393*2d102148SJC Kuo #define   UHSIC_HS				UHSIC_MODE(0)
394*2d102148SJC Kuo #define   UHSIC_RST				UHSIC_MODE(1)
395*2d102148SJC Kuo 
396*2d102148SJC Kuo #define PMC_UHSIC_SLEEPWALK_CFG		PMC_UTMIP_UHSIC_SLEEPWALK_CFG(0)
397*2d102148SJC Kuo #define   UHSIC_WAKE_WALK_EN			BIT(30)
398*2d102148SJC Kuo #define   UHSIC_LINEVAL_WALK_EN			BIT(31)
399*2d102148SJC Kuo 
400*2d102148SJC Kuo #define PMC_UHSIC_SLEEPWALK_P0		(0x210)
401*2d102148SJC Kuo #define   UHSIC_DATA0_RPD_A			BIT(1)
402*2d102148SJC Kuo #define   UHSIC_DATA0_RPU_B			BIT(11)
403*2d102148SJC Kuo #define   UHSIC_DATA0_RPU_C			BIT(19)
404*2d102148SJC Kuo #define   UHSIC_DATA0_RPU_D			BIT(27)
405*2d102148SJC Kuo #define   UHSIC_STROBE_RPU_A			BIT(2)
406*2d102148SJC Kuo #define   UHSIC_STROBE_RPD_B			BIT(8)
407*2d102148SJC Kuo #define   UHSIC_STROBE_RPD_C			BIT(16)
408*2d102148SJC Kuo #define   UHSIC_STROBE_RPD_D			BIT(24)
409*2d102148SJC 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 
416*2d102148SJC Kuo struct tegra210_xusb_padctl_context {
417*2d102148SJC Kuo 	u32 usb2_pad_mux;
418*2d102148SJC Kuo 	u32 usb2_port_cap;
419*2d102148SJC Kuo 	u32 ss_port_map;
420*2d102148SJC Kuo 	u32 usb3_pad_mux;
421*2d102148SJC Kuo };
422*2d102148SJC Kuo 
42387d66f28SThierry Reding struct tegra210_xusb_padctl {
42487d66f28SThierry Reding 	struct tegra_xusb_padctl base;
425*2d102148SJC Kuo 	struct regmap *regmap;
42687d66f28SThierry Reding 
42787d66f28SThierry Reding 	struct tegra210_xusb_fuse_calibration fuse;
428*2d102148SJC 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 
1058*2d102148SJC Kuo static int tegra210_usb3_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
1059*2d102148SJC Kuo 					      enum usb_device_speed speed)
1060*2d102148SJC Kuo {
1061*2d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1062*2d102148SJC Kuo 	int port = tegra210_usb3_lane_map(lane);
1063*2d102148SJC Kuo 	struct device *dev = padctl->dev;
1064*2d102148SJC Kuo 	u32 value;
1065*2d102148SJC Kuo 
1066*2d102148SJC Kuo 	if (port < 0) {
1067*2d102148SJC Kuo 		dev_err(dev, "invalid usb3 port number\n");
1068*2d102148SJC Kuo 		return -EINVAL;
1069*2d102148SJC Kuo 	}
1070*2d102148SJC Kuo 
1071*2d102148SJC Kuo 	mutex_lock(&padctl->lock);
1072*2d102148SJC Kuo 
1073*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
1074*2d102148SJC Kuo 	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port);
1075*2d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
1076*2d102148SJC Kuo 
1077*2d102148SJC Kuo 	usleep_range(100, 200);
1078*2d102148SJC Kuo 
1079*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
1080*2d102148SJC Kuo 	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port);
1081*2d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
1082*2d102148SJC Kuo 
1083*2d102148SJC Kuo 	usleep_range(250, 350);
1084*2d102148SJC Kuo 
1085*2d102148SJC Kuo 	mutex_unlock(&padctl->lock);
1086*2d102148SJC Kuo 
1087*2d102148SJC Kuo 	return 0;
1088*2d102148SJC Kuo }
1089*2d102148SJC Kuo 
1090*2d102148SJC Kuo static int tegra210_usb3_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
1091*2d102148SJC Kuo {
1092*2d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1093*2d102148SJC Kuo 	int port = tegra210_usb3_lane_map(lane);
1094*2d102148SJC Kuo 	struct device *dev = padctl->dev;
1095*2d102148SJC Kuo 	u32 value;
1096*2d102148SJC Kuo 
1097*2d102148SJC Kuo 	if (port < 0) {
1098*2d102148SJC Kuo 		dev_err(dev, "invalid usb3 port number\n");
1099*2d102148SJC Kuo 		return -EINVAL;
1100*2d102148SJC Kuo 	}
1101*2d102148SJC Kuo 
1102*2d102148SJC Kuo 	mutex_lock(&padctl->lock);
1103*2d102148SJC Kuo 
1104*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
1105*2d102148SJC Kuo 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port);
1106*2d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
1107*2d102148SJC Kuo 
1108*2d102148SJC Kuo 	usleep_range(100, 200);
1109*2d102148SJC Kuo 
1110*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
1111*2d102148SJC Kuo 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port);
1112*2d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
1113*2d102148SJC Kuo 
1114*2d102148SJC Kuo 	mutex_unlock(&padctl->lock);
1115*2d102148SJC Kuo 
1116*2d102148SJC Kuo 	return 0;
1117*2d102148SJC Kuo }
1118*2d102148SJC Kuo 
1119*2d102148SJC Kuo static int tegra210_usb3_enable_phy_wake(struct tegra_xusb_lane *lane)
1120*2d102148SJC Kuo {
1121*2d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1122*2d102148SJC Kuo 	int port = tegra210_usb3_lane_map(lane);
1123*2d102148SJC Kuo 	struct device *dev = padctl->dev;
1124*2d102148SJC Kuo 	u32 value;
1125*2d102148SJC Kuo 
1126*2d102148SJC Kuo 	if (port < 0) {
1127*2d102148SJC Kuo 		dev_err(dev, "invalid usb3 port number\n");
1128*2d102148SJC Kuo 		return -EINVAL;
1129*2d102148SJC Kuo 	}
1130*2d102148SJC Kuo 
1131*2d102148SJC Kuo 	mutex_lock(&padctl->lock);
1132*2d102148SJC Kuo 
1133*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
1134*2d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
1135*2d102148SJC Kuo 	value |= SS_PORT_WAKEUP_EVENT(port);
1136*2d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
1137*2d102148SJC Kuo 
1138*2d102148SJC Kuo 	usleep_range(10, 20);
1139*2d102148SJC Kuo 
1140*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
1141*2d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
1142*2d102148SJC Kuo 	value |= SS_PORT_WAKE_INTERRUPT_ENABLE(port);
1143*2d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
1144*2d102148SJC Kuo 
1145*2d102148SJC Kuo 	mutex_unlock(&padctl->lock);
1146*2d102148SJC Kuo 
1147*2d102148SJC Kuo 	return 0;
1148*2d102148SJC Kuo }
1149*2d102148SJC Kuo 
1150*2d102148SJC Kuo static int tegra210_usb3_disable_phy_wake(struct tegra_xusb_lane *lane)
1151*2d102148SJC Kuo {
1152*2d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1153*2d102148SJC Kuo 	int port = tegra210_usb3_lane_map(lane);
1154*2d102148SJC Kuo 	struct device *dev = padctl->dev;
1155*2d102148SJC Kuo 	u32 value;
1156*2d102148SJC Kuo 
1157*2d102148SJC Kuo 	if (port < 0) {
1158*2d102148SJC Kuo 		dev_err(dev, "invalid usb3 port number\n");
1159*2d102148SJC Kuo 		return -EINVAL;
1160*2d102148SJC Kuo 	}
1161*2d102148SJC Kuo 
1162*2d102148SJC Kuo 	mutex_lock(&padctl->lock);
1163*2d102148SJC Kuo 
1164*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
1165*2d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
1166*2d102148SJC Kuo 	value &= ~SS_PORT_WAKE_INTERRUPT_ENABLE(port);
1167*2d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
1168*2d102148SJC Kuo 
1169*2d102148SJC Kuo 	usleep_range(10, 20);
1170*2d102148SJC Kuo 
1171*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
1172*2d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
1173*2d102148SJC Kuo 	value |= SS_PORT_WAKEUP_EVENT(port);
1174*2d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
1175*2d102148SJC Kuo 
1176*2d102148SJC Kuo 	mutex_unlock(&padctl->lock);
1177*2d102148SJC Kuo 
1178*2d102148SJC Kuo 	return 0;
1179*2d102148SJC Kuo }
1180*2d102148SJC Kuo 
1181*2d102148SJC Kuo static bool tegra210_usb3_phy_remote_wake_detected(struct tegra_xusb_lane *lane)
1182*2d102148SJC Kuo {
1183*2d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1184*2d102148SJC Kuo 	int index = tegra210_usb3_lane_map(lane);
1185*2d102148SJC Kuo 	u32 value;
1186*2d102148SJC Kuo 
1187*2d102148SJC Kuo 	if (index < 0)
1188*2d102148SJC Kuo 		return false;
1189*2d102148SJC Kuo 
1190*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
1191*2d102148SJC Kuo 	if ((value & SS_PORT_WAKE_INTERRUPT_ENABLE(index)) && (value & SS_PORT_WAKEUP_EVENT(index)))
1192*2d102148SJC Kuo 		return true;
1193*2d102148SJC Kuo 
1194*2d102148SJC Kuo 	return false;
1195*2d102148SJC Kuo }
1196*2d102148SJC Kuo 
1197*2d102148SJC Kuo static int tegra210_utmi_enable_phy_wake(struct tegra_xusb_lane *lane)
1198*2d102148SJC Kuo {
1199*2d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1200*2d102148SJC Kuo 	unsigned int index = lane->index;
1201*2d102148SJC Kuo 	u32 value;
1202*2d102148SJC Kuo 
1203*2d102148SJC Kuo 	mutex_lock(&padctl->lock);
1204*2d102148SJC Kuo 
1205*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
1206*2d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
1207*2d102148SJC Kuo 	value |= USB2_PORT_WAKEUP_EVENT(index);
1208*2d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
1209*2d102148SJC Kuo 
1210*2d102148SJC Kuo 	usleep_range(10, 20);
1211*2d102148SJC Kuo 
1212*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
1213*2d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
1214*2d102148SJC Kuo 	value |= USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
1215*2d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
1216*2d102148SJC Kuo 
1217*2d102148SJC Kuo 	mutex_unlock(&padctl->lock);
1218*2d102148SJC Kuo 
1219*2d102148SJC Kuo 	return 0;
1220*2d102148SJC Kuo }
1221*2d102148SJC Kuo 
1222*2d102148SJC Kuo static int tegra210_utmi_disable_phy_wake(struct tegra_xusb_lane *lane)
1223*2d102148SJC Kuo {
1224*2d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1225*2d102148SJC Kuo 	unsigned int index = lane->index;
1226*2d102148SJC Kuo 	u32 value;
1227*2d102148SJC Kuo 
1228*2d102148SJC Kuo 	mutex_lock(&padctl->lock);
1229*2d102148SJC Kuo 
1230*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
1231*2d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
1232*2d102148SJC Kuo 	value &= ~USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
1233*2d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
1234*2d102148SJC Kuo 
1235*2d102148SJC Kuo 	usleep_range(10, 20);
1236*2d102148SJC Kuo 
1237*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
1238*2d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
1239*2d102148SJC Kuo 	value |= USB2_PORT_WAKEUP_EVENT(index);
1240*2d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
1241*2d102148SJC Kuo 
1242*2d102148SJC Kuo 	mutex_unlock(&padctl->lock);
1243*2d102148SJC Kuo 
1244*2d102148SJC Kuo 	return 0;
1245*2d102148SJC Kuo }
1246*2d102148SJC Kuo 
1247*2d102148SJC Kuo static bool tegra210_utmi_phy_remote_wake_detected(struct tegra_xusb_lane *lane)
1248*2d102148SJC Kuo {
1249*2d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1250*2d102148SJC Kuo 	unsigned int index = lane->index;
1251*2d102148SJC Kuo 	u32 value;
1252*2d102148SJC Kuo 
1253*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
1254*2d102148SJC Kuo 	if ((value & USB2_PORT_WAKE_INTERRUPT_ENABLE(index)) &&
1255*2d102148SJC Kuo 	    (value & USB2_PORT_WAKEUP_EVENT(index)))
1256*2d102148SJC Kuo 		return true;
1257*2d102148SJC Kuo 
1258*2d102148SJC Kuo 	return false;
1259*2d102148SJC Kuo }
1260*2d102148SJC Kuo 
1261*2d102148SJC Kuo static int tegra210_hsic_enable_phy_wake(struct tegra_xusb_lane *lane)
1262*2d102148SJC Kuo {
1263*2d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1264*2d102148SJC Kuo 	unsigned int index = lane->index;
1265*2d102148SJC Kuo 	u32 value;
1266*2d102148SJC Kuo 
1267*2d102148SJC Kuo 	mutex_lock(&padctl->lock);
1268*2d102148SJC Kuo 
1269*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
1270*2d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
1271*2d102148SJC Kuo 	value |= USB2_HSIC_PORT_WAKEUP_EVENT(index);
1272*2d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
1273*2d102148SJC Kuo 
1274*2d102148SJC Kuo 	usleep_range(10, 20);
1275*2d102148SJC Kuo 
1276*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
1277*2d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
1278*2d102148SJC Kuo 	value |= USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index);
1279*2d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
1280*2d102148SJC Kuo 
1281*2d102148SJC Kuo 	mutex_unlock(&padctl->lock);
1282*2d102148SJC Kuo 
1283*2d102148SJC Kuo 	return 0;
1284*2d102148SJC Kuo }
1285*2d102148SJC Kuo 
1286*2d102148SJC Kuo static int tegra210_hsic_disable_phy_wake(struct tegra_xusb_lane *lane)
1287*2d102148SJC Kuo {
1288*2d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1289*2d102148SJC Kuo 	unsigned int index = lane->index;
1290*2d102148SJC Kuo 	u32 value;
1291*2d102148SJC Kuo 
1292*2d102148SJC Kuo 	mutex_lock(&padctl->lock);
1293*2d102148SJC Kuo 
1294*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
1295*2d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
1296*2d102148SJC Kuo 	value &= ~USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index);
1297*2d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
1298*2d102148SJC Kuo 
1299*2d102148SJC Kuo 	usleep_range(10, 20);
1300*2d102148SJC Kuo 
1301*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
1302*2d102148SJC Kuo 	value &= ~ALL_WAKE_EVENTS;
1303*2d102148SJC Kuo 	value |= USB2_HSIC_PORT_WAKEUP_EVENT(index);
1304*2d102148SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
1305*2d102148SJC Kuo 
1306*2d102148SJC Kuo 	mutex_unlock(&padctl->lock);
1307*2d102148SJC Kuo 
1308*2d102148SJC Kuo 	return 0;
1309*2d102148SJC Kuo }
1310*2d102148SJC Kuo 
1311*2d102148SJC Kuo static bool tegra210_hsic_phy_remote_wake_detected(struct tegra_xusb_lane *lane)
1312*2d102148SJC Kuo {
1313*2d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1314*2d102148SJC Kuo 	unsigned int index = lane->index;
1315*2d102148SJC Kuo 	u32 value;
1316*2d102148SJC Kuo 
1317*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
1318*2d102148SJC Kuo 	if ((value & USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index)) &&
1319*2d102148SJC Kuo 	    (value & USB2_HSIC_PORT_WAKEUP_EVENT(index)))
1320*2d102148SJC Kuo 		return true;
1321*2d102148SJC Kuo 
1322*2d102148SJC Kuo 	return false;
1323*2d102148SJC Kuo }
1324*2d102148SJC Kuo 
1325*2d102148SJC Kuo #define padctl_pmc_readl(_priv, _offset)						\
1326*2d102148SJC Kuo ({											\
1327*2d102148SJC Kuo 	u32 value;									\
1328*2d102148SJC Kuo 	WARN(regmap_read(_priv->regmap, _offset, &value), "read %s failed\n", #_offset);\
1329*2d102148SJC Kuo 	value;										\
1330*2d102148SJC Kuo })
1331*2d102148SJC Kuo 
1332*2d102148SJC Kuo #define padctl_pmc_writel(_priv, _value, _offset)					\
1333*2d102148SJC Kuo 	WARN(regmap_write(_priv->regmap, _offset, _value), "write %s failed\n", #_offset)
1334*2d102148SJC Kuo 
1335*2d102148SJC Kuo static int tegra210_pmc_utmi_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
1336*2d102148SJC Kuo 						  enum usb_device_speed speed)
1337*2d102148SJC Kuo {
1338*2d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1339*2d102148SJC Kuo 	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
1340*2d102148SJC Kuo 	unsigned int port = lane->index;
1341*2d102148SJC Kuo 	u32 value, tctrl, pctrl, rpd_ctrl;
1342*2d102148SJC Kuo 
1343*2d102148SJC Kuo 	if (!priv->regmap)
1344*2d102148SJC Kuo 		return -EOPNOTSUPP;
1345*2d102148SJC Kuo 
1346*2d102148SJC Kuo 	if (speed > USB_SPEED_HIGH)
1347*2d102148SJC Kuo 		return -EINVAL;
1348*2d102148SJC Kuo 
1349*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
1350*2d102148SJC Kuo 	tctrl = TCTRL_VALUE(value);
1351*2d102148SJC Kuo 	pctrl = PCTRL_VALUE(value);
1352*2d102148SJC Kuo 
1353*2d102148SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port));
1354*2d102148SJC Kuo 	rpd_ctrl = RPD_CTRL_VALUE(value);
1355*2d102148SJC Kuo 
1356*2d102148SJC Kuo 	/* ensure sleepwalk logic is disabled */
1357*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
1358*2d102148SJC Kuo 	value &= ~UTMIP_MASTER_ENABLE(port);
1359*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
1360*2d102148SJC Kuo 
1361*2d102148SJC Kuo 	/* ensure sleepwalk logics are in low power mode */
1362*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG);
1363*2d102148SJC Kuo 	value |= UTMIP_PWR(port);
1364*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_MASTER_CONFIG);
1365*2d102148SJC Kuo 
1366*2d102148SJC Kuo 	/* set debounce time */
1367*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL);
1368*2d102148SJC Kuo 	value &= ~UTMIP_LINE_DEB_CNT(~0);
1369*2d102148SJC Kuo 	value |= UTMIP_LINE_DEB_CNT(0x1);
1370*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_USB_DEBOUNCE_DEL);
1371*2d102148SJC Kuo 
1372*2d102148SJC Kuo 	/* ensure fake events of sleepwalk logic are desiabled */
1373*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_FAKE(port));
1374*2d102148SJC Kuo 	value &= ~(UTMIP_FAKE_USBOP_VAL(port) | UTMIP_FAKE_USBON_VAL(port) |
1375*2d102148SJC Kuo 		   UTMIP_FAKE_USBOP_EN(port) | UTMIP_FAKE_USBON_EN(port));
1376*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_FAKE(port));
1377*2d102148SJC Kuo 
1378*2d102148SJC Kuo 	/* ensure wake events of sleepwalk logic are not latched */
1379*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
1380*2d102148SJC Kuo 	value &= ~UTMIP_LINE_WAKEUP_EN(port);
1381*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
1382*2d102148SJC Kuo 
1383*2d102148SJC Kuo 	/* disable wake event triggers of sleepwalk logic */
1384*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
1385*2d102148SJC Kuo 	value &= ~UTMIP_WAKE_VAL(port, ~0);
1386*2d102148SJC Kuo 	value |= UTMIP_WAKE_VAL_NONE(port);
1387*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
1388*2d102148SJC Kuo 
1389*2d102148SJC Kuo 	/* power down the line state detectors of the pad */
1390*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_USB_AO);
1391*2d102148SJC Kuo 	value |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port));
1392*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_USB_AO);
1393*2d102148SJC Kuo 
1394*2d102148SJC Kuo 	/* save state per speed */
1395*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SAVED_STATE(port));
1396*2d102148SJC Kuo 	value &= ~SPEED(port, ~0);
1397*2d102148SJC Kuo 
1398*2d102148SJC Kuo 	switch (speed) {
1399*2d102148SJC Kuo 	case USB_SPEED_HIGH:
1400*2d102148SJC Kuo 		value |= UTMI_HS(port);
1401*2d102148SJC Kuo 		break;
1402*2d102148SJC Kuo 
1403*2d102148SJC Kuo 	case USB_SPEED_FULL:
1404*2d102148SJC Kuo 		value |= UTMI_FS(port);
1405*2d102148SJC Kuo 		break;
1406*2d102148SJC Kuo 
1407*2d102148SJC Kuo 	case USB_SPEED_LOW:
1408*2d102148SJC Kuo 		value |= UTMI_LS(port);
1409*2d102148SJC Kuo 		break;
1410*2d102148SJC Kuo 
1411*2d102148SJC Kuo 	default:
1412*2d102148SJC Kuo 		value |= UTMI_RST(port);
1413*2d102148SJC Kuo 		break;
1414*2d102148SJC Kuo 	}
1415*2d102148SJC Kuo 
1416*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SAVED_STATE(port));
1417*2d102148SJC Kuo 
1418*2d102148SJC Kuo 	/* enable the trigger of the sleepwalk logic */
1419*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));
1420*2d102148SJC Kuo 	value |= UTMIP_LINEVAL_WALK_EN(port);
1421*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));
1422*2d102148SJC Kuo 
1423*2d102148SJC Kuo 	/*
1424*2d102148SJC Kuo 	 * Reset the walk pointer and clear the alarm of the sleepwalk logic,
1425*2d102148SJC Kuo 	 * as well as capture the configuration of the USB2.0 pad.
1426*2d102148SJC Kuo 	 */
1427*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
1428*2d102148SJC Kuo 	value |= UTMIP_CLR_WALK_PTR(port) | UTMIP_CLR_WAKE_ALARM(port) | UTMIP_CAP_CFG(port);
1429*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
1430*2d102148SJC Kuo 
1431*2d102148SJC Kuo 	/* program electrical parameters read from XUSB PADCTL */
1432*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_TERM_PAD_CFG);
1433*2d102148SJC Kuo 	value &= ~(TCTRL_VAL(~0) | PCTRL_VAL(~0));
1434*2d102148SJC Kuo 	value |= (TCTRL_VAL(tctrl) | PCTRL_VAL(pctrl));
1435*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_TERM_PAD_CFG);
1436*2d102148SJC Kuo 
1437*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_PAD_CFGX(port));
1438*2d102148SJC Kuo 	value &= ~RPD_CTRL_PX(~0);
1439*2d102148SJC Kuo 	value |= RPD_CTRL_PX(rpd_ctrl);
1440*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_PAD_CFGX(port));
1441*2d102148SJC Kuo 
1442*2d102148SJC Kuo 	/*
1443*2d102148SJC Kuo 	 * Set up the pull-ups and pull-downs of the signals during the four
1444*2d102148SJC Kuo 	 * stages of sleepwalk. If a device is connected, program sleepwalk
1445*2d102148SJC Kuo 	 * logic to maintain a J and keep driving K upon seeing remote wake.
1446*2d102148SJC Kuo 	 */
1447*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_SLEEPWALK_PX(port));
1448*2d102148SJC Kuo 	value = UTMIP_USBOP_RPD_A | UTMIP_USBOP_RPD_B | UTMIP_USBOP_RPD_C | UTMIP_USBOP_RPD_D;
1449*2d102148SJC Kuo 	value |= UTMIP_USBON_RPD_A | UTMIP_USBON_RPD_B | UTMIP_USBON_RPD_C | UTMIP_USBON_RPD_D;
1450*2d102148SJC Kuo 
1451*2d102148SJC Kuo 	switch (speed) {
1452*2d102148SJC Kuo 	case USB_SPEED_HIGH:
1453*2d102148SJC Kuo 	case USB_SPEED_FULL:
1454*2d102148SJC Kuo 		/* J state: D+/D- = high/low, K state: D+/D- = low/high */
1455*2d102148SJC Kuo 		value |= UTMIP_HIGHZ_A;
1456*2d102148SJC Kuo 		value |= UTMIP_AP_A;
1457*2d102148SJC Kuo 		value |= UTMIP_AN_B | UTMIP_AN_C | UTMIP_AN_D;
1458*2d102148SJC Kuo 		break;
1459*2d102148SJC Kuo 
1460*2d102148SJC Kuo 	case USB_SPEED_LOW:
1461*2d102148SJC Kuo 		/* J state: D+/D- = low/high, K state: D+/D- = high/low */
1462*2d102148SJC Kuo 		value |= UTMIP_HIGHZ_A;
1463*2d102148SJC Kuo 		value |= UTMIP_AN_A;
1464*2d102148SJC Kuo 		value |= UTMIP_AP_B | UTMIP_AP_C | UTMIP_AP_D;
1465*2d102148SJC Kuo 		break;
1466*2d102148SJC Kuo 
1467*2d102148SJC Kuo 	default:
1468*2d102148SJC Kuo 		value |= UTMIP_HIGHZ_A | UTMIP_HIGHZ_B | UTMIP_HIGHZ_C | UTMIP_HIGHZ_D;
1469*2d102148SJC Kuo 		break;
1470*2d102148SJC Kuo 	}
1471*2d102148SJC Kuo 
1472*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_SLEEPWALK_PX(port));
1473*2d102148SJC Kuo 
1474*2d102148SJC Kuo 	/* power up the line state detectors of the pad */
1475*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_USB_AO);
1476*2d102148SJC Kuo 	value &= ~(USBOP_VAL_PD(port) | USBON_VAL_PD(port));
1477*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_USB_AO);
1478*2d102148SJC Kuo 
1479*2d102148SJC Kuo 	usleep_range(50, 100);
1480*2d102148SJC Kuo 
1481*2d102148SJC Kuo 	/* switch the electric control of the USB2.0 pad to PMC */
1482*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
1483*2d102148SJC Kuo 	value |= UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) | UTMIP_TCTRL_USE_PMC(port);
1484*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
1485*2d102148SJC Kuo 
1486*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1);
1487*2d102148SJC Kuo 	value |= UTMIP_RPD_CTRL_USE_PMC_PX(port) | UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port);
1488*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG1);
1489*2d102148SJC Kuo 
1490*2d102148SJC Kuo 	/* set the wake signaling trigger events */
1491*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
1492*2d102148SJC Kuo 	value &= ~UTMIP_WAKE_VAL(port, ~0);
1493*2d102148SJC Kuo 	value |= UTMIP_WAKE_VAL_ANY(port);
1494*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
1495*2d102148SJC Kuo 
1496*2d102148SJC Kuo 	/* enable the wake detection */
1497*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
1498*2d102148SJC Kuo 	value |= UTMIP_MASTER_ENABLE(port);
1499*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
1500*2d102148SJC Kuo 
1501*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
1502*2d102148SJC Kuo 	value |= UTMIP_LINE_WAKEUP_EN(port);
1503*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
1504*2d102148SJC Kuo 
1505*2d102148SJC Kuo 	return 0;
1506*2d102148SJC Kuo }
1507*2d102148SJC Kuo 
1508*2d102148SJC Kuo static int tegra210_pmc_utmi_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
1509*2d102148SJC Kuo {
1510*2d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1511*2d102148SJC Kuo 	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
1512*2d102148SJC Kuo 	unsigned int port = lane->index;
1513*2d102148SJC Kuo 	u32 value;
1514*2d102148SJC Kuo 
1515*2d102148SJC Kuo 	if (!priv->regmap)
1516*2d102148SJC Kuo 		return -EOPNOTSUPP;
1517*2d102148SJC Kuo 
1518*2d102148SJC Kuo 	/* disable the wake detection */
1519*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
1520*2d102148SJC Kuo 	value &= ~UTMIP_MASTER_ENABLE(port);
1521*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
1522*2d102148SJC Kuo 
1523*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
1524*2d102148SJC Kuo 	value &= ~UTMIP_LINE_WAKEUP_EN(port);
1525*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
1526*2d102148SJC Kuo 
1527*2d102148SJC Kuo 	/* switch the electric control of the USB2.0 pad to XUSB or USB2 */
1528*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
1529*2d102148SJC Kuo 	value &= ~(UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) |
1530*2d102148SJC Kuo 		   UTMIP_TCTRL_USE_PMC(port));
1531*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
1532*2d102148SJC Kuo 
1533*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1);
1534*2d102148SJC Kuo 	value &= ~(UTMIP_RPD_CTRL_USE_PMC_PX(port) | UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port));
1535*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG1);
1536*2d102148SJC Kuo 
1537*2d102148SJC Kuo 	/* disable wake event triggers of sleepwalk logic */
1538*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
1539*2d102148SJC Kuo 	value &= ~UTMIP_WAKE_VAL(port, ~0);
1540*2d102148SJC Kuo 	value |= UTMIP_WAKE_VAL_NONE(port);
1541*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
1542*2d102148SJC Kuo 
1543*2d102148SJC Kuo 	/* power down the line state detectors of the port */
1544*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_USB_AO);
1545*2d102148SJC Kuo 	value |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port));
1546*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_USB_AO);
1547*2d102148SJC Kuo 
1548*2d102148SJC Kuo 	/* clear alarm of the sleepwalk logic */
1549*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
1550*2d102148SJC Kuo 	value |= UTMIP_CLR_WAKE_ALARM(port);
1551*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
1552*2d102148SJC Kuo 
1553*2d102148SJC Kuo 	return 0;
1554*2d102148SJC Kuo }
1555*2d102148SJC Kuo 
1556*2d102148SJC Kuo static int tegra210_pmc_hsic_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
1557*2d102148SJC Kuo 						  enum usb_device_speed speed)
1558*2d102148SJC Kuo {
1559*2d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1560*2d102148SJC Kuo 	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
1561*2d102148SJC Kuo 	u32 value;
1562*2d102148SJC Kuo 
1563*2d102148SJC Kuo 	if (!priv->regmap)
1564*2d102148SJC Kuo 		return -EOPNOTSUPP;
1565*2d102148SJC Kuo 
1566*2d102148SJC Kuo 	/* ensure sleepwalk logic is disabled */
1567*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
1568*2d102148SJC Kuo 	value &= ~UHSIC_MASTER_ENABLE;
1569*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
1570*2d102148SJC Kuo 
1571*2d102148SJC Kuo 	/* ensure sleepwalk logics are in low power mode */
1572*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG);
1573*2d102148SJC Kuo 	value |= UHSIC_PWR;
1574*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_MASTER_CONFIG);
1575*2d102148SJC Kuo 
1576*2d102148SJC Kuo 	/* set debounce time */
1577*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL);
1578*2d102148SJC Kuo 	value &= ~UHSIC_LINE_DEB_CNT(~0);
1579*2d102148SJC Kuo 	value |= UHSIC_LINE_DEB_CNT(0x1);
1580*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_USB_DEBOUNCE_DEL);
1581*2d102148SJC Kuo 
1582*2d102148SJC Kuo 	/* ensure fake events of sleepwalk logic are desiabled */
1583*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_FAKE);
1584*2d102148SJC Kuo 	value &= ~(UHSIC_FAKE_STROBE_VAL | UHSIC_FAKE_DATA_VAL |
1585*2d102148SJC Kuo 		   UHSIC_FAKE_STROBE_EN | UHSIC_FAKE_DATA_EN);
1586*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_FAKE);
1587*2d102148SJC Kuo 
1588*2d102148SJC Kuo 	/* ensure wake events of sleepwalk logic are not latched */
1589*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
1590*2d102148SJC Kuo 	value &= ~UHSIC_LINE_WAKEUP_EN;
1591*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
1592*2d102148SJC Kuo 
1593*2d102148SJC Kuo 	/* disable wake event triggers of sleepwalk logic */
1594*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
1595*2d102148SJC Kuo 	value &= ~UHSIC_WAKE_VAL(~0);
1596*2d102148SJC Kuo 	value |= UHSIC_WAKE_VAL_NONE;
1597*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
1598*2d102148SJC Kuo 
1599*2d102148SJC Kuo 	/* power down the line state detectors of the port */
1600*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_USB_AO);
1601*2d102148SJC Kuo 	value |= STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD;
1602*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_USB_AO);
1603*2d102148SJC Kuo 
1604*2d102148SJC Kuo 	/* save state, HSIC always comes up as HS */
1605*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SAVED_STATE);
1606*2d102148SJC Kuo 	value &= ~UHSIC_MODE(~0);
1607*2d102148SJC Kuo 	value |= UHSIC_HS;
1608*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SAVED_STATE);
1609*2d102148SJC Kuo 
1610*2d102148SJC Kuo 	/* enable the trigger of the sleepwalk logic */
1611*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_CFG);
1612*2d102148SJC Kuo 	value |= UHSIC_WAKE_WALK_EN | UHSIC_LINEVAL_WALK_EN;
1613*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_CFG);
1614*2d102148SJC Kuo 
1615*2d102148SJC Kuo 	/*
1616*2d102148SJC Kuo 	 * Reset the walk pointer and clear the alarm of the sleepwalk logic,
1617*2d102148SJC Kuo 	 * as well as capture the configuration of the USB2.0 port.
1618*2d102148SJC Kuo 	 */
1619*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
1620*2d102148SJC Kuo 	value |= UHSIC_CLR_WALK_PTR | UHSIC_CLR_WAKE_ALARM;
1621*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
1622*2d102148SJC Kuo 
1623*2d102148SJC Kuo 	/*
1624*2d102148SJC Kuo 	 * Set up the pull-ups and pull-downs of the signals during the four
1625*2d102148SJC Kuo 	 * stages of sleepwalk. Maintain a HSIC IDLE and keep driving HSIC
1626*2d102148SJC Kuo 	 * RESUME upon remote wake.
1627*2d102148SJC Kuo 	 */
1628*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_P0);
1629*2d102148SJC Kuo 	value = UHSIC_DATA0_RPD_A | UHSIC_DATA0_RPU_B | UHSIC_DATA0_RPU_C | UHSIC_DATA0_RPU_D |
1630*2d102148SJC Kuo 		UHSIC_STROBE_RPU_A | UHSIC_STROBE_RPD_B | UHSIC_STROBE_RPD_C | UHSIC_STROBE_RPD_D;
1631*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_P0);
1632*2d102148SJC Kuo 
1633*2d102148SJC Kuo 	/* power up the line state detectors of the port */
1634*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_USB_AO);
1635*2d102148SJC Kuo 	value &= ~(STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD);
1636*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_USB_AO);
1637*2d102148SJC Kuo 
1638*2d102148SJC Kuo 	usleep_range(50, 100);
1639*2d102148SJC Kuo 
1640*2d102148SJC Kuo 	/* set the wake signaling trigger events */
1641*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
1642*2d102148SJC Kuo 	value &= ~UHSIC_WAKE_VAL(~0);
1643*2d102148SJC Kuo 	value |= UHSIC_WAKE_VAL_SD10;
1644*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
1645*2d102148SJC Kuo 
1646*2d102148SJC Kuo 	/* enable the wake detection */
1647*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
1648*2d102148SJC Kuo 	value |= UHSIC_MASTER_ENABLE;
1649*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
1650*2d102148SJC Kuo 
1651*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
1652*2d102148SJC Kuo 	value |= UHSIC_LINE_WAKEUP_EN;
1653*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
1654*2d102148SJC Kuo 
1655*2d102148SJC Kuo 	return 0;
1656*2d102148SJC Kuo }
1657*2d102148SJC Kuo 
1658*2d102148SJC Kuo static int tegra210_pmc_hsic_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
1659*2d102148SJC Kuo {
1660*2d102148SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1661*2d102148SJC Kuo 	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
1662*2d102148SJC Kuo 	u32 value;
1663*2d102148SJC Kuo 
1664*2d102148SJC Kuo 	if (!priv->regmap)
1665*2d102148SJC Kuo 		return -EOPNOTSUPP;
1666*2d102148SJC Kuo 
1667*2d102148SJC Kuo 	/* disable the wake detection */
1668*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
1669*2d102148SJC Kuo 	value &= ~UHSIC_MASTER_ENABLE;
1670*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
1671*2d102148SJC Kuo 
1672*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
1673*2d102148SJC Kuo 	value &= ~UHSIC_LINE_WAKEUP_EN;
1674*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
1675*2d102148SJC Kuo 
1676*2d102148SJC Kuo 	/* disable wake event triggers of sleepwalk logic */
1677*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
1678*2d102148SJC Kuo 	value &= ~UHSIC_WAKE_VAL(~0);
1679*2d102148SJC Kuo 	value |= UHSIC_WAKE_VAL_NONE;
1680*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
1681*2d102148SJC Kuo 
1682*2d102148SJC Kuo 	/* power down the line state detectors of the port */
1683*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_USB_AO);
1684*2d102148SJC Kuo 	value |= STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD;
1685*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_USB_AO);
1686*2d102148SJC Kuo 
1687*2d102148SJC Kuo 	/* clear alarm of the sleepwalk logic */
1688*2d102148SJC Kuo 	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
1689*2d102148SJC Kuo 	value |= UHSIC_CLR_WAKE_ALARM;
1690*2d102148SJC Kuo 	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
1691*2d102148SJC Kuo 
1692*2d102148SJC Kuo 	return 0;
1693*2d102148SJC Kuo }
1694*2d102148SJC 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,
1791*2d102148SJC Kuo 	.enable_phy_sleepwalk = tegra210_pmc_utmi_enable_phy_sleepwalk,
1792*2d102148SJC Kuo 	.disable_phy_sleepwalk = tegra210_pmc_utmi_disable_phy_sleepwalk,
1793*2d102148SJC Kuo 	.enable_phy_wake = tegra210_utmi_enable_phy_wake,
1794*2d102148SJC Kuo 	.disable_phy_wake = tegra210_utmi_disable_phy_wake,
1795*2d102148SJC 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;
180287d66f28SThierry Reding 	u32 value;
180387d66f28SThierry Reding 
180487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
180587d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK <<
180687d66f28SThierry Reding 		   XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT);
180787d66f28SThierry Reding 	value |= XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB <<
180887d66f28SThierry Reding 		 XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT;
180987d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX);
181087d66f28SThierry Reding 
18112352fdb0SJC Kuo 	return 0;
181287d66f28SThierry Reding }
181387d66f28SThierry Reding 
181487d66f28SThierry Reding static int tegra210_usb2_phy_exit(struct phy *phy)
181587d66f28SThierry Reding {
18162352fdb0SJC Kuo 	return 0;
181787d66f28SThierry Reding }
181887d66f28SThierry Reding 
1819de792a6dSNagarjuna Kristam static int tegra210_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
1820de792a6dSNagarjuna Kristam 					      bool status)
1821de792a6dSNagarjuna Kristam {
1822de792a6dSNagarjuna Kristam 	u32 value;
1823de792a6dSNagarjuna Kristam 
1824de792a6dSNagarjuna Kristam 	dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
1825de792a6dSNagarjuna Kristam 
1826de792a6dSNagarjuna Kristam 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
1827de792a6dSNagarjuna Kristam 
1828de792a6dSNagarjuna Kristam 	if (status) {
1829de792a6dSNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
1830de792a6dSNagarjuna Kristam 		value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
1831de792a6dSNagarjuna Kristam 			   XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
1832de792a6dSNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING <<
1833de792a6dSNagarjuna Kristam 			 XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
1834de792a6dSNagarjuna Kristam 	} else {
1835de792a6dSNagarjuna Kristam 		value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
1836de792a6dSNagarjuna Kristam 	}
1837de792a6dSNagarjuna Kristam 
1838de792a6dSNagarjuna Kristam 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
1839de792a6dSNagarjuna Kristam 
1840de792a6dSNagarjuna Kristam 	return 0;
1841de792a6dSNagarjuna Kristam }
1842de792a6dSNagarjuna Kristam 
1843de792a6dSNagarjuna Kristam static int tegra210_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl,
1844de792a6dSNagarjuna Kristam 					    bool status)
1845de792a6dSNagarjuna Kristam {
1846de792a6dSNagarjuna Kristam 	u32 value;
1847de792a6dSNagarjuna Kristam 
1848de792a6dSNagarjuna Kristam 	dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear");
1849de792a6dSNagarjuna Kristam 
1850de792a6dSNagarjuna Kristam 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
1851de792a6dSNagarjuna Kristam 
1852de792a6dSNagarjuna Kristam 	if (status) {
1853de792a6dSNagarjuna Kristam 		if (value & XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON) {
1854de792a6dSNagarjuna Kristam 			value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
1855de792a6dSNagarjuna Kristam 			padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
1856de792a6dSNagarjuna Kristam 			usleep_range(1000, 2000);
1857de792a6dSNagarjuna Kristam 
1858de792a6dSNagarjuna Kristam 			value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
1859de792a6dSNagarjuna Kristam 		}
1860de792a6dSNagarjuna Kristam 
1861de792a6dSNagarjuna Kristam 		value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
1862de792a6dSNagarjuna Kristam 			   XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
1863de792a6dSNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED <<
1864de792a6dSNagarjuna Kristam 			 XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
1865de792a6dSNagarjuna Kristam 	} else {
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 	}
1871de792a6dSNagarjuna Kristam 
1872de792a6dSNagarjuna Kristam 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
1873de792a6dSNagarjuna Kristam 
1874de792a6dSNagarjuna Kristam 	return 0;
1875de792a6dSNagarjuna Kristam }
1876de792a6dSNagarjuna Kristam 
1877de792a6dSNagarjuna Kristam static int tegra210_usb2_phy_set_mode(struct phy *phy, enum phy_mode mode,
1878de792a6dSNagarjuna Kristam 				      int submode)
1879de792a6dSNagarjuna Kristam {
1880de792a6dSNagarjuna Kristam 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
1881de792a6dSNagarjuna Kristam 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1882de792a6dSNagarjuna Kristam 	struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl,
1883de792a6dSNagarjuna Kristam 								lane->index);
1884de792a6dSNagarjuna Kristam 	int err = 0;
1885de792a6dSNagarjuna Kristam 
1886de792a6dSNagarjuna Kristam 	mutex_lock(&padctl->lock);
1887de792a6dSNagarjuna Kristam 
1888de792a6dSNagarjuna Kristam 	dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode);
1889de792a6dSNagarjuna Kristam 
1890de792a6dSNagarjuna Kristam 	if (mode == PHY_MODE_USB_OTG) {
1891de792a6dSNagarjuna Kristam 		if (submode == USB_ROLE_HOST) {
1892de792a6dSNagarjuna Kristam 			tegra210_xusb_padctl_id_override(padctl, true);
1893de792a6dSNagarjuna Kristam 
1894de792a6dSNagarjuna Kristam 			err = regulator_enable(port->supply);
1895de792a6dSNagarjuna Kristam 		} else if (submode == USB_ROLE_DEVICE) {
1896de792a6dSNagarjuna Kristam 			tegra210_xusb_padctl_vbus_override(padctl, true);
1897de792a6dSNagarjuna Kristam 		} else if (submode == USB_ROLE_NONE) {
1898de792a6dSNagarjuna Kristam 			/*
1899de792a6dSNagarjuna Kristam 			 * When port is peripheral only or role transitions to
1900de792a6dSNagarjuna Kristam 			 * USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not
1901de792a6dSNagarjuna Kristam 			 * be enabled.
1902de792a6dSNagarjuna Kristam 			 */
1903de792a6dSNagarjuna Kristam 			if (regulator_is_enabled(port->supply))
1904de792a6dSNagarjuna Kristam 				regulator_disable(port->supply);
1905de792a6dSNagarjuna Kristam 
1906de792a6dSNagarjuna Kristam 			tegra210_xusb_padctl_id_override(padctl, false);
1907de792a6dSNagarjuna Kristam 			tegra210_xusb_padctl_vbus_override(padctl, false);
1908de792a6dSNagarjuna Kristam 		}
1909de792a6dSNagarjuna Kristam 	}
1910de792a6dSNagarjuna Kristam 
1911de792a6dSNagarjuna Kristam 	mutex_unlock(&padctl->lock);
1912de792a6dSNagarjuna Kristam 
1913de792a6dSNagarjuna Kristam 	return err;
1914de792a6dSNagarjuna Kristam }
1915de792a6dSNagarjuna Kristam 
191687d66f28SThierry Reding static int tegra210_usb2_phy_power_on(struct phy *phy)
191787d66f28SThierry Reding {
191887d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
191987d66f28SThierry Reding 	struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane);
192087d66f28SThierry Reding 	struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad);
192187d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
192287d66f28SThierry Reding 	struct tegra210_xusb_padctl *priv;
192387d66f28SThierry Reding 	struct tegra_xusb_usb2_port *port;
192487d66f28SThierry Reding 	unsigned int index = lane->index;
192587d66f28SThierry Reding 	u32 value;
192687d66f28SThierry Reding 	int err;
192787d66f28SThierry Reding 
192887d66f28SThierry Reding 	port = tegra_xusb_find_usb2_port(padctl, index);
192987d66f28SThierry Reding 	if (!port) {
193087d66f28SThierry Reding 		dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
193187d66f28SThierry Reding 		return -ENODEV;
193287d66f28SThierry Reding 	}
193387d66f28SThierry Reding 
193487d66f28SThierry Reding 	priv = to_tegra210_xusb_padctl(padctl);
193587d66f28SThierry Reding 
1936a5be28c3SNagarjuna Kristam 	if (port->usb3_port_fake != -1) {
1937a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
1938a5be28c3SNagarjuna Kristam 		value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(
1939a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
1940a5be28c3SNagarjuna Kristam 		value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(
1941a5be28c3SNagarjuna Kristam 					port->usb3_port_fake, index);
1942a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP);
1943a5be28c3SNagarjuna Kristam 
1944a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
1945a5be28c3SNagarjuna Kristam 		value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(
1946a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
1947a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
1948a5be28c3SNagarjuna Kristam 
1949a5be28c3SNagarjuna Kristam 		usleep_range(100, 200);
1950a5be28c3SNagarjuna Kristam 
1951a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
1952a5be28c3SNagarjuna Kristam 		value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(
1953a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
1954a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
1955a5be28c3SNagarjuna Kristam 
1956a5be28c3SNagarjuna Kristam 		usleep_range(100, 200);
1957a5be28c3SNagarjuna Kristam 
1958a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
1959a5be28c3SNagarjuna Kristam 		value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(
1960a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
1961a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
1962a5be28c3SNagarjuna Kristam 	}
1963a5be28c3SNagarjuna Kristam 
196487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
196587d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK <<
196687d66f28SThierry Reding 		    XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) |
196787d66f28SThierry Reding 		   (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK <<
196887d66f28SThierry Reding 		    XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT));
196987d66f28SThierry Reding 	value |= (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL <<
197087d66f28SThierry Reding 		  XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT);
197187d66f28SThierry Reding 
197287d66f28SThierry Reding 	if (tegra_sku_info.revision < TEGRA_REVISION_A02)
197387d66f28SThierry Reding 		value |=
197487d66f28SThierry Reding 			(XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_VAL <<
197587d66f28SThierry Reding 			XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT);
197687d66f28SThierry Reding 
197787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
197887d66f28SThierry Reding 
197987d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
198087d66f28SThierry Reding 	value &= ~XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(index);
1981ac25b6e9SNagarjuna Kristam 	if (port->mode == USB_DR_MODE_UNKNOWN)
1982ac25b6e9SNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DISABLED(index);
1983ac25b6e9SNagarjuna Kristam 	else if (port->mode == USB_DR_MODE_PERIPHERAL)
1984ac25b6e9SNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DEVICE(index);
1985ac25b6e9SNagarjuna Kristam 	else if (port->mode == USB_DR_MODE_HOST)
198687d66f28SThierry Reding 		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(index);
1987ac25b6e9SNagarjuna Kristam 	else if (port->mode == USB_DR_MODE_OTG)
1988ac25b6e9SNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_OTG(index);
198987d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP);
199087d66f28SThierry Reding 
199187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
199287d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK <<
199387d66f28SThierry Reding 		    XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT) |
199487d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD |
199587d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 |
199687d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI);
199787d66f28SThierry Reding 	value |= (priv->fuse.hs_curr_level[index] +
199887d66f28SThierry Reding 		  usb2->hs_curr_level_offset) <<
199987d66f28SThierry Reding 		 XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT;
200087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
200187d66f28SThierry Reding 
200287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
200387d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK <<
200487d66f28SThierry Reding 		    XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) |
200587d66f28SThierry Reding 		   (XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_MASK <<
200687d66f28SThierry Reding 		    XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT) |
200787d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR |
200887d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD |
200987d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD);
201087d66f28SThierry Reding 	value |= (priv->fuse.hs_term_range_adj <<
201187d66f28SThierry Reding 		  XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) |
201287d66f28SThierry Reding 		 (priv->fuse.rpd_ctrl <<
201387d66f28SThierry Reding 		  XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT);
201487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
201587d66f28SThierry Reding 
201687d66f28SThierry Reding 	value = padctl_readl(padctl,
201787d66f28SThierry Reding 			     XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
201887d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_MASK <<
201987d66f28SThierry Reding 		   XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT);
2020ac25b6e9SNagarjuna Kristam 	if (port->mode == USB_DR_MODE_HOST)
202187d66f28SThierry Reding 		value |= XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18;
2022ac25b6e9SNagarjuna Kristam 	else
2023ac25b6e9SNagarjuna Kristam 		value |=
2024ac25b6e9SNagarjuna Kristam 		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_VAL <<
2025ac25b6e9SNagarjuna Kristam 		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT;
202687d66f28SThierry Reding 	padctl_writel(padctl, value,
202787d66f28SThierry Reding 		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
202887d66f28SThierry Reding 
2029de792a6dSNagarjuna Kristam 	if (port->supply && port->mode == USB_DR_MODE_HOST) {
203087d66f28SThierry Reding 		err = regulator_enable(port->supply);
203187d66f28SThierry Reding 		if (err)
203287d66f28SThierry Reding 			return err;
2033de792a6dSNagarjuna Kristam 	}
203487d66f28SThierry Reding 
203587d66f28SThierry Reding 	mutex_lock(&padctl->lock);
203687d66f28SThierry Reding 
203787d66f28SThierry Reding 	if (pad->enable > 0) {
203887d66f28SThierry Reding 		pad->enable++;
203987d66f28SThierry Reding 		mutex_unlock(&padctl->lock);
204087d66f28SThierry Reding 		return 0;
204187d66f28SThierry Reding 	}
204287d66f28SThierry Reding 
204387d66f28SThierry Reding 	err = clk_prepare_enable(pad->clk);
204487d66f28SThierry Reding 	if (err)
204587d66f28SThierry Reding 		goto disable_regulator;
204687d66f28SThierry Reding 
204787d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
204887d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK <<
204987d66f28SThierry Reding 		    XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT) |
205087d66f28SThierry Reding 		   (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_MASK <<
205187d66f28SThierry Reding 		    XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT));
205287d66f28SThierry Reding 	value |= (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL <<
205387d66f28SThierry Reding 		  XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT) |
205487d66f28SThierry Reding 		 (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_VAL <<
205587d66f28SThierry Reding 		  XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT);
205687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
205787d66f28SThierry Reding 
205887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
205987d66f28SThierry Reding 	value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
206087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
206187d66f28SThierry Reding 
206287d66f28SThierry Reding 	udelay(1);
206387d66f28SThierry Reding 
206487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
206587d66f28SThierry Reding 	value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL1_PD_TRK;
206687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
206787d66f28SThierry Reding 
206887d66f28SThierry Reding 	udelay(50);
206987d66f28SThierry Reding 
207087d66f28SThierry Reding 	clk_disable_unprepare(pad->clk);
207187d66f28SThierry Reding 
207287d66f28SThierry Reding 	pad->enable++;
207387d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
207487d66f28SThierry Reding 
207587d66f28SThierry Reding 	return 0;
207687d66f28SThierry Reding 
207787d66f28SThierry Reding disable_regulator:
207887d66f28SThierry Reding 	regulator_disable(port->supply);
207987d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
208087d66f28SThierry Reding 	return err;
208187d66f28SThierry Reding }
208287d66f28SThierry Reding 
208387d66f28SThierry Reding static int tegra210_usb2_phy_power_off(struct phy *phy)
208487d66f28SThierry Reding {
208587d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
208687d66f28SThierry Reding 	struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad);
208787d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
208887d66f28SThierry Reding 	struct tegra_xusb_usb2_port *port;
208987d66f28SThierry Reding 	u32 value;
209087d66f28SThierry Reding 
209187d66f28SThierry Reding 	port = tegra_xusb_find_usb2_port(padctl, lane->index);
209287d66f28SThierry Reding 	if (!port) {
209387d66f28SThierry Reding 		dev_err(&phy->dev, "no port found for USB2 lane %u\n",
209487d66f28SThierry Reding 			lane->index);
209587d66f28SThierry Reding 		return -ENODEV;
209687d66f28SThierry Reding 	}
209787d66f28SThierry Reding 
209887d66f28SThierry Reding 	mutex_lock(&padctl->lock);
209987d66f28SThierry Reding 
2100a5be28c3SNagarjuna Kristam 	if (port->usb3_port_fake != -1) {
2101a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
2102a5be28c3SNagarjuna Kristam 		value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(
2103a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
2104a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
2105a5be28c3SNagarjuna Kristam 
2106a5be28c3SNagarjuna Kristam 		usleep_range(100, 200);
2107a5be28c3SNagarjuna Kristam 
2108a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
2109a5be28c3SNagarjuna Kristam 		value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(
2110a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
2111a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
2112a5be28c3SNagarjuna Kristam 
2113a5be28c3SNagarjuna Kristam 		usleep_range(250, 350);
2114a5be28c3SNagarjuna Kristam 
2115a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
2116a5be28c3SNagarjuna Kristam 		value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(
2117a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
2118a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
2119a5be28c3SNagarjuna Kristam 
2120a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
2121a5be28c3SNagarjuna Kristam 		value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(port->usb3_port_fake,
2122a5be28c3SNagarjuna Kristam 					XUSB_PADCTL_SS_PORT_MAP_PORT_DISABLED);
2123a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP);
2124a5be28c3SNagarjuna Kristam 	}
2125a5be28c3SNagarjuna Kristam 
212687d66f28SThierry Reding 	if (WARN_ON(pad->enable == 0))
212787d66f28SThierry Reding 		goto out;
212887d66f28SThierry Reding 
212987d66f28SThierry Reding 	if (--pad->enable > 0)
213087d66f28SThierry Reding 		goto out;
213187d66f28SThierry Reding 
213287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
213387d66f28SThierry Reding 	value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
213487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
213587d66f28SThierry Reding 
213687d66f28SThierry Reding out:
213787d66f28SThierry Reding 	regulator_disable(port->supply);
213887d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
213987d66f28SThierry Reding 	return 0;
214087d66f28SThierry Reding }
214187d66f28SThierry Reding 
214287d66f28SThierry Reding static const struct phy_ops tegra210_usb2_phy_ops = {
214387d66f28SThierry Reding 	.init = tegra210_usb2_phy_init,
214487d66f28SThierry Reding 	.exit = tegra210_usb2_phy_exit,
214587d66f28SThierry Reding 	.power_on = tegra210_usb2_phy_power_on,
214687d66f28SThierry Reding 	.power_off = tegra210_usb2_phy_power_off,
2147de792a6dSNagarjuna Kristam 	.set_mode = tegra210_usb2_phy_set_mode,
214887d66f28SThierry Reding 	.owner = THIS_MODULE,
214987d66f28SThierry Reding };
215087d66f28SThierry Reding 
215187d66f28SThierry Reding static struct tegra_xusb_pad *
215287d66f28SThierry Reding tegra210_usb2_pad_probe(struct tegra_xusb_padctl *padctl,
215387d66f28SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
215487d66f28SThierry Reding 			struct device_node *np)
215587d66f28SThierry Reding {
215687d66f28SThierry Reding 	struct tegra_xusb_usb2_pad *usb2;
215787d66f28SThierry Reding 	struct tegra_xusb_pad *pad;
215887d66f28SThierry Reding 	int err;
215987d66f28SThierry Reding 
216087d66f28SThierry Reding 	usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
216187d66f28SThierry Reding 	if (!usb2)
216287d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
216387d66f28SThierry Reding 
216487d66f28SThierry Reding 	pad = &usb2->base;
216587d66f28SThierry Reding 	pad->ops = &tegra210_usb2_lane_ops;
216687d66f28SThierry Reding 	pad->soc = soc;
216787d66f28SThierry Reding 
216887d66f28SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
216987d66f28SThierry Reding 	if (err < 0) {
217087d66f28SThierry Reding 		kfree(usb2);
217187d66f28SThierry Reding 		goto out;
217287d66f28SThierry Reding 	}
217387d66f28SThierry Reding 
217487d66f28SThierry Reding 	usb2->clk = devm_clk_get(&pad->dev, "trk");
217587d66f28SThierry Reding 	if (IS_ERR(usb2->clk)) {
217687d66f28SThierry Reding 		err = PTR_ERR(usb2->clk);
217787d66f28SThierry Reding 		dev_err(&pad->dev, "failed to get trk clock: %d\n", err);
217887d66f28SThierry Reding 		goto unregister;
217987d66f28SThierry Reding 	}
218087d66f28SThierry Reding 
218187d66f28SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra210_usb2_phy_ops);
218287d66f28SThierry Reding 	if (err < 0)
218387d66f28SThierry Reding 		goto unregister;
218487d66f28SThierry Reding 
218587d66f28SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
218687d66f28SThierry Reding 
218787d66f28SThierry Reding 	return pad;
218887d66f28SThierry Reding 
218987d66f28SThierry Reding unregister:
219087d66f28SThierry Reding 	device_unregister(&pad->dev);
219187d66f28SThierry Reding out:
219287d66f28SThierry Reding 	return ERR_PTR(err);
219387d66f28SThierry Reding }
219487d66f28SThierry Reding 
219587d66f28SThierry Reding static void tegra210_usb2_pad_remove(struct tegra_xusb_pad *pad)
219687d66f28SThierry Reding {
219787d66f28SThierry Reding 	struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad);
219887d66f28SThierry Reding 
219987d66f28SThierry Reding 	kfree(usb2);
220087d66f28SThierry Reding }
220187d66f28SThierry Reding 
220287d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_usb2_ops = {
220387d66f28SThierry Reding 	.probe = tegra210_usb2_pad_probe,
220487d66f28SThierry Reding 	.remove = tegra210_usb2_pad_remove,
220587d66f28SThierry Reding };
220687d66f28SThierry Reding 
220787d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_usb2_pad = {
220887d66f28SThierry Reding 	.name = "usb2",
220987d66f28SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra210_usb2_lanes),
221087d66f28SThierry Reding 	.lanes = tegra210_usb2_lanes,
221187d66f28SThierry Reding 	.ops = &tegra210_usb2_ops,
221287d66f28SThierry Reding };
221387d66f28SThierry Reding 
221487d66f28SThierry Reding static const char *tegra210_hsic_functions[] = {
221587d66f28SThierry Reding 	"snps",
221687d66f28SThierry Reding 	"xusb",
221787d66f28SThierry Reding };
221887d66f28SThierry Reding 
221987d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_hsic_lanes[] = {
222087d66f28SThierry Reding 	TEGRA210_LANE("hsic-0", 0x004, 14, 0x1, hsic),
222187d66f28SThierry Reding };
222287d66f28SThierry Reding 
222387d66f28SThierry Reding static struct tegra_xusb_lane *
222487d66f28SThierry Reding tegra210_hsic_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
222587d66f28SThierry Reding 			 unsigned int index)
222687d66f28SThierry Reding {
222787d66f28SThierry Reding 	struct tegra_xusb_hsic_lane *hsic;
222887d66f28SThierry Reding 	int err;
222987d66f28SThierry Reding 
223087d66f28SThierry Reding 	hsic = kzalloc(sizeof(*hsic), GFP_KERNEL);
223187d66f28SThierry Reding 	if (!hsic)
223287d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
223387d66f28SThierry Reding 
223487d66f28SThierry Reding 	INIT_LIST_HEAD(&hsic->base.list);
223587d66f28SThierry Reding 	hsic->base.soc = &pad->soc->lanes[index];
223687d66f28SThierry Reding 	hsic->base.index = index;
223787d66f28SThierry Reding 	hsic->base.pad = pad;
223887d66f28SThierry Reding 	hsic->base.np = np;
223987d66f28SThierry Reding 
224087d66f28SThierry Reding 	err = tegra_xusb_lane_parse_dt(&hsic->base, np);
224187d66f28SThierry Reding 	if (err < 0) {
224287d66f28SThierry Reding 		kfree(hsic);
224387d66f28SThierry Reding 		return ERR_PTR(err);
224487d66f28SThierry Reding 	}
224587d66f28SThierry Reding 
224687d66f28SThierry Reding 	return &hsic->base;
224787d66f28SThierry Reding }
224887d66f28SThierry Reding 
224987d66f28SThierry Reding static void tegra210_hsic_lane_remove(struct tegra_xusb_lane *lane)
225087d66f28SThierry Reding {
225187d66f28SThierry Reding 	struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane);
225287d66f28SThierry Reding 
225387d66f28SThierry Reding 	kfree(hsic);
225487d66f28SThierry Reding }
225587d66f28SThierry Reding 
225687d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_hsic_lane_ops = {
225787d66f28SThierry Reding 	.probe = tegra210_hsic_lane_probe,
225887d66f28SThierry Reding 	.remove = tegra210_hsic_lane_remove,
2259*2d102148SJC Kuo 	.enable_phy_sleepwalk = tegra210_pmc_hsic_enable_phy_sleepwalk,
2260*2d102148SJC Kuo 	.disable_phy_sleepwalk = tegra210_pmc_hsic_disable_phy_sleepwalk,
2261*2d102148SJC Kuo 	.enable_phy_wake = tegra210_hsic_enable_phy_wake,
2262*2d102148SJC Kuo 	.disable_phy_wake = tegra210_hsic_disable_phy_wake,
2263*2d102148SJC Kuo 	.remote_wake_detected = tegra210_hsic_phy_remote_wake_detected,
226487d66f28SThierry Reding };
226587d66f28SThierry Reding 
226687d66f28SThierry Reding static int tegra210_hsic_phy_init(struct phy *phy)
226787d66f28SThierry Reding {
226887d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
226987d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
227087d66f28SThierry Reding 	u32 value;
227187d66f28SThierry Reding 
227287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
227387d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_MASK <<
227487d66f28SThierry Reding 		   XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT);
227587d66f28SThierry Reding 	value |= XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_XUSB <<
227687d66f28SThierry Reding 		 XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT;
227787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX);
227887d66f28SThierry Reding 
22792352fdb0SJC Kuo 	return 0;
228087d66f28SThierry Reding }
228187d66f28SThierry Reding 
228287d66f28SThierry Reding static int tegra210_hsic_phy_exit(struct phy *phy)
228387d66f28SThierry Reding {
22842352fdb0SJC Kuo 	return 0;
228587d66f28SThierry Reding }
228687d66f28SThierry Reding 
228787d66f28SThierry Reding static int tegra210_hsic_phy_power_on(struct phy *phy)
228887d66f28SThierry Reding {
228987d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
229087d66f28SThierry Reding 	struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane);
229187d66f28SThierry Reding 	struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad);
229287d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
229387d66f28SThierry Reding 	unsigned int index = lane->index;
229487d66f28SThierry Reding 	u32 value;
229587d66f28SThierry Reding 	int err;
229687d66f28SThierry Reding 
229787d66f28SThierry Reding 	err = regulator_enable(pad->supply);
229887d66f28SThierry Reding 	if (err)
229987d66f28SThierry Reding 		return err;
230087d66f28SThierry Reding 
230187d66f28SThierry Reding 	padctl_writel(padctl, hsic->strobe_trim,
230287d66f28SThierry Reding 		      XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL);
230387d66f28SThierry Reding 
230487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index));
230587d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_MASK <<
230687d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT);
230787d66f28SThierry Reding 	value |= (hsic->tx_rtune_p <<
230887d66f28SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT);
230987d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index));
231087d66f28SThierry Reding 
231187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(index));
231287d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK <<
231387d66f28SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) |
231487d66f28SThierry Reding 		   (XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK <<
231587d66f28SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT));
231687d66f28SThierry Reding 	value |= (hsic->rx_strobe_trim <<
231787d66f28SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) |
231887d66f28SThierry Reding 		 (hsic->rx_data_trim <<
231987d66f28SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT);
232087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL2(index));
232187d66f28SThierry Reding 
232287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index));
232387d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA0 |
232487d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA1 |
232587d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE |
232687d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 |
232787d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 |
232887d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE |
232987d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 |
233087d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 |
233187d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE |
233287d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 |
233387d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 |
233487d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE);
233587d66f28SThierry Reding 	value |= XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 |
233687d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 |
233787d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_RPD_STROBE;
233887d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL0(index));
233987d66f28SThierry Reding 
234087d66f28SThierry Reding 	err = clk_prepare_enable(pad->clk);
234187d66f28SThierry Reding 	if (err)
234287d66f28SThierry Reding 		goto disable;
234387d66f28SThierry Reding 
234487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PAD_TRK_CTL);
234587d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_MASK <<
234687d66f28SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT) |
234787d66f28SThierry Reding 		   (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_MASK <<
234887d66f28SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT));
234987d66f28SThierry Reding 	value |= (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_VAL <<
235087d66f28SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT) |
235187d66f28SThierry Reding 		 (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_VAL <<
235287d66f28SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT);
235387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PAD_TRK_CTL);
235487d66f28SThierry Reding 
235587d66f28SThierry Reding 	udelay(1);
235687d66f28SThierry Reding 
235787d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PAD_TRK_CTL);
235887d66f28SThierry Reding 	value &= ~XUSB_PADCTL_HSIC_PAD_TRK_CTL_PD_TRK;
235987d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PAD_TRK_CTL);
236087d66f28SThierry Reding 
236187d66f28SThierry Reding 	udelay(50);
236287d66f28SThierry Reding 
236387d66f28SThierry Reding 	clk_disable_unprepare(pad->clk);
236487d66f28SThierry Reding 
236587d66f28SThierry Reding 	return 0;
236687d66f28SThierry Reding 
236787d66f28SThierry Reding disable:
236887d66f28SThierry Reding 	regulator_disable(pad->supply);
236987d66f28SThierry Reding 	return err;
237087d66f28SThierry Reding }
237187d66f28SThierry Reding 
237287d66f28SThierry Reding static int tegra210_hsic_phy_power_off(struct phy *phy)
237387d66f28SThierry Reding {
237487d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
237587d66f28SThierry Reding 	struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad);
237687d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
237787d66f28SThierry Reding 	unsigned int index = lane->index;
237887d66f28SThierry Reding 	u32 value;
237987d66f28SThierry Reding 
238087d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index));
238187d66f28SThierry Reding 	value |= XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 |
238287d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 |
238387d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE |
238487d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 |
238587d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 |
238687d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE |
238787d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 |
238887d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 |
238987d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE;
239087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index));
239187d66f28SThierry Reding 
239287d66f28SThierry Reding 	regulator_disable(pad->supply);
239387d66f28SThierry Reding 
239487d66f28SThierry Reding 	return 0;
239587d66f28SThierry Reding }
239687d66f28SThierry Reding 
239787d66f28SThierry Reding static const struct phy_ops tegra210_hsic_phy_ops = {
239887d66f28SThierry Reding 	.init = tegra210_hsic_phy_init,
239987d66f28SThierry Reding 	.exit = tegra210_hsic_phy_exit,
240087d66f28SThierry Reding 	.power_on = tegra210_hsic_phy_power_on,
240187d66f28SThierry Reding 	.power_off = tegra210_hsic_phy_power_off,
240287d66f28SThierry Reding 	.owner = THIS_MODULE,
240387d66f28SThierry Reding };
240487d66f28SThierry Reding 
240587d66f28SThierry Reding static struct tegra_xusb_pad *
240687d66f28SThierry Reding tegra210_hsic_pad_probe(struct tegra_xusb_padctl *padctl,
240787d66f28SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
240887d66f28SThierry Reding 			struct device_node *np)
240987d66f28SThierry Reding {
241087d66f28SThierry Reding 	struct tegra_xusb_hsic_pad *hsic;
241187d66f28SThierry Reding 	struct tegra_xusb_pad *pad;
241287d66f28SThierry Reding 	int err;
241387d66f28SThierry Reding 
241487d66f28SThierry Reding 	hsic = kzalloc(sizeof(*hsic), GFP_KERNEL);
241587d66f28SThierry Reding 	if (!hsic)
241687d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
241787d66f28SThierry Reding 
241887d66f28SThierry Reding 	pad = &hsic->base;
241987d66f28SThierry Reding 	pad->ops = &tegra210_hsic_lane_ops;
242087d66f28SThierry Reding 	pad->soc = soc;
242187d66f28SThierry Reding 
242287d66f28SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
242387d66f28SThierry Reding 	if (err < 0) {
242487d66f28SThierry Reding 		kfree(hsic);
242587d66f28SThierry Reding 		goto out;
242687d66f28SThierry Reding 	}
242787d66f28SThierry Reding 
242887d66f28SThierry Reding 	hsic->clk = devm_clk_get(&pad->dev, "trk");
242987d66f28SThierry Reding 	if (IS_ERR(hsic->clk)) {
243087d66f28SThierry Reding 		err = PTR_ERR(hsic->clk);
243187d66f28SThierry Reding 		dev_err(&pad->dev, "failed to get trk clock: %d\n", err);
243287d66f28SThierry Reding 		goto unregister;
243387d66f28SThierry Reding 	}
243487d66f28SThierry Reding 
243587d66f28SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra210_hsic_phy_ops);
243687d66f28SThierry Reding 	if (err < 0)
243787d66f28SThierry Reding 		goto unregister;
243887d66f28SThierry Reding 
243987d66f28SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
244087d66f28SThierry Reding 
244187d66f28SThierry Reding 	return pad;
244287d66f28SThierry Reding 
244387d66f28SThierry Reding unregister:
244487d66f28SThierry Reding 	device_unregister(&pad->dev);
244587d66f28SThierry Reding out:
244687d66f28SThierry Reding 	return ERR_PTR(err);
244787d66f28SThierry Reding }
244887d66f28SThierry Reding 
244987d66f28SThierry Reding static void tegra210_hsic_pad_remove(struct tegra_xusb_pad *pad)
245087d66f28SThierry Reding {
245187d66f28SThierry Reding 	struct tegra_xusb_hsic_pad *hsic = to_hsic_pad(pad);
245287d66f28SThierry Reding 
245387d66f28SThierry Reding 	kfree(hsic);
245487d66f28SThierry Reding }
245587d66f28SThierry Reding 
245687d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_hsic_ops = {
245787d66f28SThierry Reding 	.probe = tegra210_hsic_pad_probe,
245887d66f28SThierry Reding 	.remove = tegra210_hsic_pad_remove,
245987d66f28SThierry Reding };
246087d66f28SThierry Reding 
246187d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_hsic_pad = {
246287d66f28SThierry Reding 	.name = "hsic",
246387d66f28SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra210_hsic_lanes),
246487d66f28SThierry Reding 	.lanes = tegra210_hsic_lanes,
246587d66f28SThierry Reding 	.ops = &tegra210_hsic_ops,
246687d66f28SThierry Reding };
246787d66f28SThierry Reding 
2468c339605cSJC Kuo static void tegra210_uphy_lane_iddq_enable(struct tegra_xusb_lane *lane)
2469c339605cSJC Kuo {
2470c339605cSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
2471c339605cSJC Kuo 	u32 value;
2472c339605cSJC Kuo 
2473c339605cSJC Kuo 	value = padctl_readl(padctl, lane->soc->regs.misc_ctl2);
2474c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD;
2475c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD;
2476c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD;
2477c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD;
2478c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ;
2479c339605cSJC Kuo 	value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK;
2480c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL;
2481c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ;
2482c339605cSJC Kuo 	value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK;
2483c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL;
2484c339605cSJC Kuo 	padctl_writel(padctl, value, lane->soc->regs.misc_ctl2);
2485c339605cSJC Kuo }
2486c339605cSJC Kuo 
2487c339605cSJC Kuo static void tegra210_uphy_lane_iddq_disable(struct tegra_xusb_lane *lane)
2488c339605cSJC Kuo {
2489c339605cSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
2490c339605cSJC Kuo 	u32 value;
2491c339605cSJC Kuo 
2492c339605cSJC Kuo 	value = padctl_readl(padctl, lane->soc->regs.misc_ctl2);
2493c339605cSJC Kuo 	value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD;
2494c339605cSJC Kuo 	value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD;
2495c339605cSJC Kuo 	value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD;
2496c339605cSJC Kuo 	value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD;
2497c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ;
2498c339605cSJC Kuo 	value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK;
2499c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL;
2500c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ;
2501c339605cSJC Kuo 	value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK;
2502c339605cSJC Kuo 	value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL;
2503c339605cSJC Kuo 	padctl_writel(padctl, value, lane->soc->regs.misc_ctl2);
2504c339605cSJC Kuo }
2505c339605cSJC Kuo 
2506c339605cSJC Kuo #define TEGRA210_UPHY_LANE(_name, _offset, _shift, _mask, _type, _misc)	\
2507c339605cSJC Kuo 	{								\
2508c339605cSJC Kuo 		.name = _name,						\
2509c339605cSJC Kuo 		.offset = _offset,					\
2510c339605cSJC Kuo 		.shift = _shift,					\
2511c339605cSJC Kuo 		.mask = _mask,						\
2512c339605cSJC Kuo 		.num_funcs = ARRAY_SIZE(tegra210_##_type##_functions),	\
2513c339605cSJC Kuo 		.funcs = tegra210_##_type##_functions,			\
2514c339605cSJC Kuo 		.regs.misc_ctl2 = _misc,				\
2515c339605cSJC Kuo 	}
2516c339605cSJC Kuo 
251787d66f28SThierry Reding static const char *tegra210_pcie_functions[] = {
251887d66f28SThierry Reding 	"pcie-x1",
251987d66f28SThierry Reding 	"usb3-ss",
252087d66f28SThierry Reding 	"sata",
252187d66f28SThierry Reding 	"pcie-x4",
252287d66f28SThierry Reding };
252387d66f28SThierry Reding 
252487d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_pcie_lanes[] = {
2525c339605cSJC Kuo 	TEGRA210_UPHY_LANE("pcie-0", 0x028, 12, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)),
2526c339605cSJC Kuo 	TEGRA210_UPHY_LANE("pcie-1", 0x028, 14, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(1)),
2527c339605cSJC Kuo 	TEGRA210_UPHY_LANE("pcie-2", 0x028, 16, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(2)),
2528c339605cSJC Kuo 	TEGRA210_UPHY_LANE("pcie-3", 0x028, 18, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(3)),
2529c339605cSJC Kuo 	TEGRA210_UPHY_LANE("pcie-4", 0x028, 20, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(4)),
2530c339605cSJC Kuo 	TEGRA210_UPHY_LANE("pcie-5", 0x028, 22, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(5)),
2531c339605cSJC Kuo 	TEGRA210_UPHY_LANE("pcie-6", 0x028, 24, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(6)),
253287d66f28SThierry Reding };
253387d66f28SThierry Reding 
253423d5ec3fSJC Kuo static struct tegra_xusb_usb3_port *
253523d5ec3fSJC Kuo tegra210_lane_to_usb3_port(struct tegra_xusb_lane *lane)
253623d5ec3fSJC Kuo {
253723d5ec3fSJC Kuo 	int port;
253823d5ec3fSJC Kuo 
253923d5ec3fSJC Kuo 	if (!lane || !lane->pad || !lane->pad->padctl)
254023d5ec3fSJC Kuo 		return NULL;
254123d5ec3fSJC Kuo 
254223d5ec3fSJC Kuo 	port = tegra210_usb3_lane_map(lane);
254323d5ec3fSJC Kuo 	if (port < 0)
254423d5ec3fSJC Kuo 		return NULL;
254523d5ec3fSJC Kuo 
254623d5ec3fSJC Kuo 	return tegra_xusb_find_usb3_port(lane->pad->padctl, port);
254723d5ec3fSJC Kuo }
254823d5ec3fSJC Kuo 
254923d5ec3fSJC Kuo static int tegra210_usb3_phy_power_on(struct phy *phy)
255023d5ec3fSJC Kuo {
255123d5ec3fSJC Kuo 	struct device *dev = &phy->dev;
255223d5ec3fSJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
255323d5ec3fSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
255423d5ec3fSJC Kuo 	struct tegra_xusb_usb3_port *usb3 = tegra210_lane_to_usb3_port(lane);
255523d5ec3fSJC Kuo 	unsigned int index;
255623d5ec3fSJC Kuo 	u32 value;
255723d5ec3fSJC Kuo 
255823d5ec3fSJC Kuo 	if (!usb3) {
255923d5ec3fSJC Kuo 		dev_err(dev, "no USB3 port found for lane %u\n", lane->index);
256023d5ec3fSJC Kuo 		return -ENODEV;
256123d5ec3fSJC Kuo 	}
256223d5ec3fSJC Kuo 
256323d5ec3fSJC Kuo 	index = usb3->base.index;
256423d5ec3fSJC Kuo 
256523d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
256623d5ec3fSJC Kuo 
256723d5ec3fSJC Kuo 	if (!usb3->internal)
256823d5ec3fSJC Kuo 		value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index);
256923d5ec3fSJC Kuo 	else
257023d5ec3fSJC Kuo 		value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index);
257123d5ec3fSJC Kuo 
257223d5ec3fSJC Kuo 	value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(index);
257323d5ec3fSJC Kuo 	value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(index, usb3->port);
257423d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP);
257523d5ec3fSJC Kuo 
257623d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(index));
257723d5ec3fSJC Kuo 	value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_MASK <<
257823d5ec3fSJC Kuo 		   XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT);
257923d5ec3fSJC Kuo 	value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_VAL <<
258023d5ec3fSJC Kuo 		 XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT;
258123d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(index));
258223d5ec3fSJC Kuo 
258323d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(index));
258423d5ec3fSJC Kuo 	value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_MASK <<
258523d5ec3fSJC Kuo 		   XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT);
258623d5ec3fSJC Kuo 	value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_VAL <<
258723d5ec3fSJC Kuo 		 XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT;
258823d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(index));
258923d5ec3fSJC Kuo 
259023d5ec3fSJC Kuo 	padctl_writel(padctl, XUSB_PADCTL_UPHY_USB3_PAD_ECTL3_RX_DFE_VAL,
259123d5ec3fSJC Kuo 		      XUSB_PADCTL_UPHY_USB3_PADX_ECTL3(index));
259223d5ec3fSJC Kuo 
259323d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(index));
259423d5ec3fSJC Kuo 	value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_MASK <<
259523d5ec3fSJC Kuo 		   XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT);
259623d5ec3fSJC Kuo 	value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_VAL <<
259723d5ec3fSJC Kuo 		 XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT;
259823d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(index));
259923d5ec3fSJC Kuo 
260023d5ec3fSJC Kuo 	padctl_writel(padctl, XUSB_PADCTL_UPHY_USB3_PAD_ECTL6_RX_EQ_CTRL_H_VAL,
260123d5ec3fSJC Kuo 		      XUSB_PADCTL_UPHY_USB3_PADX_ECTL6(index));
260223d5ec3fSJC Kuo 
260323d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
260423d5ec3fSJC Kuo 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(index);
260523d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
260623d5ec3fSJC Kuo 
260723d5ec3fSJC Kuo 	usleep_range(100, 200);
260823d5ec3fSJC Kuo 
260923d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
261023d5ec3fSJC Kuo 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(index);
261123d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
261223d5ec3fSJC Kuo 
261323d5ec3fSJC Kuo 	usleep_range(100, 200);
261423d5ec3fSJC Kuo 
261523d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
261623d5ec3fSJC Kuo 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(index);
261723d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
261823d5ec3fSJC Kuo 
261923d5ec3fSJC Kuo 	return 0;
262023d5ec3fSJC Kuo }
262123d5ec3fSJC Kuo 
262223d5ec3fSJC Kuo static int tegra210_usb3_phy_power_off(struct phy *phy)
262323d5ec3fSJC Kuo {
262423d5ec3fSJC Kuo 	struct device *dev = &phy->dev;
262523d5ec3fSJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
262623d5ec3fSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
262723d5ec3fSJC Kuo 	struct tegra_xusb_usb3_port *usb3 = tegra210_lane_to_usb3_port(lane);
262823d5ec3fSJC Kuo 	unsigned int index;
262923d5ec3fSJC Kuo 	u32 value;
263023d5ec3fSJC Kuo 
263123d5ec3fSJC Kuo 	if (!usb3) {
263223d5ec3fSJC Kuo 		dev_err(dev, "no USB3 port found for lane %u\n", lane->index);
263323d5ec3fSJC Kuo 		return -ENODEV;
263423d5ec3fSJC Kuo 	}
263523d5ec3fSJC Kuo 
263623d5ec3fSJC Kuo 	index = usb3->base.index;
263723d5ec3fSJC Kuo 
263823d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
263923d5ec3fSJC Kuo 	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(index);
264023d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
264123d5ec3fSJC Kuo 
264223d5ec3fSJC Kuo 	usleep_range(100, 200);
264323d5ec3fSJC Kuo 
264423d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
264523d5ec3fSJC Kuo 	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(index);
264623d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
264723d5ec3fSJC Kuo 
264823d5ec3fSJC Kuo 	usleep_range(250, 350);
264923d5ec3fSJC Kuo 
265023d5ec3fSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
265123d5ec3fSJC Kuo 	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(index);
265223d5ec3fSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
265323d5ec3fSJC Kuo 
265423d5ec3fSJC Kuo 	return 0;
265523d5ec3fSJC Kuo }
265687d66f28SThierry Reding static struct tegra_xusb_lane *
265787d66f28SThierry Reding tegra210_pcie_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
265887d66f28SThierry Reding 			 unsigned int index)
265987d66f28SThierry Reding {
266087d66f28SThierry Reding 	struct tegra_xusb_pcie_lane *pcie;
266187d66f28SThierry Reding 	int err;
266287d66f28SThierry Reding 
266387d66f28SThierry Reding 	pcie = kzalloc(sizeof(*pcie), GFP_KERNEL);
266487d66f28SThierry Reding 	if (!pcie)
266587d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
266687d66f28SThierry Reding 
266787d66f28SThierry Reding 	INIT_LIST_HEAD(&pcie->base.list);
266887d66f28SThierry Reding 	pcie->base.soc = &pad->soc->lanes[index];
266987d66f28SThierry Reding 	pcie->base.index = index;
267087d66f28SThierry Reding 	pcie->base.pad = pad;
267187d66f28SThierry Reding 	pcie->base.np = np;
267287d66f28SThierry Reding 
267387d66f28SThierry Reding 	err = tegra_xusb_lane_parse_dt(&pcie->base, np);
267487d66f28SThierry Reding 	if (err < 0) {
267587d66f28SThierry Reding 		kfree(pcie);
267687d66f28SThierry Reding 		return ERR_PTR(err);
267787d66f28SThierry Reding 	}
267887d66f28SThierry Reding 
267987d66f28SThierry Reding 	return &pcie->base;
268087d66f28SThierry Reding }
268187d66f28SThierry Reding 
268287d66f28SThierry Reding static void tegra210_pcie_lane_remove(struct tegra_xusb_lane *lane)
268387d66f28SThierry Reding {
268487d66f28SThierry Reding 	struct tegra_xusb_pcie_lane *pcie = to_pcie_lane(lane);
268587d66f28SThierry Reding 
268687d66f28SThierry Reding 	kfree(pcie);
268787d66f28SThierry Reding }
268887d66f28SThierry Reding 
268987d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_pcie_lane_ops = {
269087d66f28SThierry Reding 	.probe = tegra210_pcie_lane_probe,
269187d66f28SThierry Reding 	.remove = tegra210_pcie_lane_remove,
2692c339605cSJC Kuo 	.iddq_enable = tegra210_uphy_lane_iddq_enable,
2693c339605cSJC Kuo 	.iddq_disable = tegra210_uphy_lane_iddq_disable,
2694*2d102148SJC Kuo 	.enable_phy_sleepwalk = tegra210_usb3_enable_phy_sleepwalk,
2695*2d102148SJC Kuo 	.disable_phy_sleepwalk = tegra210_usb3_disable_phy_sleepwalk,
2696*2d102148SJC Kuo 	.enable_phy_wake = tegra210_usb3_enable_phy_wake,
2697*2d102148SJC Kuo 	.disable_phy_wake = tegra210_usb3_disable_phy_wake,
2698*2d102148SJC Kuo 	.remote_wake_detected = tegra210_usb3_phy_remote_wake_detected,
269987d66f28SThierry Reding };
270087d66f28SThierry Reding 
270187d66f28SThierry Reding static int tegra210_pcie_phy_init(struct phy *phy)
270287d66f28SThierry Reding {
270387d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
27042352fdb0SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
270587d66f28SThierry Reding 
27062352fdb0SJC Kuo 	mutex_lock(&padctl->lock);
270787d66f28SThierry Reding 
27082352fdb0SJC Kuo 	tegra210_uphy_init(padctl);
270987d66f28SThierry Reding 
27102352fdb0SJC Kuo 	mutex_unlock(&padctl->lock);
27112352fdb0SJC Kuo 
27122352fdb0SJC Kuo 	return 0;
271387d66f28SThierry Reding }
271487d66f28SThierry Reding 
271587d66f28SThierry Reding static int tegra210_pcie_phy_power_on(struct phy *phy)
271687d66f28SThierry Reding {
271787d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
271887d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
27192352fdb0SJC Kuo 	int err = 0;
272087d66f28SThierry Reding 
272187d66f28SThierry Reding 	mutex_lock(&padctl->lock);
272287d66f28SThierry Reding 
272323d5ec3fSJC Kuo 	if (tegra_xusb_lane_check(lane, "usb3-ss"))
272423d5ec3fSJC Kuo 		err = tegra210_usb3_phy_power_on(phy);
272523d5ec3fSJC Kuo 
272687d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
272787d66f28SThierry Reding 	return err;
272887d66f28SThierry Reding }
272987d66f28SThierry Reding 
273087d66f28SThierry Reding static int tegra210_pcie_phy_power_off(struct phy *phy)
273187d66f28SThierry Reding {
273287d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
273387d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
273423d5ec3fSJC Kuo 	int err = 0;
273587d66f28SThierry Reding 
273623d5ec3fSJC Kuo 	mutex_lock(&padctl->lock);
273723d5ec3fSJC Kuo 
273823d5ec3fSJC Kuo 	if (tegra_xusb_lane_check(lane, "usb3-ss"))
273923d5ec3fSJC Kuo 		err = tegra210_usb3_phy_power_off(phy);
274023d5ec3fSJC Kuo 
274123d5ec3fSJC Kuo 	mutex_unlock(&padctl->lock);
274223d5ec3fSJC Kuo 	return err;
274387d66f28SThierry Reding }
274487d66f28SThierry Reding 
274587d66f28SThierry Reding static const struct phy_ops tegra210_pcie_phy_ops = {
274687d66f28SThierry Reding 	.init = tegra210_pcie_phy_init,
274787d66f28SThierry Reding 	.power_on = tegra210_pcie_phy_power_on,
274887d66f28SThierry Reding 	.power_off = tegra210_pcie_phy_power_off,
274987d66f28SThierry Reding 	.owner = THIS_MODULE,
275087d66f28SThierry Reding };
275187d66f28SThierry Reding 
275287d66f28SThierry Reding static struct tegra_xusb_pad *
275387d66f28SThierry Reding tegra210_pcie_pad_probe(struct tegra_xusb_padctl *padctl,
275487d66f28SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
275587d66f28SThierry Reding 			struct device_node *np)
275687d66f28SThierry Reding {
275787d66f28SThierry Reding 	struct tegra_xusb_pcie_pad *pcie;
275887d66f28SThierry Reding 	struct tegra_xusb_pad *pad;
275987d66f28SThierry Reding 	int err;
276087d66f28SThierry Reding 
276187d66f28SThierry Reding 	pcie = kzalloc(sizeof(*pcie), GFP_KERNEL);
276287d66f28SThierry Reding 	if (!pcie)
276387d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
276487d66f28SThierry Reding 
276587d66f28SThierry Reding 	pad = &pcie->base;
276687d66f28SThierry Reding 	pad->ops = &tegra210_pcie_lane_ops;
276787d66f28SThierry Reding 	pad->soc = soc;
276887d66f28SThierry Reding 
276987d66f28SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
277087d66f28SThierry Reding 	if (err < 0) {
277187d66f28SThierry Reding 		kfree(pcie);
277287d66f28SThierry Reding 		goto out;
277387d66f28SThierry Reding 	}
277487d66f28SThierry Reding 
277587d66f28SThierry Reding 	pcie->pll = devm_clk_get(&pad->dev, "pll");
277687d66f28SThierry Reding 	if (IS_ERR(pcie->pll)) {
277787d66f28SThierry Reding 		err = PTR_ERR(pcie->pll);
277887d66f28SThierry Reding 		dev_err(&pad->dev, "failed to get PLL: %d\n", err);
277987d66f28SThierry Reding 		goto unregister;
278087d66f28SThierry Reding 	}
278187d66f28SThierry Reding 
278287d66f28SThierry Reding 	pcie->rst = devm_reset_control_get(&pad->dev, "phy");
278387d66f28SThierry Reding 	if (IS_ERR(pcie->rst)) {
278487d66f28SThierry Reding 		err = PTR_ERR(pcie->rst);
278587d66f28SThierry Reding 		dev_err(&pad->dev, "failed to get PCIe pad reset: %d\n", err);
278687d66f28SThierry Reding 		goto unregister;
278787d66f28SThierry Reding 	}
278887d66f28SThierry Reding 
278987d66f28SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra210_pcie_phy_ops);
279087d66f28SThierry Reding 	if (err < 0)
279187d66f28SThierry Reding 		goto unregister;
279287d66f28SThierry Reding 
279387d66f28SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
279487d66f28SThierry Reding 
279587d66f28SThierry Reding 	return pad;
279687d66f28SThierry Reding 
279787d66f28SThierry Reding unregister:
279887d66f28SThierry Reding 	device_unregister(&pad->dev);
279987d66f28SThierry Reding out:
280087d66f28SThierry Reding 	return ERR_PTR(err);
280187d66f28SThierry Reding }
280287d66f28SThierry Reding 
280387d66f28SThierry Reding static void tegra210_pcie_pad_remove(struct tegra_xusb_pad *pad)
280487d66f28SThierry Reding {
280587d66f28SThierry Reding 	struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(pad);
280687d66f28SThierry Reding 
280787d66f28SThierry Reding 	kfree(pcie);
280887d66f28SThierry Reding }
280987d66f28SThierry Reding 
281087d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_pcie_ops = {
281187d66f28SThierry Reding 	.probe = tegra210_pcie_pad_probe,
281287d66f28SThierry Reding 	.remove = tegra210_pcie_pad_remove,
281387d66f28SThierry Reding };
281487d66f28SThierry Reding 
281587d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_pcie_pad = {
281687d66f28SThierry Reding 	.name = "pcie",
281787d66f28SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra210_pcie_lanes),
281887d66f28SThierry Reding 	.lanes = tegra210_pcie_lanes,
281987d66f28SThierry Reding 	.ops = &tegra210_pcie_ops,
282087d66f28SThierry Reding };
282187d66f28SThierry Reding 
282287d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_sata_lanes[] = {
2823c339605cSJC Kuo 	TEGRA210_UPHY_LANE("sata-0", 0x028, 30, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2),
282487d66f28SThierry Reding };
282587d66f28SThierry Reding 
282687d66f28SThierry Reding static struct tegra_xusb_lane *
282787d66f28SThierry Reding tegra210_sata_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
282887d66f28SThierry Reding 			 unsigned int index)
282987d66f28SThierry Reding {
283087d66f28SThierry Reding 	struct tegra_xusb_sata_lane *sata;
283187d66f28SThierry Reding 	int err;
283287d66f28SThierry Reding 
283387d66f28SThierry Reding 	sata = kzalloc(sizeof(*sata), GFP_KERNEL);
283487d66f28SThierry Reding 	if (!sata)
283587d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
283687d66f28SThierry Reding 
283787d66f28SThierry Reding 	INIT_LIST_HEAD(&sata->base.list);
283887d66f28SThierry Reding 	sata->base.soc = &pad->soc->lanes[index];
283987d66f28SThierry Reding 	sata->base.index = index;
284087d66f28SThierry Reding 	sata->base.pad = pad;
284187d66f28SThierry Reding 	sata->base.np = np;
284287d66f28SThierry Reding 
284387d66f28SThierry Reding 	err = tegra_xusb_lane_parse_dt(&sata->base, np);
284487d66f28SThierry Reding 	if (err < 0) {
284587d66f28SThierry Reding 		kfree(sata);
284687d66f28SThierry Reding 		return ERR_PTR(err);
284787d66f28SThierry Reding 	}
284887d66f28SThierry Reding 
284987d66f28SThierry Reding 	return &sata->base;
285087d66f28SThierry Reding }
285187d66f28SThierry Reding 
285287d66f28SThierry Reding static void tegra210_sata_lane_remove(struct tegra_xusb_lane *lane)
285387d66f28SThierry Reding {
285487d66f28SThierry Reding 	struct tegra_xusb_sata_lane *sata = to_sata_lane(lane);
285587d66f28SThierry Reding 
285687d66f28SThierry Reding 	kfree(sata);
285787d66f28SThierry Reding }
285887d66f28SThierry Reding 
285987d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_sata_lane_ops = {
286087d66f28SThierry Reding 	.probe = tegra210_sata_lane_probe,
286187d66f28SThierry Reding 	.remove = tegra210_sata_lane_remove,
2862c339605cSJC Kuo 	.iddq_enable = tegra210_uphy_lane_iddq_enable,
2863c339605cSJC Kuo 	.iddq_disable = tegra210_uphy_lane_iddq_disable,
2864*2d102148SJC Kuo 	.enable_phy_sleepwalk = tegra210_usb3_enable_phy_sleepwalk,
2865*2d102148SJC Kuo 	.disable_phy_sleepwalk = tegra210_usb3_disable_phy_sleepwalk,
2866*2d102148SJC Kuo 	.enable_phy_wake = tegra210_usb3_enable_phy_wake,
2867*2d102148SJC Kuo 	.disable_phy_wake = tegra210_usb3_disable_phy_wake,
2868*2d102148SJC Kuo 	.remote_wake_detected = tegra210_usb3_phy_remote_wake_detected,
286987d66f28SThierry Reding };
287087d66f28SThierry Reding 
287187d66f28SThierry Reding static int tegra210_sata_phy_init(struct phy *phy)
287287d66f28SThierry Reding {
287387d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
28742352fdb0SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
287587d66f28SThierry Reding 
28762352fdb0SJC Kuo 	mutex_lock(&padctl->lock);
287787d66f28SThierry Reding 
28782352fdb0SJC Kuo 	tegra210_uphy_init(padctl);
287987d66f28SThierry Reding 
28802352fdb0SJC Kuo 	mutex_unlock(&padctl->lock);
28812352fdb0SJC Kuo 	return 0;
288287d66f28SThierry Reding }
288387d66f28SThierry Reding 
288487d66f28SThierry Reding static int tegra210_sata_phy_power_on(struct phy *phy)
288587d66f28SThierry Reding {
288687d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
288787d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
28882352fdb0SJC Kuo 	int err = 0;
288987d66f28SThierry Reding 
289087d66f28SThierry Reding 	mutex_lock(&padctl->lock);
289187d66f28SThierry Reding 
289223d5ec3fSJC Kuo 	if (tegra_xusb_lane_check(lane, "usb3-ss"))
289323d5ec3fSJC Kuo 		err = tegra210_usb3_phy_power_on(phy);
289423d5ec3fSJC Kuo 
289587d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
289687d66f28SThierry Reding 	return err;
289787d66f28SThierry Reding }
289887d66f28SThierry Reding 
289987d66f28SThierry Reding static int tegra210_sata_phy_power_off(struct phy *phy)
290087d66f28SThierry Reding {
290187d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
290287d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
290323d5ec3fSJC Kuo 	int err = 0;
290487d66f28SThierry Reding 
290523d5ec3fSJC Kuo 	mutex_lock(&padctl->lock);
290623d5ec3fSJC Kuo 
290723d5ec3fSJC Kuo 	if (tegra_xusb_lane_check(lane, "usb3-ss"))
290823d5ec3fSJC Kuo 		err = tegra210_usb3_phy_power_off(phy);
290923d5ec3fSJC Kuo 
291023d5ec3fSJC Kuo 	mutex_unlock(&padctl->lock);
291123d5ec3fSJC Kuo 	return err;
291287d66f28SThierry Reding }
291387d66f28SThierry Reding 
291487d66f28SThierry Reding static const struct phy_ops tegra210_sata_phy_ops = {
291587d66f28SThierry Reding 	.init = tegra210_sata_phy_init,
291687d66f28SThierry Reding 	.power_on = tegra210_sata_phy_power_on,
291787d66f28SThierry Reding 	.power_off = tegra210_sata_phy_power_off,
291887d66f28SThierry Reding 	.owner = THIS_MODULE,
291987d66f28SThierry Reding };
292087d66f28SThierry Reding 
292187d66f28SThierry Reding static struct tegra_xusb_pad *
292287d66f28SThierry Reding tegra210_sata_pad_probe(struct tegra_xusb_padctl *padctl,
292387d66f28SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
292487d66f28SThierry Reding 			struct device_node *np)
292587d66f28SThierry Reding {
292687d66f28SThierry Reding 	struct tegra_xusb_sata_pad *sata;
292787d66f28SThierry Reding 	struct tegra_xusb_pad *pad;
292887d66f28SThierry Reding 	int err;
292987d66f28SThierry Reding 
293087d66f28SThierry Reding 	sata = kzalloc(sizeof(*sata), GFP_KERNEL);
293187d66f28SThierry Reding 	if (!sata)
293287d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
293387d66f28SThierry Reding 
293487d66f28SThierry Reding 	pad = &sata->base;
293587d66f28SThierry Reding 	pad->ops = &tegra210_sata_lane_ops;
293687d66f28SThierry Reding 	pad->soc = soc;
293787d66f28SThierry Reding 
293887d66f28SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
293987d66f28SThierry Reding 	if (err < 0) {
294087d66f28SThierry Reding 		kfree(sata);
294187d66f28SThierry Reding 		goto out;
294287d66f28SThierry Reding 	}
294387d66f28SThierry Reding 
294487d66f28SThierry Reding 	sata->rst = devm_reset_control_get(&pad->dev, "phy");
294587d66f28SThierry Reding 	if (IS_ERR(sata->rst)) {
294687d66f28SThierry Reding 		err = PTR_ERR(sata->rst);
294787d66f28SThierry Reding 		dev_err(&pad->dev, "failed to get SATA pad reset: %d\n", err);
294887d66f28SThierry Reding 		goto unregister;
294987d66f28SThierry Reding 	}
295087d66f28SThierry Reding 
295187d66f28SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra210_sata_phy_ops);
295287d66f28SThierry Reding 	if (err < 0)
295387d66f28SThierry Reding 		goto unregister;
295487d66f28SThierry Reding 
295587d66f28SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
295687d66f28SThierry Reding 
295787d66f28SThierry Reding 	return pad;
295887d66f28SThierry Reding 
295987d66f28SThierry Reding unregister:
296087d66f28SThierry Reding 	device_unregister(&pad->dev);
296187d66f28SThierry Reding out:
296287d66f28SThierry Reding 	return ERR_PTR(err);
296387d66f28SThierry Reding }
296487d66f28SThierry Reding 
296587d66f28SThierry Reding static void tegra210_sata_pad_remove(struct tegra_xusb_pad *pad)
296687d66f28SThierry Reding {
296787d66f28SThierry Reding 	struct tegra_xusb_sata_pad *sata = to_sata_pad(pad);
296887d66f28SThierry Reding 
296987d66f28SThierry Reding 	kfree(sata);
297087d66f28SThierry Reding }
297187d66f28SThierry Reding 
297287d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_sata_ops = {
297387d66f28SThierry Reding 	.probe = tegra210_sata_pad_probe,
297487d66f28SThierry Reding 	.remove = tegra210_sata_pad_remove,
297587d66f28SThierry Reding };
297687d66f28SThierry Reding 
297787d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_sata_pad = {
297887d66f28SThierry Reding 	.name = "sata",
297987d66f28SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra210_sata_lanes),
298087d66f28SThierry Reding 	.lanes = tegra210_sata_lanes,
298187d66f28SThierry Reding 	.ops = &tegra210_sata_ops,
298287d66f28SThierry Reding };
298387d66f28SThierry Reding 
298487d66f28SThierry Reding static const struct tegra_xusb_pad_soc * const tegra210_pads[] = {
298587d66f28SThierry Reding 	&tegra210_usb2_pad,
298687d66f28SThierry Reding 	&tegra210_hsic_pad,
298787d66f28SThierry Reding 	&tegra210_pcie_pad,
298887d66f28SThierry Reding 	&tegra210_sata_pad,
298987d66f28SThierry Reding };
299087d66f28SThierry Reding 
299187d66f28SThierry Reding static int tegra210_usb2_port_enable(struct tegra_xusb_port *port)
299287d66f28SThierry Reding {
299387d66f28SThierry Reding 	return 0;
299487d66f28SThierry Reding }
299587d66f28SThierry Reding 
299687d66f28SThierry Reding static void tegra210_usb2_port_disable(struct tegra_xusb_port *port)
299787d66f28SThierry Reding {
299887d66f28SThierry Reding }
299987d66f28SThierry Reding 
300087d66f28SThierry Reding static struct tegra_xusb_lane *
300187d66f28SThierry Reding tegra210_usb2_port_map(struct tegra_xusb_port *port)
300287d66f28SThierry Reding {
300387d66f28SThierry Reding 	return tegra_xusb_find_lane(port->padctl, "usb2", port->index);
300487d66f28SThierry Reding }
300587d66f28SThierry Reding 
300687d66f28SThierry Reding static const struct tegra_xusb_port_ops tegra210_usb2_port_ops = {
3007e78fdbadSThierry Reding 	.release = tegra_xusb_usb2_port_release,
30082f8da84dSThierry Reding 	.remove = tegra_xusb_usb2_port_remove,
300987d66f28SThierry Reding 	.enable = tegra210_usb2_port_enable,
301087d66f28SThierry Reding 	.disable = tegra210_usb2_port_disable,
301187d66f28SThierry Reding 	.map = tegra210_usb2_port_map,
301287d66f28SThierry Reding };
301387d66f28SThierry Reding 
301487d66f28SThierry Reding static int tegra210_hsic_port_enable(struct tegra_xusb_port *port)
301587d66f28SThierry Reding {
301687d66f28SThierry Reding 	return 0;
301787d66f28SThierry Reding }
301887d66f28SThierry Reding 
301987d66f28SThierry Reding static void tegra210_hsic_port_disable(struct tegra_xusb_port *port)
302087d66f28SThierry Reding {
302187d66f28SThierry Reding }
302287d66f28SThierry Reding 
302387d66f28SThierry Reding static struct tegra_xusb_lane *
302487d66f28SThierry Reding tegra210_hsic_port_map(struct tegra_xusb_port *port)
302587d66f28SThierry Reding {
302687d66f28SThierry Reding 	return tegra_xusb_find_lane(port->padctl, "hsic", port->index);
302787d66f28SThierry Reding }
302887d66f28SThierry Reding 
302987d66f28SThierry Reding static const struct tegra_xusb_port_ops tegra210_hsic_port_ops = {
3030e78fdbadSThierry Reding 	.release = tegra_xusb_hsic_port_release,
303187d66f28SThierry Reding 	.enable = tegra210_hsic_port_enable,
303287d66f28SThierry Reding 	.disable = tegra210_hsic_port_disable,
303387d66f28SThierry Reding 	.map = tegra210_hsic_port_map,
303487d66f28SThierry Reding };
303587d66f28SThierry Reding 
303687d66f28SThierry Reding static int tegra210_usb3_port_enable(struct tegra_xusb_port *port)
303787d66f28SThierry Reding {
303887d66f28SThierry Reding 	return 0;
303987d66f28SThierry Reding }
304087d66f28SThierry Reding 
304187d66f28SThierry Reding static void tegra210_usb3_port_disable(struct tegra_xusb_port *port)
304287d66f28SThierry Reding {
304387d66f28SThierry Reding }
304487d66f28SThierry Reding 
304587d66f28SThierry Reding static struct tegra_xusb_lane *
304687d66f28SThierry Reding tegra210_usb3_port_map(struct tegra_xusb_port *port)
304787d66f28SThierry Reding {
304887d66f28SThierry Reding 	return tegra_xusb_port_find_lane(port, tegra210_usb3_map, "usb3-ss");
304987d66f28SThierry Reding }
305087d66f28SThierry Reding 
305187d66f28SThierry Reding static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = {
3052e78fdbadSThierry Reding 	.release = tegra_xusb_usb3_port_release,
30532f8da84dSThierry Reding 	.remove = tegra_xusb_usb3_port_remove,
305487d66f28SThierry Reding 	.enable = tegra210_usb3_port_enable,
305587d66f28SThierry Reding 	.disable = tegra210_usb3_port_disable,
305687d66f28SThierry Reding 	.map = tegra210_usb3_port_map,
305787d66f28SThierry Reding };
305887d66f28SThierry Reding 
305990767cdfSNagarjuna Kristam static int tegra210_utmi_port_reset(struct phy *phy)
306090767cdfSNagarjuna Kristam {
306190767cdfSNagarjuna Kristam 	struct tegra_xusb_padctl *padctl;
306290767cdfSNagarjuna Kristam 	struct tegra_xusb_lane *lane;
306390767cdfSNagarjuna Kristam 	u32 value;
306490767cdfSNagarjuna Kristam 
306590767cdfSNagarjuna Kristam 	lane = phy_get_drvdata(phy);
306690767cdfSNagarjuna Kristam 	padctl = lane->pad->padctl;
306790767cdfSNagarjuna Kristam 
306890767cdfSNagarjuna Kristam 	value = padctl_readl(padctl,
306990767cdfSNagarjuna Kristam 		     XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL0(lane->index));
307090767cdfSNagarjuna Kristam 
307190767cdfSNagarjuna Kristam 	if ((value & XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIP) ||
307290767cdfSNagarjuna Kristam 	    (value & XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIN)) {
307390767cdfSNagarjuna Kristam 		tegra210_xusb_padctl_vbus_override(padctl, false);
307490767cdfSNagarjuna Kristam 		tegra210_xusb_padctl_vbus_override(padctl, true);
307590767cdfSNagarjuna Kristam 		return 1;
307690767cdfSNagarjuna Kristam 	}
307790767cdfSNagarjuna Kristam 
307890767cdfSNagarjuna Kristam 	return 0;
307990767cdfSNagarjuna Kristam }
308090767cdfSNagarjuna Kristam 
308187d66f28SThierry Reding static int
308287d66f28SThierry Reding tegra210_xusb_read_fuse_calibration(struct tegra210_xusb_fuse_calibration *fuse)
308387d66f28SThierry Reding {
308487d66f28SThierry Reding 	unsigned int i;
308587d66f28SThierry Reding 	u32 value;
308687d66f28SThierry Reding 	int err;
308787d66f28SThierry Reding 
308887d66f28SThierry Reding 	err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value);
308987d66f28SThierry Reding 	if (err < 0)
309087d66f28SThierry Reding 		return err;
309187d66f28SThierry Reding 
309287d66f28SThierry Reding 	for (i = 0; i < ARRAY_SIZE(fuse->hs_curr_level); i++) {
309387d66f28SThierry Reding 		fuse->hs_curr_level[i] =
309487d66f28SThierry Reding 			(value >> FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(i)) &
309587d66f28SThierry Reding 			FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK;
309687d66f28SThierry Reding 	}
309787d66f28SThierry Reding 
309887d66f28SThierry Reding 	fuse->hs_term_range_adj =
309987d66f28SThierry Reding 		(value >> FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT) &
310087d66f28SThierry Reding 		FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK;
310187d66f28SThierry Reding 
310287d66f28SThierry Reding 	err = tegra_fuse_readl(TEGRA_FUSE_USB_CALIB_EXT_0, &value);
310387d66f28SThierry Reding 	if (err < 0)
310487d66f28SThierry Reding 		return err;
310587d66f28SThierry Reding 
310687d66f28SThierry Reding 	fuse->rpd_ctrl =
310787d66f28SThierry Reding 		(value >> FUSE_USB_CALIB_EXT_RPD_CTRL_SHIFT) &
310887d66f28SThierry Reding 		FUSE_USB_CALIB_EXT_RPD_CTRL_MASK;
310987d66f28SThierry Reding 
311087d66f28SThierry Reding 	return 0;
311187d66f28SThierry Reding }
311287d66f28SThierry Reding 
311387d66f28SThierry Reding static struct tegra_xusb_padctl *
311487d66f28SThierry Reding tegra210_xusb_padctl_probe(struct device *dev,
311587d66f28SThierry Reding 			   const struct tegra_xusb_padctl_soc *soc)
311687d66f28SThierry Reding {
311787d66f28SThierry Reding 	struct tegra210_xusb_padctl *padctl;
3118*2d102148SJC Kuo 	struct platform_device *pdev;
3119*2d102148SJC Kuo 	struct device_node *np;
312087d66f28SThierry Reding 	int err;
312187d66f28SThierry Reding 
312287d66f28SThierry Reding 	padctl = devm_kzalloc(dev, sizeof(*padctl), GFP_KERNEL);
312387d66f28SThierry Reding 	if (!padctl)
312487d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
312587d66f28SThierry Reding 
312687d66f28SThierry Reding 	padctl->base.dev = dev;
312787d66f28SThierry Reding 	padctl->base.soc = soc;
312887d66f28SThierry Reding 
312987d66f28SThierry Reding 	err = tegra210_xusb_read_fuse_calibration(&padctl->fuse);
313087d66f28SThierry Reding 	if (err < 0)
313187d66f28SThierry Reding 		return ERR_PTR(err);
313287d66f28SThierry Reding 
3133*2d102148SJC Kuo 	np = of_parse_phandle(dev->of_node, "nvidia,pmc", 0);
3134*2d102148SJC Kuo 	if (!np) {
3135*2d102148SJC Kuo 		dev_warn(dev, "nvidia,pmc property is missing\n");
3136*2d102148SJC Kuo 		goto out;
3137*2d102148SJC Kuo 	}
3138*2d102148SJC Kuo 
3139*2d102148SJC Kuo 	pdev = of_find_device_by_node(np);
3140*2d102148SJC Kuo 	if (!pdev) {
3141*2d102148SJC Kuo 		dev_warn(dev, "PMC device is not available\n");
3142*2d102148SJC Kuo 		goto out;
3143*2d102148SJC Kuo 	}
3144*2d102148SJC Kuo 
3145*2d102148SJC Kuo 	if (!platform_get_drvdata(pdev))
3146*2d102148SJC Kuo 		return ERR_PTR(-EPROBE_DEFER);
3147*2d102148SJC Kuo 
3148*2d102148SJC Kuo 	padctl->regmap = dev_get_regmap(&pdev->dev, "usb_sleepwalk");
3149*2d102148SJC Kuo 	if (!padctl->regmap)
3150*2d102148SJC Kuo 		dev_info(dev, "failed to find PMC regmap\n");
3151*2d102148SJC Kuo 
3152*2d102148SJC Kuo out:
315387d66f28SThierry Reding 	return &padctl->base;
315487d66f28SThierry Reding }
315587d66f28SThierry Reding 
315687d66f28SThierry Reding static void tegra210_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
315787d66f28SThierry Reding {
315887d66f28SThierry Reding }
315987d66f28SThierry Reding 
3160*2d102148SJC Kuo static void tegra210_xusb_padctl_save(struct tegra_xusb_padctl *padctl)
3161*2d102148SJC Kuo {
3162*2d102148SJC Kuo 	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
3163*2d102148SJC Kuo 
3164*2d102148SJC Kuo 	priv->context.usb2_pad_mux =
3165*2d102148SJC Kuo 		padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
3166*2d102148SJC Kuo 	priv->context.usb2_port_cap =
3167*2d102148SJC Kuo 		padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
3168*2d102148SJC Kuo 	priv->context.ss_port_map =
3169*2d102148SJC Kuo 		padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
3170*2d102148SJC Kuo 	priv->context.usb3_pad_mux =
3171*2d102148SJC Kuo 		padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
3172*2d102148SJC Kuo }
3173*2d102148SJC Kuo 
3174*2d102148SJC Kuo static void tegra210_xusb_padctl_restore(struct tegra_xusb_padctl *padctl)
3175*2d102148SJC Kuo {
3176*2d102148SJC Kuo 	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
3177*2d102148SJC Kuo 	struct tegra_xusb_lane *lane;
3178*2d102148SJC Kuo 
3179*2d102148SJC Kuo 	padctl_writel(padctl, priv->context.usb2_pad_mux,
3180*2d102148SJC Kuo 		XUSB_PADCTL_USB2_PAD_MUX);
3181*2d102148SJC Kuo 	padctl_writel(padctl, priv->context.usb2_port_cap,
3182*2d102148SJC Kuo 		XUSB_PADCTL_USB2_PORT_CAP);
3183*2d102148SJC Kuo 	padctl_writel(padctl, priv->context.ss_port_map,
3184*2d102148SJC Kuo 		XUSB_PADCTL_SS_PORT_MAP);
3185*2d102148SJC Kuo 
3186*2d102148SJC Kuo 	list_for_each_entry(lane, &padctl->lanes, list) {
3187*2d102148SJC Kuo 		if (lane->pad->ops->iddq_enable)
3188*2d102148SJC Kuo 			tegra210_uphy_lane_iddq_enable(lane);
3189*2d102148SJC Kuo 	}
3190*2d102148SJC Kuo 
3191*2d102148SJC Kuo 	padctl_writel(padctl, priv->context.usb3_pad_mux,
3192*2d102148SJC Kuo 		XUSB_PADCTL_USB3_PAD_MUX);
3193*2d102148SJC Kuo 
3194*2d102148SJC Kuo 	list_for_each_entry(lane, &padctl->lanes, list) {
3195*2d102148SJC Kuo 		if (lane->pad->ops->iddq_disable)
3196*2d102148SJC Kuo 			tegra210_uphy_lane_iddq_disable(lane);
3197*2d102148SJC Kuo 	}
3198*2d102148SJC Kuo }
3199*2d102148SJC Kuo 
3200*2d102148SJC Kuo static int tegra210_xusb_padctl_suspend_noirq(struct tegra_xusb_padctl *padctl)
3201*2d102148SJC Kuo {
3202*2d102148SJC Kuo 	mutex_lock(&padctl->lock);
3203*2d102148SJC Kuo 
3204*2d102148SJC Kuo 	tegra210_uphy_deinit(padctl);
3205*2d102148SJC Kuo 
3206*2d102148SJC Kuo 	tegra210_xusb_padctl_save(padctl);
3207*2d102148SJC Kuo 
3208*2d102148SJC Kuo 	mutex_unlock(&padctl->lock);
3209*2d102148SJC Kuo 	return 0;
3210*2d102148SJC Kuo }
3211*2d102148SJC Kuo 
3212*2d102148SJC Kuo static int tegra210_xusb_padctl_resume_noirq(struct tegra_xusb_padctl *padctl)
3213*2d102148SJC Kuo {
3214*2d102148SJC Kuo 	mutex_lock(&padctl->lock);
3215*2d102148SJC Kuo 
3216*2d102148SJC Kuo 	tegra210_xusb_padctl_restore(padctl);
3217*2d102148SJC Kuo 
3218*2d102148SJC Kuo 	tegra210_uphy_init(padctl);
3219*2d102148SJC Kuo 
3220*2d102148SJC Kuo 	mutex_unlock(&padctl->lock);
3221*2d102148SJC Kuo 	return 0;
3222*2d102148SJC Kuo }
3223*2d102148SJC Kuo 
322487d66f28SThierry Reding static const struct tegra_xusb_padctl_ops tegra210_xusb_padctl_ops = {
322587d66f28SThierry Reding 	.probe = tegra210_xusb_padctl_probe,
322687d66f28SThierry Reding 	.remove = tegra210_xusb_padctl_remove,
3227*2d102148SJC Kuo 	.suspend_noirq = tegra210_xusb_padctl_suspend_noirq,
3228*2d102148SJC Kuo 	.resume_noirq = tegra210_xusb_padctl_resume_noirq,
322987d66f28SThierry Reding 	.usb3_set_lfps_detect = tegra210_usb3_set_lfps_detect,
323087d66f28SThierry Reding 	.hsic_set_idle = tegra210_hsic_set_idle,
323190767cdfSNagarjuna Kristam 	.vbus_override = tegra210_xusb_padctl_vbus_override,
323290767cdfSNagarjuna Kristam 	.utmi_port_reset = tegra210_utmi_port_reset,
323387d66f28SThierry Reding };
323487d66f28SThierry Reding 
3235e3888cdaSThierry Reding static const char * const tegra210_xusb_padctl_supply_names[] = {
3236e3888cdaSThierry Reding 	"avdd-pll-utmip",
3237e3888cdaSThierry Reding 	"avdd-pll-uerefe",
3238e3888cdaSThierry Reding 	"dvdd-pex-pll",
3239e3888cdaSThierry Reding 	"hvdd-pex-pll-e",
3240e3888cdaSThierry Reding };
3241e3888cdaSThierry Reding 
324287d66f28SThierry Reding const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc = {
324387d66f28SThierry Reding 	.num_pads = ARRAY_SIZE(tegra210_pads),
324487d66f28SThierry Reding 	.pads = tegra210_pads,
324587d66f28SThierry Reding 	.ports = {
324687d66f28SThierry Reding 		.usb2 = {
324787d66f28SThierry Reding 			.ops = &tegra210_usb2_port_ops,
324887d66f28SThierry Reding 			.count = 4,
324987d66f28SThierry Reding 		},
325087d66f28SThierry Reding 		.hsic = {
325187d66f28SThierry Reding 			.ops = &tegra210_hsic_port_ops,
325287d66f28SThierry Reding 			.count = 1,
325387d66f28SThierry Reding 		},
325487d66f28SThierry Reding 		.usb3 = {
325587d66f28SThierry Reding 			.ops = &tegra210_usb3_port_ops,
325687d66f28SThierry Reding 			.count = 4,
325787d66f28SThierry Reding 		},
325887d66f28SThierry Reding 	},
325987d66f28SThierry Reding 	.ops = &tegra210_xusb_padctl_ops,
3260e3888cdaSThierry Reding 	.supply_names = tegra210_xusb_padctl_supply_names,
3261e3888cdaSThierry Reding 	.num_supplies = ARRAY_SIZE(tegra210_xusb_padctl_supply_names),
3262a5be28c3SNagarjuna Kristam 	.need_fake_usb3_port = true,
326387d66f28SThierry Reding };
326487d66f28SThierry Reding EXPORT_SYMBOL_GPL(tegra210_xusb_padctl_soc);
326587d66f28SThierry Reding 
326687d66f28SThierry Reding MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>");
326787d66f28SThierry Reding MODULE_DESCRIPTION("NVIDIA Tegra 210 XUSB Pad Controller driver");
326887d66f28SThierry Reding MODULE_LICENSE("GPL v2");
3269