Commit | Line | Data |
---|---|---|
9c92ab61 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
e96be45c CZ |
2 | /* |
3 | * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd | |
4 | * Author: Chris Zhong <zyw@rock-chips.com> | |
5 | * Kever Yang <kever.yang@rock-chips.com> | |
6 | * | |
e96be45c CZ |
7 | * The ROCKCHIP Type-C PHY has two PLL clocks. The first PLL clock |
8 | * is used for USB3, the second PLL clock is used for DP. This Type-C PHY has | |
9 | * 3 working modes: USB3 only mode, DP only mode, and USB3+DP mode. | |
10 | * At USB3 only mode, both PLL clocks need to be initialized, this allows the | |
11 | * PHY to switch mode between USB3 and USB3+DP, without disconnecting the USB | |
12 | * device. | |
13 | * In The DP only mode, only the DP PLL needs to be powered on, and the 4 lanes | |
14 | * are all used for DP. | |
15 | * | |
16 | * This driver gets extcon cable state and property, then decides which mode to | |
17 | * select: | |
18 | * | |
19 | * 1. USB3 only mode: | |
20 | * EXTCON_USB or EXTCON_USB_HOST state is true, and | |
21 | * EXTCON_PROP_USB_SS property is true. | |
22 | * EXTCON_DISP_DP state is false. | |
23 | * | |
24 | * 2. DP only mode: | |
25 | * EXTCON_DISP_DP state is true, and | |
26 | * EXTCON_PROP_USB_SS property is false. | |
27 | * If EXTCON_USB_HOST state is true, it is DP + USB2 mode, since the USB2 phy | |
28 | * is a separate phy, so this case is still DP only mode. | |
29 | * | |
30 | * 3. USB3+DP mode: | |
31 | * EXTCON_USB_HOST and EXTCON_DISP_DP are both true, and | |
32 | * EXTCON_PROP_USB_SS property is true. | |
33 | * | |
34 | * This Type-C PHY driver supports normal and flip orientation. The orientation | |
35 | * is reported by the EXTCON_PROP_USB_TYPEC_POLARITY property: true is flip | |
36 | * orientation, false is normal orientation. | |
e96be45c CZ |
37 | */ |
38 | ||
39 | #include <linux/clk.h> | |
40 | #include <linux/clk-provider.h> | |
41 | #include <linux/delay.h> | |
42 | #include <linux/extcon.h> | |
43 | #include <linux/io.h> | |
44 | #include <linux/iopoll.h> | |
45 | #include <linux/kernel.h> | |
46 | #include <linux/module.h> | |
47 | #include <linux/mutex.h> | |
48 | #include <linux/of.h> | |
49 | #include <linux/of_address.h> | |
50 | #include <linux/of_platform.h> | |
51 | #include <linux/platform_device.h> | |
52 | #include <linux/regmap.h> | |
53 | #include <linux/reset.h> | |
54 | ||
55 | #include <linux/mfd/syscon.h> | |
56 | #include <linux/phy/phy.h> | |
57 | ||
58 | #define CMN_SSM_BANDGAP (0x21 << 2) | |
59 | #define CMN_SSM_BIAS (0x22 << 2) | |
60 | #define CMN_PLLSM0_PLLEN (0x29 << 2) | |
61 | #define CMN_PLLSM0_PLLPRE (0x2a << 2) | |
62 | #define CMN_PLLSM0_PLLVREF (0x2b << 2) | |
63 | #define CMN_PLLSM0_PLLLOCK (0x2c << 2) | |
64 | #define CMN_PLLSM1_PLLEN (0x31 << 2) | |
65 | #define CMN_PLLSM1_PLLPRE (0x32 << 2) | |
66 | #define CMN_PLLSM1_PLLVREF (0x33 << 2) | |
67 | #define CMN_PLLSM1_PLLLOCK (0x34 << 2) | |
68 | #define CMN_PLLSM1_USER_DEF_CTRL (0x37 << 2) | |
69 | #define CMN_ICAL_OVRD (0xc1 << 2) | |
70 | #define CMN_PLL0_VCOCAL_OVRD (0x83 << 2) | |
71 | #define CMN_PLL0_VCOCAL_INIT (0x84 << 2) | |
72 | #define CMN_PLL0_VCOCAL_ITER (0x85 << 2) | |
73 | #define CMN_PLL0_LOCK_REFCNT_START (0x90 << 2) | |
74 | #define CMN_PLL0_LOCK_PLLCNT_START (0x92 << 2) | |
75 | #define CMN_PLL0_LOCK_PLLCNT_THR (0x93 << 2) | |
76 | #define CMN_PLL0_INTDIV (0x94 << 2) | |
77 | #define CMN_PLL0_FRACDIV (0x95 << 2) | |
78 | #define CMN_PLL0_HIGH_THR (0x96 << 2) | |
79 | #define CMN_PLL0_DSM_DIAG (0x97 << 2) | |
80 | #define CMN_PLL0_SS_CTRL1 (0x98 << 2) | |
81 | #define CMN_PLL0_SS_CTRL2 (0x99 << 2) | |
82 | #define CMN_PLL1_VCOCAL_START (0xa1 << 2) | |
83 | #define CMN_PLL1_VCOCAL_OVRD (0xa3 << 2) | |
84 | #define CMN_PLL1_VCOCAL_INIT (0xa4 << 2) | |
85 | #define CMN_PLL1_VCOCAL_ITER (0xa5 << 2) | |
86 | #define CMN_PLL1_LOCK_REFCNT_START (0xb0 << 2) | |
87 | #define CMN_PLL1_LOCK_PLLCNT_START (0xb2 << 2) | |
88 | #define CMN_PLL1_LOCK_PLLCNT_THR (0xb3 << 2) | |
89 | #define CMN_PLL1_INTDIV (0xb4 << 2) | |
90 | #define CMN_PLL1_FRACDIV (0xb5 << 2) | |
91 | #define CMN_PLL1_HIGH_THR (0xb6 << 2) | |
92 | #define CMN_PLL1_DSM_DIAG (0xb7 << 2) | |
93 | #define CMN_PLL1_SS_CTRL1 (0xb8 << 2) | |
94 | #define CMN_PLL1_SS_CTRL2 (0xb9 << 2) | |
95 | #define CMN_RXCAL_OVRD (0xd1 << 2) | |
f85fd4c9 | 96 | |
e96be45c CZ |
97 | #define CMN_TXPUCAL_CTRL (0xe0 << 2) |
98 | #define CMN_TXPUCAL_OVRD (0xe1 << 2) | |
f85fd4c9 | 99 | #define CMN_TXPDCAL_CTRL (0xf0 << 2) |
e96be45c | 100 | #define CMN_TXPDCAL_OVRD (0xf1 << 2) |
f85fd4c9 DA |
101 | |
102 | /* For CMN_TXPUCAL_CTRL, CMN_TXPDCAL_CTRL */ | |
103 | #define CMN_TXPXCAL_START BIT(15) | |
104 | #define CMN_TXPXCAL_DONE BIT(14) | |
105 | #define CMN_TXPXCAL_NO_RESPONSE BIT(13) | |
106 | #define CMN_TXPXCAL_CURRENT_RESPONSE BIT(12) | |
107 | ||
108 | #define CMN_TXPU_ADJ_CTRL (0x108 << 2) | |
109 | #define CMN_TXPD_ADJ_CTRL (0x10c << 2) | |
110 | ||
111 | /* | |
112 | * For CMN_TXPUCAL_CTRL, CMN_TXPDCAL_CTRL, | |
113 | * CMN_TXPU_ADJ_CTRL, CMN_TXPDCAL_CTRL | |
114 | * | |
115 | * NOTE: some of these registers are documented to be 2's complement | |
116 | * signed numbers, but then documented to be always positive. Weird. | |
117 | * In such a case, using CMN_CALIB_CODE_POS() avoids the unnecessary | |
118 | * sign extension. | |
119 | */ | |
120 | #define CMN_CALIB_CODE_WIDTH 7 | |
121 | #define CMN_CALIB_CODE_OFFSET 0 | |
122 | #define CMN_CALIB_CODE_MASK GENMASK(CMN_CALIB_CODE_WIDTH, 0) | |
123 | #define CMN_CALIB_CODE(x) \ | |
124 | sign_extend32((x) >> CMN_CALIB_CODE_OFFSET, CMN_CALIB_CODE_WIDTH) | |
125 | ||
126 | #define CMN_CALIB_CODE_POS_MASK GENMASK(CMN_CALIB_CODE_WIDTH - 1, 0) | |
127 | #define CMN_CALIB_CODE_POS(x) \ | |
128 | (((x) >> CMN_CALIB_CODE_OFFSET) & CMN_CALIB_CODE_POS_MASK) | |
129 | ||
e96be45c CZ |
130 | #define CMN_DIAG_PLL0_FBH_OVRD (0x1c0 << 2) |
131 | #define CMN_DIAG_PLL0_FBL_OVRD (0x1c1 << 2) | |
132 | #define CMN_DIAG_PLL0_OVRD (0x1c2 << 2) | |
133 | #define CMN_DIAG_PLL0_V2I_TUNE (0x1c5 << 2) | |
134 | #define CMN_DIAG_PLL0_CP_TUNE (0x1c6 << 2) | |
135 | #define CMN_DIAG_PLL0_LF_PROG (0x1c7 << 2) | |
136 | #define CMN_DIAG_PLL1_FBH_OVRD (0x1d0 << 2) | |
137 | #define CMN_DIAG_PLL1_FBL_OVRD (0x1d1 << 2) | |
138 | #define CMN_DIAG_PLL1_OVRD (0x1d2 << 2) | |
139 | #define CMN_DIAG_PLL1_V2I_TUNE (0x1d5 << 2) | |
140 | #define CMN_DIAG_PLL1_CP_TUNE (0x1d6 << 2) | |
141 | #define CMN_DIAG_PLL1_LF_PROG (0x1d7 << 2) | |
142 | #define CMN_DIAG_PLL1_PTATIS_TUNE1 (0x1d8 << 2) | |
143 | #define CMN_DIAG_PLL1_PTATIS_TUNE2 (0x1d9 << 2) | |
144 | #define CMN_DIAG_PLL1_INCLK_CTRL (0x1da << 2) | |
145 | #define CMN_DIAG_HSCLK_SEL (0x1e0 << 2) | |
146 | ||
147 | #define XCVR_PSM_RCTRL(n) ((0x4001 | ((n) << 9)) << 2) | |
148 | #define XCVR_PSM_CAL_TMR(n) ((0x4002 | ((n) << 9)) << 2) | |
149 | #define XCVR_PSM_A0IN_TMR(n) ((0x4003 | ((n) << 9)) << 2) | |
150 | #define TX_TXCC_CAL_SCLR_MULT(n) ((0x4047 | ((n) << 9)) << 2) | |
151 | #define TX_TXCC_CPOST_MULT_00(n) ((0x404c | ((n) << 9)) << 2) | |
152 | #define TX_TXCC_CPOST_MULT_01(n) ((0x404d | ((n) << 9)) << 2) | |
153 | #define TX_TXCC_CPOST_MULT_10(n) ((0x404e | ((n) << 9)) << 2) | |
154 | #define TX_TXCC_CPOST_MULT_11(n) ((0x404f | ((n) << 9)) << 2) | |
155 | #define TX_TXCC_MGNFS_MULT_000(n) ((0x4050 | ((n) << 9)) << 2) | |
156 | #define TX_TXCC_MGNFS_MULT_001(n) ((0x4051 | ((n) << 9)) << 2) | |
157 | #define TX_TXCC_MGNFS_MULT_010(n) ((0x4052 | ((n) << 9)) << 2) | |
158 | #define TX_TXCC_MGNFS_MULT_011(n) ((0x4053 | ((n) << 9)) << 2) | |
159 | #define TX_TXCC_MGNFS_MULT_100(n) ((0x4054 | ((n) << 9)) << 2) | |
160 | #define TX_TXCC_MGNFS_MULT_101(n) ((0x4055 | ((n) << 9)) << 2) | |
161 | #define TX_TXCC_MGNFS_MULT_110(n) ((0x4056 | ((n) << 9)) << 2) | |
162 | #define TX_TXCC_MGNFS_MULT_111(n) ((0x4057 | ((n) << 9)) << 2) | |
f85fd4c9 DA |
163 | #define TX_TXCC_MGNLS_MULT_000(n) ((0x4058 | ((n) << 9)) << 2) |
164 | #define TX_TXCC_MGNLS_MULT_001(n) ((0x4059 | ((n) << 9)) << 2) | |
165 | #define TX_TXCC_MGNLS_MULT_010(n) ((0x405a | ((n) << 9)) << 2) | |
166 | #define TX_TXCC_MGNLS_MULT_011(n) ((0x405b | ((n) << 9)) << 2) | |
167 | #define TX_TXCC_MGNLS_MULT_100(n) ((0x405c | ((n) << 9)) << 2) | |
168 | #define TX_TXCC_MGNLS_MULT_101(n) ((0x405d | ((n) << 9)) << 2) | |
169 | #define TX_TXCC_MGNLS_MULT_110(n) ((0x405e | ((n) << 9)) << 2) | |
170 | #define TX_TXCC_MGNLS_MULT_111(n) ((0x405f | ((n) << 9)) << 2) | |
171 | ||
e96be45c CZ |
172 | #define XCVR_DIAG_PLLDRC_CTRL(n) ((0x40e0 | ((n) << 9)) << 2) |
173 | #define XCVR_DIAG_BIDI_CTRL(n) ((0x40e8 | ((n) << 9)) << 2) | |
174 | #define XCVR_DIAG_LANE_FCM_EN_MGN(n) ((0x40f2 | ((n) << 9)) << 2) | |
175 | #define TX_PSC_A0(n) ((0x4100 | ((n) << 9)) << 2) | |
176 | #define TX_PSC_A1(n) ((0x4101 | ((n) << 9)) << 2) | |
177 | #define TX_PSC_A2(n) ((0x4102 | ((n) << 9)) << 2) | |
178 | #define TX_PSC_A3(n) ((0x4103 | ((n) << 9)) << 2) | |
179 | #define TX_RCVDET_CTRL(n) ((0x4120 | ((n) << 9)) << 2) | |
180 | #define TX_RCVDET_EN_TMR(n) ((0x4122 | ((n) << 9)) << 2) | |
181 | #define TX_RCVDET_ST_TMR(n) ((0x4123 | ((n) << 9)) << 2) | |
182 | #define TX_DIAG_TX_DRV(n) ((0x41e1 | ((n) << 9)) << 2) | |
183 | #define TX_DIAG_BGREF_PREDRV_DELAY (0x41e7 << 2) | |
f85fd4c9 DA |
184 | |
185 | /* Use this for "n" in macros like "_MULT_XXX" to target the aux channel */ | |
186 | #define AUX_CH_LANE 8 | |
187 | ||
e96be45c | 188 | #define TX_ANA_CTRL_REG_1 (0x5020 << 2) |
f85fd4c9 DA |
189 | |
190 | #define TXDA_DP_AUX_EN BIT(15) | |
191 | #define AUXDA_SE_EN BIT(14) | |
192 | #define TXDA_CAL_LATCH_EN BIT(13) | |
193 | #define AUXDA_POLARITY BIT(12) | |
194 | #define TXDA_DRV_POWER_ISOLATION_EN BIT(11) | |
195 | #define TXDA_DRV_POWER_EN_PH_2_N BIT(10) | |
196 | #define TXDA_DRV_POWER_EN_PH_1_N BIT(9) | |
197 | #define TXDA_BGREF_EN BIT(8) | |
198 | #define TXDA_DRV_LDO_EN BIT(7) | |
199 | #define TXDA_DECAP_EN_DEL BIT(6) | |
200 | #define TXDA_DECAP_EN BIT(5) | |
201 | #define TXDA_UPHY_SUPPLY_EN_DEL BIT(4) | |
202 | #define TXDA_UPHY_SUPPLY_EN BIT(3) | |
203 | #define TXDA_LOW_LEAKAGE_EN BIT(2) | |
204 | #define TXDA_DRV_IDLE_LOWI_EN BIT(1) | |
205 | #define TXDA_DRV_CMN_MODE_EN BIT(0) | |
206 | ||
e96be45c | 207 | #define TX_ANA_CTRL_REG_2 (0x5021 << 2) |
f85fd4c9 DA |
208 | |
209 | #define AUXDA_DEBOUNCING_CLK BIT(15) | |
210 | #define TXDA_LPBK_RECOVERED_CLK_EN BIT(14) | |
211 | #define TXDA_LPBK_ISI_GEN_EN BIT(13) | |
212 | #define TXDA_LPBK_SERIAL_EN BIT(12) | |
213 | #define TXDA_LPBK_LINE_EN BIT(11) | |
214 | #define TXDA_DRV_LDO_REDC_SINKIQ BIT(10) | |
215 | #define XCVR_DECAP_EN_DEL BIT(9) | |
216 | #define XCVR_DECAP_EN BIT(8) | |
217 | #define TXDA_MPHY_ENABLE_HS_NT BIT(7) | |
218 | #define TXDA_MPHY_SA_MODE BIT(6) | |
219 | #define TXDA_DRV_LDO_RBYR_FB_EN BIT(5) | |
220 | #define TXDA_DRV_RST_PULL_DOWN BIT(4) | |
221 | #define TXDA_DRV_LDO_BG_FB_EN BIT(3) | |
222 | #define TXDA_DRV_LDO_BG_REF_EN BIT(2) | |
223 | #define TXDA_DRV_PREDRV_EN_DEL BIT(1) | |
224 | #define TXDA_DRV_PREDRV_EN BIT(0) | |
225 | ||
e96be45c | 226 | #define TXDA_COEFF_CALC_CTRL (0x5022 << 2) |
f85fd4c9 DA |
227 | |
228 | #define TX_HIGH_Z BIT(6) | |
229 | #define TX_VMARGIN_OFFSET 3 | |
230 | #define TX_VMARGIN_MASK 0x7 | |
231 | #define LOW_POWER_SWING_EN BIT(2) | |
232 | #define TX_FCM_DRV_MAIN_EN BIT(1) | |
233 | #define TX_FCM_FULL_MARGIN BIT(0) | |
234 | ||
e96be45c | 235 | #define TX_DIG_CTRL_REG_2 (0x5024 << 2) |
f85fd4c9 DA |
236 | |
237 | #define TX_HIGH_Z_TM_EN BIT(15) | |
238 | #define TX_RESCAL_CODE_OFFSET 0 | |
239 | #define TX_RESCAL_CODE_MASK 0x3f | |
240 | ||
e96be45c CZ |
241 | #define TXDA_CYA_AUXDA_CYA (0x5025 << 2) |
242 | #define TX_ANA_CTRL_REG_3 (0x5026 << 2) | |
243 | #define TX_ANA_CTRL_REG_4 (0x5027 << 2) | |
244 | #define TX_ANA_CTRL_REG_5 (0x5029 << 2) | |
245 | ||
246 | #define RX_PSC_A0(n) ((0x8000 | ((n) << 9)) << 2) | |
247 | #define RX_PSC_A1(n) ((0x8001 | ((n) << 9)) << 2) | |
248 | #define RX_PSC_A2(n) ((0x8002 | ((n) << 9)) << 2) | |
249 | #define RX_PSC_A3(n) ((0x8003 | ((n) << 9)) << 2) | |
250 | #define RX_PSC_CAL(n) ((0x8006 | ((n) << 9)) << 2) | |
251 | #define RX_PSC_RDY(n) ((0x8007 | ((n) << 9)) << 2) | |
252 | #define RX_IQPI_ILL_CAL_OVRD (0x8023 << 2) | |
253 | #define RX_EPI_ILL_CAL_OVRD (0x8033 << 2) | |
254 | #define RX_SDCAL0_OVRD (0x8041 << 2) | |
255 | #define RX_SDCAL1_OVRD (0x8049 << 2) | |
256 | #define RX_SLC_INIT (0x806d << 2) | |
257 | #define RX_SLC_RUN (0x806e << 2) | |
258 | #define RX_CDRLF_CNFG2 (0x8081 << 2) | |
259 | #define RX_SIGDET_HL_FILT_TMR(n) ((0x8090 | ((n) << 9)) << 2) | |
260 | #define RX_SLC_IOP0_OVRD (0x8101 << 2) | |
261 | #define RX_SLC_IOP1_OVRD (0x8105 << 2) | |
262 | #define RX_SLC_QOP0_OVRD (0x8109 << 2) | |
263 | #define RX_SLC_QOP1_OVRD (0x810d << 2) | |
264 | #define RX_SLC_EOP0_OVRD (0x8111 << 2) | |
265 | #define RX_SLC_EOP1_OVRD (0x8115 << 2) | |
266 | #define RX_SLC_ION0_OVRD (0x8119 << 2) | |
267 | #define RX_SLC_ION1_OVRD (0x811d << 2) | |
268 | #define RX_SLC_QON0_OVRD (0x8121 << 2) | |
269 | #define RX_SLC_QON1_OVRD (0x8125 << 2) | |
270 | #define RX_SLC_EON0_OVRD (0x8129 << 2) | |
271 | #define RX_SLC_EON1_OVRD (0x812d << 2) | |
272 | #define RX_SLC_IEP0_OVRD (0x8131 << 2) | |
273 | #define RX_SLC_IEP1_OVRD (0x8135 << 2) | |
274 | #define RX_SLC_QEP0_OVRD (0x8139 << 2) | |
275 | #define RX_SLC_QEP1_OVRD (0x813d << 2) | |
276 | #define RX_SLC_EEP0_OVRD (0x8141 << 2) | |
277 | #define RX_SLC_EEP1_OVRD (0x8145 << 2) | |
278 | #define RX_SLC_IEN0_OVRD (0x8149 << 2) | |
279 | #define RX_SLC_IEN1_OVRD (0x814d << 2) | |
280 | #define RX_SLC_QEN0_OVRD (0x8151 << 2) | |
281 | #define RX_SLC_QEN1_OVRD (0x8155 << 2) | |
282 | #define RX_SLC_EEN0_OVRD (0x8159 << 2) | |
283 | #define RX_SLC_EEN1_OVRD (0x815d << 2) | |
284 | #define RX_REE_CTRL_DATA_MASK(n) ((0x81bb | ((n) << 9)) << 2) | |
285 | #define RX_DIAG_SIGDET_TUNE(n) ((0x81dc | ((n) << 9)) << 2) | |
286 | #define RX_DIAG_SC2C_DELAY (0x81e1 << 2) | |
287 | ||
288 | #define PMA_LANE_CFG (0xc000 << 2) | |
289 | #define PIPE_CMN_CTRL1 (0xc001 << 2) | |
290 | #define PIPE_CMN_CTRL2 (0xc002 << 2) | |
291 | #define PIPE_COM_LOCK_CFG1 (0xc003 << 2) | |
292 | #define PIPE_COM_LOCK_CFG2 (0xc004 << 2) | |
293 | #define PIPE_RCV_DET_INH (0xc005 << 2) | |
294 | #define DP_MODE_CTL (0xc008 << 2) | |
295 | #define DP_CLK_CTL (0xc009 << 2) | |
296 | #define STS (0xc00F << 2) | |
297 | #define PHY_ISO_CMN_CTRL (0xc010 << 2) | |
298 | #define PHY_DP_TX_CTL (0xc408 << 2) | |
299 | #define PMA_CMN_CTRL1 (0xc800 << 2) | |
300 | #define PHY_PMA_ISO_CMN_CTRL (0xc810 << 2) | |
301 | #define PHY_ISOLATION_CTRL (0xc81f << 2) | |
302 | #define PHY_PMA_ISO_XCVR_CTRL(n) ((0xcc11 | ((n) << 6)) << 2) | |
303 | #define PHY_PMA_ISO_LINK_MODE(n) ((0xcc12 | ((n) << 6)) << 2) | |
304 | #define PHY_PMA_ISO_PWRST_CTRL(n) ((0xcc13 | ((n) << 6)) << 2) | |
305 | #define PHY_PMA_ISO_TX_DATA_LO(n) ((0xcc14 | ((n) << 6)) << 2) | |
306 | #define PHY_PMA_ISO_TX_DATA_HI(n) ((0xcc15 | ((n) << 6)) << 2) | |
307 | #define PHY_PMA_ISO_RX_DATA_LO(n) ((0xcc16 | ((n) << 6)) << 2) | |
308 | #define PHY_PMA_ISO_RX_DATA_HI(n) ((0xcc17 | ((n) << 6)) << 2) | |
309 | #define TX_BIST_CTRL(n) ((0x4140 | ((n) << 9)) << 2) | |
310 | #define TX_BIST_UDDWR(n) ((0x4141 | ((n) << 9)) << 2) | |
311 | ||
312 | /* | |
313 | * Selects which PLL clock will be driven on the analog high speed | |
314 | * clock 0: PLL 0 div 1 | |
315 | * clock 1: PLL 1 div 2 | |
316 | */ | |
317 | #define CLK_PLL_CONFIG 0X30 | |
318 | #define CLK_PLL_MASK 0x33 | |
319 | ||
320 | #define CMN_READY BIT(0) | |
321 | ||
322 | #define DP_PLL_CLOCK_ENABLE BIT(2) | |
323 | #define DP_PLL_ENABLE BIT(0) | |
324 | #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) | |
325 | #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) | |
326 | #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) | |
327 | ||
328 | #define DP_MODE_A0 BIT(4) | |
329 | #define DP_MODE_A2 BIT(6) | |
330 | #define DP_MODE_ENTER_A0 0xc101 | |
331 | #define DP_MODE_ENTER_A2 0xc104 | |
332 | ||
333 | #define PHY_MODE_SET_TIMEOUT 100000 | |
334 | ||
335 | #define PIN_ASSIGN_C_E 0x51d9 | |
336 | #define PIN_ASSIGN_D_F 0x5100 | |
337 | ||
338 | #define MODE_DISCONNECT 0 | |
339 | #define MODE_UFP_USB BIT(0) | |
340 | #define MODE_DFP_USB BIT(1) | |
341 | #define MODE_DFP_DP BIT(2) | |
342 | ||
343 | struct usb3phy_reg { | |
344 | u32 offset; | |
345 | u32 enable_bit; | |
346 | u32 write_enable; | |
347 | }; | |
348 | ||
0fbc47d9 | 349 | /** |
72fbf95f | 350 | * struct rockchip_usb3phy_port_cfg - usb3-phy port configuration. |
0fbc47d9 EBS |
351 | * @reg: the base address for usb3-phy config. |
352 | * @typec_conn_dir: the register of type-c connector direction. | |
353 | * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. | |
354 | * @external_psm: the register of type-c phy external psm clock. | |
355 | * @pipe_status: the register of type-c phy pipe status. | |
f293f740 W |
356 | * @usb3_host_disable: the register of type-c usb3 host disable. |
357 | * @usb3_host_port: the register of type-c usb3 host port. | |
866d4087 | 358 | * @uphy_dp_sel: the register of type-c phy DP select control. |
0fbc47d9 | 359 | */ |
e96be45c | 360 | struct rockchip_usb3phy_port_cfg { |
0fbc47d9 | 361 | unsigned int reg; |
e96be45c CZ |
362 | struct usb3phy_reg typec_conn_dir; |
363 | struct usb3phy_reg usb3tousb2_en; | |
364 | struct usb3phy_reg external_psm; | |
365 | struct usb3phy_reg pipe_status; | |
f293f740 W |
366 | struct usb3phy_reg usb3_host_disable; |
367 | struct usb3phy_reg usb3_host_port; | |
866d4087 | 368 | struct usb3phy_reg uphy_dp_sel; |
e96be45c CZ |
369 | }; |
370 | ||
371 | struct rockchip_typec_phy { | |
372 | struct device *dev; | |
373 | void __iomem *base; | |
374 | struct extcon_dev *extcon; | |
375 | struct regmap *grf_regs; | |
376 | struct clk *clk_core; | |
377 | struct clk *clk_ref; | |
378 | struct reset_control *uphy_rst; | |
379 | struct reset_control *pipe_rst; | |
380 | struct reset_control *tcphy_rst; | |
0fbc47d9 | 381 | const struct rockchip_usb3phy_port_cfg *port_cfgs; |
e96be45c CZ |
382 | /* mutex to protect access to individual PHYs */ |
383 | struct mutex lock; | |
384 | ||
385 | bool flip; | |
386 | u8 mode; | |
387 | }; | |
388 | ||
389 | struct phy_reg { | |
390 | u16 value; | |
391 | u32 addr; | |
392 | }; | |
393 | ||
f7f6ed92 | 394 | static struct phy_reg usb3_pll_cfg[] = { |
e96be45c CZ |
395 | { 0xf0, CMN_PLL0_VCOCAL_INIT }, |
396 | { 0x18, CMN_PLL0_VCOCAL_ITER }, | |
397 | { 0xd0, CMN_PLL0_INTDIV }, | |
398 | { 0x4a4a, CMN_PLL0_FRACDIV }, | |
399 | { 0x34, CMN_PLL0_HIGH_THR }, | |
400 | { 0x1ee, CMN_PLL0_SS_CTRL1 }, | |
401 | { 0x7f03, CMN_PLL0_SS_CTRL2 }, | |
402 | { 0x20, CMN_PLL0_DSM_DIAG }, | |
403 | { 0, CMN_DIAG_PLL0_OVRD }, | |
404 | { 0, CMN_DIAG_PLL0_FBH_OVRD }, | |
405 | { 0, CMN_DIAG_PLL0_FBL_OVRD }, | |
406 | { 0x7, CMN_DIAG_PLL0_V2I_TUNE }, | |
407 | { 0x45, CMN_DIAG_PLL0_CP_TUNE }, | |
408 | { 0x8, CMN_DIAG_PLL0_LF_PROG }, | |
409 | }; | |
410 | ||
f7f6ed92 | 411 | static struct phy_reg dp_pll_cfg[] = { |
e96be45c CZ |
412 | { 0xf0, CMN_PLL1_VCOCAL_INIT }, |
413 | { 0x18, CMN_PLL1_VCOCAL_ITER }, | |
414 | { 0x30b9, CMN_PLL1_VCOCAL_START }, | |
415 | { 0x21c, CMN_PLL1_INTDIV }, | |
416 | { 0, CMN_PLL1_FRACDIV }, | |
417 | { 0x5, CMN_PLL1_HIGH_THR }, | |
418 | { 0x35, CMN_PLL1_SS_CTRL1 }, | |
419 | { 0x7f1e, CMN_PLL1_SS_CTRL2 }, | |
420 | { 0x20, CMN_PLL1_DSM_DIAG }, | |
421 | { 0, CMN_PLLSM1_USER_DEF_CTRL }, | |
422 | { 0, CMN_DIAG_PLL1_OVRD }, | |
423 | { 0, CMN_DIAG_PLL1_FBH_OVRD }, | |
424 | { 0, CMN_DIAG_PLL1_FBL_OVRD }, | |
425 | { 0x6, CMN_DIAG_PLL1_V2I_TUNE }, | |
426 | { 0x45, CMN_DIAG_PLL1_CP_TUNE }, | |
427 | { 0x8, CMN_DIAG_PLL1_LF_PROG }, | |
428 | { 0x100, CMN_DIAG_PLL1_PTATIS_TUNE1 }, | |
429 | { 0x7, CMN_DIAG_PLL1_PTATIS_TUNE2 }, | |
430 | { 0x4, CMN_DIAG_PLL1_INCLK_CTRL }, | |
431 | }; | |
432 | ||
0fbc47d9 EBS |
433 | static const struct rockchip_usb3phy_port_cfg rk3399_usb3phy_port_cfgs[] = { |
434 | { | |
435 | .reg = 0xff7c0000, | |
436 | .typec_conn_dir = { 0xe580, 0, 16 }, | |
437 | .usb3tousb2_en = { 0xe580, 3, 19 }, | |
438 | .external_psm = { 0xe588, 14, 30 }, | |
439 | .pipe_status = { 0xe5c0, 0, 0 }, | |
f293f740 W |
440 | .usb3_host_disable = { 0x2434, 0, 16 }, |
441 | .usb3_host_port = { 0x2434, 12, 28 }, | |
866d4087 | 442 | .uphy_dp_sel = { 0x6268, 19, 19 }, |
0fbc47d9 EBS |
443 | }, |
444 | { | |
445 | .reg = 0xff800000, | |
446 | .typec_conn_dir = { 0xe58c, 0, 16 }, | |
447 | .usb3tousb2_en = { 0xe58c, 3, 19 }, | |
448 | .external_psm = { 0xe594, 14, 30 }, | |
449 | .pipe_status = { 0xe5c0, 16, 16 }, | |
f293f740 W |
450 | .usb3_host_disable = { 0x2444, 0, 16 }, |
451 | .usb3_host_port = { 0x2444, 12, 28 }, | |
866d4087 | 452 | .uphy_dp_sel = { 0x6268, 3, 19 }, |
0fbc47d9 EBS |
453 | }, |
454 | { /* sentinel */ } | |
455 | }; | |
456 | ||
e96be45c CZ |
457 | static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy) |
458 | { | |
459 | u32 i, rdata; | |
460 | ||
461 | /* | |
462 | * cmn_ref_clk_sel = 3, select the 24Mhz for clk parent | |
463 | * cmn_psm_clk_dig_div = 2, set the clk division to 2 | |
464 | */ | |
465 | writel(0x830, tcphy->base + PMA_CMN_CTRL1); | |
466 | for (i = 0; i < 4; i++) { | |
467 | /* | |
468 | * The following PHY configuration assumes a 24 MHz reference | |
469 | * clock. | |
470 | */ | |
471 | writel(0x90, tcphy->base + XCVR_DIAG_LANE_FCM_EN_MGN(i)); | |
472 | writel(0x960, tcphy->base + TX_RCVDET_EN_TMR(i)); | |
473 | writel(0x30, tcphy->base + TX_RCVDET_ST_TMR(i)); | |
474 | } | |
475 | ||
476 | rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL); | |
477 | rdata &= ~CLK_PLL_MASK; | |
478 | rdata |= CLK_PLL_CONFIG; | |
479 | writel(rdata, tcphy->base + CMN_DIAG_HSCLK_SEL); | |
480 | } | |
481 | ||
482 | static void tcphy_cfg_usb3_pll(struct rockchip_typec_phy *tcphy) | |
483 | { | |
484 | u32 i; | |
485 | ||
486 | /* load the configuration of PLL0 */ | |
487 | for (i = 0; i < ARRAY_SIZE(usb3_pll_cfg); i++) | |
488 | writel(usb3_pll_cfg[i].value, | |
489 | tcphy->base + usb3_pll_cfg[i].addr); | |
490 | } | |
491 | ||
492 | static void tcphy_cfg_dp_pll(struct rockchip_typec_phy *tcphy) | |
493 | { | |
494 | u32 i; | |
495 | ||
496 | /* set the default mode to RBR */ | |
497 | writel(DP_PLL_CLOCK_ENABLE | DP_PLL_ENABLE | DP_PLL_DATA_RATE_RBR, | |
498 | tcphy->base + DP_CLK_CTL); | |
499 | ||
500 | /* load the configuration of PLL1 */ | |
501 | for (i = 0; i < ARRAY_SIZE(dp_pll_cfg); i++) | |
502 | writel(dp_pll_cfg[i].value, tcphy->base + dp_pll_cfg[i].addr); | |
503 | } | |
504 | ||
505 | static void tcphy_tx_usb3_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane) | |
506 | { | |
507 | writel(0x7799, tcphy->base + TX_PSC_A0(lane)); | |
508 | writel(0x7798, tcphy->base + TX_PSC_A1(lane)); | |
509 | writel(0x5098, tcphy->base + TX_PSC_A2(lane)); | |
510 | writel(0x5098, tcphy->base + TX_PSC_A3(lane)); | |
511 | writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane)); | |
512 | writel(0xbf, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane)); | |
513 | } | |
514 | ||
515 | static void tcphy_rx_usb3_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane) | |
516 | { | |
517 | writel(0xa6fd, tcphy->base + RX_PSC_A0(lane)); | |
518 | writel(0xa6fd, tcphy->base + RX_PSC_A1(lane)); | |
519 | writel(0xa410, tcphy->base + RX_PSC_A2(lane)); | |
520 | writel(0x2410, tcphy->base + RX_PSC_A3(lane)); | |
521 | writel(0x23ff, tcphy->base + RX_PSC_CAL(lane)); | |
522 | writel(0x13, tcphy->base + RX_SIGDET_HL_FILT_TMR(lane)); | |
523 | writel(0x03e7, tcphy->base + RX_REE_CTRL_DATA_MASK(lane)); | |
524 | writel(0x1004, tcphy->base + RX_DIAG_SIGDET_TUNE(lane)); | |
525 | writel(0x2010, tcphy->base + RX_PSC_RDY(lane)); | |
526 | writel(0xfb, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane)); | |
527 | } | |
528 | ||
529 | static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane) | |
530 | { | |
531 | u16 rdata; | |
532 | ||
533 | writel(0xbefc, tcphy->base + XCVR_PSM_RCTRL(lane)); | |
534 | writel(0x6799, tcphy->base + TX_PSC_A0(lane)); | |
535 | writel(0x6798, tcphy->base + TX_PSC_A1(lane)); | |
536 | writel(0x98, tcphy->base + TX_PSC_A2(lane)); | |
537 | writel(0x98, tcphy->base + TX_PSC_A3(lane)); | |
538 | ||
539 | writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane)); | |
540 | writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_001(lane)); | |
541 | writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_010(lane)); | |
542 | writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_011(lane)); | |
543 | writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_100(lane)); | |
544 | writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_101(lane)); | |
545 | writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_110(lane)); | |
546 | writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_111(lane)); | |
547 | writel(0, tcphy->base + TX_TXCC_CPOST_MULT_10(lane)); | |
548 | writel(0, tcphy->base + TX_TXCC_CPOST_MULT_01(lane)); | |
549 | writel(0, tcphy->base + TX_TXCC_CPOST_MULT_00(lane)); | |
550 | writel(0, tcphy->base + TX_TXCC_CPOST_MULT_11(lane)); | |
551 | ||
552 | writel(0x128, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane)); | |
553 | writel(0x400, tcphy->base + TX_DIAG_TX_DRV(lane)); | |
554 | ||
555 | rdata = readl(tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane)); | |
556 | rdata = (rdata & 0x8fff) | 0x6000; | |
557 | writel(rdata, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane)); | |
558 | } | |
559 | ||
560 | static inline int property_enable(struct rockchip_typec_phy *tcphy, | |
561 | const struct usb3phy_reg *reg, bool en) | |
562 | { | |
563 | u32 mask = 1 << reg->write_enable; | |
564 | u32 val = en << reg->enable_bit; | |
565 | ||
566 | return regmap_write(tcphy->grf_regs, reg->offset, val | mask); | |
567 | } | |
568 | ||
f98b7438 DA |
569 | static void tcphy_dp_aux_set_flip(struct rockchip_typec_phy *tcphy) |
570 | { | |
571 | u16 tx_ana_ctrl_reg_1; | |
572 | ||
573 | /* | |
574 | * Select the polarity of the xcvr: | |
575 | * 1, Reverses the polarity (If TYPEC, Pulls ups aux_p and pull | |
576 | * down aux_m) | |
577 | * 0, Normal polarity (if TYPEC, pulls up aux_m and pulls down | |
578 | * aux_p) | |
579 | */ | |
580 | tx_ana_ctrl_reg_1 = readl(tcphy->base + TX_ANA_CTRL_REG_1); | |
581 | if (!tcphy->flip) | |
f85fd4c9 | 582 | tx_ana_ctrl_reg_1 |= AUXDA_POLARITY; |
f98b7438 | 583 | else |
f85fd4c9 | 584 | tx_ana_ctrl_reg_1 &= ~AUXDA_POLARITY; |
f98b7438 DA |
585 | writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1); |
586 | } | |
587 | ||
e96be45c CZ |
588 | static void tcphy_dp_aux_calibration(struct rockchip_typec_phy *tcphy) |
589 | { | |
f85fd4c9 | 590 | u16 val; |
f98b7438 | 591 | u16 tx_ana_ctrl_reg_1; |
f85fd4c9 | 592 | u16 tx_ana_ctrl_reg_2; |
e023b1fb DA |
593 | s32 pu_calib_code, pd_calib_code; |
594 | s32 pu_adj, pd_adj; | |
595 | u16 calib; | |
e96be45c CZ |
596 | |
597 | /* | |
e023b1fb DA |
598 | * Calculate calibration code as per docs: use an average of the |
599 | * pull down and pull up. Then add in adjustments. | |
e96be45c | 600 | */ |
f85fd4c9 DA |
601 | val = readl(tcphy->base + CMN_TXPUCAL_CTRL); |
602 | pu_calib_code = CMN_CALIB_CODE_POS(val); | |
e023b1fb DA |
603 | val = readl(tcphy->base + CMN_TXPDCAL_CTRL); |
604 | pd_calib_code = CMN_CALIB_CODE_POS(val); | |
605 | val = readl(tcphy->base + CMN_TXPU_ADJ_CTRL); | |
606 | pu_adj = CMN_CALIB_CODE(val); | |
607 | val = readl(tcphy->base + CMN_TXPD_ADJ_CTRL); | |
608 | pd_adj = CMN_CALIB_CODE(val); | |
609 | calib = (pu_calib_code + pd_calib_code) / 2 + pu_adj + pd_adj; | |
610 | ||
611 | /* disable txda_cal_latch_en for rewrite the calibration values */ | |
612 | tx_ana_ctrl_reg_1 = readl(tcphy->base + TX_ANA_CTRL_REG_1); | |
613 | tx_ana_ctrl_reg_1 &= ~TXDA_CAL_LATCH_EN; | |
614 | writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1); | |
e96be45c | 615 | |
f85fd4c9 DA |
616 | /* write the calibration, then delay 10 ms as sample in docs */ |
617 | val = readl(tcphy->base + TX_DIG_CTRL_REG_2); | |
618 | val &= ~(TX_RESCAL_CODE_MASK << TX_RESCAL_CODE_OFFSET); | |
e023b1fb | 619 | val |= calib << TX_RESCAL_CODE_OFFSET; |
e96be45c | 620 | writel(val, tcphy->base + TX_DIG_CTRL_REG_2); |
f85fd4c9 | 621 | usleep_range(10000, 10050); |
e96be45c CZ |
622 | |
623 | /* | |
624 | * Enable signal for latch that sample and holds calibration values. | |
625 | * Activate this signal for 1 clock cycle to sample new calibration | |
626 | * values. | |
627 | */ | |
f85fd4c9 | 628 | tx_ana_ctrl_reg_1 |= TXDA_CAL_LATCH_EN; |
f98b7438 | 629 | writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1); |
e96be45c CZ |
630 | usleep_range(150, 200); |
631 | ||
632 | /* set TX Voltage Level and TX Deemphasis to 0 */ | |
633 | writel(0, tcphy->base + PHY_DP_TX_CTL); | |
f85fd4c9 | 634 | |
e96be45c | 635 | /* re-enable decap */ |
f85fd4c9 DA |
636 | tx_ana_ctrl_reg_2 = XCVR_DECAP_EN; |
637 | writel(tx_ana_ctrl_reg_2, tcphy->base + TX_ANA_CTRL_REG_2); | |
638 | udelay(1); | |
639 | tx_ana_ctrl_reg_2 |= XCVR_DECAP_EN_DEL; | |
640 | writel(tx_ana_ctrl_reg_2, tcphy->base + TX_ANA_CTRL_REG_2); | |
641 | ||
642 | writel(0, tcphy->base + TX_ANA_CTRL_REG_3); | |
643 | ||
644 | tx_ana_ctrl_reg_1 |= TXDA_UPHY_SUPPLY_EN; | |
f98b7438 | 645 | writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1); |
f85fd4c9 DA |
646 | udelay(1); |
647 | tx_ana_ctrl_reg_1 |= TXDA_UPHY_SUPPLY_EN_DEL; | |
f98b7438 | 648 | writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1); |
e96be45c CZ |
649 | |
650 | writel(0, tcphy->base + TX_ANA_CTRL_REG_5); | |
651 | ||
652 | /* | |
653 | * Programs txda_drv_ldo_prog[15:0], Sets driver LDO | |
654 | * voltage 16'h1001 for DP-AUX-TX and RX | |
655 | */ | |
656 | writel(0x1001, tcphy->base + TX_ANA_CTRL_REG_4); | |
657 | ||
658 | /* re-enables Bandgap reference for LDO */ | |
f85fd4c9 | 659 | tx_ana_ctrl_reg_1 |= TXDA_DRV_LDO_EN; |
f98b7438 | 660 | writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1); |
f85fd4c9 DA |
661 | udelay(5); |
662 | tx_ana_ctrl_reg_1 |= TXDA_BGREF_EN; | |
f98b7438 | 663 | writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1); |
e96be45c CZ |
664 | |
665 | /* | |
666 | * re-enables the transmitter pre-driver, driver data selection MUX, | |
667 | * and receiver detect circuits. | |
668 | */ | |
f85fd4c9 DA |
669 | tx_ana_ctrl_reg_2 |= TXDA_DRV_PREDRV_EN; |
670 | writel(tx_ana_ctrl_reg_2, tcphy->base + TX_ANA_CTRL_REG_2); | |
671 | udelay(1); | |
672 | tx_ana_ctrl_reg_2 |= TXDA_DRV_PREDRV_EN_DEL; | |
673 | writel(tx_ana_ctrl_reg_2, tcphy->base + TX_ANA_CTRL_REG_2); | |
e96be45c CZ |
674 | |
675 | /* | |
f85fd4c9 DA |
676 | * Do all the undocumented magic: |
677 | * - Turn on TXDA_DP_AUX_EN, whatever that is, even though sample | |
678 | * never shows this going on. | |
679 | * - Turn on TXDA_DECAP_EN (and TXDA_DECAP_EN_DEL) even though | |
680 | * docs say for aux it's always 0. | |
681 | * - Turn off the LDO and BGREF, which we just spent time turning | |
682 | * on above (???). | |
683 | * | |
684 | * Without this magic, things seem worse. | |
e96be45c | 685 | */ |
f85fd4c9 DA |
686 | tx_ana_ctrl_reg_1 |= TXDA_DP_AUX_EN; |
687 | tx_ana_ctrl_reg_1 |= TXDA_DECAP_EN; | |
688 | tx_ana_ctrl_reg_1 &= ~TXDA_DRV_LDO_EN; | |
689 | tx_ana_ctrl_reg_1 &= ~TXDA_BGREF_EN; | |
690 | writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1); | |
691 | udelay(1); | |
692 | tx_ana_ctrl_reg_1 |= TXDA_DECAP_EN_DEL; | |
f98b7438 | 693 | writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1); |
e96be45c CZ |
694 | |
695 | /* | |
f85fd4c9 DA |
696 | * Undo the work we did to set the LDO voltage. |
697 | * This doesn't seem to help nor hurt, but it kinda goes with the | |
698 | * undocumented magic above. | |
e96be45c | 699 | */ |
f85fd4c9 DA |
700 | writel(0, tcphy->base + TX_ANA_CTRL_REG_4); |
701 | ||
702 | /* Don't set voltage swing to 400 mV peak to peak (differential) */ | |
26e03d80 | 703 | writel(0, tcphy->base + TXDA_COEFF_CALC_CTRL); |
f85fd4c9 DA |
704 | |
705 | /* Init TXDA_CYA_AUXDA_CYA for unknown magic reasons */ | |
e96be45c CZ |
706 | writel(0, tcphy->base + TXDA_CYA_AUXDA_CYA); |
707 | ||
f85fd4c9 DA |
708 | /* |
709 | * More undocumented magic, presumably the goal of which is to | |
710 | * make the "auxda_source_aux_oen" be ignored and instead to decide | |
711 | * about "high impedance state" based on what software puts in the | |
712 | * register TXDA_COEFF_CALC_CTRL (see TX_HIGH_Z). Since we only | |
713 | * program that register once and we don't set the bit TX_HIGH_Z, | |
714 | * presumably the goal here is that we should never put the analog | |
715 | * driver in high impedance state. | |
716 | */ | |
e96be45c | 717 | val = readl(tcphy->base + TX_DIG_CTRL_REG_2); |
f85fd4c9 | 718 | val |= TX_HIGH_Z_TM_EN; |
e96be45c CZ |
719 | writel(val, tcphy->base + TX_DIG_CTRL_REG_2); |
720 | } | |
721 | ||
722 | static int tcphy_phy_init(struct rockchip_typec_phy *tcphy, u8 mode) | |
723 | { | |
0fbc47d9 | 724 | const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs; |
e96be45c CZ |
725 | int ret, i; |
726 | u32 val; | |
727 | ||
728 | ret = clk_prepare_enable(tcphy->clk_core); | |
729 | if (ret) { | |
730 | dev_err(tcphy->dev, "Failed to prepare_enable core clock\n"); | |
731 | return ret; | |
732 | } | |
733 | ||
734 | ret = clk_prepare_enable(tcphy->clk_ref); | |
735 | if (ret) { | |
736 | dev_err(tcphy->dev, "Failed to prepare_enable ref clock\n"); | |
737 | goto err_clk_core; | |
738 | } | |
739 | ||
740 | reset_control_deassert(tcphy->tcphy_rst); | |
741 | ||
742 | property_enable(tcphy, &cfg->typec_conn_dir, tcphy->flip); | |
f98b7438 | 743 | tcphy_dp_aux_set_flip(tcphy); |
e96be45c CZ |
744 | |
745 | tcphy_cfg_24m(tcphy); | |
746 | ||
747 | if (mode == MODE_DFP_DP) { | |
748 | tcphy_cfg_dp_pll(tcphy); | |
749 | for (i = 0; i < 4; i++) | |
750 | tcphy_dp_cfg_lane(tcphy, i); | |
751 | ||
752 | writel(PIN_ASSIGN_C_E, tcphy->base + PMA_LANE_CFG); | |
753 | } else { | |
754 | tcphy_cfg_usb3_pll(tcphy); | |
755 | tcphy_cfg_dp_pll(tcphy); | |
756 | if (tcphy->flip) { | |
757 | tcphy_tx_usb3_cfg_lane(tcphy, 3); | |
758 | tcphy_rx_usb3_cfg_lane(tcphy, 2); | |
759 | tcphy_dp_cfg_lane(tcphy, 0); | |
760 | tcphy_dp_cfg_lane(tcphy, 1); | |
761 | } else { | |
762 | tcphy_tx_usb3_cfg_lane(tcphy, 0); | |
763 | tcphy_rx_usb3_cfg_lane(tcphy, 1); | |
764 | tcphy_dp_cfg_lane(tcphy, 2); | |
765 | tcphy_dp_cfg_lane(tcphy, 3); | |
766 | } | |
767 | ||
768 | writel(PIN_ASSIGN_D_F, tcphy->base + PMA_LANE_CFG); | |
769 | } | |
770 | ||
771 | writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL); | |
772 | ||
773 | reset_control_deassert(tcphy->uphy_rst); | |
774 | ||
775 | ret = readx_poll_timeout(readl, tcphy->base + PMA_CMN_CTRL1, | |
776 | val, val & CMN_READY, 10, | |
777 | PHY_MODE_SET_TIMEOUT); | |
778 | if (ret < 0) { | |
779 | dev_err(tcphy->dev, "wait pma ready timeout\n"); | |
780 | ret = -ETIMEDOUT; | |
781 | goto err_wait_pma; | |
782 | } | |
783 | ||
784 | reset_control_deassert(tcphy->pipe_rst); | |
785 | ||
786 | return 0; | |
787 | ||
788 | err_wait_pma: | |
789 | reset_control_assert(tcphy->uphy_rst); | |
790 | reset_control_assert(tcphy->tcphy_rst); | |
791 | clk_disable_unprepare(tcphy->clk_ref); | |
792 | err_clk_core: | |
793 | clk_disable_unprepare(tcphy->clk_core); | |
794 | return ret; | |
795 | } | |
796 | ||
797 | static void tcphy_phy_deinit(struct rockchip_typec_phy *tcphy) | |
798 | { | |
799 | reset_control_assert(tcphy->tcphy_rst); | |
800 | reset_control_assert(tcphy->uphy_rst); | |
801 | reset_control_assert(tcphy->pipe_rst); | |
802 | clk_disable_unprepare(tcphy->clk_core); | |
803 | clk_disable_unprepare(tcphy->clk_ref); | |
804 | } | |
805 | ||
806 | static int tcphy_get_mode(struct rockchip_typec_phy *tcphy) | |
807 | { | |
808 | struct extcon_dev *edev = tcphy->extcon; | |
809 | union extcon_property_value property; | |
810 | unsigned int id; | |
5e39c6cf | 811 | bool ufp, dp; |
e96be45c CZ |
812 | u8 mode; |
813 | int ret; | |
814 | ||
ec1fcd7b EBS |
815 | if (!edev) |
816 | return MODE_DFP_USB; | |
817 | ||
e96be45c | 818 | ufp = extcon_get_state(edev, EXTCON_USB); |
e96be45c CZ |
819 | dp = extcon_get_state(edev, EXTCON_DISP_DP); |
820 | ||
821 | mode = MODE_DFP_USB; | |
822 | id = EXTCON_USB_HOST; | |
823 | ||
824 | if (ufp) { | |
825 | mode = MODE_UFP_USB; | |
826 | id = EXTCON_USB; | |
827 | } else if (dp) { | |
828 | mode = MODE_DFP_DP; | |
829 | id = EXTCON_DISP_DP; | |
830 | ||
831 | ret = extcon_get_property(edev, id, EXTCON_PROP_USB_SS, | |
832 | &property); | |
833 | if (ret) { | |
834 | dev_err(tcphy->dev, "get superspeed property failed\n"); | |
835 | return ret; | |
836 | } | |
837 | ||
838 | if (property.intval) | |
839 | mode |= MODE_DFP_USB; | |
840 | } | |
841 | ||
842 | ret = extcon_get_property(edev, id, EXTCON_PROP_USB_TYPEC_POLARITY, | |
843 | &property); | |
844 | if (ret) { | |
845 | dev_err(tcphy->dev, "get polarity property failed\n"); | |
846 | return ret; | |
847 | } | |
848 | ||
849 | tcphy->flip = property.intval ? 1 : 0; | |
850 | ||
851 | return mode; | |
852 | } | |
853 | ||
5eac5e9c CZ |
854 | static int tcphy_cfg_usb3_to_usb2_only(struct rockchip_typec_phy *tcphy, |
855 | bool value) | |
856 | { | |
866d4087 | 857 | const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs; |
5eac5e9c CZ |
858 | |
859 | property_enable(tcphy, &cfg->usb3tousb2_en, value); | |
860 | property_enable(tcphy, &cfg->usb3_host_disable, value); | |
861 | property_enable(tcphy, &cfg->usb3_host_port, !value); | |
862 | ||
863 | return 0; | |
864 | } | |
865 | ||
e96be45c CZ |
866 | static int rockchip_usb3_phy_power_on(struct phy *phy) |
867 | { | |
868 | struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); | |
0fbc47d9 | 869 | const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs; |
e96be45c CZ |
870 | const struct usb3phy_reg *reg = &cfg->pipe_status; |
871 | int timeout, new_mode, ret = 0; | |
872 | u32 val; | |
873 | ||
874 | mutex_lock(&tcphy->lock); | |
875 | ||
876 | new_mode = tcphy_get_mode(tcphy); | |
877 | if (new_mode < 0) { | |
878 | ret = new_mode; | |
879 | goto unlock_ret; | |
880 | } | |
881 | ||
882 | /* DP-only mode; fall back to USB2 */ | |
5eac5e9c CZ |
883 | if (!(new_mode & (MODE_DFP_USB | MODE_UFP_USB))) { |
884 | tcphy_cfg_usb3_to_usb2_only(tcphy, true); | |
e96be45c | 885 | goto unlock_ret; |
5eac5e9c | 886 | } |
e96be45c CZ |
887 | |
888 | if (tcphy->mode == new_mode) | |
889 | goto unlock_ret; | |
890 | ||
2fb85009 DA |
891 | if (tcphy->mode == MODE_DISCONNECT) { |
892 | ret = tcphy_phy_init(tcphy, new_mode); | |
893 | if (ret) | |
894 | goto unlock_ret; | |
895 | } | |
e96be45c CZ |
896 | |
897 | /* wait TCPHY for pipe ready */ | |
898 | for (timeout = 0; timeout < 100; timeout++) { | |
899 | regmap_read(tcphy->grf_regs, reg->offset, &val); | |
900 | if (!(val & BIT(reg->enable_bit))) { | |
901 | tcphy->mode |= new_mode & (MODE_DFP_USB | MODE_UFP_USB); | |
5eac5e9c | 902 | |
f293f740 | 903 | /* enable usb3 host */ |
5eac5e9c | 904 | tcphy_cfg_usb3_to_usb2_only(tcphy, false); |
e96be45c CZ |
905 | goto unlock_ret; |
906 | } | |
907 | usleep_range(10, 20); | |
908 | } | |
909 | ||
910 | if (tcphy->mode == MODE_DISCONNECT) | |
911 | tcphy_phy_deinit(tcphy); | |
912 | ||
913 | ret = -ETIMEDOUT; | |
914 | ||
915 | unlock_ret: | |
916 | mutex_unlock(&tcphy->lock); | |
917 | return ret; | |
918 | } | |
919 | ||
920 | static int rockchip_usb3_phy_power_off(struct phy *phy) | |
921 | { | |
922 | struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); | |
923 | ||
924 | mutex_lock(&tcphy->lock); | |
5eac5e9c | 925 | tcphy_cfg_usb3_to_usb2_only(tcphy, false); |
e96be45c CZ |
926 | |
927 | if (tcphy->mode == MODE_DISCONNECT) | |
928 | goto unlock; | |
929 | ||
930 | tcphy->mode &= ~(MODE_UFP_USB | MODE_DFP_USB); | |
931 | if (tcphy->mode == MODE_DISCONNECT) | |
932 | tcphy_phy_deinit(tcphy); | |
933 | ||
934 | unlock: | |
935 | mutex_unlock(&tcphy->lock); | |
936 | return 0; | |
937 | } | |
938 | ||
939 | static const struct phy_ops rockchip_usb3_phy_ops = { | |
940 | .power_on = rockchip_usb3_phy_power_on, | |
941 | .power_off = rockchip_usb3_phy_power_off, | |
942 | .owner = THIS_MODULE, | |
943 | }; | |
944 | ||
945 | static int rockchip_dp_phy_power_on(struct phy *phy) | |
946 | { | |
947 | struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); | |
866d4087 | 948 | const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs; |
e96be45c CZ |
949 | int new_mode, ret = 0; |
950 | u32 val; | |
951 | ||
952 | mutex_lock(&tcphy->lock); | |
953 | ||
954 | new_mode = tcphy_get_mode(tcphy); | |
955 | if (new_mode < 0) { | |
956 | ret = new_mode; | |
957 | goto unlock_ret; | |
958 | } | |
959 | ||
960 | if (!(new_mode & MODE_DFP_DP)) { | |
961 | ret = -ENODEV; | |
962 | goto unlock_ret; | |
963 | } | |
964 | ||
965 | if (tcphy->mode == new_mode) | |
966 | goto unlock_ret; | |
967 | ||
968 | /* | |
969 | * If the PHY has been power on, but the mode is not DP only mode, | |
970 | * re-init the PHY for setting all of 4 lanes to DP. | |
971 | */ | |
972 | if (new_mode == MODE_DFP_DP && tcphy->mode != MODE_DISCONNECT) { | |
973 | tcphy_phy_deinit(tcphy); | |
2fb85009 | 974 | ret = tcphy_phy_init(tcphy, new_mode); |
e96be45c | 975 | } else if (tcphy->mode == MODE_DISCONNECT) { |
2fb85009 | 976 | ret = tcphy_phy_init(tcphy, new_mode); |
e96be45c | 977 | } |
2fb85009 DA |
978 | if (ret) |
979 | goto unlock_ret; | |
e96be45c | 980 | |
866d4087 CZ |
981 | property_enable(tcphy, &cfg->uphy_dp_sel, 1); |
982 | ||
e96be45c CZ |
983 | ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL, |
984 | val, val & DP_MODE_A2, 1000, | |
985 | PHY_MODE_SET_TIMEOUT); | |
986 | if (ret < 0) { | |
987 | dev_err(tcphy->dev, "failed to wait TCPHY enter A2\n"); | |
988 | goto power_on_finish; | |
989 | } | |
990 | ||
991 | tcphy_dp_aux_calibration(tcphy); | |
992 | ||
993 | writel(DP_MODE_ENTER_A0, tcphy->base + DP_MODE_CTL); | |
994 | ||
995 | ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL, | |
996 | val, val & DP_MODE_A0, 1000, | |
997 | PHY_MODE_SET_TIMEOUT); | |
998 | if (ret < 0) { | |
999 | writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL); | |
1000 | dev_err(tcphy->dev, "failed to wait TCPHY enter A0\n"); | |
1001 | goto power_on_finish; | |
1002 | } | |
1003 | ||
1004 | tcphy->mode |= MODE_DFP_DP; | |
1005 | ||
1006 | power_on_finish: | |
1007 | if (tcphy->mode == MODE_DISCONNECT) | |
1008 | tcphy_phy_deinit(tcphy); | |
1009 | unlock_ret: | |
1010 | mutex_unlock(&tcphy->lock); | |
1011 | return ret; | |
1012 | } | |
1013 | ||
1014 | static int rockchip_dp_phy_power_off(struct phy *phy) | |
1015 | { | |
1016 | struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); | |
1017 | ||
1018 | mutex_lock(&tcphy->lock); | |
1019 | ||
1020 | if (tcphy->mode == MODE_DISCONNECT) | |
1021 | goto unlock; | |
1022 | ||
1023 | tcphy->mode &= ~MODE_DFP_DP; | |
1024 | ||
1025 | writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL); | |
1026 | ||
1027 | if (tcphy->mode == MODE_DISCONNECT) | |
1028 | tcphy_phy_deinit(tcphy); | |
1029 | ||
1030 | unlock: | |
1031 | mutex_unlock(&tcphy->lock); | |
1032 | return 0; | |
1033 | } | |
1034 | ||
1035 | static const struct phy_ops rockchip_dp_phy_ops = { | |
1036 | .power_on = rockchip_dp_phy_power_on, | |
1037 | .power_off = rockchip_dp_phy_power_off, | |
1038 | .owner = THIS_MODULE, | |
1039 | }; | |
1040 | ||
e96be45c CZ |
1041 | static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy, |
1042 | struct device *dev) | |
1043 | { | |
e96be45c CZ |
1044 | tcphy->grf_regs = syscon_regmap_lookup_by_phandle(dev->of_node, |
1045 | "rockchip,grf"); | |
1046 | if (IS_ERR(tcphy->grf_regs)) { | |
1047 | dev_err(dev, "could not find grf dt node\n"); | |
1048 | return PTR_ERR(tcphy->grf_regs); | |
1049 | } | |
1050 | ||
1051 | tcphy->clk_core = devm_clk_get(dev, "tcpdcore"); | |
1052 | if (IS_ERR(tcphy->clk_core)) { | |
1053 | dev_err(dev, "could not get uphy core clock\n"); | |
1054 | return PTR_ERR(tcphy->clk_core); | |
1055 | } | |
1056 | ||
1057 | tcphy->clk_ref = devm_clk_get(dev, "tcpdphy-ref"); | |
1058 | if (IS_ERR(tcphy->clk_ref)) { | |
1059 | dev_err(dev, "could not get uphy ref clock\n"); | |
1060 | return PTR_ERR(tcphy->clk_ref); | |
1061 | } | |
1062 | ||
1063 | tcphy->uphy_rst = devm_reset_control_get(dev, "uphy"); | |
1064 | if (IS_ERR(tcphy->uphy_rst)) { | |
1065 | dev_err(dev, "no uphy_rst reset control found\n"); | |
1066 | return PTR_ERR(tcphy->uphy_rst); | |
1067 | } | |
1068 | ||
1069 | tcphy->pipe_rst = devm_reset_control_get(dev, "uphy-pipe"); | |
1070 | if (IS_ERR(tcphy->pipe_rst)) { | |
1071 | dev_err(dev, "no pipe_rst reset control found\n"); | |
1072 | return PTR_ERR(tcphy->pipe_rst); | |
1073 | } | |
1074 | ||
1075 | tcphy->tcphy_rst = devm_reset_control_get(dev, "uphy-tcphy"); | |
1076 | if (IS_ERR(tcphy->tcphy_rst)) { | |
1077 | dev_err(dev, "no tcphy_rst reset control found\n"); | |
1078 | return PTR_ERR(tcphy->tcphy_rst); | |
1079 | } | |
1080 | ||
1081 | return 0; | |
1082 | } | |
1083 | ||
1084 | static void typec_phy_pre_init(struct rockchip_typec_phy *tcphy) | |
1085 | { | |
0fbc47d9 | 1086 | const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs; |
e96be45c CZ |
1087 | |
1088 | reset_control_assert(tcphy->tcphy_rst); | |
1089 | reset_control_assert(tcphy->uphy_rst); | |
1090 | reset_control_assert(tcphy->pipe_rst); | |
1091 | ||
1092 | /* select external psm clock */ | |
1093 | property_enable(tcphy, &cfg->external_psm, 1); | |
1094 | property_enable(tcphy, &cfg->usb3tousb2_en, 0); | |
1095 | ||
1096 | tcphy->mode = MODE_DISCONNECT; | |
1097 | } | |
1098 | ||
1099 | static int rockchip_typec_phy_probe(struct platform_device *pdev) | |
1100 | { | |
1101 | struct device *dev = &pdev->dev; | |
1102 | struct device_node *np = dev->of_node; | |
1103 | struct device_node *child_np; | |
1104 | struct rockchip_typec_phy *tcphy; | |
1105 | struct phy_provider *phy_provider; | |
1106 | struct resource *res; | |
0fbc47d9 EBS |
1107 | const struct rockchip_usb3phy_port_cfg *phy_cfgs; |
1108 | const struct of_device_id *match; | |
1109 | int index, ret; | |
e96be45c CZ |
1110 | |
1111 | tcphy = devm_kzalloc(dev, sizeof(*tcphy), GFP_KERNEL); | |
1112 | if (!tcphy) | |
1113 | return -ENOMEM; | |
1114 | ||
0fbc47d9 EBS |
1115 | match = of_match_device(dev->driver->of_match_table, dev); |
1116 | if (!match || !match->data) { | |
1117 | dev_err(dev, "phy configs are not assigned!\n"); | |
1118 | return -EINVAL; | |
1119 | } | |
1120 | ||
e96be45c CZ |
1121 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1122 | tcphy->base = devm_ioremap_resource(dev, res); | |
1123 | if (IS_ERR(tcphy->base)) | |
1124 | return PTR_ERR(tcphy->base); | |
1125 | ||
0fbc47d9 EBS |
1126 | phy_cfgs = match->data; |
1127 | /* find out a proper config which can be matched with dt. */ | |
1128 | index = 0; | |
1129 | while (phy_cfgs[index].reg) { | |
1130 | if (phy_cfgs[index].reg == res->start) { | |
1131 | tcphy->port_cfgs = &phy_cfgs[index]; | |
1132 | break; | |
1133 | } | |
1134 | ||
1135 | ++index; | |
1136 | } | |
1137 | ||
1138 | if (!tcphy->port_cfgs) { | |
ac9ba7dc RH |
1139 | dev_err(dev, "no phy-config can be matched with %pOFn node\n", |
1140 | np); | |
0fbc47d9 EBS |
1141 | return -EINVAL; |
1142 | } | |
1143 | ||
e96be45c CZ |
1144 | ret = tcphy_parse_dt(tcphy, dev); |
1145 | if (ret) | |
1146 | return ret; | |
1147 | ||
1148 | tcphy->dev = dev; | |
1149 | platform_set_drvdata(pdev, tcphy); | |
1150 | mutex_init(&tcphy->lock); | |
1151 | ||
1152 | typec_phy_pre_init(tcphy); | |
1153 | ||
1154 | tcphy->extcon = extcon_get_edev_by_phandle(dev, 0); | |
1155 | if (IS_ERR(tcphy->extcon)) { | |
ec1fcd7b EBS |
1156 | if (PTR_ERR(tcphy->extcon) == -ENODEV) { |
1157 | tcphy->extcon = NULL; | |
1158 | } else { | |
1159 | if (PTR_ERR(tcphy->extcon) != -EPROBE_DEFER) | |
1160 | dev_err(dev, "Invalid or missing extcon\n"); | |
1161 | return PTR_ERR(tcphy->extcon); | |
1162 | } | |
e96be45c CZ |
1163 | } |
1164 | ||
2a4d5962 CZ |
1165 | pm_runtime_enable(dev); |
1166 | ||
e96be45c CZ |
1167 | for_each_available_child_of_node(np, child_np) { |
1168 | struct phy *phy; | |
1169 | ||
03e7d002 | 1170 | if (of_node_name_eq(child_np, "dp-port")) |
e96be45c CZ |
1171 | phy = devm_phy_create(dev, child_np, |
1172 | &rockchip_dp_phy_ops); | |
03e7d002 | 1173 | else if (of_node_name_eq(child_np, "usb3-port")) |
e96be45c CZ |
1174 | phy = devm_phy_create(dev, child_np, |
1175 | &rockchip_usb3_phy_ops); | |
1176 | else | |
1177 | continue; | |
1178 | ||
1179 | if (IS_ERR(phy)) { | |
ac9ba7dc RH |
1180 | dev_err(dev, "failed to create phy: %pOFn\n", |
1181 | child_np); | |
3cb0ab6e | 1182 | pm_runtime_disable(dev); |
6b5371ad | 1183 | of_node_put(child_np); |
e96be45c CZ |
1184 | return PTR_ERR(phy); |
1185 | } | |
1186 | ||
1187 | phy_set_drvdata(phy, tcphy); | |
1188 | } | |
1189 | ||
1190 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | |
1191 | if (IS_ERR(phy_provider)) { | |
1192 | dev_err(dev, "Failed to register phy provider\n"); | |
3cb0ab6e | 1193 | pm_runtime_disable(dev); |
e96be45c CZ |
1194 | return PTR_ERR(phy_provider); |
1195 | } | |
1196 | ||
1197 | return 0; | |
1198 | } | |
1199 | ||
2a4d5962 CZ |
1200 | static int rockchip_typec_phy_remove(struct platform_device *pdev) |
1201 | { | |
1202 | pm_runtime_disable(&pdev->dev); | |
1203 | ||
1204 | return 0; | |
1205 | } | |
1206 | ||
e96be45c | 1207 | static const struct of_device_id rockchip_typec_phy_dt_ids[] = { |
0fbc47d9 EBS |
1208 | { |
1209 | .compatible = "rockchip,rk3399-typec-phy", | |
1210 | .data = &rk3399_usb3phy_port_cfgs | |
1211 | }, | |
1212 | { /* sentinel */ } | |
e96be45c CZ |
1213 | }; |
1214 | ||
1215 | MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids); | |
1216 | ||
1217 | static struct platform_driver rockchip_typec_phy_driver = { | |
1218 | .probe = rockchip_typec_phy_probe, | |
2a4d5962 | 1219 | .remove = rockchip_typec_phy_remove, |
e96be45c CZ |
1220 | .driver = { |
1221 | .name = "rockchip-typec-phy", | |
1222 | .of_match_table = rockchip_typec_phy_dt_ids, | |
1223 | }, | |
1224 | }; | |
1225 | ||
1226 | module_platform_driver(rockchip_typec_phy_driver); | |
1227 | ||
1228 | MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); | |
1229 | MODULE_AUTHOR("Kever Yang <kever.yang@rock-chips.com>"); | |
1230 | MODULE_DESCRIPTION("Rockchip USB TYPE-C PHY driver"); | |
1231 | MODULE_LICENSE("GPL v2"); |