15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
294ae9843SFelipe Balbi /*
394ae9843SFelipe Balbi * Copyright (C) 2010 Google, Inc.
42d22b42dSVenu Byravarasu * Copyright (C) 2013 NVIDIA Corporation
594ae9843SFelipe Balbi *
694ae9843SFelipe Balbi * Author:
794ae9843SFelipe Balbi * Erik Gilling <konkers@google.com>
894ae9843SFelipe Balbi * Benoit Goby <benoit@android.com>
92d22b42dSVenu Byravarasu * Venu Byravarasu <vbyravarasu@nvidia.com>
1094ae9843SFelipe Balbi */
1194ae9843SFelipe Balbi
1294ae9843SFelipe Balbi #include <linux/delay.h>
1394ae9843SFelipe Balbi #include <linux/err.h>
1494ae9843SFelipe Balbi #include <linux/export.h>
159cb9322aSKrzysztof Kozlowski #include <linux/gpio/consumer.h>
165bb69850SDmitry Osipenko #include <linux/iopoll.h>
175bb69850SDmitry Osipenko #include <linux/module.h>
1894ae9843SFelipe Balbi #include <linux/of.h>
19*484468fbSRob Herring #include <linux/of_platform.h>
205bb69850SDmitry Osipenko #include <linux/platform_device.h>
215bb69850SDmitry Osipenko #include <linux/resource.h>
225bb69850SDmitry Osipenko #include <linux/slab.h>
235bb69850SDmitry Osipenko #include <linux/spinlock.h>
245bb69850SDmitry Osipenko
25f5b8c8b6SMikko Perttunen #include <linux/regulator/consumer.h>
2694ae9843SFelipe Balbi
275bb69850SDmitry Osipenko #include <linux/usb/ehci_def.h>
285bb69850SDmitry Osipenko #include <linux/usb/of.h>
295bb69850SDmitry Osipenko #include <linux/usb/tegra_usb_phy.h>
305bb69850SDmitry Osipenko #include <linux/usb/ulpi.h>
315bb69850SDmitry Osipenko
3294ae9843SFelipe Balbi #define ULPI_VIEWPORT 0x170
3394ae9843SFelipe Balbi
343e635202STuomas Tynkkynen /* PORTSC PTS/PHCD bits, Tegra20 only */
3591a687d8SStephen Warren #define TEGRA_USB_PORTSC1 0x184
3691a687d8SStephen Warren #define TEGRA_USB_PORTSC1_PTS(x) (((x) & 0x3) << 30)
37545592e8SDmitry Osipenko #define TEGRA_USB_PORTSC1_PHCD BIT(23)
3891a687d8SStephen Warren
393e635202STuomas Tynkkynen /* HOSTPC1 PTS/PHCD bits, Tegra30 and above */
403e635202STuomas Tynkkynen #define TEGRA_USB_HOSTPC1_DEVLC 0x1b4
413e635202STuomas Tynkkynen #define TEGRA_USB_HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29)
42545592e8SDmitry Osipenko #define TEGRA_USB_HOSTPC1_DEVLC_PHCD BIT(22)
433e635202STuomas Tynkkynen
4491a687d8SStephen Warren /* Bits of PORTSC1, which will get cleared by writing 1 into them */
4591a687d8SStephen Warren #define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
4691a687d8SStephen Warren
4794ae9843SFelipe Balbi #define USB_SUSP_CTRL 0x400
4835192007SDmitry Osipenko #define USB_WAKE_ON_RESUME_EN BIT(2)
49545592e8SDmitry Osipenko #define USB_WAKE_ON_CNNT_EN_DEV BIT(3)
50545592e8SDmitry Osipenko #define USB_WAKE_ON_DISCON_EN_DEV BIT(4)
51545592e8SDmitry Osipenko #define USB_SUSP_CLR BIT(5)
52545592e8SDmitry Osipenko #define USB_PHY_CLK_VALID BIT(7)
53545592e8SDmitry Osipenko #define UTMIP_RESET BIT(11)
54545592e8SDmitry Osipenko #define UHSIC_RESET BIT(11)
55545592e8SDmitry Osipenko #define UTMIP_PHY_ENABLE BIT(12)
56545592e8SDmitry Osipenko #define ULPI_PHY_ENABLE BIT(13)
57545592e8SDmitry Osipenko #define USB_SUSP_SET BIT(14)
5894ae9843SFelipe Balbi #define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
5994ae9843SFelipe Balbi
6035192007SDmitry Osipenko #define USB_PHY_VBUS_SENSORS 0x404
617917e906SDmitry Osipenko #define B_SESS_VLD_WAKEUP_EN BIT(14)
6235192007SDmitry Osipenko #define A_SESS_VLD_WAKEUP_EN BIT(22)
6335192007SDmitry Osipenko #define A_VBUS_VLD_WAKEUP_EN BIT(30)
6435192007SDmitry Osipenko
6535192007SDmitry Osipenko #define USB_PHY_VBUS_WAKEUP_ID 0x408
66c1baf6c5SDmitry Osipenko #define ID_INT_EN BIT(0)
67c1baf6c5SDmitry Osipenko #define ID_CHG_DET BIT(1)
68c1baf6c5SDmitry Osipenko #define VBUS_WAKEUP_INT_EN BIT(8)
69c1baf6c5SDmitry Osipenko #define VBUS_WAKEUP_CHG_DET BIT(9)
706f8d39a8SDmitry Osipenko #define VBUS_WAKEUP_STS BIT(10)
7135192007SDmitry Osipenko #define VBUS_WAKEUP_WAKEUP_EN BIT(30)
7235192007SDmitry Osipenko
7394ae9843SFelipe Balbi #define USB1_LEGACY_CTRL 0x410
74545592e8SDmitry Osipenko #define USB1_NO_LEGACY_MODE BIT(0)
7594ae9843SFelipe Balbi #define USB1_VBUS_SENSE_CTL_MASK (3 << 1)
7694ae9843SFelipe Balbi #define USB1_VBUS_SENSE_CTL_VBUS_WAKEUP (0 << 1)
7794ae9843SFelipe Balbi #define USB1_VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP \
7894ae9843SFelipe Balbi (1 << 1)
7994ae9843SFelipe Balbi #define USB1_VBUS_SENSE_CTL_AB_SESS_VLD (2 << 1)
8094ae9843SFelipe Balbi #define USB1_VBUS_SENSE_CTL_A_SESS_VLD (3 << 1)
8194ae9843SFelipe Balbi
8294ae9843SFelipe Balbi #define ULPI_TIMING_CTRL_0 0x424
83545592e8SDmitry Osipenko #define ULPI_OUTPUT_PINMUX_BYP BIT(10)
84545592e8SDmitry Osipenko #define ULPI_CLKOUT_PINMUX_BYP BIT(11)
8594ae9843SFelipe Balbi
8694ae9843SFelipe Balbi #define ULPI_TIMING_CTRL_1 0x428
87545592e8SDmitry Osipenko #define ULPI_DATA_TRIMMER_LOAD BIT(0)
8894ae9843SFelipe Balbi #define ULPI_DATA_TRIMMER_SEL(x) (((x) & 0x7) << 1)
89545592e8SDmitry Osipenko #define ULPI_STPDIRNXT_TRIMMER_LOAD BIT(16)
9094ae9843SFelipe Balbi #define ULPI_STPDIRNXT_TRIMMER_SEL(x) (((x) & 0x7) << 17)
91545592e8SDmitry Osipenko #define ULPI_DIR_TRIMMER_LOAD BIT(24)
9294ae9843SFelipe Balbi #define ULPI_DIR_TRIMMER_SEL(x) (((x) & 0x7) << 25)
9394ae9843SFelipe Balbi
9494ae9843SFelipe Balbi #define UTMIP_PLL_CFG1 0x804
9594ae9843SFelipe Balbi #define UTMIP_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
9694ae9843SFelipe Balbi #define UTMIP_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
9794ae9843SFelipe Balbi
9894ae9843SFelipe Balbi #define UTMIP_XCVR_CFG0 0x808
9994ae9843SFelipe Balbi #define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0)
100f5833a0bSTuomas Tynkkynen #define UTMIP_XCVR_SETUP_MSB(x) ((((x) & 0x70) >> 4) << 22)
10194ae9843SFelipe Balbi #define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8)
10294ae9843SFelipe Balbi #define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10)
103545592e8SDmitry Osipenko #define UTMIP_FORCE_PD_POWERDOWN BIT(14)
104545592e8SDmitry Osipenko #define UTMIP_FORCE_PD2_POWERDOWN BIT(16)
105545592e8SDmitry Osipenko #define UTMIP_FORCE_PDZI_POWERDOWN BIT(18)
106545592e8SDmitry Osipenko #define UTMIP_XCVR_LSBIAS_SEL BIT(21)
107e497a24dSTuomas Tynkkynen #define UTMIP_XCVR_HSSLEW(x) (((x) & 0x3) << 4)
108e497a24dSTuomas Tynkkynen #define UTMIP_XCVR_HSSLEW_MSB(x) ((((x) & 0x1fc) >> 2) << 25)
10994ae9843SFelipe Balbi
11094ae9843SFelipe Balbi #define UTMIP_BIAS_CFG0 0x80c
111545592e8SDmitry Osipenko #define UTMIP_OTGPD BIT(11)
112545592e8SDmitry Osipenko #define UTMIP_BIASPD BIT(10)
113e497a24dSTuomas Tynkkynen #define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0)
114e497a24dSTuomas Tynkkynen #define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2)
115e497a24dSTuomas Tynkkynen #define UTMIP_HSDISCON_LEVEL_MSB(x) ((((x) & 0x4) >> 2) << 24)
11694ae9843SFelipe Balbi
11794ae9843SFelipe Balbi #define UTMIP_HSRX_CFG0 0x810
11894ae9843SFelipe Balbi #define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10)
11994ae9843SFelipe Balbi #define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15)
12094ae9843SFelipe Balbi
12194ae9843SFelipe Balbi #define UTMIP_HSRX_CFG1 0x814
12294ae9843SFelipe Balbi #define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
12394ae9843SFelipe Balbi
12494ae9843SFelipe Balbi #define UTMIP_TX_CFG0 0x820
125545592e8SDmitry Osipenko #define UTMIP_FS_PREABMLE_J BIT(19)
126545592e8SDmitry Osipenko #define UTMIP_HS_DISCON_DISABLE BIT(8)
12794ae9843SFelipe Balbi
12894ae9843SFelipe Balbi #define UTMIP_MISC_CFG0 0x824
129545592e8SDmitry Osipenko #define UTMIP_DPDM_OBSERVE BIT(26)
13094ae9843SFelipe Balbi #define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27)
13194ae9843SFelipe Balbi #define UTMIP_DPDM_OBSERVE_SEL_FS_J UTMIP_DPDM_OBSERVE_SEL(0xf)
13294ae9843SFelipe Balbi #define UTMIP_DPDM_OBSERVE_SEL_FS_K UTMIP_DPDM_OBSERVE_SEL(0xe)
13394ae9843SFelipe Balbi #define UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd)
13494ae9843SFelipe Balbi #define UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc)
135545592e8SDmitry Osipenko #define UTMIP_SUSPEND_EXIT_ON_EDGE BIT(22)
13694ae9843SFelipe Balbi
13794ae9843SFelipe Balbi #define UTMIP_MISC_CFG1 0x828
13894ae9843SFelipe Balbi #define UTMIP_PLL_ACTIVE_DLY_COUNT(x) (((x) & 0x1f) << 18)
13994ae9843SFelipe Balbi #define UTMIP_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 6)
14094ae9843SFelipe Balbi
14194ae9843SFelipe Balbi #define UTMIP_DEBOUNCE_CFG0 0x82c
14294ae9843SFelipe Balbi #define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0)
14394ae9843SFelipe Balbi
14494ae9843SFelipe Balbi #define UTMIP_BAT_CHRG_CFG0 0x830
145545592e8SDmitry Osipenko #define UTMIP_PD_CHRG BIT(0)
14694ae9843SFelipe Balbi
14794ae9843SFelipe Balbi #define UTMIP_SPARE_CFG0 0x834
148545592e8SDmitry Osipenko #define FUSE_SETUP_SEL BIT(3)
14994ae9843SFelipe Balbi
15094ae9843SFelipe Balbi #define UTMIP_XCVR_CFG1 0x838
151545592e8SDmitry Osipenko #define UTMIP_FORCE_PDDISC_POWERDOWN BIT(0)
152545592e8SDmitry Osipenko #define UTMIP_FORCE_PDCHRP_POWERDOWN BIT(2)
153545592e8SDmitry Osipenko #define UTMIP_FORCE_PDDR_POWERDOWN BIT(4)
15494ae9843SFelipe Balbi #define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18)
15594ae9843SFelipe Balbi
15694ae9843SFelipe Balbi #define UTMIP_BIAS_CFG1 0x83c
15794ae9843SFelipe Balbi #define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3)
15894ae9843SFelipe Balbi
1593e635202STuomas Tynkkynen /* For Tegra30 and above only, the address is different in Tegra20 */
1603e635202STuomas Tynkkynen #define USB_USBMODE 0x1f8
1613e635202STuomas Tynkkynen #define USB_USBMODE_MASK (3 << 0)
1623e635202STuomas Tynkkynen #define USB_USBMODE_HOST (3 << 0)
1633e635202STuomas Tynkkynen #define USB_USBMODE_DEVICE (2 << 0)
1643e635202STuomas Tynkkynen
165c1baf6c5SDmitry Osipenko #define PMC_USB_AO 0xf0
166c1baf6c5SDmitry Osipenko #define VBUS_WAKEUP_PD_P0 BIT(2)
167c1baf6c5SDmitry Osipenko #define ID_PD_P0 BIT(3)
168c1baf6c5SDmitry Osipenko
16994ae9843SFelipe Balbi static DEFINE_SPINLOCK(utmip_pad_lock);
170545592e8SDmitry Osipenko static unsigned int utmip_pad_count;
17194ae9843SFelipe Balbi
17294ae9843SFelipe Balbi struct tegra_xtal_freq {
173545592e8SDmitry Osipenko unsigned int freq;
17494ae9843SFelipe Balbi u8 enable_delay;
17594ae9843SFelipe Balbi u8 stable_count;
17694ae9843SFelipe Balbi u8 active_delay;
17794ae9843SFelipe Balbi u8 xtal_freq_count;
17894ae9843SFelipe Balbi u16 debounce;
17994ae9843SFelipe Balbi };
18094ae9843SFelipe Balbi
18194ae9843SFelipe Balbi static const struct tegra_xtal_freq tegra_freq_table[] = {
18294ae9843SFelipe Balbi {
18394ae9843SFelipe Balbi .freq = 12000000,
18494ae9843SFelipe Balbi .enable_delay = 0x02,
18594ae9843SFelipe Balbi .stable_count = 0x2F,
18694ae9843SFelipe Balbi .active_delay = 0x04,
18794ae9843SFelipe Balbi .xtal_freq_count = 0x76,
18894ae9843SFelipe Balbi .debounce = 0x7530,
18994ae9843SFelipe Balbi },
19094ae9843SFelipe Balbi {
19194ae9843SFelipe Balbi .freq = 13000000,
19294ae9843SFelipe Balbi .enable_delay = 0x02,
19394ae9843SFelipe Balbi .stable_count = 0x33,
19494ae9843SFelipe Balbi .active_delay = 0x05,
19594ae9843SFelipe Balbi .xtal_freq_count = 0x7F,
19694ae9843SFelipe Balbi .debounce = 0x7EF4,
19794ae9843SFelipe Balbi },
19894ae9843SFelipe Balbi {
19994ae9843SFelipe Balbi .freq = 19200000,
20094ae9843SFelipe Balbi .enable_delay = 0x03,
20194ae9843SFelipe Balbi .stable_count = 0x4B,
20294ae9843SFelipe Balbi .active_delay = 0x06,
20394ae9843SFelipe Balbi .xtal_freq_count = 0xBB,
20494ae9843SFelipe Balbi .debounce = 0xBB80,
20594ae9843SFelipe Balbi },
20694ae9843SFelipe Balbi {
20794ae9843SFelipe Balbi .freq = 26000000,
20894ae9843SFelipe Balbi .enable_delay = 0x04,
20994ae9843SFelipe Balbi .stable_count = 0x66,
21094ae9843SFelipe Balbi .active_delay = 0x09,
21194ae9843SFelipe Balbi .xtal_freq_count = 0xFE,
21294ae9843SFelipe Balbi .debounce = 0xFDE8,
21394ae9843SFelipe Balbi },
21494ae9843SFelipe Balbi };
21594ae9843SFelipe Balbi
to_tegra_usb_phy(struct usb_phy * u_phy)216545592e8SDmitry Osipenko static inline struct tegra_usb_phy *to_tegra_usb_phy(struct usb_phy *u_phy)
217545592e8SDmitry Osipenko {
218545592e8SDmitry Osipenko return container_of(u_phy, struct tegra_usb_phy, u_phy);
219545592e8SDmitry Osipenko }
220545592e8SDmitry Osipenko
set_pts(struct tegra_usb_phy * phy,u8 pts_val)22191a687d8SStephen Warren static void set_pts(struct tegra_usb_phy *phy, u8 pts_val)
22291a687d8SStephen Warren {
22391a687d8SStephen Warren void __iomem *base = phy->regs;
22401d6ea31SDmitry Osipenko u32 val;
22591a687d8SStephen Warren
2263e635202STuomas Tynkkynen if (phy->soc_config->has_hostpc) {
227b07e5f86SDmitry Osipenko val = readl_relaxed(base + TEGRA_USB_HOSTPC1_DEVLC);
2283e635202STuomas Tynkkynen val &= ~TEGRA_USB_HOSTPC1_DEVLC_PTS(~0);
2293e635202STuomas Tynkkynen val |= TEGRA_USB_HOSTPC1_DEVLC_PTS(pts_val);
230b07e5f86SDmitry Osipenko writel_relaxed(val, base + TEGRA_USB_HOSTPC1_DEVLC);
2313e635202STuomas Tynkkynen } else {
232b07e5f86SDmitry Osipenko val = readl_relaxed(base + TEGRA_USB_PORTSC1);
233b07e5f86SDmitry Osipenko val &= ~TEGRA_PORTSC1_RWC_BITS;
2343e635202STuomas Tynkkynen val &= ~TEGRA_USB_PORTSC1_PTS(~0);
2353e635202STuomas Tynkkynen val |= TEGRA_USB_PORTSC1_PTS(pts_val);
236b07e5f86SDmitry Osipenko writel_relaxed(val, base + TEGRA_USB_PORTSC1);
23791a687d8SStephen Warren }
2383e635202STuomas Tynkkynen }
23991a687d8SStephen Warren
set_phcd(struct tegra_usb_phy * phy,bool enable)24091a687d8SStephen Warren static void set_phcd(struct tegra_usb_phy *phy, bool enable)
24191a687d8SStephen Warren {
24291a687d8SStephen Warren void __iomem *base = phy->regs;
24301d6ea31SDmitry Osipenko u32 val;
24491a687d8SStephen Warren
2453e635202STuomas Tynkkynen if (phy->soc_config->has_hostpc) {
246b07e5f86SDmitry Osipenko val = readl_relaxed(base + TEGRA_USB_HOSTPC1_DEVLC);
2473e635202STuomas Tynkkynen if (enable)
2483e635202STuomas Tynkkynen val |= TEGRA_USB_HOSTPC1_DEVLC_PHCD;
2493e635202STuomas Tynkkynen else
2503e635202STuomas Tynkkynen val &= ~TEGRA_USB_HOSTPC1_DEVLC_PHCD;
251b07e5f86SDmitry Osipenko writel_relaxed(val, base + TEGRA_USB_HOSTPC1_DEVLC);
2523e635202STuomas Tynkkynen } else {
253b07e5f86SDmitry Osipenko val = readl_relaxed(base + TEGRA_USB_PORTSC1) & ~PORT_RWC_BITS;
25491a687d8SStephen Warren if (enable)
25591a687d8SStephen Warren val |= TEGRA_USB_PORTSC1_PHCD;
25691a687d8SStephen Warren else
25791a687d8SStephen Warren val &= ~TEGRA_USB_PORTSC1_PHCD;
258b07e5f86SDmitry Osipenko writel_relaxed(val, base + TEGRA_USB_PORTSC1);
25991a687d8SStephen Warren }
2603e635202STuomas Tynkkynen }
26191a687d8SStephen Warren
utmip_pad_open(struct tegra_usb_phy * phy)26294ae9843SFelipe Balbi static int utmip_pad_open(struct tegra_usb_phy *phy)
26394ae9843SFelipe Balbi {
26414347036SDmitry Osipenko int ret;
265f59cd940SDmitry Osipenko
26614347036SDmitry Osipenko ret = clk_prepare_enable(phy->pad_clk);
26714347036SDmitry Osipenko if (ret) {
26814347036SDmitry Osipenko dev_err(phy->u_phy.dev,
26914347036SDmitry Osipenko "Failed to enable UTMI-pads clock: %d\n", ret);
27014347036SDmitry Osipenko return ret;
27114347036SDmitry Osipenko }
27214347036SDmitry Osipenko
27314347036SDmitry Osipenko spin_lock(&utmip_pad_lock);
27414347036SDmitry Osipenko
27514347036SDmitry Osipenko ret = reset_control_deassert(phy->pad_rst);
27614347036SDmitry Osipenko if (ret) {
27714347036SDmitry Osipenko dev_err(phy->u_phy.dev,
27814347036SDmitry Osipenko "Failed to initialize UTMI-pads reset: %d\n", ret);
27914347036SDmitry Osipenko goto unlock;
28014347036SDmitry Osipenko }
28114347036SDmitry Osipenko
28214347036SDmitry Osipenko ret = reset_control_assert(phy->pad_rst);
28314347036SDmitry Osipenko if (ret) {
28414347036SDmitry Osipenko dev_err(phy->u_phy.dev,
28514347036SDmitry Osipenko "Failed to assert UTMI-pads reset: %d\n", ret);
28614347036SDmitry Osipenko goto unlock;
28714347036SDmitry Osipenko }
28814347036SDmitry Osipenko
28914347036SDmitry Osipenko udelay(1);
29014347036SDmitry Osipenko
29114347036SDmitry Osipenko ret = reset_control_deassert(phy->pad_rst);
29214347036SDmitry Osipenko if (ret)
29314347036SDmitry Osipenko dev_err(phy->u_phy.dev,
29414347036SDmitry Osipenko "Failed to deassert UTMI-pads reset: %d\n", ret);
29514347036SDmitry Osipenko unlock:
29614347036SDmitry Osipenko spin_unlock(&utmip_pad_lock);
29714347036SDmitry Osipenko
29814347036SDmitry Osipenko clk_disable_unprepare(phy->pad_clk);
29914347036SDmitry Osipenko
30014347036SDmitry Osipenko return ret;
30114347036SDmitry Osipenko }
30214347036SDmitry Osipenko
utmip_pad_close(struct tegra_usb_phy * phy)30314347036SDmitry Osipenko static int utmip_pad_close(struct tegra_usb_phy *phy)
30414347036SDmitry Osipenko {
30514347036SDmitry Osipenko int ret;
30614347036SDmitry Osipenko
30714347036SDmitry Osipenko ret = clk_prepare_enable(phy->pad_clk);
30814347036SDmitry Osipenko if (ret) {
30914347036SDmitry Osipenko dev_err(phy->u_phy.dev,
31014347036SDmitry Osipenko "Failed to enable UTMI-pads clock: %d\n", ret);
31114347036SDmitry Osipenko return ret;
31214347036SDmitry Osipenko }
31314347036SDmitry Osipenko
31414347036SDmitry Osipenko ret = reset_control_assert(phy->pad_rst);
31514347036SDmitry Osipenko if (ret)
31614347036SDmitry Osipenko dev_err(phy->u_phy.dev,
31714347036SDmitry Osipenko "Failed to assert UTMI-pads reset: %d\n", ret);
31814347036SDmitry Osipenko
31914347036SDmitry Osipenko udelay(1);
32014347036SDmitry Osipenko
32114347036SDmitry Osipenko clk_disable_unprepare(phy->pad_clk);
32214347036SDmitry Osipenko
32314347036SDmitry Osipenko return ret;
32494ae9843SFelipe Balbi }
32594ae9843SFelipe Balbi
utmip_pad_power_on(struct tegra_usb_phy * phy)326545592e8SDmitry Osipenko static int utmip_pad_power_on(struct tegra_usb_phy *phy)
32794ae9843SFelipe Balbi {
328e497a24dSTuomas Tynkkynen struct tegra_utmip_config *config = phy->config;
329545592e8SDmitry Osipenko void __iomem *base = phy->pad_regs;
33001d6ea31SDmitry Osipenko u32 val;
331545592e8SDmitry Osipenko int err;
33294ae9843SFelipe Balbi
333545592e8SDmitry Osipenko err = clk_prepare_enable(phy->pad_clk);
334545592e8SDmitry Osipenko if (err)
335545592e8SDmitry Osipenko return err;
33694ae9843SFelipe Balbi
337f1f0c751SDmitry Osipenko spin_lock(&utmip_pad_lock);
33894ae9843SFelipe Balbi
33994ae9843SFelipe Balbi if (utmip_pad_count++ == 0) {
340b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_BIAS_CFG0);
34194ae9843SFelipe Balbi val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
342e497a24dSTuomas Tynkkynen
343e497a24dSTuomas Tynkkynen if (phy->soc_config->requires_extra_tuning_parameters) {
344e497a24dSTuomas Tynkkynen val &= ~(UTMIP_HSSQUELCH_LEVEL(~0) |
345e497a24dSTuomas Tynkkynen UTMIP_HSDISCON_LEVEL(~0) |
346e497a24dSTuomas Tynkkynen UTMIP_HSDISCON_LEVEL_MSB(~0));
347e497a24dSTuomas Tynkkynen
348e497a24dSTuomas Tynkkynen val |= UTMIP_HSSQUELCH_LEVEL(config->hssquelch_level);
349e497a24dSTuomas Tynkkynen val |= UTMIP_HSDISCON_LEVEL(config->hsdiscon_level);
350e497a24dSTuomas Tynkkynen val |= UTMIP_HSDISCON_LEVEL_MSB(config->hsdiscon_level);
351e497a24dSTuomas Tynkkynen }
352b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_BIAS_CFG0);
35394ae9843SFelipe Balbi }
35494ae9843SFelipe Balbi
35535192007SDmitry Osipenko if (phy->pad_wakeup) {
35635192007SDmitry Osipenko phy->pad_wakeup = false;
35735192007SDmitry Osipenko utmip_pad_count--;
35835192007SDmitry Osipenko }
35935192007SDmitry Osipenko
360f1f0c751SDmitry Osipenko spin_unlock(&utmip_pad_lock);
36194ae9843SFelipe Balbi
36294ae9843SFelipe Balbi clk_disable_unprepare(phy->pad_clk);
363545592e8SDmitry Osipenko
364545592e8SDmitry Osipenko return 0;
36594ae9843SFelipe Balbi }
36694ae9843SFelipe Balbi
utmip_pad_power_off(struct tegra_usb_phy * phy)36794ae9843SFelipe Balbi static int utmip_pad_power_off(struct tegra_usb_phy *phy)
36894ae9843SFelipe Balbi {
36994ae9843SFelipe Balbi void __iomem *base = phy->pad_regs;
37001d6ea31SDmitry Osipenko u32 val;
37192bd2ef2SDmitry Osipenko int ret;
37292bd2ef2SDmitry Osipenko
37392bd2ef2SDmitry Osipenko ret = clk_prepare_enable(phy->pad_clk);
37492bd2ef2SDmitry Osipenko if (ret)
37592bd2ef2SDmitry Osipenko return ret;
37692bd2ef2SDmitry Osipenko
377f1f0c751SDmitry Osipenko spin_lock(&utmip_pad_lock);
37894ae9843SFelipe Balbi
37994ae9843SFelipe Balbi if (!utmip_pad_count) {
380f59cd940SDmitry Osipenko dev_err(phy->u_phy.dev, "UTMIP pad already powered off\n");
38192bd2ef2SDmitry Osipenko ret = -EINVAL;
38292bd2ef2SDmitry Osipenko goto ulock;
38394ae9843SFelipe Balbi }
38494ae9843SFelipe Balbi
38535192007SDmitry Osipenko /*
38635192007SDmitry Osipenko * In accordance to TRM, OTG and Bias pad circuits could be turned off
38735192007SDmitry Osipenko * to save power if wake is enabled, but the VBUS-change detection
38835192007SDmitry Osipenko * method is board-specific and these circuits may need to be enabled
38935192007SDmitry Osipenko * to generate wakeup event, hence we will just keep them both enabled.
39035192007SDmitry Osipenko */
39135192007SDmitry Osipenko if (phy->wakeup_enabled) {
39235192007SDmitry Osipenko phy->pad_wakeup = true;
39335192007SDmitry Osipenko utmip_pad_count++;
39435192007SDmitry Osipenko }
39535192007SDmitry Osipenko
39694ae9843SFelipe Balbi if (--utmip_pad_count == 0) {
397b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_BIAS_CFG0);
39894ae9843SFelipe Balbi val |= UTMIP_OTGPD | UTMIP_BIASPD;
399b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_BIAS_CFG0);
40094ae9843SFelipe Balbi }
40192bd2ef2SDmitry Osipenko ulock:
402f1f0c751SDmitry Osipenko spin_unlock(&utmip_pad_lock);
40394ae9843SFelipe Balbi
40494ae9843SFelipe Balbi clk_disable_unprepare(phy->pad_clk);
40594ae9843SFelipe Balbi
40692bd2ef2SDmitry Osipenko return ret;
40794ae9843SFelipe Balbi }
40894ae9843SFelipe Balbi
utmi_wait_register(void __iomem * reg,u32 mask,u32 result)40994ae9843SFelipe Balbi static int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
41094ae9843SFelipe Balbi {
41143bcf64eSDmitry Osipenko u32 tmp;
41243bcf64eSDmitry Osipenko
413b07e5f86SDmitry Osipenko return readl_relaxed_poll_timeout(reg, tmp, (tmp & mask) == result,
41443bcf64eSDmitry Osipenko 2000, 6000);
41594ae9843SFelipe Balbi }
41694ae9843SFelipe Balbi
utmi_phy_clk_disable(struct tegra_usb_phy * phy)41794ae9843SFelipe Balbi static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
41894ae9843SFelipe Balbi {
41994ae9843SFelipe Balbi void __iomem *base = phy->regs;
42001d6ea31SDmitry Osipenko u32 val;
42194ae9843SFelipe Balbi
422203f44c4SJon Hunter /*
423203f44c4SJon Hunter * The USB driver may have already initiated the phy clock
424203f44c4SJon Hunter * disable so wait to see if the clock turns off and if not
425203f44c4SJon Hunter * then proceed with gating the clock.
426203f44c4SJon Hunter */
427203f44c4SJon Hunter if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) == 0)
428203f44c4SJon Hunter return;
429203f44c4SJon Hunter
43094ae9843SFelipe Balbi if (phy->is_legacy_phy) {
431b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB_SUSP_CTRL);
43294ae9843SFelipe Balbi val |= USB_SUSP_SET;
433b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB_SUSP_CTRL);
43494ae9843SFelipe Balbi
435545592e8SDmitry Osipenko usleep_range(10, 100);
43694ae9843SFelipe Balbi
437b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB_SUSP_CTRL);
43894ae9843SFelipe Balbi val &= ~USB_SUSP_SET;
439b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB_SUSP_CTRL);
440545592e8SDmitry Osipenko } else {
44191a687d8SStephen Warren set_phcd(phy, true);
442545592e8SDmitry Osipenko }
44394ae9843SFelipe Balbi
444545592e8SDmitry Osipenko if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0))
445f59cd940SDmitry Osipenko dev_err(phy->u_phy.dev,
446f59cd940SDmitry Osipenko "Timeout waiting for PHY to stabilize on disable\n");
44794ae9843SFelipe Balbi }
44894ae9843SFelipe Balbi
utmi_phy_clk_enable(struct tegra_usb_phy * phy)44994ae9843SFelipe Balbi static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
45094ae9843SFelipe Balbi {
45194ae9843SFelipe Balbi void __iomem *base = phy->regs;
45201d6ea31SDmitry Osipenko u32 val;
45394ae9843SFelipe Balbi
454203f44c4SJon Hunter /*
455203f44c4SJon Hunter * The USB driver may have already initiated the phy clock
456203f44c4SJon Hunter * enable so wait to see if the clock turns on and if not
457203f44c4SJon Hunter * then proceed with ungating the clock.
458203f44c4SJon Hunter */
459203f44c4SJon Hunter if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
460203f44c4SJon Hunter USB_PHY_CLK_VALID) == 0)
461203f44c4SJon Hunter return;
462203f44c4SJon Hunter
46394ae9843SFelipe Balbi if (phy->is_legacy_phy) {
464b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB_SUSP_CTRL);
46594ae9843SFelipe Balbi val |= USB_SUSP_CLR;
466b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB_SUSP_CTRL);
46794ae9843SFelipe Balbi
468545592e8SDmitry Osipenko usleep_range(10, 100);
46994ae9843SFelipe Balbi
470b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB_SUSP_CTRL);
47194ae9843SFelipe Balbi val &= ~USB_SUSP_CLR;
472b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB_SUSP_CTRL);
473545592e8SDmitry Osipenko } else {
47491a687d8SStephen Warren set_phcd(phy, false);
475545592e8SDmitry Osipenko }
47694ae9843SFelipe Balbi
47794ae9843SFelipe Balbi if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
47894ae9843SFelipe Balbi USB_PHY_CLK_VALID))
479f59cd940SDmitry Osipenko dev_err(phy->u_phy.dev,
480f59cd940SDmitry Osipenko "Timeout waiting for PHY to stabilize on enable\n");
48194ae9843SFelipe Balbi }
48294ae9843SFelipe Balbi
utmi_phy_power_on(struct tegra_usb_phy * phy)48394ae9843SFelipe Balbi static int utmi_phy_power_on(struct tegra_usb_phy *phy)
48494ae9843SFelipe Balbi {
48594ae9843SFelipe Balbi struct tegra_utmip_config *config = phy->config;
486545592e8SDmitry Osipenko void __iomem *base = phy->regs;
48701d6ea31SDmitry Osipenko u32 val;
488545592e8SDmitry Osipenko int err;
48994ae9843SFelipe Balbi
490b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB_SUSP_CTRL);
49194ae9843SFelipe Balbi val |= UTMIP_RESET;
492b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB_SUSP_CTRL);
49394ae9843SFelipe Balbi
49494ae9843SFelipe Balbi if (phy->is_legacy_phy) {
495b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB1_LEGACY_CTRL);
49694ae9843SFelipe Balbi val |= USB1_NO_LEGACY_MODE;
497b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB1_LEGACY_CTRL);
49894ae9843SFelipe Balbi }
49994ae9843SFelipe Balbi
500b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_TX_CFG0);
501f5833a0bSTuomas Tynkkynen val |= UTMIP_FS_PREABMLE_J;
502b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_TX_CFG0);
50394ae9843SFelipe Balbi
504b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_HSRX_CFG0);
50594ae9843SFelipe Balbi val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0));
50694ae9843SFelipe Balbi val |= UTMIP_IDLE_WAIT(config->idle_wait_delay);
50794ae9843SFelipe Balbi val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit);
508b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_HSRX_CFG0);
50994ae9843SFelipe Balbi
510b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_HSRX_CFG1);
51194ae9843SFelipe Balbi val &= ~UTMIP_HS_SYNC_START_DLY(~0);
51294ae9843SFelipe Balbi val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay);
513b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_HSRX_CFG1);
51494ae9843SFelipe Balbi
515b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_DEBOUNCE_CFG0);
51694ae9843SFelipe Balbi val &= ~UTMIP_BIAS_DEBOUNCE_A(~0);
51794ae9843SFelipe Balbi val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce);
518b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_DEBOUNCE_CFG0);
51994ae9843SFelipe Balbi
520b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_MISC_CFG0);
52194ae9843SFelipe Balbi val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
522b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_MISC_CFG0);
52394ae9843SFelipe Balbi
5243e635202STuomas Tynkkynen if (!phy->soc_config->utmi_pll_config_in_car_module) {
525b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_MISC_CFG1);
5263e635202STuomas Tynkkynen val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) |
5273e635202STuomas Tynkkynen UTMIP_PLLU_STABLE_COUNT(~0));
52894ae9843SFelipe Balbi val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
52994ae9843SFelipe Balbi UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
530b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_MISC_CFG1);
53194ae9843SFelipe Balbi
532b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_PLL_CFG1);
5333e635202STuomas Tynkkynen val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) |
5343e635202STuomas Tynkkynen UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
53594ae9843SFelipe Balbi val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
53694ae9843SFelipe Balbi UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
537b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_PLL_CFG1);
5383e635202STuomas Tynkkynen }
53994ae9843SFelipe Balbi
54035192007SDmitry Osipenko val = readl_relaxed(base + USB_SUSP_CTRL);
54135192007SDmitry Osipenko val &= ~USB_WAKE_ON_RESUME_EN;
54235192007SDmitry Osipenko writel_relaxed(val, base + USB_SUSP_CTRL);
54335192007SDmitry Osipenko
544c1baf6c5SDmitry Osipenko if (phy->mode != USB_DR_MODE_HOST) {
545b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB_SUSP_CTRL);
54694ae9843SFelipe Balbi val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
547b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB_SUSP_CTRL);
548f5833a0bSTuomas Tynkkynen
54935192007SDmitry Osipenko val = readl_relaxed(base + USB_PHY_VBUS_WAKEUP_ID);
55035192007SDmitry Osipenko val &= ~VBUS_WAKEUP_WAKEUP_EN;
551c1baf6c5SDmitry Osipenko val &= ~(ID_CHG_DET | VBUS_WAKEUP_CHG_DET);
55235192007SDmitry Osipenko writel_relaxed(val, base + USB_PHY_VBUS_WAKEUP_ID);
55335192007SDmitry Osipenko
55435192007SDmitry Osipenko val = readl_relaxed(base + USB_PHY_VBUS_SENSORS);
55535192007SDmitry Osipenko val &= ~(A_VBUS_VLD_WAKEUP_EN | A_SESS_VLD_WAKEUP_EN);
5567917e906SDmitry Osipenko val &= ~(B_SESS_VLD_WAKEUP_EN);
55735192007SDmitry Osipenko writel_relaxed(val, base + USB_PHY_VBUS_SENSORS);
55835192007SDmitry Osipenko
559b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_BAT_CHRG_CFG0);
560f5833a0bSTuomas Tynkkynen val &= ~UTMIP_PD_CHRG;
561b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_BAT_CHRG_CFG0);
562f5833a0bSTuomas Tynkkynen } else {
563b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_BAT_CHRG_CFG0);
564f5833a0bSTuomas Tynkkynen val |= UTMIP_PD_CHRG;
565b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_BAT_CHRG_CFG0);
56694ae9843SFelipe Balbi }
56794ae9843SFelipe Balbi
568545592e8SDmitry Osipenko err = utmip_pad_power_on(phy);
569545592e8SDmitry Osipenko if (err)
570545592e8SDmitry Osipenko return err;
57194ae9843SFelipe Balbi
572b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_XCVR_CFG0);
57394ae9843SFelipe Balbi val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
574f5833a0bSTuomas Tynkkynen UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_LSBIAS_SEL |
575f5833a0bSTuomas Tynkkynen UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_SETUP_MSB(~0) |
576e497a24dSTuomas Tynkkynen UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0));
577e497a24dSTuomas Tynkkynen
578e497a24dSTuomas Tynkkynen if (!config->xcvr_setup_use_fuses) {
57994ae9843SFelipe Balbi val |= UTMIP_XCVR_SETUP(config->xcvr_setup);
580f5833a0bSTuomas Tynkkynen val |= UTMIP_XCVR_SETUP_MSB(config->xcvr_setup);
581e497a24dSTuomas Tynkkynen }
58294ae9843SFelipe Balbi val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
58394ae9843SFelipe Balbi val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
584e497a24dSTuomas Tynkkynen
585e497a24dSTuomas Tynkkynen if (phy->soc_config->requires_extra_tuning_parameters) {
586e497a24dSTuomas Tynkkynen val &= ~(UTMIP_XCVR_HSSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0));
587e497a24dSTuomas Tynkkynen val |= UTMIP_XCVR_HSSLEW(config->xcvr_hsslew);
588e497a24dSTuomas Tynkkynen val |= UTMIP_XCVR_HSSLEW_MSB(config->xcvr_hsslew);
589e497a24dSTuomas Tynkkynen }
590b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_XCVR_CFG0);
59194ae9843SFelipe Balbi
592b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_XCVR_CFG1);
59394ae9843SFelipe Balbi val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
59494ae9843SFelipe Balbi UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0));
59594ae9843SFelipe Balbi val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
596b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_XCVR_CFG1);
59794ae9843SFelipe Balbi
598b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_BIAS_CFG1);
59994ae9843SFelipe Balbi val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
60094ae9843SFelipe Balbi val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
601b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_BIAS_CFG1);
60294ae9843SFelipe Balbi
603b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_SPARE_CFG0);
604e497a24dSTuomas Tynkkynen if (config->xcvr_setup_use_fuses)
60594ae9843SFelipe Balbi val |= FUSE_SETUP_SEL;
606e497a24dSTuomas Tynkkynen else
607e497a24dSTuomas Tynkkynen val &= ~FUSE_SETUP_SEL;
608b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_SPARE_CFG0);
609e497a24dSTuomas Tynkkynen
610e497a24dSTuomas Tynkkynen if (!phy->is_legacy_phy) {
611b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB_SUSP_CTRL);
61294ae9843SFelipe Balbi val |= UTMIP_PHY_ENABLE;
613b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB_SUSP_CTRL);
61494ae9843SFelipe Balbi }
61594ae9843SFelipe Balbi
616b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB_SUSP_CTRL);
61794ae9843SFelipe Balbi val &= ~UTMIP_RESET;
618b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB_SUSP_CTRL);
61994ae9843SFelipe Balbi
62094ae9843SFelipe Balbi if (phy->is_legacy_phy) {
621b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB1_LEGACY_CTRL);
62294ae9843SFelipe Balbi val &= ~USB1_VBUS_SENSE_CTL_MASK;
62394ae9843SFelipe Balbi val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD;
624b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB1_LEGACY_CTRL);
62594ae9843SFelipe Balbi
626b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB_SUSP_CTRL);
62794ae9843SFelipe Balbi val &= ~USB_SUSP_SET;
628b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB_SUSP_CTRL);
62994ae9843SFelipe Balbi }
63094ae9843SFelipe Balbi
63194ae9843SFelipe Balbi utmi_phy_clk_enable(phy);
63294ae9843SFelipe Balbi
6333e635202STuomas Tynkkynen if (phy->soc_config->requires_usbmode_setup) {
634b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB_USBMODE);
6353e635202STuomas Tynkkynen val &= ~USB_USBMODE_MASK;
6363e635202STuomas Tynkkynen if (phy->mode == USB_DR_MODE_HOST)
6373e635202STuomas Tynkkynen val |= USB_USBMODE_HOST;
6383e635202STuomas Tynkkynen else
6393e635202STuomas Tynkkynen val |= USB_USBMODE_DEVICE;
640b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB_USBMODE);
6413e635202STuomas Tynkkynen }
6423e635202STuomas Tynkkynen
64394ae9843SFelipe Balbi if (!phy->is_legacy_phy)
64491a687d8SStephen Warren set_pts(phy, 0);
64594ae9843SFelipe Balbi
64694ae9843SFelipe Balbi return 0;
64794ae9843SFelipe Balbi }
64894ae9843SFelipe Balbi
utmi_phy_power_off(struct tegra_usb_phy * phy)64994ae9843SFelipe Balbi static int utmi_phy_power_off(struct tegra_usb_phy *phy)
65094ae9843SFelipe Balbi {
65194ae9843SFelipe Balbi void __iomem *base = phy->regs;
65201d6ea31SDmitry Osipenko u32 val;
65394ae9843SFelipe Balbi
6546f8d39a8SDmitry Osipenko /*
6556f8d39a8SDmitry Osipenko * Give hardware time to settle down after VBUS disconnection,
6566f8d39a8SDmitry Osipenko * otherwise PHY will immediately wake up from suspend.
6576f8d39a8SDmitry Osipenko */
6586f8d39a8SDmitry Osipenko if (phy->wakeup_enabled && phy->mode != USB_DR_MODE_HOST)
6596f8d39a8SDmitry Osipenko readl_relaxed_poll_timeout(base + USB_PHY_VBUS_WAKEUP_ID,
6606f8d39a8SDmitry Osipenko val, !(val & VBUS_WAKEUP_STS),
6616f8d39a8SDmitry Osipenko 5000, 100000);
6626f8d39a8SDmitry Osipenko
66394ae9843SFelipe Balbi utmi_phy_clk_disable(phy);
66494ae9843SFelipe Balbi
66535192007SDmitry Osipenko /* PHY won't resume if reset is asserted */
66635192007SDmitry Osipenko if (!phy->wakeup_enabled) {
667b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB_SUSP_CTRL);
66894ae9843SFelipe Balbi val |= UTMIP_RESET;
669b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB_SUSP_CTRL);
67035192007SDmitry Osipenko }
67194ae9843SFelipe Balbi
672b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_BAT_CHRG_CFG0);
67394ae9843SFelipe Balbi val |= UTMIP_PD_CHRG;
674b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_BAT_CHRG_CFG0);
67594ae9843SFelipe Balbi
67635192007SDmitry Osipenko if (!phy->wakeup_enabled) {
677b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_XCVR_CFG0);
67894ae9843SFelipe Balbi val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
67994ae9843SFelipe Balbi UTMIP_FORCE_PDZI_POWERDOWN;
680b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_XCVR_CFG0);
68135192007SDmitry Osipenko }
68294ae9843SFelipe Balbi
683b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_XCVR_CFG1);
68494ae9843SFelipe Balbi val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
68594ae9843SFelipe Balbi UTMIP_FORCE_PDDR_POWERDOWN;
686b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_XCVR_CFG1);
68794ae9843SFelipe Balbi
68835192007SDmitry Osipenko if (phy->wakeup_enabled) {
68935192007SDmitry Osipenko val = readl_relaxed(base + USB_SUSP_CTRL);
69035192007SDmitry Osipenko val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
69135192007SDmitry Osipenko val |= USB_WAKEUP_DEBOUNCE_COUNT(5);
69235192007SDmitry Osipenko val |= USB_WAKE_ON_RESUME_EN;
69335192007SDmitry Osipenko writel_relaxed(val, base + USB_SUSP_CTRL);
69435192007SDmitry Osipenko
69535192007SDmitry Osipenko /*
69635192007SDmitry Osipenko * Ask VBUS sensor to generate wake event once cable is
69735192007SDmitry Osipenko * connected.
69835192007SDmitry Osipenko */
699c1baf6c5SDmitry Osipenko if (phy->mode != USB_DR_MODE_HOST) {
70035192007SDmitry Osipenko val = readl_relaxed(base + USB_PHY_VBUS_WAKEUP_ID);
70135192007SDmitry Osipenko val |= VBUS_WAKEUP_WAKEUP_EN;
702c1baf6c5SDmitry Osipenko val &= ~(ID_CHG_DET | VBUS_WAKEUP_CHG_DET);
70335192007SDmitry Osipenko writel_relaxed(val, base + USB_PHY_VBUS_WAKEUP_ID);
70435192007SDmitry Osipenko
70535192007SDmitry Osipenko val = readl_relaxed(base + USB_PHY_VBUS_SENSORS);
70635192007SDmitry Osipenko val |= A_VBUS_VLD_WAKEUP_EN;
70735192007SDmitry Osipenko writel_relaxed(val, base + USB_PHY_VBUS_SENSORS);
70835192007SDmitry Osipenko }
70935192007SDmitry Osipenko }
71035192007SDmitry Osipenko
71194ae9843SFelipe Balbi return utmip_pad_power_off(phy);
71294ae9843SFelipe Balbi }
71394ae9843SFelipe Balbi
utmi_phy_preresume(struct tegra_usb_phy * phy)71494ae9843SFelipe Balbi static void utmi_phy_preresume(struct tegra_usb_phy *phy)
71594ae9843SFelipe Balbi {
71694ae9843SFelipe Balbi void __iomem *base = phy->regs;
71701d6ea31SDmitry Osipenko u32 val;
71894ae9843SFelipe Balbi
719b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_TX_CFG0);
72094ae9843SFelipe Balbi val |= UTMIP_HS_DISCON_DISABLE;
721b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_TX_CFG0);
72294ae9843SFelipe Balbi }
72394ae9843SFelipe Balbi
utmi_phy_postresume(struct tegra_usb_phy * phy)72494ae9843SFelipe Balbi static void utmi_phy_postresume(struct tegra_usb_phy *phy)
72594ae9843SFelipe Balbi {
72694ae9843SFelipe Balbi void __iomem *base = phy->regs;
72701d6ea31SDmitry Osipenko u32 val;
72894ae9843SFelipe Balbi
729b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_TX_CFG0);
73094ae9843SFelipe Balbi val &= ~UTMIP_HS_DISCON_DISABLE;
731b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_TX_CFG0);
73294ae9843SFelipe Balbi }
73394ae9843SFelipe Balbi
utmi_phy_restore_start(struct tegra_usb_phy * phy,enum tegra_usb_phy_port_speed port_speed)73494ae9843SFelipe Balbi static void utmi_phy_restore_start(struct tegra_usb_phy *phy,
73594ae9843SFelipe Balbi enum tegra_usb_phy_port_speed port_speed)
73694ae9843SFelipe Balbi {
73794ae9843SFelipe Balbi void __iomem *base = phy->regs;
73801d6ea31SDmitry Osipenko u32 val;
73994ae9843SFelipe Balbi
740b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_MISC_CFG0);
74194ae9843SFelipe Balbi val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
74294ae9843SFelipe Balbi if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
74394ae9843SFelipe Balbi val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
74494ae9843SFelipe Balbi else
74594ae9843SFelipe Balbi val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
746b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_MISC_CFG0);
747545592e8SDmitry Osipenko usleep_range(1, 10);
74894ae9843SFelipe Balbi
749b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_MISC_CFG0);
75094ae9843SFelipe Balbi val |= UTMIP_DPDM_OBSERVE;
751b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_MISC_CFG0);
752545592e8SDmitry Osipenko usleep_range(10, 100);
75394ae9843SFelipe Balbi }
75494ae9843SFelipe Balbi
utmi_phy_restore_end(struct tegra_usb_phy * phy)75594ae9843SFelipe Balbi static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
75694ae9843SFelipe Balbi {
75794ae9843SFelipe Balbi void __iomem *base = phy->regs;
75801d6ea31SDmitry Osipenko u32 val;
75994ae9843SFelipe Balbi
760b07e5f86SDmitry Osipenko val = readl_relaxed(base + UTMIP_MISC_CFG0);
76194ae9843SFelipe Balbi val &= ~UTMIP_DPDM_OBSERVE;
762b07e5f86SDmitry Osipenko writel_relaxed(val, base + UTMIP_MISC_CFG0);
763545592e8SDmitry Osipenko usleep_range(10, 100);
76494ae9843SFelipe Balbi }
76594ae9843SFelipe Balbi
ulpi_phy_power_on(struct tegra_usb_phy * phy)76694ae9843SFelipe Balbi static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
76794ae9843SFelipe Balbi {
76894ae9843SFelipe Balbi void __iomem *base = phy->regs;
76901d6ea31SDmitry Osipenko u32 val;
770545592e8SDmitry Osipenko int err;
77194ae9843SFelipe Balbi
77206e60e50SDmitry Osipenko gpiod_set_value_cansleep(phy->reset_gpio, 1);
77394ae9843SFelipe Balbi
774545592e8SDmitry Osipenko err = clk_prepare_enable(phy->clk);
775545592e8SDmitry Osipenko if (err)
776545592e8SDmitry Osipenko return err;
777545592e8SDmitry Osipenko
778545592e8SDmitry Osipenko usleep_range(5000, 6000);
779545592e8SDmitry Osipenko
78006e60e50SDmitry Osipenko gpiod_set_value_cansleep(phy->reset_gpio, 0);
781545592e8SDmitry Osipenko
782545592e8SDmitry Osipenko usleep_range(1000, 2000);
78394ae9843SFelipe Balbi
784b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB_SUSP_CTRL);
78594ae9843SFelipe Balbi val |= UHSIC_RESET;
786b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB_SUSP_CTRL);
78794ae9843SFelipe Balbi
788b07e5f86SDmitry Osipenko val = readl_relaxed(base + ULPI_TIMING_CTRL_0);
78994ae9843SFelipe Balbi val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
790b07e5f86SDmitry Osipenko writel_relaxed(val, base + ULPI_TIMING_CTRL_0);
79194ae9843SFelipe Balbi
792b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB_SUSP_CTRL);
79394ae9843SFelipe Balbi val |= ULPI_PHY_ENABLE;
794b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB_SUSP_CTRL);
79594ae9843SFelipe Balbi
79694ae9843SFelipe Balbi val = 0;
797b07e5f86SDmitry Osipenko writel_relaxed(val, base + ULPI_TIMING_CTRL_1);
79894ae9843SFelipe Balbi
79994ae9843SFelipe Balbi val |= ULPI_DATA_TRIMMER_SEL(4);
80094ae9843SFelipe Balbi val |= ULPI_STPDIRNXT_TRIMMER_SEL(4);
80194ae9843SFelipe Balbi val |= ULPI_DIR_TRIMMER_SEL(4);
802b07e5f86SDmitry Osipenko writel_relaxed(val, base + ULPI_TIMING_CTRL_1);
803545592e8SDmitry Osipenko usleep_range(10, 100);
80494ae9843SFelipe Balbi
80594ae9843SFelipe Balbi val |= ULPI_DATA_TRIMMER_LOAD;
80694ae9843SFelipe Balbi val |= ULPI_STPDIRNXT_TRIMMER_LOAD;
80794ae9843SFelipe Balbi val |= ULPI_DIR_TRIMMER_LOAD;
808b07e5f86SDmitry Osipenko writel_relaxed(val, base + ULPI_TIMING_CTRL_1);
80994ae9843SFelipe Balbi
81094ae9843SFelipe Balbi /* Fix VbusInvalid due to floating VBUS */
811545592e8SDmitry Osipenko err = usb_phy_io_write(phy->ulpi, 0x40, 0x08);
812545592e8SDmitry Osipenko if (err) {
813545592e8SDmitry Osipenko dev_err(phy->u_phy.dev, "ULPI write failed: %d\n", err);
814545592e8SDmitry Osipenko goto disable_clk;
81594ae9843SFelipe Balbi }
81694ae9843SFelipe Balbi
817545592e8SDmitry Osipenko err = usb_phy_io_write(phy->ulpi, 0x80, 0x0B);
818545592e8SDmitry Osipenko if (err) {
819545592e8SDmitry Osipenko dev_err(phy->u_phy.dev, "ULPI write failed: %d\n", err);
820545592e8SDmitry Osipenko goto disable_clk;
82194ae9843SFelipe Balbi }
82294ae9843SFelipe Balbi
823b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB_SUSP_CTRL);
82494ae9843SFelipe Balbi val |= USB_SUSP_CLR;
825b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB_SUSP_CTRL);
826545592e8SDmitry Osipenko usleep_range(100, 1000);
82794ae9843SFelipe Balbi
828b07e5f86SDmitry Osipenko val = readl_relaxed(base + USB_SUSP_CTRL);
82994ae9843SFelipe Balbi val &= ~USB_SUSP_CLR;
830b07e5f86SDmitry Osipenko writel_relaxed(val, base + USB_SUSP_CTRL);
83194ae9843SFelipe Balbi
83294ae9843SFelipe Balbi return 0;
833545592e8SDmitry Osipenko
834545592e8SDmitry Osipenko disable_clk:
835545592e8SDmitry Osipenko clk_disable_unprepare(phy->clk);
836545592e8SDmitry Osipenko
837545592e8SDmitry Osipenko return err;
83894ae9843SFelipe Balbi }
83994ae9843SFelipe Balbi
ulpi_phy_power_off(struct tegra_usb_phy * phy)84094ae9843SFelipe Balbi static int ulpi_phy_power_off(struct tegra_usb_phy *phy)
84194ae9843SFelipe Balbi {
84206e60e50SDmitry Osipenko gpiod_set_value_cansleep(phy->reset_gpio, 1);
84328d190acSDmitry Osipenko usleep_range(5000, 6000);
84428d190acSDmitry Osipenko clk_disable_unprepare(phy->clk);
84528d190acSDmitry Osipenko
84635192007SDmitry Osipenko /*
84735192007SDmitry Osipenko * Wakeup currently unimplemented for ULPI, thus PHY needs to be
84835192007SDmitry Osipenko * force-resumed.
84935192007SDmitry Osipenko */
85035192007SDmitry Osipenko if (WARN_ON_ONCE(phy->wakeup_enabled)) {
85135192007SDmitry Osipenko ulpi_phy_power_on(phy);
85235192007SDmitry Osipenko return -EOPNOTSUPP;
85335192007SDmitry Osipenko }
85435192007SDmitry Osipenko
85528d190acSDmitry Osipenko return 0;
85694ae9843SFelipe Balbi }
85794ae9843SFelipe Balbi
tegra_usb_phy_power_on(struct tegra_usb_phy * phy)85894ae9843SFelipe Balbi static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
85994ae9843SFelipe Balbi {
86018bd8bffSDmitry Osipenko int err;
86118bd8bffSDmitry Osipenko
86218bd8bffSDmitry Osipenko if (phy->powered_on)
86318bd8bffSDmitry Osipenko return 0;
86418bd8bffSDmitry Osipenko
86594ae9843SFelipe Balbi if (phy->is_ulpi_phy)
86618bd8bffSDmitry Osipenko err = ulpi_phy_power_on(phy);
86794ae9843SFelipe Balbi else
86818bd8bffSDmitry Osipenko err = utmi_phy_power_on(phy);
86918bd8bffSDmitry Osipenko if (err)
87018bd8bffSDmitry Osipenko return err;
87118bd8bffSDmitry Osipenko
87218bd8bffSDmitry Osipenko phy->powered_on = true;
87318bd8bffSDmitry Osipenko
874b100402eSDmitry Osipenko /* Let PHY settle down */
875b100402eSDmitry Osipenko usleep_range(2000, 2500);
876b100402eSDmitry Osipenko
87718bd8bffSDmitry Osipenko return 0;
87894ae9843SFelipe Balbi }
87994ae9843SFelipe Balbi
tegra_usb_phy_power_off(struct tegra_usb_phy * phy)88094ae9843SFelipe Balbi static int tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
88194ae9843SFelipe Balbi {
88218bd8bffSDmitry Osipenko int err;
88318bd8bffSDmitry Osipenko
88418bd8bffSDmitry Osipenko if (!phy->powered_on)
88518bd8bffSDmitry Osipenko return 0;
88618bd8bffSDmitry Osipenko
88794ae9843SFelipe Balbi if (phy->is_ulpi_phy)
88818bd8bffSDmitry Osipenko err = ulpi_phy_power_off(phy);
88994ae9843SFelipe Balbi else
89018bd8bffSDmitry Osipenko err = utmi_phy_power_off(phy);
89118bd8bffSDmitry Osipenko if (err)
89218bd8bffSDmitry Osipenko return err;
89318bd8bffSDmitry Osipenko
89418bd8bffSDmitry Osipenko phy->powered_on = false;
89518bd8bffSDmitry Osipenko
89618bd8bffSDmitry Osipenko return 0;
89794ae9843SFelipe Balbi }
89894ae9843SFelipe Balbi
tegra_usb_phy_shutdown(struct usb_phy * u_phy)8995dcdafddSDmitry Osipenko static void tegra_usb_phy_shutdown(struct usb_phy *u_phy)
9005dcdafddSDmitry Osipenko {
901545592e8SDmitry Osipenko struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy);
9025dcdafddSDmitry Osipenko
9035dcdafddSDmitry Osipenko if (WARN_ON(!phy->freq))
9045dcdafddSDmitry Osipenko return;
9055dcdafddSDmitry Osipenko
906c1baf6c5SDmitry Osipenko usb_phy_set_wakeup(u_phy, false);
9075dcdafddSDmitry Osipenko tegra_usb_phy_power_off(phy);
9085dcdafddSDmitry Osipenko
9095dcdafddSDmitry Osipenko if (!phy->is_ulpi_phy)
9105dcdafddSDmitry Osipenko utmip_pad_close(phy);
9115dcdafddSDmitry Osipenko
9125dcdafddSDmitry Osipenko regulator_disable(phy->vbus);
9135dcdafddSDmitry Osipenko clk_disable_unprepare(phy->pll_u);
9145dcdafddSDmitry Osipenko
9155dcdafddSDmitry Osipenko phy->freq = NULL;
9165dcdafddSDmitry Osipenko }
9175dcdafddSDmitry Osipenko
tegra_usb_phy_isr(int irq,void * data)918c1baf6c5SDmitry Osipenko static irqreturn_t tegra_usb_phy_isr(int irq, void *data)
919c1baf6c5SDmitry Osipenko {
920c1baf6c5SDmitry Osipenko u32 val, int_mask = ID_CHG_DET | VBUS_WAKEUP_CHG_DET;
921c1baf6c5SDmitry Osipenko struct tegra_usb_phy *phy = data;
922c1baf6c5SDmitry Osipenko void __iomem *base = phy->regs;
923c1baf6c5SDmitry Osipenko
924c1baf6c5SDmitry Osipenko /*
925c1baf6c5SDmitry Osipenko * The PHY interrupt also wakes the USB controller driver since
926c1baf6c5SDmitry Osipenko * interrupt is shared. We don't do anything in the PHY driver,
927c1baf6c5SDmitry Osipenko * so just clear the interrupt.
928c1baf6c5SDmitry Osipenko */
929c1baf6c5SDmitry Osipenko val = readl_relaxed(base + USB_PHY_VBUS_WAKEUP_ID);
930c1baf6c5SDmitry Osipenko writel_relaxed(val, base + USB_PHY_VBUS_WAKEUP_ID);
931c1baf6c5SDmitry Osipenko
932c1baf6c5SDmitry Osipenko return val & int_mask ? IRQ_HANDLED : IRQ_NONE;
933c1baf6c5SDmitry Osipenko }
934c1baf6c5SDmitry Osipenko
tegra_usb_phy_set_wakeup(struct usb_phy * u_phy,bool enable)93535192007SDmitry Osipenko static int tegra_usb_phy_set_wakeup(struct usb_phy *u_phy, bool enable)
93635192007SDmitry Osipenko {
93735192007SDmitry Osipenko struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy);
938c1baf6c5SDmitry Osipenko void __iomem *base = phy->regs;
939c1baf6c5SDmitry Osipenko int ret = 0;
940c1baf6c5SDmitry Osipenko u32 val;
941c1baf6c5SDmitry Osipenko
942c1baf6c5SDmitry Osipenko if (phy->wakeup_enabled && phy->mode != USB_DR_MODE_HOST &&
943c1baf6c5SDmitry Osipenko phy->irq > 0) {
944c1baf6c5SDmitry Osipenko disable_irq(phy->irq);
945c1baf6c5SDmitry Osipenko
946c1baf6c5SDmitry Osipenko val = readl_relaxed(base + USB_PHY_VBUS_WAKEUP_ID);
947c1baf6c5SDmitry Osipenko val &= ~(ID_INT_EN | VBUS_WAKEUP_INT_EN);
948c1baf6c5SDmitry Osipenko writel_relaxed(val, base + USB_PHY_VBUS_WAKEUP_ID);
949c1baf6c5SDmitry Osipenko
950c1baf6c5SDmitry Osipenko enable_irq(phy->irq);
951c1baf6c5SDmitry Osipenko
952c1baf6c5SDmitry Osipenko free_irq(phy->irq, phy);
953c1baf6c5SDmitry Osipenko
954c1baf6c5SDmitry Osipenko phy->wakeup_enabled = false;
955c1baf6c5SDmitry Osipenko }
956c1baf6c5SDmitry Osipenko
957c1baf6c5SDmitry Osipenko if (enable && phy->mode != USB_DR_MODE_HOST && phy->irq > 0) {
958c1baf6c5SDmitry Osipenko ret = request_irq(phy->irq, tegra_usb_phy_isr, IRQF_SHARED,
959c1baf6c5SDmitry Osipenko dev_name(phy->u_phy.dev), phy);
960c1baf6c5SDmitry Osipenko if (!ret) {
961c1baf6c5SDmitry Osipenko disable_irq(phy->irq);
962c1baf6c5SDmitry Osipenko
963c1baf6c5SDmitry Osipenko /*
964c1baf6c5SDmitry Osipenko * USB clock will be resumed once wake event will be
965c1baf6c5SDmitry Osipenko * generated. The ID-change event requires to have
966c1baf6c5SDmitry Osipenko * interrupts enabled, otherwise it won't be generated.
967c1baf6c5SDmitry Osipenko */
968c1baf6c5SDmitry Osipenko val = readl_relaxed(base + USB_PHY_VBUS_WAKEUP_ID);
969c1baf6c5SDmitry Osipenko val |= ID_INT_EN | VBUS_WAKEUP_INT_EN;
970c1baf6c5SDmitry Osipenko writel_relaxed(val, base + USB_PHY_VBUS_WAKEUP_ID);
971c1baf6c5SDmitry Osipenko
972c1baf6c5SDmitry Osipenko enable_irq(phy->irq);
973c1baf6c5SDmitry Osipenko } else {
974c1baf6c5SDmitry Osipenko dev_err(phy->u_phy.dev,
975c1baf6c5SDmitry Osipenko "Failed to request interrupt: %d", ret);
976c1baf6c5SDmitry Osipenko enable = false;
977c1baf6c5SDmitry Osipenko }
978c1baf6c5SDmitry Osipenko }
97935192007SDmitry Osipenko
98035192007SDmitry Osipenko phy->wakeup_enabled = enable;
98135192007SDmitry Osipenko
982c1baf6c5SDmitry Osipenko return ret;
98335192007SDmitry Osipenko }
98435192007SDmitry Osipenko
tegra_usb_phy_set_suspend(struct usb_phy * u_phy,int suspend)985545592e8SDmitry Osipenko static int tegra_usb_phy_set_suspend(struct usb_phy *u_phy, int suspend)
98694ae9843SFelipe Balbi {
987545592e8SDmitry Osipenko struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy);
988c1baf6c5SDmitry Osipenko int ret;
9895dcdafddSDmitry Osipenko
9905dcdafddSDmitry Osipenko if (WARN_ON(!phy->freq))
9915dcdafddSDmitry Osipenko return -EINVAL;
9925dcdafddSDmitry Osipenko
993c1baf6c5SDmitry Osipenko /*
994c1baf6c5SDmitry Osipenko * PHY is sharing IRQ with the CI driver, hence here we either
995c1baf6c5SDmitry Osipenko * disable interrupt for both PHY and CI or for CI only. The
996c1baf6c5SDmitry Osipenko * interrupt needs to be disabled while hardware is reprogrammed
997c1baf6c5SDmitry Osipenko * because interrupt touches the programmed registers, and thus,
998c1baf6c5SDmitry Osipenko * there could be a race condition.
999c1baf6c5SDmitry Osipenko */
1000c1baf6c5SDmitry Osipenko if (phy->irq > 0)
1001c1baf6c5SDmitry Osipenko disable_irq(phy->irq);
1002c1baf6c5SDmitry Osipenko
100394ae9843SFelipe Balbi if (suspend)
1004c1baf6c5SDmitry Osipenko ret = tegra_usb_phy_power_off(phy);
100594ae9843SFelipe Balbi else
1006c1baf6c5SDmitry Osipenko ret = tegra_usb_phy_power_on(phy);
1007c1baf6c5SDmitry Osipenko
1008c1baf6c5SDmitry Osipenko if (phy->irq > 0)
1009c1baf6c5SDmitry Osipenko enable_irq(phy->irq);
1010c1baf6c5SDmitry Osipenko
1011c1baf6c5SDmitry Osipenko return ret;
1012c1baf6c5SDmitry Osipenko }
1013c1baf6c5SDmitry Osipenko
tegra_usb_phy_configure_pmc(struct tegra_usb_phy * phy)1014c1baf6c5SDmitry Osipenko static int tegra_usb_phy_configure_pmc(struct tegra_usb_phy *phy)
1015c1baf6c5SDmitry Osipenko {
1016c1baf6c5SDmitry Osipenko int err, val = 0;
1017c1baf6c5SDmitry Osipenko
1018c1baf6c5SDmitry Osipenko /* older device-trees don't have PMC regmap */
1019c1baf6c5SDmitry Osipenko if (!phy->pmc_regmap)
1020c1baf6c5SDmitry Osipenko return 0;
1021c1baf6c5SDmitry Osipenko
1022c1baf6c5SDmitry Osipenko /*
1023c1baf6c5SDmitry Osipenko * Tegra20 has a different layout of PMC USB register bits and AO is
1024c1baf6c5SDmitry Osipenko * enabled by default after system reset on Tegra20, so assume nothing
1025c1baf6c5SDmitry Osipenko * to do on Tegra20.
1026c1baf6c5SDmitry Osipenko */
1027c1baf6c5SDmitry Osipenko if (!phy->soc_config->requires_pmc_ao_power_up)
1028c1baf6c5SDmitry Osipenko return 0;
1029c1baf6c5SDmitry Osipenko
1030c1baf6c5SDmitry Osipenko /* enable VBUS wake-up detector */
1031c1baf6c5SDmitry Osipenko if (phy->mode != USB_DR_MODE_HOST)
1032c1baf6c5SDmitry Osipenko val |= VBUS_WAKEUP_PD_P0 << phy->instance * 4;
1033c1baf6c5SDmitry Osipenko
1034c1baf6c5SDmitry Osipenko /* enable ID-pin ACC detector for OTG mode switching */
1035c1baf6c5SDmitry Osipenko if (phy->mode == USB_DR_MODE_OTG)
1036c1baf6c5SDmitry Osipenko val |= ID_PD_P0 << phy->instance * 4;
1037c1baf6c5SDmitry Osipenko
1038c1baf6c5SDmitry Osipenko /* disable detectors to reset them */
1039c1baf6c5SDmitry Osipenko err = regmap_set_bits(phy->pmc_regmap, PMC_USB_AO, val);
1040c1baf6c5SDmitry Osipenko if (err) {
1041c1baf6c5SDmitry Osipenko dev_err(phy->u_phy.dev, "Failed to disable PMC AO: %d\n", err);
1042c1baf6c5SDmitry Osipenko return err;
1043c1baf6c5SDmitry Osipenko }
1044c1baf6c5SDmitry Osipenko
1045c1baf6c5SDmitry Osipenko usleep_range(10, 100);
1046c1baf6c5SDmitry Osipenko
1047c1baf6c5SDmitry Osipenko /* enable detectors */
1048c1baf6c5SDmitry Osipenko err = regmap_clear_bits(phy->pmc_regmap, PMC_USB_AO, val);
1049c1baf6c5SDmitry Osipenko if (err) {
1050c1baf6c5SDmitry Osipenko dev_err(phy->u_phy.dev, "Failed to enable PMC AO: %d\n", err);
1051c1baf6c5SDmitry Osipenko return err;
1052c1baf6c5SDmitry Osipenko }
1053c1baf6c5SDmitry Osipenko
1054c1baf6c5SDmitry Osipenko /* detectors starts to work after 10ms */
1055c1baf6c5SDmitry Osipenko usleep_range(10000, 15000);
1056c1baf6c5SDmitry Osipenko
1057c1baf6c5SDmitry Osipenko return 0;
105894ae9843SFelipe Balbi }
105994ae9843SFelipe Balbi
tegra_usb_phy_init(struct usb_phy * u_phy)10605dcdafddSDmitry Osipenko static int tegra_usb_phy_init(struct usb_phy *u_phy)
10612d22b42dSVenu Byravarasu {
1062545592e8SDmitry Osipenko struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy);
106394ae9843SFelipe Balbi unsigned long parent_rate;
1064545592e8SDmitry Osipenko unsigned int i;
106594ae9843SFelipe Balbi int err;
106694ae9843SFelipe Balbi
10675dcdafddSDmitry Osipenko if (WARN_ON(phy->freq))
10685dcdafddSDmitry Osipenko return 0;
10692d22b42dSVenu Byravarasu
10702d22b42dSVenu Byravarasu err = clk_prepare_enable(phy->pll_u);
10712d22b42dSVenu Byravarasu if (err)
10722d22b42dSVenu Byravarasu return err;
107394ae9843SFelipe Balbi
107494ae9843SFelipe Balbi parent_rate = clk_get_rate(clk_get_parent(phy->pll_u));
107594ae9843SFelipe Balbi for (i = 0; i < ARRAY_SIZE(tegra_freq_table); i++) {
107694ae9843SFelipe Balbi if (tegra_freq_table[i].freq == parent_rate) {
107794ae9843SFelipe Balbi phy->freq = &tegra_freq_table[i];
107894ae9843SFelipe Balbi break;
107994ae9843SFelipe Balbi }
108094ae9843SFelipe Balbi }
108194ae9843SFelipe Balbi if (!phy->freq) {
1082f59cd940SDmitry Osipenko dev_err(phy->u_phy.dev, "Invalid pll_u parent rate %ld\n",
1083f59cd940SDmitry Osipenko parent_rate);
108494ae9843SFelipe Balbi err = -EINVAL;
1085aecc5af3SDmitry Osipenko goto disable_clk;
108694ae9843SFelipe Balbi }
108794ae9843SFelipe Balbi
1088f5b8c8b6SMikko Perttunen err = regulator_enable(phy->vbus);
1089f5b8c8b6SMikko Perttunen if (err) {
1090185d0fd5STuomas Tynkkynen dev_err(phy->u_phy.dev,
10919df3adcaSDmitry Osipenko "Failed to enable USB VBUS regulator: %d\n", err);
1092aecc5af3SDmitry Osipenko goto disable_clk;
1093f5b8c8b6SMikko Perttunen }
1094f5b8c8b6SMikko Perttunen
109506e60e50SDmitry Osipenko if (!phy->is_ulpi_phy) {
10962d22b42dSVenu Byravarasu err = utmip_pad_open(phy);
1097545592e8SDmitry Osipenko if (err)
1098aecc5af3SDmitry Osipenko goto disable_vbus;
109906e60e50SDmitry Osipenko }
110094ae9843SFelipe Balbi
1101c1baf6c5SDmitry Osipenko err = tegra_usb_phy_configure_pmc(phy);
1102c1baf6c5SDmitry Osipenko if (err)
1103c1baf6c5SDmitry Osipenko goto close_phy;
1104c1baf6c5SDmitry Osipenko
11055dcdafddSDmitry Osipenko err = tegra_usb_phy_power_on(phy);
11065dcdafddSDmitry Osipenko if (err)
11075dcdafddSDmitry Osipenko goto close_phy;
11085dcdafddSDmitry Osipenko
11092d22b42dSVenu Byravarasu return 0;
111094ae9843SFelipe Balbi
11115dcdafddSDmitry Osipenko close_phy:
11125dcdafddSDmitry Osipenko if (!phy->is_ulpi_phy)
11135dcdafddSDmitry Osipenko utmip_pad_close(phy);
1114aecc5af3SDmitry Osipenko
1115aecc5af3SDmitry Osipenko disable_vbus:
1116aecc5af3SDmitry Osipenko regulator_disable(phy->vbus);
1117aecc5af3SDmitry Osipenko
1118aecc5af3SDmitry Osipenko disable_clk:
111994ae9843SFelipe Balbi clk_disable_unprepare(phy->pll_u);
11205dcdafddSDmitry Osipenko
11215dcdafddSDmitry Osipenko phy->freq = NULL;
11225dcdafddSDmitry Osipenko
11232d22b42dSVenu Byravarasu return err;
112494ae9843SFelipe Balbi }
112594ae9843SFelipe Balbi
tegra_usb_phy_preresume(struct usb_phy * u_phy)1126545592e8SDmitry Osipenko void tegra_usb_phy_preresume(struct usb_phy *u_phy)
112794ae9843SFelipe Balbi {
1128545592e8SDmitry Osipenko struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy);
112994ae9843SFelipe Balbi
113094ae9843SFelipe Balbi if (!phy->is_ulpi_phy)
113194ae9843SFelipe Balbi utmi_phy_preresume(phy);
113294ae9843SFelipe Balbi }
113394ae9843SFelipe Balbi EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume);
113494ae9843SFelipe Balbi
tegra_usb_phy_postresume(struct usb_phy * u_phy)1135545592e8SDmitry Osipenko void tegra_usb_phy_postresume(struct usb_phy *u_phy)
113694ae9843SFelipe Balbi {
1137545592e8SDmitry Osipenko struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy);
113894ae9843SFelipe Balbi
113994ae9843SFelipe Balbi if (!phy->is_ulpi_phy)
114094ae9843SFelipe Balbi utmi_phy_postresume(phy);
114194ae9843SFelipe Balbi }
114294ae9843SFelipe Balbi EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume);
114394ae9843SFelipe Balbi
tegra_ehci_phy_restore_start(struct usb_phy * u_phy,enum tegra_usb_phy_port_speed port_speed)1144545592e8SDmitry Osipenko void tegra_ehci_phy_restore_start(struct usb_phy *u_phy,
114594ae9843SFelipe Balbi enum tegra_usb_phy_port_speed port_speed)
114694ae9843SFelipe Balbi {
1147545592e8SDmitry Osipenko struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy);
114894ae9843SFelipe Balbi
114994ae9843SFelipe Balbi if (!phy->is_ulpi_phy)
115094ae9843SFelipe Balbi utmi_phy_restore_start(phy, port_speed);
115194ae9843SFelipe Balbi }
115294ae9843SFelipe Balbi EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start);
115394ae9843SFelipe Balbi
tegra_ehci_phy_restore_end(struct usb_phy * u_phy)1154545592e8SDmitry Osipenko void tegra_ehci_phy_restore_end(struct usb_phy *u_phy)
115594ae9843SFelipe Balbi {
1156545592e8SDmitry Osipenko struct tegra_usb_phy *phy = to_tegra_usb_phy(u_phy);
115794ae9843SFelipe Balbi
115894ae9843SFelipe Balbi if (!phy->is_ulpi_phy)
115994ae9843SFelipe Balbi utmi_phy_restore_end(phy);
116094ae9843SFelipe Balbi }
116194ae9843SFelipe Balbi EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end);
116294ae9843SFelipe Balbi
read_utmi_param(struct platform_device * pdev,const char * param,u8 * dest)116381d5dfe6SMikko Perttunen static int read_utmi_param(struct platform_device *pdev, const char *param,
116481d5dfe6SMikko Perttunen u8 *dest)
116581d5dfe6SMikko Perttunen {
116681d5dfe6SMikko Perttunen u32 value;
1167545592e8SDmitry Osipenko int err;
1168545592e8SDmitry Osipenko
1169545592e8SDmitry Osipenko err = of_property_read_u32(pdev->dev.of_node, param, &value);
1170545592e8SDmitry Osipenko if (err)
1171f59cd940SDmitry Osipenko dev_err(&pdev->dev,
1172f59cd940SDmitry Osipenko "Failed to read USB UTMI parameter %s: %d\n",
117381d5dfe6SMikko Perttunen param, err);
1174545592e8SDmitry Osipenko else
1175545592e8SDmitry Osipenko *dest = value;
1176545592e8SDmitry Osipenko
117781d5dfe6SMikko Perttunen return err;
117881d5dfe6SMikko Perttunen }
117981d5dfe6SMikko Perttunen
utmi_phy_probe(struct tegra_usb_phy * tegra_phy,struct platform_device * pdev)118081d5dfe6SMikko Perttunen static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy,
118181d5dfe6SMikko Perttunen struct platform_device *pdev)
118281d5dfe6SMikko Perttunen {
1183545592e8SDmitry Osipenko struct tegra_utmip_config *config;
118481d5dfe6SMikko Perttunen struct resource *res;
118581d5dfe6SMikko Perttunen int err;
118681d5dfe6SMikko Perttunen
118781d5dfe6SMikko Perttunen tegra_phy->is_ulpi_phy = false;
118881d5dfe6SMikko Perttunen
118981d5dfe6SMikko Perttunen res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
119081d5dfe6SMikko Perttunen if (!res) {
1191f59cd940SDmitry Osipenko dev_err(&pdev->dev, "Failed to get UTMI pad regs\n");
119281d5dfe6SMikko Perttunen return -ENXIO;
119381d5dfe6SMikko Perttunen }
119481d5dfe6SMikko Perttunen
1195a4a60194SDmitry Osipenko /*
1196a4a60194SDmitry Osipenko * Note that UTMI pad registers are shared by all PHYs, therefore
1197a4a60194SDmitry Osipenko * devm_platform_ioremap_resource() can't be used here.
1198a4a60194SDmitry Osipenko */
119981d5dfe6SMikko Perttunen tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start,
120081d5dfe6SMikko Perttunen resource_size(res));
1201851dd02bSChris Ruehl if (!tegra_phy->pad_regs) {
1202f59cd940SDmitry Osipenko dev_err(&pdev->dev, "Failed to remap UTMI pad regs\n");
120381d5dfe6SMikko Perttunen return -ENOMEM;
120481d5dfe6SMikko Perttunen }
120581d5dfe6SMikko Perttunen
12069ce9ec95SThierry Reding tegra_phy->config = devm_kzalloc(&pdev->dev, sizeof(*config),
12079ce9ec95SThierry Reding GFP_KERNEL);
120801ad32d5SPeter Chen if (!tegra_phy->config)
120981d5dfe6SMikko Perttunen return -ENOMEM;
121081d5dfe6SMikko Perttunen
121181d5dfe6SMikko Perttunen config = tegra_phy->config;
121281d5dfe6SMikko Perttunen
121381d5dfe6SMikko Perttunen err = read_utmi_param(pdev, "nvidia,hssync-start-delay",
121481d5dfe6SMikko Perttunen &config->hssync_start_delay);
1215545592e8SDmitry Osipenko if (err)
121681d5dfe6SMikko Perttunen return err;
121781d5dfe6SMikko Perttunen
121881d5dfe6SMikko Perttunen err = read_utmi_param(pdev, "nvidia,elastic-limit",
121981d5dfe6SMikko Perttunen &config->elastic_limit);
1220545592e8SDmitry Osipenko if (err)
122181d5dfe6SMikko Perttunen return err;
122281d5dfe6SMikko Perttunen
122381d5dfe6SMikko Perttunen err = read_utmi_param(pdev, "nvidia,idle-wait-delay",
122481d5dfe6SMikko Perttunen &config->idle_wait_delay);
1225545592e8SDmitry Osipenko if (err)
122681d5dfe6SMikko Perttunen return err;
122781d5dfe6SMikko Perttunen
122881d5dfe6SMikko Perttunen err = read_utmi_param(pdev, "nvidia,term-range-adj",
122981d5dfe6SMikko Perttunen &config->term_range_adj);
1230545592e8SDmitry Osipenko if (err)
123181d5dfe6SMikko Perttunen return err;
123281d5dfe6SMikko Perttunen
123381d5dfe6SMikko Perttunen err = read_utmi_param(pdev, "nvidia,xcvr-lsfslew",
123481d5dfe6SMikko Perttunen &config->xcvr_lsfslew);
1235545592e8SDmitry Osipenko if (err)
123681d5dfe6SMikko Perttunen return err;
123781d5dfe6SMikko Perttunen
123881d5dfe6SMikko Perttunen err = read_utmi_param(pdev, "nvidia,xcvr-lsrslew",
123981d5dfe6SMikko Perttunen &config->xcvr_lsrslew);
1240545592e8SDmitry Osipenko if (err)
124181d5dfe6SMikko Perttunen return err;
124281d5dfe6SMikko Perttunen
1243e497a24dSTuomas Tynkkynen if (tegra_phy->soc_config->requires_extra_tuning_parameters) {
1244e497a24dSTuomas Tynkkynen err = read_utmi_param(pdev, "nvidia,xcvr-hsslew",
1245e497a24dSTuomas Tynkkynen &config->xcvr_hsslew);
1246545592e8SDmitry Osipenko if (err)
1247e497a24dSTuomas Tynkkynen return err;
1248e497a24dSTuomas Tynkkynen
1249e497a24dSTuomas Tynkkynen err = read_utmi_param(pdev, "nvidia,hssquelch-level",
1250e497a24dSTuomas Tynkkynen &config->hssquelch_level);
1251545592e8SDmitry Osipenko if (err)
1252e497a24dSTuomas Tynkkynen return err;
1253e497a24dSTuomas Tynkkynen
1254e497a24dSTuomas Tynkkynen err = read_utmi_param(pdev, "nvidia,hsdiscon-level",
1255e497a24dSTuomas Tynkkynen &config->hsdiscon_level);
1256545592e8SDmitry Osipenko if (err)
1257e497a24dSTuomas Tynkkynen return err;
1258e497a24dSTuomas Tynkkynen }
1259e497a24dSTuomas Tynkkynen
1260e497a24dSTuomas Tynkkynen config->xcvr_setup_use_fuses = of_property_read_bool(
1261e497a24dSTuomas Tynkkynen pdev->dev.of_node, "nvidia,xcvr-setup-use-fuses");
1262e497a24dSTuomas Tynkkynen
1263e497a24dSTuomas Tynkkynen if (!config->xcvr_setup_use_fuses) {
1264e497a24dSTuomas Tynkkynen err = read_utmi_param(pdev, "nvidia,xcvr-setup",
1265e497a24dSTuomas Tynkkynen &config->xcvr_setup);
1266545592e8SDmitry Osipenko if (err)
1267e497a24dSTuomas Tynkkynen return err;
1268e497a24dSTuomas Tynkkynen }
1269e497a24dSTuomas Tynkkynen
127081d5dfe6SMikko Perttunen return 0;
127181d5dfe6SMikko Perttunen }
127281d5dfe6SMikko Perttunen
tegra_usb_phy_put_pmc_device(void * dev)1273c1baf6c5SDmitry Osipenko static void tegra_usb_phy_put_pmc_device(void *dev)
1274c1baf6c5SDmitry Osipenko {
1275c1baf6c5SDmitry Osipenko put_device(dev);
1276c1baf6c5SDmitry Osipenko }
1277c1baf6c5SDmitry Osipenko
tegra_usb_phy_parse_pmc(struct device * dev,struct tegra_usb_phy * phy)1278c1baf6c5SDmitry Osipenko static int tegra_usb_phy_parse_pmc(struct device *dev,
1279c1baf6c5SDmitry Osipenko struct tegra_usb_phy *phy)
1280c1baf6c5SDmitry Osipenko {
1281c1baf6c5SDmitry Osipenko struct platform_device *pmc_pdev;
1282c1baf6c5SDmitry Osipenko struct of_phandle_args args;
1283c1baf6c5SDmitry Osipenko int err;
1284c1baf6c5SDmitry Osipenko
1285c1baf6c5SDmitry Osipenko err = of_parse_phandle_with_fixed_args(dev->of_node, "nvidia,pmc",
1286c1baf6c5SDmitry Osipenko 1, 0, &args);
1287c1baf6c5SDmitry Osipenko if (err) {
1288c1baf6c5SDmitry Osipenko if (err != -ENOENT)
1289c1baf6c5SDmitry Osipenko return err;
1290c1baf6c5SDmitry Osipenko
1291c1baf6c5SDmitry Osipenko dev_warn_once(dev, "nvidia,pmc is missing, please update your device-tree\n");
1292c1baf6c5SDmitry Osipenko return 0;
1293c1baf6c5SDmitry Osipenko }
1294c1baf6c5SDmitry Osipenko
1295c1baf6c5SDmitry Osipenko pmc_pdev = of_find_device_by_node(args.np);
1296c1baf6c5SDmitry Osipenko of_node_put(args.np);
1297c1baf6c5SDmitry Osipenko if (!pmc_pdev)
1298c1baf6c5SDmitry Osipenko return -ENODEV;
1299c1baf6c5SDmitry Osipenko
1300c1baf6c5SDmitry Osipenko err = devm_add_action_or_reset(dev, tegra_usb_phy_put_pmc_device,
1301c1baf6c5SDmitry Osipenko &pmc_pdev->dev);
1302c1baf6c5SDmitry Osipenko if (err)
1303c1baf6c5SDmitry Osipenko return err;
1304c1baf6c5SDmitry Osipenko
1305c1baf6c5SDmitry Osipenko if (!platform_get_drvdata(pmc_pdev))
1306c1baf6c5SDmitry Osipenko return -EPROBE_DEFER;
1307c1baf6c5SDmitry Osipenko
1308c1baf6c5SDmitry Osipenko phy->pmc_regmap = dev_get_regmap(&pmc_pdev->dev, "usb_sleepwalk");
1309c1baf6c5SDmitry Osipenko if (!phy->pmc_regmap)
1310c1baf6c5SDmitry Osipenko return -EINVAL;
1311c1baf6c5SDmitry Osipenko
1312c1baf6c5SDmitry Osipenko phy->instance = args.args[0];
1313c1baf6c5SDmitry Osipenko
1314c1baf6c5SDmitry Osipenko return 0;
1315c1baf6c5SDmitry Osipenko }
1316c1baf6c5SDmitry Osipenko
13173e635202STuomas Tynkkynen static const struct tegra_phy_soc_config tegra20_soc_config = {
13183e635202STuomas Tynkkynen .utmi_pll_config_in_car_module = false,
13193e635202STuomas Tynkkynen .has_hostpc = false,
13203e635202STuomas Tynkkynen .requires_usbmode_setup = false,
13213e635202STuomas Tynkkynen .requires_extra_tuning_parameters = false,
1322c1baf6c5SDmitry Osipenko .requires_pmc_ao_power_up = false,
13233e635202STuomas Tynkkynen };
13243e635202STuomas Tynkkynen
13253e635202STuomas Tynkkynen static const struct tegra_phy_soc_config tegra30_soc_config = {
13263e635202STuomas Tynkkynen .utmi_pll_config_in_car_module = true,
13273e635202STuomas Tynkkynen .has_hostpc = true,
13283e635202STuomas Tynkkynen .requires_usbmode_setup = true,
13293e635202STuomas Tynkkynen .requires_extra_tuning_parameters = true,
1330c1baf6c5SDmitry Osipenko .requires_pmc_ao_power_up = true,
13313e635202STuomas Tynkkynen };
13323e635202STuomas Tynkkynen
13330f0520baSJingoo Han static const struct of_device_id tegra_usb_phy_id_table[] = {
13343e635202STuomas Tynkkynen { .compatible = "nvidia,tegra30-usb-phy", .data = &tegra30_soc_config },
13353e635202STuomas Tynkkynen { .compatible = "nvidia,tegra20-usb-phy", .data = &tegra20_soc_config },
13363e635202STuomas Tynkkynen { },
13373e635202STuomas Tynkkynen };
13383e635202STuomas Tynkkynen MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table);
13393e635202STuomas Tynkkynen
tegra_usb_phy_probe(struct platform_device * pdev)13402d22b42dSVenu Byravarasu static int tegra_usb_phy_probe(struct platform_device *pdev)
13412d22b42dSVenu Byravarasu {
13422d22b42dSVenu Byravarasu struct device_node *np = pdev->dev.of_node;
1343545592e8SDmitry Osipenko struct tegra_usb_phy *tegra_phy;
13449fdb07f7STuomas Tynkkynen enum usb_phy_interface phy_type;
1345545592e8SDmitry Osipenko struct reset_control *reset;
134606e60e50SDmitry Osipenko struct gpio_desc *gpiod;
1347545592e8SDmitry Osipenko struct resource *res;
134887541747SDmitry Osipenko struct usb_phy *phy;
13492d22b42dSVenu Byravarasu int err;
13502d22b42dSVenu Byravarasu
13512d22b42dSVenu Byravarasu tegra_phy = devm_kzalloc(&pdev->dev, sizeof(*tegra_phy), GFP_KERNEL);
135201ad32d5SPeter Chen if (!tegra_phy)
13532d22b42dSVenu Byravarasu return -ENOMEM;
13542d22b42dSVenu Byravarasu
1355545592e8SDmitry Osipenko tegra_phy->soc_config = of_device_get_match_data(&pdev->dev);
1356c1baf6c5SDmitry Osipenko tegra_phy->irq = platform_get_irq_optional(pdev, 0);
13573e635202STuomas Tynkkynen
13582d22b42dSVenu Byravarasu res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
13592d22b42dSVenu Byravarasu if (!res) {
13602d22b42dSVenu Byravarasu dev_err(&pdev->dev, "Failed to get I/O memory\n");
13612d22b42dSVenu Byravarasu return -ENXIO;
13622d22b42dSVenu Byravarasu }
13632d22b42dSVenu Byravarasu
1364a4a60194SDmitry Osipenko /*
1365a4a60194SDmitry Osipenko * Note that PHY and USB controller are using shared registers,
1366a4a60194SDmitry Osipenko * therefore devm_platform_ioremap_resource() can't be used here.
1367a4a60194SDmitry Osipenko */
13682d22b42dSVenu Byravarasu tegra_phy->regs = devm_ioremap(&pdev->dev, res->start,
13692d22b42dSVenu Byravarasu resource_size(res));
13702d22b42dSVenu Byravarasu if (!tegra_phy->regs) {
13712d22b42dSVenu Byravarasu dev_err(&pdev->dev, "Failed to remap I/O memory\n");
13722d22b42dSVenu Byravarasu return -ENOMEM;
13732d22b42dSVenu Byravarasu }
13742d22b42dSVenu Byravarasu
13752d22b42dSVenu Byravarasu tegra_phy->is_legacy_phy =
13762d22b42dSVenu Byravarasu of_property_read_bool(np, "nvidia,has-legacy-mode");
13772d22b42dSVenu Byravarasu
1378a3927e1aSRob Herring if (of_property_present(np, "dr_mode"))
137906e7114fSHeikki Krogerus tegra_phy->mode = usb_get_dr_mode(&pdev->dev);
13802d22b42dSVenu Byravarasu else
13816558d7edSTuomas Tynkkynen tegra_phy->mode = USB_DR_MODE_HOST;
13826558d7edSTuomas Tynkkynen
13836558d7edSTuomas Tynkkynen if (tegra_phy->mode == USB_DR_MODE_UNKNOWN) {
13846558d7edSTuomas Tynkkynen dev_err(&pdev->dev, "dr_mode is invalid\n");
13856558d7edSTuomas Tynkkynen return -EINVAL;
13866558d7edSTuomas Tynkkynen }
13872d22b42dSVenu Byravarasu
1388f5b8c8b6SMikko Perttunen /* On some boards, the VBUS regulator doesn't need to be controlled */
1389f5b8c8b6SMikko Perttunen tegra_phy->vbus = devm_regulator_get(&pdev->dev, "vbus");
1390f5b8c8b6SMikko Perttunen if (IS_ERR(tegra_phy->vbus))
1391f5b8c8b6SMikko Perttunen return PTR_ERR(tegra_phy->vbus);
1392f5b8c8b6SMikko Perttunen
13935dcdafddSDmitry Osipenko tegra_phy->pll_u = devm_clk_get(&pdev->dev, "pll_u");
13945dcdafddSDmitry Osipenko err = PTR_ERR_OR_ZERO(tegra_phy->pll_u);
13955dcdafddSDmitry Osipenko if (err) {
13965dcdafddSDmitry Osipenko dev_err(&pdev->dev, "Failed to get pll_u clock: %d\n", err);
13972d22b42dSVenu Byravarasu return err;
13985dcdafddSDmitry Osipenko }
13992d22b42dSVenu Byravarasu
1400c1baf6c5SDmitry Osipenko err = tegra_usb_phy_parse_pmc(&pdev->dev, tegra_phy);
1401c1baf6c5SDmitry Osipenko if (err) {
1402c1baf6c5SDmitry Osipenko dev_err_probe(&pdev->dev, err, "Failed to get PMC regmap\n");
1403c1baf6c5SDmitry Osipenko return err;
1404c1baf6c5SDmitry Osipenko }
1405c1baf6c5SDmitry Osipenko
1406545592e8SDmitry Osipenko phy_type = of_usb_get_phy_mode(np);
1407545592e8SDmitry Osipenko switch (phy_type) {
1408545592e8SDmitry Osipenko case USBPHY_INTERFACE_MODE_UTMI:
1409545592e8SDmitry Osipenko err = utmi_phy_probe(tegra_phy, pdev);
1410545592e8SDmitry Osipenko if (err)
1411545592e8SDmitry Osipenko return err;
1412545592e8SDmitry Osipenko
1413545592e8SDmitry Osipenko tegra_phy->pad_clk = devm_clk_get(&pdev->dev, "utmi-pads");
1414545592e8SDmitry Osipenko err = PTR_ERR_OR_ZERO(tegra_phy->pad_clk);
1415545592e8SDmitry Osipenko if (err) {
1416545592e8SDmitry Osipenko dev_err(&pdev->dev,
1417545592e8SDmitry Osipenko "Failed to get UTMIP pad clock: %d\n", err);
1418545592e8SDmitry Osipenko return err;
1419545592e8SDmitry Osipenko }
1420545592e8SDmitry Osipenko
1421545592e8SDmitry Osipenko reset = devm_reset_control_get_optional_shared(&pdev->dev,
1422545592e8SDmitry Osipenko "utmi-pads");
1423545592e8SDmitry Osipenko err = PTR_ERR_OR_ZERO(reset);
1424545592e8SDmitry Osipenko if (err) {
1425545592e8SDmitry Osipenko dev_err(&pdev->dev,
1426545592e8SDmitry Osipenko "Failed to get UTMI-pads reset: %d\n", err);
1427545592e8SDmitry Osipenko return err;
1428545592e8SDmitry Osipenko }
1429545592e8SDmitry Osipenko tegra_phy->pad_rst = reset;
1430545592e8SDmitry Osipenko break;
1431545592e8SDmitry Osipenko
1432545592e8SDmitry Osipenko case USBPHY_INTERFACE_MODE_ULPI:
1433545592e8SDmitry Osipenko tegra_phy->is_ulpi_phy = true;
1434545592e8SDmitry Osipenko
14355dcdafddSDmitry Osipenko tegra_phy->clk = devm_clk_get(&pdev->dev, "ulpi-link");
14365dcdafddSDmitry Osipenko err = PTR_ERR_OR_ZERO(tegra_phy->clk);
14375dcdafddSDmitry Osipenko if (err) {
14385dcdafddSDmitry Osipenko dev_err(&pdev->dev,
14395dcdafddSDmitry Osipenko "Failed to get ULPI clock: %d\n", err);
14405dcdafddSDmitry Osipenko return err;
14415dcdafddSDmitry Osipenko }
14425dcdafddSDmitry Osipenko
1443255930b9SDmitry Torokhov gpiod = devm_gpiod_get(&pdev->dev, "nvidia,phy-reset",
1444255930b9SDmitry Torokhov GPIOD_OUT_HIGH);
144506e60e50SDmitry Osipenko err = PTR_ERR_OR_ZERO(gpiod);
1446545592e8SDmitry Osipenko if (err) {
144706e60e50SDmitry Osipenko dev_err(&pdev->dev,
144806e60e50SDmitry Osipenko "Request failed for reset GPIO: %d\n", err);
14495dcdafddSDmitry Osipenko return err;
14505dcdafddSDmitry Osipenko }
1451255930b9SDmitry Torokhov
1452255930b9SDmitry Torokhov err = gpiod_set_consumer_name(gpiod, "ulpi_phy_reset_b");
1453255930b9SDmitry Torokhov if (err) {
1454255930b9SDmitry Torokhov dev_err(&pdev->dev,
1455255930b9SDmitry Torokhov "Failed to set up reset GPIO name: %d\n", err);
1456255930b9SDmitry Torokhov return err;
1457255930b9SDmitry Torokhov }
1458255930b9SDmitry Torokhov
145906e60e50SDmitry Osipenko tegra_phy->reset_gpio = gpiod;
14605dcdafddSDmitry Osipenko
146187541747SDmitry Osipenko phy = devm_otg_ulpi_create(&pdev->dev,
146287541747SDmitry Osipenko &ulpi_viewport_access_ops, 0);
146387541747SDmitry Osipenko if (!phy) {
14645dcdafddSDmitry Osipenko dev_err(&pdev->dev, "Failed to create ULPI OTG\n");
1465545592e8SDmitry Osipenko return -ENOMEM;
14665dcdafddSDmitry Osipenko }
14675dcdafddSDmitry Osipenko
146887541747SDmitry Osipenko tegra_phy->ulpi = phy;
14695dcdafddSDmitry Osipenko tegra_phy->ulpi->io_priv = tegra_phy->regs + ULPI_VIEWPORT;
1470545592e8SDmitry Osipenko break;
14715dcdafddSDmitry Osipenko
1472545592e8SDmitry Osipenko default:
1473545592e8SDmitry Osipenko dev_err(&pdev->dev, "phy_type %u is invalid or unsupported\n",
1474545592e8SDmitry Osipenko phy_type);
1475545592e8SDmitry Osipenko return -EINVAL;
14765dcdafddSDmitry Osipenko }
14775dcdafddSDmitry Osipenko
14785dcdafddSDmitry Osipenko tegra_phy->u_phy.dev = &pdev->dev;
14795dcdafddSDmitry Osipenko tegra_phy->u_phy.init = tegra_usb_phy_init;
14805dcdafddSDmitry Osipenko tegra_phy->u_phy.shutdown = tegra_usb_phy_shutdown;
148135192007SDmitry Osipenko tegra_phy->u_phy.set_wakeup = tegra_usb_phy_set_wakeup;
14825dcdafddSDmitry Osipenko tegra_phy->u_phy.set_suspend = tegra_usb_phy_set_suspend;
14832d22b42dSVenu Byravarasu
148472031b52SLibo Chen platform_set_drvdata(pdev, tegra_phy);
14850ee5b4abSTuomas Tynkkynen
1486d410912eSTang Bin return usb_add_phy_dev(&tegra_phy->u_phy);
14870ee5b4abSTuomas Tynkkynen }
14880ee5b4abSTuomas Tynkkynen
tegra_usb_phy_remove(struct platform_device * pdev)1489d95a0ce2SUwe Kleine-König static void tegra_usb_phy_remove(struct platform_device *pdev)
14900ee5b4abSTuomas Tynkkynen {
14910ee5b4abSTuomas Tynkkynen struct tegra_usb_phy *tegra_phy = platform_get_drvdata(pdev);
14920ee5b4abSTuomas Tynkkynen
14930ee5b4abSTuomas Tynkkynen usb_remove_phy(&tegra_phy->u_phy);
14942d22b42dSVenu Byravarasu }
14952d22b42dSVenu Byravarasu
14962d22b42dSVenu Byravarasu static struct platform_driver tegra_usb_phy_driver = {
14972d22b42dSVenu Byravarasu .probe = tegra_usb_phy_probe,
1498d95a0ce2SUwe Kleine-König .remove_new = tegra_usb_phy_remove,
14992d22b42dSVenu Byravarasu .driver = {
15002d22b42dSVenu Byravarasu .name = "tegra-phy",
150178723920SSachin Kamat .of_match_table = tegra_usb_phy_id_table,
15022d22b42dSVenu Byravarasu },
15032d22b42dSVenu Byravarasu };
15042d22b42dSVenu Byravarasu module_platform_driver(tegra_usb_phy_driver);
15052d22b42dSVenu Byravarasu
1506587376a1SStephen Warren MODULE_DESCRIPTION("Tegra USB PHY driver");
1507587376a1SStephen Warren MODULE_LICENSE("GPL v2");
1508