diff options
author | Thierry Reding <treding@nvidia.com> | 2015-11-11 12:24:21 -0500 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2016-04-29 10:44:47 -0400 |
commit | 53d2a715c24034ee4017f3c15c82bb4a53a07da5 (patch) | |
tree | a520b1e745e31eba9fb8936c3e19e1c4103214e1 | |
parent | d6f83c1b1dcac39729f48fe1c2d426b9c135df41 (diff) |
phy: Add Tegra XUSB pad controller support
Add a new driver for the XUSB pad controller found on NVIDIA Tegra SoCs.
This hardware block used to be exposed as a pin controller, but it turns
out that this isn't a good fit. The new driver and DT binding much more
accurately describe the hardware and are more flexible in supporting new
SoC generations.
Acked-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r-- | drivers/phy/Kconfig | 2 | ||||
-rw-r--r-- | drivers/phy/Makefile | 2 | ||||
-rw-r--r-- | drivers/phy/tegra/Kconfig | 8 | ||||
-rw-r--r-- | drivers/phy/tegra/Makefile | 5 | ||||
-rw-r--r-- | drivers/phy/tegra/xusb-tegra124.c | 1752 | ||||
-rw-r--r-- | drivers/phy/tegra/xusb.c | 1021 | ||||
-rw-r--r-- | drivers/phy/tegra/xusb.h | 421 | ||||
-rw-r--r-- | drivers/pinctrl/tegra/pinctrl-tegra-xusb.c | 20 | ||||
-rw-r--r-- | include/linux/phy/tegra/xusb.h | 30 |
9 files changed, 3245 insertions, 16 deletions
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 26566db09de0..27e5f6ee9a2a 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig | |||
@@ -421,4 +421,6 @@ config PHY_CYGNUS_PCIE | |||
421 | Enable this to support the Broadcom Cygnus PCIe PHY. | 421 | Enable this to support the Broadcom Cygnus PCIe PHY. |
422 | If unsure, say N. | 422 | If unsure, say N. |
423 | 423 | ||
424 | source "drivers/phy/tegra/Kconfig" | ||
425 | |||
424 | endmenu | 426 | endmenu |
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 24596a96a887..d4f06e69fd9a 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile | |||
@@ -52,3 +52,5 @@ obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o | |||
52 | obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o | 52 | obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o |
53 | obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o | 53 | obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o |
54 | obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o | 54 | obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o |
55 | |||
56 | obj-$(CONFIG_ARCH_TEGRA) += tegra/ | ||
diff --git a/drivers/phy/tegra/Kconfig b/drivers/phy/tegra/Kconfig new file mode 100644 index 000000000000..a3b1de953fb7 --- /dev/null +++ b/drivers/phy/tegra/Kconfig | |||
@@ -0,0 +1,8 @@ | |||
1 | config PHY_TEGRA_XUSB | ||
2 | tristate "NVIDIA Tegra XUSB pad controller driver" | ||
3 | depends on ARCH_TEGRA | ||
4 | help | ||
5 | Choose this option if you have an NVIDIA Tegra SoC. | ||
6 | |||
7 | To compile this driver as a module, choose M here: the module will | ||
8 | be called phy-tegra-xusb. | ||
diff --git a/drivers/phy/tegra/Makefile b/drivers/phy/tegra/Makefile new file mode 100644 index 000000000000..31150b4337cd --- /dev/null +++ b/drivers/phy/tegra/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | obj-$(CONFIG_PHY_TEGRA_XUSB) += phy-tegra-xusb.o | ||
2 | |||
3 | phy-tegra-xusb-y += xusb.o | ||
4 | phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_124_SOC) += xusb-tegra124.o | ||
5 | phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_132_SOC) += xusb-tegra124.o | ||
diff --git a/drivers/phy/tegra/xusb-tegra124.c b/drivers/phy/tegra/xusb-tegra124.c new file mode 100644 index 000000000000..119957249a51 --- /dev/null +++ b/drivers/phy/tegra/xusb-tegra124.c | |||
@@ -0,0 +1,1752 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/mailbox_client.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/phy/phy.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/regulator/consumer.h> | ||
22 | #include <linux/reset.h> | ||
23 | #include <linux/slab.h> | ||
24 | |||
25 | #include <soc/tegra/fuse.h> | ||
26 | |||
27 | #include "xusb.h" | ||
28 | |||
29 | #define FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(x) ((x) ? 15 : 0) | ||
30 | #define FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK 0x3f | ||
31 | #define FUSE_SKU_CALIB_HS_IREF_CAP_SHIFT 13 | ||
32 | #define FUSE_SKU_CALIB_HS_IREF_CAP_MASK 0x3 | ||
33 | #define FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_SHIFT 11 | ||
34 | #define FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_MASK 0x3 | ||
35 | #define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT 7 | ||
36 | #define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK 0xf | ||
37 | |||
38 | #define XUSB_PADCTL_USB2_PORT_CAP 0x008 | ||
39 | #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(x) ((x) * 4) | ||
40 | #define XUSB_PADCTL_USB2_PORT_CAP_PORT_CAP_MASK 0x3 | ||
41 | #define XUSB_PADCTL_USB2_PORT_CAP_DISABLED 0x0 | ||
42 | #define XUSB_PADCTL_USB2_PORT_CAP_HOST 0x1 | ||
43 | #define XUSB_PADCTL_USB2_PORT_CAP_DEVICE 0x2 | ||
44 | #define XUSB_PADCTL_USB2_PORT_CAP_OTG 0x3 | ||
45 | |||
46 | #define XUSB_PADCTL_SS_PORT_MAP 0x014 | ||
47 | #define XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(x) (1 << (((x) * 4) + 3)) | ||
48 | #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_SHIFT(x) ((x) * 4) | ||
49 | #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(x) (0x7 << ((x) * 4)) | ||
50 | #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(x, v) (((v) & 0x7) << ((x) * 4)) | ||
51 | #define XUSB_PADCTL_SS_PORT_MAP_PORT_MAP_MASK 0x7 | ||
52 | |||
53 | #define XUSB_PADCTL_ELPG_PROGRAM 0x01c | ||
54 | #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26) | ||
55 | #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25) | ||
56 | #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24) | ||
57 | #define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(x) (1 << (18 + (x) * 4)) | ||
58 | #define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(x) \ | ||
59 | (1 << (17 + (x) * 4)) | ||
60 | #define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN(x) (1 << (16 + (x) * 4)) | ||
61 | |||
62 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040 | ||
63 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19) | ||
64 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK (0xf << 12) | ||
65 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1) | ||
66 | |||
67 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044 | ||
68 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6) | ||
69 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5) | ||
70 | #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4) | ||
71 | |||
72 | #define XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(x) (0x058 + (x) * 4) | ||
73 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT 24 | ||
74 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK 0xff | ||
75 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_VAL 0x24 | ||
76 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT 16 | ||
77 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK 0x3f | ||
78 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT 8 | ||
79 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK 0x3f | ||
80 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT 8 | ||
81 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK 0xffff | ||
82 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_VAL 0xf070 | ||
83 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT 4 | ||
84 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK 0xf | ||
85 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_VAL 0xf | ||
86 | |||
87 | #define XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(x) (0x068 + (x) * 4) | ||
88 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT 24 | ||
89 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK 0x1f | ||
90 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT 16 | ||
91 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK 0x7f | ||
92 | #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_VAL 0x002008ee | ||
93 | |||
94 | #define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL2(x) ((x) < 2 ? 0x078 + (x) * 4 : \ | ||
95 | 0x0f8 + (x) * 4) | ||
96 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT 28 | ||
97 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_MASK 0x3 | ||
98 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_VAL 0x1 | ||
99 | |||
100 | #define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL5(x) ((x) < 2 ? 0x090 + (x) * 4 : \ | ||
101 | 0x11c + (x) * 4) | ||
102 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL5_RX_QEYE_EN (1 << 8) | ||
103 | |||
104 | #define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL6(x) ((x) < 2 ? 0x098 + (x) * 4 : \ | ||
105 | 0x128 + (x) * 4) | ||
106 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT 24 | ||
107 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK 0x3f | ||
108 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_TAP_MASK 0x1f | ||
109 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_AMP_MASK 0x7f | ||
110 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT 16 | ||
111 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK 0xff | ||
112 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_G_Z 0x21 | ||
113 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_TAP 0x32 | ||
114 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_AMP 0x33 | ||
115 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_CTLE_Z 0x48 | ||
116 | #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_LATCH_G_Z 0xa1 | ||
117 | |||
118 | #define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x0a0 + (x) * 4) | ||
119 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI (1 << 21) | ||
120 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 (1 << 20) | ||
121 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD (1 << 19) | ||
122 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT 14 | ||
123 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_MASK 0x3 | ||
124 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_VAL(x) ((x) ? 0x0 : 0x3) | ||
125 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT 6 | ||
126 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_MASK 0x3f | ||
127 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_VAL 0x0e | ||
128 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT 0 | ||
129 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK 0x3f | ||
130 | |||
131 | #define XUSB_PADCTL_USB2_OTG_PADX_CTL1(x) (0x0ac + (x) * 4) | ||
132 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT 9 | ||
133 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_MASK 0x3 | ||
134 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT 3 | ||
135 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK 0x7 | ||
136 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2) | ||
137 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP (1 << 1) | ||
138 | #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP (1 << 0) | ||
139 | |||
140 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x0b8 | ||
141 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 12) | ||
142 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT 2 | ||
143 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK 0x7 | ||
144 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL 0x5 | ||
145 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT 0 | ||
146 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK 0x3 | ||
147 | |||
148 | #define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x0c0 + (x) * 4) | ||
149 | #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT 12 | ||
150 | #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK 0x7 | ||
151 | #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT 8 | ||
152 | #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK 0x7 | ||
153 | #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT 4 | ||
154 | #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK 0x7 | ||
155 | #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT 0 | ||
156 | #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK 0x7 | ||
157 | |||
158 | #define XUSB_PADCTL_HSIC_PADX_CTL1(x) (0x0c8 + (x) * 4) | ||
159 | #define XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE (1 << 10) | ||
160 | #define XUSB_PADCTL_HSIC_PAD_CTL1_RPU_DATA (1 << 9) | ||
161 | #define XUSB_PADCTL_HSIC_PAD_CTL1_RPD_STROBE (1 << 8) | ||
162 | #define XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA (1 << 7) | ||
163 | #define XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI (1 << 5) | ||
164 | #define XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX (1 << 4) | ||
165 | #define XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX (1 << 3) | ||
166 | #define XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX (1 << 2) | ||
167 | #define XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN (1 << 0) | ||
168 | |||
169 | #define XUSB_PADCTL_HSIC_PADX_CTL2(x) (0x0d0 + (x) * 4) | ||
170 | #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT 4 | ||
171 | #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK 0x7 | ||
172 | #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT 0 | ||
173 | #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK 0x7 | ||
174 | |||
175 | #define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL 0x0e0 | ||
176 | #define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL_STRB_TRIM_MASK 0x1f | ||
177 | |||
178 | #define XUSB_PADCTL_USB3_PAD_MUX 0x134 | ||
179 | #define XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(x) (1 << (1 + (x))) | ||
180 | #define XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(x) (1 << (6 + (x))) | ||
181 | |||
182 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138 | ||
183 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27) | ||
184 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24) | ||
185 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_SHIFT 20 | ||
186 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_MASK 0x3 | ||
187 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3) | ||
188 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST (1 << 1) | ||
189 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0) | ||
190 | |||
191 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2 0x13c | ||
192 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_SHIFT 20 | ||
193 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_MASK 0xf | ||
194 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_SHIFT 16 | ||
195 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_MASK 0xf | ||
196 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_TCLKOUT_EN (1 << 12) | ||
197 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_TXCLKREF_SEL (1 << 4) | ||
198 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_SHIFT 0 | ||
199 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_MASK 0x7 | ||
200 | |||
201 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL3 0x140 | ||
202 | #define XUSB_PADCTL_IOPHY_PLL_S0_CTL3_RCAL_BYPASS (1 << 7) | ||
203 | |||
204 | #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148 | ||
205 | #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1) | ||
206 | #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0) | ||
207 | |||
208 | #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 0x14c | ||
209 | |||
210 | #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 0x158 | ||
211 | |||
212 | #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 0x15c | ||
213 | |||
214 | struct tegra124_xusb_fuse_calibration { | ||
215 | u32 hs_curr_level[3]; | ||
216 | u32 hs_iref_cap; | ||
217 | u32 hs_term_range_adj; | ||
218 | u32 hs_squelch_level; | ||
219 | }; | ||
220 | |||
221 | struct tegra124_xusb_padctl { | ||
222 | struct tegra_xusb_padctl base; | ||
223 | |||
224 | struct tegra124_xusb_fuse_calibration fuse; | ||
225 | }; | ||
226 | |||
227 | static inline struct tegra124_xusb_padctl * | ||
228 | to_tegra124_xusb_padctl(struct tegra_xusb_padctl *padctl) | ||
229 | { | ||
230 | return container_of(padctl, struct tegra124_xusb_padctl, base); | ||
231 | } | ||
232 | |||
233 | static int tegra124_xusb_padctl_enable(struct tegra_xusb_padctl *padctl) | ||
234 | { | ||
235 | u32 value; | ||
236 | |||
237 | mutex_lock(&padctl->lock); | ||
238 | |||
239 | if (padctl->enable++ > 0) | ||
240 | goto out; | ||
241 | |||
242 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
243 | value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; | ||
244 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
245 | |||
246 | usleep_range(100, 200); | ||
247 | |||
248 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
249 | value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; | ||
250 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
251 | |||
252 | usleep_range(100, 200); | ||
253 | |||
254 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
255 | value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; | ||
256 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
257 | |||
258 | out: | ||
259 | mutex_unlock(&padctl->lock); | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static int tegra124_xusb_padctl_disable(struct tegra_xusb_padctl *padctl) | ||
264 | { | ||
265 | u32 value; | ||
266 | |||
267 | mutex_lock(&padctl->lock); | ||
268 | |||
269 | if (WARN_ON(padctl->enable == 0)) | ||
270 | goto out; | ||
271 | |||
272 | if (--padctl->enable > 0) | ||
273 | goto out; | ||
274 | |||
275 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
276 | value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; | ||
277 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
278 | |||
279 | usleep_range(100, 200); | ||
280 | |||
281 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
282 | value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; | ||
283 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
284 | |||
285 | usleep_range(100, 200); | ||
286 | |||
287 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
288 | value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; | ||
289 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
290 | |||
291 | out: | ||
292 | mutex_unlock(&padctl->lock); | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static int tegra124_usb3_save_context(struct tegra_xusb_padctl *padctl, | ||
297 | unsigned int index) | ||
298 | { | ||
299 | struct tegra_xusb_usb3_port *port; | ||
300 | struct tegra_xusb_lane *lane; | ||
301 | u32 value, offset; | ||
302 | |||
303 | port = tegra_xusb_find_usb3_port(padctl, index); | ||
304 | if (!port) | ||
305 | return -ENODEV; | ||
306 | |||
307 | port->context_saved = true; | ||
308 | lane = port->base.lane; | ||
309 | |||
310 | if (lane->pad == padctl->pcie) | ||
311 | offset = XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL6(lane->index); | ||
312 | else | ||
313 | offset = XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6; | ||
314 | |||
315 | value = padctl_readl(padctl, offset); | ||
316 | value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK << | ||
317 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT); | ||
318 | value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_TAP << | ||
319 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT; | ||
320 | padctl_writel(padctl, value, offset); | ||
321 | |||
322 | value = padctl_readl(padctl, offset) >> | ||
323 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT; | ||
324 | port->tap1 = value & XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_TAP_MASK; | ||
325 | |||
326 | value = padctl_readl(padctl, offset); | ||
327 | value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK << | ||
328 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT); | ||
329 | value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_AMP << | ||
330 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT; | ||
331 | padctl_writel(padctl, value, offset); | ||
332 | |||
333 | value = padctl_readl(padctl, offset) >> | ||
334 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT; | ||
335 | port->amp = value & XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_AMP_MASK; | ||
336 | |||
337 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(index)); | ||
338 | value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK << | ||
339 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) | | ||
340 | (XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK << | ||
341 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT)); | ||
342 | value |= (port->tap1 << | ||
343 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) | | ||
344 | (port->amp << | ||
345 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT); | ||
346 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(index)); | ||
347 | |||
348 | value = padctl_readl(padctl, offset); | ||
349 | value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK << | ||
350 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT); | ||
351 | value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_LATCH_G_Z << | ||
352 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT; | ||
353 | padctl_writel(padctl, value, offset); | ||
354 | |||
355 | value = padctl_readl(padctl, offset); | ||
356 | value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK << | ||
357 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT); | ||
358 | value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_G_Z << | ||
359 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT; | ||
360 | padctl_writel(padctl, value, offset); | ||
361 | |||
362 | value = padctl_readl(padctl, offset) >> | ||
363 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT; | ||
364 | port->ctle_g = value & | ||
365 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK; | ||
366 | |||
367 | value = padctl_readl(padctl, offset); | ||
368 | value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK << | ||
369 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT); | ||
370 | value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_CTLE_Z << | ||
371 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT; | ||
372 | padctl_writel(padctl, value, offset); | ||
373 | |||
374 | value = padctl_readl(padctl, offset) >> | ||
375 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT; | ||
376 | port->ctle_z = value & | ||
377 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK; | ||
378 | |||
379 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(index)); | ||
380 | value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK << | ||
381 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) | | ||
382 | (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK << | ||
383 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT)); | ||
384 | value |= (port->ctle_g << | ||
385 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) | | ||
386 | (port->ctle_z << | ||
387 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT); | ||
388 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(index)); | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static int tegra124_hsic_set_idle(struct tegra_xusb_padctl *padctl, | ||
394 | unsigned int index, bool idle) | ||
395 | { | ||
396 | u32 value; | ||
397 | |||
398 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
399 | |||
400 | if (idle) | ||
401 | value |= XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA | | ||
402 | XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE; | ||
403 | else | ||
404 | value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA | | ||
405 | XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE); | ||
406 | |||
407 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
408 | |||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | #define TEGRA124_LANE(_name, _offset, _shift, _mask, _type) \ | ||
413 | { \ | ||
414 | .name = _name, \ | ||
415 | .offset = _offset, \ | ||
416 | .shift = _shift, \ | ||
417 | .mask = _mask, \ | ||
418 | .num_funcs = ARRAY_SIZE(tegra124_##_type##_functions), \ | ||
419 | .funcs = tegra124_##_type##_functions, \ | ||
420 | } | ||
421 | |||
422 | static const char * const tegra124_usb2_functions[] = { | ||
423 | "snps", | ||
424 | "xusb", | ||
425 | "uart", | ||
426 | }; | ||
427 | |||
428 | static const struct tegra_xusb_lane_soc tegra124_usb2_lanes[] = { | ||
429 | TEGRA124_LANE("usb2-0", 0x004, 0, 0x3, usb2), | ||
430 | TEGRA124_LANE("usb2-1", 0x004, 2, 0x3, usb2), | ||
431 | TEGRA124_LANE("usb2-2", 0x004, 4, 0x3, usb2), | ||
432 | }; | ||
433 | |||
434 | static struct tegra_xusb_lane * | ||
435 | tegra124_usb2_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, | ||
436 | unsigned int index) | ||
437 | { | ||
438 | struct tegra_xusb_usb2_lane *usb2; | ||
439 | int err; | ||
440 | |||
441 | usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL); | ||
442 | if (!usb2) | ||
443 | return ERR_PTR(-ENOMEM); | ||
444 | |||
445 | INIT_LIST_HEAD(&usb2->base.list); | ||
446 | usb2->base.soc = &pad->soc->lanes[index]; | ||
447 | usb2->base.index = index; | ||
448 | usb2->base.pad = pad; | ||
449 | usb2->base.np = np; | ||
450 | |||
451 | err = tegra_xusb_lane_parse_dt(&usb2->base, np); | ||
452 | if (err < 0) { | ||
453 | kfree(usb2); | ||
454 | return ERR_PTR(err); | ||
455 | } | ||
456 | |||
457 | return &usb2->base; | ||
458 | } | ||
459 | |||
460 | static void tegra124_usb2_lane_remove(struct tegra_xusb_lane *lane) | ||
461 | { | ||
462 | struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane); | ||
463 | |||
464 | kfree(usb2); | ||
465 | } | ||
466 | |||
467 | static const struct tegra_xusb_lane_ops tegra124_usb2_lane_ops = { | ||
468 | .probe = tegra124_usb2_lane_probe, | ||
469 | .remove = tegra124_usb2_lane_remove, | ||
470 | }; | ||
471 | |||
472 | static int tegra124_usb2_phy_init(struct phy *phy) | ||
473 | { | ||
474 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
475 | |||
476 | return tegra124_xusb_padctl_enable(lane->pad->padctl); | ||
477 | } | ||
478 | |||
479 | static int tegra124_usb2_phy_exit(struct phy *phy) | ||
480 | { | ||
481 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
482 | |||
483 | return tegra124_xusb_padctl_disable(lane->pad->padctl); | ||
484 | } | ||
485 | |||
486 | static int tegra124_usb2_phy_power_on(struct phy *phy) | ||
487 | { | ||
488 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
489 | struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane); | ||
490 | struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad); | ||
491 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
492 | struct tegra124_xusb_padctl *priv; | ||
493 | struct tegra_xusb_usb2_port *port; | ||
494 | unsigned int index = lane->index; | ||
495 | u32 value; | ||
496 | int err; | ||
497 | |||
498 | port = tegra_xusb_find_usb2_port(padctl, index); | ||
499 | if (!port) { | ||
500 | dev_err(&phy->dev, "no port found for USB2 lane %u\n", index); | ||
501 | return -ENODEV; | ||
502 | } | ||
503 | |||
504 | priv = to_tegra124_xusb_padctl(padctl); | ||
505 | |||
506 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
507 | value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK << | ||
508 | XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) | | ||
509 | (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK << | ||
510 | XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT)); | ||
511 | value |= (priv->fuse.hs_squelch_level << | ||
512 | XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) | | ||
513 | (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL << | ||
514 | XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT); | ||
515 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
516 | |||
517 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP); | ||
518 | value &= ~(XUSB_PADCTL_USB2_PORT_CAP_PORT_CAP_MASK << | ||
519 | XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(index)); | ||
520 | value |= XUSB_PADCTL_USB2_PORT_CAP_HOST << | ||
521 | XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(index); | ||
522 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP); | ||
523 | |||
524 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); | ||
525 | value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK << | ||
526 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT) | | ||
527 | (XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_MASK << | ||
528 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT) | | ||
529 | (XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_MASK << | ||
530 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT) | | ||
531 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD | | ||
532 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 | | ||
533 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI); | ||
534 | value |= (priv->fuse.hs_curr_level[index] + | ||
535 | usb2->hs_curr_level_offset) << | ||
536 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT; | ||
537 | value |= XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_VAL << | ||
538 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT; | ||
539 | value |= XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_VAL(index) << | ||
540 | XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT; | ||
541 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); | ||
542 | |||
543 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); | ||
544 | value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK << | ||
545 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) | | ||
546 | (XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_MASK << | ||
547 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT) | | ||
548 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR | | ||
549 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP | | ||
550 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP); | ||
551 | value |= (priv->fuse.hs_term_range_adj << | ||
552 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) | | ||
553 | (priv->fuse.hs_iref_cap << | ||
554 | XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT); | ||
555 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); | ||
556 | |||
557 | err = regulator_enable(port->supply); | ||
558 | if (err) | ||
559 | return err; | ||
560 | |||
561 | mutex_lock(&pad->lock); | ||
562 | |||
563 | if (pad->enable++ > 0) | ||
564 | goto out; | ||
565 | |||
566 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
567 | value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD; | ||
568 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
569 | |||
570 | out: | ||
571 | mutex_unlock(&pad->lock); | ||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | static int tegra124_usb2_phy_power_off(struct phy *phy) | ||
576 | { | ||
577 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
578 | struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad); | ||
579 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
580 | struct tegra_xusb_usb2_port *port; | ||
581 | u32 value; | ||
582 | |||
583 | port = tegra_xusb_find_usb2_port(padctl, lane->index); | ||
584 | if (!port) { | ||
585 | dev_err(&phy->dev, "no port found for USB2 lane %u\n", | ||
586 | lane->index); | ||
587 | return -ENODEV; | ||
588 | } | ||
589 | |||
590 | mutex_lock(&pad->lock); | ||
591 | |||
592 | if (WARN_ON(pad->enable == 0)) | ||
593 | goto out; | ||
594 | |||
595 | if (--pad->enable > 0) | ||
596 | goto out; | ||
597 | |||
598 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
599 | value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD; | ||
600 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
601 | |||
602 | out: | ||
603 | regulator_disable(port->supply); | ||
604 | mutex_unlock(&pad->lock); | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | static const struct phy_ops tegra124_usb2_phy_ops = { | ||
609 | .init = tegra124_usb2_phy_init, | ||
610 | .exit = tegra124_usb2_phy_exit, | ||
611 | .power_on = tegra124_usb2_phy_power_on, | ||
612 | .power_off = tegra124_usb2_phy_power_off, | ||
613 | .owner = THIS_MODULE, | ||
614 | }; | ||
615 | |||
616 | static struct tegra_xusb_pad * | ||
617 | tegra124_usb2_pad_probe(struct tegra_xusb_padctl *padctl, | ||
618 | const struct tegra_xusb_pad_soc *soc, | ||
619 | struct device_node *np) | ||
620 | { | ||
621 | struct tegra_xusb_usb2_pad *usb2; | ||
622 | struct tegra_xusb_pad *pad; | ||
623 | int err; | ||
624 | |||
625 | usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL); | ||
626 | if (!usb2) | ||
627 | return ERR_PTR(-ENOMEM); | ||
628 | |||
629 | mutex_init(&usb2->lock); | ||
630 | |||
631 | pad = &usb2->base; | ||
632 | pad->ops = &tegra124_usb2_lane_ops; | ||
633 | pad->soc = soc; | ||
634 | |||
635 | err = tegra_xusb_pad_init(pad, padctl, np); | ||
636 | if (err < 0) { | ||
637 | kfree(usb2); | ||
638 | goto out; | ||
639 | } | ||
640 | |||
641 | err = tegra_xusb_pad_register(pad, &tegra124_usb2_phy_ops); | ||
642 | if (err < 0) | ||
643 | goto unregister; | ||
644 | |||
645 | dev_set_drvdata(&pad->dev, pad); | ||
646 | |||
647 | return pad; | ||
648 | |||
649 | unregister: | ||
650 | device_unregister(&pad->dev); | ||
651 | out: | ||
652 | return ERR_PTR(err); | ||
653 | } | ||
654 | |||
655 | static void tegra124_usb2_pad_remove(struct tegra_xusb_pad *pad) | ||
656 | { | ||
657 | struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad); | ||
658 | |||
659 | kfree(usb2); | ||
660 | } | ||
661 | |||
662 | static const struct tegra_xusb_pad_ops tegra124_usb2_ops = { | ||
663 | .probe = tegra124_usb2_pad_probe, | ||
664 | .remove = tegra124_usb2_pad_remove, | ||
665 | }; | ||
666 | |||
667 | static const struct tegra_xusb_pad_soc tegra124_usb2_pad = { | ||
668 | .name = "usb2", | ||
669 | .num_lanes = ARRAY_SIZE(tegra124_usb2_lanes), | ||
670 | .lanes = tegra124_usb2_lanes, | ||
671 | .ops = &tegra124_usb2_ops, | ||
672 | }; | ||
673 | |||
674 | static const char * const tegra124_ulpi_functions[] = { | ||
675 | "snps", | ||
676 | "xusb", | ||
677 | }; | ||
678 | |||
679 | static const struct tegra_xusb_lane_soc tegra124_ulpi_lanes[] = { | ||
680 | TEGRA124_LANE("ulpi-0", 0x004, 12, 0x1, ulpi), | ||
681 | }; | ||
682 | |||
683 | static struct tegra_xusb_lane * | ||
684 | tegra124_ulpi_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, | ||
685 | unsigned int index) | ||
686 | { | ||
687 | struct tegra_xusb_ulpi_lane *ulpi; | ||
688 | int err; | ||
689 | |||
690 | ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL); | ||
691 | if (!ulpi) | ||
692 | return ERR_PTR(-ENOMEM); | ||
693 | |||
694 | INIT_LIST_HEAD(&ulpi->base.list); | ||
695 | ulpi->base.soc = &pad->soc->lanes[index]; | ||
696 | ulpi->base.index = index; | ||
697 | ulpi->base.pad = pad; | ||
698 | ulpi->base.np = np; | ||
699 | |||
700 | err = tegra_xusb_lane_parse_dt(&ulpi->base, np); | ||
701 | if (err < 0) { | ||
702 | kfree(ulpi); | ||
703 | return ERR_PTR(err); | ||
704 | } | ||
705 | |||
706 | return &ulpi->base; | ||
707 | } | ||
708 | |||
709 | static void tegra124_ulpi_lane_remove(struct tegra_xusb_lane *lane) | ||
710 | { | ||
711 | struct tegra_xusb_ulpi_lane *ulpi = to_ulpi_lane(lane); | ||
712 | |||
713 | kfree(ulpi); | ||
714 | } | ||
715 | |||
716 | static const struct tegra_xusb_lane_ops tegra124_ulpi_lane_ops = { | ||
717 | .probe = tegra124_ulpi_lane_probe, | ||
718 | .remove = tegra124_ulpi_lane_remove, | ||
719 | }; | ||
720 | |||
721 | static int tegra124_ulpi_phy_init(struct phy *phy) | ||
722 | { | ||
723 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
724 | |||
725 | return tegra124_xusb_padctl_enable(lane->pad->padctl); | ||
726 | } | ||
727 | |||
728 | static int tegra124_ulpi_phy_exit(struct phy *phy) | ||
729 | { | ||
730 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
731 | |||
732 | return tegra124_xusb_padctl_disable(lane->pad->padctl); | ||
733 | } | ||
734 | |||
735 | static int tegra124_ulpi_phy_power_on(struct phy *phy) | ||
736 | { | ||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | static int tegra124_ulpi_phy_power_off(struct phy *phy) | ||
741 | { | ||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | static const struct phy_ops tegra124_ulpi_phy_ops = { | ||
746 | .init = tegra124_ulpi_phy_init, | ||
747 | .exit = tegra124_ulpi_phy_exit, | ||
748 | .power_on = tegra124_ulpi_phy_power_on, | ||
749 | .power_off = tegra124_ulpi_phy_power_off, | ||
750 | .owner = THIS_MODULE, | ||
751 | }; | ||
752 | |||
753 | static struct tegra_xusb_pad * | ||
754 | tegra124_ulpi_pad_probe(struct tegra_xusb_padctl *padctl, | ||
755 | const struct tegra_xusb_pad_soc *soc, | ||
756 | struct device_node *np) | ||
757 | { | ||
758 | struct tegra_xusb_ulpi_pad *ulpi; | ||
759 | struct tegra_xusb_pad *pad; | ||
760 | int err; | ||
761 | |||
762 | ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL); | ||
763 | if (!ulpi) | ||
764 | return ERR_PTR(-ENOMEM); | ||
765 | |||
766 | pad = &ulpi->base; | ||
767 | pad->ops = &tegra124_ulpi_lane_ops; | ||
768 | pad->soc = soc; | ||
769 | |||
770 | err = tegra_xusb_pad_init(pad, padctl, np); | ||
771 | if (err < 0) { | ||
772 | kfree(ulpi); | ||
773 | goto out; | ||
774 | } | ||
775 | |||
776 | err = tegra_xusb_pad_register(pad, &tegra124_ulpi_phy_ops); | ||
777 | if (err < 0) | ||
778 | goto unregister; | ||
779 | |||
780 | dev_set_drvdata(&pad->dev, pad); | ||
781 | |||
782 | return pad; | ||
783 | |||
784 | unregister: | ||
785 | device_unregister(&pad->dev); | ||
786 | out: | ||
787 | return ERR_PTR(err); | ||
788 | } | ||
789 | |||
790 | static void tegra124_ulpi_pad_remove(struct tegra_xusb_pad *pad) | ||
791 | { | ||
792 | struct tegra_xusb_ulpi_pad *ulpi = to_ulpi_pad(pad); | ||
793 | |||
794 | kfree(ulpi); | ||
795 | } | ||
796 | |||
797 | static const struct tegra_xusb_pad_ops tegra124_ulpi_ops = { | ||
798 | .probe = tegra124_ulpi_pad_probe, | ||
799 | .remove = tegra124_ulpi_pad_remove, | ||
800 | }; | ||
801 | |||
802 | static const struct tegra_xusb_pad_soc tegra124_ulpi_pad = { | ||
803 | .name = "ulpi", | ||
804 | .num_lanes = ARRAY_SIZE(tegra124_ulpi_lanes), | ||
805 | .lanes = tegra124_ulpi_lanes, | ||
806 | .ops = &tegra124_ulpi_ops, | ||
807 | }; | ||
808 | |||
809 | static const char * const tegra124_hsic_functions[] = { | ||
810 | "snps", | ||
811 | "xusb", | ||
812 | }; | ||
813 | |||
814 | static const struct tegra_xusb_lane_soc tegra124_hsic_lanes[] = { | ||
815 | TEGRA124_LANE("hsic-0", 0x004, 14, 0x1, hsic), | ||
816 | TEGRA124_LANE("hsic-1", 0x004, 15, 0x1, hsic), | ||
817 | }; | ||
818 | |||
819 | static struct tegra_xusb_lane * | ||
820 | tegra124_hsic_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, | ||
821 | unsigned int index) | ||
822 | { | ||
823 | struct tegra_xusb_hsic_lane *hsic; | ||
824 | int err; | ||
825 | |||
826 | hsic = kzalloc(sizeof(*hsic), GFP_KERNEL); | ||
827 | if (!hsic) | ||
828 | return ERR_PTR(-ENOMEM); | ||
829 | |||
830 | INIT_LIST_HEAD(&hsic->base.list); | ||
831 | hsic->base.soc = &pad->soc->lanes[index]; | ||
832 | hsic->base.index = index; | ||
833 | hsic->base.pad = pad; | ||
834 | hsic->base.np = np; | ||
835 | |||
836 | err = tegra_xusb_lane_parse_dt(&hsic->base, np); | ||
837 | if (err < 0) { | ||
838 | kfree(hsic); | ||
839 | return ERR_PTR(err); | ||
840 | } | ||
841 | |||
842 | return &hsic->base; | ||
843 | } | ||
844 | |||
845 | static void tegra124_hsic_lane_remove(struct tegra_xusb_lane *lane) | ||
846 | { | ||
847 | struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane); | ||
848 | |||
849 | kfree(hsic); | ||
850 | } | ||
851 | |||
852 | static const struct tegra_xusb_lane_ops tegra124_hsic_lane_ops = { | ||
853 | .probe = tegra124_hsic_lane_probe, | ||
854 | .remove = tegra124_hsic_lane_remove, | ||
855 | }; | ||
856 | |||
857 | static int tegra124_hsic_phy_init(struct phy *phy) | ||
858 | { | ||
859 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
860 | |||
861 | return tegra124_xusb_padctl_enable(lane->pad->padctl); | ||
862 | } | ||
863 | |||
864 | static int tegra124_hsic_phy_exit(struct phy *phy) | ||
865 | { | ||
866 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
867 | |||
868 | return tegra124_xusb_padctl_disable(lane->pad->padctl); | ||
869 | } | ||
870 | |||
871 | static int tegra124_hsic_phy_power_on(struct phy *phy) | ||
872 | { | ||
873 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
874 | struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane); | ||
875 | struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad); | ||
876 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
877 | unsigned int index = lane->index; | ||
878 | u32 value; | ||
879 | int err; | ||
880 | |||
881 | err = regulator_enable(pad->supply); | ||
882 | if (err) | ||
883 | return err; | ||
884 | |||
885 | padctl_writel(padctl, hsic->strobe_trim, | ||
886 | XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL); | ||
887 | |||
888 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
889 | |||
890 | if (hsic->auto_term) | ||
891 | value |= XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN; | ||
892 | else | ||
893 | value &= ~XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN; | ||
894 | |||
895 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
896 | |||
897 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index)); | ||
898 | value &= ~((XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK << | ||
899 | XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT) | | ||
900 | (XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK << | ||
901 | XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT) | | ||
902 | (XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK << | ||
903 | XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT) | | ||
904 | (XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK << | ||
905 | XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT)); | ||
906 | value |= (hsic->tx_rtune_n << | ||
907 | XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT) | | ||
908 | (hsic->tx_rtune_p << | ||
909 | XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT) | | ||
910 | (hsic->tx_rslew_n << | ||
911 | XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT) | | ||
912 | (hsic->tx_rslew_p << | ||
913 | XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT); | ||
914 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL0(index)); | ||
915 | |||
916 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(index)); | ||
917 | value &= ~((XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK << | ||
918 | XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) | | ||
919 | (XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK << | ||
920 | XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT)); | ||
921 | value |= (hsic->rx_strobe_trim << | ||
922 | XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) | | ||
923 | (hsic->rx_data_trim << | ||
924 | XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT); | ||
925 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL2(index)); | ||
926 | |||
927 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
928 | value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_RPD_STROBE | | ||
929 | XUSB_PADCTL_HSIC_PAD_CTL1_RPU_DATA | | ||
930 | XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX | | ||
931 | XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI | | ||
932 | XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX | | ||
933 | XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX); | ||
934 | value |= XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA | | ||
935 | XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE; | ||
936 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
937 | |||
938 | return 0; | ||
939 | } | ||
940 | |||
941 | static int tegra124_hsic_phy_power_off(struct phy *phy) | ||
942 | { | ||
943 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
944 | struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad); | ||
945 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
946 | unsigned int index = lane->index; | ||
947 | u32 value; | ||
948 | |||
949 | value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
950 | value |= XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX | | ||
951 | XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI | | ||
952 | XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX | | ||
953 | XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX; | ||
954 | padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index)); | ||
955 | |||
956 | regulator_disable(pad->supply); | ||
957 | |||
958 | return 0; | ||
959 | } | ||
960 | |||
961 | static const struct phy_ops tegra124_hsic_phy_ops = { | ||
962 | .init = tegra124_hsic_phy_init, | ||
963 | .exit = tegra124_hsic_phy_exit, | ||
964 | .power_on = tegra124_hsic_phy_power_on, | ||
965 | .power_off = tegra124_hsic_phy_power_off, | ||
966 | .owner = THIS_MODULE, | ||
967 | }; | ||
968 | |||
969 | static struct tegra_xusb_pad * | ||
970 | tegra124_hsic_pad_probe(struct tegra_xusb_padctl *padctl, | ||
971 | const struct tegra_xusb_pad_soc *soc, | ||
972 | struct device_node *np) | ||
973 | { | ||
974 | struct tegra_xusb_hsic_pad *hsic; | ||
975 | struct tegra_xusb_pad *pad; | ||
976 | int err; | ||
977 | |||
978 | hsic = kzalloc(sizeof(*hsic), GFP_KERNEL); | ||
979 | if (!hsic) | ||
980 | return ERR_PTR(-ENOMEM); | ||
981 | |||
982 | pad = &hsic->base; | ||
983 | pad->ops = &tegra124_hsic_lane_ops; | ||
984 | pad->soc = soc; | ||
985 | |||
986 | err = tegra_xusb_pad_init(pad, padctl, np); | ||
987 | if (err < 0) { | ||
988 | kfree(hsic); | ||
989 | goto out; | ||
990 | } | ||
991 | |||
992 | err = tegra_xusb_pad_register(pad, &tegra124_hsic_phy_ops); | ||
993 | if (err < 0) | ||
994 | goto unregister; | ||
995 | |||
996 | dev_set_drvdata(&pad->dev, pad); | ||
997 | |||
998 | return pad; | ||
999 | |||
1000 | unregister: | ||
1001 | device_unregister(&pad->dev); | ||
1002 | out: | ||
1003 | return ERR_PTR(err); | ||
1004 | } | ||
1005 | |||
1006 | static void tegra124_hsic_pad_remove(struct tegra_xusb_pad *pad) | ||
1007 | { | ||
1008 | struct tegra_xusb_hsic_pad *hsic = to_hsic_pad(pad); | ||
1009 | |||
1010 | kfree(hsic); | ||
1011 | } | ||
1012 | |||
1013 | static const struct tegra_xusb_pad_ops tegra124_hsic_ops = { | ||
1014 | .probe = tegra124_hsic_pad_probe, | ||
1015 | .remove = tegra124_hsic_pad_remove, | ||
1016 | }; | ||
1017 | |||
1018 | static const struct tegra_xusb_pad_soc tegra124_hsic_pad = { | ||
1019 | .name = "hsic", | ||
1020 | .num_lanes = ARRAY_SIZE(tegra124_hsic_lanes), | ||
1021 | .lanes = tegra124_hsic_lanes, | ||
1022 | .ops = &tegra124_hsic_ops, | ||
1023 | }; | ||
1024 | |||
1025 | static const char * const tegra124_pcie_functions[] = { | ||
1026 | "pcie", | ||
1027 | "usb3-ss", | ||
1028 | "sata", | ||
1029 | }; | ||
1030 | |||
1031 | static const struct tegra_xusb_lane_soc tegra124_pcie_lanes[] = { | ||
1032 | TEGRA124_LANE("pcie-0", 0x134, 16, 0x3, pcie), | ||
1033 | TEGRA124_LANE("pcie-1", 0x134, 18, 0x3, pcie), | ||
1034 | TEGRA124_LANE("pcie-2", 0x134, 20, 0x3, pcie), | ||
1035 | TEGRA124_LANE("pcie-3", 0x134, 22, 0x3, pcie), | ||
1036 | TEGRA124_LANE("pcie-4", 0x134, 24, 0x3, pcie), | ||
1037 | }; | ||
1038 | |||
1039 | static struct tegra_xusb_lane * | ||
1040 | tegra124_pcie_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, | ||
1041 | unsigned int index) | ||
1042 | { | ||
1043 | struct tegra_xusb_pcie_lane *pcie; | ||
1044 | int err; | ||
1045 | |||
1046 | pcie = kzalloc(sizeof(*pcie), GFP_KERNEL); | ||
1047 | if (!pcie) | ||
1048 | return ERR_PTR(-ENOMEM); | ||
1049 | |||
1050 | INIT_LIST_HEAD(&pcie->base.list); | ||
1051 | pcie->base.soc = &pad->soc->lanes[index]; | ||
1052 | pcie->base.index = index; | ||
1053 | pcie->base.pad = pad; | ||
1054 | pcie->base.np = np; | ||
1055 | |||
1056 | err = tegra_xusb_lane_parse_dt(&pcie->base, np); | ||
1057 | if (err < 0) { | ||
1058 | kfree(pcie); | ||
1059 | return ERR_PTR(err); | ||
1060 | } | ||
1061 | |||
1062 | return &pcie->base; | ||
1063 | } | ||
1064 | |||
1065 | static void tegra124_pcie_lane_remove(struct tegra_xusb_lane *lane) | ||
1066 | { | ||
1067 | struct tegra_xusb_pcie_lane *pcie = to_pcie_lane(lane); | ||
1068 | |||
1069 | kfree(pcie); | ||
1070 | } | ||
1071 | |||
1072 | static const struct tegra_xusb_lane_ops tegra124_pcie_lane_ops = { | ||
1073 | .probe = tegra124_pcie_lane_probe, | ||
1074 | .remove = tegra124_pcie_lane_remove, | ||
1075 | }; | ||
1076 | |||
1077 | static int tegra124_pcie_phy_init(struct phy *phy) | ||
1078 | { | ||
1079 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1080 | |||
1081 | return tegra124_xusb_padctl_enable(lane->pad->padctl); | ||
1082 | } | ||
1083 | |||
1084 | static int tegra124_pcie_phy_exit(struct phy *phy) | ||
1085 | { | ||
1086 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1087 | |||
1088 | return tegra124_xusb_padctl_disable(lane->pad->padctl); | ||
1089 | } | ||
1090 | |||
1091 | static int tegra124_pcie_phy_power_on(struct phy *phy) | ||
1092 | { | ||
1093 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1094 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
1095 | unsigned long timeout; | ||
1096 | int err = -ETIMEDOUT; | ||
1097 | u32 value; | ||
1098 | |||
1099 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
1100 | value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK; | ||
1101 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
1102 | |||
1103 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL2); | ||
1104 | value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN | | ||
1105 | XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN | | ||
1106 | XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL; | ||
1107 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL2); | ||
1108 | |||
1109 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
1110 | value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST; | ||
1111 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
1112 | |||
1113 | timeout = jiffies + msecs_to_jiffies(50); | ||
1114 | |||
1115 | while (time_before(jiffies, timeout)) { | ||
1116 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
1117 | if (value & XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET) { | ||
1118 | err = 0; | ||
1119 | break; | ||
1120 | } | ||
1121 | |||
1122 | usleep_range(100, 200); | ||
1123 | } | ||
1124 | |||
1125 | value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); | ||
1126 | value |= XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->index); | ||
1127 | padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); | ||
1128 | |||
1129 | return err; | ||
1130 | } | ||
1131 | |||
1132 | static int tegra124_pcie_phy_power_off(struct phy *phy) | ||
1133 | { | ||
1134 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1135 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
1136 | u32 value; | ||
1137 | |||
1138 | value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); | ||
1139 | value &= ~XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->index); | ||
1140 | padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); | ||
1141 | |||
1142 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
1143 | value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST; | ||
1144 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); | ||
1145 | |||
1146 | return 0; | ||
1147 | } | ||
1148 | |||
1149 | static const struct phy_ops tegra124_pcie_phy_ops = { | ||
1150 | .init = tegra124_pcie_phy_init, | ||
1151 | .exit = tegra124_pcie_phy_exit, | ||
1152 | .power_on = tegra124_pcie_phy_power_on, | ||
1153 | .power_off = tegra124_pcie_phy_power_off, | ||
1154 | .owner = THIS_MODULE, | ||
1155 | }; | ||
1156 | |||
1157 | static struct tegra_xusb_pad * | ||
1158 | tegra124_pcie_pad_probe(struct tegra_xusb_padctl *padctl, | ||
1159 | const struct tegra_xusb_pad_soc *soc, | ||
1160 | struct device_node *np) | ||
1161 | { | ||
1162 | struct tegra_xusb_pcie_pad *pcie; | ||
1163 | struct tegra_xusb_pad *pad; | ||
1164 | int err; | ||
1165 | |||
1166 | pcie = kzalloc(sizeof(*pcie), GFP_KERNEL); | ||
1167 | if (!pcie) | ||
1168 | return ERR_PTR(-ENOMEM); | ||
1169 | |||
1170 | pad = &pcie->base; | ||
1171 | pad->ops = &tegra124_pcie_lane_ops; | ||
1172 | pad->soc = soc; | ||
1173 | |||
1174 | err = tegra_xusb_pad_init(pad, padctl, np); | ||
1175 | if (err < 0) { | ||
1176 | kfree(pcie); | ||
1177 | goto out; | ||
1178 | } | ||
1179 | |||
1180 | err = tegra_xusb_pad_register(pad, &tegra124_pcie_phy_ops); | ||
1181 | if (err < 0) | ||
1182 | goto unregister; | ||
1183 | |||
1184 | dev_set_drvdata(&pad->dev, pad); | ||
1185 | |||
1186 | return pad; | ||
1187 | |||
1188 | unregister: | ||
1189 | device_unregister(&pad->dev); | ||
1190 | out: | ||
1191 | return ERR_PTR(err); | ||
1192 | } | ||
1193 | |||
1194 | static void tegra124_pcie_pad_remove(struct tegra_xusb_pad *pad) | ||
1195 | { | ||
1196 | struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(pad); | ||
1197 | |||
1198 | kfree(pcie); | ||
1199 | } | ||
1200 | |||
1201 | static const struct tegra_xusb_pad_ops tegra124_pcie_ops = { | ||
1202 | .probe = tegra124_pcie_pad_probe, | ||
1203 | .remove = tegra124_pcie_pad_remove, | ||
1204 | }; | ||
1205 | |||
1206 | static const struct tegra_xusb_pad_soc tegra124_pcie_pad = { | ||
1207 | .name = "pcie", | ||
1208 | .num_lanes = ARRAY_SIZE(tegra124_pcie_lanes), | ||
1209 | .lanes = tegra124_pcie_lanes, | ||
1210 | .ops = &tegra124_pcie_ops, | ||
1211 | }; | ||
1212 | |||
1213 | static const struct tegra_xusb_lane_soc tegra124_sata_lanes[] = { | ||
1214 | TEGRA124_LANE("sata-0", 0x134, 26, 0x3, pcie), | ||
1215 | }; | ||
1216 | |||
1217 | static struct tegra_xusb_lane * | ||
1218 | tegra124_sata_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, | ||
1219 | unsigned int index) | ||
1220 | { | ||
1221 | struct tegra_xusb_sata_lane *sata; | ||
1222 | int err; | ||
1223 | |||
1224 | sata = kzalloc(sizeof(*sata), GFP_KERNEL); | ||
1225 | if (!sata) | ||
1226 | return ERR_PTR(-ENOMEM); | ||
1227 | |||
1228 | INIT_LIST_HEAD(&sata->base.list); | ||
1229 | sata->base.soc = &pad->soc->lanes[index]; | ||
1230 | sata->base.index = index; | ||
1231 | sata->base.pad = pad; | ||
1232 | sata->base.np = np; | ||
1233 | |||
1234 | err = tegra_xusb_lane_parse_dt(&sata->base, np); | ||
1235 | if (err < 0) { | ||
1236 | kfree(sata); | ||
1237 | return ERR_PTR(err); | ||
1238 | } | ||
1239 | |||
1240 | return &sata->base; | ||
1241 | } | ||
1242 | |||
1243 | static void tegra124_sata_lane_remove(struct tegra_xusb_lane *lane) | ||
1244 | { | ||
1245 | struct tegra_xusb_sata_lane *sata = to_sata_lane(lane); | ||
1246 | |||
1247 | kfree(sata); | ||
1248 | } | ||
1249 | |||
1250 | static const struct tegra_xusb_lane_ops tegra124_sata_lane_ops = { | ||
1251 | .probe = tegra124_sata_lane_probe, | ||
1252 | .remove = tegra124_sata_lane_remove, | ||
1253 | }; | ||
1254 | |||
1255 | static int tegra124_sata_phy_init(struct phy *phy) | ||
1256 | { | ||
1257 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1258 | |||
1259 | return tegra124_xusb_padctl_enable(lane->pad->padctl); | ||
1260 | } | ||
1261 | |||
1262 | static int tegra124_sata_phy_exit(struct phy *phy) | ||
1263 | { | ||
1264 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1265 | |||
1266 | return tegra124_xusb_padctl_disable(lane->pad->padctl); | ||
1267 | } | ||
1268 | |||
1269 | static int tegra124_sata_phy_power_on(struct phy *phy) | ||
1270 | { | ||
1271 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1272 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
1273 | unsigned long timeout; | ||
1274 | int err = -ETIMEDOUT; | ||
1275 | u32 value; | ||
1276 | |||
1277 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); | ||
1278 | value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; | ||
1279 | value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ; | ||
1280 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); | ||
1281 | |||
1282 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1283 | value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; | ||
1284 | value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ; | ||
1285 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1286 | |||
1287 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1288 | value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE; | ||
1289 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1290 | |||
1291 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1292 | value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST; | ||
1293 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1294 | |||
1295 | timeout = jiffies + msecs_to_jiffies(50); | ||
1296 | |||
1297 | while (time_before(jiffies, timeout)) { | ||
1298 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1299 | if (value & XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET) { | ||
1300 | err = 0; | ||
1301 | break; | ||
1302 | } | ||
1303 | |||
1304 | usleep_range(100, 200); | ||
1305 | } | ||
1306 | |||
1307 | value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); | ||
1308 | value |= XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(lane->index); | ||
1309 | padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); | ||
1310 | |||
1311 | return err; | ||
1312 | } | ||
1313 | |||
1314 | static int tegra124_sata_phy_power_off(struct phy *phy) | ||
1315 | { | ||
1316 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
1317 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
1318 | u32 value; | ||
1319 | |||
1320 | value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); | ||
1321 | value &= ~XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(lane->index); | ||
1322 | padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); | ||
1323 | |||
1324 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1325 | value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST; | ||
1326 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1327 | |||
1328 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1329 | value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE; | ||
1330 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1331 | |||
1332 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1333 | value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; | ||
1334 | value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ; | ||
1335 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1336 | |||
1337 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); | ||
1338 | value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; | ||
1339 | value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ; | ||
1340 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); | ||
1341 | |||
1342 | return 0; | ||
1343 | } | ||
1344 | |||
1345 | static const struct phy_ops tegra124_sata_phy_ops = { | ||
1346 | .init = tegra124_sata_phy_init, | ||
1347 | .exit = tegra124_sata_phy_exit, | ||
1348 | .power_on = tegra124_sata_phy_power_on, | ||
1349 | .power_off = tegra124_sata_phy_power_off, | ||
1350 | .owner = THIS_MODULE, | ||
1351 | }; | ||
1352 | |||
1353 | static struct tegra_xusb_pad * | ||
1354 | tegra124_sata_pad_probe(struct tegra_xusb_padctl *padctl, | ||
1355 | const struct tegra_xusb_pad_soc *soc, | ||
1356 | struct device_node *np) | ||
1357 | { | ||
1358 | struct tegra_xusb_sata_pad *sata; | ||
1359 | struct tegra_xusb_pad *pad; | ||
1360 | int err; | ||
1361 | |||
1362 | sata = kzalloc(sizeof(*sata), GFP_KERNEL); | ||
1363 | if (!sata) | ||
1364 | return ERR_PTR(-ENOMEM); | ||
1365 | |||
1366 | pad = &sata->base; | ||
1367 | pad->ops = &tegra124_sata_lane_ops; | ||
1368 | pad->soc = soc; | ||
1369 | |||
1370 | err = tegra_xusb_pad_init(pad, padctl, np); | ||
1371 | if (err < 0) { | ||
1372 | kfree(sata); | ||
1373 | goto out; | ||
1374 | } | ||
1375 | |||
1376 | err = tegra_xusb_pad_register(pad, &tegra124_sata_phy_ops); | ||
1377 | if (err < 0) | ||
1378 | goto unregister; | ||
1379 | |||
1380 | dev_set_drvdata(&pad->dev, pad); | ||
1381 | |||
1382 | return pad; | ||
1383 | |||
1384 | unregister: | ||
1385 | device_unregister(&pad->dev); | ||
1386 | out: | ||
1387 | return ERR_PTR(err); | ||
1388 | } | ||
1389 | |||
1390 | static void tegra124_sata_pad_remove(struct tegra_xusb_pad *pad) | ||
1391 | { | ||
1392 | struct tegra_xusb_sata_pad *sata = to_sata_pad(pad); | ||
1393 | |||
1394 | kfree(sata); | ||
1395 | } | ||
1396 | |||
1397 | static const struct tegra_xusb_pad_ops tegra124_sata_ops = { | ||
1398 | .probe = tegra124_sata_pad_probe, | ||
1399 | .remove = tegra124_sata_pad_remove, | ||
1400 | }; | ||
1401 | |||
1402 | static const struct tegra_xusb_pad_soc tegra124_sata_pad = { | ||
1403 | .name = "sata", | ||
1404 | .num_lanes = ARRAY_SIZE(tegra124_sata_lanes), | ||
1405 | .lanes = tegra124_sata_lanes, | ||
1406 | .ops = &tegra124_sata_ops, | ||
1407 | }; | ||
1408 | |||
1409 | static const struct tegra_xusb_pad_soc *tegra124_pads[] = { | ||
1410 | &tegra124_usb2_pad, | ||
1411 | &tegra124_ulpi_pad, | ||
1412 | &tegra124_hsic_pad, | ||
1413 | &tegra124_pcie_pad, | ||
1414 | &tegra124_sata_pad, | ||
1415 | }; | ||
1416 | |||
1417 | static int tegra124_usb2_port_enable(struct tegra_xusb_port *port) | ||
1418 | { | ||
1419 | return 0; | ||
1420 | } | ||
1421 | |||
1422 | static void tegra124_usb2_port_disable(struct tegra_xusb_port *port) | ||
1423 | { | ||
1424 | } | ||
1425 | |||
1426 | static struct tegra_xusb_lane * | ||
1427 | tegra124_usb2_port_map(struct tegra_xusb_port *port) | ||
1428 | { | ||
1429 | return tegra_xusb_find_lane(port->padctl, "usb2", port->index); | ||
1430 | } | ||
1431 | |||
1432 | static const struct tegra_xusb_port_ops tegra124_usb2_port_ops = { | ||
1433 | .enable = tegra124_usb2_port_enable, | ||
1434 | .disable = tegra124_usb2_port_disable, | ||
1435 | .map = tegra124_usb2_port_map, | ||
1436 | }; | ||
1437 | |||
1438 | static int tegra124_ulpi_port_enable(struct tegra_xusb_port *port) | ||
1439 | { | ||
1440 | return 0; | ||
1441 | } | ||
1442 | |||
1443 | static void tegra124_ulpi_port_disable(struct tegra_xusb_port *port) | ||
1444 | { | ||
1445 | } | ||
1446 | |||
1447 | static struct tegra_xusb_lane * | ||
1448 | tegra124_ulpi_port_map(struct tegra_xusb_port *port) | ||
1449 | { | ||
1450 | return tegra_xusb_find_lane(port->padctl, "ulpi", port->index); | ||
1451 | } | ||
1452 | |||
1453 | static const struct tegra_xusb_port_ops tegra124_ulpi_port_ops = { | ||
1454 | .enable = tegra124_ulpi_port_enable, | ||
1455 | .disable = tegra124_ulpi_port_disable, | ||
1456 | .map = tegra124_ulpi_port_map, | ||
1457 | }; | ||
1458 | |||
1459 | static int tegra124_hsic_port_enable(struct tegra_xusb_port *port) | ||
1460 | { | ||
1461 | return 0; | ||
1462 | } | ||
1463 | |||
1464 | static void tegra124_hsic_port_disable(struct tegra_xusb_port *port) | ||
1465 | { | ||
1466 | } | ||
1467 | |||
1468 | static struct tegra_xusb_lane * | ||
1469 | tegra124_hsic_port_map(struct tegra_xusb_port *port) | ||
1470 | { | ||
1471 | return tegra_xusb_find_lane(port->padctl, "hsic", port->index); | ||
1472 | } | ||
1473 | |||
1474 | static const struct tegra_xusb_port_ops tegra124_hsic_port_ops = { | ||
1475 | .enable = tegra124_hsic_port_enable, | ||
1476 | .disable = tegra124_hsic_port_disable, | ||
1477 | .map = tegra124_hsic_port_map, | ||
1478 | }; | ||
1479 | |||
1480 | static int tegra124_usb3_port_enable(struct tegra_xusb_port *port) | ||
1481 | { | ||
1482 | struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port); | ||
1483 | struct tegra_xusb_padctl *padctl = port->padctl; | ||
1484 | struct tegra_xusb_lane *lane = usb3->base.lane; | ||
1485 | unsigned int index = port->index, offset; | ||
1486 | int ret = 0; | ||
1487 | u32 value; | ||
1488 | |||
1489 | value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); | ||
1490 | |||
1491 | if (!usb3->internal) | ||
1492 | value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index); | ||
1493 | else | ||
1494 | value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index); | ||
1495 | |||
1496 | value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(index); | ||
1497 | value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(index, usb3->port); | ||
1498 | padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP); | ||
1499 | |||
1500 | /* | ||
1501 | * TODO: move this code into the PCIe/SATA PHY ->power_on() callbacks | ||
1502 | * and conditionalize based on mux function? This seems to work, but | ||
1503 | * might not be the exact proper sequence. | ||
1504 | */ | ||
1505 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(index)); | ||
1506 | value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK << | ||
1507 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) | | ||
1508 | (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK << | ||
1509 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) | | ||
1510 | (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK << | ||
1511 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT)); | ||
1512 | value |= (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_VAL << | ||
1513 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) | | ||
1514 | (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_VAL << | ||
1515 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT) | | ||
1516 | (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_VAL << | ||
1517 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT); | ||
1518 | |||
1519 | if (usb3->context_saved) { | ||
1520 | value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK << | ||
1521 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) | | ||
1522 | (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK << | ||
1523 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT)); | ||
1524 | value |= (usb3->ctle_g << | ||
1525 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) | | ||
1526 | (usb3->ctle_z << | ||
1527 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT); | ||
1528 | } | ||
1529 | |||
1530 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(index)); | ||
1531 | |||
1532 | value = XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_VAL; | ||
1533 | |||
1534 | if (usb3->context_saved) { | ||
1535 | value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK << | ||
1536 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) | | ||
1537 | (XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK << | ||
1538 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT)); | ||
1539 | value |= (usb3->tap1 << | ||
1540 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) | | ||
1541 | (usb3->amp << | ||
1542 | XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT); | ||
1543 | } | ||
1544 | |||
1545 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(index)); | ||
1546 | |||
1547 | if (lane->pad == padctl->pcie) | ||
1548 | offset = XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL2(lane->index); | ||
1549 | else | ||
1550 | offset = XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2; | ||
1551 | |||
1552 | value = padctl_readl(padctl, offset); | ||
1553 | value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_MASK << | ||
1554 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT); | ||
1555 | value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_VAL << | ||
1556 | XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT; | ||
1557 | padctl_writel(padctl, value, offset); | ||
1558 | |||
1559 | if (lane->pad == padctl->pcie) | ||
1560 | offset = XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL5(lane->index); | ||
1561 | else | ||
1562 | offset = XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5; | ||
1563 | |||
1564 | value = padctl_readl(padctl, offset); | ||
1565 | value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL5_RX_QEYE_EN; | ||
1566 | padctl_writel(padctl, value, offset); | ||
1567 | |||
1568 | /* Enable SATA PHY when SATA lane is used */ | ||
1569 | if (lane->pad == padctl->sata) { | ||
1570 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1571 | value &= ~(XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_MASK << | ||
1572 | XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_SHIFT); | ||
1573 | value |= 0x2 << | ||
1574 | XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_SHIFT; | ||
1575 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); | ||
1576 | |||
1577 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL2); | ||
1578 | value &= ~((XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_MASK << | ||
1579 | XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_SHIFT) | | ||
1580 | (XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_MASK << | ||
1581 | XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_SHIFT) | | ||
1582 | (XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_MASK << | ||
1583 | XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_SHIFT) | | ||
1584 | XUSB_PADCTL_IOPHY_PLL_S0_CTL2_TCLKOUT_EN); | ||
1585 | value |= (0x7 << | ||
1586 | XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_SHIFT) | | ||
1587 | (0x8 << | ||
1588 | XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_SHIFT) | | ||
1589 | (0x8 << | ||
1590 | XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_SHIFT) | | ||
1591 | XUSB_PADCTL_IOPHY_PLL_S0_CTL2_TXCLKREF_SEL; | ||
1592 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL2); | ||
1593 | |||
1594 | value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL3); | ||
1595 | value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL3_RCAL_BYPASS; | ||
1596 | padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL3); | ||
1597 | } | ||
1598 | |||
1599 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
1600 | value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(index); | ||
1601 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
1602 | |||
1603 | usleep_range(100, 200); | ||
1604 | |||
1605 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
1606 | value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(index); | ||
1607 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
1608 | |||
1609 | usleep_range(100, 200); | ||
1610 | |||
1611 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
1612 | value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN(index); | ||
1613 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
1614 | |||
1615 | return ret; | ||
1616 | } | ||
1617 | |||
1618 | static void tegra124_usb3_port_disable(struct tegra_xusb_port *port) | ||
1619 | { | ||
1620 | struct tegra_xusb_padctl *padctl = port->padctl; | ||
1621 | u32 value; | ||
1622 | |||
1623 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
1624 | value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port->index); | ||
1625 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
1626 | |||
1627 | usleep_range(100, 200); | ||
1628 | |||
1629 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
1630 | value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN(port->index); | ||
1631 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
1632 | |||
1633 | usleep_range(250, 350); | ||
1634 | |||
1635 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); | ||
1636 | value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(port->index); | ||
1637 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); | ||
1638 | |||
1639 | value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); | ||
1640 | value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(port->index); | ||
1641 | value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(port->index, 0x7); | ||
1642 | padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP); | ||
1643 | } | ||
1644 | |||
1645 | static const struct tegra_xusb_lane_map tegra124_usb3_map[] = { | ||
1646 | { 0, "pcie", 0 }, | ||
1647 | { 1, "pcie", 1 }, | ||
1648 | { 1, "sata", 0 }, | ||
1649 | { 0, NULL, 0 }, | ||
1650 | }; | ||
1651 | |||
1652 | static struct tegra_xusb_lane * | ||
1653 | tegra124_usb3_port_map(struct tegra_xusb_port *port) | ||
1654 | { | ||
1655 | return tegra_xusb_port_find_lane(port, tegra124_usb3_map, "usb3-ss"); | ||
1656 | } | ||
1657 | |||
1658 | static const struct tegra_xusb_port_ops tegra124_usb3_port_ops = { | ||
1659 | .enable = tegra124_usb3_port_enable, | ||
1660 | .disable = tegra124_usb3_port_disable, | ||
1661 | .map = tegra124_usb3_port_map, | ||
1662 | }; | ||
1663 | |||
1664 | static int | ||
1665 | tegra124_xusb_read_fuse_calibration(struct tegra124_xusb_fuse_calibration *fuse) | ||
1666 | { | ||
1667 | unsigned int i; | ||
1668 | int err; | ||
1669 | u32 value; | ||
1670 | |||
1671 | err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value); | ||
1672 | if (err < 0) | ||
1673 | return err; | ||
1674 | |||
1675 | for (i = 0; i < ARRAY_SIZE(fuse->hs_curr_level); i++) { | ||
1676 | fuse->hs_curr_level[i] = | ||
1677 | (value >> FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(i)) & | ||
1678 | FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK; | ||
1679 | } | ||
1680 | fuse->hs_iref_cap = | ||
1681 | (value >> FUSE_SKU_CALIB_HS_IREF_CAP_SHIFT) & | ||
1682 | FUSE_SKU_CALIB_HS_IREF_CAP_MASK; | ||
1683 | fuse->hs_term_range_adj = | ||
1684 | (value >> FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT) & | ||
1685 | FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK; | ||
1686 | fuse->hs_squelch_level = | ||
1687 | (value >> FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_SHIFT) & | ||
1688 | FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_MASK; | ||
1689 | |||
1690 | return 0; | ||
1691 | } | ||
1692 | |||
1693 | static struct tegra_xusb_padctl * | ||
1694 | tegra124_xusb_padctl_probe(struct device *dev, | ||
1695 | const struct tegra_xusb_padctl_soc *soc) | ||
1696 | { | ||
1697 | struct tegra124_xusb_padctl *padctl; | ||
1698 | int err; | ||
1699 | |||
1700 | padctl = devm_kzalloc(dev, sizeof(*padctl), GFP_KERNEL); | ||
1701 | if (!padctl) | ||
1702 | return ERR_PTR(-ENOMEM); | ||
1703 | |||
1704 | padctl->base.dev = dev; | ||
1705 | padctl->base.soc = soc; | ||
1706 | |||
1707 | err = tegra124_xusb_read_fuse_calibration(&padctl->fuse); | ||
1708 | if (err < 0) | ||
1709 | return ERR_PTR(err); | ||
1710 | |||
1711 | return &padctl->base; | ||
1712 | } | ||
1713 | |||
1714 | static void tegra124_xusb_padctl_remove(struct tegra_xusb_padctl *padctl) | ||
1715 | { | ||
1716 | } | ||
1717 | |||
1718 | static const struct tegra_xusb_padctl_ops tegra124_xusb_padctl_ops = { | ||
1719 | .probe = tegra124_xusb_padctl_probe, | ||
1720 | .remove = tegra124_xusb_padctl_remove, | ||
1721 | .usb3_save_context = tegra124_usb3_save_context, | ||
1722 | .hsic_set_idle = tegra124_hsic_set_idle, | ||
1723 | }; | ||
1724 | |||
1725 | const struct tegra_xusb_padctl_soc tegra124_xusb_padctl_soc = { | ||
1726 | .num_pads = ARRAY_SIZE(tegra124_pads), | ||
1727 | .pads = tegra124_pads, | ||
1728 | .ports = { | ||
1729 | .usb2 = { | ||
1730 | .ops = &tegra124_usb2_port_ops, | ||
1731 | .count = 3, | ||
1732 | }, | ||
1733 | .ulpi = { | ||
1734 | .ops = &tegra124_ulpi_port_ops, | ||
1735 | .count = 1, | ||
1736 | }, | ||
1737 | .hsic = { | ||
1738 | .ops = &tegra124_hsic_port_ops, | ||
1739 | .count = 2, | ||
1740 | }, | ||
1741 | .usb3 = { | ||
1742 | .ops = &tegra124_usb3_port_ops, | ||
1743 | .count = 2, | ||
1744 | }, | ||
1745 | }, | ||
1746 | .ops = &tegra124_xusb_padctl_ops, | ||
1747 | }; | ||
1748 | EXPORT_SYMBOL_GPL(tegra124_xusb_padctl_soc); | ||
1749 | |||
1750 | MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); | ||
1751 | MODULE_DESCRIPTION("NVIDIA Tegra 124 XUSB Pad Controller driver"); | ||
1752 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c new file mode 100644 index 000000000000..ec83dfdbc206 --- /dev/null +++ b/drivers/phy/tegra/xusb.c | |||
@@ -0,0 +1,1021 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/mailbox_client.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/of_device.h> | ||
20 | #include <linux/phy/phy.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/regulator/consumer.h> | ||
23 | #include <linux/reset.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/workqueue.h> | ||
26 | |||
27 | #include <soc/tegra/fuse.h> | ||
28 | |||
29 | #include "xusb.h" | ||
30 | |||
31 | static struct phy *tegra_xusb_pad_of_xlate(struct device *dev, | ||
32 | struct of_phandle_args *args) | ||
33 | { | ||
34 | struct tegra_xusb_pad *pad = dev_get_drvdata(dev); | ||
35 | struct phy *phy = NULL; | ||
36 | unsigned int i; | ||
37 | |||
38 | if (args->args_count != 0) | ||
39 | return ERR_PTR(-EINVAL); | ||
40 | |||
41 | for (i = 0; i < pad->soc->num_lanes; i++) { | ||
42 | if (!pad->lanes[i]) | ||
43 | continue; | ||
44 | |||
45 | if (pad->lanes[i]->dev.of_node == args->np) { | ||
46 | phy = pad->lanes[i]; | ||
47 | break; | ||
48 | } | ||
49 | } | ||
50 | |||
51 | if (phy == NULL) | ||
52 | phy = ERR_PTR(-ENODEV); | ||
53 | |||
54 | return phy; | ||
55 | } | ||
56 | |||
57 | static const struct of_device_id tegra_xusb_padctl_of_match[] = { | ||
58 | #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC) | ||
59 | { | ||
60 | .compatible = "nvidia,tegra124-xusb-padctl", | ||
61 | .data = &tegra124_xusb_padctl_soc, | ||
62 | }, | ||
63 | #endif | ||
64 | #if defined(CONFIG_ARCH_TEGRA_210_SOC) | ||
65 | { | ||
66 | .compatible = "nvidia,tegra210-xusb-padctl", | ||
67 | .data = &tegra210_xusb_padctl_soc, | ||
68 | }, | ||
69 | #endif | ||
70 | { } | ||
71 | }; | ||
72 | MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match); | ||
73 | |||
74 | static struct device_node * | ||
75 | tegra_xusb_find_pad_node(struct tegra_xusb_padctl *padctl, const char *name) | ||
76 | { | ||
77 | /* | ||
78 | * of_find_node_by_name() drops a reference, so make sure to grab one. | ||
79 | */ | ||
80 | struct device_node *np = of_node_get(padctl->dev->of_node); | ||
81 | |||
82 | np = of_find_node_by_name(np, "pads"); | ||
83 | if (np) | ||
84 | np = of_find_node_by_name(np, name); | ||
85 | |||
86 | return np; | ||
87 | } | ||
88 | |||
89 | static struct device_node * | ||
90 | tegra_xusb_pad_find_phy_node(struct tegra_xusb_pad *pad, unsigned int index) | ||
91 | { | ||
92 | /* | ||
93 | * of_find_node_by_name() drops a reference, so make sure to grab one. | ||
94 | */ | ||
95 | struct device_node *np = of_node_get(pad->dev.of_node); | ||
96 | |||
97 | np = of_find_node_by_name(np, "lanes"); | ||
98 | if (!np) | ||
99 | return NULL; | ||
100 | |||
101 | return of_find_node_by_name(np, pad->soc->lanes[index].name); | ||
102 | } | ||
103 | |||
104 | int tegra_xusb_lane_lookup_function(struct tegra_xusb_lane *lane, | ||
105 | const char *function) | ||
106 | { | ||
107 | unsigned int i; | ||
108 | |||
109 | for (i = 0; i < lane->soc->num_funcs; i++) | ||
110 | if (strcmp(function, lane->soc->funcs[i]) == 0) | ||
111 | return i; | ||
112 | |||
113 | return -EINVAL; | ||
114 | } | ||
115 | |||
116 | int tegra_xusb_lane_parse_dt(struct tegra_xusb_lane *lane, | ||
117 | struct device_node *np) | ||
118 | { | ||
119 | struct device *dev = &lane->pad->dev; | ||
120 | const char *function; | ||
121 | int err; | ||
122 | |||
123 | err = of_property_read_string(np, "nvidia,function", &function); | ||
124 | if (err < 0) | ||
125 | return err; | ||
126 | |||
127 | err = tegra_xusb_lane_lookup_function(lane, function); | ||
128 | if (err < 0) { | ||
129 | dev_err(dev, "invalid function \"%s\" for lane \"%s\"\n", | ||
130 | function, np->name); | ||
131 | return err; | ||
132 | } | ||
133 | |||
134 | lane->function = err; | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static void tegra_xusb_lane_destroy(struct phy *phy) | ||
140 | { | ||
141 | if (phy) { | ||
142 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
143 | |||
144 | lane->pad->ops->remove(lane); | ||
145 | phy_destroy(phy); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void tegra_xusb_pad_release(struct device *dev) | ||
150 | { | ||
151 | struct tegra_xusb_pad *pad = to_tegra_xusb_pad(dev); | ||
152 | |||
153 | pad->soc->ops->remove(pad); | ||
154 | } | ||
155 | |||
156 | static struct device_type tegra_xusb_pad_type = { | ||
157 | .release = tegra_xusb_pad_release, | ||
158 | }; | ||
159 | |||
160 | int tegra_xusb_pad_init(struct tegra_xusb_pad *pad, | ||
161 | struct tegra_xusb_padctl *padctl, | ||
162 | struct device_node *np) | ||
163 | { | ||
164 | int err; | ||
165 | |||
166 | device_initialize(&pad->dev); | ||
167 | INIT_LIST_HEAD(&pad->list); | ||
168 | pad->dev.parent = padctl->dev; | ||
169 | pad->dev.type = &tegra_xusb_pad_type; | ||
170 | pad->dev.of_node = np; | ||
171 | pad->padctl = padctl; | ||
172 | |||
173 | err = dev_set_name(&pad->dev, "%s", pad->soc->name); | ||
174 | if (err < 0) | ||
175 | goto unregister; | ||
176 | |||
177 | err = device_add(&pad->dev); | ||
178 | if (err < 0) | ||
179 | goto unregister; | ||
180 | |||
181 | return 0; | ||
182 | |||
183 | unregister: | ||
184 | device_unregister(&pad->dev); | ||
185 | return err; | ||
186 | } | ||
187 | |||
188 | int tegra_xusb_pad_register(struct tegra_xusb_pad *pad, | ||
189 | const struct phy_ops *ops) | ||
190 | { | ||
191 | struct device_node *children; | ||
192 | struct phy *lane; | ||
193 | unsigned int i; | ||
194 | int err; | ||
195 | |||
196 | children = of_find_node_by_name(pad->dev.of_node, "lanes"); | ||
197 | if (!children) | ||
198 | return -ENODEV; | ||
199 | |||
200 | pad->lanes = devm_kcalloc(&pad->dev, pad->soc->num_lanes, sizeof(lane), | ||
201 | GFP_KERNEL); | ||
202 | if (!pad->lanes) { | ||
203 | of_node_put(children); | ||
204 | return -ENOMEM; | ||
205 | } | ||
206 | |||
207 | for (i = 0; i < pad->soc->num_lanes; i++) { | ||
208 | struct device_node *np = tegra_xusb_pad_find_phy_node(pad, i); | ||
209 | struct tegra_xusb_lane *lane; | ||
210 | |||
211 | /* skip disabled lanes */ | ||
212 | if (!np || !of_device_is_available(np)) { | ||
213 | of_node_put(np); | ||
214 | continue; | ||
215 | } | ||
216 | |||
217 | pad->lanes[i] = phy_create(&pad->dev, np, ops); | ||
218 | if (IS_ERR(pad->lanes[i])) { | ||
219 | err = PTR_ERR(pad->lanes[i]); | ||
220 | of_node_put(np); | ||
221 | goto remove; | ||
222 | } | ||
223 | |||
224 | lane = pad->ops->probe(pad, np, i); | ||
225 | if (IS_ERR(lane)) { | ||
226 | phy_destroy(pad->lanes[i]); | ||
227 | err = PTR_ERR(lane); | ||
228 | goto remove; | ||
229 | } | ||
230 | |||
231 | list_add_tail(&lane->list, &pad->padctl->lanes); | ||
232 | phy_set_drvdata(pad->lanes[i], lane); | ||
233 | } | ||
234 | |||
235 | pad->provider = of_phy_provider_register_full(&pad->dev, children, | ||
236 | tegra_xusb_pad_of_xlate); | ||
237 | if (IS_ERR(pad->provider)) { | ||
238 | err = PTR_ERR(pad->provider); | ||
239 | goto remove; | ||
240 | } | ||
241 | |||
242 | return 0; | ||
243 | |||
244 | remove: | ||
245 | while (i--) | ||
246 | tegra_xusb_lane_destroy(pad->lanes[i]); | ||
247 | |||
248 | of_node_put(children); | ||
249 | |||
250 | return err; | ||
251 | } | ||
252 | |||
253 | void tegra_xusb_pad_unregister(struct tegra_xusb_pad *pad) | ||
254 | { | ||
255 | unsigned int i = pad->soc->num_lanes; | ||
256 | |||
257 | of_phy_provider_unregister(pad->provider); | ||
258 | |||
259 | while (i--) | ||
260 | tegra_xusb_lane_destroy(pad->lanes[i]); | ||
261 | |||
262 | device_unregister(&pad->dev); | ||
263 | } | ||
264 | |||
265 | static struct tegra_xusb_pad * | ||
266 | tegra_xusb_pad_create(struct tegra_xusb_padctl *padctl, | ||
267 | const struct tegra_xusb_pad_soc *soc) | ||
268 | { | ||
269 | struct tegra_xusb_pad *pad; | ||
270 | struct device_node *np; | ||
271 | int err; | ||
272 | |||
273 | np = tegra_xusb_find_pad_node(padctl, soc->name); | ||
274 | if (!np || !of_device_is_available(np)) | ||
275 | return NULL; | ||
276 | |||
277 | pad = soc->ops->probe(padctl, soc, np); | ||
278 | if (IS_ERR(pad)) { | ||
279 | err = PTR_ERR(pad); | ||
280 | dev_err(padctl->dev, "failed to create pad %s: %d\n", | ||
281 | soc->name, err); | ||
282 | return ERR_PTR(err); | ||
283 | } | ||
284 | |||
285 | /* XXX move this into ->probe() to avoid string comparison */ | ||
286 | if (strcmp(soc->name, "pcie") == 0) | ||
287 | padctl->pcie = pad; | ||
288 | |||
289 | if (strcmp(soc->name, "sata") == 0) | ||
290 | padctl->sata = pad; | ||
291 | |||
292 | if (strcmp(soc->name, "usb2") == 0) | ||
293 | padctl->usb2 = pad; | ||
294 | |||
295 | if (strcmp(soc->name, "ulpi") == 0) | ||
296 | padctl->ulpi = pad; | ||
297 | |||
298 | if (strcmp(soc->name, "hsic") == 0) | ||
299 | padctl->hsic = pad; | ||
300 | |||
301 | return pad; | ||
302 | } | ||
303 | |||
304 | static void __tegra_xusb_remove_pads(struct tegra_xusb_padctl *padctl) | ||
305 | { | ||
306 | struct tegra_xusb_pad *pad, *tmp; | ||
307 | |||
308 | list_for_each_entry_safe_reverse(pad, tmp, &padctl->pads, list) { | ||
309 | list_del(&pad->list); | ||
310 | tegra_xusb_pad_unregister(pad); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | static void tegra_xusb_remove_pads(struct tegra_xusb_padctl *padctl) | ||
315 | { | ||
316 | mutex_lock(&padctl->lock); | ||
317 | __tegra_xusb_remove_pads(padctl); | ||
318 | mutex_unlock(&padctl->lock); | ||
319 | } | ||
320 | |||
321 | static void tegra_xusb_lane_program(struct tegra_xusb_lane *lane) | ||
322 | { | ||
323 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
324 | const struct tegra_xusb_lane_soc *soc = lane->soc; | ||
325 | u32 value; | ||
326 | |||
327 | /* choose function */ | ||
328 | value = padctl_readl(padctl, soc->offset); | ||
329 | value &= ~(soc->mask << soc->shift); | ||
330 | value |= lane->function << soc->shift; | ||
331 | padctl_writel(padctl, value, soc->offset); | ||
332 | } | ||
333 | |||
334 | static void tegra_xusb_pad_program(struct tegra_xusb_pad *pad) | ||
335 | { | ||
336 | unsigned int i; | ||
337 | |||
338 | for (i = 0; i < pad->soc->num_lanes; i++) { | ||
339 | struct tegra_xusb_lane *lane; | ||
340 | |||
341 | if (pad->lanes[i]) { | ||
342 | lane = phy_get_drvdata(pad->lanes[i]); | ||
343 | tegra_xusb_lane_program(lane); | ||
344 | } | ||
345 | } | ||
346 | } | ||
347 | |||
348 | static int tegra_xusb_setup_pads(struct tegra_xusb_padctl *padctl) | ||
349 | { | ||
350 | struct tegra_xusb_pad *pad; | ||
351 | unsigned int i; | ||
352 | |||
353 | mutex_lock(&padctl->lock); | ||
354 | |||
355 | for (i = 0; i < padctl->soc->num_pads; i++) { | ||
356 | const struct tegra_xusb_pad_soc *soc = padctl->soc->pads[i]; | ||
357 | int err; | ||
358 | |||
359 | pad = tegra_xusb_pad_create(padctl, soc); | ||
360 | if (IS_ERR(pad)) { | ||
361 | err = PTR_ERR(pad); | ||
362 | dev_err(padctl->dev, "failed to create pad %s: %d\n", | ||
363 | soc->name, err); | ||
364 | __tegra_xusb_remove_pads(padctl); | ||
365 | mutex_unlock(&padctl->lock); | ||
366 | return err; | ||
367 | } | ||
368 | |||
369 | if (!pad) | ||
370 | continue; | ||
371 | |||
372 | list_add_tail(&pad->list, &padctl->pads); | ||
373 | } | ||
374 | |||
375 | list_for_each_entry(pad, &padctl->pads, list) | ||
376 | tegra_xusb_pad_program(pad); | ||
377 | |||
378 | mutex_unlock(&padctl->lock); | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static bool tegra_xusb_lane_check(struct tegra_xusb_lane *lane, | ||
383 | const char *function) | ||
384 | { | ||
385 | const char *func = lane->soc->funcs[lane->function]; | ||
386 | |||
387 | return strcmp(function, func) == 0; | ||
388 | } | ||
389 | |||
390 | struct tegra_xusb_lane *tegra_xusb_find_lane(struct tegra_xusb_padctl *padctl, | ||
391 | const char *type, | ||
392 | unsigned int index) | ||
393 | { | ||
394 | struct tegra_xusb_lane *lane, *hit = ERR_PTR(-ENODEV); | ||
395 | char *name; | ||
396 | |||
397 | name = kasprintf(GFP_KERNEL, "%s-%u", type, index); | ||
398 | if (!name) | ||
399 | return ERR_PTR(-ENOMEM); | ||
400 | |||
401 | list_for_each_entry(lane, &padctl->lanes, list) { | ||
402 | if (strcmp(lane->soc->name, name) == 0) { | ||
403 | hit = lane; | ||
404 | break; | ||
405 | } | ||
406 | } | ||
407 | |||
408 | kfree(name); | ||
409 | return hit; | ||
410 | } | ||
411 | |||
412 | struct tegra_xusb_lane * | ||
413 | tegra_xusb_port_find_lane(struct tegra_xusb_port *port, | ||
414 | const struct tegra_xusb_lane_map *map, | ||
415 | const char *function) | ||
416 | { | ||
417 | struct tegra_xusb_lane *lane, *match = ERR_PTR(-ENODEV); | ||
418 | |||
419 | for (map = map; map->type; map++) { | ||
420 | if (port->index != map->port) | ||
421 | continue; | ||
422 | |||
423 | lane = tegra_xusb_find_lane(port->padctl, map->type, | ||
424 | map->index); | ||
425 | if (IS_ERR(lane)) | ||
426 | continue; | ||
427 | |||
428 | if (!tegra_xusb_lane_check(lane, function)) | ||
429 | continue; | ||
430 | |||
431 | if (!IS_ERR(match)) | ||
432 | dev_err(&port->dev, "conflicting match: %s-%u / %s\n", | ||
433 | map->type, map->index, match->soc->name); | ||
434 | else | ||
435 | match = lane; | ||
436 | } | ||
437 | |||
438 | return match; | ||
439 | } | ||
440 | |||
441 | static struct device_node * | ||
442 | tegra_xusb_find_port_node(struct tegra_xusb_padctl *padctl, const char *type, | ||
443 | unsigned int index) | ||
444 | { | ||
445 | /* | ||
446 | * of_find_node_by_name() drops a reference, so make sure to grab one. | ||
447 | */ | ||
448 | struct device_node *np = of_node_get(padctl->dev->of_node); | ||
449 | |||
450 | np = of_find_node_by_name(np, "ports"); | ||
451 | if (np) { | ||
452 | char *name; | ||
453 | |||
454 | name = kasprintf(GFP_KERNEL, "%s-%u", type, index); | ||
455 | np = of_find_node_by_name(np, name); | ||
456 | kfree(name); | ||
457 | } | ||
458 | |||
459 | return np; | ||
460 | } | ||
461 | |||
462 | struct tegra_xusb_port * | ||
463 | tegra_xusb_find_port(struct tegra_xusb_padctl *padctl, const char *type, | ||
464 | unsigned int index) | ||
465 | { | ||
466 | struct tegra_xusb_port *port; | ||
467 | struct device_node *np; | ||
468 | |||
469 | np = tegra_xusb_find_port_node(padctl, type, index); | ||
470 | if (!np) | ||
471 | return NULL; | ||
472 | |||
473 | list_for_each_entry(port, &padctl->ports, list) { | ||
474 | if (np == port->dev.of_node) { | ||
475 | of_node_put(np); | ||
476 | return port; | ||
477 | } | ||
478 | } | ||
479 | |||
480 | of_node_put(np); | ||
481 | |||
482 | return NULL; | ||
483 | } | ||
484 | |||
485 | struct tegra_xusb_usb2_port * | ||
486 | tegra_xusb_find_usb2_port(struct tegra_xusb_padctl *padctl, unsigned int index) | ||
487 | { | ||
488 | struct tegra_xusb_port *port; | ||
489 | |||
490 | port = tegra_xusb_find_port(padctl, "usb2", index); | ||
491 | if (port) | ||
492 | return to_usb2_port(port); | ||
493 | |||
494 | return NULL; | ||
495 | } | ||
496 | |||
497 | struct tegra_xusb_usb3_port * | ||
498 | tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl, unsigned int index) | ||
499 | { | ||
500 | struct tegra_xusb_port *port; | ||
501 | |||
502 | port = tegra_xusb_find_port(padctl, "usb3", index); | ||
503 | if (port) | ||
504 | return to_usb3_port(port); | ||
505 | |||
506 | return NULL; | ||
507 | } | ||
508 | |||
509 | static void tegra_xusb_port_release(struct device *dev) | ||
510 | { | ||
511 | } | ||
512 | |||
513 | static struct device_type tegra_xusb_port_type = { | ||
514 | .release = tegra_xusb_port_release, | ||
515 | }; | ||
516 | |||
517 | static int tegra_xusb_port_init(struct tegra_xusb_port *port, | ||
518 | struct tegra_xusb_padctl *padctl, | ||
519 | struct device_node *np, | ||
520 | const char *name, | ||
521 | unsigned int index) | ||
522 | { | ||
523 | int err; | ||
524 | |||
525 | INIT_LIST_HEAD(&port->list); | ||
526 | port->padctl = padctl; | ||
527 | port->index = index; | ||
528 | |||
529 | device_initialize(&port->dev); | ||
530 | port->dev.type = &tegra_xusb_port_type; | ||
531 | port->dev.of_node = of_node_get(np); | ||
532 | port->dev.parent = padctl->dev; | ||
533 | |||
534 | err = dev_set_name(&port->dev, "%s-%u", name, index); | ||
535 | if (err < 0) | ||
536 | goto unregister; | ||
537 | |||
538 | err = device_add(&port->dev); | ||
539 | if (err < 0) | ||
540 | goto unregister; | ||
541 | |||
542 | return 0; | ||
543 | |||
544 | unregister: | ||
545 | device_unregister(&port->dev); | ||
546 | return err; | ||
547 | } | ||
548 | |||
549 | static void tegra_xusb_port_unregister(struct tegra_xusb_port *port) | ||
550 | { | ||
551 | device_unregister(&port->dev); | ||
552 | } | ||
553 | |||
554 | static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2) | ||
555 | { | ||
556 | struct tegra_xusb_port *port = &usb2->base; | ||
557 | struct device_node *np = port->dev.of_node; | ||
558 | |||
559 | usb2->internal = of_property_read_bool(np, "nvidia,internal"); | ||
560 | |||
561 | usb2->supply = devm_regulator_get(&port->dev, "vbus"); | ||
562 | if (IS_ERR(usb2->supply)) | ||
563 | return PTR_ERR(usb2->supply); | ||
564 | |||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | static int tegra_xusb_add_usb2_port(struct tegra_xusb_padctl *padctl, | ||
569 | unsigned int index) | ||
570 | { | ||
571 | struct tegra_xusb_usb2_port *usb2; | ||
572 | struct device_node *np; | ||
573 | int err = 0; | ||
574 | |||
575 | /* | ||
576 | * USB2 ports don't require additional properties, but if the port is | ||
577 | * marked as disabled there is no reason to register it. | ||
578 | */ | ||
579 | np = tegra_xusb_find_port_node(padctl, "usb2", index); | ||
580 | if (!np || !of_device_is_available(np)) | ||
581 | goto out; | ||
582 | |||
583 | usb2 = devm_kzalloc(padctl->dev, sizeof(*usb2), GFP_KERNEL); | ||
584 | if (!usb2) { | ||
585 | err = -ENOMEM; | ||
586 | goto out; | ||
587 | } | ||
588 | |||
589 | err = tegra_xusb_port_init(&usb2->base, padctl, np, "usb2", index); | ||
590 | if (err < 0) | ||
591 | goto out; | ||
592 | |||
593 | usb2->base.ops = padctl->soc->ports.usb2.ops; | ||
594 | |||
595 | usb2->base.lane = usb2->base.ops->map(&usb2->base); | ||
596 | if (IS_ERR(usb2->base.lane)) { | ||
597 | err = PTR_ERR(usb2->base.lane); | ||
598 | goto out; | ||
599 | } | ||
600 | |||
601 | err = tegra_xusb_usb2_port_parse_dt(usb2); | ||
602 | if (err < 0) { | ||
603 | tegra_xusb_port_unregister(&usb2->base); | ||
604 | goto out; | ||
605 | } | ||
606 | |||
607 | list_add_tail(&usb2->base.list, &padctl->ports); | ||
608 | |||
609 | out: | ||
610 | of_node_put(np); | ||
611 | return err; | ||
612 | } | ||
613 | |||
614 | static int tegra_xusb_ulpi_port_parse_dt(struct tegra_xusb_ulpi_port *ulpi) | ||
615 | { | ||
616 | struct tegra_xusb_port *port = &ulpi->base; | ||
617 | struct device_node *np = port->dev.of_node; | ||
618 | |||
619 | ulpi->internal = of_property_read_bool(np, "nvidia,internal"); | ||
620 | |||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | static int tegra_xusb_add_ulpi_port(struct tegra_xusb_padctl *padctl, | ||
625 | unsigned int index) | ||
626 | { | ||
627 | struct tegra_xusb_ulpi_port *ulpi; | ||
628 | struct device_node *np; | ||
629 | int err = 0; | ||
630 | |||
631 | np = tegra_xusb_find_port_node(padctl, "ulpi", index); | ||
632 | if (!np || !of_device_is_available(np)) | ||
633 | goto out; | ||
634 | |||
635 | ulpi = devm_kzalloc(padctl->dev, sizeof(*ulpi), GFP_KERNEL); | ||
636 | if (!ulpi) { | ||
637 | err = -ENOMEM; | ||
638 | goto out; | ||
639 | } | ||
640 | |||
641 | err = tegra_xusb_port_init(&ulpi->base, padctl, np, "ulpi", index); | ||
642 | if (err < 0) | ||
643 | goto out; | ||
644 | |||
645 | ulpi->base.ops = padctl->soc->ports.ulpi.ops; | ||
646 | |||
647 | ulpi->base.lane = ulpi->base.ops->map(&ulpi->base); | ||
648 | if (IS_ERR(ulpi->base.lane)) { | ||
649 | err = PTR_ERR(ulpi->base.lane); | ||
650 | goto out; | ||
651 | } | ||
652 | |||
653 | err = tegra_xusb_ulpi_port_parse_dt(ulpi); | ||
654 | if (err < 0) { | ||
655 | tegra_xusb_port_unregister(&ulpi->base); | ||
656 | goto out; | ||
657 | } | ||
658 | |||
659 | list_add_tail(&ulpi->base.list, &padctl->ports); | ||
660 | |||
661 | out: | ||
662 | of_node_put(np); | ||
663 | return err; | ||
664 | } | ||
665 | |||
666 | static int tegra_xusb_hsic_port_parse_dt(struct tegra_xusb_hsic_port *hsic) | ||
667 | { | ||
668 | /* XXX */ | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | static int tegra_xusb_add_hsic_port(struct tegra_xusb_padctl *padctl, | ||
673 | unsigned int index) | ||
674 | { | ||
675 | struct tegra_xusb_hsic_port *hsic; | ||
676 | struct device_node *np; | ||
677 | int err = 0; | ||
678 | |||
679 | np = tegra_xusb_find_port_node(padctl, "hsic", index); | ||
680 | if (!np || !of_device_is_available(np)) | ||
681 | goto out; | ||
682 | |||
683 | hsic = devm_kzalloc(padctl->dev, sizeof(*hsic), GFP_KERNEL); | ||
684 | if (!hsic) { | ||
685 | err = -ENOMEM; | ||
686 | goto out; | ||
687 | } | ||
688 | |||
689 | err = tegra_xusb_port_init(&hsic->base, padctl, np, "hsic", index); | ||
690 | if (err < 0) | ||
691 | goto out; | ||
692 | |||
693 | hsic->base.ops = padctl->soc->ports.hsic.ops; | ||
694 | |||
695 | hsic->base.lane = hsic->base.ops->map(&hsic->base); | ||
696 | if (IS_ERR(hsic->base.lane)) { | ||
697 | err = PTR_ERR(hsic->base.lane); | ||
698 | goto out; | ||
699 | } | ||
700 | |||
701 | err = tegra_xusb_hsic_port_parse_dt(hsic); | ||
702 | if (err < 0) { | ||
703 | tegra_xusb_port_unregister(&hsic->base); | ||
704 | goto out; | ||
705 | } | ||
706 | |||
707 | list_add_tail(&hsic->base.list, &padctl->ports); | ||
708 | |||
709 | out: | ||
710 | of_node_put(np); | ||
711 | return err; | ||
712 | } | ||
713 | |||
714 | static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3) | ||
715 | { | ||
716 | struct tegra_xusb_port *port = &usb3->base; | ||
717 | struct device_node *np = port->dev.of_node; | ||
718 | u32 value; | ||
719 | int err; | ||
720 | |||
721 | err = of_property_read_u32(np, "nvidia,usb2-companion", &value); | ||
722 | if (err < 0) { | ||
723 | dev_err(&port->dev, "failed to read port: %d\n", err); | ||
724 | return err; | ||
725 | } | ||
726 | |||
727 | usb3->port = value; | ||
728 | |||
729 | usb3->internal = of_property_read_bool(np, "nvidia,internal"); | ||
730 | |||
731 | usb3->supply = devm_regulator_get(&port->dev, "vbus"); | ||
732 | if (IS_ERR(usb3->supply)) | ||
733 | return PTR_ERR(usb3->supply); | ||
734 | |||
735 | return 0; | ||
736 | } | ||
737 | |||
738 | static int tegra_xusb_add_usb3_port(struct tegra_xusb_padctl *padctl, | ||
739 | unsigned int index) | ||
740 | { | ||
741 | struct tegra_xusb_usb3_port *usb3; | ||
742 | struct device_node *np; | ||
743 | int err = 0; | ||
744 | |||
745 | /* | ||
746 | * If there is no supplemental configuration in the device tree the | ||
747 | * port is unusable. But it is valid to configure only a single port, | ||
748 | * hence return 0 instead of an error to allow ports to be optional. | ||
749 | */ | ||
750 | np = tegra_xusb_find_port_node(padctl, "usb3", index); | ||
751 | if (!np || !of_device_is_available(np)) | ||
752 | goto out; | ||
753 | |||
754 | usb3 = devm_kzalloc(padctl->dev, sizeof(*usb3), GFP_KERNEL); | ||
755 | if (!usb3) { | ||
756 | err = -ENOMEM; | ||
757 | goto out; | ||
758 | } | ||
759 | |||
760 | err = tegra_xusb_port_init(&usb3->base, padctl, np, "usb3", index); | ||
761 | if (err < 0) | ||
762 | goto out; | ||
763 | |||
764 | usb3->base.ops = padctl->soc->ports.usb3.ops; | ||
765 | |||
766 | usb3->base.lane = usb3->base.ops->map(&usb3->base); | ||
767 | if (IS_ERR(usb3->base.lane)) { | ||
768 | err = PTR_ERR(usb3->base.lane); | ||
769 | goto out; | ||
770 | } | ||
771 | |||
772 | err = tegra_xusb_usb3_port_parse_dt(usb3); | ||
773 | if (err < 0) { | ||
774 | tegra_xusb_port_unregister(&usb3->base); | ||
775 | goto out; | ||
776 | } | ||
777 | |||
778 | list_add_tail(&usb3->base.list, &padctl->ports); | ||
779 | |||
780 | out: | ||
781 | of_node_put(np); | ||
782 | return err; | ||
783 | } | ||
784 | |||
785 | static void __tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl) | ||
786 | { | ||
787 | struct tegra_xusb_port *port, *tmp; | ||
788 | |||
789 | list_for_each_entry_safe_reverse(port, tmp, &padctl->ports, list) { | ||
790 | list_del(&port->list); | ||
791 | tegra_xusb_port_unregister(port); | ||
792 | } | ||
793 | } | ||
794 | |||
795 | static int tegra_xusb_setup_ports(struct tegra_xusb_padctl *padctl) | ||
796 | { | ||
797 | struct tegra_xusb_port *port; | ||
798 | unsigned int i; | ||
799 | int err = 0; | ||
800 | |||
801 | mutex_lock(&padctl->lock); | ||
802 | |||
803 | for (i = 0; i < padctl->soc->ports.usb2.count; i++) { | ||
804 | err = tegra_xusb_add_usb2_port(padctl, i); | ||
805 | if (err < 0) | ||
806 | goto remove_ports; | ||
807 | } | ||
808 | |||
809 | for (i = 0; i < padctl->soc->ports.ulpi.count; i++) { | ||
810 | err = tegra_xusb_add_ulpi_port(padctl, i); | ||
811 | if (err < 0) | ||
812 | goto remove_ports; | ||
813 | } | ||
814 | |||
815 | for (i = 0; i < padctl->soc->ports.hsic.count; i++) { | ||
816 | err = tegra_xusb_add_hsic_port(padctl, i); | ||
817 | if (err < 0) | ||
818 | goto remove_ports; | ||
819 | } | ||
820 | |||
821 | for (i = 0; i < padctl->soc->ports.usb3.count; i++) { | ||
822 | err = tegra_xusb_add_usb3_port(padctl, i); | ||
823 | if (err < 0) | ||
824 | goto remove_ports; | ||
825 | } | ||
826 | |||
827 | list_for_each_entry(port, &padctl->ports, list) { | ||
828 | err = port->ops->enable(port); | ||
829 | if (err < 0) | ||
830 | dev_err(padctl->dev, "failed to enable port %s: %d\n", | ||
831 | dev_name(&port->dev), err); | ||
832 | } | ||
833 | |||
834 | goto unlock; | ||
835 | |||
836 | remove_ports: | ||
837 | __tegra_xusb_remove_ports(padctl); | ||
838 | unlock: | ||
839 | mutex_unlock(&padctl->lock); | ||
840 | return err; | ||
841 | } | ||
842 | |||
843 | static void tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl) | ||
844 | { | ||
845 | mutex_lock(&padctl->lock); | ||
846 | __tegra_xusb_remove_ports(padctl); | ||
847 | mutex_unlock(&padctl->lock); | ||
848 | } | ||
849 | |||
850 | static int tegra_xusb_padctl_probe(struct platform_device *pdev) | ||
851 | { | ||
852 | struct device_node *np = of_node_get(pdev->dev.of_node); | ||
853 | const struct tegra_xusb_padctl_soc *soc; | ||
854 | struct tegra_xusb_padctl *padctl; | ||
855 | const struct of_device_id *match; | ||
856 | struct resource *res; | ||
857 | int err; | ||
858 | |||
859 | /* for backwards compatibility with old device trees */ | ||
860 | np = of_find_node_by_name(np, "pads"); | ||
861 | if (!np) { | ||
862 | dev_warn(&pdev->dev, "deprecated DT, using legacy driver\n"); | ||
863 | return tegra_xusb_padctl_legacy_probe(pdev); | ||
864 | } | ||
865 | |||
866 | of_node_put(np); | ||
867 | |||
868 | match = of_match_node(tegra_xusb_padctl_of_match, pdev->dev.of_node); | ||
869 | soc = match->data; | ||
870 | |||
871 | padctl = soc->ops->probe(&pdev->dev, soc); | ||
872 | if (IS_ERR(padctl)) | ||
873 | return PTR_ERR(padctl); | ||
874 | |||
875 | platform_set_drvdata(pdev, padctl); | ||
876 | INIT_LIST_HEAD(&padctl->ports); | ||
877 | INIT_LIST_HEAD(&padctl->lanes); | ||
878 | INIT_LIST_HEAD(&padctl->pads); | ||
879 | mutex_init(&padctl->lock); | ||
880 | |||
881 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
882 | padctl->regs = devm_ioremap_resource(&pdev->dev, res); | ||
883 | if (IS_ERR(padctl->regs)) { | ||
884 | err = PTR_ERR(padctl->regs); | ||
885 | goto remove; | ||
886 | } | ||
887 | |||
888 | padctl->rst = devm_reset_control_get(&pdev->dev, NULL); | ||
889 | if (IS_ERR(padctl->rst)) { | ||
890 | err = PTR_ERR(padctl->rst); | ||
891 | goto remove; | ||
892 | } | ||
893 | |||
894 | err = reset_control_deassert(padctl->rst); | ||
895 | if (err < 0) | ||
896 | goto remove; | ||
897 | |||
898 | err = tegra_xusb_setup_pads(padctl); | ||
899 | if (err < 0) { | ||
900 | dev_err(&pdev->dev, "failed to setup pads: %d\n", err); | ||
901 | goto reset; | ||
902 | } | ||
903 | |||
904 | err = tegra_xusb_setup_ports(padctl); | ||
905 | if (err) { | ||
906 | dev_err(&pdev->dev, "failed to setup XUSB ports: %d\n", err); | ||
907 | goto remove_pads; | ||
908 | } | ||
909 | |||
910 | return 0; | ||
911 | |||
912 | remove_pads: | ||
913 | tegra_xusb_remove_pads(padctl); | ||
914 | reset: | ||
915 | reset_control_assert(padctl->rst); | ||
916 | remove: | ||
917 | soc->ops->remove(padctl); | ||
918 | return err; | ||
919 | } | ||
920 | |||
921 | static int tegra_xusb_padctl_remove(struct platform_device *pdev) | ||
922 | { | ||
923 | struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev); | ||
924 | int err; | ||
925 | |||
926 | tegra_xusb_remove_ports(padctl); | ||
927 | tegra_xusb_remove_pads(padctl); | ||
928 | |||
929 | err = reset_control_assert(padctl->rst); | ||
930 | if (err < 0) | ||
931 | dev_err(&pdev->dev, "failed to assert reset: %d\n", err); | ||
932 | |||
933 | padctl->soc->ops->remove(padctl); | ||
934 | |||
935 | return err; | ||
936 | } | ||
937 | |||
938 | static struct platform_driver tegra_xusb_padctl_driver = { | ||
939 | .driver = { | ||
940 | .name = "tegra-xusb-padctl", | ||
941 | .of_match_table = tegra_xusb_padctl_of_match, | ||
942 | }, | ||
943 | .probe = tegra_xusb_padctl_probe, | ||
944 | .remove = tegra_xusb_padctl_remove, | ||
945 | }; | ||
946 | module_platform_driver(tegra_xusb_padctl_driver); | ||
947 | |||
948 | struct tegra_xusb_padctl *tegra_xusb_padctl_get(struct device *dev) | ||
949 | { | ||
950 | struct tegra_xusb_padctl *padctl; | ||
951 | struct platform_device *pdev; | ||
952 | struct device_node *np; | ||
953 | |||
954 | np = of_parse_phandle(dev->of_node, "nvidia,xusb-padctl", 0); | ||
955 | if (!np) | ||
956 | return ERR_PTR(-EINVAL); | ||
957 | |||
958 | /* | ||
959 | * This is slightly ugly. A better implementation would be to keep a | ||
960 | * registry of pad controllers, but since there will almost certainly | ||
961 | * only ever be one per SoC that would be a little overkill. | ||
962 | */ | ||
963 | pdev = of_find_device_by_node(np); | ||
964 | if (!pdev) { | ||
965 | of_node_put(np); | ||
966 | return ERR_PTR(-ENODEV); | ||
967 | } | ||
968 | |||
969 | of_node_put(np); | ||
970 | |||
971 | padctl = platform_get_drvdata(pdev); | ||
972 | if (!padctl) { | ||
973 | put_device(&pdev->dev); | ||
974 | return ERR_PTR(-EPROBE_DEFER); | ||
975 | } | ||
976 | |||
977 | return padctl; | ||
978 | } | ||
979 | EXPORT_SYMBOL_GPL(tegra_xusb_padctl_get); | ||
980 | |||
981 | void tegra_xusb_padctl_put(struct tegra_xusb_padctl *padctl) | ||
982 | { | ||
983 | if (padctl) | ||
984 | put_device(padctl->dev); | ||
985 | } | ||
986 | EXPORT_SYMBOL_GPL(tegra_xusb_padctl_put); | ||
987 | |||
988 | int tegra_xusb_padctl_usb3_save_context(struct tegra_xusb_padctl *padctl, | ||
989 | unsigned int port) | ||
990 | { | ||
991 | if (padctl->soc->ops->usb3_save_context) | ||
992 | return padctl->soc->ops->usb3_save_context(padctl, port); | ||
993 | |||
994 | return -ENOSYS; | ||
995 | } | ||
996 | EXPORT_SYMBOL_GPL(tegra_xusb_padctl_usb3_save_context); | ||
997 | |||
998 | int tegra_xusb_padctl_hsic_set_idle(struct tegra_xusb_padctl *padctl, | ||
999 | unsigned int port, bool idle) | ||
1000 | { | ||
1001 | if (padctl->soc->ops->hsic_set_idle) | ||
1002 | return padctl->soc->ops->hsic_set_idle(padctl, port, idle); | ||
1003 | |||
1004 | return -ENOSYS; | ||
1005 | } | ||
1006 | EXPORT_SYMBOL_GPL(tegra_xusb_padctl_hsic_set_idle); | ||
1007 | |||
1008 | int tegra_xusb_padctl_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl, | ||
1009 | unsigned int port, bool enable) | ||
1010 | { | ||
1011 | if (padctl->soc->ops->usb3_set_lfps_detect) | ||
1012 | return padctl->soc->ops->usb3_set_lfps_detect(padctl, port, | ||
1013 | enable); | ||
1014 | |||
1015 | return -ENOSYS; | ||
1016 | } | ||
1017 | EXPORT_SYMBOL_GPL(tegra_xusb_padctl_usb3_set_lfps_detect); | ||
1018 | |||
1019 | MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); | ||
1020 | MODULE_DESCRIPTION("Tegra XUSB Pad Controller driver"); | ||
1021 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h new file mode 100644 index 000000000000..b49dbc36efa3 --- /dev/null +++ b/drivers/phy/tegra/xusb.h | |||
@@ -0,0 +1,421 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. | ||
3 | * Copyright (c) 2015, Google Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #ifndef __PHY_TEGRA_XUSB_H | ||
16 | #define __PHY_TEGRA_XUSB_H | ||
17 | |||
18 | #include <linux/io.h> | ||
19 | #include <linux/mutex.h> | ||
20 | #include <linux/workqueue.h> | ||
21 | |||
22 | /* legacy entry points for backwards-compatibility */ | ||
23 | int tegra_xusb_padctl_legacy_probe(struct platform_device *pdev); | ||
24 | int tegra_xusb_padctl_legacy_remove(struct platform_device *pdev); | ||
25 | |||
26 | struct phy; | ||
27 | struct phy_provider; | ||
28 | struct platform_device; | ||
29 | struct regulator; | ||
30 | |||
31 | /* | ||
32 | * lanes | ||
33 | */ | ||
34 | struct tegra_xusb_lane_soc { | ||
35 | const char *name; | ||
36 | |||
37 | unsigned int offset; | ||
38 | unsigned int shift; | ||
39 | unsigned int mask; | ||
40 | |||
41 | const char * const *funcs; | ||
42 | unsigned int num_funcs; | ||
43 | }; | ||
44 | |||
45 | struct tegra_xusb_lane { | ||
46 | const struct tegra_xusb_lane_soc *soc; | ||
47 | struct tegra_xusb_pad *pad; | ||
48 | struct device_node *np; | ||
49 | struct list_head list; | ||
50 | unsigned int function; | ||
51 | unsigned int index; | ||
52 | }; | ||
53 | |||
54 | int tegra_xusb_lane_parse_dt(struct tegra_xusb_lane *lane, | ||
55 | struct device_node *np); | ||
56 | |||
57 | struct tegra_xusb_usb2_lane { | ||
58 | struct tegra_xusb_lane base; | ||
59 | |||
60 | u32 hs_curr_level_offset; | ||
61 | }; | ||
62 | |||
63 | static inline struct tegra_xusb_usb2_lane * | ||
64 | to_usb2_lane(struct tegra_xusb_lane *lane) | ||
65 | { | ||
66 | return container_of(lane, struct tegra_xusb_usb2_lane, base); | ||
67 | } | ||
68 | |||
69 | struct tegra_xusb_ulpi_lane { | ||
70 | struct tegra_xusb_lane base; | ||
71 | }; | ||
72 | |||
73 | static inline struct tegra_xusb_ulpi_lane * | ||
74 | to_ulpi_lane(struct tegra_xusb_lane *lane) | ||
75 | { | ||
76 | return container_of(lane, struct tegra_xusb_ulpi_lane, base); | ||
77 | } | ||
78 | |||
79 | struct tegra_xusb_hsic_lane { | ||
80 | struct tegra_xusb_lane base; | ||
81 | |||
82 | u32 strobe_trim; | ||
83 | u32 rx_strobe_trim; | ||
84 | u32 rx_data_trim; | ||
85 | u32 tx_rtune_n; | ||
86 | u32 tx_rtune_p; | ||
87 | u32 tx_rslew_n; | ||
88 | u32 tx_rslew_p; | ||
89 | bool auto_term; | ||
90 | }; | ||
91 | |||
92 | static inline struct tegra_xusb_hsic_lane * | ||
93 | to_hsic_lane(struct tegra_xusb_lane *lane) | ||
94 | { | ||
95 | return container_of(lane, struct tegra_xusb_hsic_lane, base); | ||
96 | } | ||
97 | |||
98 | struct tegra_xusb_pcie_lane { | ||
99 | struct tegra_xusb_lane base; | ||
100 | }; | ||
101 | |||
102 | static inline struct tegra_xusb_pcie_lane * | ||
103 | to_pcie_lane(struct tegra_xusb_lane *lane) | ||
104 | { | ||
105 | return container_of(lane, struct tegra_xusb_pcie_lane, base); | ||
106 | } | ||
107 | |||
108 | struct tegra_xusb_sata_lane { | ||
109 | struct tegra_xusb_lane base; | ||
110 | }; | ||
111 | |||
112 | static inline struct tegra_xusb_sata_lane * | ||
113 | to_sata_lane(struct tegra_xusb_lane *lane) | ||
114 | { | ||
115 | return container_of(lane, struct tegra_xusb_sata_lane, base); | ||
116 | } | ||
117 | |||
118 | struct tegra_xusb_lane_ops { | ||
119 | struct tegra_xusb_lane *(*probe)(struct tegra_xusb_pad *pad, | ||
120 | struct device_node *np, | ||
121 | unsigned int index); | ||
122 | void (*remove)(struct tegra_xusb_lane *lane); | ||
123 | }; | ||
124 | |||
125 | /* | ||
126 | * pads | ||
127 | */ | ||
128 | struct tegra_xusb_pad_soc; | ||
129 | struct tegra_xusb_padctl; | ||
130 | |||
131 | struct tegra_xusb_pad_ops { | ||
132 | struct tegra_xusb_pad *(*probe)(struct tegra_xusb_padctl *padctl, | ||
133 | const struct tegra_xusb_pad_soc *soc, | ||
134 | struct device_node *np); | ||
135 | void (*remove)(struct tegra_xusb_pad *pad); | ||
136 | }; | ||
137 | |||
138 | struct tegra_xusb_pad_soc { | ||
139 | const char *name; | ||
140 | |||
141 | const struct tegra_xusb_lane_soc *lanes; | ||
142 | unsigned int num_lanes; | ||
143 | |||
144 | const struct tegra_xusb_pad_ops *ops; | ||
145 | }; | ||
146 | |||
147 | struct tegra_xusb_pad { | ||
148 | const struct tegra_xusb_pad_soc *soc; | ||
149 | struct tegra_xusb_padctl *padctl; | ||
150 | struct phy_provider *provider; | ||
151 | struct phy **lanes; | ||
152 | struct device dev; | ||
153 | |||
154 | const struct tegra_xusb_lane_ops *ops; | ||
155 | |||
156 | struct list_head list; | ||
157 | }; | ||
158 | |||
159 | static inline struct tegra_xusb_pad *to_tegra_xusb_pad(struct device *dev) | ||
160 | { | ||
161 | return container_of(dev, struct tegra_xusb_pad, dev); | ||
162 | } | ||
163 | |||
164 | int tegra_xusb_pad_init(struct tegra_xusb_pad *pad, | ||
165 | struct tegra_xusb_padctl *padctl, | ||
166 | struct device_node *np); | ||
167 | int tegra_xusb_pad_register(struct tegra_xusb_pad *pad, | ||
168 | const struct phy_ops *ops); | ||
169 | void tegra_xusb_pad_unregister(struct tegra_xusb_pad *pad); | ||
170 | |||
171 | struct tegra_xusb_usb2_pad { | ||
172 | struct tegra_xusb_pad base; | ||
173 | |||
174 | struct clk *clk; | ||
175 | unsigned int enable; | ||
176 | struct mutex lock; | ||
177 | }; | ||
178 | |||
179 | static inline struct tegra_xusb_usb2_pad * | ||
180 | to_usb2_pad(struct tegra_xusb_pad *pad) | ||
181 | { | ||
182 | return container_of(pad, struct tegra_xusb_usb2_pad, base); | ||
183 | } | ||
184 | |||
185 | struct tegra_xusb_ulpi_pad { | ||
186 | struct tegra_xusb_pad base; | ||
187 | }; | ||
188 | |||
189 | static inline struct tegra_xusb_ulpi_pad * | ||
190 | to_ulpi_pad(struct tegra_xusb_pad *pad) | ||
191 | { | ||
192 | return container_of(pad, struct tegra_xusb_ulpi_pad, base); | ||
193 | } | ||
194 | |||
195 | struct tegra_xusb_hsic_pad { | ||
196 | struct tegra_xusb_pad base; | ||
197 | |||
198 | struct regulator *supply; | ||
199 | struct clk *clk; | ||
200 | }; | ||
201 | |||
202 | static inline struct tegra_xusb_hsic_pad * | ||
203 | to_hsic_pad(struct tegra_xusb_pad *pad) | ||
204 | { | ||
205 | return container_of(pad, struct tegra_xusb_hsic_pad, base); | ||
206 | } | ||
207 | |||
208 | struct tegra_xusb_pcie_pad { | ||
209 | struct tegra_xusb_pad base; | ||
210 | |||
211 | struct reset_control *rst; | ||
212 | struct clk *pll; | ||
213 | |||
214 | unsigned int enable; | ||
215 | }; | ||
216 | |||
217 | static inline struct tegra_xusb_pcie_pad * | ||
218 | to_pcie_pad(struct tegra_xusb_pad *pad) | ||
219 | { | ||
220 | return container_of(pad, struct tegra_xusb_pcie_pad, base); | ||
221 | } | ||
222 | |||
223 | struct tegra_xusb_sata_pad { | ||
224 | struct tegra_xusb_pad base; | ||
225 | |||
226 | struct reset_control *rst; | ||
227 | struct clk *pll; | ||
228 | |||
229 | unsigned int enable; | ||
230 | }; | ||
231 | |||
232 | static inline struct tegra_xusb_sata_pad * | ||
233 | to_sata_pad(struct tegra_xusb_pad *pad) | ||
234 | { | ||
235 | return container_of(pad, struct tegra_xusb_sata_pad, base); | ||
236 | } | ||
237 | |||
238 | /* | ||
239 | * ports | ||
240 | */ | ||
241 | struct tegra_xusb_port_ops; | ||
242 | |||
243 | struct tegra_xusb_port { | ||
244 | struct tegra_xusb_padctl *padctl; | ||
245 | struct tegra_xusb_lane *lane; | ||
246 | unsigned int index; | ||
247 | |||
248 | struct list_head list; | ||
249 | struct device dev; | ||
250 | |||
251 | const struct tegra_xusb_port_ops *ops; | ||
252 | }; | ||
253 | |||
254 | struct tegra_xusb_lane_map { | ||
255 | unsigned int port; | ||
256 | const char *type; | ||
257 | unsigned int index; | ||
258 | const char *func; | ||
259 | }; | ||
260 | |||
261 | struct tegra_xusb_lane * | ||
262 | tegra_xusb_port_find_lane(struct tegra_xusb_port *port, | ||
263 | const struct tegra_xusb_lane_map *map, | ||
264 | const char *function); | ||
265 | |||
266 | struct tegra_xusb_port * | ||
267 | tegra_xusb_find_port(struct tegra_xusb_padctl *padctl, const char *type, | ||
268 | unsigned int index); | ||
269 | |||
270 | struct tegra_xusb_usb2_port { | ||
271 | struct tegra_xusb_port base; | ||
272 | |||
273 | struct regulator *supply; | ||
274 | bool internal; | ||
275 | }; | ||
276 | |||
277 | static inline struct tegra_xusb_usb2_port * | ||
278 | to_usb2_port(struct tegra_xusb_port *port) | ||
279 | { | ||
280 | return container_of(port, struct tegra_xusb_usb2_port, base); | ||
281 | } | ||
282 | |||
283 | struct tegra_xusb_usb2_port * | ||
284 | tegra_xusb_find_usb2_port(struct tegra_xusb_padctl *padctl, | ||
285 | unsigned int index); | ||
286 | |||
287 | struct tegra_xusb_ulpi_port { | ||
288 | struct tegra_xusb_port base; | ||
289 | |||
290 | struct regulator *supply; | ||
291 | bool internal; | ||
292 | }; | ||
293 | |||
294 | static inline struct tegra_xusb_ulpi_port * | ||
295 | to_ulpi_port(struct tegra_xusb_port *port) | ||
296 | { | ||
297 | return container_of(port, struct tegra_xusb_ulpi_port, base); | ||
298 | } | ||
299 | |||
300 | struct tegra_xusb_hsic_port { | ||
301 | struct tegra_xusb_port base; | ||
302 | }; | ||
303 | |||
304 | static inline struct tegra_xusb_hsic_port * | ||
305 | to_hsic_port(struct tegra_xusb_port *port) | ||
306 | { | ||
307 | return container_of(port, struct tegra_xusb_hsic_port, base); | ||
308 | } | ||
309 | |||
310 | struct tegra_xusb_usb3_port { | ||
311 | struct tegra_xusb_port base; | ||
312 | struct regulator *supply; | ||
313 | bool context_saved; | ||
314 | unsigned int port; | ||
315 | bool internal; | ||
316 | |||
317 | u32 tap1; | ||
318 | u32 amp; | ||
319 | u32 ctle_z; | ||
320 | u32 ctle_g; | ||
321 | }; | ||
322 | |||
323 | static inline struct tegra_xusb_usb3_port * | ||
324 | to_usb3_port(struct tegra_xusb_port *port) | ||
325 | { | ||
326 | return container_of(port, struct tegra_xusb_usb3_port, base); | ||
327 | } | ||
328 | |||
329 | struct tegra_xusb_usb3_port * | ||
330 | tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl, | ||
331 | unsigned int index); | ||
332 | |||
333 | struct tegra_xusb_port_ops { | ||
334 | int (*enable)(struct tegra_xusb_port *port); | ||
335 | void (*disable)(struct tegra_xusb_port *port); | ||
336 | struct tegra_xusb_lane *(*map)(struct tegra_xusb_port *port); | ||
337 | }; | ||
338 | |||
339 | /* | ||
340 | * pad controller | ||
341 | */ | ||
342 | struct tegra_xusb_padctl_soc; | ||
343 | |||
344 | struct tegra_xusb_padctl_ops { | ||
345 | struct tegra_xusb_padctl * | ||
346 | (*probe)(struct device *dev, | ||
347 | const struct tegra_xusb_padctl_soc *soc); | ||
348 | void (*remove)(struct tegra_xusb_padctl *padctl); | ||
349 | |||
350 | int (*usb3_save_context)(struct tegra_xusb_padctl *padctl, | ||
351 | unsigned int index); | ||
352 | int (*hsic_set_idle)(struct tegra_xusb_padctl *padctl, | ||
353 | unsigned int index, bool idle); | ||
354 | int (*usb3_set_lfps_detect)(struct tegra_xusb_padctl *padctl, | ||
355 | unsigned int index, bool enable); | ||
356 | }; | ||
357 | |||
358 | struct tegra_xusb_padctl_soc { | ||
359 | const struct tegra_xusb_pad_soc * const *pads; | ||
360 | unsigned int num_pads; | ||
361 | |||
362 | struct { | ||
363 | struct { | ||
364 | const struct tegra_xusb_port_ops *ops; | ||
365 | unsigned int count; | ||
366 | } usb2, ulpi, hsic, usb3; | ||
367 | } ports; | ||
368 | |||
369 | const struct tegra_xusb_padctl_ops *ops; | ||
370 | }; | ||
371 | |||
372 | struct tegra_xusb_padctl { | ||
373 | struct device *dev; | ||
374 | void __iomem *regs; | ||
375 | struct mutex lock; | ||
376 | struct reset_control *rst; | ||
377 | |||
378 | const struct tegra_xusb_padctl_soc *soc; | ||
379 | |||
380 | struct tegra_xusb_pad *pcie; | ||
381 | struct tegra_xusb_pad *sata; | ||
382 | struct tegra_xusb_pad *ulpi; | ||
383 | struct tegra_xusb_pad *usb2; | ||
384 | struct tegra_xusb_pad *hsic; | ||
385 | |||
386 | struct list_head ports; | ||
387 | struct list_head lanes; | ||
388 | struct list_head pads; | ||
389 | |||
390 | unsigned int enable; | ||
391 | |||
392 | struct clk *clk; | ||
393 | }; | ||
394 | |||
395 | static inline void padctl_writel(struct tegra_xusb_padctl *padctl, u32 value, | ||
396 | unsigned long offset) | ||
397 | { | ||
398 | dev_dbg(padctl->dev, "%08lx < %08x\n", offset, value); | ||
399 | writel(value, padctl->regs + offset); | ||
400 | } | ||
401 | |||
402 | static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl, | ||
403 | unsigned long offset) | ||
404 | { | ||
405 | u32 value = readl(padctl->regs + offset); | ||
406 | dev_dbg(padctl->dev, "%08lx > %08x\n", offset, value); | ||
407 | return value; | ||
408 | } | ||
409 | |||
410 | struct tegra_xusb_lane *tegra_xusb_find_lane(struct tegra_xusb_padctl *padctl, | ||
411 | const char *name, | ||
412 | unsigned int index); | ||
413 | |||
414 | #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC) | ||
415 | extern const struct tegra_xusb_padctl_soc tegra124_xusb_padctl_soc; | ||
416 | #endif | ||
417 | #if defined(CONFIG_ARCH_TEGRA_210_SOC) | ||
418 | extern const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc; | ||
419 | #endif | ||
420 | |||
421 | #endif /* __PHY_TEGRA_XUSB_H */ | ||
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c b/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c index 2f06029c9405..946cda3fee35 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra-xusb.c | |||
@@ -873,7 +873,7 @@ static const struct of_device_id tegra_xusb_padctl_of_match[] = { | |||
873 | }; | 873 | }; |
874 | MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match); | 874 | MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match); |
875 | 875 | ||
876 | static int tegra_xusb_padctl_probe(struct platform_device *pdev) | 876 | int tegra_xusb_padctl_legacy_probe(struct platform_device *pdev) |
877 | { | 877 | { |
878 | struct tegra_xusb_padctl *padctl; | 878 | struct tegra_xusb_padctl *padctl; |
879 | const struct of_device_id *match; | 879 | const struct of_device_id *match; |
@@ -955,8 +955,9 @@ reset: | |||
955 | reset_control_assert(padctl->rst); | 955 | reset_control_assert(padctl->rst); |
956 | return err; | 956 | return err; |
957 | } | 957 | } |
958 | EXPORT_SYMBOL_GPL(tegra_xusb_padctl_legacy_probe); | ||
958 | 959 | ||
959 | static int tegra_xusb_padctl_remove(struct platform_device *pdev) | 960 | int tegra_xusb_padctl_legacy_remove(struct platform_device *pdev) |
960 | { | 961 | { |
961 | struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev); | 962 | struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev); |
962 | int err; | 963 | int err; |
@@ -969,17 +970,4 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev) | |||
969 | 970 | ||
970 | return err; | 971 | return err; |
971 | } | 972 | } |
972 | 973 | EXPORT_SYMBOL_GPL(tegra_xusb_padctl_legacy_remove); | |
973 | static struct platform_driver tegra_xusb_padctl_driver = { | ||
974 | .driver = { | ||
975 | .name = "tegra-xusb-padctl", | ||
976 | .of_match_table = tegra_xusb_padctl_of_match, | ||
977 | }, | ||
978 | .probe = tegra_xusb_padctl_probe, | ||
979 | .remove = tegra_xusb_padctl_remove, | ||
980 | }; | ||
981 | module_platform_driver(tegra_xusb_padctl_driver); | ||
982 | |||
983 | MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); | ||
984 | MODULE_DESCRIPTION("Tegra 124 XUSB Pad Control driver"); | ||
985 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/include/linux/phy/tegra/xusb.h b/include/linux/phy/tegra/xusb.h new file mode 100644 index 000000000000..8e1a57a78d9f --- /dev/null +++ b/include/linux/phy/tegra/xusb.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | #ifndef PHY_TEGRA_XUSB_H | ||
15 | #define PHY_TEGRA_XUSB_H | ||
16 | |||
17 | struct tegra_xusb_padctl; | ||
18 | struct device; | ||
19 | |||
20 | struct tegra_xusb_padctl *tegra_xusb_padctl_get(struct device *dev); | ||
21 | void tegra_xusb_padctl_put(struct tegra_xusb_padctl *padctl); | ||
22 | |||
23 | int tegra_xusb_padctl_usb3_save_context(struct tegra_xusb_padctl *padctl, | ||
24 | unsigned int port); | ||
25 | int tegra_xusb_padctl_hsic_set_idle(struct tegra_xusb_padctl *padctl, | ||
26 | unsigned int port, bool idle); | ||
27 | int tegra_xusb_padctl_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl, | ||
28 | unsigned int port, bool enable); | ||
29 | |||
30 | #endif /* PHY_TEGRA_XUSB_H */ | ||