xref: /linux/drivers/phy/realtek/phy-rtk-usb2.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
1*eeda4945SStanley Chang // SPDX-License-Identifier: GPL-2.0
2*eeda4945SStanley Chang /*
3*eeda4945SStanley Chang  *  phy-rtk-usb2.c RTK usb2.0 PHY driver
4*eeda4945SStanley Chang  *
5*eeda4945SStanley Chang  * Copyright (C) 2023 Realtek Semiconductor Corporation
6*eeda4945SStanley Chang  *
7*eeda4945SStanley Chang  */
8*eeda4945SStanley Chang 
9*eeda4945SStanley Chang #include <linux/module.h>
10*eeda4945SStanley Chang #include <linux/of.h>
11*eeda4945SStanley Chang #include <linux/of_address.h>
12*eeda4945SStanley Chang #include <linux/platform_device.h>
13*eeda4945SStanley Chang #include <linux/uaccess.h>
14*eeda4945SStanley Chang #include <linux/debugfs.h>
15*eeda4945SStanley Chang #include <linux/nvmem-consumer.h>
16*eeda4945SStanley Chang #include <linux/regmap.h>
17*eeda4945SStanley Chang #include <linux/sys_soc.h>
18*eeda4945SStanley Chang #include <linux/mfd/syscon.h>
19*eeda4945SStanley Chang #include <linux/phy/phy.h>
20*eeda4945SStanley Chang #include <linux/usb.h>
21*eeda4945SStanley Chang 
22*eeda4945SStanley Chang /* GUSB2PHYACCn register */
23*eeda4945SStanley Chang #define PHY_NEW_REG_REQ BIT(25)
24*eeda4945SStanley Chang #define PHY_VSTS_BUSY   BIT(23)
25*eeda4945SStanley Chang #define PHY_VCTRL_SHIFT 8
26*eeda4945SStanley Chang #define PHY_REG_DATA_MASK 0xff
27*eeda4945SStanley Chang 
28*eeda4945SStanley Chang #define GET_LOW_NIBBLE(addr) ((addr) & 0x0f)
29*eeda4945SStanley Chang #define GET_HIGH_NIBBLE(addr) (((addr) & 0xf0) >> 4)
30*eeda4945SStanley Chang 
31*eeda4945SStanley Chang #define EFUS_USB_DC_CAL_RATE 2
32*eeda4945SStanley Chang #define EFUS_USB_DC_CAL_MAX 7
33*eeda4945SStanley Chang 
34*eeda4945SStanley Chang #define EFUS_USB_DC_DIS_RATE 1
35*eeda4945SStanley Chang #define EFUS_USB_DC_DIS_MAX 7
36*eeda4945SStanley Chang 
37*eeda4945SStanley Chang #define MAX_PHY_DATA_SIZE 20
38*eeda4945SStanley Chang #define OFFEST_PHY_READ 0x20
39*eeda4945SStanley Chang 
40*eeda4945SStanley Chang #define MAX_USB_PHY_NUM 4
41*eeda4945SStanley Chang #define MAX_USB_PHY_PAGE0_DATA_SIZE 16
42*eeda4945SStanley Chang #define MAX_USB_PHY_PAGE1_DATA_SIZE 16
43*eeda4945SStanley Chang #define MAX_USB_PHY_PAGE2_DATA_SIZE 8
44*eeda4945SStanley Chang 
45*eeda4945SStanley Chang #define SET_PAGE_OFFSET 0xf4
46*eeda4945SStanley Chang #define SET_PAGE_0 0x9b
47*eeda4945SStanley Chang #define SET_PAGE_1 0xbb
48*eeda4945SStanley Chang #define SET_PAGE_2 0xdb
49*eeda4945SStanley Chang 
50*eeda4945SStanley Chang #define PAGE_START 0xe0
51*eeda4945SStanley Chang #define PAGE0_0XE4 0xe4
52*eeda4945SStanley Chang #define PAGE0_0XE6 0xe6
53*eeda4945SStanley Chang #define PAGE0_0XE7 0xe7
54*eeda4945SStanley Chang #define PAGE1_0XE0 0xe0
55*eeda4945SStanley Chang #define PAGE1_0XE2 0xe2
56*eeda4945SStanley Chang 
57*eeda4945SStanley Chang #define SENSITIVITY_CTRL (BIT(4) | BIT(5) | BIT(6))
58*eeda4945SStanley Chang #define ENABLE_AUTO_SENSITIVITY_CALIBRATION BIT(2)
59*eeda4945SStanley Chang #define DEFAULT_DC_DRIVING_VALUE (0x8)
60*eeda4945SStanley Chang #define DEFAULT_DC_DISCONNECTION_VALUE (0x6)
61*eeda4945SStanley Chang #define HS_CLK_SELECT BIT(6)
62*eeda4945SStanley Chang 
63*eeda4945SStanley Chang struct phy_reg {
64*eeda4945SStanley Chang 	void __iomem *reg_wrap_vstatus;
65*eeda4945SStanley Chang 	void __iomem *reg_gusb2phyacc0;
66*eeda4945SStanley Chang 	int vstatus_index;
67*eeda4945SStanley Chang };
68*eeda4945SStanley Chang 
69*eeda4945SStanley Chang struct phy_data {
70*eeda4945SStanley Chang 	u8 addr;
71*eeda4945SStanley Chang 	u8 data;
72*eeda4945SStanley Chang };
73*eeda4945SStanley Chang 
74*eeda4945SStanley Chang struct phy_cfg {
75*eeda4945SStanley Chang 	int page0_size;
76*eeda4945SStanley Chang 	struct phy_data page0[MAX_USB_PHY_PAGE0_DATA_SIZE];
77*eeda4945SStanley Chang 	int page1_size;
78*eeda4945SStanley Chang 	struct phy_data page1[MAX_USB_PHY_PAGE1_DATA_SIZE];
79*eeda4945SStanley Chang 	int page2_size;
80*eeda4945SStanley Chang 	struct phy_data page2[MAX_USB_PHY_PAGE2_DATA_SIZE];
81*eeda4945SStanley Chang 
82*eeda4945SStanley Chang 	int num_phy;
83*eeda4945SStanley Chang 
84*eeda4945SStanley Chang 	bool check_efuse;
85*eeda4945SStanley Chang 	int check_efuse_version;
86*eeda4945SStanley Chang #define CHECK_EFUSE_V1 1
87*eeda4945SStanley Chang #define CHECK_EFUSE_V2 2
88*eeda4945SStanley Chang 	int efuse_dc_driving_rate;
89*eeda4945SStanley Chang 	int efuse_dc_disconnect_rate;
90*eeda4945SStanley Chang 	int dc_driving_mask;
91*eeda4945SStanley Chang 	int dc_disconnect_mask;
92*eeda4945SStanley Chang 	bool usb_dc_disconnect_at_page0;
93*eeda4945SStanley Chang 	int driving_updated_for_dev_dis;
94*eeda4945SStanley Chang 
95*eeda4945SStanley Chang 	bool do_toggle;
96*eeda4945SStanley Chang 	bool do_toggle_driving;
97*eeda4945SStanley Chang 	bool use_default_parameter;
98*eeda4945SStanley Chang 	bool is_double_sensitivity_mode;
99*eeda4945SStanley Chang };
100*eeda4945SStanley Chang 
101*eeda4945SStanley Chang struct phy_parameter {
102*eeda4945SStanley Chang 	struct phy_reg phy_reg;
103*eeda4945SStanley Chang 
104*eeda4945SStanley Chang 	/* Get from efuse */
105*eeda4945SStanley Chang 	s8 efuse_usb_dc_cal;
106*eeda4945SStanley Chang 	s8 efuse_usb_dc_dis;
107*eeda4945SStanley Chang 
108*eeda4945SStanley Chang 	/* Get from dts */
109*eeda4945SStanley Chang 	bool inverse_hstx_sync_clock;
110*eeda4945SStanley Chang 	u32 driving_level;
111*eeda4945SStanley Chang 	s32 driving_level_compensate;
112*eeda4945SStanley Chang 	s32 disconnection_compensate;
113*eeda4945SStanley Chang };
114*eeda4945SStanley Chang 
115*eeda4945SStanley Chang struct rtk_phy {
116*eeda4945SStanley Chang 	struct device *dev;
117*eeda4945SStanley Chang 
118*eeda4945SStanley Chang 	struct phy_cfg *phy_cfg;
119*eeda4945SStanley Chang 	int num_phy;
120*eeda4945SStanley Chang 	struct phy_parameter *phy_parameter;
121*eeda4945SStanley Chang 
122*eeda4945SStanley Chang 	struct dentry *debug_dir;
123*eeda4945SStanley Chang };
124*eeda4945SStanley Chang 
125*eeda4945SStanley Chang /* mapping 0xE0 to 0 ... 0xE7 to 7, 0xF0 to 8 ,,, 0xF7 to 15 */
page_addr_to_array_index(u8 addr)126*eeda4945SStanley Chang static inline int page_addr_to_array_index(u8 addr)
127*eeda4945SStanley Chang {
128*eeda4945SStanley Chang 	return (int)((((addr) - PAGE_START) & 0x7) +
129*eeda4945SStanley Chang 		((((addr) - PAGE_START) & 0x10) >> 1));
130*eeda4945SStanley Chang }
131*eeda4945SStanley Chang 
array_index_to_page_addr(int index)132*eeda4945SStanley Chang static inline u8 array_index_to_page_addr(int index)
133*eeda4945SStanley Chang {
134*eeda4945SStanley Chang 	return ((((index) + PAGE_START) & 0x7) +
135*eeda4945SStanley Chang 		((((index) & 0x8) << 1) + PAGE_START));
136*eeda4945SStanley Chang }
137*eeda4945SStanley Chang 
138*eeda4945SStanley Chang #define PHY_IO_TIMEOUT_USEC		(50000)
139*eeda4945SStanley Chang #define PHY_IO_DELAY_US			(100)
140*eeda4945SStanley Chang 
utmi_wait_register(void __iomem * reg,u32 mask,u32 result)141*eeda4945SStanley Chang static inline int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
142*eeda4945SStanley Chang {
143*eeda4945SStanley Chang 	int ret;
144*eeda4945SStanley Chang 	unsigned int val;
145*eeda4945SStanley Chang 
146*eeda4945SStanley Chang 	ret = read_poll_timeout(readl, val, ((val & mask) == result),
147*eeda4945SStanley Chang 				PHY_IO_DELAY_US, PHY_IO_TIMEOUT_USEC, false, reg);
148*eeda4945SStanley Chang 	if (ret) {
149*eeda4945SStanley Chang 		pr_err("%s can't program USB phy\n", __func__);
150*eeda4945SStanley Chang 		return -ETIMEDOUT;
151*eeda4945SStanley Chang 	}
152*eeda4945SStanley Chang 
153*eeda4945SStanley Chang 	return 0;
154*eeda4945SStanley Chang }
155*eeda4945SStanley Chang 
rtk_phy_read(struct phy_reg * phy_reg,char addr)156*eeda4945SStanley Chang static char rtk_phy_read(struct phy_reg *phy_reg, char addr)
157*eeda4945SStanley Chang {
158*eeda4945SStanley Chang 	void __iomem *reg_gusb2phyacc0 = phy_reg->reg_gusb2phyacc0;
159*eeda4945SStanley Chang 	unsigned int val;
160*eeda4945SStanley Chang 	int ret = 0;
161*eeda4945SStanley Chang 
162*eeda4945SStanley Chang 	addr -= OFFEST_PHY_READ;
163*eeda4945SStanley Chang 
164*eeda4945SStanley Chang 	/* polling until VBusy == 0 */
165*eeda4945SStanley Chang 	ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
166*eeda4945SStanley Chang 	if (ret)
167*eeda4945SStanley Chang 		return (char)ret;
168*eeda4945SStanley Chang 
169*eeda4945SStanley Chang 	/* VCtrl = low nibble of addr, and set PHY_NEW_REG_REQ */
170*eeda4945SStanley Chang 	val = PHY_NEW_REG_REQ | (GET_LOW_NIBBLE(addr) << PHY_VCTRL_SHIFT);
171*eeda4945SStanley Chang 	writel(val, reg_gusb2phyacc0);
172*eeda4945SStanley Chang 	ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
173*eeda4945SStanley Chang 	if (ret)
174*eeda4945SStanley Chang 		return (char)ret;
175*eeda4945SStanley Chang 
176*eeda4945SStanley Chang 	/* VCtrl = high nibble of addr, and set PHY_NEW_REG_REQ */
177*eeda4945SStanley Chang 	val = PHY_NEW_REG_REQ | (GET_HIGH_NIBBLE(addr) << PHY_VCTRL_SHIFT);
178*eeda4945SStanley Chang 	writel(val, reg_gusb2phyacc0);
179*eeda4945SStanley Chang 	ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
180*eeda4945SStanley Chang 	if (ret)
181*eeda4945SStanley Chang 		return (char)ret;
182*eeda4945SStanley Chang 
183*eeda4945SStanley Chang 	val = readl(reg_gusb2phyacc0);
184*eeda4945SStanley Chang 
185*eeda4945SStanley Chang 	return (char)(val & PHY_REG_DATA_MASK);
186*eeda4945SStanley Chang }
187*eeda4945SStanley Chang 
rtk_phy_write(struct phy_reg * phy_reg,char addr,char data)188*eeda4945SStanley Chang static int rtk_phy_write(struct phy_reg *phy_reg, char addr, char data)
189*eeda4945SStanley Chang {
190*eeda4945SStanley Chang 	unsigned int val;
191*eeda4945SStanley Chang 	void __iomem *reg_wrap_vstatus = phy_reg->reg_wrap_vstatus;
192*eeda4945SStanley Chang 	void __iomem *reg_gusb2phyacc0 = phy_reg->reg_gusb2phyacc0;
193*eeda4945SStanley Chang 	int shift_bits = phy_reg->vstatus_index * 8;
194*eeda4945SStanley Chang 	int ret = 0;
195*eeda4945SStanley Chang 
196*eeda4945SStanley Chang 	/* write data to VStatusOut2 (data output to phy) */
197*eeda4945SStanley Chang 	writel((u32)data << shift_bits, reg_wrap_vstatus);
198*eeda4945SStanley Chang 
199*eeda4945SStanley Chang 	ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
200*eeda4945SStanley Chang 	if (ret)
201*eeda4945SStanley Chang 		return ret;
202*eeda4945SStanley Chang 
203*eeda4945SStanley Chang 	/* VCtrl = low nibble of addr, set PHY_NEW_REG_REQ */
204*eeda4945SStanley Chang 	val = PHY_NEW_REG_REQ | (GET_LOW_NIBBLE(addr) << PHY_VCTRL_SHIFT);
205*eeda4945SStanley Chang 
206*eeda4945SStanley Chang 	writel(val, reg_gusb2phyacc0);
207*eeda4945SStanley Chang 	ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
208*eeda4945SStanley Chang 	if (ret)
209*eeda4945SStanley Chang 		return ret;
210*eeda4945SStanley Chang 
211*eeda4945SStanley Chang 	/* VCtrl = high nibble of addr, set PHY_NEW_REG_REQ */
212*eeda4945SStanley Chang 	val = PHY_NEW_REG_REQ | (GET_HIGH_NIBBLE(addr) << PHY_VCTRL_SHIFT);
213*eeda4945SStanley Chang 
214*eeda4945SStanley Chang 	writel(val, reg_gusb2phyacc0);
215*eeda4945SStanley Chang 	ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
216*eeda4945SStanley Chang 	if (ret)
217*eeda4945SStanley Chang 		return ret;
218*eeda4945SStanley Chang 
219*eeda4945SStanley Chang 	return 0;
220*eeda4945SStanley Chang }
221*eeda4945SStanley Chang 
rtk_phy_set_page(struct phy_reg * phy_reg,int page)222*eeda4945SStanley Chang static int rtk_phy_set_page(struct phy_reg *phy_reg, int page)
223*eeda4945SStanley Chang {
224*eeda4945SStanley Chang 	switch (page) {
225*eeda4945SStanley Chang 	case 0:
226*eeda4945SStanley Chang 		return rtk_phy_write(phy_reg, SET_PAGE_OFFSET, SET_PAGE_0);
227*eeda4945SStanley Chang 	case 1:
228*eeda4945SStanley Chang 		return rtk_phy_write(phy_reg, SET_PAGE_OFFSET, SET_PAGE_1);
229*eeda4945SStanley Chang 	case 2:
230*eeda4945SStanley Chang 		return rtk_phy_write(phy_reg, SET_PAGE_OFFSET, SET_PAGE_2);
231*eeda4945SStanley Chang 	default:
232*eeda4945SStanley Chang 		pr_err("%s error page=%d\n", __func__, page);
233*eeda4945SStanley Chang 	}
234*eeda4945SStanley Chang 
235*eeda4945SStanley Chang 	return -EINVAL;
236*eeda4945SStanley Chang }
237*eeda4945SStanley Chang 
__updated_dc_disconnect_level_page0_0xe4(struct phy_cfg * phy_cfg,struct phy_parameter * phy_parameter,u8 data)238*eeda4945SStanley Chang static u8 __updated_dc_disconnect_level_page0_0xe4(struct phy_cfg *phy_cfg,
239*eeda4945SStanley Chang 						   struct phy_parameter *phy_parameter, u8 data)
240*eeda4945SStanley Chang {
241*eeda4945SStanley Chang 	u8 ret;
242*eeda4945SStanley Chang 	s32 val;
243*eeda4945SStanley Chang 	s32 dc_disconnect_mask = phy_cfg->dc_disconnect_mask;
244*eeda4945SStanley Chang 	int offset = 4;
245*eeda4945SStanley Chang 
246*eeda4945SStanley Chang 	val = (s32)((data >> offset) & dc_disconnect_mask)
247*eeda4945SStanley Chang 		     + phy_parameter->efuse_usb_dc_dis
248*eeda4945SStanley Chang 		     + phy_parameter->disconnection_compensate;
249*eeda4945SStanley Chang 
250*eeda4945SStanley Chang 	if (val > dc_disconnect_mask)
251*eeda4945SStanley Chang 		val = dc_disconnect_mask;
252*eeda4945SStanley Chang 	else if (val < 0)
253*eeda4945SStanley Chang 		val = 0;
254*eeda4945SStanley Chang 
255*eeda4945SStanley Chang 	ret = (data & (~(dc_disconnect_mask << offset))) |
256*eeda4945SStanley Chang 		    (val & dc_disconnect_mask) << offset;
257*eeda4945SStanley Chang 
258*eeda4945SStanley Chang 	return ret;
259*eeda4945SStanley Chang }
260*eeda4945SStanley Chang 
261*eeda4945SStanley Chang /* updated disconnect level at page0 */
update_dc_disconnect_level_at_page0(struct rtk_phy * rtk_phy,struct phy_parameter * phy_parameter,bool update)262*eeda4945SStanley Chang static void update_dc_disconnect_level_at_page0(struct rtk_phy *rtk_phy,
263*eeda4945SStanley Chang 						struct phy_parameter *phy_parameter, bool update)
264*eeda4945SStanley Chang {
265*eeda4945SStanley Chang 	struct phy_cfg *phy_cfg;
266*eeda4945SStanley Chang 	struct phy_reg *phy_reg;
267*eeda4945SStanley Chang 	struct phy_data *phy_data_page;
268*eeda4945SStanley Chang 	struct phy_data *phy_data;
269*eeda4945SStanley Chang 	u8 addr, data;
270*eeda4945SStanley Chang 	int offset = 4;
271*eeda4945SStanley Chang 	s32 dc_disconnect_mask;
272*eeda4945SStanley Chang 	int i;
273*eeda4945SStanley Chang 
274*eeda4945SStanley Chang 	phy_cfg = rtk_phy->phy_cfg;
275*eeda4945SStanley Chang 	phy_reg = &phy_parameter->phy_reg;
276*eeda4945SStanley Chang 
277*eeda4945SStanley Chang 	/* Set page 0 */
278*eeda4945SStanley Chang 	phy_data_page = phy_cfg->page0;
279*eeda4945SStanley Chang 	rtk_phy_set_page(phy_reg, 0);
280*eeda4945SStanley Chang 
281*eeda4945SStanley Chang 	i = page_addr_to_array_index(PAGE0_0XE4);
282*eeda4945SStanley Chang 	phy_data = phy_data_page + i;
283*eeda4945SStanley Chang 	if (!phy_data->addr) {
284*eeda4945SStanley Chang 		phy_data->addr = PAGE0_0XE4;
285*eeda4945SStanley Chang 		phy_data->data = rtk_phy_read(phy_reg, PAGE0_0XE4);
286*eeda4945SStanley Chang 	}
287*eeda4945SStanley Chang 
288*eeda4945SStanley Chang 	addr = phy_data->addr;
289*eeda4945SStanley Chang 	data = phy_data->data;
290*eeda4945SStanley Chang 	dc_disconnect_mask = phy_cfg->dc_disconnect_mask;
291*eeda4945SStanley Chang 
292*eeda4945SStanley Chang 	if (update)
293*eeda4945SStanley Chang 		data = __updated_dc_disconnect_level_page0_0xe4(phy_cfg, phy_parameter, data);
294*eeda4945SStanley Chang 	else
295*eeda4945SStanley Chang 		data = (data & ~(dc_disconnect_mask << offset)) |
296*eeda4945SStanley Chang 			(DEFAULT_DC_DISCONNECTION_VALUE << offset);
297*eeda4945SStanley Chang 
298*eeda4945SStanley Chang 	if (rtk_phy_write(phy_reg, addr, data))
299*eeda4945SStanley Chang 		dev_err(rtk_phy->dev,
300*eeda4945SStanley Chang 			"%s: Error to set page1 parameter addr=0x%x value=0x%x\n",
301*eeda4945SStanley Chang 			__func__, addr, data);
302*eeda4945SStanley Chang }
303*eeda4945SStanley Chang 
__updated_dc_disconnect_level_page1_0xe2(struct phy_cfg * phy_cfg,struct phy_parameter * phy_parameter,u8 data)304*eeda4945SStanley Chang static u8 __updated_dc_disconnect_level_page1_0xe2(struct phy_cfg *phy_cfg,
305*eeda4945SStanley Chang 						   struct phy_parameter *phy_parameter, u8 data)
306*eeda4945SStanley Chang {
307*eeda4945SStanley Chang 	u8 ret;
308*eeda4945SStanley Chang 	s32 val;
309*eeda4945SStanley Chang 	s32 dc_disconnect_mask = phy_cfg->dc_disconnect_mask;
310*eeda4945SStanley Chang 
311*eeda4945SStanley Chang 	if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) {
312*eeda4945SStanley Chang 		val = (s32)(data & dc_disconnect_mask)
313*eeda4945SStanley Chang 			    + phy_parameter->efuse_usb_dc_dis
314*eeda4945SStanley Chang 			    + phy_parameter->disconnection_compensate;
315*eeda4945SStanley Chang 	} else { /* for CHECK_EFUSE_V2 or no efuse */
316*eeda4945SStanley Chang 		if (phy_parameter->efuse_usb_dc_dis)
317*eeda4945SStanley Chang 			val = (s32)(phy_parameter->efuse_usb_dc_dis +
318*eeda4945SStanley Chang 				    phy_parameter->disconnection_compensate);
319*eeda4945SStanley Chang 		else
320*eeda4945SStanley Chang 			val = (s32)((data & dc_disconnect_mask) +
321*eeda4945SStanley Chang 				    phy_parameter->disconnection_compensate);
322*eeda4945SStanley Chang 	}
323*eeda4945SStanley Chang 
324*eeda4945SStanley Chang 	if (val > dc_disconnect_mask)
325*eeda4945SStanley Chang 		val = dc_disconnect_mask;
326*eeda4945SStanley Chang 	else if (val < 0)
327*eeda4945SStanley Chang 		val = 0;
328*eeda4945SStanley Chang 
329*eeda4945SStanley Chang 	ret = (data & (~dc_disconnect_mask)) | (val & dc_disconnect_mask);
330*eeda4945SStanley Chang 
331*eeda4945SStanley Chang 	return ret;
332*eeda4945SStanley Chang }
333*eeda4945SStanley Chang 
334*eeda4945SStanley Chang /* updated disconnect level at page1 */
update_dc_disconnect_level_at_page1(struct rtk_phy * rtk_phy,struct phy_parameter * phy_parameter,bool update)335*eeda4945SStanley Chang static void update_dc_disconnect_level_at_page1(struct rtk_phy *rtk_phy,
336*eeda4945SStanley Chang 						struct phy_parameter *phy_parameter, bool update)
337*eeda4945SStanley Chang {
338*eeda4945SStanley Chang 	struct phy_cfg *phy_cfg;
339*eeda4945SStanley Chang 	struct phy_data *phy_data_page;
340*eeda4945SStanley Chang 	struct phy_data *phy_data;
341*eeda4945SStanley Chang 	struct phy_reg *phy_reg;
342*eeda4945SStanley Chang 	u8 addr, data;
343*eeda4945SStanley Chang 	s32 dc_disconnect_mask;
344*eeda4945SStanley Chang 	int i;
345*eeda4945SStanley Chang 
346*eeda4945SStanley Chang 	phy_cfg = rtk_phy->phy_cfg;
347*eeda4945SStanley Chang 	phy_reg = &phy_parameter->phy_reg;
348*eeda4945SStanley Chang 
349*eeda4945SStanley Chang 	/* Set page 1 */
350*eeda4945SStanley Chang 	phy_data_page = phy_cfg->page1;
351*eeda4945SStanley Chang 	rtk_phy_set_page(phy_reg, 1);
352*eeda4945SStanley Chang 
353*eeda4945SStanley Chang 	i = page_addr_to_array_index(PAGE1_0XE2);
354*eeda4945SStanley Chang 	phy_data = phy_data_page + i;
355*eeda4945SStanley Chang 	if (!phy_data->addr) {
356*eeda4945SStanley Chang 		phy_data->addr = PAGE1_0XE2;
357*eeda4945SStanley Chang 		phy_data->data = rtk_phy_read(phy_reg, PAGE1_0XE2);
358*eeda4945SStanley Chang 	}
359*eeda4945SStanley Chang 
360*eeda4945SStanley Chang 	addr = phy_data->addr;
361*eeda4945SStanley Chang 	data = phy_data->data;
362*eeda4945SStanley Chang 	dc_disconnect_mask = phy_cfg->dc_disconnect_mask;
363*eeda4945SStanley Chang 
364*eeda4945SStanley Chang 	if (update)
365*eeda4945SStanley Chang 		data = __updated_dc_disconnect_level_page1_0xe2(phy_cfg, phy_parameter, data);
366*eeda4945SStanley Chang 	else
367*eeda4945SStanley Chang 		data = (data & ~dc_disconnect_mask) | DEFAULT_DC_DISCONNECTION_VALUE;
368*eeda4945SStanley Chang 
369*eeda4945SStanley Chang 	if (rtk_phy_write(phy_reg, addr, data))
370*eeda4945SStanley Chang 		dev_err(rtk_phy->dev,
371*eeda4945SStanley Chang 			"%s: Error to set page1 parameter addr=0x%x value=0x%x\n",
372*eeda4945SStanley Chang 			__func__, addr, data);
373*eeda4945SStanley Chang }
374*eeda4945SStanley Chang 
update_dc_disconnect_level(struct rtk_phy * rtk_phy,struct phy_parameter * phy_parameter,bool update)375*eeda4945SStanley Chang static void update_dc_disconnect_level(struct rtk_phy *rtk_phy,
376*eeda4945SStanley Chang 				       struct phy_parameter *phy_parameter, bool update)
377*eeda4945SStanley Chang {
378*eeda4945SStanley Chang 	struct phy_cfg *phy_cfg = rtk_phy->phy_cfg;
379*eeda4945SStanley Chang 
380*eeda4945SStanley Chang 	if (phy_cfg->usb_dc_disconnect_at_page0)
381*eeda4945SStanley Chang 		update_dc_disconnect_level_at_page0(rtk_phy, phy_parameter, update);
382*eeda4945SStanley Chang 	else
383*eeda4945SStanley Chang 		update_dc_disconnect_level_at_page1(rtk_phy, phy_parameter, update);
384*eeda4945SStanley Chang }
385*eeda4945SStanley Chang 
__update_dc_driving_page0_0xe4(struct phy_cfg * phy_cfg,struct phy_parameter * phy_parameter,u8 data)386*eeda4945SStanley Chang static u8 __update_dc_driving_page0_0xe4(struct phy_cfg *phy_cfg,
387*eeda4945SStanley Chang 					 struct phy_parameter *phy_parameter, u8 data)
388*eeda4945SStanley Chang {
389*eeda4945SStanley Chang 	s32 driving_level_compensate = phy_parameter->driving_level_compensate;
390*eeda4945SStanley Chang 	s32 dc_driving_mask = phy_cfg->dc_driving_mask;
391*eeda4945SStanley Chang 	s32 val;
392*eeda4945SStanley Chang 	u8 ret;
393*eeda4945SStanley Chang 
394*eeda4945SStanley Chang 	if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) {
395*eeda4945SStanley Chang 		val = (s32)(data & dc_driving_mask) + driving_level_compensate
396*eeda4945SStanley Chang 			    + phy_parameter->efuse_usb_dc_cal;
397*eeda4945SStanley Chang 	} else { /* for CHECK_EFUSE_V2 or no efuse */
398*eeda4945SStanley Chang 		if (phy_parameter->efuse_usb_dc_cal)
399*eeda4945SStanley Chang 			val = (s32)((phy_parameter->efuse_usb_dc_cal & dc_driving_mask)
400*eeda4945SStanley Chang 				    + driving_level_compensate);
401*eeda4945SStanley Chang 		else
402*eeda4945SStanley Chang 			val = (s32)(data & dc_driving_mask);
403*eeda4945SStanley Chang 	}
404*eeda4945SStanley Chang 
405*eeda4945SStanley Chang 	if (val > dc_driving_mask)
406*eeda4945SStanley Chang 		val = dc_driving_mask;
407*eeda4945SStanley Chang 	else if (val < 0)
408*eeda4945SStanley Chang 		val = 0;
409*eeda4945SStanley Chang 
410*eeda4945SStanley Chang 	ret = (data & (~dc_driving_mask)) | (val & dc_driving_mask);
411*eeda4945SStanley Chang 
412*eeda4945SStanley Chang 	return ret;
413*eeda4945SStanley Chang }
414*eeda4945SStanley Chang 
update_dc_driving_level(struct rtk_phy * rtk_phy,struct phy_parameter * phy_parameter)415*eeda4945SStanley Chang static void update_dc_driving_level(struct rtk_phy *rtk_phy,
416*eeda4945SStanley Chang 				    struct phy_parameter *phy_parameter)
417*eeda4945SStanley Chang {
418*eeda4945SStanley Chang 	struct phy_cfg *phy_cfg;
419*eeda4945SStanley Chang 	struct phy_reg *phy_reg;
420*eeda4945SStanley Chang 
421*eeda4945SStanley Chang 	phy_reg = &phy_parameter->phy_reg;
422*eeda4945SStanley Chang 	phy_cfg = rtk_phy->phy_cfg;
423*eeda4945SStanley Chang 	if (!phy_cfg->page0[4].addr) {
424*eeda4945SStanley Chang 		rtk_phy_set_page(phy_reg, 0);
425*eeda4945SStanley Chang 		phy_cfg->page0[4].addr = PAGE0_0XE4;
426*eeda4945SStanley Chang 		phy_cfg->page0[4].data = rtk_phy_read(phy_reg, PAGE0_0XE4);
427*eeda4945SStanley Chang 	}
428*eeda4945SStanley Chang 
429*eeda4945SStanley Chang 	if (phy_parameter->driving_level != DEFAULT_DC_DRIVING_VALUE) {
430*eeda4945SStanley Chang 		u32 dc_driving_mask;
431*eeda4945SStanley Chang 		u8 driving_level;
432*eeda4945SStanley Chang 		u8 data;
433*eeda4945SStanley Chang 
434*eeda4945SStanley Chang 		data = phy_cfg->page0[4].data;
435*eeda4945SStanley Chang 		dc_driving_mask = phy_cfg->dc_driving_mask;
436*eeda4945SStanley Chang 		driving_level = data & dc_driving_mask;
437*eeda4945SStanley Chang 
438*eeda4945SStanley Chang 		dev_dbg(rtk_phy->dev, "%s driving_level=%d => dts driving_level=%d\n",
439*eeda4945SStanley Chang 			__func__, driving_level, phy_parameter->driving_level);
440*eeda4945SStanley Chang 
441*eeda4945SStanley Chang 		phy_cfg->page0[4].data = (data & (~dc_driving_mask)) |
442*eeda4945SStanley Chang 			    (phy_parameter->driving_level & dc_driving_mask);
443*eeda4945SStanley Chang 	}
444*eeda4945SStanley Chang 
445*eeda4945SStanley Chang 	phy_cfg->page0[4].data = __update_dc_driving_page0_0xe4(phy_cfg,
446*eeda4945SStanley Chang 								phy_parameter,
447*eeda4945SStanley Chang 								phy_cfg->page0[4].data);
448*eeda4945SStanley Chang }
449*eeda4945SStanley Chang 
update_hs_clk_select(struct rtk_phy * rtk_phy,struct phy_parameter * phy_parameter)450*eeda4945SStanley Chang static void update_hs_clk_select(struct rtk_phy *rtk_phy,
451*eeda4945SStanley Chang 				 struct phy_parameter *phy_parameter)
452*eeda4945SStanley Chang {
453*eeda4945SStanley Chang 	struct phy_cfg *phy_cfg;
454*eeda4945SStanley Chang 	struct phy_reg *phy_reg;
455*eeda4945SStanley Chang 
456*eeda4945SStanley Chang 	phy_cfg = rtk_phy->phy_cfg;
457*eeda4945SStanley Chang 	phy_reg = &phy_parameter->phy_reg;
458*eeda4945SStanley Chang 
459*eeda4945SStanley Chang 	if (phy_parameter->inverse_hstx_sync_clock) {
460*eeda4945SStanley Chang 		if (!phy_cfg->page0[6].addr) {
461*eeda4945SStanley Chang 			rtk_phy_set_page(phy_reg, 0);
462*eeda4945SStanley Chang 			phy_cfg->page0[6].addr = PAGE0_0XE6;
463*eeda4945SStanley Chang 			phy_cfg->page0[6].data = rtk_phy_read(phy_reg, PAGE0_0XE6);
464*eeda4945SStanley Chang 		}
465*eeda4945SStanley Chang 
466*eeda4945SStanley Chang 		phy_cfg->page0[6].data = phy_cfg->page0[6].data | HS_CLK_SELECT;
467*eeda4945SStanley Chang 	}
468*eeda4945SStanley Chang }
469*eeda4945SStanley Chang 
do_rtk_phy_toggle(struct rtk_phy * rtk_phy,int index,bool connect)470*eeda4945SStanley Chang static void do_rtk_phy_toggle(struct rtk_phy *rtk_phy,
471*eeda4945SStanley Chang 			      int index, bool connect)
472*eeda4945SStanley Chang {
473*eeda4945SStanley Chang 	struct phy_parameter *phy_parameter;
474*eeda4945SStanley Chang 	struct phy_cfg *phy_cfg;
475*eeda4945SStanley Chang 	struct phy_reg *phy_reg;
476*eeda4945SStanley Chang 	struct phy_data *phy_data_page;
477*eeda4945SStanley Chang 	u8 addr, data;
478*eeda4945SStanley Chang 	int i;
479*eeda4945SStanley Chang 
480*eeda4945SStanley Chang 	phy_cfg = rtk_phy->phy_cfg;
481*eeda4945SStanley Chang 	phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
482*eeda4945SStanley Chang 	phy_reg = &phy_parameter->phy_reg;
483*eeda4945SStanley Chang 
484*eeda4945SStanley Chang 	if (!phy_cfg->do_toggle)
485*eeda4945SStanley Chang 		goto out;
486*eeda4945SStanley Chang 
487*eeda4945SStanley Chang 	if (phy_cfg->is_double_sensitivity_mode)
488*eeda4945SStanley Chang 		goto do_toggle_driving;
489*eeda4945SStanley Chang 
490*eeda4945SStanley Chang 	/* Set page 0 */
491*eeda4945SStanley Chang 	rtk_phy_set_page(phy_reg, 0);
492*eeda4945SStanley Chang 
493*eeda4945SStanley Chang 	addr = PAGE0_0XE7;
494*eeda4945SStanley Chang 	data = rtk_phy_read(phy_reg, addr);
495*eeda4945SStanley Chang 
496*eeda4945SStanley Chang 	if (connect)
497*eeda4945SStanley Chang 		rtk_phy_write(phy_reg, addr, data & (~SENSITIVITY_CTRL));
498*eeda4945SStanley Chang 	else
499*eeda4945SStanley Chang 		rtk_phy_write(phy_reg, addr, data | (SENSITIVITY_CTRL));
500*eeda4945SStanley Chang 
501*eeda4945SStanley Chang do_toggle_driving:
502*eeda4945SStanley Chang 
503*eeda4945SStanley Chang 	if (!phy_cfg->do_toggle_driving)
504*eeda4945SStanley Chang 		goto do_toggle;
505*eeda4945SStanley Chang 
506*eeda4945SStanley Chang 	/* Page 0 addr 0xE4 driving capability */
507*eeda4945SStanley Chang 
508*eeda4945SStanley Chang 	/* Set page 0 */
509*eeda4945SStanley Chang 	phy_data_page = phy_cfg->page0;
510*eeda4945SStanley Chang 	rtk_phy_set_page(phy_reg, 0);
511*eeda4945SStanley Chang 
512*eeda4945SStanley Chang 	i = page_addr_to_array_index(PAGE0_0XE4);
513*eeda4945SStanley Chang 	addr = phy_data_page[i].addr;
514*eeda4945SStanley Chang 	data = phy_data_page[i].data;
515*eeda4945SStanley Chang 
516*eeda4945SStanley Chang 	if (connect) {
517*eeda4945SStanley Chang 		rtk_phy_write(phy_reg, addr, data);
518*eeda4945SStanley Chang 	} else {
519*eeda4945SStanley Chang 		u8 value;
520*eeda4945SStanley Chang 		s32 tmp;
521*eeda4945SStanley Chang 		s32 driving_updated =
522*eeda4945SStanley Chang 			    phy_cfg->driving_updated_for_dev_dis;
523*eeda4945SStanley Chang 		s32 dc_driving_mask = phy_cfg->dc_driving_mask;
524*eeda4945SStanley Chang 
525*eeda4945SStanley Chang 		tmp = (s32)(data & dc_driving_mask) + driving_updated;
526*eeda4945SStanley Chang 
527*eeda4945SStanley Chang 		if (tmp > dc_driving_mask)
528*eeda4945SStanley Chang 			tmp = dc_driving_mask;
529*eeda4945SStanley Chang 		else if (tmp < 0)
530*eeda4945SStanley Chang 			tmp = 0;
531*eeda4945SStanley Chang 
532*eeda4945SStanley Chang 		value = (data & (~dc_driving_mask)) | (tmp & dc_driving_mask);
533*eeda4945SStanley Chang 
534*eeda4945SStanley Chang 		rtk_phy_write(phy_reg, addr, value);
535*eeda4945SStanley Chang 	}
536*eeda4945SStanley Chang 
537*eeda4945SStanley Chang do_toggle:
538*eeda4945SStanley Chang 	/* restore dc disconnect level before toggle */
539*eeda4945SStanley Chang 	update_dc_disconnect_level(rtk_phy, phy_parameter, false);
540*eeda4945SStanley Chang 
541*eeda4945SStanley Chang 	/* Set page 1 */
542*eeda4945SStanley Chang 	rtk_phy_set_page(phy_reg, 1);
543*eeda4945SStanley Chang 
544*eeda4945SStanley Chang 	addr = PAGE1_0XE0;
545*eeda4945SStanley Chang 	data = rtk_phy_read(phy_reg, addr);
546*eeda4945SStanley Chang 
547*eeda4945SStanley Chang 	rtk_phy_write(phy_reg, addr, data &
548*eeda4945SStanley Chang 		      (~ENABLE_AUTO_SENSITIVITY_CALIBRATION));
549*eeda4945SStanley Chang 	mdelay(1);
550*eeda4945SStanley Chang 	rtk_phy_write(phy_reg, addr, data |
551*eeda4945SStanley Chang 		      (ENABLE_AUTO_SENSITIVITY_CALIBRATION));
552*eeda4945SStanley Chang 
553*eeda4945SStanley Chang 	/* update dc disconnect level after toggle */
554*eeda4945SStanley Chang 	update_dc_disconnect_level(rtk_phy, phy_parameter, true);
555*eeda4945SStanley Chang 
556*eeda4945SStanley Chang out:
557*eeda4945SStanley Chang 	return;
558*eeda4945SStanley Chang }
559*eeda4945SStanley Chang 
do_rtk_phy_init(struct rtk_phy * rtk_phy,int index)560*eeda4945SStanley Chang static int do_rtk_phy_init(struct rtk_phy *rtk_phy, int index)
561*eeda4945SStanley Chang {
562*eeda4945SStanley Chang 	struct phy_parameter *phy_parameter;
563*eeda4945SStanley Chang 	struct phy_cfg *phy_cfg;
564*eeda4945SStanley Chang 	struct phy_data *phy_data_page;
565*eeda4945SStanley Chang 	struct phy_reg *phy_reg;
566*eeda4945SStanley Chang 	int i;
567*eeda4945SStanley Chang 
568*eeda4945SStanley Chang 	phy_cfg = rtk_phy->phy_cfg;
569*eeda4945SStanley Chang 	phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
570*eeda4945SStanley Chang 	phy_reg = &phy_parameter->phy_reg;
571*eeda4945SStanley Chang 
572*eeda4945SStanley Chang 	if (phy_cfg->use_default_parameter) {
573*eeda4945SStanley Chang 		dev_dbg(rtk_phy->dev, "%s phy#%d use default parameter\n",
574*eeda4945SStanley Chang 			__func__, index);
575*eeda4945SStanley Chang 		goto do_toggle;
576*eeda4945SStanley Chang 	}
577*eeda4945SStanley Chang 
578*eeda4945SStanley Chang 	/* Set page 0 */
579*eeda4945SStanley Chang 	phy_data_page = phy_cfg->page0;
580*eeda4945SStanley Chang 	rtk_phy_set_page(phy_reg, 0);
581*eeda4945SStanley Chang 
582*eeda4945SStanley Chang 	for (i = 0; i < phy_cfg->page0_size; i++) {
583*eeda4945SStanley Chang 		struct phy_data *phy_data = phy_data_page + i;
584*eeda4945SStanley Chang 		u8 addr = phy_data->addr;
585*eeda4945SStanley Chang 		u8 data = phy_data->data;
586*eeda4945SStanley Chang 
587*eeda4945SStanley Chang 		if (!addr)
588*eeda4945SStanley Chang 			continue;
589*eeda4945SStanley Chang 
590*eeda4945SStanley Chang 		if (rtk_phy_write(phy_reg, addr, data)) {
591*eeda4945SStanley Chang 			dev_err(rtk_phy->dev,
592*eeda4945SStanley Chang 				"%s: Error to set page0 parameter addr=0x%x value=0x%x\n",
593*eeda4945SStanley Chang 				__func__, addr, data);
594*eeda4945SStanley Chang 			return -EINVAL;
595*eeda4945SStanley Chang 		}
596*eeda4945SStanley Chang 	}
597*eeda4945SStanley Chang 
598*eeda4945SStanley Chang 	/* Set page 1 */
599*eeda4945SStanley Chang 	phy_data_page = phy_cfg->page1;
600*eeda4945SStanley Chang 	rtk_phy_set_page(phy_reg, 1);
601*eeda4945SStanley Chang 
602*eeda4945SStanley Chang 	for (i = 0; i < phy_cfg->page1_size; i++) {
603*eeda4945SStanley Chang 		struct phy_data *phy_data = phy_data_page + i;
604*eeda4945SStanley Chang 		u8 addr = phy_data->addr;
605*eeda4945SStanley Chang 		u8 data = phy_data->data;
606*eeda4945SStanley Chang 
607*eeda4945SStanley Chang 		if (!addr)
608*eeda4945SStanley Chang 			continue;
609*eeda4945SStanley Chang 
610*eeda4945SStanley Chang 		if (rtk_phy_write(phy_reg, addr, data)) {
611*eeda4945SStanley Chang 			dev_err(rtk_phy->dev,
612*eeda4945SStanley Chang 				"%s: Error to set page1 parameter addr=0x%x value=0x%x\n",
613*eeda4945SStanley Chang 				__func__, addr, data);
614*eeda4945SStanley Chang 			return -EINVAL;
615*eeda4945SStanley Chang 		}
616*eeda4945SStanley Chang 	}
617*eeda4945SStanley Chang 
618*eeda4945SStanley Chang 	if (phy_cfg->page2_size == 0)
619*eeda4945SStanley Chang 		goto do_toggle;
620*eeda4945SStanley Chang 
621*eeda4945SStanley Chang 	/* Set page 2 */
622*eeda4945SStanley Chang 	phy_data_page = phy_cfg->page2;
623*eeda4945SStanley Chang 	rtk_phy_set_page(phy_reg, 2);
624*eeda4945SStanley Chang 
625*eeda4945SStanley Chang 	for (i = 0; i < phy_cfg->page2_size; i++) {
626*eeda4945SStanley Chang 		struct phy_data *phy_data = phy_data_page + i;
627*eeda4945SStanley Chang 		u8 addr = phy_data->addr;
628*eeda4945SStanley Chang 		u8 data = phy_data->data;
629*eeda4945SStanley Chang 
630*eeda4945SStanley Chang 		if (!addr)
631*eeda4945SStanley Chang 			continue;
632*eeda4945SStanley Chang 
633*eeda4945SStanley Chang 		if (rtk_phy_write(phy_reg, addr, data)) {
634*eeda4945SStanley Chang 			dev_err(rtk_phy->dev,
635*eeda4945SStanley Chang 				"%s: Error to set page2 parameter addr=0x%x value=0x%x\n",
636*eeda4945SStanley Chang 				__func__, addr, data);
637*eeda4945SStanley Chang 			return -EINVAL;
638*eeda4945SStanley Chang 		}
639*eeda4945SStanley Chang 	}
640*eeda4945SStanley Chang 
641*eeda4945SStanley Chang do_toggle:
642*eeda4945SStanley Chang 	do_rtk_phy_toggle(rtk_phy, index, false);
643*eeda4945SStanley Chang 
644*eeda4945SStanley Chang 	return 0;
645*eeda4945SStanley Chang }
646*eeda4945SStanley Chang 
rtk_phy_init(struct phy * phy)647*eeda4945SStanley Chang static int rtk_phy_init(struct phy *phy)
648*eeda4945SStanley Chang {
649*eeda4945SStanley Chang 	struct rtk_phy *rtk_phy = phy_get_drvdata(phy);
650*eeda4945SStanley Chang 	unsigned long phy_init_time = jiffies;
651*eeda4945SStanley Chang 	int i, ret = 0;
652*eeda4945SStanley Chang 
653*eeda4945SStanley Chang 	if (!rtk_phy)
654*eeda4945SStanley Chang 		return -EINVAL;
655*eeda4945SStanley Chang 
656*eeda4945SStanley Chang 	for (i = 0; i < rtk_phy->num_phy; i++)
657*eeda4945SStanley Chang 		ret = do_rtk_phy_init(rtk_phy, i);
658*eeda4945SStanley Chang 
659*eeda4945SStanley Chang 	dev_dbg(rtk_phy->dev, "Initialized RTK USB 2.0 PHY (take %dms)\n",
660*eeda4945SStanley Chang 		jiffies_to_msecs(jiffies - phy_init_time));
661*eeda4945SStanley Chang 	return ret;
662*eeda4945SStanley Chang }
663*eeda4945SStanley Chang 
rtk_phy_exit(struct phy * phy)664*eeda4945SStanley Chang static int rtk_phy_exit(struct phy *phy)
665*eeda4945SStanley Chang {
666*eeda4945SStanley Chang 	return 0;
667*eeda4945SStanley Chang }
668*eeda4945SStanley Chang 
rtk_phy_toggle(struct rtk_phy * rtk_phy,bool connect,int port)669*eeda4945SStanley Chang static void rtk_phy_toggle(struct rtk_phy *rtk_phy, bool connect, int port)
670*eeda4945SStanley Chang {
671*eeda4945SStanley Chang 	int index = port;
672*eeda4945SStanley Chang 
673*eeda4945SStanley Chang 	if (index > rtk_phy->num_phy) {
674*eeda4945SStanley Chang 		dev_err(rtk_phy->dev, "%s: The port=%d is not in usb phy (num_phy=%d)\n",
675*eeda4945SStanley Chang 			__func__, index, rtk_phy->num_phy);
676*eeda4945SStanley Chang 		return;
677*eeda4945SStanley Chang 	}
678*eeda4945SStanley Chang 
679*eeda4945SStanley Chang 	do_rtk_phy_toggle(rtk_phy, index, connect);
680*eeda4945SStanley Chang }
681*eeda4945SStanley Chang 
rtk_phy_connect(struct phy * phy,int port)682*eeda4945SStanley Chang static int rtk_phy_connect(struct phy *phy, int port)
683*eeda4945SStanley Chang {
684*eeda4945SStanley Chang 	struct rtk_phy *rtk_phy = phy_get_drvdata(phy);
685*eeda4945SStanley Chang 
686*eeda4945SStanley Chang 	dev_dbg(rtk_phy->dev, "%s port=%d\n", __func__, port);
687*eeda4945SStanley Chang 	rtk_phy_toggle(rtk_phy, true, port);
688*eeda4945SStanley Chang 
689*eeda4945SStanley Chang 	return 0;
690*eeda4945SStanley Chang }
691*eeda4945SStanley Chang 
rtk_phy_disconnect(struct phy * phy,int port)692*eeda4945SStanley Chang static int rtk_phy_disconnect(struct phy *phy, int port)
693*eeda4945SStanley Chang {
694*eeda4945SStanley Chang 	struct rtk_phy *rtk_phy = phy_get_drvdata(phy);
695*eeda4945SStanley Chang 
696*eeda4945SStanley Chang 	dev_dbg(rtk_phy->dev, "%s port=%d\n", __func__, port);
697*eeda4945SStanley Chang 	rtk_phy_toggle(rtk_phy, false, port);
698*eeda4945SStanley Chang 
699*eeda4945SStanley Chang 	return 0;
700*eeda4945SStanley Chang }
701*eeda4945SStanley Chang 
702*eeda4945SStanley Chang static const struct phy_ops ops = {
703*eeda4945SStanley Chang 	.init		= rtk_phy_init,
704*eeda4945SStanley Chang 	.exit		= rtk_phy_exit,
705*eeda4945SStanley Chang 	.connect	= rtk_phy_connect,
706*eeda4945SStanley Chang 	.disconnect	= rtk_phy_disconnect,
707*eeda4945SStanley Chang 	.owner		= THIS_MODULE,
708*eeda4945SStanley Chang };
709*eeda4945SStanley Chang 
710*eeda4945SStanley Chang #ifdef CONFIG_DEBUG_FS
create_phy_debug_root(void)711*eeda4945SStanley Chang static struct dentry *create_phy_debug_root(void)
712*eeda4945SStanley Chang {
713*eeda4945SStanley Chang 	struct dentry *phy_debug_root;
714*eeda4945SStanley Chang 
715*eeda4945SStanley Chang 	phy_debug_root = debugfs_lookup("phy", usb_debug_root);
716*eeda4945SStanley Chang 	if (!phy_debug_root)
717*eeda4945SStanley Chang 		phy_debug_root = debugfs_create_dir("phy", usb_debug_root);
718*eeda4945SStanley Chang 
719*eeda4945SStanley Chang 	return phy_debug_root;
720*eeda4945SStanley Chang }
721*eeda4945SStanley Chang 
rtk_usb2_parameter_show(struct seq_file * s,void * unused)722*eeda4945SStanley Chang static int rtk_usb2_parameter_show(struct seq_file *s, void *unused)
723*eeda4945SStanley Chang {
724*eeda4945SStanley Chang 	struct rtk_phy *rtk_phy = s->private;
725*eeda4945SStanley Chang 	struct phy_cfg *phy_cfg;
726*eeda4945SStanley Chang 	int i, index;
727*eeda4945SStanley Chang 
728*eeda4945SStanley Chang 	phy_cfg = rtk_phy->phy_cfg;
729*eeda4945SStanley Chang 
730*eeda4945SStanley Chang 	seq_puts(s, "Property:\n");
731*eeda4945SStanley Chang 	seq_printf(s, "  check_efuse: %s\n",
732*eeda4945SStanley Chang 		   phy_cfg->check_efuse ? "Enable" : "Disable");
733*eeda4945SStanley Chang 	seq_printf(s, "  check_efuse_version: %d\n",
734*eeda4945SStanley Chang 		   phy_cfg->check_efuse_version);
735*eeda4945SStanley Chang 	seq_printf(s, "  efuse_dc_driving_rate: %d\n",
736*eeda4945SStanley Chang 		   phy_cfg->efuse_dc_driving_rate);
737*eeda4945SStanley Chang 	seq_printf(s, "  dc_driving_mask: 0x%x\n",
738*eeda4945SStanley Chang 		   phy_cfg->dc_driving_mask);
739*eeda4945SStanley Chang 	seq_printf(s, "  efuse_dc_disconnect_rate: %d\n",
740*eeda4945SStanley Chang 		   phy_cfg->efuse_dc_disconnect_rate);
741*eeda4945SStanley Chang 	seq_printf(s, "  dc_disconnect_mask: 0x%x\n",
742*eeda4945SStanley Chang 		   phy_cfg->dc_disconnect_mask);
743*eeda4945SStanley Chang 	seq_printf(s, "  usb_dc_disconnect_at_page0: %s\n",
744*eeda4945SStanley Chang 		   phy_cfg->usb_dc_disconnect_at_page0 ? "true" : "false");
745*eeda4945SStanley Chang 	seq_printf(s, "  do_toggle: %s\n",
746*eeda4945SStanley Chang 		   phy_cfg->do_toggle ? "Enable" : "Disable");
747*eeda4945SStanley Chang 	seq_printf(s, "  do_toggle_driving: %s\n",
748*eeda4945SStanley Chang 		   phy_cfg->do_toggle_driving ? "Enable" : "Disable");
749*eeda4945SStanley Chang 	seq_printf(s, "  driving_updated_for_dev_dis: 0x%x\n",
750*eeda4945SStanley Chang 		   phy_cfg->driving_updated_for_dev_dis);
751*eeda4945SStanley Chang 	seq_printf(s, "  use_default_parameter: %s\n",
752*eeda4945SStanley Chang 		   phy_cfg->use_default_parameter ? "Enable" : "Disable");
753*eeda4945SStanley Chang 	seq_printf(s, "  is_double_sensitivity_mode: %s\n",
754*eeda4945SStanley Chang 		   phy_cfg->is_double_sensitivity_mode ? "Enable" : "Disable");
755*eeda4945SStanley Chang 
756*eeda4945SStanley Chang 	for (index = 0; index < rtk_phy->num_phy; index++) {
757*eeda4945SStanley Chang 		struct phy_parameter *phy_parameter;
758*eeda4945SStanley Chang 		struct phy_reg *phy_reg;
759*eeda4945SStanley Chang 		struct phy_data *phy_data_page;
760*eeda4945SStanley Chang 
761*eeda4945SStanley Chang 		phy_parameter =  &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
762*eeda4945SStanley Chang 		phy_reg = &phy_parameter->phy_reg;
763*eeda4945SStanley Chang 
764*eeda4945SStanley Chang 		seq_printf(s, "PHY %d:\n", index);
765*eeda4945SStanley Chang 
766*eeda4945SStanley Chang 		seq_puts(s, "Page 0:\n");
767*eeda4945SStanley Chang 		/* Set page 0 */
768*eeda4945SStanley Chang 		phy_data_page = phy_cfg->page0;
769*eeda4945SStanley Chang 		rtk_phy_set_page(phy_reg, 0);
770*eeda4945SStanley Chang 
771*eeda4945SStanley Chang 		for (i = 0; i < phy_cfg->page0_size; i++) {
772*eeda4945SStanley Chang 			struct phy_data *phy_data = phy_data_page + i;
773*eeda4945SStanley Chang 			u8 addr = array_index_to_page_addr(i);
774*eeda4945SStanley Chang 			u8 data = phy_data->data;
775*eeda4945SStanley Chang 			u8 value = rtk_phy_read(phy_reg, addr);
776*eeda4945SStanley Chang 
777*eeda4945SStanley Chang 			if (phy_data->addr)
778*eeda4945SStanley Chang 				seq_printf(s, "  Page 0: addr=0x%x data=0x%02x ==> read value=0x%02x\n",
779*eeda4945SStanley Chang 					   addr, data, value);
780*eeda4945SStanley Chang 			else
781*eeda4945SStanley Chang 				seq_printf(s, "  Page 0: addr=0x%x data=none ==> read value=0x%02x\n",
782*eeda4945SStanley Chang 					   addr, value);
783*eeda4945SStanley Chang 		}
784*eeda4945SStanley Chang 
785*eeda4945SStanley Chang 		seq_puts(s, "Page 1:\n");
786*eeda4945SStanley Chang 		/* Set page 1 */
787*eeda4945SStanley Chang 		phy_data_page = phy_cfg->page1;
788*eeda4945SStanley Chang 		rtk_phy_set_page(phy_reg, 1);
789*eeda4945SStanley Chang 
790*eeda4945SStanley Chang 		for (i = 0; i < phy_cfg->page1_size; i++) {
791*eeda4945SStanley Chang 			struct phy_data *phy_data = phy_data_page + i;
792*eeda4945SStanley Chang 			u8 addr = array_index_to_page_addr(i);
793*eeda4945SStanley Chang 			u8 data = phy_data->data;
794*eeda4945SStanley Chang 			u8 value = rtk_phy_read(phy_reg, addr);
795*eeda4945SStanley Chang 
796*eeda4945SStanley Chang 			if (phy_data->addr)
797*eeda4945SStanley Chang 				seq_printf(s, "  Page 1: addr=0x%x data=0x%02x ==> read value=0x%02x\n",
798*eeda4945SStanley Chang 					   addr, data, value);
799*eeda4945SStanley Chang 			else
800*eeda4945SStanley Chang 				seq_printf(s, "  Page 1: addr=0x%x data=none ==> read value=0x%02x\n",
801*eeda4945SStanley Chang 					   addr, value);
802*eeda4945SStanley Chang 		}
803*eeda4945SStanley Chang 
804*eeda4945SStanley Chang 		if (phy_cfg->page2_size == 0)
805*eeda4945SStanley Chang 			goto out;
806*eeda4945SStanley Chang 
807*eeda4945SStanley Chang 		seq_puts(s, "Page 2:\n");
808*eeda4945SStanley Chang 		/* Set page 2 */
809*eeda4945SStanley Chang 		phy_data_page = phy_cfg->page2;
810*eeda4945SStanley Chang 		rtk_phy_set_page(phy_reg, 2);
811*eeda4945SStanley Chang 
812*eeda4945SStanley Chang 		for (i = 0; i < phy_cfg->page2_size; i++) {
813*eeda4945SStanley Chang 			struct phy_data *phy_data = phy_data_page + i;
814*eeda4945SStanley Chang 			u8 addr = array_index_to_page_addr(i);
815*eeda4945SStanley Chang 			u8 data = phy_data->data;
816*eeda4945SStanley Chang 			u8 value = rtk_phy_read(phy_reg, addr);
817*eeda4945SStanley Chang 
818*eeda4945SStanley Chang 			if (phy_data->addr)
819*eeda4945SStanley Chang 				seq_printf(s, "  Page 2: addr=0x%x data=0x%02x ==> read value=0x%02x\n",
820*eeda4945SStanley Chang 					   addr, data, value);
821*eeda4945SStanley Chang 			else
822*eeda4945SStanley Chang 				seq_printf(s, "  Page 2: addr=0x%x data=none ==> read value=0x%02x\n",
823*eeda4945SStanley Chang 					   addr, value);
824*eeda4945SStanley Chang 		}
825*eeda4945SStanley Chang 
826*eeda4945SStanley Chang out:
827*eeda4945SStanley Chang 		seq_puts(s, "PHY Property:\n");
828*eeda4945SStanley Chang 		seq_printf(s, "  efuse_usb_dc_cal: %d\n",
829*eeda4945SStanley Chang 			   (int)phy_parameter->efuse_usb_dc_cal);
830*eeda4945SStanley Chang 		seq_printf(s, "  efuse_usb_dc_dis: %d\n",
831*eeda4945SStanley Chang 			   (int)phy_parameter->efuse_usb_dc_dis);
832*eeda4945SStanley Chang 		seq_printf(s, "  inverse_hstx_sync_clock: %s\n",
833*eeda4945SStanley Chang 			   phy_parameter->inverse_hstx_sync_clock ? "Enable" : "Disable");
834*eeda4945SStanley Chang 		seq_printf(s, "  driving_level: %d\n",
835*eeda4945SStanley Chang 			   phy_parameter->driving_level);
836*eeda4945SStanley Chang 		seq_printf(s, "  driving_level_compensate: %d\n",
837*eeda4945SStanley Chang 			   phy_parameter->driving_level_compensate);
838*eeda4945SStanley Chang 		seq_printf(s, "  disconnection_compensate: %d\n",
839*eeda4945SStanley Chang 			   phy_parameter->disconnection_compensate);
840*eeda4945SStanley Chang 	}
841*eeda4945SStanley Chang 
842*eeda4945SStanley Chang 	return 0;
843*eeda4945SStanley Chang }
844*eeda4945SStanley Chang DEFINE_SHOW_ATTRIBUTE(rtk_usb2_parameter);
845*eeda4945SStanley Chang 
create_debug_files(struct rtk_phy * rtk_phy)846*eeda4945SStanley Chang static inline void create_debug_files(struct rtk_phy *rtk_phy)
847*eeda4945SStanley Chang {
848*eeda4945SStanley Chang 	struct dentry *phy_debug_root = NULL;
849*eeda4945SStanley Chang 
850*eeda4945SStanley Chang 	phy_debug_root = create_phy_debug_root();
851*eeda4945SStanley Chang 	if (!phy_debug_root)
852*eeda4945SStanley Chang 		return;
853*eeda4945SStanley Chang 
854*eeda4945SStanley Chang 	rtk_phy->debug_dir = debugfs_create_dir(dev_name(rtk_phy->dev),
855*eeda4945SStanley Chang 						phy_debug_root);
856*eeda4945SStanley Chang 
857*eeda4945SStanley Chang 	debugfs_create_file("parameter", 0444, rtk_phy->debug_dir, rtk_phy,
858*eeda4945SStanley Chang 			    &rtk_usb2_parameter_fops);
859*eeda4945SStanley Chang }
860*eeda4945SStanley Chang 
remove_debug_files(struct rtk_phy * rtk_phy)861*eeda4945SStanley Chang static inline void remove_debug_files(struct rtk_phy *rtk_phy)
862*eeda4945SStanley Chang {
863*eeda4945SStanley Chang 	debugfs_remove_recursive(rtk_phy->debug_dir);
864*eeda4945SStanley Chang }
865*eeda4945SStanley Chang #else
create_debug_files(struct rtk_phy * rtk_phy)866*eeda4945SStanley Chang static inline void create_debug_files(struct rtk_phy *rtk_phy) { }
remove_debug_files(struct rtk_phy * rtk_phy)867*eeda4945SStanley Chang static inline void remove_debug_files(struct rtk_phy *rtk_phy) { }
868*eeda4945SStanley Chang #endif /* CONFIG_DEBUG_FS */
869*eeda4945SStanley Chang 
get_phy_data_by_efuse(struct rtk_phy * rtk_phy,struct phy_parameter * phy_parameter,int index)870*eeda4945SStanley Chang static int get_phy_data_by_efuse(struct rtk_phy *rtk_phy,
871*eeda4945SStanley Chang 				 struct phy_parameter *phy_parameter, int index)
872*eeda4945SStanley Chang {
873*eeda4945SStanley Chang 	struct phy_cfg *phy_cfg = rtk_phy->phy_cfg;
874*eeda4945SStanley Chang 	u8 value = 0;
875*eeda4945SStanley Chang 	struct nvmem_cell *cell;
876*eeda4945SStanley Chang 	struct soc_device_attribute rtk_soc_groot[] = {
877*eeda4945SStanley Chang 		    { .family = "Realtek Groot",},
878*eeda4945SStanley Chang 		    { /* empty */ } };
879*eeda4945SStanley Chang 
880*eeda4945SStanley Chang 	if (!phy_cfg->check_efuse)
881*eeda4945SStanley Chang 		goto out;
882*eeda4945SStanley Chang 
883*eeda4945SStanley Chang 	/* Read efuse for usb dc cal */
884*eeda4945SStanley Chang 	cell = nvmem_cell_get(rtk_phy->dev, "usb-dc-cal");
885*eeda4945SStanley Chang 	if (IS_ERR(cell)) {
886*eeda4945SStanley Chang 		dev_dbg(rtk_phy->dev, "%s no usb-dc-cal: %ld\n",
887*eeda4945SStanley Chang 			__func__, PTR_ERR(cell));
888*eeda4945SStanley Chang 	} else {
889*eeda4945SStanley Chang 		unsigned char *buf;
890*eeda4945SStanley Chang 		size_t buf_size;
891*eeda4945SStanley Chang 
892*eeda4945SStanley Chang 		buf = nvmem_cell_read(cell, &buf_size);
893*eeda4945SStanley Chang 		if (!IS_ERR(buf)) {
894*eeda4945SStanley Chang 			value = buf[0] & phy_cfg->dc_driving_mask;
895*eeda4945SStanley Chang 			kfree(buf);
896*eeda4945SStanley Chang 		}
897*eeda4945SStanley Chang 		nvmem_cell_put(cell);
898*eeda4945SStanley Chang 	}
899*eeda4945SStanley Chang 
900*eeda4945SStanley Chang 	if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) {
901*eeda4945SStanley Chang 		int rate = phy_cfg->efuse_dc_driving_rate;
902*eeda4945SStanley Chang 
903*eeda4945SStanley Chang 		if (value <= EFUS_USB_DC_CAL_MAX)
904*eeda4945SStanley Chang 			phy_parameter->efuse_usb_dc_cal = (int8_t)(value * rate);
905*eeda4945SStanley Chang 		else
906*eeda4945SStanley Chang 			phy_parameter->efuse_usb_dc_cal = -(int8_t)
907*eeda4945SStanley Chang 				    ((EFUS_USB_DC_CAL_MAX & value) * rate);
908*eeda4945SStanley Chang 
909*eeda4945SStanley Chang 		if (soc_device_match(rtk_soc_groot)) {
910*eeda4945SStanley Chang 			dev_dbg(rtk_phy->dev, "For groot IC we need a workaround to adjust efuse_usb_dc_cal\n");
911*eeda4945SStanley Chang 
912*eeda4945SStanley Chang 			/* We don't multiple dc_cal_rate=2 for positive dc cal compensate */
913*eeda4945SStanley Chang 			if (value <= EFUS_USB_DC_CAL_MAX)
914*eeda4945SStanley Chang 				phy_parameter->efuse_usb_dc_cal = (int8_t)(value);
915*eeda4945SStanley Chang 
916*eeda4945SStanley Chang 			/* We set max dc cal compensate is 0x8 if otp is 0x7 */
917*eeda4945SStanley Chang 			if (value == 0x7)
918*eeda4945SStanley Chang 				phy_parameter->efuse_usb_dc_cal = (int8_t)(value + 1);
919*eeda4945SStanley Chang 		}
920*eeda4945SStanley Chang 	} else { /* for CHECK_EFUSE_V2 */
921*eeda4945SStanley Chang 		phy_parameter->efuse_usb_dc_cal = value & phy_cfg->dc_driving_mask;
922*eeda4945SStanley Chang 	}
923*eeda4945SStanley Chang 
924*eeda4945SStanley Chang 	/* Read efuse for usb dc disconnect level */
925*eeda4945SStanley Chang 	value = 0;
926*eeda4945SStanley Chang 	cell = nvmem_cell_get(rtk_phy->dev, "usb-dc-dis");
927*eeda4945SStanley Chang 	if (IS_ERR(cell)) {
928*eeda4945SStanley Chang 		dev_dbg(rtk_phy->dev, "%s no usb-dc-dis: %ld\n",
929*eeda4945SStanley Chang 			__func__, PTR_ERR(cell));
930*eeda4945SStanley Chang 	} else {
931*eeda4945SStanley Chang 		unsigned char *buf;
932*eeda4945SStanley Chang 		size_t buf_size;
933*eeda4945SStanley Chang 
934*eeda4945SStanley Chang 		buf = nvmem_cell_read(cell, &buf_size);
935*eeda4945SStanley Chang 		if (!IS_ERR(buf)) {
936*eeda4945SStanley Chang 			value = buf[0] & phy_cfg->dc_disconnect_mask;
937*eeda4945SStanley Chang 			kfree(buf);
938*eeda4945SStanley Chang 		}
939*eeda4945SStanley Chang 		nvmem_cell_put(cell);
940*eeda4945SStanley Chang 	}
941*eeda4945SStanley Chang 
942*eeda4945SStanley Chang 	if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) {
943*eeda4945SStanley Chang 		int rate = phy_cfg->efuse_dc_disconnect_rate;
944*eeda4945SStanley Chang 
945*eeda4945SStanley Chang 		if (value <= EFUS_USB_DC_DIS_MAX)
946*eeda4945SStanley Chang 			phy_parameter->efuse_usb_dc_dis = (int8_t)(value * rate);
947*eeda4945SStanley Chang 		else
948*eeda4945SStanley Chang 			phy_parameter->efuse_usb_dc_dis = -(int8_t)
949*eeda4945SStanley Chang 				    ((EFUS_USB_DC_DIS_MAX & value) * rate);
950*eeda4945SStanley Chang 	} else { /* for CHECK_EFUSE_V2 */
951*eeda4945SStanley Chang 		phy_parameter->efuse_usb_dc_dis = value & phy_cfg->dc_disconnect_mask;
952*eeda4945SStanley Chang 	}
953*eeda4945SStanley Chang 
954*eeda4945SStanley Chang out:
955*eeda4945SStanley Chang 	return 0;
956*eeda4945SStanley Chang }
957*eeda4945SStanley Chang 
parse_phy_data(struct rtk_phy * rtk_phy)958*eeda4945SStanley Chang static int parse_phy_data(struct rtk_phy *rtk_phy)
959*eeda4945SStanley Chang {
960*eeda4945SStanley Chang 	struct device *dev = rtk_phy->dev;
961*eeda4945SStanley Chang 	struct device_node *np = dev->of_node;
962*eeda4945SStanley Chang 	struct phy_parameter *phy_parameter;
963*eeda4945SStanley Chang 	int ret = 0;
964*eeda4945SStanley Chang 	int index;
965*eeda4945SStanley Chang 
966*eeda4945SStanley Chang 	rtk_phy->phy_parameter = devm_kzalloc(dev, sizeof(struct phy_parameter) *
967*eeda4945SStanley Chang 						rtk_phy->num_phy, GFP_KERNEL);
968*eeda4945SStanley Chang 	if (!rtk_phy->phy_parameter)
969*eeda4945SStanley Chang 		return -ENOMEM;
970*eeda4945SStanley Chang 
971*eeda4945SStanley Chang 	for (index = 0; index < rtk_phy->num_phy; index++) {
972*eeda4945SStanley Chang 		phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
973*eeda4945SStanley Chang 
974*eeda4945SStanley Chang 		phy_parameter->phy_reg.reg_wrap_vstatus = of_iomap(np, 0);
975*eeda4945SStanley Chang 		phy_parameter->phy_reg.reg_gusb2phyacc0 = of_iomap(np, 1) + index;
976*eeda4945SStanley Chang 		phy_parameter->phy_reg.vstatus_index = index;
977*eeda4945SStanley Chang 
978*eeda4945SStanley Chang 		if (of_property_read_bool(np, "realtek,inverse-hstx-sync-clock"))
979*eeda4945SStanley Chang 			phy_parameter->inverse_hstx_sync_clock = true;
980*eeda4945SStanley Chang 		else
981*eeda4945SStanley Chang 			phy_parameter->inverse_hstx_sync_clock = false;
982*eeda4945SStanley Chang 
983*eeda4945SStanley Chang 		if (of_property_read_u32_index(np, "realtek,driving-level",
984*eeda4945SStanley Chang 					       index, &phy_parameter->driving_level))
985*eeda4945SStanley Chang 			phy_parameter->driving_level = DEFAULT_DC_DRIVING_VALUE;
986*eeda4945SStanley Chang 
987*eeda4945SStanley Chang 		if (of_property_read_u32_index(np, "realtek,driving-level-compensate",
988*eeda4945SStanley Chang 					       index, &phy_parameter->driving_level_compensate))
989*eeda4945SStanley Chang 			phy_parameter->driving_level_compensate = 0;
990*eeda4945SStanley Chang 
991*eeda4945SStanley Chang 		if (of_property_read_u32_index(np, "realtek,disconnection-compensate",
992*eeda4945SStanley Chang 					       index, &phy_parameter->disconnection_compensate))
993*eeda4945SStanley Chang 			phy_parameter->disconnection_compensate = 0;
994*eeda4945SStanley Chang 
995*eeda4945SStanley Chang 		get_phy_data_by_efuse(rtk_phy, phy_parameter, index);
996*eeda4945SStanley Chang 
997*eeda4945SStanley Chang 		update_dc_driving_level(rtk_phy, phy_parameter);
998*eeda4945SStanley Chang 
999*eeda4945SStanley Chang 		update_hs_clk_select(rtk_phy, phy_parameter);
1000*eeda4945SStanley Chang 	}
1001*eeda4945SStanley Chang 
1002*eeda4945SStanley Chang 	return ret;
1003*eeda4945SStanley Chang }
1004*eeda4945SStanley Chang 
rtk_usb2phy_probe(struct platform_device * pdev)1005*eeda4945SStanley Chang static int rtk_usb2phy_probe(struct platform_device *pdev)
1006*eeda4945SStanley Chang {
1007*eeda4945SStanley Chang 	struct rtk_phy *rtk_phy;
1008*eeda4945SStanley Chang 	struct device *dev = &pdev->dev;
1009*eeda4945SStanley Chang 	struct phy *generic_phy;
1010*eeda4945SStanley Chang 	struct phy_provider *phy_provider;
1011*eeda4945SStanley Chang 	const struct phy_cfg *phy_cfg;
1012*eeda4945SStanley Chang 	int ret = 0;
1013*eeda4945SStanley Chang 
1014*eeda4945SStanley Chang 	phy_cfg = of_device_get_match_data(dev);
1015*eeda4945SStanley Chang 	if (!phy_cfg) {
1016*eeda4945SStanley Chang 		dev_err(dev, "phy config are not assigned!\n");
1017*eeda4945SStanley Chang 		return -EINVAL;
1018*eeda4945SStanley Chang 	}
1019*eeda4945SStanley Chang 
1020*eeda4945SStanley Chang 	rtk_phy = devm_kzalloc(dev, sizeof(*rtk_phy), GFP_KERNEL);
1021*eeda4945SStanley Chang 	if (!rtk_phy)
1022*eeda4945SStanley Chang 		return -ENOMEM;
1023*eeda4945SStanley Chang 
1024*eeda4945SStanley Chang 	rtk_phy->dev			= &pdev->dev;
1025*eeda4945SStanley Chang 	rtk_phy->phy_cfg = devm_kzalloc(dev, sizeof(*phy_cfg), GFP_KERNEL);
1026*eeda4945SStanley Chang 
1027*eeda4945SStanley Chang 	memcpy(rtk_phy->phy_cfg, phy_cfg, sizeof(*phy_cfg));
1028*eeda4945SStanley Chang 
1029*eeda4945SStanley Chang 	rtk_phy->num_phy = phy_cfg->num_phy;
1030*eeda4945SStanley Chang 
1031*eeda4945SStanley Chang 	ret = parse_phy_data(rtk_phy);
1032*eeda4945SStanley Chang 	if (ret)
1033*eeda4945SStanley Chang 		goto err;
1034*eeda4945SStanley Chang 
1035*eeda4945SStanley Chang 	platform_set_drvdata(pdev, rtk_phy);
1036*eeda4945SStanley Chang 
1037*eeda4945SStanley Chang 	generic_phy = devm_phy_create(rtk_phy->dev, NULL, &ops);
1038*eeda4945SStanley Chang 	if (IS_ERR(generic_phy))
1039*eeda4945SStanley Chang 		return PTR_ERR(generic_phy);
1040*eeda4945SStanley Chang 
1041*eeda4945SStanley Chang 	phy_set_drvdata(generic_phy, rtk_phy);
1042*eeda4945SStanley Chang 
1043*eeda4945SStanley Chang 	phy_provider = devm_of_phy_provider_register(rtk_phy->dev,
1044*eeda4945SStanley Chang 						     of_phy_simple_xlate);
1045*eeda4945SStanley Chang 	if (IS_ERR(phy_provider))
1046*eeda4945SStanley Chang 		return PTR_ERR(phy_provider);
1047*eeda4945SStanley Chang 
1048*eeda4945SStanley Chang 	create_debug_files(rtk_phy);
1049*eeda4945SStanley Chang 
1050*eeda4945SStanley Chang err:
1051*eeda4945SStanley Chang 	return ret;
1052*eeda4945SStanley Chang }
1053*eeda4945SStanley Chang 
rtk_usb2phy_remove(struct platform_device * pdev)1054*eeda4945SStanley Chang static void rtk_usb2phy_remove(struct platform_device *pdev)
1055*eeda4945SStanley Chang {
1056*eeda4945SStanley Chang 	struct rtk_phy *rtk_phy = platform_get_drvdata(pdev);
1057*eeda4945SStanley Chang 
1058*eeda4945SStanley Chang 	remove_debug_files(rtk_phy);
1059*eeda4945SStanley Chang }
1060*eeda4945SStanley Chang 
1061*eeda4945SStanley Chang static const struct phy_cfg rtd1295_phy_cfg = {
1062*eeda4945SStanley Chang 	.page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
1063*eeda4945SStanley Chang 	.page0 = { [0] = {0xe0, 0x90},
1064*eeda4945SStanley Chang 		   [3] = {0xe3, 0x3a},
1065*eeda4945SStanley Chang 		   [4] = {0xe4, 0x68},
1066*eeda4945SStanley Chang 		   [6] = {0xe6, 0x91},
1067*eeda4945SStanley Chang 		  [13] = {0xf5, 0x81},
1068*eeda4945SStanley Chang 		  [15] = {0xf7, 0x02}, },
1069*eeda4945SStanley Chang 	.page1_size = 8,
1070*eeda4945SStanley Chang 	.page1 = { /* default parameter */ },
1071*eeda4945SStanley Chang 	.page2_size = 0,
1072*eeda4945SStanley Chang 	.page2 = { /* no parameter */ },
1073*eeda4945SStanley Chang 	.num_phy = 1,
1074*eeda4945SStanley Chang 	.check_efuse = false,
1075*eeda4945SStanley Chang 	.check_efuse_version = CHECK_EFUSE_V1,
1076*eeda4945SStanley Chang 	.efuse_dc_driving_rate = 1,
1077*eeda4945SStanley Chang 	.dc_driving_mask = 0xf,
1078*eeda4945SStanley Chang 	.efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
1079*eeda4945SStanley Chang 	.dc_disconnect_mask = 0xf,
1080*eeda4945SStanley Chang 	.usb_dc_disconnect_at_page0 = true,
1081*eeda4945SStanley Chang 	.do_toggle = true,
1082*eeda4945SStanley Chang 	.do_toggle_driving = false,
1083*eeda4945SStanley Chang 	.driving_updated_for_dev_dis = 0xf,
1084*eeda4945SStanley Chang 	.use_default_parameter = false,
1085*eeda4945SStanley Chang 	.is_double_sensitivity_mode = false,
1086*eeda4945SStanley Chang };
1087*eeda4945SStanley Chang 
1088*eeda4945SStanley Chang static const struct phy_cfg rtd1395_phy_cfg = {
1089*eeda4945SStanley Chang 	.page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
1090*eeda4945SStanley Chang 	.page0 = { [4] = {0xe4, 0xac},
1091*eeda4945SStanley Chang 		  [13] = {0xf5, 0x00},
1092*eeda4945SStanley Chang 		  [15] = {0xf7, 0x02}, },
1093*eeda4945SStanley Chang 	.page1_size = 8,
1094*eeda4945SStanley Chang 	.page1 = { /* default parameter */ },
1095*eeda4945SStanley Chang 	.page2_size = 0,
1096*eeda4945SStanley Chang 	.page2 = { /* no parameter */ },
1097*eeda4945SStanley Chang 	.num_phy = 1,
1098*eeda4945SStanley Chang 	.check_efuse = false,
1099*eeda4945SStanley Chang 	.check_efuse_version = CHECK_EFUSE_V1,
1100*eeda4945SStanley Chang 	.efuse_dc_driving_rate = 1,
1101*eeda4945SStanley Chang 	.dc_driving_mask = 0xf,
1102*eeda4945SStanley Chang 	.efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
1103*eeda4945SStanley Chang 	.dc_disconnect_mask = 0xf,
1104*eeda4945SStanley Chang 	.usb_dc_disconnect_at_page0 = true,
1105*eeda4945SStanley Chang 	.do_toggle = true,
1106*eeda4945SStanley Chang 	.do_toggle_driving = false,
1107*eeda4945SStanley Chang 	.driving_updated_for_dev_dis = 0xf,
1108*eeda4945SStanley Chang 	.use_default_parameter = false,
1109*eeda4945SStanley Chang 	.is_double_sensitivity_mode = false,
1110*eeda4945SStanley Chang };
1111*eeda4945SStanley Chang 
1112*eeda4945SStanley Chang static const struct phy_cfg rtd1395_phy_cfg_2port = {
1113*eeda4945SStanley Chang 	.page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
1114*eeda4945SStanley Chang 	.page0 = { [4] = {0xe4, 0xac},
1115*eeda4945SStanley Chang 		  [13] = {0xf5, 0x00},
1116*eeda4945SStanley Chang 		  [15] = {0xf7, 0x02}, },
1117*eeda4945SStanley Chang 	.page1_size = 8,
1118*eeda4945SStanley Chang 	.page1 = { /* default parameter */ },
1119*eeda4945SStanley Chang 	.page2_size = 0,
1120*eeda4945SStanley Chang 	.page2 = { /* no parameter */ },
1121*eeda4945SStanley Chang 	.num_phy = 2,
1122*eeda4945SStanley Chang 	.check_efuse = false,
1123*eeda4945SStanley Chang 	.check_efuse_version = CHECK_EFUSE_V1,
1124*eeda4945SStanley Chang 	.efuse_dc_driving_rate = 1,
1125*eeda4945SStanley Chang 	.dc_driving_mask = 0xf,
1126*eeda4945SStanley Chang 	.efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
1127*eeda4945SStanley Chang 	.dc_disconnect_mask = 0xf,
1128*eeda4945SStanley Chang 	.usb_dc_disconnect_at_page0 = true,
1129*eeda4945SStanley Chang 	.do_toggle = true,
1130*eeda4945SStanley Chang 	.do_toggle_driving = false,
1131*eeda4945SStanley Chang 	.driving_updated_for_dev_dis = 0xf,
1132*eeda4945SStanley Chang 	.use_default_parameter = false,
1133*eeda4945SStanley Chang 	.is_double_sensitivity_mode = false,
1134*eeda4945SStanley Chang };
1135*eeda4945SStanley Chang 
1136*eeda4945SStanley Chang static const struct phy_cfg rtd1619_phy_cfg = {
1137*eeda4945SStanley Chang 	.page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
1138*eeda4945SStanley Chang 	.page0 = { [4] = {0xe4, 0x68}, },
1139*eeda4945SStanley Chang 	.page1_size = 8,
1140*eeda4945SStanley Chang 	.page1 = { /* default parameter */ },
1141*eeda4945SStanley Chang 	.page2_size = 0,
1142*eeda4945SStanley Chang 	.page2 = { /* no parameter */ },
1143*eeda4945SStanley Chang 	.num_phy = 1,
1144*eeda4945SStanley Chang 	.check_efuse = true,
1145*eeda4945SStanley Chang 	.check_efuse_version = CHECK_EFUSE_V1,
1146*eeda4945SStanley Chang 	.efuse_dc_driving_rate = 1,
1147*eeda4945SStanley Chang 	.dc_driving_mask = 0xf,
1148*eeda4945SStanley Chang 	.efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
1149*eeda4945SStanley Chang 	.dc_disconnect_mask = 0xf,
1150*eeda4945SStanley Chang 	.usb_dc_disconnect_at_page0 = true,
1151*eeda4945SStanley Chang 	.do_toggle = true,
1152*eeda4945SStanley Chang 	.do_toggle_driving = false,
1153*eeda4945SStanley Chang 	.driving_updated_for_dev_dis = 0xf,
1154*eeda4945SStanley Chang 	.use_default_parameter = false,
1155*eeda4945SStanley Chang 	.is_double_sensitivity_mode = false,
1156*eeda4945SStanley Chang };
1157*eeda4945SStanley Chang 
1158*eeda4945SStanley Chang static const struct phy_cfg rtd1319_phy_cfg = {
1159*eeda4945SStanley Chang 	.page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
1160*eeda4945SStanley Chang 	.page0 = { [0] = {0xe0, 0x18},
1161*eeda4945SStanley Chang 		   [4] = {0xe4, 0x6a},
1162*eeda4945SStanley Chang 		   [7] = {0xe7, 0x71},
1163*eeda4945SStanley Chang 		  [13] = {0xf5, 0x15},
1164*eeda4945SStanley Chang 		  [15] = {0xf7, 0x32}, },
1165*eeda4945SStanley Chang 	.page1_size = 8,
1166*eeda4945SStanley Chang 	.page1 = { [3] = {0xe3, 0x44}, },
1167*eeda4945SStanley Chang 	.page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
1168*eeda4945SStanley Chang 	.page2 = { [0] = {0xe0, 0x01}, },
1169*eeda4945SStanley Chang 	.num_phy = 1,
1170*eeda4945SStanley Chang 	.check_efuse = true,
1171*eeda4945SStanley Chang 	.check_efuse_version = CHECK_EFUSE_V1,
1172*eeda4945SStanley Chang 	.efuse_dc_driving_rate = 1,
1173*eeda4945SStanley Chang 	.dc_driving_mask = 0xf,
1174*eeda4945SStanley Chang 	.efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
1175*eeda4945SStanley Chang 	.dc_disconnect_mask = 0xf,
1176*eeda4945SStanley Chang 	.usb_dc_disconnect_at_page0 = true,
1177*eeda4945SStanley Chang 	.do_toggle = true,
1178*eeda4945SStanley Chang 	.do_toggle_driving = true,
1179*eeda4945SStanley Chang 	.driving_updated_for_dev_dis = 0xf,
1180*eeda4945SStanley Chang 	.use_default_parameter = false,
1181*eeda4945SStanley Chang 	.is_double_sensitivity_mode = true,
1182*eeda4945SStanley Chang };
1183*eeda4945SStanley Chang 
1184*eeda4945SStanley Chang static const struct phy_cfg rtd1312c_phy_cfg = {
1185*eeda4945SStanley Chang 	.page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
1186*eeda4945SStanley Chang 	.page0 = { [0] = {0xe0, 0x14},
1187*eeda4945SStanley Chang 		   [4] = {0xe4, 0x67},
1188*eeda4945SStanley Chang 		   [5] = {0xe5, 0x55}, },
1189*eeda4945SStanley Chang 	.page1_size = 8,
1190*eeda4945SStanley Chang 	.page1 = { [3] = {0xe3, 0x23},
1191*eeda4945SStanley Chang 		   [6] = {0xe6, 0x58}, },
1192*eeda4945SStanley Chang 	.page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
1193*eeda4945SStanley Chang 	.page2 = { /* default parameter */ },
1194*eeda4945SStanley Chang 	.num_phy = 1,
1195*eeda4945SStanley Chang 	.check_efuse = true,
1196*eeda4945SStanley Chang 	.check_efuse_version = CHECK_EFUSE_V1,
1197*eeda4945SStanley Chang 	.efuse_dc_driving_rate = 1,
1198*eeda4945SStanley Chang 	.dc_driving_mask = 0xf,
1199*eeda4945SStanley Chang 	.efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
1200*eeda4945SStanley Chang 	.dc_disconnect_mask = 0xf,
1201*eeda4945SStanley Chang 	.usb_dc_disconnect_at_page0 = true,
1202*eeda4945SStanley Chang 	.do_toggle = true,
1203*eeda4945SStanley Chang 	.do_toggle_driving = true,
1204*eeda4945SStanley Chang 	.driving_updated_for_dev_dis = 0xf,
1205*eeda4945SStanley Chang 	.use_default_parameter = false,
1206*eeda4945SStanley Chang 	.is_double_sensitivity_mode = true,
1207*eeda4945SStanley Chang };
1208*eeda4945SStanley Chang 
1209*eeda4945SStanley Chang static const struct phy_cfg rtd1619b_phy_cfg = {
1210*eeda4945SStanley Chang 	.page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
1211*eeda4945SStanley Chang 	.page0 = { [0] = {0xe0, 0xa3},
1212*eeda4945SStanley Chang 		   [4] = {0xe4, 0xa8},
1213*eeda4945SStanley Chang 		   [5] = {0xe5, 0x4f},
1214*eeda4945SStanley Chang 		   [6] = {0xe6, 0x02}, },
1215*eeda4945SStanley Chang 	.page1_size = 8,
1216*eeda4945SStanley Chang 	.page1 = { [3] = {0xe3, 0x64}, },
1217*eeda4945SStanley Chang 	.page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
1218*eeda4945SStanley Chang 	.page2 = { [7] = {0xe7, 0x45}, },
1219*eeda4945SStanley Chang 	.num_phy = 1,
1220*eeda4945SStanley Chang 	.check_efuse = true,
1221*eeda4945SStanley Chang 	.check_efuse_version = CHECK_EFUSE_V1,
1222*eeda4945SStanley Chang 	.efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE,
1223*eeda4945SStanley Chang 	.dc_driving_mask = 0x1f,
1224*eeda4945SStanley Chang 	.efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
1225*eeda4945SStanley Chang 	.dc_disconnect_mask = 0xf,
1226*eeda4945SStanley Chang 	.usb_dc_disconnect_at_page0 = false,
1227*eeda4945SStanley Chang 	.do_toggle = true,
1228*eeda4945SStanley Chang 	.do_toggle_driving = true,
1229*eeda4945SStanley Chang 	.driving_updated_for_dev_dis = 0x8,
1230*eeda4945SStanley Chang 	.use_default_parameter = false,
1231*eeda4945SStanley Chang 	.is_double_sensitivity_mode = true,
1232*eeda4945SStanley Chang };
1233*eeda4945SStanley Chang 
1234*eeda4945SStanley Chang static const struct phy_cfg rtd1319d_phy_cfg = {
1235*eeda4945SStanley Chang 	.page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
1236*eeda4945SStanley Chang 	.page0 = { [0] = {0xe0, 0xa3},
1237*eeda4945SStanley Chang 		   [4] = {0xe4, 0x8e},
1238*eeda4945SStanley Chang 		   [5] = {0xe5, 0x4f},
1239*eeda4945SStanley Chang 		   [6] = {0xe6, 0x02}, },
1240*eeda4945SStanley Chang 	.page1_size = MAX_USB_PHY_PAGE1_DATA_SIZE,
1241*eeda4945SStanley Chang 	.page1 = { [14] = {0xf5, 0x1}, },
1242*eeda4945SStanley Chang 	.page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
1243*eeda4945SStanley Chang 	.page2 = { [7] = {0xe7, 0x44}, },
1244*eeda4945SStanley Chang 	.check_efuse = true,
1245*eeda4945SStanley Chang 	.num_phy = 1,
1246*eeda4945SStanley Chang 	.check_efuse_version = CHECK_EFUSE_V1,
1247*eeda4945SStanley Chang 	.efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE,
1248*eeda4945SStanley Chang 	.dc_driving_mask = 0x1f,
1249*eeda4945SStanley Chang 	.efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
1250*eeda4945SStanley Chang 	.dc_disconnect_mask = 0xf,
1251*eeda4945SStanley Chang 	.usb_dc_disconnect_at_page0 = false,
1252*eeda4945SStanley Chang 	.do_toggle = true,
1253*eeda4945SStanley Chang 	.do_toggle_driving = false,
1254*eeda4945SStanley Chang 	.driving_updated_for_dev_dis = 0x8,
1255*eeda4945SStanley Chang 	.use_default_parameter = false,
1256*eeda4945SStanley Chang 	.is_double_sensitivity_mode = true,
1257*eeda4945SStanley Chang };
1258*eeda4945SStanley Chang 
1259*eeda4945SStanley Chang static const struct phy_cfg rtd1315e_phy_cfg = {
1260*eeda4945SStanley Chang 	.page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
1261*eeda4945SStanley Chang 	.page0 = { [0] = {0xe0, 0xa3},
1262*eeda4945SStanley Chang 		   [4] = {0xe4, 0x8c},
1263*eeda4945SStanley Chang 		   [5] = {0xe5, 0x4f},
1264*eeda4945SStanley Chang 		   [6] = {0xe6, 0x02}, },
1265*eeda4945SStanley Chang 	.page1_size = MAX_USB_PHY_PAGE1_DATA_SIZE,
1266*eeda4945SStanley Chang 	.page1 = { [3] = {0xe3, 0x7f},
1267*eeda4945SStanley Chang 		  [14] = {0xf5, 0x01}, },
1268*eeda4945SStanley Chang 	.page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
1269*eeda4945SStanley Chang 	.page2 = { [7] = {0xe7, 0x44}, },
1270*eeda4945SStanley Chang 	.num_phy = 1,
1271*eeda4945SStanley Chang 	.check_efuse = true,
1272*eeda4945SStanley Chang 	.check_efuse_version = CHECK_EFUSE_V2,
1273*eeda4945SStanley Chang 	.efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE,
1274*eeda4945SStanley Chang 	.dc_driving_mask = 0x1f,
1275*eeda4945SStanley Chang 	.efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
1276*eeda4945SStanley Chang 	.dc_disconnect_mask = 0xf,
1277*eeda4945SStanley Chang 	.usb_dc_disconnect_at_page0 = false,
1278*eeda4945SStanley Chang 	.do_toggle = true,
1279*eeda4945SStanley Chang 	.do_toggle_driving = false,
1280*eeda4945SStanley Chang 	.driving_updated_for_dev_dis = 0x8,
1281*eeda4945SStanley Chang 	.use_default_parameter = false,
1282*eeda4945SStanley Chang 	.is_double_sensitivity_mode = true,
1283*eeda4945SStanley Chang };
1284*eeda4945SStanley Chang 
1285*eeda4945SStanley Chang static const struct of_device_id usbphy_rtk_dt_match[] = {
1286*eeda4945SStanley Chang 	{ .compatible = "realtek,rtd1295-usb2phy", .data = &rtd1295_phy_cfg },
1287*eeda4945SStanley Chang 	{ .compatible = "realtek,rtd1312c-usb2phy", .data = &rtd1312c_phy_cfg },
1288*eeda4945SStanley Chang 	{ .compatible = "realtek,rtd1315e-usb2phy", .data = &rtd1315e_phy_cfg },
1289*eeda4945SStanley Chang 	{ .compatible = "realtek,rtd1319-usb2phy", .data = &rtd1319_phy_cfg },
1290*eeda4945SStanley Chang 	{ .compatible = "realtek,rtd1319d-usb2phy", .data = &rtd1319d_phy_cfg },
1291*eeda4945SStanley Chang 	{ .compatible = "realtek,rtd1395-usb2phy", .data = &rtd1395_phy_cfg },
1292*eeda4945SStanley Chang 	{ .compatible = "realtek,rtd1395-usb2phy-2port", .data = &rtd1395_phy_cfg_2port },
1293*eeda4945SStanley Chang 	{ .compatible = "realtek,rtd1619-usb2phy", .data = &rtd1619_phy_cfg },
1294*eeda4945SStanley Chang 	{ .compatible = "realtek,rtd1619b-usb2phy", .data = &rtd1619b_phy_cfg },
1295*eeda4945SStanley Chang 	{},
1296*eeda4945SStanley Chang };
1297*eeda4945SStanley Chang MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match);
1298*eeda4945SStanley Chang 
1299*eeda4945SStanley Chang static struct platform_driver rtk_usb2phy_driver = {
1300*eeda4945SStanley Chang 	.probe		= rtk_usb2phy_probe,
1301*eeda4945SStanley Chang 	.remove_new	= rtk_usb2phy_remove,
1302*eeda4945SStanley Chang 	.driver		= {
1303*eeda4945SStanley Chang 		.name	= "rtk-usb2phy",
1304*eeda4945SStanley Chang 		.of_match_table = usbphy_rtk_dt_match,
1305*eeda4945SStanley Chang 	},
1306*eeda4945SStanley Chang };
1307*eeda4945SStanley Chang 
1308*eeda4945SStanley Chang module_platform_driver(rtk_usb2phy_driver);
1309*eeda4945SStanley Chang 
1310*eeda4945SStanley Chang MODULE_LICENSE("GPL");
1311*eeda4945SStanley Chang MODULE_AUTHOR("Stanley Chang <stanley_chang@realtek.com>");
1312*eeda4945SStanley Chang MODULE_DESCRIPTION("Realtek usb 2.0 phy driver");
1313