1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * phy-rtk-usb3.c RTK usb3.0 phy driver |
4 | * |
5 | * copyright (c) 2023 realtek semiconductor corporation |
6 | * |
7 | */ |
8 | |
9 | #include <linux/module.h> |
10 | #include <linux/of.h> |
11 | #include <linux/of_address.h> |
12 | #include <linux/platform_device.h> |
13 | #include <linux/uaccess.h> |
14 | #include <linux/debugfs.h> |
15 | #include <linux/nvmem-consumer.h> |
16 | #include <linux/regmap.h> |
17 | #include <linux/sys_soc.h> |
18 | #include <linux/mfd/syscon.h> |
19 | #include <linux/phy/phy.h> |
20 | #include <linux/usb.h> |
21 | |
22 | #define USB_MDIO_CTRL_PHY_BUSY BIT(7) |
23 | #define USB_MDIO_CTRL_PHY_WRITE BIT(0) |
24 | #define USB_MDIO_CTRL_PHY_ADDR_SHIFT 8 |
25 | #define USB_MDIO_CTRL_PHY_DATA_SHIFT 16 |
26 | |
27 | #define MAX_USB_PHY_DATA_SIZE 0x30 |
28 | #define PHY_ADDR_0X09 0x09 |
29 | #define PHY_ADDR_0X0B 0x0b |
30 | #define PHY_ADDR_0X0D 0x0d |
31 | #define PHY_ADDR_0X10 0x10 |
32 | #define PHY_ADDR_0X1F 0x1f |
33 | #define PHY_ADDR_0X20 0x20 |
34 | #define PHY_ADDR_0X21 0x21 |
35 | #define PHY_ADDR_0X30 0x30 |
36 | |
37 | #define REG_0X09_FORCE_CALIBRATION BIT(9) |
38 | #define REG_0X0B_RX_OFFSET_RANGE_MASK 0xc |
39 | #define REG_0X0D_RX_DEBUG_TEST_EN BIT(6) |
40 | #define REG_0X10_DEBUG_MODE_SETTING 0x3c0 |
41 | #define REG_0X10_DEBUG_MODE_SETTING_MASK 0x3f8 |
42 | #define REG_0X1F_RX_OFFSET_CODE_MASK 0x1e |
43 | |
44 | #define USB_U3_TX_LFPS_SWING_TRIM_SHIFT 4 |
45 | #define USB_U3_TX_LFPS_SWING_TRIM_MASK 0xf |
46 | #define AMPLITUDE_CONTROL_COARSE_MASK 0xff |
47 | #define AMPLITUDE_CONTROL_FINE_MASK 0xffff |
48 | #define AMPLITUDE_CONTROL_COARSE_DEFAULT 0xff |
49 | #define AMPLITUDE_CONTROL_FINE_DEFAULT 0xffff |
50 | |
51 | #define PHY_ADDR_MAP_ARRAY_INDEX(addr) (addr) |
52 | #define ARRAY_INDEX_MAP_PHY_ADDR(index) (index) |
53 | |
54 | struct phy_reg { |
55 | void __iomem *reg_mdio_ctl; |
56 | }; |
57 | |
58 | struct phy_data { |
59 | u8 addr; |
60 | u16 data; |
61 | }; |
62 | |
63 | struct phy_cfg { |
64 | int param_size; |
65 | struct phy_data param[MAX_USB_PHY_DATA_SIZE]; |
66 | |
67 | bool check_efuse; |
68 | bool do_toggle; |
69 | bool do_toggle_once; |
70 | bool use_default_parameter; |
71 | bool check_rx_front_end_offset; |
72 | }; |
73 | |
74 | struct phy_parameter { |
75 | struct phy_reg phy_reg; |
76 | |
77 | /* Get from efuse */ |
78 | u8 efuse_usb_u3_tx_lfps_swing_trim; |
79 | |
80 | /* Get from dts */ |
81 | u32 amplitude_control_coarse; |
82 | u32 amplitude_control_fine; |
83 | }; |
84 | |
85 | struct rtk_phy { |
86 | struct device *dev; |
87 | |
88 | struct phy_cfg *phy_cfg; |
89 | int num_phy; |
90 | struct phy_parameter *phy_parameter; |
91 | |
92 | struct dentry *debug_dir; |
93 | }; |
94 | |
95 | #define PHY_IO_TIMEOUT_USEC (50000) |
96 | #define PHY_IO_DELAY_US (100) |
97 | |
98 | static inline int utmi_wait_register(void __iomem *reg, u32 mask, u32 result) |
99 | { |
100 | int ret; |
101 | unsigned int val; |
102 | |
103 | ret = read_poll_timeout(readl, val, ((val & mask) == result), |
104 | PHY_IO_DELAY_US, PHY_IO_TIMEOUT_USEC, false, reg); |
105 | if (ret) { |
106 | pr_err("%s can't program USB phy\n" , __func__); |
107 | return -ETIMEDOUT; |
108 | } |
109 | |
110 | return 0; |
111 | } |
112 | |
113 | static int rtk_phy3_wait_vbusy(struct phy_reg *phy_reg) |
114 | { |
115 | return utmi_wait_register(reg: phy_reg->reg_mdio_ctl, USB_MDIO_CTRL_PHY_BUSY, result: 0); |
116 | } |
117 | |
118 | static u16 rtk_phy_read(struct phy_reg *phy_reg, char addr) |
119 | { |
120 | unsigned int tmp; |
121 | u32 value; |
122 | |
123 | tmp = (addr << USB_MDIO_CTRL_PHY_ADDR_SHIFT); |
124 | |
125 | writel(val: tmp, addr: phy_reg->reg_mdio_ctl); |
126 | |
127 | rtk_phy3_wait_vbusy(phy_reg); |
128 | |
129 | value = readl(addr: phy_reg->reg_mdio_ctl); |
130 | value = value >> USB_MDIO_CTRL_PHY_DATA_SHIFT; |
131 | |
132 | return (u16)value; |
133 | } |
134 | |
135 | static int rtk_phy_write(struct phy_reg *phy_reg, char addr, u16 data) |
136 | { |
137 | unsigned int val; |
138 | |
139 | val = USB_MDIO_CTRL_PHY_WRITE | |
140 | (addr << USB_MDIO_CTRL_PHY_ADDR_SHIFT) | |
141 | (data << USB_MDIO_CTRL_PHY_DATA_SHIFT); |
142 | |
143 | writel(val, addr: phy_reg->reg_mdio_ctl); |
144 | |
145 | rtk_phy3_wait_vbusy(phy_reg); |
146 | |
147 | return 0; |
148 | } |
149 | |
150 | static void do_rtk_usb3_phy_toggle(struct rtk_phy *rtk_phy, int index, bool connect) |
151 | { |
152 | struct phy_cfg *phy_cfg = rtk_phy->phy_cfg; |
153 | struct phy_reg *phy_reg; |
154 | struct phy_parameter *phy_parameter; |
155 | struct phy_data *phy_data; |
156 | u8 addr; |
157 | u16 data; |
158 | int i; |
159 | |
160 | phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; |
161 | phy_reg = &phy_parameter->phy_reg; |
162 | |
163 | if (!phy_cfg->do_toggle) |
164 | return; |
165 | |
166 | i = PHY_ADDR_MAP_ARRAY_INDEX(PHY_ADDR_0X09); |
167 | phy_data = phy_cfg->param + i; |
168 | addr = phy_data->addr; |
169 | data = phy_data->data; |
170 | |
171 | if (!addr && !data) { |
172 | addr = PHY_ADDR_0X09; |
173 | data = rtk_phy_read(phy_reg, addr); |
174 | phy_data->addr = addr; |
175 | phy_data->data = data; |
176 | } |
177 | |
178 | rtk_phy_write(phy_reg, addr, data: data & (~REG_0X09_FORCE_CALIBRATION)); |
179 | mdelay(1); |
180 | rtk_phy_write(phy_reg, addr, data: data | REG_0X09_FORCE_CALIBRATION); |
181 | } |
182 | |
183 | static int do_rtk_phy_init(struct rtk_phy *rtk_phy, int index) |
184 | { |
185 | struct phy_cfg *phy_cfg; |
186 | struct phy_reg *phy_reg; |
187 | struct phy_parameter *phy_parameter; |
188 | int i = 0; |
189 | |
190 | phy_cfg = rtk_phy->phy_cfg; |
191 | phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; |
192 | phy_reg = &phy_parameter->phy_reg; |
193 | |
194 | if (phy_cfg->use_default_parameter) |
195 | goto do_toggle; |
196 | |
197 | for (i = 0; i < phy_cfg->param_size; i++) { |
198 | struct phy_data *phy_data = phy_cfg->param + i; |
199 | u8 addr = phy_data->addr; |
200 | u16 data = phy_data->data; |
201 | |
202 | if (!addr && !data) |
203 | continue; |
204 | |
205 | rtk_phy_write(phy_reg, addr, data); |
206 | } |
207 | |
208 | do_toggle: |
209 | if (phy_cfg->do_toggle_once) |
210 | phy_cfg->do_toggle = true; |
211 | |
212 | do_rtk_usb3_phy_toggle(rtk_phy, index, connect: false); |
213 | |
214 | if (phy_cfg->do_toggle_once) { |
215 | u16 check_value = 0; |
216 | int count = 10; |
217 | u16 value_0x0d, value_0x10; |
218 | |
219 | /* Enable Debug mode by set 0x0D and 0x10 */ |
220 | value_0x0d = rtk_phy_read(phy_reg, PHY_ADDR_0X0D); |
221 | value_0x10 = rtk_phy_read(phy_reg, PHY_ADDR_0X10); |
222 | |
223 | rtk_phy_write(phy_reg, PHY_ADDR_0X0D, |
224 | data: value_0x0d | REG_0X0D_RX_DEBUG_TEST_EN); |
225 | rtk_phy_write(phy_reg, PHY_ADDR_0X10, |
226 | data: (value_0x10 & ~REG_0X10_DEBUG_MODE_SETTING_MASK) | |
227 | REG_0X10_DEBUG_MODE_SETTING); |
228 | |
229 | check_value = rtk_phy_read(phy_reg, PHY_ADDR_0X30); |
230 | |
231 | while (!(check_value & BIT(15))) { |
232 | check_value = rtk_phy_read(phy_reg, PHY_ADDR_0X30); |
233 | mdelay(1); |
234 | if (count-- < 0) |
235 | break; |
236 | } |
237 | |
238 | if (!(check_value & BIT(15))) |
239 | dev_info(rtk_phy->dev, "toggle fail addr=0x%02x, data=0x%04x\n" , |
240 | PHY_ADDR_0X30, check_value); |
241 | |
242 | /* Disable Debug mode by set 0x0D and 0x10 to default*/ |
243 | rtk_phy_write(phy_reg, PHY_ADDR_0X0D, data: value_0x0d); |
244 | rtk_phy_write(phy_reg, PHY_ADDR_0X10, data: value_0x10); |
245 | |
246 | phy_cfg->do_toggle = false; |
247 | } |
248 | |
249 | if (phy_cfg->check_rx_front_end_offset) { |
250 | u16 rx_offset_code, rx_offset_range; |
251 | u16 code_mask = REG_0X1F_RX_OFFSET_CODE_MASK; |
252 | u16 range_mask = REG_0X0B_RX_OFFSET_RANGE_MASK; |
253 | bool do_update = false; |
254 | |
255 | rx_offset_code = rtk_phy_read(phy_reg, PHY_ADDR_0X1F); |
256 | if (((rx_offset_code & code_mask) == 0x0) || |
257 | ((rx_offset_code & code_mask) == code_mask)) |
258 | do_update = true; |
259 | |
260 | rx_offset_range = rtk_phy_read(phy_reg, PHY_ADDR_0X0B); |
261 | if (((rx_offset_range & range_mask) == range_mask) && do_update) { |
262 | dev_warn(rtk_phy->dev, "Don't update rx_offset_range (rx_offset_code=0x%x, rx_offset_range=0x%x)\n" , |
263 | rx_offset_code, rx_offset_range); |
264 | do_update = false; |
265 | } |
266 | |
267 | if (do_update) { |
268 | u16 tmp1, tmp2; |
269 | |
270 | tmp1 = rx_offset_range & (~range_mask); |
271 | tmp2 = rx_offset_range & range_mask; |
272 | tmp2 += (1 << 2); |
273 | rx_offset_range = tmp1 | (tmp2 & range_mask); |
274 | rtk_phy_write(phy_reg, PHY_ADDR_0X0B, data: rx_offset_range); |
275 | goto do_toggle; |
276 | } |
277 | } |
278 | |
279 | return 0; |
280 | } |
281 | |
282 | static int rtk_phy_init(struct phy *phy) |
283 | { |
284 | struct rtk_phy *rtk_phy = phy_get_drvdata(phy); |
285 | int ret = 0; |
286 | int i; |
287 | unsigned long phy_init_time = jiffies; |
288 | |
289 | for (i = 0; i < rtk_phy->num_phy; i++) |
290 | ret = do_rtk_phy_init(rtk_phy, index: i); |
291 | |
292 | dev_dbg(rtk_phy->dev, "Initialized RTK USB 3.0 PHY (take %dms)\n" , |
293 | jiffies_to_msecs(jiffies - phy_init_time)); |
294 | |
295 | return ret; |
296 | } |
297 | |
298 | static int rtk_phy_exit(struct phy *phy) |
299 | { |
300 | return 0; |
301 | } |
302 | |
303 | static void rtk_phy_toggle(struct rtk_phy *rtk_phy, bool connect, int port) |
304 | { |
305 | int index = port; |
306 | |
307 | if (index > rtk_phy->num_phy) { |
308 | dev_err(rtk_phy->dev, "%s: The port=%d is not in usb phy (num_phy=%d)\n" , |
309 | __func__, index, rtk_phy->num_phy); |
310 | return; |
311 | } |
312 | |
313 | do_rtk_usb3_phy_toggle(rtk_phy, index, connect); |
314 | } |
315 | |
316 | static int rtk_phy_connect(struct phy *phy, int port) |
317 | { |
318 | struct rtk_phy *rtk_phy = phy_get_drvdata(phy); |
319 | |
320 | dev_dbg(rtk_phy->dev, "%s port=%d\n" , __func__, port); |
321 | rtk_phy_toggle(rtk_phy, connect: true, port); |
322 | |
323 | return 0; |
324 | } |
325 | |
326 | static int rtk_phy_disconnect(struct phy *phy, int port) |
327 | { |
328 | struct rtk_phy *rtk_phy = phy_get_drvdata(phy); |
329 | |
330 | dev_dbg(rtk_phy->dev, "%s port=%d\n" , __func__, port); |
331 | rtk_phy_toggle(rtk_phy, connect: false, port); |
332 | |
333 | return 0; |
334 | } |
335 | |
336 | static const struct phy_ops ops = { |
337 | .init = rtk_phy_init, |
338 | .exit = rtk_phy_exit, |
339 | .connect = rtk_phy_connect, |
340 | .disconnect = rtk_phy_disconnect, |
341 | .owner = THIS_MODULE, |
342 | }; |
343 | |
344 | #ifdef CONFIG_DEBUG_FS |
345 | static struct dentry *create_phy_debug_root(void) |
346 | { |
347 | struct dentry *phy_debug_root; |
348 | |
349 | phy_debug_root = debugfs_lookup(name: "phy" , parent: usb_debug_root); |
350 | if (!phy_debug_root) |
351 | phy_debug_root = debugfs_create_dir(name: "phy" , parent: usb_debug_root); |
352 | |
353 | return phy_debug_root; |
354 | } |
355 | |
356 | static int rtk_usb3_parameter_show(struct seq_file *s, void *unused) |
357 | { |
358 | struct rtk_phy *rtk_phy = s->private; |
359 | struct phy_cfg *phy_cfg; |
360 | int i, index; |
361 | |
362 | phy_cfg = rtk_phy->phy_cfg; |
363 | |
364 | seq_puts(m: s, s: "Property:\n" ); |
365 | seq_printf(m: s, fmt: " check_efuse: %s\n" , |
366 | phy_cfg->check_efuse ? "Enable" : "Disable" ); |
367 | seq_printf(m: s, fmt: " do_toggle: %s\n" , |
368 | phy_cfg->do_toggle ? "Enable" : "Disable" ); |
369 | seq_printf(m: s, fmt: " do_toggle_once: %s\n" , |
370 | phy_cfg->do_toggle_once ? "Enable" : "Disable" ); |
371 | seq_printf(m: s, fmt: " use_default_parameter: %s\n" , |
372 | phy_cfg->use_default_parameter ? "Enable" : "Disable" ); |
373 | |
374 | for (index = 0; index < rtk_phy->num_phy; index++) { |
375 | struct phy_reg *phy_reg; |
376 | struct phy_parameter *phy_parameter; |
377 | |
378 | phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; |
379 | phy_reg = &phy_parameter->phy_reg; |
380 | |
381 | seq_printf(m: s, fmt: "PHY %d:\n" , index); |
382 | |
383 | for (i = 0; i < phy_cfg->param_size; i++) { |
384 | struct phy_data *phy_data = phy_cfg->param + i; |
385 | u8 addr = ARRAY_INDEX_MAP_PHY_ADDR(i); |
386 | u16 data = phy_data->data; |
387 | |
388 | if (!phy_data->addr && !data) |
389 | seq_printf(m: s, fmt: " addr = 0x%02x, data = none ==> read value = 0x%04x\n" , |
390 | addr, rtk_phy_read(phy_reg, addr)); |
391 | else |
392 | seq_printf(m: s, fmt: " addr = 0x%02x, data = 0x%04x ==> read value = 0x%04x\n" , |
393 | addr, data, rtk_phy_read(phy_reg, addr)); |
394 | } |
395 | |
396 | seq_puts(m: s, s: "PHY Property:\n" ); |
397 | seq_printf(m: s, fmt: " efuse_usb_u3_tx_lfps_swing_trim: 0x%x\n" , |
398 | (int)phy_parameter->efuse_usb_u3_tx_lfps_swing_trim); |
399 | seq_printf(m: s, fmt: " amplitude_control_coarse: 0x%x\n" , |
400 | (int)phy_parameter->amplitude_control_coarse); |
401 | seq_printf(m: s, fmt: " amplitude_control_fine: 0x%x\n" , |
402 | (int)phy_parameter->amplitude_control_fine); |
403 | } |
404 | |
405 | return 0; |
406 | } |
407 | DEFINE_SHOW_ATTRIBUTE(rtk_usb3_parameter); |
408 | |
409 | static inline void create_debug_files(struct rtk_phy *rtk_phy) |
410 | { |
411 | struct dentry *phy_debug_root = NULL; |
412 | |
413 | phy_debug_root = create_phy_debug_root(); |
414 | |
415 | if (!phy_debug_root) |
416 | return; |
417 | |
418 | rtk_phy->debug_dir = debugfs_create_dir(name: dev_name(dev: rtk_phy->dev), parent: phy_debug_root); |
419 | |
420 | debugfs_create_file(name: "parameter" , mode: 0444, parent: rtk_phy->debug_dir, data: rtk_phy, |
421 | fops: &rtk_usb3_parameter_fops); |
422 | } |
423 | |
424 | static inline void remove_debug_files(struct rtk_phy *rtk_phy) |
425 | { |
426 | debugfs_remove_recursive(dentry: rtk_phy->debug_dir); |
427 | } |
428 | #else |
429 | static inline void create_debug_files(struct rtk_phy *rtk_phy) { } |
430 | static inline void remove_debug_files(struct rtk_phy *rtk_phy) { } |
431 | #endif /* CONFIG_DEBUG_FS */ |
432 | |
433 | static int get_phy_data_by_efuse(struct rtk_phy *rtk_phy, |
434 | struct phy_parameter *phy_parameter, int index) |
435 | { |
436 | struct phy_cfg *phy_cfg = rtk_phy->phy_cfg; |
437 | u8 value = 0; |
438 | struct nvmem_cell *cell; |
439 | |
440 | if (!phy_cfg->check_efuse) |
441 | goto out; |
442 | |
443 | cell = nvmem_cell_get(dev: rtk_phy->dev, id: "usb_u3_tx_lfps_swing_trim" ); |
444 | if (IS_ERR(ptr: cell)) { |
445 | dev_dbg(rtk_phy->dev, "%s no usb_u3_tx_lfps_swing_trim: %ld\n" , |
446 | __func__, PTR_ERR(cell)); |
447 | } else { |
448 | unsigned char *buf; |
449 | size_t buf_size; |
450 | |
451 | buf = nvmem_cell_read(cell, len: &buf_size); |
452 | if (!IS_ERR(ptr: buf)) { |
453 | value = buf[0] & USB_U3_TX_LFPS_SWING_TRIM_MASK; |
454 | kfree(objp: buf); |
455 | } |
456 | nvmem_cell_put(cell); |
457 | } |
458 | |
459 | if (value > 0 && value < 0x8) |
460 | phy_parameter->efuse_usb_u3_tx_lfps_swing_trim = 0x8; |
461 | else |
462 | phy_parameter->efuse_usb_u3_tx_lfps_swing_trim = (u8)value; |
463 | |
464 | out: |
465 | return 0; |
466 | } |
467 | |
468 | static void update_amplitude_control_value(struct rtk_phy *rtk_phy, |
469 | struct phy_parameter *phy_parameter) |
470 | { |
471 | struct phy_cfg *phy_cfg; |
472 | struct phy_reg *phy_reg; |
473 | |
474 | phy_reg = &phy_parameter->phy_reg; |
475 | phy_cfg = rtk_phy->phy_cfg; |
476 | |
477 | if (phy_parameter->amplitude_control_coarse != AMPLITUDE_CONTROL_COARSE_DEFAULT) { |
478 | u16 val_mask = AMPLITUDE_CONTROL_COARSE_MASK; |
479 | u16 data; |
480 | |
481 | if (!phy_cfg->param[PHY_ADDR_0X20].addr && !phy_cfg->param[PHY_ADDR_0X20].data) { |
482 | phy_cfg->param[PHY_ADDR_0X20].addr = PHY_ADDR_0X20; |
483 | data = rtk_phy_read(phy_reg, PHY_ADDR_0X20); |
484 | } else { |
485 | data = phy_cfg->param[PHY_ADDR_0X20].data; |
486 | } |
487 | |
488 | data &= (~val_mask); |
489 | data |= (phy_parameter->amplitude_control_coarse & val_mask); |
490 | |
491 | phy_cfg->param[PHY_ADDR_0X20].data = data; |
492 | } |
493 | |
494 | if (phy_parameter->efuse_usb_u3_tx_lfps_swing_trim) { |
495 | u8 efuse_val = phy_parameter->efuse_usb_u3_tx_lfps_swing_trim; |
496 | u16 val_mask = USB_U3_TX_LFPS_SWING_TRIM_MASK; |
497 | int val_shift = USB_U3_TX_LFPS_SWING_TRIM_SHIFT; |
498 | u16 data; |
499 | |
500 | if (!phy_cfg->param[PHY_ADDR_0X20].addr && !phy_cfg->param[PHY_ADDR_0X20].data) { |
501 | phy_cfg->param[PHY_ADDR_0X20].addr = PHY_ADDR_0X20; |
502 | data = rtk_phy_read(phy_reg, PHY_ADDR_0X20); |
503 | } else { |
504 | data = phy_cfg->param[PHY_ADDR_0X20].data; |
505 | } |
506 | |
507 | data &= ~(val_mask << val_shift); |
508 | data |= ((efuse_val & val_mask) << val_shift); |
509 | |
510 | phy_cfg->param[PHY_ADDR_0X20].data = data; |
511 | } |
512 | |
513 | if (phy_parameter->amplitude_control_fine != AMPLITUDE_CONTROL_FINE_DEFAULT) { |
514 | u16 val_mask = AMPLITUDE_CONTROL_FINE_MASK; |
515 | |
516 | if (!phy_cfg->param[PHY_ADDR_0X21].addr && !phy_cfg->param[PHY_ADDR_0X21].data) |
517 | phy_cfg->param[PHY_ADDR_0X21].addr = PHY_ADDR_0X21; |
518 | |
519 | phy_cfg->param[PHY_ADDR_0X21].data = |
520 | phy_parameter->amplitude_control_fine & val_mask; |
521 | } |
522 | } |
523 | |
524 | static int parse_phy_data(struct rtk_phy *rtk_phy) |
525 | { |
526 | struct device *dev = rtk_phy->dev; |
527 | struct phy_parameter *phy_parameter; |
528 | int ret = 0; |
529 | int index; |
530 | |
531 | rtk_phy->phy_parameter = devm_kzalloc(dev, size: sizeof(struct phy_parameter) * |
532 | rtk_phy->num_phy, GFP_KERNEL); |
533 | if (!rtk_phy->phy_parameter) |
534 | return -ENOMEM; |
535 | |
536 | for (index = 0; index < rtk_phy->num_phy; index++) { |
537 | phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; |
538 | |
539 | phy_parameter->phy_reg.reg_mdio_ctl = of_iomap(node: dev->of_node, index: 0) + index; |
540 | |
541 | /* Amplitude control address 0x20 bit 0 to bit 7 */ |
542 | if (of_property_read_u32(np: dev->of_node, propname: "realtek,amplitude-control-coarse-tuning" , |
543 | out_value: &phy_parameter->amplitude_control_coarse)) |
544 | phy_parameter->amplitude_control_coarse = AMPLITUDE_CONTROL_COARSE_DEFAULT; |
545 | |
546 | /* Amplitude control address 0x21 bit 0 to bit 16 */ |
547 | if (of_property_read_u32(np: dev->of_node, propname: "realtek,amplitude-control-fine-tuning" , |
548 | out_value: &phy_parameter->amplitude_control_fine)) |
549 | phy_parameter->amplitude_control_fine = AMPLITUDE_CONTROL_FINE_DEFAULT; |
550 | |
551 | get_phy_data_by_efuse(rtk_phy, phy_parameter, index); |
552 | |
553 | update_amplitude_control_value(rtk_phy, phy_parameter); |
554 | } |
555 | |
556 | return ret; |
557 | } |
558 | |
559 | static int rtk_usb3phy_probe(struct platform_device *pdev) |
560 | { |
561 | struct rtk_phy *rtk_phy; |
562 | struct device *dev = &pdev->dev; |
563 | struct phy *generic_phy; |
564 | struct phy_provider *phy_provider; |
565 | const struct phy_cfg *phy_cfg; |
566 | int ret; |
567 | |
568 | phy_cfg = of_device_get_match_data(dev); |
569 | if (!phy_cfg) { |
570 | dev_err(dev, "phy config are not assigned!\n" ); |
571 | return -EINVAL; |
572 | } |
573 | |
574 | rtk_phy = devm_kzalloc(dev, size: sizeof(*rtk_phy), GFP_KERNEL); |
575 | if (!rtk_phy) |
576 | return -ENOMEM; |
577 | |
578 | rtk_phy->dev = &pdev->dev; |
579 | rtk_phy->phy_cfg = devm_kzalloc(dev, size: sizeof(*phy_cfg), GFP_KERNEL); |
580 | |
581 | memcpy(rtk_phy->phy_cfg, phy_cfg, sizeof(*phy_cfg)); |
582 | |
583 | rtk_phy->num_phy = 1; |
584 | |
585 | ret = parse_phy_data(rtk_phy); |
586 | if (ret) |
587 | goto err; |
588 | |
589 | platform_set_drvdata(pdev, data: rtk_phy); |
590 | |
591 | generic_phy = devm_phy_create(dev: rtk_phy->dev, NULL, ops: &ops); |
592 | if (IS_ERR(ptr: generic_phy)) |
593 | return PTR_ERR(ptr: generic_phy); |
594 | |
595 | phy_set_drvdata(phy: generic_phy, data: rtk_phy); |
596 | |
597 | phy_provider = devm_of_phy_provider_register(rtk_phy->dev, of_phy_simple_xlate); |
598 | if (IS_ERR(ptr: phy_provider)) |
599 | return PTR_ERR(ptr: phy_provider); |
600 | |
601 | create_debug_files(rtk_phy); |
602 | |
603 | err: |
604 | return ret; |
605 | } |
606 | |
607 | static void rtk_usb3phy_remove(struct platform_device *pdev) |
608 | { |
609 | struct rtk_phy *rtk_phy = platform_get_drvdata(pdev); |
610 | |
611 | remove_debug_files(rtk_phy); |
612 | } |
613 | |
614 | static const struct phy_cfg rtd1295_phy_cfg = { |
615 | .param_size = MAX_USB_PHY_DATA_SIZE, |
616 | .param = { [0] = {0x01, 0x4008}, [1] = {0x01, 0xe046}, |
617 | [2] = {0x02, 0x6046}, [3] = {0x03, 0x2779}, |
618 | [4] = {0x04, 0x72f5}, [5] = {0x05, 0x2ad3}, |
619 | [6] = {0x06, 0x000e}, [7] = {0x07, 0x2e00}, |
620 | [8] = {0x08, 0x3591}, [9] = {0x09, 0x525c}, |
621 | [10] = {0x0a, 0xa600}, [11] = {0x0b, 0xa904}, |
622 | [12] = {0x0c, 0xc000}, [13] = {0x0d, 0xef1c}, |
623 | [14] = {0x0e, 0x2000}, [15] = {0x0f, 0x0000}, |
624 | [16] = {0x10, 0x000c}, [17] = {0x11, 0x4c00}, |
625 | [18] = {0x12, 0xfc00}, [19] = {0x13, 0x0c81}, |
626 | [20] = {0x14, 0xde01}, [21] = {0x15, 0x0000}, |
627 | [22] = {0x16, 0x0000}, [23] = {0x17, 0x0000}, |
628 | [24] = {0x18, 0x0000}, [25] = {0x19, 0x4004}, |
629 | [26] = {0x1a, 0x1260}, [27] = {0x1b, 0xff00}, |
630 | [28] = {0x1c, 0xcb00}, [29] = {0x1d, 0xa03f}, |
631 | [30] = {0x1e, 0xc2e0}, [31] = {0x1f, 0x2807}, |
632 | [32] = {0x20, 0x947a}, [33] = {0x21, 0x88aa}, |
633 | [34] = {0x22, 0x0057}, [35] = {0x23, 0xab66}, |
634 | [36] = {0x24, 0x0800}, [37] = {0x25, 0x0000}, |
635 | [38] = {0x26, 0x040a}, [39] = {0x27, 0x01d6}, |
636 | [40] = {0x28, 0xf8c2}, [41] = {0x29, 0x3080}, |
637 | [42] = {0x2a, 0x3082}, [43] = {0x2b, 0x2078}, |
638 | [44] = {0x2c, 0xffff}, [45] = {0x2d, 0xffff}, |
639 | [46] = {0x2e, 0x0000}, [47] = {0x2f, 0x0040}, }, |
640 | .check_efuse = false, |
641 | .do_toggle = true, |
642 | .do_toggle_once = false, |
643 | .use_default_parameter = false, |
644 | .check_rx_front_end_offset = false, |
645 | }; |
646 | |
647 | static const struct phy_cfg rtd1619_phy_cfg = { |
648 | .param_size = MAX_USB_PHY_DATA_SIZE, |
649 | .param = { [8] = {0x08, 0x3591}, |
650 | [38] = {0x26, 0x840b}, |
651 | [40] = {0x28, 0xf842}, }, |
652 | .check_efuse = false, |
653 | .do_toggle = true, |
654 | .do_toggle_once = false, |
655 | .use_default_parameter = false, |
656 | .check_rx_front_end_offset = false, |
657 | }; |
658 | |
659 | static const struct phy_cfg rtd1319_phy_cfg = { |
660 | .param_size = MAX_USB_PHY_DATA_SIZE, |
661 | .param = { [1] = {0x01, 0xac86}, |
662 | [6] = {0x06, 0x0003}, |
663 | [9] = {0x09, 0x924c}, |
664 | [10] = {0x0a, 0xa608}, |
665 | [11] = {0x0b, 0xb905}, |
666 | [14] = {0x0e, 0x2010}, |
667 | [32] = {0x20, 0x705a}, |
668 | [33] = {0x21, 0xf645}, |
669 | [34] = {0x22, 0x0013}, |
670 | [35] = {0x23, 0xcb66}, |
671 | [41] = {0x29, 0xff00}, }, |
672 | .check_efuse = true, |
673 | .do_toggle = true, |
674 | .do_toggle_once = false, |
675 | .use_default_parameter = false, |
676 | .check_rx_front_end_offset = false, |
677 | }; |
678 | |
679 | static const struct phy_cfg rtd1619b_phy_cfg = { |
680 | .param_size = MAX_USB_PHY_DATA_SIZE, |
681 | .param = { [1] = {0x01, 0xac8c}, |
682 | [6] = {0x06, 0x0017}, |
683 | [9] = {0x09, 0x724c}, |
684 | [10] = {0x0a, 0xb610}, |
685 | [11] = {0x0b, 0xb90d}, |
686 | [13] = {0x0d, 0xef2a}, |
687 | [15] = {0x0f, 0x9050}, |
688 | [16] = {0x10, 0x000c}, |
689 | [32] = {0x20, 0x70ff}, |
690 | [34] = {0x22, 0x0013}, |
691 | [35] = {0x23, 0xdb66}, |
692 | [38] = {0x26, 0x8609}, |
693 | [41] = {0x29, 0xff13}, |
694 | [42] = {0x2a, 0x3070}, }, |
695 | .check_efuse = true, |
696 | .do_toggle = false, |
697 | .do_toggle_once = true, |
698 | .use_default_parameter = false, |
699 | .check_rx_front_end_offset = false, |
700 | }; |
701 | |
702 | static const struct phy_cfg rtd1319d_phy_cfg = { |
703 | .param_size = MAX_USB_PHY_DATA_SIZE, |
704 | .param = { [1] = {0x01, 0xac89}, |
705 | [4] = {0x04, 0xf2f5}, |
706 | [6] = {0x06, 0x0017}, |
707 | [9] = {0x09, 0x424c}, |
708 | [10] = {0x0a, 0x9610}, |
709 | [11] = {0x0b, 0x9901}, |
710 | [12] = {0x0c, 0xf000}, |
711 | [13] = {0x0d, 0xef2a}, |
712 | [14] = {0x0e, 0x1000}, |
713 | [15] = {0x0f, 0x9050}, |
714 | [32] = {0x20, 0x7077}, |
715 | [35] = {0x23, 0x0b62}, |
716 | [37] = {0x25, 0x10ec}, |
717 | [42] = {0x2a, 0x3070}, }, |
718 | .check_efuse = true, |
719 | .do_toggle = false, |
720 | .do_toggle_once = true, |
721 | .use_default_parameter = false, |
722 | .check_rx_front_end_offset = true, |
723 | }; |
724 | |
725 | static const struct of_device_id usbphy_rtk_dt_match[] = { |
726 | { .compatible = "realtek,rtd1295-usb3phy" , .data = &rtd1295_phy_cfg }, |
727 | { .compatible = "realtek,rtd1319-usb3phy" , .data = &rtd1319_phy_cfg }, |
728 | { .compatible = "realtek,rtd1319d-usb3phy" , .data = &rtd1319d_phy_cfg }, |
729 | { .compatible = "realtek,rtd1619-usb3phy" , .data = &rtd1619_phy_cfg }, |
730 | { .compatible = "realtek,rtd1619b-usb3phy" , .data = &rtd1619b_phy_cfg }, |
731 | {}, |
732 | }; |
733 | MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match); |
734 | |
735 | static struct platform_driver rtk_usb3phy_driver = { |
736 | .probe = rtk_usb3phy_probe, |
737 | .remove_new = rtk_usb3phy_remove, |
738 | .driver = { |
739 | .name = "rtk-usb3phy" , |
740 | .of_match_table = usbphy_rtk_dt_match, |
741 | }, |
742 | }; |
743 | |
744 | module_platform_driver(rtk_usb3phy_driver); |
745 | |
746 | MODULE_LICENSE("GPL" ); |
747 | MODULE_AUTHOR("Stanley Chang <stanley_chang@realtek.com>" ); |
748 | MODULE_DESCRIPTION("Realtek usb 3.0 phy driver" ); |
749 | |