1bbf71168SJC Kuo // SPDX-License-Identifier: GPL-2.0
2bbf71168SJC Kuo /*
377bfa0fcSJim Lin  * Copyright (c) 2016-2022, NVIDIA CORPORATION.  All rights reserved.
4bbf71168SJC Kuo  */
5bbf71168SJC Kuo 
6bbf71168SJC Kuo #include <linux/delay.h>
7bbf71168SJC Kuo #include <linux/io.h>
8bbf71168SJC Kuo #include <linux/module.h>
9bbf71168SJC Kuo #include <linux/of.h>
10bbf71168SJC Kuo #include <linux/phy/phy.h>
11bbf71168SJC Kuo #include <linux/regulator/consumer.h>
12bbf71168SJC Kuo #include <linux/platform_device.h>
13bbf71168SJC Kuo #include <linux/clk.h>
14bbf71168SJC Kuo #include <linux/slab.h>
15bbf71168SJC Kuo 
16bbf71168SJC Kuo #include <soc/tegra/fuse.h>
17bbf71168SJC Kuo 
18bbf71168SJC Kuo #include "xusb.h"
19bbf71168SJC Kuo 
20bbf71168SJC Kuo /* FUSE USB_CALIB registers */
21bbf71168SJC Kuo #define HS_CURR_LEVEL_PADX_SHIFT(x)	((x) ? (11 + (x - 1) * 6) : 0)
22bbf71168SJC Kuo #define HS_CURR_LEVEL_PAD_MASK		0x3f
23bbf71168SJC Kuo #define HS_TERM_RANGE_ADJ_SHIFT		7
24bbf71168SJC Kuo #define HS_TERM_RANGE_ADJ_MASK		0xf
25bbf71168SJC Kuo #define HS_SQUELCH_SHIFT		29
26bbf71168SJC Kuo #define HS_SQUELCH_MASK			0x7
27bbf71168SJC Kuo 
28bbf71168SJC Kuo #define RPD_CTRL_SHIFT			0
29bbf71168SJC Kuo #define RPD_CTRL_MASK			0x1f
30bbf71168SJC Kuo 
31bbf71168SJC Kuo /* XUSB PADCTL registers */
32bbf71168SJC Kuo #define XUSB_PADCTL_USB2_PAD_MUX	0x4
33bbf71168SJC Kuo #define  USB2_PORT_SHIFT(x)		((x) * 2)
34bbf71168SJC Kuo #define  USB2_PORT_MASK			0x3
35bbf71168SJC Kuo #define   PORT_XUSB			1
36bbf71168SJC Kuo #define  HSIC_PORT_SHIFT(x)		((x) + 20)
37bbf71168SJC Kuo #define  HSIC_PORT_MASK			0x1
38bbf71168SJC Kuo #define   PORT_HSIC			0
39bbf71168SJC Kuo 
40bbf71168SJC Kuo #define XUSB_PADCTL_USB2_PORT_CAP	0x8
41bbf71168SJC Kuo #define XUSB_PADCTL_SS_PORT_CAP		0xc
42bbf71168SJC Kuo #define  PORTX_CAP_SHIFT(x)		((x) * 4)
43bbf71168SJC Kuo #define  PORT_CAP_MASK			0x3
44bbf71168SJC Kuo #define   PORT_CAP_DISABLED		0x0
45bbf71168SJC Kuo #define   PORT_CAP_HOST			0x1
46bbf71168SJC Kuo #define   PORT_CAP_DEVICE		0x2
47bbf71168SJC Kuo #define   PORT_CAP_OTG			0x3
48bbf71168SJC Kuo 
49bbf71168SJC Kuo #define XUSB_PADCTL_ELPG_PROGRAM		0x20
50bbf71168SJC Kuo #define  USB2_PORT_WAKE_INTERRUPT_ENABLE(x)		BIT(x)
51bbf71168SJC Kuo #define  USB2_PORT_WAKEUP_EVENT(x)			BIT((x) +  7)
52bbf71168SJC Kuo #define  SS_PORT_WAKE_INTERRUPT_ENABLE(x)		BIT((x) + 14)
53bbf71168SJC Kuo #define  SS_PORT_WAKEUP_EVENT(x)			BIT((x) + 21)
54bbf71168SJC Kuo #define  USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(x)	BIT((x) + 28)
55bbf71168SJC Kuo #define  USB2_HSIC_PORT_WAKEUP_EVENT(x)			BIT((x) + 30)
56bbf71168SJC Kuo #define  ALL_WAKE_EVENTS						\
57bbf71168SJC Kuo 	(USB2_PORT_WAKEUP_EVENT(0) | USB2_PORT_WAKEUP_EVENT(1) |	\
58bbf71168SJC Kuo 	USB2_PORT_WAKEUP_EVENT(2) | SS_PORT_WAKEUP_EVENT(0) |		\
59bbf71168SJC Kuo 	SS_PORT_WAKEUP_EVENT(1) | SS_PORT_WAKEUP_EVENT(2) |		\
60bbf71168SJC Kuo 	USB2_HSIC_PORT_WAKEUP_EVENT(0))
61bbf71168SJC Kuo 
62bbf71168SJC Kuo #define XUSB_PADCTL_ELPG_PROGRAM_1		0x24
63bbf71168SJC Kuo #define  SSPX_ELPG_CLAMP_EN(x)			BIT(0 + (x) * 3)
64bbf71168SJC Kuo #define  SSPX_ELPG_CLAMP_EN_EARLY(x)		BIT(1 + (x) * 3)
65bbf71168SJC Kuo #define  SSPX_ELPG_VCORE_DOWN(x)		BIT(2 + (x) * 3)
661ef535c6SJC Kuo #define XUSB_PADCTL_SS_PORT_CFG			0x2c
671ef535c6SJC Kuo #define   PORTX_SPEED_SUPPORT_SHIFT(x)		((x) * 4)
681ef535c6SJC Kuo #define   PORTX_SPEED_SUPPORT_MASK		(0x3)
691ef535c6SJC Kuo #define     PORT_SPEED_SUPPORT_GEN1		(0x0)
70bbf71168SJC Kuo 
71bbf71168SJC Kuo #define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x)	(0x88 + (x) * 0x40)
72bbf71168SJC Kuo #define  HS_CURR_LEVEL(x)			((x) & 0x3f)
73bbf71168SJC Kuo #define  TERM_SEL				BIT(25)
74bbf71168SJC Kuo #define  USB2_OTG_PD				BIT(26)
75bbf71168SJC Kuo #define  USB2_OTG_PD2				BIT(27)
76bbf71168SJC Kuo #define  USB2_OTG_PD2_OVRD_EN			BIT(28)
77bbf71168SJC Kuo #define  USB2_OTG_PD_ZI				BIT(29)
78bbf71168SJC Kuo 
79bbf71168SJC Kuo #define XUSB_PADCTL_USB2_OTG_PADX_CTL1(x)	(0x8c + (x) * 0x40)
80bbf71168SJC Kuo #define  USB2_OTG_PD_DR				BIT(2)
81bbf71168SJC Kuo #define  TERM_RANGE_ADJ(x)			(((x) & 0xf) << 3)
82bbf71168SJC Kuo #define  RPD_CTRL(x)				(((x) & 0x1f) << 26)
83bbf71168SJC Kuo 
84bbf71168SJC Kuo #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0		0x284
85bbf71168SJC Kuo #define  BIAS_PAD_PD				BIT(11)
86bbf71168SJC Kuo #define  HS_SQUELCH_LEVEL(x)			(((x) & 0x7) << 0)
87bbf71168SJC Kuo 
88bbf71168SJC Kuo #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1		0x288
89bbf71168SJC Kuo #define  USB2_TRK_START_TIMER(x)		(((x) & 0x7f) << 12)
90bbf71168SJC Kuo #define  USB2_TRK_DONE_RESET_TIMER(x)		(((x) & 0x7f) << 19)
91bbf71168SJC Kuo #define  USB2_PD_TRK				BIT(26)
92d8163a32SSing-Han Chen #define  USB2_TRK_COMPLETED			BIT(31)
93d8163a32SSing-Han Chen 
94d8163a32SSing-Han Chen #define XUSB_PADCTL_USB2_BIAS_PAD_CTL2		0x28c
95d8163a32SSing-Han Chen #define  USB2_TRK_HW_MODE			BIT(0)
96d8163a32SSing-Han Chen #define  CYA_TRK_CODE_UPDATE_ON_IDLE		BIT(31)
97bbf71168SJC Kuo 
98bbf71168SJC Kuo #define XUSB_PADCTL_HSIC_PADX_CTL0(x)		(0x300 + (x) * 0x20)
99bbf71168SJC Kuo #define  HSIC_PD_TX_DATA0			BIT(1)
100bbf71168SJC Kuo #define  HSIC_PD_TX_STROBE			BIT(3)
101bbf71168SJC Kuo #define  HSIC_PD_RX_DATA0			BIT(4)
102bbf71168SJC Kuo #define  HSIC_PD_RX_STROBE			BIT(6)
103bbf71168SJC Kuo #define  HSIC_PD_ZI_DATA0			BIT(7)
104bbf71168SJC Kuo #define  HSIC_PD_ZI_STROBE			BIT(9)
105bbf71168SJC Kuo #define  HSIC_RPD_DATA0				BIT(13)
106bbf71168SJC Kuo #define  HSIC_RPD_STROBE			BIT(15)
107bbf71168SJC Kuo #define  HSIC_RPU_DATA0				BIT(16)
108bbf71168SJC Kuo #define  HSIC_RPU_STROBE			BIT(18)
109bbf71168SJC Kuo 
110bbf71168SJC Kuo #define XUSB_PADCTL_HSIC_PAD_TRK_CTL0		0x340
111bbf71168SJC Kuo #define  HSIC_TRK_START_TIMER(x)		(((x) & 0x7f) << 5)
112bbf71168SJC Kuo #define  HSIC_TRK_DONE_RESET_TIMER(x)		(((x) & 0x7f) << 12)
113bbf71168SJC Kuo #define  HSIC_PD_TRK				BIT(19)
114bbf71168SJC Kuo 
115bbf71168SJC Kuo #define USB2_VBUS_ID				0x360
116bbf71168SJC Kuo #define  VBUS_OVERRIDE				BIT(14)
117bbf71168SJC Kuo #define  ID_OVERRIDE(x)				(((x) & 0xf) << 18)
118bbf71168SJC Kuo #define  ID_OVERRIDE_FLOATING			ID_OVERRIDE(8)
119bbf71168SJC Kuo #define  ID_OVERRIDE_GROUNDED			ID_OVERRIDE(0)
120bbf71168SJC Kuo 
1211f9cab6cSJC Kuo /* XUSB AO registers */
1221f9cab6cSJC Kuo #define XUSB_AO_USB_DEBOUNCE_DEL		(0x4)
1231f9cab6cSJC Kuo #define   UHSIC_LINE_DEB_CNT(x)			(((x) & 0xf) << 4)
1241f9cab6cSJC Kuo #define   UTMIP_LINE_DEB_CNT(x)			((x) & 0xf)
1251f9cab6cSJC Kuo 
1261f9cab6cSJC Kuo #define XUSB_AO_UTMIP_TRIGGERS(x)		(0x40 + (x) * 4)
1271f9cab6cSJC Kuo #define   CLR_WALK_PTR				BIT(0)
1281f9cab6cSJC Kuo #define   CAP_CFG				BIT(1)
1291f9cab6cSJC Kuo #define   CLR_WAKE_ALARM			BIT(3)
1301f9cab6cSJC Kuo 
1311f9cab6cSJC Kuo #define XUSB_AO_UHSIC_TRIGGERS(x)		(0x60 + (x) * 4)
1321f9cab6cSJC Kuo #define   HSIC_CLR_WALK_PTR			BIT(0)
1331f9cab6cSJC Kuo #define   HSIC_CLR_WAKE_ALARM			BIT(3)
1341f9cab6cSJC Kuo #define   HSIC_CAP_CFG				BIT(4)
1351f9cab6cSJC Kuo 
1361f9cab6cSJC Kuo #define XUSB_AO_UTMIP_SAVED_STATE(x)		(0x70 + (x) * 4)
1371f9cab6cSJC Kuo #define   SPEED(x)				((x) & 0x3)
1381f9cab6cSJC Kuo #define     UTMI_HS				SPEED(0)
1391f9cab6cSJC Kuo #define     UTMI_FS				SPEED(1)
1401f9cab6cSJC Kuo #define     UTMI_LS				SPEED(2)
1411f9cab6cSJC Kuo #define     UTMI_RST				SPEED(3)
1421f9cab6cSJC Kuo 
1431f9cab6cSJC Kuo #define XUSB_AO_UHSIC_SAVED_STATE(x)		(0x90 + (x) * 4)
1441f9cab6cSJC Kuo #define   MODE(x)				((x) & 0x1)
1451f9cab6cSJC Kuo #define   MODE_HS				MODE(0)
1461f9cab6cSJC Kuo #define   MODE_RST				MODE(1)
1471f9cab6cSJC Kuo 
148*8b798761SHenry Lin #define XUSB_AO_UTMIP_SLEEPWALK_STATUS(x)	(0xa0 + (x) * 4)
149*8b798761SHenry Lin 
1501f9cab6cSJC Kuo #define XUSB_AO_UTMIP_SLEEPWALK_CFG(x)		(0xd0 + (x) * 4)
1511f9cab6cSJC Kuo #define XUSB_AO_UHSIC_SLEEPWALK_CFG(x)		(0xf0 + (x) * 4)
1521f9cab6cSJC Kuo #define   FAKE_USBOP_VAL			BIT(0)
1531f9cab6cSJC Kuo #define   FAKE_USBON_VAL			BIT(1)
1541f9cab6cSJC Kuo #define   FAKE_USBOP_EN				BIT(2)
1551f9cab6cSJC Kuo #define   FAKE_USBON_EN				BIT(3)
1561f9cab6cSJC Kuo #define   FAKE_STROBE_VAL			BIT(0)
1571f9cab6cSJC Kuo #define   FAKE_DATA_VAL				BIT(1)
1581f9cab6cSJC Kuo #define   FAKE_STROBE_EN			BIT(2)
1591f9cab6cSJC Kuo #define   FAKE_DATA_EN				BIT(3)
1601f9cab6cSJC Kuo #define   WAKE_WALK_EN				BIT(14)
1611f9cab6cSJC Kuo #define   MASTER_ENABLE				BIT(15)
1621f9cab6cSJC Kuo #define   LINEVAL_WALK_EN			BIT(16)
1631f9cab6cSJC Kuo #define   WAKE_VAL(x)				(((x) & 0xf) << 17)
1641f9cab6cSJC Kuo #define     WAKE_VAL_NONE			WAKE_VAL(12)
1651f9cab6cSJC Kuo #define     WAKE_VAL_ANY			WAKE_VAL(15)
1661f9cab6cSJC Kuo #define     WAKE_VAL_DS10			WAKE_VAL(2)
1671f9cab6cSJC Kuo #define   LINE_WAKEUP_EN			BIT(21)
1681f9cab6cSJC Kuo #define   MASTER_CFG_SEL			BIT(22)
1691f9cab6cSJC Kuo 
1701f9cab6cSJC Kuo #define XUSB_AO_UTMIP_SLEEPWALK(x)		(0x100 + (x) * 4)
1711f9cab6cSJC Kuo /* phase A */
1721f9cab6cSJC Kuo #define   USBOP_RPD_A				BIT(0)
1731f9cab6cSJC Kuo #define   USBON_RPD_A				BIT(1)
1741f9cab6cSJC Kuo #define   AP_A					BIT(4)
1751f9cab6cSJC Kuo #define   AN_A					BIT(5)
1761f9cab6cSJC Kuo #define   HIGHZ_A				BIT(6)
177*8b798761SHenry Lin #define   MASTER_ENABLE_A			BIT(7)
1781f9cab6cSJC Kuo /* phase B */
1791f9cab6cSJC Kuo #define   USBOP_RPD_B				BIT(8)
1801f9cab6cSJC Kuo #define   USBON_RPD_B				BIT(9)
1811f9cab6cSJC Kuo #define   AP_B					BIT(12)
1821f9cab6cSJC Kuo #define   AN_B					BIT(13)
1831f9cab6cSJC Kuo #define   HIGHZ_B				BIT(14)
184*8b798761SHenry Lin #define   MASTER_ENABLE_B			BIT(15)
1851f9cab6cSJC Kuo /* phase C */
1861f9cab6cSJC Kuo #define   USBOP_RPD_C				BIT(16)
1871f9cab6cSJC Kuo #define   USBON_RPD_C				BIT(17)
1881f9cab6cSJC Kuo #define   AP_C					BIT(20)
1891f9cab6cSJC Kuo #define   AN_C					BIT(21)
1901f9cab6cSJC Kuo #define   HIGHZ_C				BIT(22)
191*8b798761SHenry Lin #define   MASTER_ENABLE_C			BIT(23)
1921f9cab6cSJC Kuo /* phase D */
1931f9cab6cSJC Kuo #define   USBOP_RPD_D				BIT(24)
1941f9cab6cSJC Kuo #define   USBON_RPD_D				BIT(25)
1951f9cab6cSJC Kuo #define   AP_D					BIT(28)
1961f9cab6cSJC Kuo #define   AN_D					BIT(29)
1971f9cab6cSJC Kuo #define   HIGHZ_D				BIT(30)
198*8b798761SHenry Lin #define   MASTER_ENABLE_D			BIT(31)
199*8b798761SHenry Lin #define   MASTER_ENABLE_B_C_D					\
200*8b798761SHenry Lin 	 (MASTER_ENABLE_B | MASTER_ENABLE_C | MASTER_ENABLE_D)
2011f9cab6cSJC Kuo 
2021f9cab6cSJC Kuo #define XUSB_AO_UHSIC_SLEEPWALK(x)		(0x120 + (x) * 4)
2031f9cab6cSJC Kuo /* phase A */
2041f9cab6cSJC Kuo #define   RPD_STROBE_A				BIT(0)
2051f9cab6cSJC Kuo #define   RPD_DATA0_A				BIT(1)
2061f9cab6cSJC Kuo #define   RPU_STROBE_A				BIT(2)
2071f9cab6cSJC Kuo #define   RPU_DATA0_A				BIT(3)
2081f9cab6cSJC Kuo /* phase B */
2091f9cab6cSJC Kuo #define   RPD_STROBE_B				BIT(8)
2101f9cab6cSJC Kuo #define   RPD_DATA0_B				BIT(9)
2111f9cab6cSJC Kuo #define   RPU_STROBE_B				BIT(10)
2121f9cab6cSJC Kuo #define   RPU_DATA0_B				BIT(11)
2131f9cab6cSJC Kuo /* phase C */
2141f9cab6cSJC Kuo #define   RPD_STROBE_C				BIT(16)
2151f9cab6cSJC Kuo #define   RPD_DATA0_C				BIT(17)
2161f9cab6cSJC Kuo #define   RPU_STROBE_C				BIT(18)
2171f9cab6cSJC Kuo #define   RPU_DATA0_C				BIT(19)
2181f9cab6cSJC Kuo /* phase D */
2191f9cab6cSJC Kuo #define   RPD_STROBE_D				BIT(24)
2201f9cab6cSJC Kuo #define   RPD_DATA0_D				BIT(25)
2211f9cab6cSJC Kuo #define   RPU_STROBE_D				BIT(26)
2221f9cab6cSJC Kuo #define   RPU_DATA0_D				BIT(27)
2231f9cab6cSJC Kuo 
2241f9cab6cSJC Kuo #define XUSB_AO_UTMIP_PAD_CFG(x)		(0x130 + (x) * 4)
2251f9cab6cSJC Kuo #define   FSLS_USE_XUSB_AO			BIT(3)
2261f9cab6cSJC Kuo #define   TRK_CTRL_USE_XUSB_AO			BIT(4)
2271f9cab6cSJC Kuo #define   RPD_CTRL_USE_XUSB_AO			BIT(5)
2281f9cab6cSJC Kuo #define   RPU_USE_XUSB_AO			BIT(6)
2291f9cab6cSJC Kuo #define   VREG_USE_XUSB_AO			BIT(7)
2301f9cab6cSJC Kuo #define   USBOP_VAL_PD				BIT(8)
2311f9cab6cSJC Kuo #define   USBON_VAL_PD				BIT(9)
2321f9cab6cSJC Kuo #define   E_DPD_OVRD_EN				BIT(10)
2331f9cab6cSJC Kuo #define   E_DPD_OVRD_VAL			BIT(11)
2341f9cab6cSJC Kuo 
2351f9cab6cSJC Kuo #define XUSB_AO_UHSIC_PAD_CFG(x)		(0x150 + (x) * 4)
2361f9cab6cSJC Kuo #define   STROBE_VAL_PD				BIT(0)
2371f9cab6cSJC Kuo #define   DATA0_VAL_PD				BIT(1)
2381f9cab6cSJC Kuo #define   USE_XUSB_AO				BIT(4)
2391f9cab6cSJC Kuo 
240bbf71168SJC Kuo #define TEGRA186_LANE(_name, _offset, _shift, _mask, _type)		\
241bbf71168SJC Kuo 	{								\
242bbf71168SJC Kuo 		.name = _name,						\
243bbf71168SJC Kuo 		.offset = _offset,					\
244bbf71168SJC Kuo 		.shift = _shift,					\
245bbf71168SJC Kuo 		.mask = _mask,						\
246bbf71168SJC Kuo 		.num_funcs = ARRAY_SIZE(tegra186_##_type##_functions),	\
247bbf71168SJC Kuo 		.funcs = tegra186_##_type##_functions,			\
248bbf71168SJC Kuo 	}
249bbf71168SJC Kuo 
250bbf71168SJC Kuo struct tegra_xusb_fuse_calibration {
251bbf71168SJC Kuo 	u32 *hs_curr_level;
252bbf71168SJC Kuo 	u32 hs_squelch;
253bbf71168SJC Kuo 	u32 hs_term_range_adj;
254bbf71168SJC Kuo 	u32 rpd_ctrl;
255bbf71168SJC Kuo };
256bbf71168SJC Kuo 
2571f9cab6cSJC Kuo struct tegra186_xusb_padctl_context {
2581f9cab6cSJC Kuo 	u32 vbus_id;
2591f9cab6cSJC Kuo 	u32 usb2_pad_mux;
2601f9cab6cSJC Kuo 	u32 usb2_port_cap;
2611f9cab6cSJC Kuo 	u32 ss_port_cap;
2621f9cab6cSJC Kuo };
2631f9cab6cSJC Kuo 
264bbf71168SJC Kuo struct tegra186_xusb_padctl {
265bbf71168SJC Kuo 	struct tegra_xusb_padctl base;
2661f9cab6cSJC Kuo 	void __iomem *ao_regs;
267bbf71168SJC Kuo 
268bbf71168SJC Kuo 	struct tegra_xusb_fuse_calibration calib;
269bbf71168SJC Kuo 
270bbf71168SJC Kuo 	/* UTMI bias and tracking */
271bbf71168SJC Kuo 	struct clk *usb2_trk_clk;
272bbf71168SJC Kuo 	unsigned int bias_pad_enable;
2731f9cab6cSJC Kuo 
2741f9cab6cSJC Kuo 	/* padctl context */
2751f9cab6cSJC Kuo 	struct tegra186_xusb_padctl_context context;
276bbf71168SJC Kuo };
277bbf71168SJC Kuo 
ao_writel(struct tegra186_xusb_padctl * priv,u32 value,unsigned int offset)2781f9cab6cSJC Kuo static inline void ao_writel(struct tegra186_xusb_padctl *priv, u32 value, unsigned int offset)
2791f9cab6cSJC Kuo {
2801f9cab6cSJC Kuo 	writel(value, priv->ao_regs + offset);
2811f9cab6cSJC Kuo }
2821f9cab6cSJC Kuo 
ao_readl(struct tegra186_xusb_padctl * priv,unsigned int offset)2831f9cab6cSJC Kuo static inline u32 ao_readl(struct tegra186_xusb_padctl *priv, unsigned int offset)
2841f9cab6cSJC Kuo {
2851f9cab6cSJC Kuo 	return readl(priv->ao_regs + offset);
2861f9cab6cSJC Kuo }
2871f9cab6cSJC Kuo 
288bbf71168SJC Kuo static inline struct tegra186_xusb_padctl *
to_tegra186_xusb_padctl(struct tegra_xusb_padctl * padctl)289bbf71168SJC Kuo to_tegra186_xusb_padctl(struct tegra_xusb_padctl *padctl)
290bbf71168SJC Kuo {
291bbf71168SJC Kuo 	return container_of(padctl, struct tegra186_xusb_padctl, base);
292bbf71168SJC Kuo }
293bbf71168SJC Kuo 
294bbf71168SJC Kuo /* USB 2.0 UTMI PHY support */
295bbf71168SJC Kuo static struct tegra_xusb_lane *
tegra186_usb2_lane_probe(struct tegra_xusb_pad * pad,struct device_node * np,unsigned int index)296bbf71168SJC Kuo tegra186_usb2_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
297bbf71168SJC Kuo 			 unsigned int index)
298bbf71168SJC Kuo {
299bbf71168SJC Kuo 	struct tegra_xusb_usb2_lane *usb2;
300bbf71168SJC Kuo 	int err;
301bbf71168SJC Kuo 
302bbf71168SJC Kuo 	usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
303bbf71168SJC Kuo 	if (!usb2)
304bbf71168SJC Kuo 		return ERR_PTR(-ENOMEM);
305bbf71168SJC Kuo 
306bbf71168SJC Kuo 	INIT_LIST_HEAD(&usb2->base.list);
307bbf71168SJC Kuo 	usb2->base.soc = &pad->soc->lanes[index];
308bbf71168SJC Kuo 	usb2->base.index = index;
309bbf71168SJC Kuo 	usb2->base.pad = pad;
310bbf71168SJC Kuo 	usb2->base.np = np;
311bbf71168SJC Kuo 
312bbf71168SJC Kuo 	err = tegra_xusb_lane_parse_dt(&usb2->base, np);
313bbf71168SJC Kuo 	if (err < 0) {
314bbf71168SJC Kuo 		kfree(usb2);
315bbf71168SJC Kuo 		return ERR_PTR(err);
316bbf71168SJC Kuo 	}
317bbf71168SJC Kuo 
318bbf71168SJC Kuo 	return &usb2->base;
319bbf71168SJC Kuo }
320bbf71168SJC Kuo 
tegra186_usb2_lane_remove(struct tegra_xusb_lane * lane)321bbf71168SJC Kuo static void tegra186_usb2_lane_remove(struct tegra_xusb_lane *lane)
322bbf71168SJC Kuo {
323bbf71168SJC Kuo 	struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane);
324bbf71168SJC Kuo 
325bbf71168SJC Kuo 	kfree(usb2);
326bbf71168SJC Kuo }
327bbf71168SJC Kuo 
tegra186_utmi_enable_phy_sleepwalk(struct tegra_xusb_lane * lane,enum usb_device_speed speed)3281f9cab6cSJC Kuo static int tegra186_utmi_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
3291f9cab6cSJC Kuo 					      enum usb_device_speed speed)
3301f9cab6cSJC Kuo {
3311f9cab6cSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
3321f9cab6cSJC Kuo 	struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
3331f9cab6cSJC Kuo 	unsigned int index = lane->index;
3341f9cab6cSJC Kuo 	u32 value;
3351f9cab6cSJC Kuo 
3361f9cab6cSJC Kuo 	mutex_lock(&padctl->lock);
3371f9cab6cSJC Kuo 
3381f9cab6cSJC Kuo 	/* ensure sleepwalk logic is disabled */
3391f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
3401f9cab6cSJC Kuo 	value &= ~MASTER_ENABLE;
3411f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
3421f9cab6cSJC Kuo 
3431f9cab6cSJC Kuo 	/* ensure sleepwalk logics are in low power mode */
3441f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
3451f9cab6cSJC Kuo 	value |= MASTER_CFG_SEL;
3461f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
3471f9cab6cSJC Kuo 
3481f9cab6cSJC Kuo 	/* set debounce time */
3491f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_USB_DEBOUNCE_DEL);
3501f9cab6cSJC Kuo 	value &= ~UTMIP_LINE_DEB_CNT(~0);
3511f9cab6cSJC Kuo 	value |= UTMIP_LINE_DEB_CNT(1);
3521f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_USB_DEBOUNCE_DEL);
3531f9cab6cSJC Kuo 
3541f9cab6cSJC Kuo 	/* ensure fake events of sleepwalk logic are desiabled */
3551f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
3561f9cab6cSJC Kuo 	value &= ~(FAKE_USBOP_VAL | FAKE_USBON_VAL |
3571f9cab6cSJC Kuo 		FAKE_USBOP_EN | FAKE_USBON_EN);
3581f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
3591f9cab6cSJC Kuo 
3601f9cab6cSJC Kuo 	/* ensure wake events of sleepwalk logic are not latched */
3611f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
3621f9cab6cSJC Kuo 	value &= ~LINE_WAKEUP_EN;
3631f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
3641f9cab6cSJC Kuo 
3651f9cab6cSJC Kuo 	/* disable wake event triggers of sleepwalk logic */
3661f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
3671f9cab6cSJC Kuo 	value &= ~WAKE_VAL(~0);
3681f9cab6cSJC Kuo 	value |= WAKE_VAL_NONE;
3691f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
3701f9cab6cSJC Kuo 
3711f9cab6cSJC Kuo 	/* power down the line state detectors of the pad */
3721f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index));
3731f9cab6cSJC Kuo 	value |= (USBOP_VAL_PD | USBON_VAL_PD);
3741f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index));
3751f9cab6cSJC Kuo 
3761f9cab6cSJC Kuo 	/* save state per speed */
3771f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_SAVED_STATE(index));
3781f9cab6cSJC Kuo 	value &= ~SPEED(~0);
3791f9cab6cSJC Kuo 
3801f9cab6cSJC Kuo 	switch (speed) {
3811f9cab6cSJC Kuo 	case USB_SPEED_HIGH:
3821f9cab6cSJC Kuo 		value |= UTMI_HS;
3831f9cab6cSJC Kuo 		break;
3841f9cab6cSJC Kuo 
3851f9cab6cSJC Kuo 	case USB_SPEED_FULL:
3861f9cab6cSJC Kuo 		value |= UTMI_FS;
3871f9cab6cSJC Kuo 		break;
3881f9cab6cSJC Kuo 
3891f9cab6cSJC Kuo 	case USB_SPEED_LOW:
3901f9cab6cSJC Kuo 		value |= UTMI_LS;
3911f9cab6cSJC Kuo 		break;
3921f9cab6cSJC Kuo 
3931f9cab6cSJC Kuo 	default:
3941f9cab6cSJC Kuo 		value |= UTMI_RST;
3951f9cab6cSJC Kuo 		break;
3961f9cab6cSJC Kuo 	}
3971f9cab6cSJC Kuo 
3981f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_SAVED_STATE(index));
3991f9cab6cSJC Kuo 
4001f9cab6cSJC Kuo 	/* enable the trigger of the sleepwalk logic */
4011f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
4021f9cab6cSJC Kuo 	value |= LINEVAL_WALK_EN;
4031f9cab6cSJC Kuo 	value &= ~WAKE_WALK_EN;
4041f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
4051f9cab6cSJC Kuo 
4061f9cab6cSJC Kuo 	/* reset the walk pointer and clear the alarm of the sleepwalk logic,
4071f9cab6cSJC Kuo 	 * as well as capture the configuration of the USB2.0 pad
4081f9cab6cSJC Kuo 	 */
4091f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_TRIGGERS(index));
4101f9cab6cSJC Kuo 	value |= (CLR_WALK_PTR | CLR_WAKE_ALARM | CAP_CFG);
4111f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_TRIGGERS(index));
4121f9cab6cSJC Kuo 
4131f9cab6cSJC Kuo 	/* setup the pull-ups and pull-downs of the signals during the four
4141f9cab6cSJC Kuo 	 * stages of sleepwalk.
4151f9cab6cSJC Kuo 	 * if device is connected, program sleepwalk logic to maintain a J and
4161f9cab6cSJC Kuo 	 * keep driving K upon seeing remote wake.
4171f9cab6cSJC Kuo 	 */
4181f9cab6cSJC Kuo 	value = USBOP_RPD_A | USBOP_RPD_B | USBOP_RPD_C | USBOP_RPD_D;
4191f9cab6cSJC Kuo 	value |= USBON_RPD_A | USBON_RPD_B | USBON_RPD_C | USBON_RPD_D;
4201f9cab6cSJC Kuo 
4211f9cab6cSJC Kuo 	switch (speed) {
4221f9cab6cSJC Kuo 	case USB_SPEED_HIGH:
4231f9cab6cSJC Kuo 	case USB_SPEED_FULL:
4241f9cab6cSJC Kuo 		/* J state: D+/D- = high/low, K state: D+/D- = low/high */
4251f9cab6cSJC Kuo 		value |= HIGHZ_A;
4261f9cab6cSJC Kuo 		value |= AP_A;
4271f9cab6cSJC Kuo 		value |= AN_B | AN_C | AN_D;
428*8b798761SHenry Lin 		if (padctl->soc->supports_lp_cfg_en)
429*8b798761SHenry Lin 			value |= MASTER_ENABLE_B_C_D;
4301f9cab6cSJC Kuo 		break;
4311f9cab6cSJC Kuo 
4321f9cab6cSJC Kuo 	case USB_SPEED_LOW:
4331f9cab6cSJC Kuo 		/* J state: D+/D- = low/high, K state: D+/D- = high/low */
4341f9cab6cSJC Kuo 		value |= HIGHZ_A;
4351f9cab6cSJC Kuo 		value |= AN_A;
4361f9cab6cSJC Kuo 		value |= AP_B | AP_C | AP_D;
437*8b798761SHenry Lin 		if (padctl->soc->supports_lp_cfg_en)
438*8b798761SHenry Lin 			value |= MASTER_ENABLE_B_C_D;
4391f9cab6cSJC Kuo 		break;
4401f9cab6cSJC Kuo 
4411f9cab6cSJC Kuo 	default:
4421f9cab6cSJC Kuo 		value |= HIGHZ_A | HIGHZ_B | HIGHZ_C | HIGHZ_D;
4431f9cab6cSJC Kuo 		break;
4441f9cab6cSJC Kuo 	}
4451f9cab6cSJC Kuo 
4461f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK(index));
4471f9cab6cSJC Kuo 
4481f9cab6cSJC Kuo 	/* power up the line state detectors of the pad */
4491f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index));
4501f9cab6cSJC Kuo 	value &= ~(USBOP_VAL_PD | USBON_VAL_PD);
4511f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index));
4521f9cab6cSJC Kuo 
4531f9cab6cSJC Kuo 	usleep_range(150, 200);
4541f9cab6cSJC Kuo 
4551f9cab6cSJC Kuo 	/* switch the electric control of the USB2.0 pad to XUSB_AO */
4561f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index));
4571f9cab6cSJC Kuo 	value |= FSLS_USE_XUSB_AO | TRK_CTRL_USE_XUSB_AO | RPD_CTRL_USE_XUSB_AO |
4581f9cab6cSJC Kuo 		 RPU_USE_XUSB_AO | VREG_USE_XUSB_AO;
4591f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index));
4601f9cab6cSJC Kuo 
4611f9cab6cSJC Kuo 	/* set the wake signaling trigger events */
4621f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
4631f9cab6cSJC Kuo 	value &= ~WAKE_VAL(~0);
4641f9cab6cSJC Kuo 	value |= WAKE_VAL_ANY;
4651f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
4661f9cab6cSJC Kuo 
4671f9cab6cSJC Kuo 	/* enable the wake detection */
4681f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
4691f9cab6cSJC Kuo 	value |= MASTER_ENABLE | LINE_WAKEUP_EN;
4701f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
4711f9cab6cSJC Kuo 
4721f9cab6cSJC Kuo 	mutex_unlock(&padctl->lock);
4731f9cab6cSJC Kuo 
4741f9cab6cSJC Kuo 	return 0;
4751f9cab6cSJC Kuo }
4761f9cab6cSJC Kuo 
tegra186_utmi_disable_phy_sleepwalk(struct tegra_xusb_lane * lane)4771f9cab6cSJC Kuo static int tegra186_utmi_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
4781f9cab6cSJC Kuo {
4791f9cab6cSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
4801f9cab6cSJC Kuo 	struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
4811f9cab6cSJC Kuo 	unsigned int index = lane->index;
4821f9cab6cSJC Kuo 	u32 value;
4831f9cab6cSJC Kuo 
4841f9cab6cSJC Kuo 	mutex_lock(&padctl->lock);
4851f9cab6cSJC Kuo 
4861f9cab6cSJC Kuo 	/* disable the wake detection */
4871f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
4881f9cab6cSJC Kuo 	value &= ~(MASTER_ENABLE | LINE_WAKEUP_EN);
4891f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
4901f9cab6cSJC Kuo 
4911f9cab6cSJC Kuo 	/* switch the electric control of the USB2.0 pad to XUSB vcore logic */
4921f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index));
4931f9cab6cSJC Kuo 	value &= ~(FSLS_USE_XUSB_AO | TRK_CTRL_USE_XUSB_AO | RPD_CTRL_USE_XUSB_AO |
4941f9cab6cSJC Kuo 		   RPU_USE_XUSB_AO | VREG_USE_XUSB_AO);
4951f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index));
4961f9cab6cSJC Kuo 
4971f9cab6cSJC Kuo 	/* disable wake event triggers of sleepwalk logic */
4981f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
4991f9cab6cSJC Kuo 	value &= ~WAKE_VAL(~0);
5001f9cab6cSJC Kuo 	value |= WAKE_VAL_NONE;
5011f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
5021f9cab6cSJC Kuo 
503*8b798761SHenry Lin 	if (padctl->soc->supports_lp_cfg_en) {
504*8b798761SHenry Lin 		/* disable the four stages of sleepwalk */
505*8b798761SHenry Lin 		value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK(index));
506*8b798761SHenry Lin 		value &= ~(MASTER_ENABLE_A | MASTER_ENABLE_B_C_D);
507*8b798761SHenry Lin 		ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK(index));
508*8b798761SHenry Lin 	}
509*8b798761SHenry Lin 
5101f9cab6cSJC Kuo 	/* power down the line state detectors of the port */
5111f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index));
5121f9cab6cSJC Kuo 	value |= USBOP_VAL_PD | USBON_VAL_PD;
5131f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index));
5141f9cab6cSJC Kuo 
5151f9cab6cSJC Kuo 	/* clear alarm of the sleepwalk logic */
5161f9cab6cSJC Kuo 	value = ao_readl(priv, XUSB_AO_UTMIP_TRIGGERS(index));
5171f9cab6cSJC Kuo 	value |= CLR_WAKE_ALARM;
5181f9cab6cSJC Kuo 	ao_writel(priv, value, XUSB_AO_UTMIP_TRIGGERS(index));
5191f9cab6cSJC Kuo 
5201f9cab6cSJC Kuo 	mutex_unlock(&padctl->lock);
5211f9cab6cSJC Kuo 
5221f9cab6cSJC Kuo 	return 0;
5231f9cab6cSJC Kuo }
5241f9cab6cSJC Kuo 
tegra186_utmi_enable_phy_wake(struct tegra_xusb_lane * lane)5251f9cab6cSJC Kuo static int tegra186_utmi_enable_phy_wake(struct tegra_xusb_lane *lane)
5261f9cab6cSJC Kuo {
5271f9cab6cSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
5281f9cab6cSJC Kuo 	unsigned int index = lane->index;
5291f9cab6cSJC Kuo 	u32 value;
5301f9cab6cSJC Kuo 
5311f9cab6cSJC Kuo 	mutex_lock(&padctl->lock);
5321f9cab6cSJC Kuo 
5331f9cab6cSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
5341f9cab6cSJC Kuo 	value &= ~ALL_WAKE_EVENTS;
5351f9cab6cSJC Kuo 	value |= USB2_PORT_WAKEUP_EVENT(index);
5361f9cab6cSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
5371f9cab6cSJC Kuo 
5381f9cab6cSJC Kuo 	usleep_range(10, 20);
5391f9cab6cSJC Kuo 
5401f9cab6cSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
5411f9cab6cSJC Kuo 	value &= ~ALL_WAKE_EVENTS;
5421f9cab6cSJC Kuo 	value |= USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
5431f9cab6cSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
5441f9cab6cSJC Kuo 
5451f9cab6cSJC Kuo 	mutex_unlock(&padctl->lock);
5461f9cab6cSJC Kuo 
5471f9cab6cSJC Kuo 	return 0;
5481f9cab6cSJC Kuo }
5491f9cab6cSJC Kuo 
tegra186_utmi_disable_phy_wake(struct tegra_xusb_lane * lane)5501f9cab6cSJC Kuo static int tegra186_utmi_disable_phy_wake(struct tegra_xusb_lane *lane)
5511f9cab6cSJC Kuo {
5521f9cab6cSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
5531f9cab6cSJC Kuo 	unsigned int index = lane->index;
5541f9cab6cSJC Kuo 	u32 value;
5551f9cab6cSJC Kuo 
5561f9cab6cSJC Kuo 	mutex_lock(&padctl->lock);
5571f9cab6cSJC Kuo 
5581f9cab6cSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
5591f9cab6cSJC Kuo 	value &= ~ALL_WAKE_EVENTS;
5601f9cab6cSJC Kuo 	value &= ~USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
5611f9cab6cSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
5621f9cab6cSJC Kuo 
5631f9cab6cSJC Kuo 	usleep_range(10, 20);
5641f9cab6cSJC Kuo 
5651f9cab6cSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
5661f9cab6cSJC Kuo 	value &= ~ALL_WAKE_EVENTS;
5671f9cab6cSJC Kuo 	value |= USB2_PORT_WAKEUP_EVENT(index);
5681f9cab6cSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
5691f9cab6cSJC Kuo 
5701f9cab6cSJC Kuo 	mutex_unlock(&padctl->lock);
5711f9cab6cSJC Kuo 
5721f9cab6cSJC Kuo 	return 0;
5731f9cab6cSJC Kuo }
5741f9cab6cSJC Kuo 
tegra186_utmi_phy_remote_wake_detected(struct tegra_xusb_lane * lane)5751f9cab6cSJC Kuo static bool tegra186_utmi_phy_remote_wake_detected(struct tegra_xusb_lane *lane)
5761f9cab6cSJC Kuo {
5771f9cab6cSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
5781f9cab6cSJC Kuo 	unsigned int index = lane->index;
5791f9cab6cSJC Kuo 	u32 value;
5801f9cab6cSJC Kuo 
5811f9cab6cSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
5821f9cab6cSJC Kuo 	if ((value & USB2_PORT_WAKE_INTERRUPT_ENABLE(index)) &&
5831f9cab6cSJC Kuo 	    (value & USB2_PORT_WAKEUP_EVENT(index)))
5841f9cab6cSJC Kuo 		return true;
5851f9cab6cSJC Kuo 
5861f9cab6cSJC Kuo 	return false;
5871f9cab6cSJC Kuo }
5881f9cab6cSJC Kuo 
589bbf71168SJC Kuo static const struct tegra_xusb_lane_ops tegra186_usb2_lane_ops = {
590bbf71168SJC Kuo 	.probe = tegra186_usb2_lane_probe,
591bbf71168SJC Kuo 	.remove = tegra186_usb2_lane_remove,
5921f9cab6cSJC Kuo 	.enable_phy_sleepwalk = tegra186_utmi_enable_phy_sleepwalk,
5931f9cab6cSJC Kuo 	.disable_phy_sleepwalk = tegra186_utmi_disable_phy_sleepwalk,
5941f9cab6cSJC Kuo 	.enable_phy_wake = tegra186_utmi_enable_phy_wake,
5951f9cab6cSJC Kuo 	.disable_phy_wake = tegra186_utmi_disable_phy_wake,
5961f9cab6cSJC Kuo 	.remote_wake_detected = tegra186_utmi_phy_remote_wake_detected,
597bbf71168SJC Kuo };
598bbf71168SJC Kuo 
tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl * padctl)599bbf71168SJC Kuo static void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl)
600bbf71168SJC Kuo {
601bbf71168SJC Kuo 	struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
602bbf71168SJC Kuo 	struct device *dev = padctl->dev;
603bbf71168SJC Kuo 	u32 value;
604bbf71168SJC Kuo 	int err;
605bbf71168SJC Kuo 
606bbf71168SJC Kuo 	mutex_lock(&padctl->lock);
607bbf71168SJC Kuo 
608bbf71168SJC Kuo 	if (priv->bias_pad_enable++ > 0) {
609bbf71168SJC Kuo 		mutex_unlock(&padctl->lock);
610bbf71168SJC Kuo 		return;
611bbf71168SJC Kuo 	}
612bbf71168SJC Kuo 
613bbf71168SJC Kuo 	err = clk_prepare_enable(priv->usb2_trk_clk);
614bbf71168SJC Kuo 	if (err < 0)
615bbf71168SJC Kuo 		dev_warn(dev, "failed to enable USB2 trk clock: %d\n", err);
616bbf71168SJC Kuo 
617bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
618bbf71168SJC Kuo 	value &= ~USB2_TRK_START_TIMER(~0);
619bbf71168SJC Kuo 	value |= USB2_TRK_START_TIMER(0x1e);
620bbf71168SJC Kuo 	value &= ~USB2_TRK_DONE_RESET_TIMER(~0);
621bbf71168SJC Kuo 	value |= USB2_TRK_DONE_RESET_TIMER(0xa);
622bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
623bbf71168SJC Kuo 
624bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
625bbf71168SJC Kuo 	value &= ~BIAS_PAD_PD;
626bbf71168SJC Kuo 	value &= ~HS_SQUELCH_LEVEL(~0);
627bbf71168SJC Kuo 	value |= HS_SQUELCH_LEVEL(priv->calib.hs_squelch);
628bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
629bbf71168SJC Kuo 
630bbf71168SJC Kuo 	udelay(1);
631bbf71168SJC Kuo 
632bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
633bbf71168SJC Kuo 	value &= ~USB2_PD_TRK;
634bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
635bbf71168SJC Kuo 
636d8163a32SSing-Han Chen 	if (padctl->soc->poll_trk_completed) {
637d8163a32SSing-Han Chen 		err = padctl_readl_poll(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1,
638d8163a32SSing-Han Chen 					USB2_TRK_COMPLETED, USB2_TRK_COMPLETED, 100);
639d8163a32SSing-Han Chen 		if (err) {
640d8163a32SSing-Han Chen 			/* The failure with polling on trk complete will not
641d8163a32SSing-Han Chen 			 * cause the failure of powering on the bias pad.
642d8163a32SSing-Han Chen 			 */
643d8163a32SSing-Han Chen 			dev_warn(dev, "failed to poll USB2 trk completed: %d\n", err);
644d8163a32SSing-Han Chen 		}
64571d9e899SWayne Chang 
646d8163a32SSing-Han Chen 		value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
647d8163a32SSing-Han Chen 		value |= USB2_TRK_COMPLETED;
648d8163a32SSing-Han Chen 		padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
649d8163a32SSing-Han Chen 	} else {
650d8163a32SSing-Han Chen 		udelay(100);
651d8163a32SSing-Han Chen 	}
652d8163a32SSing-Han Chen 
653d8163a32SSing-Han Chen 	if (padctl->soc->trk_hw_mode) {
654d8163a32SSing-Han Chen 		value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL2);
655d8163a32SSing-Han Chen 		value |= USB2_TRK_HW_MODE;
656d8163a32SSing-Han Chen 		value &= ~CYA_TRK_CODE_UPDATE_ON_IDLE;
657d8163a32SSing-Han Chen 		padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL2);
658d8163a32SSing-Han Chen 	} else {
65971d9e899SWayne Chang 		clk_disable_unprepare(priv->usb2_trk_clk);
660d8163a32SSing-Han Chen 	}
66171d9e899SWayne Chang 
662bbf71168SJC Kuo 	mutex_unlock(&padctl->lock);
663bbf71168SJC Kuo }
664bbf71168SJC Kuo 
tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl * padctl)665bbf71168SJC Kuo static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl)
666bbf71168SJC Kuo {
667bbf71168SJC Kuo 	struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
668bbf71168SJC Kuo 	u32 value;
669bbf71168SJC Kuo 
670bbf71168SJC Kuo 	mutex_lock(&padctl->lock);
671bbf71168SJC Kuo 
672bbf71168SJC Kuo 	if (WARN_ON(priv->bias_pad_enable == 0)) {
673bbf71168SJC Kuo 		mutex_unlock(&padctl->lock);
674bbf71168SJC Kuo 		return;
675bbf71168SJC Kuo 	}
676bbf71168SJC Kuo 
677bbf71168SJC Kuo 	if (--priv->bias_pad_enable > 0) {
678bbf71168SJC Kuo 		mutex_unlock(&padctl->lock);
679bbf71168SJC Kuo 		return;
680bbf71168SJC Kuo 	}
681bbf71168SJC Kuo 
682bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
683bbf71168SJC Kuo 	value |= USB2_PD_TRK;
684bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
685bbf71168SJC Kuo 
686d8163a32SSing-Han Chen 	if (padctl->soc->trk_hw_mode) {
687d8163a32SSing-Han Chen 		value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL2);
688d8163a32SSing-Han Chen 		value &= ~USB2_TRK_HW_MODE;
689d8163a32SSing-Han Chen 		padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL2);
690d8163a32SSing-Han Chen 		clk_disable_unprepare(priv->usb2_trk_clk);
691d8163a32SSing-Han Chen 	}
692d8163a32SSing-Han Chen 
693bbf71168SJC Kuo 	mutex_unlock(&padctl->lock);
694bbf71168SJC Kuo }
695bbf71168SJC Kuo 
tegra186_utmi_pad_power_on(struct phy * phy)69677bfa0fcSJim Lin static void tegra186_utmi_pad_power_on(struct phy *phy)
697bbf71168SJC Kuo {
698bbf71168SJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
699bbf71168SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
700bbf71168SJC Kuo 	struct tegra_xusb_usb2_port *port;
701bbf71168SJC Kuo 	struct device *dev = padctl->dev;
702bbf71168SJC Kuo 	unsigned int index = lane->index;
703bbf71168SJC Kuo 	u32 value;
704bbf71168SJC Kuo 
705bbf71168SJC Kuo 	if (!phy)
706bbf71168SJC Kuo 		return;
707bbf71168SJC Kuo 
708bbf71168SJC Kuo 	port = tegra_xusb_find_usb2_port(padctl, index);
709bbf71168SJC Kuo 	if (!port) {
710bbf71168SJC Kuo 		dev_err(dev, "no port found for USB2 lane %u\n", index);
711bbf71168SJC Kuo 		return;
712bbf71168SJC Kuo 	}
713bbf71168SJC Kuo 
71477bfa0fcSJim Lin 	dev_dbg(dev, "power on UTMI pad %u\n", index);
71577bfa0fcSJim Lin 
716bbf71168SJC Kuo 	tegra186_utmi_bias_pad_power_on(padctl);
717bbf71168SJC Kuo 
718bbf71168SJC Kuo 	udelay(2);
719bbf71168SJC Kuo 
720bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
721bbf71168SJC Kuo 	value &= ~USB2_OTG_PD;
722bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
723bbf71168SJC Kuo 
724bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
725bbf71168SJC Kuo 	value &= ~USB2_OTG_PD_DR;
726bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
727bbf71168SJC Kuo }
728bbf71168SJC Kuo 
tegra186_utmi_pad_power_down(struct phy * phy)72977bfa0fcSJim Lin static void tegra186_utmi_pad_power_down(struct phy *phy)
730bbf71168SJC Kuo {
731bbf71168SJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
732bbf71168SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
733bbf71168SJC Kuo 	unsigned int index = lane->index;
734bbf71168SJC Kuo 	u32 value;
735bbf71168SJC Kuo 
736bbf71168SJC Kuo 	if (!phy)
737bbf71168SJC Kuo 		return;
738bbf71168SJC Kuo 
73977bfa0fcSJim Lin 	dev_dbg(padctl->dev, "power down UTMI pad %u\n", index);
74077bfa0fcSJim Lin 
741bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
742bbf71168SJC Kuo 	value |= USB2_OTG_PD;
743bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
744bbf71168SJC Kuo 
745bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
746bbf71168SJC Kuo 	value |= USB2_OTG_PD_DR;
747bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
748bbf71168SJC Kuo 
749bbf71168SJC Kuo 	udelay(2);
750bbf71168SJC Kuo 
751bbf71168SJC Kuo 	tegra186_utmi_bias_pad_power_off(padctl);
752bbf71168SJC Kuo }
753bbf71168SJC Kuo 
tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl * padctl,bool status)75449d46e3cSNagarjuna Kristam static int tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
75549d46e3cSNagarjuna Kristam 					       bool status)
75649d46e3cSNagarjuna Kristam {
75749d46e3cSNagarjuna Kristam 	u32 value;
75849d46e3cSNagarjuna Kristam 
75949d46e3cSNagarjuna Kristam 	dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
76049d46e3cSNagarjuna Kristam 
76149d46e3cSNagarjuna Kristam 	value = padctl_readl(padctl, USB2_VBUS_ID);
76249d46e3cSNagarjuna Kristam 
76349d46e3cSNagarjuna Kristam 	if (status) {
76449d46e3cSNagarjuna Kristam 		value |= VBUS_OVERRIDE;
76549d46e3cSNagarjuna Kristam 		value &= ~ID_OVERRIDE(~0);
76649d46e3cSNagarjuna Kristam 		value |= ID_OVERRIDE_FLOATING;
76749d46e3cSNagarjuna Kristam 	} else {
76849d46e3cSNagarjuna Kristam 		value &= ~VBUS_OVERRIDE;
76949d46e3cSNagarjuna Kristam 	}
77049d46e3cSNagarjuna Kristam 
77149d46e3cSNagarjuna Kristam 	padctl_writel(padctl, value, USB2_VBUS_ID);
77249d46e3cSNagarjuna Kristam 
77349d46e3cSNagarjuna Kristam 	return 0;
77449d46e3cSNagarjuna Kristam }
77549d46e3cSNagarjuna Kristam 
tegra186_xusb_padctl_id_override(struct tegra_xusb_padctl * padctl,bool status)77649d46e3cSNagarjuna Kristam static int tegra186_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl,
77749d46e3cSNagarjuna Kristam 					    bool status)
77849d46e3cSNagarjuna Kristam {
77949d46e3cSNagarjuna Kristam 	u32 value;
78049d46e3cSNagarjuna Kristam 
78149d46e3cSNagarjuna Kristam 	dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear");
78249d46e3cSNagarjuna Kristam 
78349d46e3cSNagarjuna Kristam 	value = padctl_readl(padctl, USB2_VBUS_ID);
78449d46e3cSNagarjuna Kristam 
78549d46e3cSNagarjuna Kristam 	if (status) {
78649d46e3cSNagarjuna Kristam 		if (value & VBUS_OVERRIDE) {
78749d46e3cSNagarjuna Kristam 			value &= ~VBUS_OVERRIDE;
78849d46e3cSNagarjuna Kristam 			padctl_writel(padctl, value, USB2_VBUS_ID);
78949d46e3cSNagarjuna Kristam 			usleep_range(1000, 2000);
79049d46e3cSNagarjuna Kristam 
79149d46e3cSNagarjuna Kristam 			value = padctl_readl(padctl, USB2_VBUS_ID);
79249d46e3cSNagarjuna Kristam 		}
79349d46e3cSNagarjuna Kristam 
79449d46e3cSNagarjuna Kristam 		value &= ~ID_OVERRIDE(~0);
79549d46e3cSNagarjuna Kristam 		value |= ID_OVERRIDE_GROUNDED;
79649d46e3cSNagarjuna Kristam 	} else {
79749d46e3cSNagarjuna Kristam 		value &= ~ID_OVERRIDE(~0);
79849d46e3cSNagarjuna Kristam 		value |= ID_OVERRIDE_FLOATING;
79949d46e3cSNagarjuna Kristam 	}
80049d46e3cSNagarjuna Kristam 
80149d46e3cSNagarjuna Kristam 	padctl_writel(padctl, value, USB2_VBUS_ID);
80249d46e3cSNagarjuna Kristam 
80349d46e3cSNagarjuna Kristam 	return 0;
80449d46e3cSNagarjuna Kristam }
80549d46e3cSNagarjuna Kristam 
tegra186_utmi_phy_set_mode(struct phy * phy,enum phy_mode mode,int submode)80649d46e3cSNagarjuna Kristam static int tegra186_utmi_phy_set_mode(struct phy *phy, enum phy_mode mode,
80749d46e3cSNagarjuna Kristam 				      int submode)
80849d46e3cSNagarjuna Kristam {
80949d46e3cSNagarjuna Kristam 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
81049d46e3cSNagarjuna Kristam 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
81149d46e3cSNagarjuna Kristam 	struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl,
81249d46e3cSNagarjuna Kristam 								lane->index);
81349d46e3cSNagarjuna Kristam 	int err = 0;
81449d46e3cSNagarjuna Kristam 
81549d46e3cSNagarjuna Kristam 	mutex_lock(&padctl->lock);
81649d46e3cSNagarjuna Kristam 
81749d46e3cSNagarjuna Kristam 	dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode);
81849d46e3cSNagarjuna Kristam 
81949d46e3cSNagarjuna Kristam 	if (mode == PHY_MODE_USB_OTG) {
82049d46e3cSNagarjuna Kristam 		if (submode == USB_ROLE_HOST) {
82149d46e3cSNagarjuna Kristam 			tegra186_xusb_padctl_id_override(padctl, true);
82249d46e3cSNagarjuna Kristam 
82349d46e3cSNagarjuna Kristam 			err = regulator_enable(port->supply);
82449d46e3cSNagarjuna Kristam 		} else if (submode == USB_ROLE_DEVICE) {
82549d46e3cSNagarjuna Kristam 			tegra186_xusb_padctl_vbus_override(padctl, true);
82649d46e3cSNagarjuna Kristam 		} else if (submode == USB_ROLE_NONE) {
82749d46e3cSNagarjuna Kristam 			/*
82849d46e3cSNagarjuna Kristam 			 * When port is peripheral only or role transitions to
82949d46e3cSNagarjuna Kristam 			 * USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not
83049d46e3cSNagarjuna Kristam 			 * enabled.
83149d46e3cSNagarjuna Kristam 			 */
83249d46e3cSNagarjuna Kristam 			if (regulator_is_enabled(port->supply))
83349d46e3cSNagarjuna Kristam 				regulator_disable(port->supply);
83449d46e3cSNagarjuna Kristam 
83549d46e3cSNagarjuna Kristam 			tegra186_xusb_padctl_id_override(padctl, false);
83649d46e3cSNagarjuna Kristam 			tegra186_xusb_padctl_vbus_override(padctl, false);
83749d46e3cSNagarjuna Kristam 		}
83849d46e3cSNagarjuna Kristam 	}
83949d46e3cSNagarjuna Kristam 
84049d46e3cSNagarjuna Kristam 	mutex_unlock(&padctl->lock);
84149d46e3cSNagarjuna Kristam 
84249d46e3cSNagarjuna Kristam 	return err;
84349d46e3cSNagarjuna Kristam }
84449d46e3cSNagarjuna Kristam 
tegra186_utmi_phy_power_on(struct phy * phy)845bbf71168SJC Kuo static int tegra186_utmi_phy_power_on(struct phy *phy)
846bbf71168SJC Kuo {
847bbf71168SJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
848bbf71168SJC Kuo 	struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane);
849bbf71168SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
850bbf71168SJC Kuo 	struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
851bbf71168SJC Kuo 	struct tegra_xusb_usb2_port *port;
852bbf71168SJC Kuo 	unsigned int index = lane->index;
853bbf71168SJC Kuo 	struct device *dev = padctl->dev;
854bbf71168SJC Kuo 	u32 value;
855bbf71168SJC Kuo 
856bbf71168SJC Kuo 	port = tegra_xusb_find_usb2_port(padctl, index);
857bbf71168SJC Kuo 	if (!port) {
858bbf71168SJC Kuo 		dev_err(dev, "no port found for USB2 lane %u\n", index);
859bbf71168SJC Kuo 		return -ENODEV;
860bbf71168SJC Kuo 	}
861bbf71168SJC Kuo 
862bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
863bbf71168SJC Kuo 	value &= ~(USB2_PORT_MASK << USB2_PORT_SHIFT(index));
864bbf71168SJC Kuo 	value |= (PORT_XUSB << USB2_PORT_SHIFT(index));
865bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX);
866bbf71168SJC Kuo 
867bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
868bbf71168SJC Kuo 	value &= ~(PORT_CAP_MASK << PORTX_CAP_SHIFT(index));
869bbf71168SJC Kuo 
870bbf71168SJC Kuo 	if (port->mode == USB_DR_MODE_UNKNOWN)
871bbf71168SJC Kuo 		value |= (PORT_CAP_DISABLED << PORTX_CAP_SHIFT(index));
872bbf71168SJC Kuo 	else if (port->mode == USB_DR_MODE_PERIPHERAL)
873bbf71168SJC Kuo 		value |= (PORT_CAP_DEVICE << PORTX_CAP_SHIFT(index));
874bbf71168SJC Kuo 	else if (port->mode == USB_DR_MODE_HOST)
875bbf71168SJC Kuo 		value |= (PORT_CAP_HOST << PORTX_CAP_SHIFT(index));
876bbf71168SJC Kuo 	else if (port->mode == USB_DR_MODE_OTG)
877bbf71168SJC Kuo 		value |= (PORT_CAP_OTG << PORTX_CAP_SHIFT(index));
878bbf71168SJC Kuo 
879bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP);
880bbf71168SJC Kuo 
881bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
882bbf71168SJC Kuo 	value &= ~USB2_OTG_PD_ZI;
883bbf71168SJC Kuo 	value |= TERM_SEL;
884bbf71168SJC Kuo 	value &= ~HS_CURR_LEVEL(~0);
885bbf71168SJC Kuo 
886bbf71168SJC Kuo 	if (usb2->hs_curr_level_offset) {
887bbf71168SJC Kuo 		int hs_current_level;
888bbf71168SJC Kuo 
889bbf71168SJC Kuo 		hs_current_level = (int)priv->calib.hs_curr_level[index] +
890bbf71168SJC Kuo 						usb2->hs_curr_level_offset;
891bbf71168SJC Kuo 
892bbf71168SJC Kuo 		if (hs_current_level < 0)
893bbf71168SJC Kuo 			hs_current_level = 0;
894bbf71168SJC Kuo 		if (hs_current_level > 0x3f)
895bbf71168SJC Kuo 			hs_current_level = 0x3f;
896bbf71168SJC Kuo 
897bbf71168SJC Kuo 		value |= HS_CURR_LEVEL(hs_current_level);
898bbf71168SJC Kuo 	} else {
899bbf71168SJC Kuo 		value |= HS_CURR_LEVEL(priv->calib.hs_curr_level[index]);
900bbf71168SJC Kuo 	}
901bbf71168SJC Kuo 
902bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
903bbf71168SJC Kuo 
904bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
905bbf71168SJC Kuo 	value &= ~TERM_RANGE_ADJ(~0);
906bbf71168SJC Kuo 	value |= TERM_RANGE_ADJ(priv->calib.hs_term_range_adj);
907bbf71168SJC Kuo 	value &= ~RPD_CTRL(~0);
908bbf71168SJC Kuo 	value |= RPD_CTRL(priv->calib.rpd_ctrl);
909bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
910bbf71168SJC Kuo 
91177bfa0fcSJim Lin 	tegra186_utmi_pad_power_on(phy);
91277bfa0fcSJim Lin 
913bbf71168SJC Kuo 	return 0;
914bbf71168SJC Kuo }
915bbf71168SJC Kuo 
tegra186_utmi_phy_power_off(struct phy * phy)916bbf71168SJC Kuo static int tegra186_utmi_phy_power_off(struct phy *phy)
917bbf71168SJC Kuo {
91877bfa0fcSJim Lin 	tegra186_utmi_pad_power_down(phy);
919bbf71168SJC Kuo 
920bbf71168SJC Kuo 	return 0;
921bbf71168SJC Kuo }
922bbf71168SJC Kuo 
tegra186_utmi_phy_init(struct phy * phy)923bbf71168SJC Kuo static int tegra186_utmi_phy_init(struct phy *phy)
924bbf71168SJC Kuo {
925bbf71168SJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
926bbf71168SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
927bbf71168SJC Kuo 	struct tegra_xusb_usb2_port *port;
928bbf71168SJC Kuo 	unsigned int index = lane->index;
929bbf71168SJC Kuo 	struct device *dev = padctl->dev;
930bbf71168SJC Kuo 	int err;
931bbf71168SJC Kuo 
932bbf71168SJC Kuo 	port = tegra_xusb_find_usb2_port(padctl, index);
933bbf71168SJC Kuo 	if (!port) {
934bbf71168SJC Kuo 		dev_err(dev, "no port found for USB2 lane %u\n", index);
935bbf71168SJC Kuo 		return -ENODEV;
936bbf71168SJC Kuo 	}
937bbf71168SJC Kuo 
938bbf71168SJC Kuo 	if (port->supply && port->mode == USB_DR_MODE_HOST) {
939bbf71168SJC Kuo 		err = regulator_enable(port->supply);
940bbf71168SJC Kuo 		if (err) {
941bbf71168SJC Kuo 			dev_err(dev, "failed to enable port %u VBUS: %d\n",
942bbf71168SJC Kuo 				index, err);
943bbf71168SJC Kuo 			return err;
944bbf71168SJC Kuo 		}
945bbf71168SJC Kuo 	}
946bbf71168SJC Kuo 
947bbf71168SJC Kuo 	return 0;
948bbf71168SJC Kuo }
949bbf71168SJC Kuo 
tegra186_utmi_phy_exit(struct phy * phy)950bbf71168SJC Kuo static int tegra186_utmi_phy_exit(struct phy *phy)
951bbf71168SJC Kuo {
952bbf71168SJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
953bbf71168SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
954bbf71168SJC Kuo 	struct tegra_xusb_usb2_port *port;
955bbf71168SJC Kuo 	unsigned int index = lane->index;
956bbf71168SJC Kuo 	struct device *dev = padctl->dev;
957bbf71168SJC Kuo 	int err;
958bbf71168SJC Kuo 
959bbf71168SJC Kuo 	port = tegra_xusb_find_usb2_port(padctl, index);
960bbf71168SJC Kuo 	if (!port) {
961bbf71168SJC Kuo 		dev_err(dev, "no port found for USB2 lane %u\n", index);
962bbf71168SJC Kuo 		return -ENODEV;
963bbf71168SJC Kuo 	}
964bbf71168SJC Kuo 
965bbf71168SJC Kuo 	if (port->supply && port->mode == USB_DR_MODE_HOST) {
966bbf71168SJC Kuo 		err = regulator_disable(port->supply);
967bbf71168SJC Kuo 		if (err) {
968bbf71168SJC Kuo 			dev_err(dev, "failed to disable port %u VBUS: %d\n",
969bbf71168SJC Kuo 				index, err);
970bbf71168SJC Kuo 			return err;
971bbf71168SJC Kuo 		}
972bbf71168SJC Kuo 	}
973bbf71168SJC Kuo 
974bbf71168SJC Kuo 	return 0;
975bbf71168SJC Kuo }
976bbf71168SJC Kuo 
977bbf71168SJC Kuo static const struct phy_ops utmi_phy_ops = {
978bbf71168SJC Kuo 	.init = tegra186_utmi_phy_init,
979bbf71168SJC Kuo 	.exit = tegra186_utmi_phy_exit,
980bbf71168SJC Kuo 	.power_on = tegra186_utmi_phy_power_on,
981bbf71168SJC Kuo 	.power_off = tegra186_utmi_phy_power_off,
98249d46e3cSNagarjuna Kristam 	.set_mode = tegra186_utmi_phy_set_mode,
983bbf71168SJC Kuo 	.owner = THIS_MODULE,
984bbf71168SJC Kuo };
985bbf71168SJC Kuo 
986bbf71168SJC Kuo static struct tegra_xusb_pad *
tegra186_usb2_pad_probe(struct tegra_xusb_padctl * padctl,const struct tegra_xusb_pad_soc * soc,struct device_node * np)987bbf71168SJC Kuo tegra186_usb2_pad_probe(struct tegra_xusb_padctl *padctl,
988bbf71168SJC Kuo 			const struct tegra_xusb_pad_soc *soc,
989bbf71168SJC Kuo 			struct device_node *np)
990bbf71168SJC Kuo {
991bbf71168SJC Kuo 	struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
992bbf71168SJC Kuo 	struct tegra_xusb_usb2_pad *usb2;
993bbf71168SJC Kuo 	struct tegra_xusb_pad *pad;
994bbf71168SJC Kuo 	int err;
995bbf71168SJC Kuo 
996bbf71168SJC Kuo 	usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
997bbf71168SJC Kuo 	if (!usb2)
998bbf71168SJC Kuo 		return ERR_PTR(-ENOMEM);
999bbf71168SJC Kuo 
1000bbf71168SJC Kuo 	pad = &usb2->base;
1001bbf71168SJC Kuo 	pad->ops = &tegra186_usb2_lane_ops;
1002bbf71168SJC Kuo 	pad->soc = soc;
1003bbf71168SJC Kuo 
1004bbf71168SJC Kuo 	err = tegra_xusb_pad_init(pad, padctl, np);
1005bbf71168SJC Kuo 	if (err < 0) {
1006bbf71168SJC Kuo 		kfree(usb2);
1007bbf71168SJC Kuo 		goto out;
1008bbf71168SJC Kuo 	}
1009bbf71168SJC Kuo 
1010bbf71168SJC Kuo 	priv->usb2_trk_clk = devm_clk_get(&pad->dev, "trk");
1011bbf71168SJC Kuo 	if (IS_ERR(priv->usb2_trk_clk)) {
1012bbf71168SJC Kuo 		err = PTR_ERR(priv->usb2_trk_clk);
1013bbf71168SJC Kuo 		dev_dbg(&pad->dev, "failed to get usb2 trk clock: %d\n", err);
1014bbf71168SJC Kuo 		goto unregister;
1015bbf71168SJC Kuo 	}
1016bbf71168SJC Kuo 
1017bbf71168SJC Kuo 	err = tegra_xusb_pad_register(pad, &utmi_phy_ops);
1018bbf71168SJC Kuo 	if (err < 0)
1019bbf71168SJC Kuo 		goto unregister;
1020bbf71168SJC Kuo 
1021bbf71168SJC Kuo 	dev_set_drvdata(&pad->dev, pad);
1022bbf71168SJC Kuo 
1023bbf71168SJC Kuo 	return pad;
1024bbf71168SJC Kuo 
1025bbf71168SJC Kuo unregister:
1026bbf71168SJC Kuo 	device_unregister(&pad->dev);
1027bbf71168SJC Kuo out:
1028bbf71168SJC Kuo 	return ERR_PTR(err);
1029bbf71168SJC Kuo }
1030bbf71168SJC Kuo 
tegra186_usb2_pad_remove(struct tegra_xusb_pad * pad)1031bbf71168SJC Kuo static void tegra186_usb2_pad_remove(struct tegra_xusb_pad *pad)
1032bbf71168SJC Kuo {
1033bbf71168SJC Kuo 	struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad);
1034bbf71168SJC Kuo 
1035bbf71168SJC Kuo 	kfree(usb2);
1036bbf71168SJC Kuo }
1037bbf71168SJC Kuo 
1038bbf71168SJC Kuo static const struct tegra_xusb_pad_ops tegra186_usb2_pad_ops = {
1039bbf71168SJC Kuo 	.probe = tegra186_usb2_pad_probe,
1040bbf71168SJC Kuo 	.remove = tegra186_usb2_pad_remove,
1041bbf71168SJC Kuo };
1042bbf71168SJC Kuo 
1043bbf71168SJC Kuo static const char * const tegra186_usb2_functions[] = {
1044bbf71168SJC Kuo 	"xusb",
1045bbf71168SJC Kuo };
1046bbf71168SJC Kuo 
tegra186_usb2_port_enable(struct tegra_xusb_port * port)1047bbf71168SJC Kuo static int tegra186_usb2_port_enable(struct tegra_xusb_port *port)
1048bbf71168SJC Kuo {
1049bbf71168SJC Kuo 	return 0;
1050bbf71168SJC Kuo }
1051bbf71168SJC Kuo 
tegra186_usb2_port_disable(struct tegra_xusb_port * port)1052bbf71168SJC Kuo static void tegra186_usb2_port_disable(struct tegra_xusb_port *port)
1053bbf71168SJC Kuo {
1054bbf71168SJC Kuo }
1055bbf71168SJC Kuo 
1056bbf71168SJC Kuo static struct tegra_xusb_lane *
tegra186_usb2_port_map(struct tegra_xusb_port * port)1057bbf71168SJC Kuo tegra186_usb2_port_map(struct tegra_xusb_port *port)
1058bbf71168SJC Kuo {
1059bbf71168SJC Kuo 	return tegra_xusb_find_lane(port->padctl, "usb2", port->index);
1060bbf71168SJC Kuo }
1061bbf71168SJC Kuo 
1062bbf71168SJC Kuo static const struct tegra_xusb_port_ops tegra186_usb2_port_ops = {
1063e78fdbadSThierry Reding 	.release = tegra_xusb_usb2_port_release,
10642f8da84dSThierry Reding 	.remove = tegra_xusb_usb2_port_remove,
1065bbf71168SJC Kuo 	.enable = tegra186_usb2_port_enable,
1066bbf71168SJC Kuo 	.disable = tegra186_usb2_port_disable,
1067bbf71168SJC Kuo 	.map = tegra186_usb2_port_map,
1068bbf71168SJC Kuo };
1069bbf71168SJC Kuo 
1070bbf71168SJC Kuo /* SuperSpeed PHY support */
1071bbf71168SJC Kuo static struct tegra_xusb_lane *
tegra186_usb3_lane_probe(struct tegra_xusb_pad * pad,struct device_node * np,unsigned int index)1072bbf71168SJC Kuo tegra186_usb3_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
1073bbf71168SJC Kuo 			 unsigned int index)
1074bbf71168SJC Kuo {
1075bbf71168SJC Kuo 	struct tegra_xusb_usb3_lane *usb3;
1076bbf71168SJC Kuo 	int err;
1077bbf71168SJC Kuo 
1078bbf71168SJC Kuo 	usb3 = kzalloc(sizeof(*usb3), GFP_KERNEL);
1079bbf71168SJC Kuo 	if (!usb3)
1080bbf71168SJC Kuo 		return ERR_PTR(-ENOMEM);
1081bbf71168SJC Kuo 
1082bbf71168SJC Kuo 	INIT_LIST_HEAD(&usb3->base.list);
1083bbf71168SJC Kuo 	usb3->base.soc = &pad->soc->lanes[index];
1084bbf71168SJC Kuo 	usb3->base.index = index;
1085bbf71168SJC Kuo 	usb3->base.pad = pad;
1086bbf71168SJC Kuo 	usb3->base.np = np;
1087bbf71168SJC Kuo 
1088bbf71168SJC Kuo 	err = tegra_xusb_lane_parse_dt(&usb3->base, np);
1089bbf71168SJC Kuo 	if (err < 0) {
1090bbf71168SJC Kuo 		kfree(usb3);
1091bbf71168SJC Kuo 		return ERR_PTR(err);
1092bbf71168SJC Kuo 	}
1093bbf71168SJC Kuo 
1094bbf71168SJC Kuo 	return &usb3->base;
1095bbf71168SJC Kuo }
1096bbf71168SJC Kuo 
tegra186_usb3_lane_remove(struct tegra_xusb_lane * lane)1097bbf71168SJC Kuo static void tegra186_usb3_lane_remove(struct tegra_xusb_lane *lane)
1098bbf71168SJC Kuo {
1099bbf71168SJC Kuo 	struct tegra_xusb_usb3_lane *usb3 = to_usb3_lane(lane);
1100bbf71168SJC Kuo 
1101bbf71168SJC Kuo 	kfree(usb3);
1102bbf71168SJC Kuo }
1103bbf71168SJC Kuo 
tegra186_usb3_enable_phy_sleepwalk(struct tegra_xusb_lane * lane,enum usb_device_speed speed)11041f9cab6cSJC Kuo static int tegra186_usb3_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
11051f9cab6cSJC Kuo 					      enum usb_device_speed speed)
11061f9cab6cSJC Kuo {
11071f9cab6cSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
11081f9cab6cSJC Kuo 	unsigned int index = lane->index;
11091f9cab6cSJC Kuo 	u32 value;
11101f9cab6cSJC Kuo 
11111f9cab6cSJC Kuo 	mutex_lock(&padctl->lock);
11121f9cab6cSJC Kuo 
11131f9cab6cSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
11141f9cab6cSJC Kuo 	value |= SSPX_ELPG_CLAMP_EN_EARLY(index);
11151f9cab6cSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
11161f9cab6cSJC Kuo 
11171f9cab6cSJC Kuo 	usleep_range(100, 200);
11181f9cab6cSJC Kuo 
11191f9cab6cSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
11201f9cab6cSJC Kuo 	value |= SSPX_ELPG_CLAMP_EN(index);
11211f9cab6cSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
11221f9cab6cSJC Kuo 
11231f9cab6cSJC Kuo 	usleep_range(250, 350);
11241f9cab6cSJC Kuo 
11251f9cab6cSJC Kuo 	mutex_unlock(&padctl->lock);
11261f9cab6cSJC Kuo 
11271f9cab6cSJC Kuo 	return 0;
11281f9cab6cSJC Kuo }
11291f9cab6cSJC Kuo 
tegra186_usb3_disable_phy_sleepwalk(struct tegra_xusb_lane * lane)11301f9cab6cSJC Kuo static int tegra186_usb3_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
11311f9cab6cSJC Kuo {
11321f9cab6cSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
11331f9cab6cSJC Kuo 	unsigned int index = lane->index;
11341f9cab6cSJC Kuo 	u32 value;
11351f9cab6cSJC Kuo 
11361f9cab6cSJC Kuo 	mutex_lock(&padctl->lock);
11371f9cab6cSJC Kuo 
11381f9cab6cSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
11391f9cab6cSJC Kuo 	value &= ~SSPX_ELPG_CLAMP_EN_EARLY(index);
11401f9cab6cSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
11411f9cab6cSJC Kuo 
11421f9cab6cSJC Kuo 	usleep_range(100, 200);
11431f9cab6cSJC Kuo 
11441f9cab6cSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
11451f9cab6cSJC Kuo 	value &= ~SSPX_ELPG_CLAMP_EN(index);
11461f9cab6cSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
11471f9cab6cSJC Kuo 
11481f9cab6cSJC Kuo 	mutex_unlock(&padctl->lock);
11491f9cab6cSJC Kuo 
11501f9cab6cSJC Kuo 	return 0;
11511f9cab6cSJC Kuo }
11521f9cab6cSJC Kuo 
tegra186_usb3_enable_phy_wake(struct tegra_xusb_lane * lane)11531f9cab6cSJC Kuo static int tegra186_usb3_enable_phy_wake(struct tegra_xusb_lane *lane)
11541f9cab6cSJC Kuo {
11551f9cab6cSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
11561f9cab6cSJC Kuo 	unsigned int index = lane->index;
11571f9cab6cSJC Kuo 	u32 value;
11581f9cab6cSJC Kuo 
11591f9cab6cSJC Kuo 	mutex_lock(&padctl->lock);
11601f9cab6cSJC Kuo 
11611f9cab6cSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
11621f9cab6cSJC Kuo 	value &= ~ALL_WAKE_EVENTS;
11631f9cab6cSJC Kuo 	value |= SS_PORT_WAKEUP_EVENT(index);
11641f9cab6cSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
11651f9cab6cSJC Kuo 
11661f9cab6cSJC Kuo 	usleep_range(10, 20);
11671f9cab6cSJC Kuo 
11681f9cab6cSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
11691f9cab6cSJC Kuo 	value &= ~ALL_WAKE_EVENTS;
11701f9cab6cSJC Kuo 	value |= SS_PORT_WAKE_INTERRUPT_ENABLE(index);
11711f9cab6cSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
11721f9cab6cSJC Kuo 
11731f9cab6cSJC Kuo 	mutex_unlock(&padctl->lock);
11741f9cab6cSJC Kuo 
11751f9cab6cSJC Kuo 	return 0;
11761f9cab6cSJC Kuo }
11771f9cab6cSJC Kuo 
tegra186_usb3_disable_phy_wake(struct tegra_xusb_lane * lane)11781f9cab6cSJC Kuo static int tegra186_usb3_disable_phy_wake(struct tegra_xusb_lane *lane)
11791f9cab6cSJC Kuo {
11801f9cab6cSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
11811f9cab6cSJC Kuo 	unsigned int index = lane->index;
11821f9cab6cSJC Kuo 	u32 value;
11831f9cab6cSJC Kuo 
11841f9cab6cSJC Kuo 	mutex_lock(&padctl->lock);
11851f9cab6cSJC Kuo 
11861f9cab6cSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
11871f9cab6cSJC Kuo 	value &= ~ALL_WAKE_EVENTS;
11881f9cab6cSJC Kuo 	value &= ~SS_PORT_WAKE_INTERRUPT_ENABLE(index);
11891f9cab6cSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
11901f9cab6cSJC Kuo 
11911f9cab6cSJC Kuo 	usleep_range(10, 20);
11921f9cab6cSJC Kuo 
11931f9cab6cSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
11941f9cab6cSJC Kuo 	value &= ~ALL_WAKE_EVENTS;
11951f9cab6cSJC Kuo 	value |= SS_PORT_WAKEUP_EVENT(index);
11961f9cab6cSJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
11971f9cab6cSJC Kuo 
11981f9cab6cSJC Kuo 	mutex_unlock(&padctl->lock);
11991f9cab6cSJC Kuo 
12001f9cab6cSJC Kuo 	return 0;
12011f9cab6cSJC Kuo }
12021f9cab6cSJC Kuo 
tegra186_usb3_phy_remote_wake_detected(struct tegra_xusb_lane * lane)12031f9cab6cSJC Kuo static bool tegra186_usb3_phy_remote_wake_detected(struct tegra_xusb_lane *lane)
12041f9cab6cSJC Kuo {
12051f9cab6cSJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
12061f9cab6cSJC Kuo 	unsigned int index = lane->index;
12071f9cab6cSJC Kuo 	u32 value;
12081f9cab6cSJC Kuo 
12091f9cab6cSJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
12101f9cab6cSJC Kuo 	if ((value & SS_PORT_WAKE_INTERRUPT_ENABLE(index)) && (value & SS_PORT_WAKEUP_EVENT(index)))
12111f9cab6cSJC Kuo 		return true;
12121f9cab6cSJC Kuo 
12131f9cab6cSJC Kuo 	return false;
12141f9cab6cSJC Kuo }
12151f9cab6cSJC Kuo 
1216bbf71168SJC Kuo static const struct tegra_xusb_lane_ops tegra186_usb3_lane_ops = {
1217bbf71168SJC Kuo 	.probe = tegra186_usb3_lane_probe,
1218bbf71168SJC Kuo 	.remove = tegra186_usb3_lane_remove,
12191f9cab6cSJC Kuo 	.enable_phy_sleepwalk = tegra186_usb3_enable_phy_sleepwalk,
12201f9cab6cSJC Kuo 	.disable_phy_sleepwalk = tegra186_usb3_disable_phy_sleepwalk,
12211f9cab6cSJC Kuo 	.enable_phy_wake = tegra186_usb3_enable_phy_wake,
12221f9cab6cSJC Kuo 	.disable_phy_wake = tegra186_usb3_disable_phy_wake,
12231f9cab6cSJC Kuo 	.remote_wake_detected = tegra186_usb3_phy_remote_wake_detected,
1224bbf71168SJC Kuo };
12251f9cab6cSJC Kuo 
tegra186_usb3_port_enable(struct tegra_xusb_port * port)1226bbf71168SJC Kuo static int tegra186_usb3_port_enable(struct tegra_xusb_port *port)
1227bbf71168SJC Kuo {
1228bbf71168SJC Kuo 	return 0;
1229bbf71168SJC Kuo }
1230bbf71168SJC Kuo 
tegra186_usb3_port_disable(struct tegra_xusb_port * port)1231bbf71168SJC Kuo static void tegra186_usb3_port_disable(struct tegra_xusb_port *port)
1232bbf71168SJC Kuo {
1233bbf71168SJC Kuo }
1234bbf71168SJC Kuo 
1235bbf71168SJC Kuo static struct tegra_xusb_lane *
tegra186_usb3_port_map(struct tegra_xusb_port * port)1236bbf71168SJC Kuo tegra186_usb3_port_map(struct tegra_xusb_port *port)
1237bbf71168SJC Kuo {
1238bbf71168SJC Kuo 	return tegra_xusb_find_lane(port->padctl, "usb3", port->index);
1239bbf71168SJC Kuo }
1240bbf71168SJC Kuo 
1241bbf71168SJC Kuo static const struct tegra_xusb_port_ops tegra186_usb3_port_ops = {
1242e78fdbadSThierry Reding 	.release = tegra_xusb_usb3_port_release,
1243bbf71168SJC Kuo 	.enable = tegra186_usb3_port_enable,
1244bbf71168SJC Kuo 	.disable = tegra186_usb3_port_disable,
1245bbf71168SJC Kuo 	.map = tegra186_usb3_port_map,
1246bbf71168SJC Kuo };
1247bbf71168SJC Kuo 
tegra186_usb3_phy_power_on(struct phy * phy)1248bbf71168SJC Kuo static int tegra186_usb3_phy_power_on(struct phy *phy)
1249bbf71168SJC Kuo {
1250bbf71168SJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
1251bbf71168SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1252bbf71168SJC Kuo 	struct tegra_xusb_usb3_port *port;
1253bbf71168SJC Kuo 	struct tegra_xusb_usb2_port *usb2;
1254bbf71168SJC Kuo 	unsigned int index = lane->index;
1255bbf71168SJC Kuo 	struct device *dev = padctl->dev;
1256bbf71168SJC Kuo 	u32 value;
1257bbf71168SJC Kuo 
1258bbf71168SJC Kuo 	port = tegra_xusb_find_usb3_port(padctl, index);
1259bbf71168SJC Kuo 	if (!port) {
1260bbf71168SJC Kuo 		dev_err(dev, "no port found for USB3 lane %u\n", index);
1261bbf71168SJC Kuo 		return -ENODEV;
1262bbf71168SJC Kuo 	}
1263bbf71168SJC Kuo 
1264bbf71168SJC Kuo 	usb2 = tegra_xusb_find_usb2_port(padctl, port->port);
1265bbf71168SJC Kuo 	if (!usb2) {
1266bbf71168SJC Kuo 		dev_err(dev, "no companion port found for USB3 lane %u\n",
1267bbf71168SJC Kuo 			index);
1268bbf71168SJC Kuo 		return -ENODEV;
1269bbf71168SJC Kuo 	}
1270bbf71168SJC Kuo 
1271bbf71168SJC Kuo 	mutex_lock(&padctl->lock);
1272bbf71168SJC Kuo 
1273bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_CAP);
1274bbf71168SJC Kuo 	value &= ~(PORT_CAP_MASK << PORTX_CAP_SHIFT(index));
1275bbf71168SJC Kuo 
1276bbf71168SJC Kuo 	if (usb2->mode == USB_DR_MODE_UNKNOWN)
1277bbf71168SJC Kuo 		value |= (PORT_CAP_DISABLED << PORTX_CAP_SHIFT(index));
1278bbf71168SJC Kuo 	else if (usb2->mode == USB_DR_MODE_PERIPHERAL)
1279bbf71168SJC Kuo 		value |= (PORT_CAP_DEVICE << PORTX_CAP_SHIFT(index));
1280bbf71168SJC Kuo 	else if (usb2->mode == USB_DR_MODE_HOST)
1281bbf71168SJC Kuo 		value |= (PORT_CAP_HOST << PORTX_CAP_SHIFT(index));
1282bbf71168SJC Kuo 	else if (usb2->mode == USB_DR_MODE_OTG)
1283bbf71168SJC Kuo 		value |= (PORT_CAP_OTG << PORTX_CAP_SHIFT(index));
1284bbf71168SJC Kuo 
1285bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_CAP);
1286bbf71168SJC Kuo 
12871ef535c6SJC Kuo 	if (padctl->soc->supports_gen2 && port->disable_gen2) {
12881ef535c6SJC Kuo 		value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_CFG);
12891ef535c6SJC Kuo 		value &= ~(PORTX_SPEED_SUPPORT_MASK <<
12901ef535c6SJC Kuo 			PORTX_SPEED_SUPPORT_SHIFT(index));
12911ef535c6SJC Kuo 		value |= (PORT_SPEED_SUPPORT_GEN1 <<
12921ef535c6SJC Kuo 			PORTX_SPEED_SUPPORT_SHIFT(index));
12931ef535c6SJC Kuo 		padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_CFG);
12941ef535c6SJC Kuo 	}
12951ef535c6SJC Kuo 
1296bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
1297bbf71168SJC Kuo 	value &= ~SSPX_ELPG_VCORE_DOWN(index);
1298bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
1299bbf71168SJC Kuo 
1300bbf71168SJC Kuo 	usleep_range(100, 200);
1301bbf71168SJC Kuo 
1302bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
1303bbf71168SJC Kuo 	value &= ~SSPX_ELPG_CLAMP_EN_EARLY(index);
1304bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
1305bbf71168SJC Kuo 
1306bbf71168SJC Kuo 	usleep_range(100, 200);
1307bbf71168SJC Kuo 
1308bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
1309bbf71168SJC Kuo 	value &= ~SSPX_ELPG_CLAMP_EN(index);
1310bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
1311bbf71168SJC Kuo 
1312bbf71168SJC Kuo 	mutex_unlock(&padctl->lock);
1313bbf71168SJC Kuo 
1314bbf71168SJC Kuo 	return 0;
1315bbf71168SJC Kuo }
1316bbf71168SJC Kuo 
tegra186_usb3_phy_power_off(struct phy * phy)1317bbf71168SJC Kuo static int tegra186_usb3_phy_power_off(struct phy *phy)
1318bbf71168SJC Kuo {
1319bbf71168SJC Kuo 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
1320bbf71168SJC Kuo 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
1321bbf71168SJC Kuo 	struct tegra_xusb_usb3_port *port;
1322bbf71168SJC Kuo 	unsigned int index = lane->index;
1323bbf71168SJC Kuo 	struct device *dev = padctl->dev;
1324bbf71168SJC Kuo 	u32 value;
1325bbf71168SJC Kuo 
1326bbf71168SJC Kuo 	port = tegra_xusb_find_usb3_port(padctl, index);
1327bbf71168SJC Kuo 	if (!port) {
1328bbf71168SJC Kuo 		dev_err(dev, "no port found for USB3 lane %u\n", index);
1329bbf71168SJC Kuo 		return -ENODEV;
1330bbf71168SJC Kuo 	}
1331bbf71168SJC Kuo 
1332bbf71168SJC Kuo 	mutex_lock(&padctl->lock);
1333bbf71168SJC Kuo 
1334bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
1335bbf71168SJC Kuo 	value |= SSPX_ELPG_CLAMP_EN_EARLY(index);
1336bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
1337bbf71168SJC Kuo 
1338bbf71168SJC Kuo 	usleep_range(100, 200);
1339bbf71168SJC Kuo 
1340bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
1341bbf71168SJC Kuo 	value |= SSPX_ELPG_CLAMP_EN(index);
1342bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
1343bbf71168SJC Kuo 
1344bbf71168SJC Kuo 	usleep_range(250, 350);
1345bbf71168SJC Kuo 
1346bbf71168SJC Kuo 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
1347bbf71168SJC Kuo 	value |= SSPX_ELPG_VCORE_DOWN(index);
1348bbf71168SJC Kuo 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
1349bbf71168SJC Kuo 
1350bbf71168SJC Kuo 	mutex_unlock(&padctl->lock);
1351bbf71168SJC Kuo 
1352bbf71168SJC Kuo 	return 0;
1353bbf71168SJC Kuo }
1354bbf71168SJC Kuo 
tegra186_usb3_phy_init(struct phy * phy)1355bbf71168SJC Kuo static int tegra186_usb3_phy_init(struct phy *phy)
1356bbf71168SJC Kuo {
1357bbf71168SJC Kuo 	return 0;
1358bbf71168SJC Kuo }
1359bbf71168SJC Kuo 
tegra186_usb3_phy_exit(struct phy * phy)1360bbf71168SJC Kuo static int tegra186_usb3_phy_exit(struct phy *phy)
1361bbf71168SJC Kuo {
1362bbf71168SJC Kuo 	return 0;
1363bbf71168SJC Kuo }
1364bbf71168SJC Kuo 
1365bbf71168SJC Kuo static const struct phy_ops usb3_phy_ops = {
1366bbf71168SJC Kuo 	.init = tegra186_usb3_phy_init,
1367bbf71168SJC Kuo 	.exit = tegra186_usb3_phy_exit,
1368bbf71168SJC Kuo 	.power_on = tegra186_usb3_phy_power_on,
1369bbf71168SJC Kuo 	.power_off = tegra186_usb3_phy_power_off,
1370bbf71168SJC Kuo 	.owner = THIS_MODULE,
1371bbf71168SJC Kuo };
1372bbf71168SJC Kuo 
1373bbf71168SJC Kuo static struct tegra_xusb_pad *
tegra186_usb3_pad_probe(struct tegra_xusb_padctl * padctl,const struct tegra_xusb_pad_soc * soc,struct device_node * np)1374bbf71168SJC Kuo tegra186_usb3_pad_probe(struct tegra_xusb_padctl *padctl,
1375bbf71168SJC Kuo 			const struct tegra_xusb_pad_soc *soc,
1376bbf71168SJC Kuo 			struct device_node *np)
1377bbf71168SJC Kuo {
1378bbf71168SJC Kuo 	struct tegra_xusb_usb3_pad *usb3;
1379bbf71168SJC Kuo 	struct tegra_xusb_pad *pad;
1380bbf71168SJC Kuo 	int err;
1381bbf71168SJC Kuo 
1382bbf71168SJC Kuo 	usb3 = kzalloc(sizeof(*usb3), GFP_KERNEL);
1383bbf71168SJC Kuo 	if (!usb3)
1384bbf71168SJC Kuo 		return ERR_PTR(-ENOMEM);
1385bbf71168SJC Kuo 
1386bbf71168SJC Kuo 	pad = &usb3->base;
1387bbf71168SJC Kuo 	pad->ops = &tegra186_usb3_lane_ops;
1388bbf71168SJC Kuo 	pad->soc = soc;
1389bbf71168SJC Kuo 
1390bbf71168SJC Kuo 	err = tegra_xusb_pad_init(pad, padctl, np);
1391bbf71168SJC Kuo 	if (err < 0) {
1392bbf71168SJC Kuo 		kfree(usb3);
1393bbf71168SJC Kuo 		goto out;
1394bbf71168SJC Kuo 	}
1395bbf71168SJC Kuo 
1396bbf71168SJC Kuo 	err = tegra_xusb_pad_register(pad, &usb3_phy_ops);
1397bbf71168SJC Kuo 	if (err < 0)
1398bbf71168SJC Kuo 		goto unregister;
1399bbf71168SJC Kuo 
1400bbf71168SJC Kuo 	dev_set_drvdata(&pad->dev, pad);
1401bbf71168SJC Kuo 
1402bbf71168SJC Kuo 	return pad;
1403bbf71168SJC Kuo 
1404bbf71168SJC Kuo unregister:
1405bbf71168SJC Kuo 	device_unregister(&pad->dev);
1406bbf71168SJC Kuo out:
1407bbf71168SJC Kuo 	return ERR_PTR(err);
1408bbf71168SJC Kuo }
1409bbf71168SJC Kuo 
tegra186_usb3_pad_remove(struct tegra_xusb_pad * pad)1410bbf71168SJC Kuo static void tegra186_usb3_pad_remove(struct tegra_xusb_pad *pad)
1411bbf71168SJC Kuo {
1412bbf71168SJC Kuo 	struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad);
1413bbf71168SJC Kuo 
1414bbf71168SJC Kuo 	kfree(usb2);
1415bbf71168SJC Kuo }
1416bbf71168SJC Kuo 
1417bbf71168SJC Kuo static const struct tegra_xusb_pad_ops tegra186_usb3_pad_ops = {
1418bbf71168SJC Kuo 	.probe = tegra186_usb3_pad_probe,
1419bbf71168SJC Kuo 	.remove = tegra186_usb3_pad_remove,
1420bbf71168SJC Kuo };
1421bbf71168SJC Kuo 
1422bbf71168SJC Kuo static const char * const tegra186_usb3_functions[] = {
1423bbf71168SJC Kuo 	"xusb",
1424bbf71168SJC Kuo };
1425bbf71168SJC Kuo 
1426bbf71168SJC Kuo static int
tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl * padctl)1427bbf71168SJC Kuo tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl)
1428bbf71168SJC Kuo {
1429bbf71168SJC Kuo 	struct device *dev = padctl->base.dev;
1430bbf71168SJC Kuo 	unsigned int i, count;
1431bbf71168SJC Kuo 	u32 value, *level;
1432bbf71168SJC Kuo 	int err;
1433bbf71168SJC Kuo 
1434bbf71168SJC Kuo 	count = padctl->base.soc->ports.usb2.count;
1435bbf71168SJC Kuo 
1436bbf71168SJC Kuo 	level = devm_kcalloc(dev, count, sizeof(u32), GFP_KERNEL);
1437bbf71168SJC Kuo 	if (!level)
1438bbf71168SJC Kuo 		return -ENOMEM;
1439bbf71168SJC Kuo 
1440bbf71168SJC Kuo 	err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value);
14416177f796SYuan Can 	if (err)
14426177f796SYuan Can 		return dev_err_probe(dev, err,
14436177f796SYuan Can 				     "failed to read calibration fuse\n");
1444bbf71168SJC Kuo 
1445bbf71168SJC Kuo 	dev_dbg(dev, "FUSE_USB_CALIB_0 %#x\n", value);
1446bbf71168SJC Kuo 
1447bbf71168SJC Kuo 	for (i = 0; i < count; i++)
1448bbf71168SJC Kuo 		level[i] = (value >> HS_CURR_LEVEL_PADX_SHIFT(i)) &
1449bbf71168SJC Kuo 				HS_CURR_LEVEL_PAD_MASK;
1450bbf71168SJC Kuo 
1451bbf71168SJC Kuo 	padctl->calib.hs_curr_level = level;
1452bbf71168SJC Kuo 
1453bbf71168SJC Kuo 	padctl->calib.hs_squelch = (value >> HS_SQUELCH_SHIFT) &
1454bbf71168SJC Kuo 					HS_SQUELCH_MASK;
1455bbf71168SJC Kuo 	padctl->calib.hs_term_range_adj = (value >> HS_TERM_RANGE_ADJ_SHIFT) &
1456bbf71168SJC Kuo 						HS_TERM_RANGE_ADJ_MASK;
1457bbf71168SJC Kuo 
1458bbf71168SJC Kuo 	err = tegra_fuse_readl(TEGRA_FUSE_USB_CALIB_EXT_0, &value);
1459bbf71168SJC Kuo 	if (err) {
1460bbf71168SJC Kuo 		dev_err(dev, "failed to read calibration fuse: %d\n", err);
1461bbf71168SJC Kuo 		return err;
1462bbf71168SJC Kuo 	}
1463bbf71168SJC Kuo 
1464bbf71168SJC Kuo 	dev_dbg(dev, "FUSE_USB_CALIB_EXT_0 %#x\n", value);
1465bbf71168SJC Kuo 
1466bbf71168SJC Kuo 	padctl->calib.rpd_ctrl = (value >> RPD_CTRL_SHIFT) & RPD_CTRL_MASK;
1467bbf71168SJC Kuo 
1468bbf71168SJC Kuo 	return 0;
1469bbf71168SJC Kuo }
1470bbf71168SJC Kuo 
1471bbf71168SJC Kuo static struct tegra_xusb_padctl *
tegra186_xusb_padctl_probe(struct device * dev,const struct tegra_xusb_padctl_soc * soc)1472bbf71168SJC Kuo tegra186_xusb_padctl_probe(struct device *dev,
1473bbf71168SJC Kuo 			   const struct tegra_xusb_padctl_soc *soc)
1474bbf71168SJC Kuo {
14751f9cab6cSJC Kuo 	struct platform_device *pdev = to_platform_device(dev);
1476bbf71168SJC Kuo 	struct tegra186_xusb_padctl *priv;
14771f9cab6cSJC Kuo 	struct resource *res;
1478bbf71168SJC Kuo 	int err;
1479bbf71168SJC Kuo 
1480bbf71168SJC Kuo 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
1481bbf71168SJC Kuo 	if (!priv)
1482bbf71168SJC Kuo 		return ERR_PTR(-ENOMEM);
1483bbf71168SJC Kuo 
1484bbf71168SJC Kuo 	priv->base.dev = dev;
1485bbf71168SJC Kuo 	priv->base.soc = soc;
1486bbf71168SJC Kuo 
14871f9cab6cSJC Kuo 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ao");
14881f9cab6cSJC Kuo 	priv->ao_regs = devm_ioremap_resource(dev, res);
14891f9cab6cSJC Kuo 	if (IS_ERR(priv->ao_regs))
14901f9cab6cSJC Kuo 		return ERR_CAST(priv->ao_regs);
14911f9cab6cSJC Kuo 
1492bbf71168SJC Kuo 	err = tegra186_xusb_read_fuse_calibration(priv);
1493bbf71168SJC Kuo 	if (err < 0)
1494bbf71168SJC Kuo 		return ERR_PTR(err);
1495bbf71168SJC Kuo 
1496bbf71168SJC Kuo 	return &priv->base;
1497bbf71168SJC Kuo }
1498bbf71168SJC Kuo 
tegra186_xusb_padctl_save(struct tegra_xusb_padctl * padctl)14991f9cab6cSJC Kuo static void tegra186_xusb_padctl_save(struct tegra_xusb_padctl *padctl)
15001f9cab6cSJC Kuo {
15011f9cab6cSJC Kuo 	struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
15021f9cab6cSJC Kuo 
15031f9cab6cSJC Kuo 	priv->context.vbus_id = padctl_readl(padctl, USB2_VBUS_ID);
15041f9cab6cSJC Kuo 	priv->context.usb2_pad_mux = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
15051f9cab6cSJC Kuo 	priv->context.usb2_port_cap = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
15061f9cab6cSJC Kuo 	priv->context.ss_port_cap = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_CAP);
15071f9cab6cSJC Kuo }
15081f9cab6cSJC Kuo 
tegra186_xusb_padctl_restore(struct tegra_xusb_padctl * padctl)15091f9cab6cSJC Kuo static void tegra186_xusb_padctl_restore(struct tegra_xusb_padctl *padctl)
15101f9cab6cSJC Kuo {
15111f9cab6cSJC Kuo 	struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
15121f9cab6cSJC Kuo 
15131f9cab6cSJC Kuo 	padctl_writel(padctl, priv->context.usb2_pad_mux, XUSB_PADCTL_USB2_PAD_MUX);
15141f9cab6cSJC Kuo 	padctl_writel(padctl, priv->context.usb2_port_cap, XUSB_PADCTL_USB2_PORT_CAP);
15151f9cab6cSJC Kuo 	padctl_writel(padctl, priv->context.ss_port_cap, XUSB_PADCTL_SS_PORT_CAP);
15161f9cab6cSJC Kuo 	padctl_writel(padctl, priv->context.vbus_id, USB2_VBUS_ID);
15171f9cab6cSJC Kuo }
15181f9cab6cSJC Kuo 
tegra186_xusb_padctl_suspend_noirq(struct tegra_xusb_padctl * padctl)15191f9cab6cSJC Kuo static int tegra186_xusb_padctl_suspend_noirq(struct tegra_xusb_padctl *padctl)
15201f9cab6cSJC Kuo {
15211f9cab6cSJC Kuo 	tegra186_xusb_padctl_save(padctl);
15221f9cab6cSJC Kuo 
15231f9cab6cSJC Kuo 	return 0;
15241f9cab6cSJC Kuo }
15251f9cab6cSJC Kuo 
tegra186_xusb_padctl_resume_noirq(struct tegra_xusb_padctl * padctl)15261f9cab6cSJC Kuo static int tegra186_xusb_padctl_resume_noirq(struct tegra_xusb_padctl *padctl)
15271f9cab6cSJC Kuo {
15281f9cab6cSJC Kuo 	tegra186_xusb_padctl_restore(padctl);
15291f9cab6cSJC Kuo 
15301f9cab6cSJC Kuo 	return 0;
15311f9cab6cSJC Kuo }
15321f9cab6cSJC Kuo 
tegra186_xusb_padctl_remove(struct tegra_xusb_padctl * padctl)1533bbf71168SJC Kuo static void tegra186_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
1534bbf71168SJC Kuo {
1535bbf71168SJC Kuo }
1536bbf71168SJC Kuo 
1537bbf71168SJC Kuo static const struct tegra_xusb_padctl_ops tegra186_xusb_padctl_ops = {
1538bbf71168SJC Kuo 	.probe = tegra186_xusb_padctl_probe,
1539bbf71168SJC Kuo 	.remove = tegra186_xusb_padctl_remove,
15401f9cab6cSJC Kuo 	.suspend_noirq = tegra186_xusb_padctl_suspend_noirq,
15411f9cab6cSJC Kuo 	.resume_noirq = tegra186_xusb_padctl_resume_noirq,
1542a8a24429SNagarjuna Kristam 	.vbus_override = tegra186_xusb_padctl_vbus_override,
154377bfa0fcSJim Lin 	.utmi_pad_power_on = tegra186_utmi_pad_power_on,
154477bfa0fcSJim Lin 	.utmi_pad_power_down = tegra186_utmi_pad_power_down,
1545bbf71168SJC Kuo };
1546bbf71168SJC Kuo 
154705114192SJC Kuo #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC)
1548bbf71168SJC Kuo static const char * const tegra186_xusb_padctl_supply_names[] = {
1549bbf71168SJC Kuo 	"avdd-pll-erefeut",
1550bbf71168SJC Kuo 	"avdd-usb",
1551bbf71168SJC Kuo 	"vclamp-usb",
1552bbf71168SJC Kuo 	"vddio-hsic",
1553bbf71168SJC Kuo };
1554bbf71168SJC Kuo 
155505114192SJC Kuo static const struct tegra_xusb_lane_soc tegra186_usb2_lanes[] = {
155605114192SJC Kuo 	TEGRA186_LANE("usb2-0", 0,  0, 0, usb2),
155705114192SJC Kuo 	TEGRA186_LANE("usb2-1", 0,  0, 0, usb2),
155805114192SJC Kuo 	TEGRA186_LANE("usb2-2", 0,  0, 0, usb2),
155905114192SJC Kuo };
156005114192SJC Kuo 
156105114192SJC Kuo static const struct tegra_xusb_pad_soc tegra186_usb2_pad = {
156205114192SJC Kuo 	.name = "usb2",
156305114192SJC Kuo 	.num_lanes = ARRAY_SIZE(tegra186_usb2_lanes),
156405114192SJC Kuo 	.lanes = tegra186_usb2_lanes,
156505114192SJC Kuo 	.ops = &tegra186_usb2_pad_ops,
156605114192SJC Kuo };
156705114192SJC Kuo 
156805114192SJC Kuo static const struct tegra_xusb_lane_soc tegra186_usb3_lanes[] = {
156905114192SJC Kuo 	TEGRA186_LANE("usb3-0", 0,  0, 0, usb3),
157005114192SJC Kuo 	TEGRA186_LANE("usb3-1", 0,  0, 0, usb3),
157105114192SJC Kuo 	TEGRA186_LANE("usb3-2", 0,  0, 0, usb3),
157205114192SJC Kuo };
157305114192SJC Kuo 
157405114192SJC Kuo static const struct tegra_xusb_pad_soc tegra186_usb3_pad = {
157505114192SJC Kuo 	.name = "usb3",
157605114192SJC Kuo 	.num_lanes = ARRAY_SIZE(tegra186_usb3_lanes),
157705114192SJC Kuo 	.lanes = tegra186_usb3_lanes,
157805114192SJC Kuo 	.ops = &tegra186_usb3_pad_ops,
157905114192SJC Kuo };
158005114192SJC Kuo 
158105114192SJC Kuo static const struct tegra_xusb_pad_soc * const tegra186_pads[] = {
158205114192SJC Kuo 	&tegra186_usb2_pad,
158305114192SJC Kuo 	&tegra186_usb3_pad,
158405114192SJC Kuo #if 0 /* TODO implement */
158505114192SJC Kuo 	&tegra186_hsic_pad,
158605114192SJC Kuo #endif
158705114192SJC Kuo };
158805114192SJC Kuo 
1589bbf71168SJC Kuo const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc = {
1590bbf71168SJC Kuo 	.num_pads = ARRAY_SIZE(tegra186_pads),
1591bbf71168SJC Kuo 	.pads = tegra186_pads,
1592bbf71168SJC Kuo 	.ports = {
1593bbf71168SJC Kuo 		.usb2 = {
1594bbf71168SJC Kuo 			.ops = &tegra186_usb2_port_ops,
1595bbf71168SJC Kuo 			.count = 3,
1596bbf71168SJC Kuo 		},
1597bbf71168SJC Kuo #if 0 /* TODO implement */
1598bbf71168SJC Kuo 		.hsic = {
1599bbf71168SJC Kuo 			.ops = &tegra186_hsic_port_ops,
1600bbf71168SJC Kuo 			.count = 1,
1601bbf71168SJC Kuo 		},
1602bbf71168SJC Kuo #endif
1603bbf71168SJC Kuo 		.usb3 = {
1604bbf71168SJC Kuo 			.ops = &tegra186_usb3_port_ops,
1605bbf71168SJC Kuo 			.count = 3,
1606bbf71168SJC Kuo 		},
1607bbf71168SJC Kuo 	},
1608bbf71168SJC Kuo 	.ops = &tegra186_xusb_padctl_ops,
1609bbf71168SJC Kuo 	.supply_names = tegra186_xusb_padctl_supply_names,
1610bbf71168SJC Kuo 	.num_supplies = ARRAY_SIZE(tegra186_xusb_padctl_supply_names),
1611bbf71168SJC Kuo };
1612bbf71168SJC Kuo EXPORT_SYMBOL_GPL(tegra186_xusb_padctl_soc);
161305114192SJC Kuo #endif
1614bbf71168SJC Kuo 
1615d8163a32SSing-Han Chen #if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
1616d8163a32SSing-Han Chen 	IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
16171ef535c6SJC Kuo static const char * const tegra194_xusb_padctl_supply_names[] = {
16181ef535c6SJC Kuo 	"avdd-usb",
16191ef535c6SJC Kuo 	"vclamp-usb",
16201ef535c6SJC Kuo };
16211ef535c6SJC Kuo 
16221ef535c6SJC Kuo static const struct tegra_xusb_lane_soc tegra194_usb2_lanes[] = {
16231ef535c6SJC Kuo 	TEGRA186_LANE("usb2-0", 0,  0, 0, usb2),
16241ef535c6SJC Kuo 	TEGRA186_LANE("usb2-1", 0,  0, 0, usb2),
16251ef535c6SJC Kuo 	TEGRA186_LANE("usb2-2", 0,  0, 0, usb2),
16261ef535c6SJC Kuo 	TEGRA186_LANE("usb2-3", 0,  0, 0, usb2),
16271ef535c6SJC Kuo };
16281ef535c6SJC Kuo 
16291ef535c6SJC Kuo static const struct tegra_xusb_pad_soc tegra194_usb2_pad = {
16301ef535c6SJC Kuo 	.name = "usb2",
16311ef535c6SJC Kuo 	.num_lanes = ARRAY_SIZE(tegra194_usb2_lanes),
16321ef535c6SJC Kuo 	.lanes = tegra194_usb2_lanes,
16331ef535c6SJC Kuo 	.ops = &tegra186_usb2_pad_ops,
16341ef535c6SJC Kuo };
16351ef535c6SJC Kuo 
16361ef535c6SJC Kuo static const struct tegra_xusb_lane_soc tegra194_usb3_lanes[] = {
16371ef535c6SJC Kuo 	TEGRA186_LANE("usb3-0", 0,  0, 0, usb3),
16381ef535c6SJC Kuo 	TEGRA186_LANE("usb3-1", 0,  0, 0, usb3),
16391ef535c6SJC Kuo 	TEGRA186_LANE("usb3-2", 0,  0, 0, usb3),
16401ef535c6SJC Kuo 	TEGRA186_LANE("usb3-3", 0,  0, 0, usb3),
16411ef535c6SJC Kuo };
16421ef535c6SJC Kuo 
16431ef535c6SJC Kuo static const struct tegra_xusb_pad_soc tegra194_usb3_pad = {
16441ef535c6SJC Kuo 	.name = "usb3",
16451ef535c6SJC Kuo 	.num_lanes = ARRAY_SIZE(tegra194_usb3_lanes),
16461ef535c6SJC Kuo 	.lanes = tegra194_usb3_lanes,
16471ef535c6SJC Kuo 	.ops = &tegra186_usb3_pad_ops,
16481ef535c6SJC Kuo };
16491ef535c6SJC Kuo 
16501ef535c6SJC Kuo static const struct tegra_xusb_pad_soc * const tegra194_pads[] = {
16511ef535c6SJC Kuo 	&tegra194_usb2_pad,
16521ef535c6SJC Kuo 	&tegra194_usb3_pad,
16531ef535c6SJC Kuo };
16541ef535c6SJC Kuo 
16551ef535c6SJC Kuo const struct tegra_xusb_padctl_soc tegra194_xusb_padctl_soc = {
16561ef535c6SJC Kuo 	.num_pads = ARRAY_SIZE(tegra194_pads),
16571ef535c6SJC Kuo 	.pads = tegra194_pads,
16581ef535c6SJC Kuo 	.ports = {
16591ef535c6SJC Kuo 		.usb2 = {
16601ef535c6SJC Kuo 			.ops = &tegra186_usb2_port_ops,
16611ef535c6SJC Kuo 			.count = 4,
16621ef535c6SJC Kuo 		},
16631ef535c6SJC Kuo 		.usb3 = {
16641ef535c6SJC Kuo 			.ops = &tegra186_usb3_port_ops,
16651ef535c6SJC Kuo 			.count = 4,
16661ef535c6SJC Kuo 		},
16671ef535c6SJC Kuo 	},
16681ef535c6SJC Kuo 	.ops = &tegra186_xusb_padctl_ops,
16691ef535c6SJC Kuo 	.supply_names = tegra194_xusb_padctl_supply_names,
16701ef535c6SJC Kuo 	.num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names),
16711ef535c6SJC Kuo 	.supports_gen2 = true,
1672d8163a32SSing-Han Chen 	.poll_trk_completed = true,
16731ef535c6SJC Kuo };
16741ef535c6SJC Kuo EXPORT_SYMBOL_GPL(tegra194_xusb_padctl_soc);
1675d8163a32SSing-Han Chen 
1676d8163a32SSing-Han Chen const struct tegra_xusb_padctl_soc tegra234_xusb_padctl_soc = {
1677d8163a32SSing-Han Chen 	.num_pads = ARRAY_SIZE(tegra194_pads),
1678d8163a32SSing-Han Chen 	.pads = tegra194_pads,
1679d8163a32SSing-Han Chen 	.ports = {
1680d8163a32SSing-Han Chen 		.usb2 = {
1681d8163a32SSing-Han Chen 			.ops = &tegra186_usb2_port_ops,
1682d8163a32SSing-Han Chen 			.count = 4,
1683d8163a32SSing-Han Chen 		},
1684d8163a32SSing-Han Chen 		.usb3 = {
1685d8163a32SSing-Han Chen 			.ops = &tegra186_usb3_port_ops,
1686d8163a32SSing-Han Chen 			.count = 4,
1687d8163a32SSing-Han Chen 		},
1688d8163a32SSing-Han Chen 	},
1689d8163a32SSing-Han Chen 	.ops = &tegra186_xusb_padctl_ops,
1690d8163a32SSing-Han Chen 	.supply_names = tegra194_xusb_padctl_supply_names,
1691d8163a32SSing-Han Chen 	.num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names),
1692d8163a32SSing-Han Chen 	.supports_gen2 = true,
1693d8163a32SSing-Han Chen 	.poll_trk_completed = true,
1694d8163a32SSing-Han Chen 	.trk_hw_mode = true,
1695*8b798761SHenry Lin 	.supports_lp_cfg_en = true,
1696d8163a32SSing-Han Chen };
1697d8163a32SSing-Han Chen EXPORT_SYMBOL_GPL(tegra234_xusb_padctl_soc);
16981ef535c6SJC Kuo #endif
16991ef535c6SJC Kuo 
1700bbf71168SJC Kuo MODULE_AUTHOR("JC Kuo <jckuo@nvidia.com>");
1701bbf71168SJC Kuo MODULE_DESCRIPTION("NVIDIA Tegra186 XUSB Pad Controller driver");
1702bbf71168SJC Kuo MODULE_LICENSE("GPL v2");
1703