xref: /openbmc/linux/drivers/usb/phy/phy-tegra-usb.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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