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