xref: /linux/drivers/phy/tegra/xusb-tegra210.c (revision de792a6da7f026a5aa047ee62a0fafb1e5d0e6ed)
12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
287d66f28SThierry Reding /*
387d66f28SThierry Reding  * Copyright (c) 2014, 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>
1487d66f28SThierry Reding #include <linux/phy/phy.h>
1587d66f28SThierry Reding #include <linux/platform_device.h>
1687d66f28SThierry Reding #include <linux/regulator/consumer.h>
1787d66f28SThierry Reding #include <linux/reset.h>
1887d66f28SThierry Reding #include <linux/slab.h>
1987d66f28SThierry Reding 
2087d66f28SThierry Reding #include <soc/tegra/fuse.h>
2187d66f28SThierry Reding 
2287d66f28SThierry Reding #include "xusb.h"
2387d66f28SThierry Reding 
2487d66f28SThierry Reding #define FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(x) \
2587d66f28SThierry Reding 					((x) ? (11 + ((x) - 1) * 6) : 0)
2687d66f28SThierry Reding #define FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK 0x3f
2787d66f28SThierry Reding #define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT 7
2887d66f28SThierry Reding #define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK 0xf
2987d66f28SThierry Reding 
3087d66f28SThierry Reding #define FUSE_USB_CALIB_EXT_RPD_CTRL_SHIFT 0
3187d66f28SThierry Reding #define FUSE_USB_CALIB_EXT_RPD_CTRL_MASK 0x1f
3287d66f28SThierry Reding 
3387d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX 0x004
3487d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT 16
3587d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_MASK 0x3
3687d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_XUSB 0x1
3787d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT 18
3887d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK 0x3
3987d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB 0x1
4087d66f28SThierry Reding 
4187d66f28SThierry Reding #define XUSB_PADCTL_USB2_PORT_CAP 0x008
42ac25b6e9SNagarjuna Kristam #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DISABLED(x) (0x0 << ((x) * 4))
4387d66f28SThierry Reding #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(x) (0x1 << ((x) * 4))
44ac25b6e9SNagarjuna Kristam #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DEVICE(x) (0x2 << ((x) * 4))
45ac25b6e9SNagarjuna Kristam #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_OTG(x) (0x3 << ((x) * 4))
4687d66f28SThierry Reding #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(x) (0x3 << ((x) * 4))
4787d66f28SThierry Reding 
4887d66f28SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP 0x014
4987d66f28SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(x) (1 << (((x) * 5) + 4))
5087d66f28SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_SHIFT(x) ((x) * 5)
5187d66f28SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(x) (0x7 << ((x) * 5))
5287d66f28SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(x, v) (((v) & 0x7) << ((x) * 5))
53a5be28c3SNagarjuna Kristam #define XUSB_PADCTL_SS_PORT_MAP_PORT_DISABLED 0x7
5487d66f28SThierry Reding 
5587d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1 0x024
5687d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN (1 << 31)
5787d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 30)
5887d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN (1 << 29)
5987d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(x) (1 << (2 + (x) * 3))
6087d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(x) \
6187d66f28SThierry Reding 							(1 << (1 + (x) * 3))
6287d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(x) (1 << ((x) * 3))
6387d66f28SThierry Reding 
6487d66f28SThierry Reding #define XUSB_PADCTL_USB3_PAD_MUX 0x028
6587d66f28SThierry Reding #define XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(x) (1 << (1 + (x)))
6687d66f28SThierry Reding #define XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(x) (1 << (8 + (x)))
6787d66f28SThierry Reding 
6890767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL0(x) (0x080 + (x) * 0x40)
6990767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIP (1 << 18)
7090767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIN (1 << 22)
7190767cdfSNagarjuna Kristam 
7287d66f28SThierry Reding #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(x) (0x084 + (x) * 0x40)
7387d66f28SThierry Reding #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT 7
7487d66f28SThierry Reding #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_MASK 0x3
75ac25b6e9SNagarjuna Kristam #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_VAL 0x1
7687d66f28SThierry Reding #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18 (1 << 6)
7787d66f28SThierry Reding 
7887d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x088 + (x) * 0x40)
7987d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI (1 << 29)
8087d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 (1 << 27)
8187d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD (1 << 26)
8287d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT 0
8387d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK 0x3f
8487d66f28SThierry Reding 
8587d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PADX_CTL1(x) (0x08c + (x) * 0x40)
8687d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT 26
8787d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_MASK 0x1f
8887d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT 3
8987d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK 0xf
9087d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2)
9187d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD (1 << 1)
9287d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD (1 << 0)
9387d66f28SThierry Reding 
9487d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x284
9587d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 11)
9687d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT 3
9787d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK 0x7
9887d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL 0x7
9987d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT 0
10087d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK 0x7
10187d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_VAL 0x2
10287d66f28SThierry Reding 
10387d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1 0x288
10487d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_PD_TRK (1 << 26)
10587d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT 19
10687d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_MASK 0x7f
10787d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_VAL 0x0a
10887d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT 12
10987d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK 0x7f
11087d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL 0x1e
11187d66f28SThierry Reding 
11287d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x300 + (x) * 0x20)
11387d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE (1 << 18)
11487d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA1 (1 << 17)
11587d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA0 (1 << 16)
11687d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPD_STROBE (1 << 15)
11787d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 (1 << 14)
11887d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 (1 << 13)
11987d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE (1 << 9)
12087d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 (1 << 8)
12187d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 (1 << 7)
12287d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE (1 << 6)
12387d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 (1 << 5)
12487d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 (1 << 4)
12587d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE (1 << 3)
12687d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 (1 << 2)
12787d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 (1 << 1)
12887d66f28SThierry Reding 
12987d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PADX_CTL1(x) (0x304 + (x) * 0x20)
13087d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT 0
13187d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_MASK 0xf
13287d66f28SThierry Reding 
13387d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PADX_CTL2(x) (0x308 + (x) * 0x20)
13487d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT 8
13587d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK 0xf
13687d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT 0
13787d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK 0xff
13887d66f28SThierry Reding 
13987d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL 0x340
14087d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_PD_TRK (1 << 19)
14187d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT 12
14287d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_MASK 0x7f
14387d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_VAL 0x0a
14487d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT 5
14587d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_MASK 0x7f
14687d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_VAL 0x1e
14787d66f28SThierry Reding 
14887d66f28SThierry Reding #define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL 0x344
14987d66f28SThierry Reding 
15087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_P0_CTL1 0x360
15187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT 20
15287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_MASK 0xff
15387d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_USB_VAL 0x19
15487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SATA_VAL 0x1e
15587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_SHIFT 16
15687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK 0x3
15787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_LOCKDET_STATUS (1 << 15)
15887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD (1 << 4)
15987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_ENABLE (1 << 3)
16087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_SHIFT 1
16187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_MASK 0x3
16287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_IDDQ (1 << 0)
16387d66f28SThierry Reding 
16487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_P0_CTL2 0x364
16587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT 4
16687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK 0xffffff
16787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_VAL 0x136
16887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD (1 << 2)
16987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE (1 << 1)
17087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN (1 << 0)
17187d66f28SThierry Reding 
17287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_P0_CTL4 0x36c
173e7f4da4cSThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_XDIGCLK_EN (1 << 19)
17487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN (1 << 15)
17587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT 12
17687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK 0x3
17787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_USB_VAL 0x2
17887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SATA_VAL 0x0
17987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_REFCLKBUF_EN (1 << 8)
18087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_SHIFT 4
18187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_MASK 0xf
18287d66f28SThierry Reding 
18387d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_P0_CTL5 0x370
18487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT 16
18587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_MASK 0xff
18687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_VAL 0x2a
18787d66f28SThierry Reding 
18887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_P0_CTL8 0x37c
18987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE (1 << 31)
19087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD (1 << 15)
19187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN (1 << 13)
19287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN (1 << 12)
19387d66f28SThierry Reding 
19487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL1(x) (0x460 + (x) * 0x40)
19587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT 20
19687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_MASK 0x3
19787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_VAL 0x1
19887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN BIT(18)
19987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD BIT(13)
20087d66f28SThierry Reding 
20187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_S0_CTL1 0x860
20287d66f28SThierry Reding 
20387d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_S0_CTL2 0x864
20487d66f28SThierry Reding 
20587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_S0_CTL4 0x86c
20687d66f28SThierry Reding 
20787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_S0_CTL5 0x870
20887d66f28SThierry Reding 
20987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_S0_CTL8 0x87c
21087d66f28SThierry Reding 
21187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1 0x960
21287d66f28SThierry Reding 
21387d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(x) (0xa60 + (x) * 0x40)
21487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT 16
21587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_MASK 0x3
21687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_VAL 0x2
21787d66f28SThierry Reding 
21887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(x) (0xa64 + (x) * 0x40)
21987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT 0
22087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_MASK 0xffff
22187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_VAL 0x00fc
22287d66f28SThierry Reding 
22387d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL3(x) (0xa68 + (x) * 0x40)
22487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL3_RX_DFE_VAL 0xc0077f1f
22587d66f28SThierry Reding 
22687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(x) (0xa6c + (x) * 0x40)
22787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT 16
22887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_MASK 0xffff
22987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_VAL 0x01c7
23087d66f28SThierry Reding 
23187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL6(x) (0xa74 + (x) * 0x40)
23287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL6_RX_EQ_CTRL_H_VAL 0xfcf01368
23387d66f28SThierry Reding 
23490767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID 0xc60
23590767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON (1 << 14)
23690767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT 18
23790767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK 0xf
23890767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING 8
239*de792a6dSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED 0
24090767cdfSNagarjuna Kristam 
24187d66f28SThierry Reding struct tegra210_xusb_fuse_calibration {
24287d66f28SThierry Reding 	u32 hs_curr_level[4];
24387d66f28SThierry Reding 	u32 hs_term_range_adj;
24487d66f28SThierry Reding 	u32 rpd_ctrl;
24587d66f28SThierry Reding };
24687d66f28SThierry Reding 
24787d66f28SThierry Reding struct tegra210_xusb_padctl {
24887d66f28SThierry Reding 	struct tegra_xusb_padctl base;
24987d66f28SThierry Reding 
25087d66f28SThierry Reding 	struct tegra210_xusb_fuse_calibration fuse;
25187d66f28SThierry Reding };
25287d66f28SThierry Reding 
25387d66f28SThierry Reding static inline struct tegra210_xusb_padctl *
25487d66f28SThierry Reding to_tegra210_xusb_padctl(struct tegra_xusb_padctl *padctl)
25587d66f28SThierry Reding {
25687d66f28SThierry Reding 	return container_of(padctl, struct tegra210_xusb_padctl, base);
25787d66f28SThierry Reding }
25887d66f28SThierry Reding 
25987d66f28SThierry Reding /* must be called under padctl->lock */
26087d66f28SThierry Reding static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl)
26187d66f28SThierry Reding {
26287d66f28SThierry Reding 	struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(padctl->pcie);
26387d66f28SThierry Reding 	unsigned long timeout;
26487d66f28SThierry Reding 	u32 value;
26587d66f28SThierry Reding 	int err;
26687d66f28SThierry Reding 
26787d66f28SThierry Reding 	if (pcie->enable > 0) {
26887d66f28SThierry Reding 		pcie->enable++;
26987d66f28SThierry Reding 		return 0;
27087d66f28SThierry Reding 	}
27187d66f28SThierry Reding 
27287d66f28SThierry Reding 	err = clk_prepare_enable(pcie->pll);
27387d66f28SThierry Reding 	if (err < 0)
27487d66f28SThierry Reding 		return err;
27587d66f28SThierry Reding 
27687d66f28SThierry Reding 	err = reset_control_deassert(pcie->rst);
27787d66f28SThierry Reding 	if (err < 0)
27887d66f28SThierry Reding 		goto disable;
27987d66f28SThierry Reding 
28087d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
28187d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK <<
28287d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT);
28387d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_VAL <<
28487d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT;
28587d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
28687d66f28SThierry Reding 
28787d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL5);
28887d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_MASK <<
28987d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT);
29087d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_VAL <<
29187d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT;
29287d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL5);
29387d66f28SThierry Reding 
29487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
29587d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD;
29687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
29787d66f28SThierry Reding 
29887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
29987d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD;
30087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
30187d66f28SThierry Reding 
30287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
30387d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD;
30487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
30587d66f28SThierry Reding 
30687d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL4);
30787d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK <<
30887d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT) |
30987d66f28SThierry Reding 		   (XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_MASK <<
31087d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_SHIFT));
31187d66f28SThierry Reding 	value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_USB_VAL <<
31287d66f28SThierry Reding 		  XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT) |
31387d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN;
31487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL4);
31587d66f28SThierry Reding 
31687d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
31787d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK <<
31887d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_SHIFT) |
31987d66f28SThierry Reding 		   (XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_MASK <<
32087d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT));
32187d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_USB_VAL <<
32287d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT;
32387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
32487d66f28SThierry Reding 
32587d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
32687d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_IDDQ;
32787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
32887d66f28SThierry Reding 
32987d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
33087d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_MASK <<
33187d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_SHIFT);
33287d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
33387d66f28SThierry Reding 
33487d66f28SThierry Reding 	usleep_range(10, 20);
33587d66f28SThierry Reding 
33687d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL4);
33787d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL4_REFCLKBUF_EN;
33887d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL4);
33987d66f28SThierry Reding 
34087d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
34187d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN;
34287d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
34387d66f28SThierry Reding 
34487d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
34587d66f28SThierry Reding 
34687d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
34787d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
34887d66f28SThierry Reding 		if (value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE)
34987d66f28SThierry Reding 			break;
35087d66f28SThierry Reding 
35187d66f28SThierry Reding 		usleep_range(10, 20);
35287d66f28SThierry Reding 	}
35387d66f28SThierry Reding 
35487d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
35587d66f28SThierry Reding 		err = -ETIMEDOUT;
35687d66f28SThierry Reding 		goto reset;
35787d66f28SThierry Reding 	}
35887d66f28SThierry Reding 
35987d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
36087d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN;
36187d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
36287d66f28SThierry Reding 
36387d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
36487d66f28SThierry Reding 
36587d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
36687d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
36787d66f28SThierry Reding 		if (!(value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE))
36887d66f28SThierry Reding 			break;
36987d66f28SThierry Reding 
37087d66f28SThierry Reding 		usleep_range(10, 20);
37187d66f28SThierry Reding 	}
37287d66f28SThierry Reding 
37387d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
37487d66f28SThierry Reding 		err = -ETIMEDOUT;
37587d66f28SThierry Reding 		goto reset;
37687d66f28SThierry Reding 	}
37787d66f28SThierry Reding 
37887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
37987d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL1_ENABLE;
38087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
38187d66f28SThierry Reding 
38287d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
38387d66f28SThierry Reding 
38487d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
38587d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
38687d66f28SThierry Reding 		if (value & XUSB_PADCTL_UPHY_PLL_CTL1_LOCKDET_STATUS)
38787d66f28SThierry Reding 			break;
38887d66f28SThierry Reding 
38987d66f28SThierry Reding 		usleep_range(10, 20);
39087d66f28SThierry Reding 	}
39187d66f28SThierry Reding 
39287d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
39387d66f28SThierry Reding 		err = -ETIMEDOUT;
39487d66f28SThierry Reding 		goto reset;
39587d66f28SThierry Reding 	}
39687d66f28SThierry Reding 
39787d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
39887d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN |
39987d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN;
40087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
40187d66f28SThierry Reding 
40287d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
40387d66f28SThierry Reding 
40487d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
40587d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
40687d66f28SThierry Reding 		if (value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE)
40787d66f28SThierry Reding 			break;
40887d66f28SThierry Reding 
40987d66f28SThierry Reding 		usleep_range(10, 20);
41087d66f28SThierry Reding 	}
41187d66f28SThierry Reding 
41287d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
41387d66f28SThierry Reding 		err = -ETIMEDOUT;
41487d66f28SThierry Reding 		goto reset;
41587d66f28SThierry Reding 	}
41687d66f28SThierry Reding 
41787d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
41887d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN;
41987d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
42087d66f28SThierry Reding 
42187d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
42287d66f28SThierry Reding 
42387d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
42487d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
42587d66f28SThierry Reding 		if (!(value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE))
42687d66f28SThierry Reding 			break;
42787d66f28SThierry Reding 
42887d66f28SThierry Reding 		usleep_range(10, 20);
42987d66f28SThierry Reding 	}
43087d66f28SThierry Reding 
43187d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
43287d66f28SThierry Reding 		err = -ETIMEDOUT;
43387d66f28SThierry Reding 		goto reset;
43487d66f28SThierry Reding 	}
43587d66f28SThierry Reding 
43687d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
43787d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN;
43887d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
43987d66f28SThierry Reding 
44087d66f28SThierry Reding 	tegra210_xusb_pll_hw_control_enable();
44187d66f28SThierry Reding 
44287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
44387d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD;
44487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
44587d66f28SThierry Reding 
44687d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
44787d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD;
44887d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
44987d66f28SThierry Reding 
45087d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
45187d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD;
45287d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
45387d66f28SThierry Reding 
45487d66f28SThierry Reding 	usleep_range(10, 20);
45587d66f28SThierry Reding 
45687d66f28SThierry Reding 	tegra210_xusb_pll_hw_sequence_start();
45787d66f28SThierry Reding 
45887d66f28SThierry Reding 	pcie->enable++;
45987d66f28SThierry Reding 
46087d66f28SThierry Reding 	return 0;
46187d66f28SThierry Reding 
46287d66f28SThierry Reding reset:
46387d66f28SThierry Reding 	reset_control_assert(pcie->rst);
46487d66f28SThierry Reding disable:
46587d66f28SThierry Reding 	clk_disable_unprepare(pcie->pll);
46687d66f28SThierry Reding 	return err;
46787d66f28SThierry Reding }
46887d66f28SThierry Reding 
46987d66f28SThierry Reding static void tegra210_pex_uphy_disable(struct tegra_xusb_padctl *padctl)
47087d66f28SThierry Reding {
47187d66f28SThierry Reding 	struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(padctl->pcie);
47287d66f28SThierry Reding 
47387d66f28SThierry Reding 	mutex_lock(&padctl->lock);
47487d66f28SThierry Reding 
47587d66f28SThierry Reding 	if (WARN_ON(pcie->enable == 0))
47687d66f28SThierry Reding 		goto unlock;
47787d66f28SThierry Reding 
47887d66f28SThierry Reding 	if (--pcie->enable > 0)
47987d66f28SThierry Reding 		goto unlock;
48087d66f28SThierry Reding 
48187d66f28SThierry Reding 	reset_control_assert(pcie->rst);
48287d66f28SThierry Reding 	clk_disable_unprepare(pcie->pll);
48387d66f28SThierry Reding 
48487d66f28SThierry Reding unlock:
48587d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
48687d66f28SThierry Reding }
48787d66f28SThierry Reding 
48887d66f28SThierry Reding /* must be called under padctl->lock */
48987d66f28SThierry Reding static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl, bool usb)
49087d66f28SThierry Reding {
49187d66f28SThierry Reding 	struct tegra_xusb_sata_pad *sata = to_sata_pad(padctl->sata);
49287d66f28SThierry Reding 	unsigned long timeout;
49387d66f28SThierry Reding 	u32 value;
49487d66f28SThierry Reding 	int err;
49587d66f28SThierry Reding 
49687d66f28SThierry Reding 	if (sata->enable > 0) {
49787d66f28SThierry Reding 		sata->enable++;
49887d66f28SThierry Reding 		return 0;
49987d66f28SThierry Reding 	}
50087d66f28SThierry Reding 
50187d66f28SThierry Reding 	err = clk_prepare_enable(sata->pll);
50287d66f28SThierry Reding 	if (err < 0)
50387d66f28SThierry Reding 		return err;
50487d66f28SThierry Reding 
50587d66f28SThierry Reding 	err = reset_control_deassert(sata->rst);
50687d66f28SThierry Reding 	if (err < 0)
50787d66f28SThierry Reding 		goto disable;
50887d66f28SThierry Reding 
50987d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
51087d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK <<
51187d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT);
51287d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_VAL <<
51387d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT;
51487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
51587d66f28SThierry Reding 
51687d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL5);
51787d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_MASK <<
51887d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT);
51987d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_VAL <<
52087d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT;
52187d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL5);
52287d66f28SThierry Reding 
52387d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
52487d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD;
52587d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
52687d66f28SThierry Reding 
52787d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
52887d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD;
52987d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
53087d66f28SThierry Reding 
53187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
53287d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD;
53387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
53487d66f28SThierry Reding 
53587d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL4);
53687d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK <<
53787d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT) |
53887d66f28SThierry Reding 		   (XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_MASK <<
53987d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_SHIFT));
54087d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN;
54187d66f28SThierry Reding 
54287d66f28SThierry Reding 	if (usb)
54387d66f28SThierry Reding 		value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_USB_VAL <<
54487d66f28SThierry Reding 			  XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT);
54587d66f28SThierry Reding 	else
54687d66f28SThierry Reding 		value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SATA_VAL <<
54787d66f28SThierry Reding 			  XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT);
54887d66f28SThierry Reding 
549e7f4da4cSThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL4_XDIGCLK_EN;
55087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL4);
55187d66f28SThierry Reding 
55287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
55387d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK <<
55487d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_SHIFT) |
55587d66f28SThierry Reding 		   (XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_MASK <<
55687d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT));
55787d66f28SThierry Reding 
55887d66f28SThierry Reding 	if (usb)
55987d66f28SThierry Reding 		value |= XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_USB_VAL <<
56087d66f28SThierry Reding 			 XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT;
56187d66f28SThierry Reding 	else
56287d66f28SThierry Reding 		value |= XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SATA_VAL <<
56387d66f28SThierry Reding 			 XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT;
56487d66f28SThierry Reding 
56587d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
56687d66f28SThierry Reding 
56787d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
56887d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_IDDQ;
56987d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
57087d66f28SThierry Reding 
57187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
57287d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_MASK <<
57387d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_SHIFT);
57487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
57587d66f28SThierry Reding 
57687d66f28SThierry Reding 	usleep_range(10, 20);
57787d66f28SThierry Reding 
57887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL4);
57987d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL4_REFCLKBUF_EN;
58087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL4);
58187d66f28SThierry Reding 
58287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
58387d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN;
58487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
58587d66f28SThierry Reding 
58687d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
58787d66f28SThierry Reding 
58887d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
58987d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
59087d66f28SThierry Reding 		if (value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE)
59187d66f28SThierry Reding 			break;
59287d66f28SThierry Reding 
59387d66f28SThierry Reding 		usleep_range(10, 20);
59487d66f28SThierry Reding 	}
59587d66f28SThierry Reding 
59687d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
59787d66f28SThierry Reding 		err = -ETIMEDOUT;
59887d66f28SThierry Reding 		goto reset;
59987d66f28SThierry Reding 	}
60087d66f28SThierry Reding 
60187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
60287d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN;
60387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
60487d66f28SThierry Reding 
60587d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
60687d66f28SThierry Reding 
60787d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
60887d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
60987d66f28SThierry Reding 		if (!(value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE))
61087d66f28SThierry Reding 			break;
61187d66f28SThierry Reding 
61287d66f28SThierry Reding 		usleep_range(10, 20);
61387d66f28SThierry Reding 	}
61487d66f28SThierry Reding 
61587d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
61687d66f28SThierry Reding 		err = -ETIMEDOUT;
61787d66f28SThierry Reding 		goto reset;
61887d66f28SThierry Reding 	}
61987d66f28SThierry Reding 
62087d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
62187d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL1_ENABLE;
62287d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
62387d66f28SThierry Reding 
62487d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
62587d66f28SThierry Reding 
62687d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
62787d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
62887d66f28SThierry Reding 		if (value & XUSB_PADCTL_UPHY_PLL_CTL1_LOCKDET_STATUS)
62987d66f28SThierry Reding 			break;
63087d66f28SThierry Reding 
63187d66f28SThierry Reding 		usleep_range(10, 20);
63287d66f28SThierry Reding 	}
63387d66f28SThierry Reding 
63487d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
63587d66f28SThierry Reding 		err = -ETIMEDOUT;
63687d66f28SThierry Reding 		goto reset;
63787d66f28SThierry Reding 	}
63887d66f28SThierry Reding 
63987d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
64087d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN |
64187d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN;
64287d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
64387d66f28SThierry Reding 
64487d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
64587d66f28SThierry Reding 
64687d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
64787d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
64887d66f28SThierry Reding 		if (value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE)
64987d66f28SThierry Reding 			break;
65087d66f28SThierry Reding 
65187d66f28SThierry Reding 		usleep_range(10, 20);
65287d66f28SThierry Reding 	}
65387d66f28SThierry Reding 
65487d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
65587d66f28SThierry Reding 		err = -ETIMEDOUT;
65687d66f28SThierry Reding 		goto reset;
65787d66f28SThierry Reding 	}
65887d66f28SThierry Reding 
65987d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
66087d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN;
66187d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
66287d66f28SThierry Reding 
66387d66f28SThierry Reding 	timeout = jiffies + msecs_to_jiffies(100);
66487d66f28SThierry Reding 
66587d66f28SThierry Reding 	while (time_before(jiffies, timeout)) {
66687d66f28SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
66787d66f28SThierry Reding 		if (!(value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE))
66887d66f28SThierry Reding 			break;
66987d66f28SThierry Reding 
67087d66f28SThierry Reding 		usleep_range(10, 20);
67187d66f28SThierry Reding 	}
67287d66f28SThierry Reding 
67387d66f28SThierry Reding 	if (time_after_eq(jiffies, timeout)) {
67487d66f28SThierry Reding 		err = -ETIMEDOUT;
67587d66f28SThierry Reding 		goto reset;
67687d66f28SThierry Reding 	}
67787d66f28SThierry Reding 
67887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
67987d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN;
68087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
68187d66f28SThierry Reding 
68287d66f28SThierry Reding 	tegra210_sata_pll_hw_control_enable();
68387d66f28SThierry Reding 
68487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
68587d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD;
68687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
68787d66f28SThierry Reding 
68887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
68987d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD;
69087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2);
69187d66f28SThierry Reding 
69287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
69387d66f28SThierry Reding 	value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD;
69487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8);
69587d66f28SThierry Reding 
69687d66f28SThierry Reding 	usleep_range(10, 20);
69787d66f28SThierry Reding 
69887d66f28SThierry Reding 	tegra210_sata_pll_hw_sequence_start();
69987d66f28SThierry Reding 
70087d66f28SThierry Reding 	sata->enable++;
70187d66f28SThierry Reding 
70287d66f28SThierry Reding 	return 0;
70387d66f28SThierry Reding 
70487d66f28SThierry Reding reset:
70587d66f28SThierry Reding 	reset_control_assert(sata->rst);
70687d66f28SThierry Reding disable:
70787d66f28SThierry Reding 	clk_disable_unprepare(sata->pll);
70887d66f28SThierry Reding 	return err;
70987d66f28SThierry Reding }
71087d66f28SThierry Reding 
71187d66f28SThierry Reding static void tegra210_sata_uphy_disable(struct tegra_xusb_padctl *padctl)
71287d66f28SThierry Reding {
71387d66f28SThierry Reding 	struct tegra_xusb_sata_pad *sata = to_sata_pad(padctl->sata);
71487d66f28SThierry Reding 
71587d66f28SThierry Reding 	mutex_lock(&padctl->lock);
71687d66f28SThierry Reding 
71787d66f28SThierry Reding 	if (WARN_ON(sata->enable == 0))
71887d66f28SThierry Reding 		goto unlock;
71987d66f28SThierry Reding 
72087d66f28SThierry Reding 	if (--sata->enable > 0)
72187d66f28SThierry Reding 		goto unlock;
72287d66f28SThierry Reding 
72387d66f28SThierry Reding 	reset_control_assert(sata->rst);
72487d66f28SThierry Reding 	clk_disable_unprepare(sata->pll);
72587d66f28SThierry Reding 
72687d66f28SThierry Reding unlock:
72787d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
72887d66f28SThierry Reding }
72987d66f28SThierry Reding 
73087d66f28SThierry Reding static int tegra210_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
73187d66f28SThierry Reding {
73287d66f28SThierry Reding 	u32 value;
73387d66f28SThierry Reding 
73487d66f28SThierry Reding 	mutex_lock(&padctl->lock);
73587d66f28SThierry Reding 
73687d66f28SThierry Reding 	if (padctl->enable++ > 0)
73787d66f28SThierry Reding 		goto out;
73887d66f28SThierry Reding 
73987d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
74087d66f28SThierry Reding 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN;
74187d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
74287d66f28SThierry Reding 
74387d66f28SThierry Reding 	usleep_range(100, 200);
74487d66f28SThierry Reding 
74587d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
74687d66f28SThierry Reding 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY;
74787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
74887d66f28SThierry Reding 
74987d66f28SThierry Reding 	usleep_range(100, 200);
75087d66f28SThierry Reding 
75187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
75287d66f28SThierry Reding 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN;
75387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
75487d66f28SThierry Reding 
75587d66f28SThierry Reding out:
75687d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
75787d66f28SThierry Reding 	return 0;
75887d66f28SThierry Reding }
75987d66f28SThierry Reding 
76087d66f28SThierry Reding static int tegra210_xusb_padctl_disable(struct tegra_xusb_padctl *padctl)
76187d66f28SThierry Reding {
76287d66f28SThierry Reding 	u32 value;
76387d66f28SThierry Reding 
76487d66f28SThierry Reding 	mutex_lock(&padctl->lock);
76587d66f28SThierry Reding 
76687d66f28SThierry Reding 	if (WARN_ON(padctl->enable == 0))
76787d66f28SThierry Reding 		goto out;
76887d66f28SThierry Reding 
76987d66f28SThierry Reding 	if (--padctl->enable > 0)
77087d66f28SThierry Reding 		goto out;
77187d66f28SThierry Reding 
77287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
77387d66f28SThierry Reding 	value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN;
77487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
77587d66f28SThierry Reding 
77687d66f28SThierry Reding 	usleep_range(100, 200);
77787d66f28SThierry Reding 
77887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
77987d66f28SThierry Reding 	value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY;
78087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
78187d66f28SThierry Reding 
78287d66f28SThierry Reding 	usleep_range(100, 200);
78387d66f28SThierry Reding 
78487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
78587d66f28SThierry Reding 	value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN;
78687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
78787d66f28SThierry Reding 
78887d66f28SThierry Reding out:
78987d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
79087d66f28SThierry Reding 	return 0;
79187d66f28SThierry Reding }
79287d66f28SThierry Reding 
79387d66f28SThierry Reding static int tegra210_hsic_set_idle(struct tegra_xusb_padctl *padctl,
79487d66f28SThierry Reding 				  unsigned int index, bool idle)
79587d66f28SThierry Reding {
79687d66f28SThierry Reding 	u32 value;
79787d66f28SThierry Reding 
79887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index));
79987d66f28SThierry Reding 
80087d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA0 |
80187d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA1 |
80287d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_RPD_STROBE);
80387d66f28SThierry Reding 
80487d66f28SThierry Reding 	if (idle)
80587d66f28SThierry Reding 		value |= XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 |
80687d66f28SThierry Reding 			 XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 |
80787d66f28SThierry Reding 			 XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE;
80887d66f28SThierry Reding 	else
80987d66f28SThierry Reding 		value &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 |
81087d66f28SThierry Reding 			   XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 |
81187d66f28SThierry Reding 			   XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE);
81287d66f28SThierry Reding 
81387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL0(index));
81487d66f28SThierry Reding 
81587d66f28SThierry Reding 	return 0;
81687d66f28SThierry Reding }
81787d66f28SThierry Reding 
81887d66f28SThierry Reding static int tegra210_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl,
81987d66f28SThierry Reding 					 unsigned int index, bool enable)
82087d66f28SThierry Reding {
82187d66f28SThierry Reding 	struct tegra_xusb_port *port;
82287d66f28SThierry Reding 	struct tegra_xusb_lane *lane;
82387d66f28SThierry Reding 	u32 value, offset;
82487d66f28SThierry Reding 
82587d66f28SThierry Reding 	port = tegra_xusb_find_port(padctl, "usb3", index);
82687d66f28SThierry Reding 	if (!port)
82787d66f28SThierry Reding 		return -ENODEV;
82887d66f28SThierry Reding 
82987d66f28SThierry Reding 	lane = port->lane;
83087d66f28SThierry Reding 
83187d66f28SThierry Reding 	if (lane->pad == padctl->pcie)
83287d66f28SThierry Reding 		offset = XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL1(lane->index);
83387d66f28SThierry Reding 	else
83487d66f28SThierry Reding 		offset = XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1;
83587d66f28SThierry Reding 
83687d66f28SThierry Reding 	value = padctl_readl(padctl, offset);
83787d66f28SThierry Reding 
83887d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_MASK <<
83987d66f28SThierry Reding 		    XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT) |
84087d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN |
84187d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD);
84287d66f28SThierry Reding 
84387d66f28SThierry Reding 	if (!enable) {
84487d66f28SThierry Reding 		value |= (XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_VAL <<
84587d66f28SThierry Reding 			  XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT) |
84687d66f28SThierry Reding 			 XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN |
84787d66f28SThierry Reding 			 XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD;
84887d66f28SThierry Reding 	}
84987d66f28SThierry Reding 
85087d66f28SThierry Reding 	padctl_writel(padctl, value, offset);
85187d66f28SThierry Reding 
85287d66f28SThierry Reding 	return 0;
85387d66f28SThierry Reding }
85487d66f28SThierry Reding 
85587d66f28SThierry Reding #define TEGRA210_LANE(_name, _offset, _shift, _mask, _type)		\
85687d66f28SThierry Reding 	{								\
85787d66f28SThierry Reding 		.name = _name,						\
85887d66f28SThierry Reding 		.offset = _offset,					\
85987d66f28SThierry Reding 		.shift = _shift,					\
86087d66f28SThierry Reding 		.mask = _mask,						\
86187d66f28SThierry Reding 		.num_funcs = ARRAY_SIZE(tegra210_##_type##_functions),	\
86287d66f28SThierry Reding 		.funcs = tegra210_##_type##_functions,			\
86387d66f28SThierry Reding 	}
86487d66f28SThierry Reding 
86587d66f28SThierry Reding static const char *tegra210_usb2_functions[] = {
86687d66f28SThierry Reding 	"snps",
86787d66f28SThierry Reding 	"xusb",
86887d66f28SThierry Reding 	"uart"
86987d66f28SThierry Reding };
87087d66f28SThierry Reding 
87187d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_usb2_lanes[] = {
87287d66f28SThierry Reding 	TEGRA210_LANE("usb2-0", 0x004,  0, 0x3, usb2),
87387d66f28SThierry Reding 	TEGRA210_LANE("usb2-1", 0x004,  2, 0x3, usb2),
87487d66f28SThierry Reding 	TEGRA210_LANE("usb2-2", 0x004,  4, 0x3, usb2),
87587d66f28SThierry Reding 	TEGRA210_LANE("usb2-3", 0x004,  6, 0x3, usb2),
87687d66f28SThierry Reding };
87787d66f28SThierry Reding 
87887d66f28SThierry Reding static struct tegra_xusb_lane *
87987d66f28SThierry Reding tegra210_usb2_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
88087d66f28SThierry Reding 			 unsigned int index)
88187d66f28SThierry Reding {
88287d66f28SThierry Reding 	struct tegra_xusb_usb2_lane *usb2;
88387d66f28SThierry Reding 	int err;
88487d66f28SThierry Reding 
88587d66f28SThierry Reding 	usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
88687d66f28SThierry Reding 	if (!usb2)
88787d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
88887d66f28SThierry Reding 
88987d66f28SThierry Reding 	INIT_LIST_HEAD(&usb2->base.list);
89087d66f28SThierry Reding 	usb2->base.soc = &pad->soc->lanes[index];
89187d66f28SThierry Reding 	usb2->base.index = index;
89287d66f28SThierry Reding 	usb2->base.pad = pad;
89387d66f28SThierry Reding 	usb2->base.np = np;
89487d66f28SThierry Reding 
89587d66f28SThierry Reding 	err = tegra_xusb_lane_parse_dt(&usb2->base, np);
89687d66f28SThierry Reding 	if (err < 0) {
89787d66f28SThierry Reding 		kfree(usb2);
89887d66f28SThierry Reding 		return ERR_PTR(err);
89987d66f28SThierry Reding 	}
90087d66f28SThierry Reding 
90187d66f28SThierry Reding 	return &usb2->base;
90287d66f28SThierry Reding }
90387d66f28SThierry Reding 
90487d66f28SThierry Reding static void tegra210_usb2_lane_remove(struct tegra_xusb_lane *lane)
90587d66f28SThierry Reding {
90687d66f28SThierry Reding 	struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane);
90787d66f28SThierry Reding 
90887d66f28SThierry Reding 	kfree(usb2);
90987d66f28SThierry Reding }
91087d66f28SThierry Reding 
91187d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_usb2_lane_ops = {
91287d66f28SThierry Reding 	.probe = tegra210_usb2_lane_probe,
91387d66f28SThierry Reding 	.remove = tegra210_usb2_lane_remove,
91487d66f28SThierry Reding };
91587d66f28SThierry Reding 
91687d66f28SThierry Reding static int tegra210_usb2_phy_init(struct phy *phy)
91787d66f28SThierry Reding {
91887d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
91987d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
92087d66f28SThierry Reding 	u32 value;
92187d66f28SThierry Reding 
92287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
92387d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK <<
92487d66f28SThierry Reding 		   XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT);
92587d66f28SThierry Reding 	value |= XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB <<
92687d66f28SThierry Reding 		 XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT;
92787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX);
92887d66f28SThierry Reding 
92987d66f28SThierry Reding 	return tegra210_xusb_padctl_enable(padctl);
93087d66f28SThierry Reding }
93187d66f28SThierry Reding 
93287d66f28SThierry Reding static int tegra210_usb2_phy_exit(struct phy *phy)
93387d66f28SThierry Reding {
93487d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
93587d66f28SThierry Reding 
93687d66f28SThierry Reding 	return tegra210_xusb_padctl_disable(lane->pad->padctl);
93787d66f28SThierry Reding }
93887d66f28SThierry Reding 
939*de792a6dSNagarjuna Kristam static int tegra210_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
940*de792a6dSNagarjuna Kristam 					      bool status)
941*de792a6dSNagarjuna Kristam {
942*de792a6dSNagarjuna Kristam 	u32 value;
943*de792a6dSNagarjuna Kristam 
944*de792a6dSNagarjuna Kristam 	dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
945*de792a6dSNagarjuna Kristam 
946*de792a6dSNagarjuna Kristam 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
947*de792a6dSNagarjuna Kristam 
948*de792a6dSNagarjuna Kristam 	if (status) {
949*de792a6dSNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
950*de792a6dSNagarjuna Kristam 		value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
951*de792a6dSNagarjuna Kristam 			   XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
952*de792a6dSNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING <<
953*de792a6dSNagarjuna Kristam 			 XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
954*de792a6dSNagarjuna Kristam 	} else {
955*de792a6dSNagarjuna Kristam 		value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
956*de792a6dSNagarjuna Kristam 	}
957*de792a6dSNagarjuna Kristam 
958*de792a6dSNagarjuna Kristam 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
959*de792a6dSNagarjuna Kristam 
960*de792a6dSNagarjuna Kristam 	return 0;
961*de792a6dSNagarjuna Kristam }
962*de792a6dSNagarjuna Kristam 
963*de792a6dSNagarjuna Kristam static int tegra210_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl,
964*de792a6dSNagarjuna Kristam 					    bool status)
965*de792a6dSNagarjuna Kristam {
966*de792a6dSNagarjuna Kristam 	u32 value;
967*de792a6dSNagarjuna Kristam 
968*de792a6dSNagarjuna Kristam 	dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear");
969*de792a6dSNagarjuna Kristam 
970*de792a6dSNagarjuna Kristam 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
971*de792a6dSNagarjuna Kristam 
972*de792a6dSNagarjuna Kristam 	if (status) {
973*de792a6dSNagarjuna Kristam 		if (value & XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON) {
974*de792a6dSNagarjuna Kristam 			value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
975*de792a6dSNagarjuna Kristam 			padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
976*de792a6dSNagarjuna Kristam 			usleep_range(1000, 2000);
977*de792a6dSNagarjuna Kristam 
978*de792a6dSNagarjuna Kristam 			value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
979*de792a6dSNagarjuna Kristam 		}
980*de792a6dSNagarjuna Kristam 
981*de792a6dSNagarjuna Kristam 		value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
982*de792a6dSNagarjuna Kristam 			   XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
983*de792a6dSNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED <<
984*de792a6dSNagarjuna Kristam 			 XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
985*de792a6dSNagarjuna Kristam 	} else {
986*de792a6dSNagarjuna Kristam 		value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
987*de792a6dSNagarjuna Kristam 			   XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
988*de792a6dSNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING <<
989*de792a6dSNagarjuna Kristam 			 XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
990*de792a6dSNagarjuna Kristam 	}
991*de792a6dSNagarjuna Kristam 
992*de792a6dSNagarjuna Kristam 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
993*de792a6dSNagarjuna Kristam 
994*de792a6dSNagarjuna Kristam 	return 0;
995*de792a6dSNagarjuna Kristam }
996*de792a6dSNagarjuna Kristam 
997*de792a6dSNagarjuna Kristam static int tegra210_usb2_phy_set_mode(struct phy *phy, enum phy_mode mode,
998*de792a6dSNagarjuna Kristam 				      int submode)
999*de792a6dSNagarjuna Kristam {
1000*de792a6dSNagarjuna Kristam 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
1001*de792a6dSNagarjuna Kristam 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1002*de792a6dSNagarjuna Kristam 	struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl,
1003*de792a6dSNagarjuna Kristam 								lane->index);
1004*de792a6dSNagarjuna Kristam 	int err = 0;
1005*de792a6dSNagarjuna Kristam 
1006*de792a6dSNagarjuna Kristam 	mutex_lock(&padctl->lock);
1007*de792a6dSNagarjuna Kristam 
1008*de792a6dSNagarjuna Kristam 	dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode);
1009*de792a6dSNagarjuna Kristam 
1010*de792a6dSNagarjuna Kristam 	if (mode == PHY_MODE_USB_OTG) {
1011*de792a6dSNagarjuna Kristam 		if (submode == USB_ROLE_HOST) {
1012*de792a6dSNagarjuna Kristam 			tegra210_xusb_padctl_id_override(padctl, true);
1013*de792a6dSNagarjuna Kristam 
1014*de792a6dSNagarjuna Kristam 			err = regulator_enable(port->supply);
1015*de792a6dSNagarjuna Kristam 		} else if (submode == USB_ROLE_DEVICE) {
1016*de792a6dSNagarjuna Kristam 			tegra210_xusb_padctl_vbus_override(padctl, true);
1017*de792a6dSNagarjuna Kristam 		} else if (submode == USB_ROLE_NONE) {
1018*de792a6dSNagarjuna Kristam 			/*
1019*de792a6dSNagarjuna Kristam 			 * When port is peripheral only or role transitions to
1020*de792a6dSNagarjuna Kristam 			 * USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not
1021*de792a6dSNagarjuna Kristam 			 * be enabled.
1022*de792a6dSNagarjuna Kristam 			 */
1023*de792a6dSNagarjuna Kristam 			if (regulator_is_enabled(port->supply))
1024*de792a6dSNagarjuna Kristam 				regulator_disable(port->supply);
1025*de792a6dSNagarjuna Kristam 
1026*de792a6dSNagarjuna Kristam 			tegra210_xusb_padctl_id_override(padctl, false);
1027*de792a6dSNagarjuna Kristam 			tegra210_xusb_padctl_vbus_override(padctl, false);
1028*de792a6dSNagarjuna Kristam 		}
1029*de792a6dSNagarjuna Kristam 	}
1030*de792a6dSNagarjuna Kristam 
1031*de792a6dSNagarjuna Kristam 	mutex_unlock(&padctl->lock);
1032*de792a6dSNagarjuna Kristam 
1033*de792a6dSNagarjuna Kristam 	return err;
1034*de792a6dSNagarjuna Kristam }
1035*de792a6dSNagarjuna Kristam 
103687d66f28SThierry Reding static int tegra210_usb2_phy_power_on(struct phy *phy)
103787d66f28SThierry Reding {
103887d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
103987d66f28SThierry Reding 	struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane);
104087d66f28SThierry Reding 	struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad);
104187d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
104287d66f28SThierry Reding 	struct tegra210_xusb_padctl *priv;
104387d66f28SThierry Reding 	struct tegra_xusb_usb2_port *port;
104487d66f28SThierry Reding 	unsigned int index = lane->index;
104587d66f28SThierry Reding 	u32 value;
104687d66f28SThierry Reding 	int err;
104787d66f28SThierry Reding 
104887d66f28SThierry Reding 	port = tegra_xusb_find_usb2_port(padctl, index);
104987d66f28SThierry Reding 	if (!port) {
105087d66f28SThierry Reding 		dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
105187d66f28SThierry Reding 		return -ENODEV;
105287d66f28SThierry Reding 	}
105387d66f28SThierry Reding 
105487d66f28SThierry Reding 	priv = to_tegra210_xusb_padctl(padctl);
105587d66f28SThierry Reding 
1056a5be28c3SNagarjuna Kristam 	if (port->usb3_port_fake != -1) {
1057a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
1058a5be28c3SNagarjuna Kristam 		value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(
1059a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
1060a5be28c3SNagarjuna Kristam 		value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(
1061a5be28c3SNagarjuna Kristam 					port->usb3_port_fake, index);
1062a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP);
1063a5be28c3SNagarjuna Kristam 
1064a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
1065a5be28c3SNagarjuna Kristam 		value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(
1066a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
1067a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
1068a5be28c3SNagarjuna Kristam 
1069a5be28c3SNagarjuna Kristam 		usleep_range(100, 200);
1070a5be28c3SNagarjuna Kristam 
1071a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
1072a5be28c3SNagarjuna Kristam 		value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(
1073a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
1074a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
1075a5be28c3SNagarjuna Kristam 
1076a5be28c3SNagarjuna Kristam 		usleep_range(100, 200);
1077a5be28c3SNagarjuna Kristam 
1078a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
1079a5be28c3SNagarjuna Kristam 		value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(
1080a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
1081a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
1082a5be28c3SNagarjuna Kristam 	}
1083a5be28c3SNagarjuna Kristam 
108487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
108587d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK <<
108687d66f28SThierry Reding 		    XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) |
108787d66f28SThierry Reding 		   (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK <<
108887d66f28SThierry Reding 		    XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT));
108987d66f28SThierry Reding 	value |= (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL <<
109087d66f28SThierry Reding 		  XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT);
109187d66f28SThierry Reding 
109287d66f28SThierry Reding 	if (tegra_sku_info.revision < TEGRA_REVISION_A02)
109387d66f28SThierry Reding 		value |=
109487d66f28SThierry Reding 			(XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_VAL <<
109587d66f28SThierry Reding 			XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT);
109687d66f28SThierry Reding 
109787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
109887d66f28SThierry Reding 
109987d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
110087d66f28SThierry Reding 	value &= ~XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(index);
1101ac25b6e9SNagarjuna Kristam 	if (port->mode == USB_DR_MODE_UNKNOWN)
1102ac25b6e9SNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DISABLED(index);
1103ac25b6e9SNagarjuna Kristam 	else if (port->mode == USB_DR_MODE_PERIPHERAL)
1104ac25b6e9SNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DEVICE(index);
1105ac25b6e9SNagarjuna Kristam 	else if (port->mode == USB_DR_MODE_HOST)
110687d66f28SThierry Reding 		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(index);
1107ac25b6e9SNagarjuna Kristam 	else if (port->mode == USB_DR_MODE_OTG)
1108ac25b6e9SNagarjuna Kristam 		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_OTG(index);
110987d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP);
111087d66f28SThierry Reding 
111187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
111287d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK <<
111387d66f28SThierry Reding 		    XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT) |
111487d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD |
111587d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 |
111687d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI);
111787d66f28SThierry Reding 	value |= (priv->fuse.hs_curr_level[index] +
111887d66f28SThierry Reding 		  usb2->hs_curr_level_offset) <<
111987d66f28SThierry Reding 		 XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT;
112087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
112187d66f28SThierry Reding 
112287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
112387d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK <<
112487d66f28SThierry Reding 		    XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) |
112587d66f28SThierry Reding 		   (XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_MASK <<
112687d66f28SThierry Reding 		    XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT) |
112787d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR |
112887d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD |
112987d66f28SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD);
113087d66f28SThierry Reding 	value |= (priv->fuse.hs_term_range_adj <<
113187d66f28SThierry Reding 		  XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) |
113287d66f28SThierry Reding 		 (priv->fuse.rpd_ctrl <<
113387d66f28SThierry Reding 		  XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT);
113487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
113587d66f28SThierry Reding 
113687d66f28SThierry Reding 	value = padctl_readl(padctl,
113787d66f28SThierry Reding 			     XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
113887d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_MASK <<
113987d66f28SThierry Reding 		   XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT);
1140ac25b6e9SNagarjuna Kristam 	if (port->mode == USB_DR_MODE_HOST)
114187d66f28SThierry Reding 		value |= XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18;
1142ac25b6e9SNagarjuna Kristam 	else
1143ac25b6e9SNagarjuna Kristam 		value |=
1144ac25b6e9SNagarjuna Kristam 		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_VAL <<
1145ac25b6e9SNagarjuna Kristam 		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT;
114687d66f28SThierry Reding 	padctl_writel(padctl, value,
114787d66f28SThierry Reding 		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
114887d66f28SThierry Reding 
1149*de792a6dSNagarjuna Kristam 	if (port->supply && port->mode == USB_DR_MODE_HOST) {
115087d66f28SThierry Reding 		err = regulator_enable(port->supply);
115187d66f28SThierry Reding 		if (err)
115287d66f28SThierry Reding 			return err;
1153*de792a6dSNagarjuna Kristam 	}
115487d66f28SThierry Reding 
115587d66f28SThierry Reding 	mutex_lock(&padctl->lock);
115687d66f28SThierry Reding 
115787d66f28SThierry Reding 	if (pad->enable > 0) {
115887d66f28SThierry Reding 		pad->enable++;
115987d66f28SThierry Reding 		mutex_unlock(&padctl->lock);
116087d66f28SThierry Reding 		return 0;
116187d66f28SThierry Reding 	}
116287d66f28SThierry Reding 
116387d66f28SThierry Reding 	err = clk_prepare_enable(pad->clk);
116487d66f28SThierry Reding 	if (err)
116587d66f28SThierry Reding 		goto disable_regulator;
116687d66f28SThierry Reding 
116787d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
116887d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK <<
116987d66f28SThierry Reding 		    XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT) |
117087d66f28SThierry Reding 		   (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_MASK <<
117187d66f28SThierry Reding 		    XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT));
117287d66f28SThierry Reding 	value |= (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL <<
117387d66f28SThierry Reding 		  XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT) |
117487d66f28SThierry Reding 		 (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_VAL <<
117587d66f28SThierry Reding 		  XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT);
117687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
117787d66f28SThierry Reding 
117887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
117987d66f28SThierry Reding 	value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
118087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
118187d66f28SThierry Reding 
118287d66f28SThierry Reding 	udelay(1);
118387d66f28SThierry Reding 
118487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
118587d66f28SThierry Reding 	value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL1_PD_TRK;
118687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
118787d66f28SThierry Reding 
118887d66f28SThierry Reding 	udelay(50);
118987d66f28SThierry Reding 
119087d66f28SThierry Reding 	clk_disable_unprepare(pad->clk);
119187d66f28SThierry Reding 
119287d66f28SThierry Reding 	pad->enable++;
119387d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
119487d66f28SThierry Reding 
119587d66f28SThierry Reding 	return 0;
119687d66f28SThierry Reding 
119787d66f28SThierry Reding disable_regulator:
119887d66f28SThierry Reding 	regulator_disable(port->supply);
119987d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
120087d66f28SThierry Reding 	return err;
120187d66f28SThierry Reding }
120287d66f28SThierry Reding 
120387d66f28SThierry Reding static int tegra210_usb2_phy_power_off(struct phy *phy)
120487d66f28SThierry Reding {
120587d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
120687d66f28SThierry Reding 	struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad);
120787d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
120887d66f28SThierry Reding 	struct tegra_xusb_usb2_port *port;
120987d66f28SThierry Reding 	u32 value;
121087d66f28SThierry Reding 
121187d66f28SThierry Reding 	port = tegra_xusb_find_usb2_port(padctl, lane->index);
121287d66f28SThierry Reding 	if (!port) {
121387d66f28SThierry Reding 		dev_err(&phy->dev, "no port found for USB2 lane %u\n",
121487d66f28SThierry Reding 			lane->index);
121587d66f28SThierry Reding 		return -ENODEV;
121687d66f28SThierry Reding 	}
121787d66f28SThierry Reding 
121887d66f28SThierry Reding 	mutex_lock(&padctl->lock);
121987d66f28SThierry Reding 
1220a5be28c3SNagarjuna Kristam 	if (port->usb3_port_fake != -1) {
1221a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
1222a5be28c3SNagarjuna Kristam 		value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(
1223a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
1224a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
1225a5be28c3SNagarjuna Kristam 
1226a5be28c3SNagarjuna Kristam 		usleep_range(100, 200);
1227a5be28c3SNagarjuna Kristam 
1228a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
1229a5be28c3SNagarjuna Kristam 		value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(
1230a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
1231a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
1232a5be28c3SNagarjuna Kristam 
1233a5be28c3SNagarjuna Kristam 		usleep_range(250, 350);
1234a5be28c3SNagarjuna Kristam 
1235a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
1236a5be28c3SNagarjuna Kristam 		value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(
1237a5be28c3SNagarjuna Kristam 					port->usb3_port_fake);
1238a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
1239a5be28c3SNagarjuna Kristam 
1240a5be28c3SNagarjuna Kristam 		value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
1241a5be28c3SNagarjuna Kristam 		value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(port->usb3_port_fake,
1242a5be28c3SNagarjuna Kristam 					XUSB_PADCTL_SS_PORT_MAP_PORT_DISABLED);
1243a5be28c3SNagarjuna Kristam 		padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP);
1244a5be28c3SNagarjuna Kristam 	}
1245a5be28c3SNagarjuna Kristam 
124687d66f28SThierry Reding 	if (WARN_ON(pad->enable == 0))
124787d66f28SThierry Reding 		goto out;
124887d66f28SThierry Reding 
124987d66f28SThierry Reding 	if (--pad->enable > 0)
125087d66f28SThierry Reding 		goto out;
125187d66f28SThierry Reding 
125287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
125387d66f28SThierry Reding 	value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
125487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
125587d66f28SThierry Reding 
125687d66f28SThierry Reding out:
125787d66f28SThierry Reding 	regulator_disable(port->supply);
125887d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
125987d66f28SThierry Reding 	return 0;
126087d66f28SThierry Reding }
126187d66f28SThierry Reding 
126287d66f28SThierry Reding static const struct phy_ops tegra210_usb2_phy_ops = {
126387d66f28SThierry Reding 	.init = tegra210_usb2_phy_init,
126487d66f28SThierry Reding 	.exit = tegra210_usb2_phy_exit,
126587d66f28SThierry Reding 	.power_on = tegra210_usb2_phy_power_on,
126687d66f28SThierry Reding 	.power_off = tegra210_usb2_phy_power_off,
1267*de792a6dSNagarjuna Kristam 	.set_mode = tegra210_usb2_phy_set_mode,
126887d66f28SThierry Reding 	.owner = THIS_MODULE,
126987d66f28SThierry Reding };
127087d66f28SThierry Reding 
127187d66f28SThierry Reding static struct tegra_xusb_pad *
127287d66f28SThierry Reding tegra210_usb2_pad_probe(struct tegra_xusb_padctl *padctl,
127387d66f28SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
127487d66f28SThierry Reding 			struct device_node *np)
127587d66f28SThierry Reding {
127687d66f28SThierry Reding 	struct tegra_xusb_usb2_pad *usb2;
127787d66f28SThierry Reding 	struct tegra_xusb_pad *pad;
127887d66f28SThierry Reding 	int err;
127987d66f28SThierry Reding 
128087d66f28SThierry Reding 	usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
128187d66f28SThierry Reding 	if (!usb2)
128287d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
128387d66f28SThierry Reding 
128487d66f28SThierry Reding 	pad = &usb2->base;
128587d66f28SThierry Reding 	pad->ops = &tegra210_usb2_lane_ops;
128687d66f28SThierry Reding 	pad->soc = soc;
128787d66f28SThierry Reding 
128887d66f28SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
128987d66f28SThierry Reding 	if (err < 0) {
129087d66f28SThierry Reding 		kfree(usb2);
129187d66f28SThierry Reding 		goto out;
129287d66f28SThierry Reding 	}
129387d66f28SThierry Reding 
129487d66f28SThierry Reding 	usb2->clk = devm_clk_get(&pad->dev, "trk");
129587d66f28SThierry Reding 	if (IS_ERR(usb2->clk)) {
129687d66f28SThierry Reding 		err = PTR_ERR(usb2->clk);
129787d66f28SThierry Reding 		dev_err(&pad->dev, "failed to get trk clock: %d\n", err);
129887d66f28SThierry Reding 		goto unregister;
129987d66f28SThierry Reding 	}
130087d66f28SThierry Reding 
130187d66f28SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra210_usb2_phy_ops);
130287d66f28SThierry Reding 	if (err < 0)
130387d66f28SThierry Reding 		goto unregister;
130487d66f28SThierry Reding 
130587d66f28SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
130687d66f28SThierry Reding 
130787d66f28SThierry Reding 	return pad;
130887d66f28SThierry Reding 
130987d66f28SThierry Reding unregister:
131087d66f28SThierry Reding 	device_unregister(&pad->dev);
131187d66f28SThierry Reding out:
131287d66f28SThierry Reding 	return ERR_PTR(err);
131387d66f28SThierry Reding }
131487d66f28SThierry Reding 
131587d66f28SThierry Reding static void tegra210_usb2_pad_remove(struct tegra_xusb_pad *pad)
131687d66f28SThierry Reding {
131787d66f28SThierry Reding 	struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad);
131887d66f28SThierry Reding 
131987d66f28SThierry Reding 	kfree(usb2);
132087d66f28SThierry Reding }
132187d66f28SThierry Reding 
132287d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_usb2_ops = {
132387d66f28SThierry Reding 	.probe = tegra210_usb2_pad_probe,
132487d66f28SThierry Reding 	.remove = tegra210_usb2_pad_remove,
132587d66f28SThierry Reding };
132687d66f28SThierry Reding 
132787d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_usb2_pad = {
132887d66f28SThierry Reding 	.name = "usb2",
132987d66f28SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra210_usb2_lanes),
133087d66f28SThierry Reding 	.lanes = tegra210_usb2_lanes,
133187d66f28SThierry Reding 	.ops = &tegra210_usb2_ops,
133287d66f28SThierry Reding };
133387d66f28SThierry Reding 
133487d66f28SThierry Reding static const char *tegra210_hsic_functions[] = {
133587d66f28SThierry Reding 	"snps",
133687d66f28SThierry Reding 	"xusb",
133787d66f28SThierry Reding };
133887d66f28SThierry Reding 
133987d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_hsic_lanes[] = {
134087d66f28SThierry Reding 	TEGRA210_LANE("hsic-0", 0x004, 14, 0x1, hsic),
134187d66f28SThierry Reding };
134287d66f28SThierry Reding 
134387d66f28SThierry Reding static struct tegra_xusb_lane *
134487d66f28SThierry Reding tegra210_hsic_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
134587d66f28SThierry Reding 			 unsigned int index)
134687d66f28SThierry Reding {
134787d66f28SThierry Reding 	struct tegra_xusb_hsic_lane *hsic;
134887d66f28SThierry Reding 	int err;
134987d66f28SThierry Reding 
135087d66f28SThierry Reding 	hsic = kzalloc(sizeof(*hsic), GFP_KERNEL);
135187d66f28SThierry Reding 	if (!hsic)
135287d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
135387d66f28SThierry Reding 
135487d66f28SThierry Reding 	INIT_LIST_HEAD(&hsic->base.list);
135587d66f28SThierry Reding 	hsic->base.soc = &pad->soc->lanes[index];
135687d66f28SThierry Reding 	hsic->base.index = index;
135787d66f28SThierry Reding 	hsic->base.pad = pad;
135887d66f28SThierry Reding 	hsic->base.np = np;
135987d66f28SThierry Reding 
136087d66f28SThierry Reding 	err = tegra_xusb_lane_parse_dt(&hsic->base, np);
136187d66f28SThierry Reding 	if (err < 0) {
136287d66f28SThierry Reding 		kfree(hsic);
136387d66f28SThierry Reding 		return ERR_PTR(err);
136487d66f28SThierry Reding 	}
136587d66f28SThierry Reding 
136687d66f28SThierry Reding 	return &hsic->base;
136787d66f28SThierry Reding }
136887d66f28SThierry Reding 
136987d66f28SThierry Reding static void tegra210_hsic_lane_remove(struct tegra_xusb_lane *lane)
137087d66f28SThierry Reding {
137187d66f28SThierry Reding 	struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane);
137287d66f28SThierry Reding 
137387d66f28SThierry Reding 	kfree(hsic);
137487d66f28SThierry Reding }
137587d66f28SThierry Reding 
137687d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_hsic_lane_ops = {
137787d66f28SThierry Reding 	.probe = tegra210_hsic_lane_probe,
137887d66f28SThierry Reding 	.remove = tegra210_hsic_lane_remove,
137987d66f28SThierry Reding };
138087d66f28SThierry Reding 
138187d66f28SThierry Reding static int tegra210_hsic_phy_init(struct phy *phy)
138287d66f28SThierry Reding {
138387d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
138487d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
138587d66f28SThierry Reding 	u32 value;
138687d66f28SThierry Reding 
138787d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
138887d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_MASK <<
138987d66f28SThierry Reding 		   XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT);
139087d66f28SThierry Reding 	value |= XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_XUSB <<
139187d66f28SThierry Reding 		 XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT;
139287d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX);
139387d66f28SThierry Reding 
139487d66f28SThierry Reding 	return tegra210_xusb_padctl_enable(padctl);
139587d66f28SThierry Reding }
139687d66f28SThierry Reding 
139787d66f28SThierry Reding static int tegra210_hsic_phy_exit(struct phy *phy)
139887d66f28SThierry Reding {
139987d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
140087d66f28SThierry Reding 
140187d66f28SThierry Reding 	return tegra210_xusb_padctl_disable(lane->pad->padctl);
140287d66f28SThierry Reding }
140387d66f28SThierry Reding 
140487d66f28SThierry Reding static int tegra210_hsic_phy_power_on(struct phy *phy)
140587d66f28SThierry Reding {
140687d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
140787d66f28SThierry Reding 	struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane);
140887d66f28SThierry Reding 	struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad);
140987d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
141087d66f28SThierry Reding 	unsigned int index = lane->index;
141187d66f28SThierry Reding 	u32 value;
141287d66f28SThierry Reding 	int err;
141387d66f28SThierry Reding 
141487d66f28SThierry Reding 	err = regulator_enable(pad->supply);
141587d66f28SThierry Reding 	if (err)
141687d66f28SThierry Reding 		return err;
141787d66f28SThierry Reding 
141887d66f28SThierry Reding 	padctl_writel(padctl, hsic->strobe_trim,
141987d66f28SThierry Reding 		      XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL);
142087d66f28SThierry Reding 
142187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index));
142287d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_MASK <<
142387d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT);
142487d66f28SThierry Reding 	value |= (hsic->tx_rtune_p <<
142587d66f28SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT);
142687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index));
142787d66f28SThierry Reding 
142887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(index));
142987d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK <<
143087d66f28SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) |
143187d66f28SThierry Reding 		   (XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK <<
143287d66f28SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT));
143387d66f28SThierry Reding 	value |= (hsic->rx_strobe_trim <<
143487d66f28SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) |
143587d66f28SThierry Reding 		 (hsic->rx_data_trim <<
143687d66f28SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT);
143787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL2(index));
143887d66f28SThierry Reding 
143987d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index));
144087d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA0 |
144187d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA1 |
144287d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE |
144387d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 |
144487d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 |
144587d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE |
144687d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 |
144787d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 |
144887d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE |
144987d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 |
145087d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 |
145187d66f28SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE);
145287d66f28SThierry Reding 	value |= XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 |
145387d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 |
145487d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_RPD_STROBE;
145587d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL0(index));
145687d66f28SThierry Reding 
145787d66f28SThierry Reding 	err = clk_prepare_enable(pad->clk);
145887d66f28SThierry Reding 	if (err)
145987d66f28SThierry Reding 		goto disable;
146087d66f28SThierry Reding 
146187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PAD_TRK_CTL);
146287d66f28SThierry Reding 	value &= ~((XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_MASK <<
146387d66f28SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT) |
146487d66f28SThierry Reding 		   (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_MASK <<
146587d66f28SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT));
146687d66f28SThierry Reding 	value |= (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_VAL <<
146787d66f28SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT) |
146887d66f28SThierry Reding 		 (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_VAL <<
146987d66f28SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT);
147087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PAD_TRK_CTL);
147187d66f28SThierry Reding 
147287d66f28SThierry Reding 	udelay(1);
147387d66f28SThierry Reding 
147487d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PAD_TRK_CTL);
147587d66f28SThierry Reding 	value &= ~XUSB_PADCTL_HSIC_PAD_TRK_CTL_PD_TRK;
147687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PAD_TRK_CTL);
147787d66f28SThierry Reding 
147887d66f28SThierry Reding 	udelay(50);
147987d66f28SThierry Reding 
148087d66f28SThierry Reding 	clk_disable_unprepare(pad->clk);
148187d66f28SThierry Reding 
148287d66f28SThierry Reding 	return 0;
148387d66f28SThierry Reding 
148487d66f28SThierry Reding disable:
148587d66f28SThierry Reding 	regulator_disable(pad->supply);
148687d66f28SThierry Reding 	return err;
148787d66f28SThierry Reding }
148887d66f28SThierry Reding 
148987d66f28SThierry Reding static int tegra210_hsic_phy_power_off(struct phy *phy)
149087d66f28SThierry Reding {
149187d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
149287d66f28SThierry Reding 	struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad);
149387d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
149487d66f28SThierry Reding 	unsigned int index = lane->index;
149587d66f28SThierry Reding 	u32 value;
149687d66f28SThierry Reding 
149787d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index));
149887d66f28SThierry Reding 	value |= XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 |
149987d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 |
150087d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE |
150187d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 |
150287d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 |
150387d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE |
150487d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 |
150587d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 |
150687d66f28SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE;
150787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index));
150887d66f28SThierry Reding 
150987d66f28SThierry Reding 	regulator_disable(pad->supply);
151087d66f28SThierry Reding 
151187d66f28SThierry Reding 	return 0;
151287d66f28SThierry Reding }
151387d66f28SThierry Reding 
151487d66f28SThierry Reding static const struct phy_ops tegra210_hsic_phy_ops = {
151587d66f28SThierry Reding 	.init = tegra210_hsic_phy_init,
151687d66f28SThierry Reding 	.exit = tegra210_hsic_phy_exit,
151787d66f28SThierry Reding 	.power_on = tegra210_hsic_phy_power_on,
151887d66f28SThierry Reding 	.power_off = tegra210_hsic_phy_power_off,
151987d66f28SThierry Reding 	.owner = THIS_MODULE,
152087d66f28SThierry Reding };
152187d66f28SThierry Reding 
152287d66f28SThierry Reding static struct tegra_xusb_pad *
152387d66f28SThierry Reding tegra210_hsic_pad_probe(struct tegra_xusb_padctl *padctl,
152487d66f28SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
152587d66f28SThierry Reding 			struct device_node *np)
152687d66f28SThierry Reding {
152787d66f28SThierry Reding 	struct tegra_xusb_hsic_pad *hsic;
152887d66f28SThierry Reding 	struct tegra_xusb_pad *pad;
152987d66f28SThierry Reding 	int err;
153087d66f28SThierry Reding 
153187d66f28SThierry Reding 	hsic = kzalloc(sizeof(*hsic), GFP_KERNEL);
153287d66f28SThierry Reding 	if (!hsic)
153387d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
153487d66f28SThierry Reding 
153587d66f28SThierry Reding 	pad = &hsic->base;
153687d66f28SThierry Reding 	pad->ops = &tegra210_hsic_lane_ops;
153787d66f28SThierry Reding 	pad->soc = soc;
153887d66f28SThierry Reding 
153987d66f28SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
154087d66f28SThierry Reding 	if (err < 0) {
154187d66f28SThierry Reding 		kfree(hsic);
154287d66f28SThierry Reding 		goto out;
154387d66f28SThierry Reding 	}
154487d66f28SThierry Reding 
154587d66f28SThierry Reding 	hsic->clk = devm_clk_get(&pad->dev, "trk");
154687d66f28SThierry Reding 	if (IS_ERR(hsic->clk)) {
154787d66f28SThierry Reding 		err = PTR_ERR(hsic->clk);
154887d66f28SThierry Reding 		dev_err(&pad->dev, "failed to get trk clock: %d\n", err);
154987d66f28SThierry Reding 		goto unregister;
155087d66f28SThierry Reding 	}
155187d66f28SThierry Reding 
155287d66f28SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra210_hsic_phy_ops);
155387d66f28SThierry Reding 	if (err < 0)
155487d66f28SThierry Reding 		goto unregister;
155587d66f28SThierry Reding 
155687d66f28SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
155787d66f28SThierry Reding 
155887d66f28SThierry Reding 	return pad;
155987d66f28SThierry Reding 
156087d66f28SThierry Reding unregister:
156187d66f28SThierry Reding 	device_unregister(&pad->dev);
156287d66f28SThierry Reding out:
156387d66f28SThierry Reding 	return ERR_PTR(err);
156487d66f28SThierry Reding }
156587d66f28SThierry Reding 
156687d66f28SThierry Reding static void tegra210_hsic_pad_remove(struct tegra_xusb_pad *pad)
156787d66f28SThierry Reding {
156887d66f28SThierry Reding 	struct tegra_xusb_hsic_pad *hsic = to_hsic_pad(pad);
156987d66f28SThierry Reding 
157087d66f28SThierry Reding 	kfree(hsic);
157187d66f28SThierry Reding }
157287d66f28SThierry Reding 
157387d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_hsic_ops = {
157487d66f28SThierry Reding 	.probe = tegra210_hsic_pad_probe,
157587d66f28SThierry Reding 	.remove = tegra210_hsic_pad_remove,
157687d66f28SThierry Reding };
157787d66f28SThierry Reding 
157887d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_hsic_pad = {
157987d66f28SThierry Reding 	.name = "hsic",
158087d66f28SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra210_hsic_lanes),
158187d66f28SThierry Reding 	.lanes = tegra210_hsic_lanes,
158287d66f28SThierry Reding 	.ops = &tegra210_hsic_ops,
158387d66f28SThierry Reding };
158487d66f28SThierry Reding 
158587d66f28SThierry Reding static const char *tegra210_pcie_functions[] = {
158687d66f28SThierry Reding 	"pcie-x1",
158787d66f28SThierry Reding 	"usb3-ss",
158887d66f28SThierry Reding 	"sata",
158987d66f28SThierry Reding 	"pcie-x4",
159087d66f28SThierry Reding };
159187d66f28SThierry Reding 
159287d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_pcie_lanes[] = {
159387d66f28SThierry Reding 	TEGRA210_LANE("pcie-0", 0x028, 12, 0x3, pcie),
159487d66f28SThierry Reding 	TEGRA210_LANE("pcie-1", 0x028, 14, 0x3, pcie),
159587d66f28SThierry Reding 	TEGRA210_LANE("pcie-2", 0x028, 16, 0x3, pcie),
159687d66f28SThierry Reding 	TEGRA210_LANE("pcie-3", 0x028, 18, 0x3, pcie),
159787d66f28SThierry Reding 	TEGRA210_LANE("pcie-4", 0x028, 20, 0x3, pcie),
159887d66f28SThierry Reding 	TEGRA210_LANE("pcie-5", 0x028, 22, 0x3, pcie),
159987d66f28SThierry Reding 	TEGRA210_LANE("pcie-6", 0x028, 24, 0x3, pcie),
160087d66f28SThierry Reding };
160187d66f28SThierry Reding 
160287d66f28SThierry Reding static struct tegra_xusb_lane *
160387d66f28SThierry Reding tegra210_pcie_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
160487d66f28SThierry Reding 			 unsigned int index)
160587d66f28SThierry Reding {
160687d66f28SThierry Reding 	struct tegra_xusb_pcie_lane *pcie;
160787d66f28SThierry Reding 	int err;
160887d66f28SThierry Reding 
160987d66f28SThierry Reding 	pcie = kzalloc(sizeof(*pcie), GFP_KERNEL);
161087d66f28SThierry Reding 	if (!pcie)
161187d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
161287d66f28SThierry Reding 
161387d66f28SThierry Reding 	INIT_LIST_HEAD(&pcie->base.list);
161487d66f28SThierry Reding 	pcie->base.soc = &pad->soc->lanes[index];
161587d66f28SThierry Reding 	pcie->base.index = index;
161687d66f28SThierry Reding 	pcie->base.pad = pad;
161787d66f28SThierry Reding 	pcie->base.np = np;
161887d66f28SThierry Reding 
161987d66f28SThierry Reding 	err = tegra_xusb_lane_parse_dt(&pcie->base, np);
162087d66f28SThierry Reding 	if (err < 0) {
162187d66f28SThierry Reding 		kfree(pcie);
162287d66f28SThierry Reding 		return ERR_PTR(err);
162387d66f28SThierry Reding 	}
162487d66f28SThierry Reding 
162587d66f28SThierry Reding 	return &pcie->base;
162687d66f28SThierry Reding }
162787d66f28SThierry Reding 
162887d66f28SThierry Reding static void tegra210_pcie_lane_remove(struct tegra_xusb_lane *lane)
162987d66f28SThierry Reding {
163087d66f28SThierry Reding 	struct tegra_xusb_pcie_lane *pcie = to_pcie_lane(lane);
163187d66f28SThierry Reding 
163287d66f28SThierry Reding 	kfree(pcie);
163387d66f28SThierry Reding }
163487d66f28SThierry Reding 
163587d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_pcie_lane_ops = {
163687d66f28SThierry Reding 	.probe = tegra210_pcie_lane_probe,
163787d66f28SThierry Reding 	.remove = tegra210_pcie_lane_remove,
163887d66f28SThierry Reding };
163987d66f28SThierry Reding 
164087d66f28SThierry Reding static int tegra210_pcie_phy_init(struct phy *phy)
164187d66f28SThierry Reding {
164287d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
164387d66f28SThierry Reding 
164487d66f28SThierry Reding 	return tegra210_xusb_padctl_enable(lane->pad->padctl);
164587d66f28SThierry Reding }
164687d66f28SThierry Reding 
164787d66f28SThierry Reding static int tegra210_pcie_phy_exit(struct phy *phy)
164887d66f28SThierry Reding {
164987d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
165087d66f28SThierry Reding 
165187d66f28SThierry Reding 	return tegra210_xusb_padctl_disable(lane->pad->padctl);
165287d66f28SThierry Reding }
165387d66f28SThierry Reding 
165487d66f28SThierry Reding static int tegra210_pcie_phy_power_on(struct phy *phy)
165587d66f28SThierry Reding {
165687d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
165787d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
165887d66f28SThierry Reding 	u32 value;
165987d66f28SThierry Reding 	int err;
166087d66f28SThierry Reding 
166187d66f28SThierry Reding 	mutex_lock(&padctl->lock);
166287d66f28SThierry Reding 
166387d66f28SThierry Reding 	err = tegra210_pex_uphy_enable(padctl);
166487d66f28SThierry Reding 	if (err < 0)
166587d66f28SThierry Reding 		goto unlock;
166687d66f28SThierry Reding 
166787d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
166887d66f28SThierry Reding 	value |= XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->index);
166987d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
167087d66f28SThierry Reding 
167187d66f28SThierry Reding unlock:
167287d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
167387d66f28SThierry Reding 	return err;
167487d66f28SThierry Reding }
167587d66f28SThierry Reding 
167687d66f28SThierry Reding static int tegra210_pcie_phy_power_off(struct phy *phy)
167787d66f28SThierry Reding {
167887d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
167987d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
168087d66f28SThierry Reding 	u32 value;
168187d66f28SThierry Reding 
168287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
168387d66f28SThierry Reding 	value &= ~XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->index);
168487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
168587d66f28SThierry Reding 
168687d66f28SThierry Reding 	tegra210_pex_uphy_disable(padctl);
168787d66f28SThierry Reding 
168887d66f28SThierry Reding 	return 0;
168987d66f28SThierry Reding }
169087d66f28SThierry Reding 
169187d66f28SThierry Reding static const struct phy_ops tegra210_pcie_phy_ops = {
169287d66f28SThierry Reding 	.init = tegra210_pcie_phy_init,
169387d66f28SThierry Reding 	.exit = tegra210_pcie_phy_exit,
169487d66f28SThierry Reding 	.power_on = tegra210_pcie_phy_power_on,
169587d66f28SThierry Reding 	.power_off = tegra210_pcie_phy_power_off,
169687d66f28SThierry Reding 	.owner = THIS_MODULE,
169787d66f28SThierry Reding };
169887d66f28SThierry Reding 
169987d66f28SThierry Reding static struct tegra_xusb_pad *
170087d66f28SThierry Reding tegra210_pcie_pad_probe(struct tegra_xusb_padctl *padctl,
170187d66f28SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
170287d66f28SThierry Reding 			struct device_node *np)
170387d66f28SThierry Reding {
170487d66f28SThierry Reding 	struct tegra_xusb_pcie_pad *pcie;
170587d66f28SThierry Reding 	struct tegra_xusb_pad *pad;
170687d66f28SThierry Reding 	int err;
170787d66f28SThierry Reding 
170887d66f28SThierry Reding 	pcie = kzalloc(sizeof(*pcie), GFP_KERNEL);
170987d66f28SThierry Reding 	if (!pcie)
171087d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
171187d66f28SThierry Reding 
171287d66f28SThierry Reding 	pad = &pcie->base;
171387d66f28SThierry Reding 	pad->ops = &tegra210_pcie_lane_ops;
171487d66f28SThierry Reding 	pad->soc = soc;
171587d66f28SThierry Reding 
171687d66f28SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
171787d66f28SThierry Reding 	if (err < 0) {
171887d66f28SThierry Reding 		kfree(pcie);
171987d66f28SThierry Reding 		goto out;
172087d66f28SThierry Reding 	}
172187d66f28SThierry Reding 
172287d66f28SThierry Reding 	pcie->pll = devm_clk_get(&pad->dev, "pll");
172387d66f28SThierry Reding 	if (IS_ERR(pcie->pll)) {
172487d66f28SThierry Reding 		err = PTR_ERR(pcie->pll);
172587d66f28SThierry Reding 		dev_err(&pad->dev, "failed to get PLL: %d\n", err);
172687d66f28SThierry Reding 		goto unregister;
172787d66f28SThierry Reding 	}
172887d66f28SThierry Reding 
172987d66f28SThierry Reding 	pcie->rst = devm_reset_control_get(&pad->dev, "phy");
173087d66f28SThierry Reding 	if (IS_ERR(pcie->rst)) {
173187d66f28SThierry Reding 		err = PTR_ERR(pcie->rst);
173287d66f28SThierry Reding 		dev_err(&pad->dev, "failed to get PCIe pad reset: %d\n", err);
173387d66f28SThierry Reding 		goto unregister;
173487d66f28SThierry Reding 	}
173587d66f28SThierry Reding 
173687d66f28SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra210_pcie_phy_ops);
173787d66f28SThierry Reding 	if (err < 0)
173887d66f28SThierry Reding 		goto unregister;
173987d66f28SThierry Reding 
174087d66f28SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
174187d66f28SThierry Reding 
174287d66f28SThierry Reding 	return pad;
174387d66f28SThierry Reding 
174487d66f28SThierry Reding unregister:
174587d66f28SThierry Reding 	device_unregister(&pad->dev);
174687d66f28SThierry Reding out:
174787d66f28SThierry Reding 	return ERR_PTR(err);
174887d66f28SThierry Reding }
174987d66f28SThierry Reding 
175087d66f28SThierry Reding static void tegra210_pcie_pad_remove(struct tegra_xusb_pad *pad)
175187d66f28SThierry Reding {
175287d66f28SThierry Reding 	struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(pad);
175387d66f28SThierry Reding 
175487d66f28SThierry Reding 	kfree(pcie);
175587d66f28SThierry Reding }
175687d66f28SThierry Reding 
175787d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_pcie_ops = {
175887d66f28SThierry Reding 	.probe = tegra210_pcie_pad_probe,
175987d66f28SThierry Reding 	.remove = tegra210_pcie_pad_remove,
176087d66f28SThierry Reding };
176187d66f28SThierry Reding 
176287d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_pcie_pad = {
176387d66f28SThierry Reding 	.name = "pcie",
176487d66f28SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra210_pcie_lanes),
176587d66f28SThierry Reding 	.lanes = tegra210_pcie_lanes,
176687d66f28SThierry Reding 	.ops = &tegra210_pcie_ops,
176787d66f28SThierry Reding };
176887d66f28SThierry Reding 
176987d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_sata_lanes[] = {
177087d66f28SThierry Reding 	TEGRA210_LANE("sata-0", 0x028, 30, 0x3, pcie),
177187d66f28SThierry Reding };
177287d66f28SThierry Reding 
177387d66f28SThierry Reding static struct tegra_xusb_lane *
177487d66f28SThierry Reding tegra210_sata_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
177587d66f28SThierry Reding 			 unsigned int index)
177687d66f28SThierry Reding {
177787d66f28SThierry Reding 	struct tegra_xusb_sata_lane *sata;
177887d66f28SThierry Reding 	int err;
177987d66f28SThierry Reding 
178087d66f28SThierry Reding 	sata = kzalloc(sizeof(*sata), GFP_KERNEL);
178187d66f28SThierry Reding 	if (!sata)
178287d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
178387d66f28SThierry Reding 
178487d66f28SThierry Reding 	INIT_LIST_HEAD(&sata->base.list);
178587d66f28SThierry Reding 	sata->base.soc = &pad->soc->lanes[index];
178687d66f28SThierry Reding 	sata->base.index = index;
178787d66f28SThierry Reding 	sata->base.pad = pad;
178887d66f28SThierry Reding 	sata->base.np = np;
178987d66f28SThierry Reding 
179087d66f28SThierry Reding 	err = tegra_xusb_lane_parse_dt(&sata->base, np);
179187d66f28SThierry Reding 	if (err < 0) {
179287d66f28SThierry Reding 		kfree(sata);
179387d66f28SThierry Reding 		return ERR_PTR(err);
179487d66f28SThierry Reding 	}
179587d66f28SThierry Reding 
179687d66f28SThierry Reding 	return &sata->base;
179787d66f28SThierry Reding }
179887d66f28SThierry Reding 
179987d66f28SThierry Reding static void tegra210_sata_lane_remove(struct tegra_xusb_lane *lane)
180087d66f28SThierry Reding {
180187d66f28SThierry Reding 	struct tegra_xusb_sata_lane *sata = to_sata_lane(lane);
180287d66f28SThierry Reding 
180387d66f28SThierry Reding 	kfree(sata);
180487d66f28SThierry Reding }
180587d66f28SThierry Reding 
180687d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_sata_lane_ops = {
180787d66f28SThierry Reding 	.probe = tegra210_sata_lane_probe,
180887d66f28SThierry Reding 	.remove = tegra210_sata_lane_remove,
180987d66f28SThierry Reding };
181087d66f28SThierry Reding 
181187d66f28SThierry Reding static int tegra210_sata_phy_init(struct phy *phy)
181287d66f28SThierry Reding {
181387d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
181487d66f28SThierry Reding 
181587d66f28SThierry Reding 	return tegra210_xusb_padctl_enable(lane->pad->padctl);
181687d66f28SThierry Reding }
181787d66f28SThierry Reding 
181887d66f28SThierry Reding static int tegra210_sata_phy_exit(struct phy *phy)
181987d66f28SThierry Reding {
182087d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
182187d66f28SThierry Reding 
182287d66f28SThierry Reding 	return tegra210_xusb_padctl_disable(lane->pad->padctl);
182387d66f28SThierry Reding }
182487d66f28SThierry Reding 
182587d66f28SThierry Reding static int tegra210_sata_phy_power_on(struct phy *phy)
182687d66f28SThierry Reding {
182787d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
182887d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
182987d66f28SThierry Reding 	u32 value;
183087d66f28SThierry Reding 	int err;
183187d66f28SThierry Reding 
183287d66f28SThierry Reding 	mutex_lock(&padctl->lock);
183387d66f28SThierry Reding 
183487d66f28SThierry Reding 	err = tegra210_sata_uphy_enable(padctl, false);
183587d66f28SThierry Reding 	if (err < 0)
183687d66f28SThierry Reding 		goto unlock;
183787d66f28SThierry Reding 
183887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
183987d66f28SThierry Reding 	value |= XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(lane->index);
184087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
184187d66f28SThierry Reding 
184287d66f28SThierry Reding unlock:
184387d66f28SThierry Reding 	mutex_unlock(&padctl->lock);
184487d66f28SThierry Reding 	return err;
184587d66f28SThierry Reding }
184687d66f28SThierry Reding 
184787d66f28SThierry Reding static int tegra210_sata_phy_power_off(struct phy *phy)
184887d66f28SThierry Reding {
184987d66f28SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
185087d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
185187d66f28SThierry Reding 	u32 value;
185287d66f28SThierry Reding 
185387d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
185487d66f28SThierry Reding 	value &= ~XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(lane->index);
185587d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
185687d66f28SThierry Reding 
185787d66f28SThierry Reding 	tegra210_sata_uphy_disable(lane->pad->padctl);
185887d66f28SThierry Reding 
185987d66f28SThierry Reding 	return 0;
186087d66f28SThierry Reding }
186187d66f28SThierry Reding 
186287d66f28SThierry Reding static const struct phy_ops tegra210_sata_phy_ops = {
186387d66f28SThierry Reding 	.init = tegra210_sata_phy_init,
186487d66f28SThierry Reding 	.exit = tegra210_sata_phy_exit,
186587d66f28SThierry Reding 	.power_on = tegra210_sata_phy_power_on,
186687d66f28SThierry Reding 	.power_off = tegra210_sata_phy_power_off,
186787d66f28SThierry Reding 	.owner = THIS_MODULE,
186887d66f28SThierry Reding };
186987d66f28SThierry Reding 
187087d66f28SThierry Reding static struct tegra_xusb_pad *
187187d66f28SThierry Reding tegra210_sata_pad_probe(struct tegra_xusb_padctl *padctl,
187287d66f28SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
187387d66f28SThierry Reding 			struct device_node *np)
187487d66f28SThierry Reding {
187587d66f28SThierry Reding 	struct tegra_xusb_sata_pad *sata;
187687d66f28SThierry Reding 	struct tegra_xusb_pad *pad;
187787d66f28SThierry Reding 	int err;
187887d66f28SThierry Reding 
187987d66f28SThierry Reding 	sata = kzalloc(sizeof(*sata), GFP_KERNEL);
188087d66f28SThierry Reding 	if (!sata)
188187d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
188287d66f28SThierry Reding 
188387d66f28SThierry Reding 	pad = &sata->base;
188487d66f28SThierry Reding 	pad->ops = &tegra210_sata_lane_ops;
188587d66f28SThierry Reding 	pad->soc = soc;
188687d66f28SThierry Reding 
188787d66f28SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
188887d66f28SThierry Reding 	if (err < 0) {
188987d66f28SThierry Reding 		kfree(sata);
189087d66f28SThierry Reding 		goto out;
189187d66f28SThierry Reding 	}
189287d66f28SThierry Reding 
189387d66f28SThierry Reding 	sata->rst = devm_reset_control_get(&pad->dev, "phy");
189487d66f28SThierry Reding 	if (IS_ERR(sata->rst)) {
189587d66f28SThierry Reding 		err = PTR_ERR(sata->rst);
189687d66f28SThierry Reding 		dev_err(&pad->dev, "failed to get SATA pad reset: %d\n", err);
189787d66f28SThierry Reding 		goto unregister;
189887d66f28SThierry Reding 	}
189987d66f28SThierry Reding 
190087d66f28SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra210_sata_phy_ops);
190187d66f28SThierry Reding 	if (err < 0)
190287d66f28SThierry Reding 		goto unregister;
190387d66f28SThierry Reding 
190487d66f28SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
190587d66f28SThierry Reding 
190687d66f28SThierry Reding 	return pad;
190787d66f28SThierry Reding 
190887d66f28SThierry Reding unregister:
190987d66f28SThierry Reding 	device_unregister(&pad->dev);
191087d66f28SThierry Reding out:
191187d66f28SThierry Reding 	return ERR_PTR(err);
191287d66f28SThierry Reding }
191387d66f28SThierry Reding 
191487d66f28SThierry Reding static void tegra210_sata_pad_remove(struct tegra_xusb_pad *pad)
191587d66f28SThierry Reding {
191687d66f28SThierry Reding 	struct tegra_xusb_sata_pad *sata = to_sata_pad(pad);
191787d66f28SThierry Reding 
191887d66f28SThierry Reding 	kfree(sata);
191987d66f28SThierry Reding }
192087d66f28SThierry Reding 
192187d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_sata_ops = {
192287d66f28SThierry Reding 	.probe = tegra210_sata_pad_probe,
192387d66f28SThierry Reding 	.remove = tegra210_sata_pad_remove,
192487d66f28SThierry Reding };
192587d66f28SThierry Reding 
192687d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_sata_pad = {
192787d66f28SThierry Reding 	.name = "sata",
192887d66f28SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra210_sata_lanes),
192987d66f28SThierry Reding 	.lanes = tegra210_sata_lanes,
193087d66f28SThierry Reding 	.ops = &tegra210_sata_ops,
193187d66f28SThierry Reding };
193287d66f28SThierry Reding 
193387d66f28SThierry Reding static const struct tegra_xusb_pad_soc * const tegra210_pads[] = {
193487d66f28SThierry Reding 	&tegra210_usb2_pad,
193587d66f28SThierry Reding 	&tegra210_hsic_pad,
193687d66f28SThierry Reding 	&tegra210_pcie_pad,
193787d66f28SThierry Reding 	&tegra210_sata_pad,
193887d66f28SThierry Reding };
193987d66f28SThierry Reding 
194087d66f28SThierry Reding static int tegra210_usb2_port_enable(struct tegra_xusb_port *port)
194187d66f28SThierry Reding {
194287d66f28SThierry Reding 	return 0;
194387d66f28SThierry Reding }
194487d66f28SThierry Reding 
194587d66f28SThierry Reding static void tegra210_usb2_port_disable(struct tegra_xusb_port *port)
194687d66f28SThierry Reding {
194787d66f28SThierry Reding }
194887d66f28SThierry Reding 
194987d66f28SThierry Reding static struct tegra_xusb_lane *
195087d66f28SThierry Reding tegra210_usb2_port_map(struct tegra_xusb_port *port)
195187d66f28SThierry Reding {
195287d66f28SThierry Reding 	return tegra_xusb_find_lane(port->padctl, "usb2", port->index);
195387d66f28SThierry Reding }
195487d66f28SThierry Reding 
195587d66f28SThierry Reding static const struct tegra_xusb_port_ops tegra210_usb2_port_ops = {
195687d66f28SThierry Reding 	.enable = tegra210_usb2_port_enable,
195787d66f28SThierry Reding 	.disable = tegra210_usb2_port_disable,
195887d66f28SThierry Reding 	.map = tegra210_usb2_port_map,
195987d66f28SThierry Reding };
196087d66f28SThierry Reding 
196187d66f28SThierry Reding static int tegra210_hsic_port_enable(struct tegra_xusb_port *port)
196287d66f28SThierry Reding {
196387d66f28SThierry Reding 	return 0;
196487d66f28SThierry Reding }
196587d66f28SThierry Reding 
196687d66f28SThierry Reding static void tegra210_hsic_port_disable(struct tegra_xusb_port *port)
196787d66f28SThierry Reding {
196887d66f28SThierry Reding }
196987d66f28SThierry Reding 
197087d66f28SThierry Reding static struct tegra_xusb_lane *
197187d66f28SThierry Reding tegra210_hsic_port_map(struct tegra_xusb_port *port)
197287d66f28SThierry Reding {
197387d66f28SThierry Reding 	return tegra_xusb_find_lane(port->padctl, "hsic", port->index);
197487d66f28SThierry Reding }
197587d66f28SThierry Reding 
197687d66f28SThierry Reding static const struct tegra_xusb_port_ops tegra210_hsic_port_ops = {
197787d66f28SThierry Reding 	.enable = tegra210_hsic_port_enable,
197887d66f28SThierry Reding 	.disable = tegra210_hsic_port_disable,
197987d66f28SThierry Reding 	.map = tegra210_hsic_port_map,
198087d66f28SThierry Reding };
198187d66f28SThierry Reding 
198287d66f28SThierry Reding static int tegra210_usb3_port_enable(struct tegra_xusb_port *port)
198387d66f28SThierry Reding {
198487d66f28SThierry Reding 	struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port);
198587d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = port->padctl;
198687d66f28SThierry Reding 	struct tegra_xusb_lane *lane = usb3->base.lane;
198787d66f28SThierry Reding 	unsigned int index = port->index;
198887d66f28SThierry Reding 	u32 value;
198987d66f28SThierry Reding 	int err;
199087d66f28SThierry Reding 
199187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
199287d66f28SThierry Reding 
199387d66f28SThierry Reding 	if (!usb3->internal)
199487d66f28SThierry Reding 		value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index);
199587d66f28SThierry Reding 	else
199687d66f28SThierry Reding 		value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index);
199787d66f28SThierry Reding 
199887d66f28SThierry Reding 	value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(index);
199987d66f28SThierry Reding 	value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(index, usb3->port);
200087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP);
200187d66f28SThierry Reding 
200287d66f28SThierry Reding 	/*
200387d66f28SThierry Reding 	 * TODO: move this code into the PCIe/SATA PHY ->power_on() callbacks
200487d66f28SThierry Reding 	 * and conditionalize based on mux function? This seems to work, but
200587d66f28SThierry Reding 	 * might not be the exact proper sequence.
200687d66f28SThierry Reding 	 */
200787d66f28SThierry Reding 	err = regulator_enable(usb3->supply);
200887d66f28SThierry Reding 	if (err < 0)
200987d66f28SThierry Reding 		return err;
201087d66f28SThierry Reding 
201187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(index));
201287d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_MASK <<
201387d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT);
201487d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_VAL <<
201587d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT;
201687d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(index));
201787d66f28SThierry Reding 
201887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(index));
201987d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_MASK <<
202087d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT);
202187d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_VAL <<
202287d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT;
202387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(index));
202487d66f28SThierry Reding 
202587d66f28SThierry Reding 	padctl_writel(padctl, XUSB_PADCTL_UPHY_USB3_PAD_ECTL3_RX_DFE_VAL,
202687d66f28SThierry Reding 		      XUSB_PADCTL_UPHY_USB3_PADX_ECTL3(index));
202787d66f28SThierry Reding 
202887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(index));
202987d66f28SThierry Reding 	value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_MASK <<
203087d66f28SThierry Reding 		   XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT);
203187d66f28SThierry Reding 	value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_VAL <<
203287d66f28SThierry Reding 		 XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT;
203387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(index));
203487d66f28SThierry Reding 
203587d66f28SThierry Reding 	padctl_writel(padctl, XUSB_PADCTL_UPHY_USB3_PAD_ECTL6_RX_EQ_CTRL_H_VAL,
203687d66f28SThierry Reding 		      XUSB_PADCTL_UPHY_USB3_PADX_ECTL6(index));
203787d66f28SThierry Reding 
203887d66f28SThierry Reding 	if (lane->pad == padctl->sata)
203987d66f28SThierry Reding 		err = tegra210_sata_uphy_enable(padctl, true);
204087d66f28SThierry Reding 	else
204187d66f28SThierry Reding 		err = tegra210_pex_uphy_enable(padctl);
204287d66f28SThierry Reding 
204387d66f28SThierry Reding 	if (err) {
204487d66f28SThierry Reding 		dev_err(&port->dev, "%s: failed to enable UPHY: %d\n",
204587d66f28SThierry Reding 			__func__, err);
204687d66f28SThierry Reding 		return err;
204787d66f28SThierry Reding 	}
204887d66f28SThierry Reding 
204987d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
205087d66f28SThierry Reding 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(index);
205187d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
205287d66f28SThierry Reding 
205387d66f28SThierry Reding 	usleep_range(100, 200);
205487d66f28SThierry Reding 
205587d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
205687d66f28SThierry Reding 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(index);
205787d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
205887d66f28SThierry Reding 
205987d66f28SThierry Reding 	usleep_range(100, 200);
206087d66f28SThierry Reding 
206187d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
206287d66f28SThierry Reding 	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(index);
206387d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
206487d66f28SThierry Reding 
206587d66f28SThierry Reding 	return 0;
206687d66f28SThierry Reding }
206787d66f28SThierry Reding 
206887d66f28SThierry Reding static void tegra210_usb3_port_disable(struct tegra_xusb_port *port)
206987d66f28SThierry Reding {
207087d66f28SThierry Reding 	struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port);
207187d66f28SThierry Reding 	struct tegra_xusb_padctl *padctl = port->padctl;
207287d66f28SThierry Reding 	struct tegra_xusb_lane *lane = port->lane;
207387d66f28SThierry Reding 	unsigned int index = port->index;
207487d66f28SThierry Reding 	u32 value;
207587d66f28SThierry Reding 
207687d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
207787d66f28SThierry Reding 	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(index);
207887d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
207987d66f28SThierry Reding 
208087d66f28SThierry Reding 	usleep_range(100, 200);
208187d66f28SThierry Reding 
208287d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
208387d66f28SThierry Reding 	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(index);
208487d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
208587d66f28SThierry Reding 
208687d66f28SThierry Reding 	usleep_range(250, 350);
208787d66f28SThierry Reding 
208887d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
208987d66f28SThierry Reding 	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(index);
209087d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
209187d66f28SThierry Reding 
209287d66f28SThierry Reding 	if (lane->pad == padctl->sata)
209387d66f28SThierry Reding 		tegra210_sata_uphy_disable(padctl);
209487d66f28SThierry Reding 	else
209587d66f28SThierry Reding 		tegra210_pex_uphy_disable(padctl);
209687d66f28SThierry Reding 
209787d66f28SThierry Reding 	regulator_disable(usb3->supply);
209887d66f28SThierry Reding 
209987d66f28SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
210087d66f28SThierry Reding 	value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(index);
210187d66f28SThierry Reding 	value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(index, 0x7);
210287d66f28SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP);
210387d66f28SThierry Reding }
210487d66f28SThierry Reding 
210587d66f28SThierry Reding static const struct tegra_xusb_lane_map tegra210_usb3_map[] = {
210687d66f28SThierry Reding 	{ 0, "pcie", 6 },
210787d66f28SThierry Reding 	{ 1, "pcie", 5 },
210887d66f28SThierry Reding 	{ 2, "pcie", 0 },
210987d66f28SThierry Reding 	{ 2, "pcie", 3 },
211087d66f28SThierry Reding 	{ 3, "pcie", 4 },
211187d66f28SThierry Reding 	{ 3, "pcie", 4 },
211287d66f28SThierry Reding 	{ 0, NULL,   0 }
211387d66f28SThierry Reding };
211487d66f28SThierry Reding 
211587d66f28SThierry Reding static struct tegra_xusb_lane *
211687d66f28SThierry Reding tegra210_usb3_port_map(struct tegra_xusb_port *port)
211787d66f28SThierry Reding {
211887d66f28SThierry Reding 	return tegra_xusb_port_find_lane(port, tegra210_usb3_map, "usb3-ss");
211987d66f28SThierry Reding }
212087d66f28SThierry Reding 
212187d66f28SThierry Reding static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = {
212287d66f28SThierry Reding 	.enable = tegra210_usb3_port_enable,
212387d66f28SThierry Reding 	.disable = tegra210_usb3_port_disable,
212487d66f28SThierry Reding 	.map = tegra210_usb3_port_map,
212587d66f28SThierry Reding };
212687d66f28SThierry Reding 
212790767cdfSNagarjuna Kristam static int tegra210_utmi_port_reset(struct phy *phy)
212890767cdfSNagarjuna Kristam {
212990767cdfSNagarjuna Kristam 	struct tegra_xusb_padctl *padctl;
213090767cdfSNagarjuna Kristam 	struct tegra_xusb_lane *lane;
213190767cdfSNagarjuna Kristam 	u32 value;
213290767cdfSNagarjuna Kristam 
213390767cdfSNagarjuna Kristam 	lane = phy_get_drvdata(phy);
213490767cdfSNagarjuna Kristam 	padctl = lane->pad->padctl;
213590767cdfSNagarjuna Kristam 
213690767cdfSNagarjuna Kristam 	value = padctl_readl(padctl,
213790767cdfSNagarjuna Kristam 		     XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL0(lane->index));
213890767cdfSNagarjuna Kristam 
213990767cdfSNagarjuna Kristam 	if ((value & XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIP) ||
214090767cdfSNagarjuna Kristam 	    (value & XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIN)) {
214190767cdfSNagarjuna Kristam 		tegra210_xusb_padctl_vbus_override(padctl, false);
214290767cdfSNagarjuna Kristam 		tegra210_xusb_padctl_vbus_override(padctl, true);
214390767cdfSNagarjuna Kristam 		return 1;
214490767cdfSNagarjuna Kristam 	}
214590767cdfSNagarjuna Kristam 
214690767cdfSNagarjuna Kristam 	return 0;
214790767cdfSNagarjuna Kristam }
214890767cdfSNagarjuna Kristam 
214987d66f28SThierry Reding static int
215087d66f28SThierry Reding tegra210_xusb_read_fuse_calibration(struct tegra210_xusb_fuse_calibration *fuse)
215187d66f28SThierry Reding {
215287d66f28SThierry Reding 	unsigned int i;
215387d66f28SThierry Reding 	u32 value;
215487d66f28SThierry Reding 	int err;
215587d66f28SThierry Reding 
215687d66f28SThierry Reding 	err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value);
215787d66f28SThierry Reding 	if (err < 0)
215887d66f28SThierry Reding 		return err;
215987d66f28SThierry Reding 
216087d66f28SThierry Reding 	for (i = 0; i < ARRAY_SIZE(fuse->hs_curr_level); i++) {
216187d66f28SThierry Reding 		fuse->hs_curr_level[i] =
216287d66f28SThierry Reding 			(value >> FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(i)) &
216387d66f28SThierry Reding 			FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK;
216487d66f28SThierry Reding 	}
216587d66f28SThierry Reding 
216687d66f28SThierry Reding 	fuse->hs_term_range_adj =
216787d66f28SThierry Reding 		(value >> FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT) &
216887d66f28SThierry Reding 		FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK;
216987d66f28SThierry Reding 
217087d66f28SThierry Reding 	err = tegra_fuse_readl(TEGRA_FUSE_USB_CALIB_EXT_0, &value);
217187d66f28SThierry Reding 	if (err < 0)
217287d66f28SThierry Reding 		return err;
217387d66f28SThierry Reding 
217487d66f28SThierry Reding 	fuse->rpd_ctrl =
217587d66f28SThierry Reding 		(value >> FUSE_USB_CALIB_EXT_RPD_CTRL_SHIFT) &
217687d66f28SThierry Reding 		FUSE_USB_CALIB_EXT_RPD_CTRL_MASK;
217787d66f28SThierry Reding 
217887d66f28SThierry Reding 	return 0;
217987d66f28SThierry Reding }
218087d66f28SThierry Reding 
218187d66f28SThierry Reding static struct tegra_xusb_padctl *
218287d66f28SThierry Reding tegra210_xusb_padctl_probe(struct device *dev,
218387d66f28SThierry Reding 			   const struct tegra_xusb_padctl_soc *soc)
218487d66f28SThierry Reding {
218587d66f28SThierry Reding 	struct tegra210_xusb_padctl *padctl;
218687d66f28SThierry Reding 	int err;
218787d66f28SThierry Reding 
218887d66f28SThierry Reding 	padctl = devm_kzalloc(dev, sizeof(*padctl), GFP_KERNEL);
218987d66f28SThierry Reding 	if (!padctl)
219087d66f28SThierry Reding 		return ERR_PTR(-ENOMEM);
219187d66f28SThierry Reding 
219287d66f28SThierry Reding 	padctl->base.dev = dev;
219387d66f28SThierry Reding 	padctl->base.soc = soc;
219487d66f28SThierry Reding 
219587d66f28SThierry Reding 	err = tegra210_xusb_read_fuse_calibration(&padctl->fuse);
219687d66f28SThierry Reding 	if (err < 0)
219787d66f28SThierry Reding 		return ERR_PTR(err);
219887d66f28SThierry Reding 
219987d66f28SThierry Reding 	return &padctl->base;
220087d66f28SThierry Reding }
220187d66f28SThierry Reding 
220287d66f28SThierry Reding static void tegra210_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
220387d66f28SThierry Reding {
220487d66f28SThierry Reding }
220587d66f28SThierry Reding 
220687d66f28SThierry Reding static const struct tegra_xusb_padctl_ops tegra210_xusb_padctl_ops = {
220787d66f28SThierry Reding 	.probe = tegra210_xusb_padctl_probe,
220887d66f28SThierry Reding 	.remove = tegra210_xusb_padctl_remove,
220987d66f28SThierry Reding 	.usb3_set_lfps_detect = tegra210_usb3_set_lfps_detect,
221087d66f28SThierry Reding 	.hsic_set_idle = tegra210_hsic_set_idle,
221190767cdfSNagarjuna Kristam 	.vbus_override = tegra210_xusb_padctl_vbus_override,
221290767cdfSNagarjuna Kristam 	.utmi_port_reset = tegra210_utmi_port_reset,
221387d66f28SThierry Reding };
221487d66f28SThierry Reding 
2215e3888cdaSThierry Reding static const char * const tegra210_xusb_padctl_supply_names[] = {
2216e3888cdaSThierry Reding 	"avdd-pll-utmip",
2217e3888cdaSThierry Reding 	"avdd-pll-uerefe",
2218e3888cdaSThierry Reding 	"dvdd-pex-pll",
2219e3888cdaSThierry Reding 	"hvdd-pex-pll-e",
2220e3888cdaSThierry Reding };
2221e3888cdaSThierry Reding 
222287d66f28SThierry Reding const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc = {
222387d66f28SThierry Reding 	.num_pads = ARRAY_SIZE(tegra210_pads),
222487d66f28SThierry Reding 	.pads = tegra210_pads,
222587d66f28SThierry Reding 	.ports = {
222687d66f28SThierry Reding 		.usb2 = {
222787d66f28SThierry Reding 			.ops = &tegra210_usb2_port_ops,
222887d66f28SThierry Reding 			.count = 4,
222987d66f28SThierry Reding 		},
223087d66f28SThierry Reding 		.hsic = {
223187d66f28SThierry Reding 			.ops = &tegra210_hsic_port_ops,
223287d66f28SThierry Reding 			.count = 1,
223387d66f28SThierry Reding 		},
223487d66f28SThierry Reding 		.usb3 = {
223587d66f28SThierry Reding 			.ops = &tegra210_usb3_port_ops,
223687d66f28SThierry Reding 			.count = 4,
223787d66f28SThierry Reding 		},
223887d66f28SThierry Reding 	},
223987d66f28SThierry Reding 	.ops = &tegra210_xusb_padctl_ops,
2240e3888cdaSThierry Reding 	.supply_names = tegra210_xusb_padctl_supply_names,
2241e3888cdaSThierry Reding 	.num_supplies = ARRAY_SIZE(tegra210_xusb_padctl_supply_names),
2242a5be28c3SNagarjuna Kristam 	.need_fake_usb3_port = true,
224387d66f28SThierry Reding };
224487d66f28SThierry Reding EXPORT_SYMBOL_GPL(tegra210_xusb_padctl_soc);
224587d66f28SThierry Reding 
224687d66f28SThierry Reding MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>");
224787d66f28SThierry Reding MODULE_DESCRIPTION("NVIDIA Tegra 210 XUSB Pad Controller driver");
224887d66f28SThierry Reding MODULE_LICENSE("GPL v2");
2249