blob: 2afbf9f36d8329ab9a44f5ff1c67b222ef0d8dcb [file] [log] [blame]
Chunfeng Yundc7f1902015-09-29 11:01:36 +08001/*
2 * Copyright (c) 2015 MediaTek Inc.
3 * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include <dt-bindings/phy/phy.h>
17#include <linux/clk.h>
18#include <linux/delay.h>
19#include <linux/io.h>
20#include <linux/module.h>
21#include <linux/of_address.h>
22#include <linux/phy/phy.h>
23#include <linux/platform_device.h>
24
25/*
26 * for sifslv2 register, but exclude port's;
27 * relative to USB3_SIF2_BASE base address
28 */
29#define SSUSB_SIFSLV_SPLLC 0x0000
30
31/* offsets of sub-segment in each port registers */
32#define SSUSB_SIFSLV_U2PHY_COM_BASE 0x0000
33#define SSUSB_SIFSLV_U3PHYD_BASE 0x0100
34#define SSUSB_USB30_PHYA_SIV_B_BASE 0x0300
35#define SSUSB_SIFSLV_U3PHYA_DA_BASE 0x0400
36
37#define U3P_USBPHYACR0 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0000)
38#define PA0_RG_U2PLL_FORCE_ON BIT(15)
39
40#define U3P_USBPHYACR2 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0008)
41#define PA2_RG_SIF_U2PLL_FORCE_EN BIT(18)
42
43#define U3P_USBPHYACR5 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0014)
44#define PA5_RG_U2_HSTX_SRCTRL GENMASK(14, 12)
45#define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12)
46#define PA5_RG_U2_HS_100U_U3_EN BIT(11)
47
48#define U3P_USBPHYACR6 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0018)
49#define PA6_RG_U2_ISO_EN BIT(31)
50#define PA6_RG_U2_BC11_SW_EN BIT(23)
51#define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20)
Chunfeng Yun43f53b12015-12-04 10:08:56 +080052#define PA6_RG_U2_SQTH GENMASK(3, 0)
53#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x))
Chunfeng Yundc7f1902015-09-29 11:01:36 +080054
55#define U3P_U2PHYACR4 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0020)
56#define P2C_RG_USB20_GPIO_CTL BIT(9)
57#define P2C_USB20_GPIO_MODE BIT(8)
58#define P2C_U2_GPIO_CTR_MSK (P2C_RG_USB20_GPIO_CTL | P2C_USB20_GPIO_MODE)
59
60#define U3D_U2PHYDCR0 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0060)
61#define P2C_RG_SIF_U2PLL_FORCE_ON BIT(24)
62
63#define U3P_U2PHYDTM0 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0068)
64#define P2C_FORCE_UART_EN BIT(26)
65#define P2C_FORCE_DATAIN BIT(23)
66#define P2C_FORCE_DM_PULLDOWN BIT(21)
67#define P2C_FORCE_DP_PULLDOWN BIT(20)
68#define P2C_FORCE_XCVRSEL BIT(19)
69#define P2C_FORCE_SUSPENDM BIT(18)
70#define P2C_FORCE_TERMSEL BIT(17)
71#define P2C_RG_DATAIN GENMASK(13, 10)
72#define P2C_RG_DATAIN_VAL(x) ((0xf & (x)) << 10)
73#define P2C_RG_DMPULLDOWN BIT(7)
74#define P2C_RG_DPPULLDOWN BIT(6)
75#define P2C_RG_XCVRSEL GENMASK(5, 4)
76#define P2C_RG_XCVRSEL_VAL(x) ((0x3 & (x)) << 4)
77#define P2C_RG_SUSPENDM BIT(3)
78#define P2C_RG_TERMSEL BIT(2)
79#define P2C_DTM0_PART_MASK \
80 (P2C_FORCE_DATAIN | P2C_FORCE_DM_PULLDOWN | \
81 P2C_FORCE_DP_PULLDOWN | P2C_FORCE_XCVRSEL | \
82 P2C_FORCE_TERMSEL | P2C_RG_DMPULLDOWN | \
83 P2C_RG_DPPULLDOWN | P2C_RG_TERMSEL)
84
85#define U3P_U2PHYDTM1 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x006C)
86#define P2C_RG_UART_EN BIT(16)
87#define P2C_RG_VBUSVALID BIT(5)
88#define P2C_RG_SESSEND BIT(4)
89#define P2C_RG_AVALID BIT(2)
90
91#define U3P_U3_PHYA_REG0 (SSUSB_USB30_PHYA_SIV_B_BASE + 0x0000)
92#define P3A_RG_U3_VUSB10_ON BIT(5)
93
94#define U3P_U3_PHYA_REG6 (SSUSB_USB30_PHYA_SIV_B_BASE + 0x0018)
95#define P3A_RG_TX_EIDLE_CM GENMASK(31, 28)
96#define P3A_RG_TX_EIDLE_CM_VAL(x) ((0xf & (x)) << 28)
97
98#define U3P_U3_PHYA_REG9 (SSUSB_USB30_PHYA_SIV_B_BASE + 0x0024)
99#define P3A_RG_RX_DAC_MUX GENMASK(5, 1)
100#define P3A_RG_RX_DAC_MUX_VAL(x) ((0x1f & (x)) << 1)
101
102#define U3P_U3PHYA_DA_REG0 (SSUSB_SIFSLV_U3PHYA_DA_BASE + 0x0000)
103#define P3A_RG_XTAL_EXT_EN_U3 GENMASK(11, 10)
104#define P3A_RG_XTAL_EXT_EN_U3_VAL(x) ((0x3 & (x)) << 10)
105
106#define U3P_PHYD_CDR1 (SSUSB_SIFSLV_U3PHYD_BASE + 0x005c)
107#define P3D_RG_CDR_BIR_LTD1 GENMASK(28, 24)
108#define P3D_RG_CDR_BIR_LTD1_VAL(x) ((0x1f & (x)) << 24)
109#define P3D_RG_CDR_BIR_LTD0 GENMASK(12, 8)
110#define P3D_RG_CDR_BIR_LTD0_VAL(x) ((0x1f & (x)) << 8)
111
112#define U3P_XTALCTL3 (SSUSB_SIFSLV_SPLLC + 0x0018)
113#define XC3_RG_U3_XTAL_RX_PWD BIT(9)
114#define XC3_RG_U3_FRC_XTAL_RX_PWD BIT(8)
115
116struct mt65xx_phy_instance {
117 struct phy *phy;
118 void __iomem *port_base;
119 u32 index;
120 u8 type;
121};
122
123struct mt65xx_u3phy {
124 struct device *dev;
125 void __iomem *sif_base; /* include sif2, but exclude port's */
126 struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */
127 struct mt65xx_phy_instance **phys;
128 int nphys;
129};
130
131static void phy_instance_init(struct mt65xx_u3phy *u3phy,
132 struct mt65xx_phy_instance *instance)
133{
134 void __iomem *port_base = instance->port_base;
135 u32 index = instance->index;
136 u32 tmp;
137
138 /* switch to USB function. (system register, force ip into usb mode) */
139 tmp = readl(port_base + U3P_U2PHYDTM0);
140 tmp &= ~P2C_FORCE_UART_EN;
141 tmp |= P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0);
142 writel(tmp, port_base + U3P_U2PHYDTM0);
143
144 tmp = readl(port_base + U3P_U2PHYDTM1);
145 tmp &= ~P2C_RG_UART_EN;
146 writel(tmp, port_base + U3P_U2PHYDTM1);
147
148 if (!index) {
149 tmp = readl(port_base + U3P_U2PHYACR4);
150 tmp &= ~P2C_U2_GPIO_CTR_MSK;
151 writel(tmp, port_base + U3P_U2PHYACR4);
152
153 tmp = readl(port_base + U3P_USBPHYACR2);
154 tmp |= PA2_RG_SIF_U2PLL_FORCE_EN;
155 writel(tmp, port_base + U3P_USBPHYACR2);
156
157 tmp = readl(port_base + U3D_U2PHYDCR0);
158 tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
159 writel(tmp, port_base + U3D_U2PHYDCR0);
160 } else {
161 tmp = readl(port_base + U3D_U2PHYDCR0);
162 tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
163 writel(tmp, port_base + U3D_U2PHYDCR0);
164
165 tmp = readl(port_base + U3P_U2PHYDTM0);
166 tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
167 writel(tmp, port_base + U3P_U2PHYDTM0);
168 }
169
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800170 tmp = readl(port_base + U3P_USBPHYACR6);
Chunfeng Yun43f53b12015-12-04 10:08:56 +0800171 tmp &= ~PA6_RG_U2_BC11_SW_EN; /* DP/DM BC1.1 path Disable */
172 tmp &= ~PA6_RG_U2_SQTH;
173 tmp |= PA6_RG_U2_SQTH_VAL(2);
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800174 writel(tmp, port_base + U3P_USBPHYACR6);
175
176 tmp = readl(port_base + U3P_U3PHYA_DA_REG0);
177 tmp &= ~P3A_RG_XTAL_EXT_EN_U3;
178 tmp |= P3A_RG_XTAL_EXT_EN_U3_VAL(2);
179 writel(tmp, port_base + U3P_U3PHYA_DA_REG0);
180
181 tmp = readl(port_base + U3P_U3_PHYA_REG9);
182 tmp &= ~P3A_RG_RX_DAC_MUX;
183 tmp |= P3A_RG_RX_DAC_MUX_VAL(4);
184 writel(tmp, port_base + U3P_U3_PHYA_REG9);
185
186 tmp = readl(port_base + U3P_U3_PHYA_REG6);
187 tmp &= ~P3A_RG_TX_EIDLE_CM;
188 tmp |= P3A_RG_TX_EIDLE_CM_VAL(0xe);
189 writel(tmp, port_base + U3P_U3_PHYA_REG6);
190
191 tmp = readl(port_base + U3P_PHYD_CDR1);
192 tmp &= ~(P3D_RG_CDR_BIR_LTD0 | P3D_RG_CDR_BIR_LTD1);
193 tmp |= P3D_RG_CDR_BIR_LTD0_VAL(0xc) | P3D_RG_CDR_BIR_LTD1_VAL(0x3);
194 writel(tmp, port_base + U3P_PHYD_CDR1);
195
196 dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
197}
198
199static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
200 struct mt65xx_phy_instance *instance)
201{
202 void __iomem *port_base = instance->port_base;
203 u32 index = instance->index;
204 u32 tmp;
205
206 if (!index) {
207 /* Set RG_SSUSB_VUSB10_ON as 1 after VUSB10 ready */
208 tmp = readl(port_base + U3P_U3_PHYA_REG0);
209 tmp |= P3A_RG_U3_VUSB10_ON;
210 writel(tmp, port_base + U3P_U3_PHYA_REG0);
211 }
212
213 /* (force_suspendm=0) (let suspendm=1, enable usb 480MHz pll) */
214 tmp = readl(port_base + U3P_U2PHYDTM0);
215 tmp &= ~(P2C_FORCE_SUSPENDM | P2C_RG_XCVRSEL);
216 tmp &= ~(P2C_RG_DATAIN | P2C_DTM0_PART_MASK);
217 writel(tmp, port_base + U3P_U2PHYDTM0);
218
219 /* OTG Enable */
220 tmp = readl(port_base + U3P_USBPHYACR6);
221 tmp |= PA6_RG_U2_OTG_VBUSCMP_EN;
222 writel(tmp, port_base + U3P_USBPHYACR6);
223
224 if (!index) {
225 tmp = readl(u3phy->sif_base + U3P_XTALCTL3);
226 tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD;
227 writel(tmp, u3phy->sif_base + U3P_XTALCTL3);
228
229 /* [mt8173]disable Change 100uA current from SSUSB */
230 tmp = readl(port_base + U3P_USBPHYACR5);
231 tmp &= ~PA5_RG_U2_HS_100U_U3_EN;
232 writel(tmp, port_base + U3P_USBPHYACR5);
233 }
234
235 tmp = readl(port_base + U3P_U2PHYDTM1);
236 tmp |= P2C_RG_VBUSVALID | P2C_RG_AVALID;
237 tmp &= ~P2C_RG_SESSEND;
238 writel(tmp, port_base + U3P_U2PHYDTM1);
239
240 /* USB 2.0 slew rate calibration */
241 tmp = readl(port_base + U3P_USBPHYACR5);
242 tmp &= ~PA5_RG_U2_HSTX_SRCTRL;
243 tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(4);
244 writel(tmp, port_base + U3P_USBPHYACR5);
245
246 if (index) {
247 tmp = readl(port_base + U3D_U2PHYDCR0);
248 tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
249 writel(tmp, port_base + U3D_U2PHYDCR0);
250
251 tmp = readl(port_base + U3P_U2PHYDTM0);
252 tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
253 writel(tmp, port_base + U3P_U2PHYDTM0);
254 }
255 dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
256}
257
258static void phy_instance_power_off(struct mt65xx_u3phy *u3phy,
259 struct mt65xx_phy_instance *instance)
260{
261 void __iomem *port_base = instance->port_base;
262 u32 index = instance->index;
263 u32 tmp;
264
265 tmp = readl(port_base + U3P_U2PHYDTM0);
266 tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN);
267 tmp |= P2C_FORCE_SUSPENDM;
268 writel(tmp, port_base + U3P_U2PHYDTM0);
269
270 /* OTG Disable */
271 tmp = readl(port_base + U3P_USBPHYACR6);
272 tmp &= ~PA6_RG_U2_OTG_VBUSCMP_EN;
273 writel(tmp, port_base + U3P_USBPHYACR6);
274
275 if (!index) {
276 /* (also disable)Change 100uA current switch to USB2.0 */
277 tmp = readl(port_base + U3P_USBPHYACR5);
278 tmp &= ~PA5_RG_U2_HS_100U_U3_EN;
279 writel(tmp, port_base + U3P_USBPHYACR5);
280 }
281
282 /* let suspendm=0, set utmi into analog power down */
283 tmp = readl(port_base + U3P_U2PHYDTM0);
284 tmp &= ~P2C_RG_SUSPENDM;
285 writel(tmp, port_base + U3P_U2PHYDTM0);
286 udelay(1);
287
288 tmp = readl(port_base + U3P_U2PHYDTM1);
289 tmp &= ~(P2C_RG_VBUSVALID | P2C_RG_AVALID);
290 tmp |= P2C_RG_SESSEND;
291 writel(tmp, port_base + U3P_U2PHYDTM1);
292
293 if (!index) {
294 tmp = readl(port_base + U3P_U3_PHYA_REG0);
295 tmp &= ~P3A_RG_U3_VUSB10_ON;
296 writel(tmp, port_base + U3P_U3_PHYA_REG0);
297 } else {
298 tmp = readl(port_base + U3D_U2PHYDCR0);
299 tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
300 writel(tmp, port_base + U3D_U2PHYDCR0);
301 }
302
303 dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
304}
305
306static void phy_instance_exit(struct mt65xx_u3phy *u3phy,
307 struct mt65xx_phy_instance *instance)
308{
309 void __iomem *port_base = instance->port_base;
310 u32 index = instance->index;
311 u32 tmp;
312
313 if (index) {
314 tmp = readl(port_base + U3D_U2PHYDCR0);
315 tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
316 writel(tmp, port_base + U3D_U2PHYDCR0);
317
318 tmp = readl(port_base + U3P_U2PHYDTM0);
319 tmp &= ~P2C_FORCE_SUSPENDM;
320 writel(tmp, port_base + U3P_U2PHYDTM0);
321 }
322}
323
324static int mt65xx_phy_init(struct phy *phy)
325{
326 struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
327 struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
328 int ret;
329
330 ret = clk_prepare_enable(u3phy->u3phya_ref);
331 if (ret) {
332 dev_err(u3phy->dev, "failed to enable u3phya_ref\n");
333 return ret;
334 }
335
336 phy_instance_init(u3phy, instance);
337 return 0;
338}
339
340static int mt65xx_phy_power_on(struct phy *phy)
341{
342 struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
343 struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
344
345 phy_instance_power_on(u3phy, instance);
346 return 0;
347}
348
349static int mt65xx_phy_power_off(struct phy *phy)
350{
351 struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
352 struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
353
354 phy_instance_power_off(u3phy, instance);
355 return 0;
356}
357
358static int mt65xx_phy_exit(struct phy *phy)
359{
360 struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
361 struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
362
363 phy_instance_exit(u3phy, instance);
364 clk_disable_unprepare(u3phy->u3phya_ref);
365 return 0;
366}
367
368static struct phy *mt65xx_phy_xlate(struct device *dev,
369 struct of_phandle_args *args)
370{
371 struct mt65xx_u3phy *u3phy = dev_get_drvdata(dev);
372 struct mt65xx_phy_instance *instance = NULL;
373 struct device_node *phy_np = args->np;
374 int index;
375
376
377 if (args->args_count != 1) {
378 dev_err(dev, "invalid number of cells in 'phy' property\n");
379 return ERR_PTR(-EINVAL);
380 }
381
382 for (index = 0; index < u3phy->nphys; index++)
383 if (phy_np == u3phy->phys[index]->phy->dev.of_node) {
384 instance = u3phy->phys[index];
385 break;
386 }
387
388 if (!instance) {
389 dev_err(dev, "failed to find appropriate phy\n");
390 return ERR_PTR(-EINVAL);
391 }
392
393 instance->type = args->args[0];
394
395 if (!(instance->type == PHY_TYPE_USB2 ||
396 instance->type == PHY_TYPE_USB3)) {
397 dev_err(dev, "unsupported device type: %d\n", instance->type);
398 return ERR_PTR(-EINVAL);
399 }
400
401 return instance->phy;
402}
403
404static struct phy_ops mt65xx_u3phy_ops = {
405 .init = mt65xx_phy_init,
406 .exit = mt65xx_phy_exit,
407 .power_on = mt65xx_phy_power_on,
408 .power_off = mt65xx_phy_power_off,
409 .owner = THIS_MODULE,
410};
411
412static int mt65xx_u3phy_probe(struct platform_device *pdev)
413{
414 struct device *dev = &pdev->dev;
415 struct device_node *np = dev->of_node;
416 struct device_node *child_np;
417 struct phy_provider *provider;
418 struct resource *sif_res;
419 struct mt65xx_u3phy *u3phy;
420 struct resource res;
Julia Lawall2bb80cc2015-11-16 12:33:15 +0100421 int port, retval;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800422
423 u3phy = devm_kzalloc(dev, sizeof(*u3phy), GFP_KERNEL);
424 if (!u3phy)
425 return -ENOMEM;
426
427 u3phy->nphys = of_get_child_count(np);
428 u3phy->phys = devm_kcalloc(dev, u3phy->nphys,
429 sizeof(*u3phy->phys), GFP_KERNEL);
430 if (!u3phy->phys)
431 return -ENOMEM;
432
433 u3phy->dev = dev;
434 platform_set_drvdata(pdev, u3phy);
435
436 sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
437 u3phy->sif_base = devm_ioremap_resource(dev, sif_res);
438 if (IS_ERR(u3phy->sif_base)) {
439 dev_err(dev, "failed to remap sif regs\n");
440 return PTR_ERR(u3phy->sif_base);
441 }
442
443 u3phy->u3phya_ref = devm_clk_get(dev, "u3phya_ref");
444 if (IS_ERR(u3phy->u3phya_ref)) {
445 dev_err(dev, "error to get u3phya_ref\n");
446 return PTR_ERR(u3phy->u3phya_ref);
447 }
448
449 port = 0;
450 for_each_child_of_node(np, child_np) {
451 struct mt65xx_phy_instance *instance;
452 struct phy *phy;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800453
454 instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL);
Julia Lawall2bb80cc2015-11-16 12:33:15 +0100455 if (!instance) {
456 retval = -ENOMEM;
457 goto put_child;
458 }
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800459
460 u3phy->phys[port] = instance;
461
462 phy = devm_phy_create(dev, child_np, &mt65xx_u3phy_ops);
463 if (IS_ERR(phy)) {
464 dev_err(dev, "failed to create phy\n");
Julia Lawall2bb80cc2015-11-16 12:33:15 +0100465 retval = PTR_ERR(phy);
466 goto put_child;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800467 }
468
469 retval = of_address_to_resource(child_np, 0, &res);
470 if (retval) {
471 dev_err(dev, "failed to get address resource(id-%d)\n",
472 port);
Julia Lawall2bb80cc2015-11-16 12:33:15 +0100473 goto put_child;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800474 }
475
476 instance->port_base = devm_ioremap_resource(&phy->dev, &res);
477 if (IS_ERR(instance->port_base)) {
478 dev_err(dev, "failed to remap phy regs\n");
Julia Lawall2bb80cc2015-11-16 12:33:15 +0100479 retval = PTR_ERR(instance->port_base);
480 goto put_child;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800481 }
482
483 instance->phy = phy;
484 instance->index = port;
485 phy_set_drvdata(phy, instance);
486 port++;
487 }
488
489 provider = devm_of_phy_provider_register(dev, mt65xx_phy_xlate);
490
491 return PTR_ERR_OR_ZERO(provider);
Julia Lawall2bb80cc2015-11-16 12:33:15 +0100492put_child:
493 of_node_put(child_np);
494 return retval;
Chunfeng Yundc7f1902015-09-29 11:01:36 +0800495}
496
497static const struct of_device_id mt65xx_u3phy_id_table[] = {
498 { .compatible = "mediatek,mt8173-u3phy", },
499 { },
500};
501MODULE_DEVICE_TABLE(of, mt65xx_u3phy_id_table);
502
503static struct platform_driver mt65xx_u3phy_driver = {
504 .probe = mt65xx_u3phy_probe,
505 .driver = {
506 .name = "mt65xx-u3phy",
507 .of_match_table = mt65xx_u3phy_id_table,
508 },
509};
510
511module_platform_driver(mt65xx_u3phy_driver);
512
513MODULE_AUTHOR("Chunfeng Yun <chunfeng.yun@mediatek.com>");
514MODULE_DESCRIPTION("mt65xx USB PHY driver");
515MODULE_LICENSE("GPL v2");