sunxi: phy: Add USB PHY support for Allwinner H6
[oweals/u-boot.git] / drivers / phy / allwinner / phy-sun4i-usb.c
1 /*
2  * Allwinner sun4i USB PHY driver
3  *
4  * Copyright (C) 2017 Jagan Teki <jagan@amarulasolutions.com>
5  * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
6  * Copyright (C) 2014 Roman Byshko <rbyshko@gmail.com>
7  *
8  * Modelled arch/arm/mach-sunxi/usb_phy.c to compatible with generic-phy.
9  *
10  * SPDX-License-Identifier:     GPL-2.0+
11  */
12
13 #include <common.h>
14 #include <clk.h>
15 #include <dm.h>
16 #include <dm/device.h>
17 #include <generic-phy.h>
18 #include <phy-sun4i-usb.h>
19 #include <reset.h>
20 #include <asm/gpio.h>
21 #include <asm/io.h>
22 #include <asm/arch/clock.h>
23 #include <asm/arch/cpu.h>
24
25 #define REG_ISCR                        0x00
26 #define REG_PHYCTL_A10                  0x04
27 #define REG_PHYBIST                     0x08
28 #define REG_PHYTUNE                     0x0c
29 #define REG_PHYCTL_A33                  0x10
30 #define REG_PHY_OTGCTL                  0x20
31 #define REG_PMU_UNK1                    0x10
32
33 /* Common Control Bits for Both PHYs */
34 #define PHY_PLL_BW                      0x03
35 #define PHY_RES45_CAL_EN                0x0c
36
37 /* Private Control Bits for Each PHY */
38 #define PHY_TX_AMPLITUDE_TUNE           0x20
39 #define PHY_TX_SLEWRATE_TUNE            0x22
40 #define PHY_DISCON_TH_SEL               0x2a
41 #define PHY_SQUELCH_DETECT              0x3c
42
43 #define PHYCTL_DATA                     BIT(7)
44 #define OTGCTL_ROUTE_MUSB               BIT(0)
45
46 #define PHY_TX_RATE                     BIT(4)
47 #define PHY_TX_MAGNITUDE                BIT(2)
48 #define PHY_TX_AMPLITUDE_LEN            5
49
50 #define PHY_RES45_CAL_DATA              BIT(0)
51 #define PHY_RES45_CAL_LEN               1
52 #define PHY_DISCON_TH_LEN               2
53
54 #define SUNXI_AHB_ICHR8_EN              BIT(10)
55 #define SUNXI_AHB_INCR4_BURST_EN        BIT(9)
56 #define SUNXI_AHB_INCRX_ALIGN_EN        BIT(8)
57 #define SUNXI_ULPI_BYPASS_EN            BIT(0)
58
59 /* A83T specific control bits for PHY0 */
60 #define PHY_CTL_VBUSVLDEXT              BIT(5)
61 #define PHY_CTL_SIDDQ                   BIT(3)
62
63 /* A83T specific control bits for PHY2 HSIC */
64 #define SUNXI_EHCI_HS_FORCE             BIT(20)
65 #define SUNXI_HSIC_CONNECT_INT          BIT(16)
66 #define SUNXI_HSIC                      BIT(1)
67
68 #define MAX_PHYS                        4
69
70 enum sun4i_usb_phy_type {
71         sun4i_a10_phy,
72         sun6i_a31_phy,
73         sun8i_a33_phy,
74         sun8i_a83t_phy,
75         sun8i_h3_phy,
76         sun8i_v3s_phy,
77         sun50i_a64_phy,
78         sun50i_h6_phy,
79 };
80
81 struct sun4i_usb_phy_cfg {
82         int num_phys;
83         enum sun4i_usb_phy_type type;
84         u32 disc_thresh;
85         u8 phyctl_offset;
86         bool dedicated_clocks;
87         bool enable_pmu_unk1;
88         bool phy0_dual_route;
89         int missing_phys;
90 };
91
92 struct sun4i_usb_phy_info {
93         const char *gpio_vbus;
94         const char *gpio_vbus_det;
95         const char *gpio_id_det;
96 } phy_info[] = {
97         {
98                 .gpio_vbus = CONFIG_USB0_VBUS_PIN,
99                 .gpio_vbus_det = CONFIG_USB0_VBUS_DET,
100                 .gpio_id_det = CONFIG_USB0_ID_DET,
101         },
102         {
103                 .gpio_vbus = CONFIG_USB1_VBUS_PIN,
104                 .gpio_vbus_det = NULL,
105                 .gpio_id_det = NULL,
106         },
107         {
108                 .gpio_vbus = CONFIG_USB2_VBUS_PIN,
109                 .gpio_vbus_det = NULL,
110                 .gpio_id_det = NULL,
111         },
112         {
113                 .gpio_vbus = CONFIG_USB3_VBUS_PIN,
114                 .gpio_vbus_det = NULL,
115                 .gpio_id_det = NULL,
116         },
117 };
118
119 struct sun4i_usb_phy_plat {
120         void __iomem *pmu;
121         int power_on_count;
122         int gpio_vbus;
123         int gpio_vbus_det;
124         int gpio_id_det;
125         struct clk clocks;
126         struct reset_ctl resets;
127         int id;
128 };
129
130 struct sun4i_usb_phy_data {
131         void __iomem *base;
132         const struct sun4i_usb_phy_cfg *cfg;
133         struct sun4i_usb_phy_plat *usb_phy;
134 };
135
136 static int initial_usb_scan_delay = CONFIG_INITIAL_USB_SCAN_DELAY;
137
138 static void sun4i_usb_phy_write(struct phy *phy, u32 addr, u32 data, int len)
139 {
140         struct sun4i_usb_phy_data *phy_data = dev_get_priv(phy->dev);
141         struct sun4i_usb_phy_plat *usb_phy = &phy_data->usb_phy[phy->id];
142         u32 temp, usbc_bit = BIT(usb_phy->id * 2);
143         void __iomem *phyctl = phy_data->base + phy_data->cfg->phyctl_offset;
144         int i;
145
146         if (phy_data->cfg->phyctl_offset == REG_PHYCTL_A33) {
147                 /* SoCs newer than A33 need us to set phyctl to 0 explicitly */
148                 writel(0, phyctl);
149         }
150
151         for (i = 0; i < len; i++) {
152                 temp = readl(phyctl);
153
154                 /* clear the address portion */
155                 temp &= ~(0xff << 8);
156
157                 /* set the address */
158                 temp |= ((addr + i) << 8);
159                 writel(temp, phyctl);
160
161                 /* set the data bit and clear usbc bit*/
162                 temp = readb(phyctl);
163                 if (data & 0x1)
164                         temp |= PHYCTL_DATA;
165                 else
166                         temp &= ~PHYCTL_DATA;
167                 temp &= ~usbc_bit;
168                 writeb(temp, phyctl);
169
170                 /* pulse usbc_bit */
171                 temp = readb(phyctl);
172                 temp |= usbc_bit;
173                 writeb(temp, phyctl);
174
175                 temp = readb(phyctl);
176                 temp &= ~usbc_bit;
177                 writeb(temp, phyctl);
178
179                 data >>= 1;
180         }
181 }
182
183 static void sun4i_usb_phy_passby(struct phy *phy, bool enable)
184 {
185         struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
186         struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
187         u32 bits, reg_value;
188
189         if (!usb_phy->pmu)
190                 return;
191
192         bits = SUNXI_AHB_ICHR8_EN | SUNXI_AHB_INCR4_BURST_EN |
193                 SUNXI_AHB_INCRX_ALIGN_EN | SUNXI_ULPI_BYPASS_EN;
194
195         /* A83T USB2 is HSIC */
196         if (data->cfg->type == sun8i_a83t_phy && usb_phy->id == 2)
197                 bits |= SUNXI_EHCI_HS_FORCE | SUNXI_HSIC_CONNECT_INT |
198                         SUNXI_HSIC;
199
200         reg_value = readl(usb_phy->pmu);
201
202         if (enable)
203                 reg_value |= bits;
204         else
205                 reg_value &= ~bits;
206
207         writel(reg_value, usb_phy->pmu);
208 }
209
210 static int sun4i_usb_phy_power_on(struct phy *phy)
211 {
212         struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
213         struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
214
215         if (initial_usb_scan_delay) {
216                 mdelay(initial_usb_scan_delay);
217                 initial_usb_scan_delay = 0;
218         }
219
220         usb_phy->power_on_count++;
221         if (usb_phy->power_on_count != 1)
222                 return 0;
223
224         if (usb_phy->gpio_vbus >= 0)
225                 gpio_set_value(usb_phy->gpio_vbus, SUNXI_GPIO_PULL_UP);
226
227         return 0;
228 }
229
230 static int sun4i_usb_phy_power_off(struct phy *phy)
231 {
232         struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
233         struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
234
235         usb_phy->power_on_count--;
236         if (usb_phy->power_on_count != 0)
237                 return 0;
238
239         if (usb_phy->gpio_vbus >= 0)
240                 gpio_set_value(usb_phy->gpio_vbus, SUNXI_GPIO_PULL_DISABLE);
241
242         return 0;
243 }
244
245 static void sun4i_usb_phy0_reroute(struct sun4i_usb_phy_data *data, bool id_det)
246 {
247         u32 regval;
248
249         regval = readl(data->base + REG_PHY_OTGCTL);
250         if (!id_det) {
251                 /* Host mode. Route phy0 to EHCI/OHCI */
252                 regval &= ~OTGCTL_ROUTE_MUSB;
253         } else {
254                 /* Peripheral mode. Route phy0 to MUSB */
255                 regval |= OTGCTL_ROUTE_MUSB;
256         }
257         writel(regval, data->base + REG_PHY_OTGCTL);
258 }
259
260 static int sun4i_usb_phy_init(struct phy *phy)
261 {
262         struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
263         struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
264         u32 val;
265         int ret;
266
267         ret = clk_enable(&usb_phy->clocks);
268         if (ret) {
269                 dev_err(dev, "failed to enable usb_%ldphy clock\n", phy->id);
270                 return ret;
271         }
272
273         ret = reset_deassert(&usb_phy->resets);
274         if (ret) {
275                 dev_err(dev, "failed to deassert usb_%ldreset reset\n", phy->id);
276                 return ret;
277         }
278
279         if (data->cfg->type == sun8i_a83t_phy) {
280                 if (phy->id == 0) {
281                         val = readl(data->base + data->cfg->phyctl_offset);
282                         val |= PHY_CTL_VBUSVLDEXT;
283                         val &= ~PHY_CTL_SIDDQ;
284                         writel(val, data->base + data->cfg->phyctl_offset);
285                 }
286         } else {
287                 if (usb_phy->pmu && data->cfg->enable_pmu_unk1) {
288                         val = readl(usb_phy->pmu + REG_PMU_UNK1);
289                         writel(val & ~2, usb_phy->pmu + REG_PMU_UNK1);
290                 }
291
292                 if (usb_phy->id == 0)
293                         sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN,
294                                             PHY_RES45_CAL_DATA,
295                                             PHY_RES45_CAL_LEN);
296
297                 /* Adjust PHY's magnitude and rate */
298                 sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE,
299                                     PHY_TX_MAGNITUDE | PHY_TX_RATE,
300                                     PHY_TX_AMPLITUDE_LEN);
301
302                 /* Disconnect threshold adjustment */
303                 sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL,
304                                     data->cfg->disc_thresh, PHY_DISCON_TH_LEN);
305         }
306
307         sun4i_usb_phy_passby(phy, true);
308
309         sun4i_usb_phy0_reroute(data, true);
310
311         return 0;
312 }
313
314 static int sun4i_usb_phy_exit(struct phy *phy)
315 {
316         struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
317         struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
318         int ret;
319
320         if (phy->id == 0) {
321                 if (data->cfg->type == sun8i_a83t_phy) {
322                         void __iomem *phyctl = data->base +
323                                 data->cfg->phyctl_offset;
324
325                         writel(readl(phyctl) | PHY_CTL_SIDDQ, phyctl);
326                 }
327         }
328
329         sun4i_usb_phy_passby(phy, false);
330
331         ret = clk_disable(&usb_phy->clocks);
332         if (ret) {
333                 dev_err(dev, "failed to disable usb_%ldphy clock\n", phy->id);
334                 return ret;
335         }
336
337         ret = reset_assert(&usb_phy->resets);
338         if (ret) {
339                 dev_err(dev, "failed to assert usb_%ldreset reset\n", phy->id);
340                 return ret;
341         }
342
343         return 0;
344 }
345
346 static int sun4i_usb_phy_xlate(struct phy *phy,
347                                struct ofnode_phandle_args *args)
348 {
349         struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
350
351         if (args->args_count >= data->cfg->num_phys)
352                 return -EINVAL;
353
354         if (data->cfg->missing_phys & BIT(args->args[0]))
355                 return -ENODEV;
356
357         if (args->args_count)
358                 phy->id = args->args[0];
359         else
360                 phy->id = 0;
361
362         debug("%s: phy_id = %ld\n", __func__, phy->id);
363         return 0;
364 }
365
366 int sun4i_usb_phy_vbus_detect(struct phy *phy)
367 {
368         struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
369         struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
370         int err, retries = 3;
371
372         debug("%s: id_det = %d\n", __func__, usb_phy->gpio_id_det);
373
374         if (usb_phy->gpio_vbus_det < 0)
375                 return usb_phy->gpio_vbus_det;
376
377         err = gpio_get_value(usb_phy->gpio_vbus_det);
378         /*
379          * Vbus may have been provided by the board and just been turned of
380          * some milliseconds ago on reset, what we're measuring then is a
381          * residual charge on Vbus, sleep a bit and try again.
382          */
383         while (err > 0 && retries--) {
384                 mdelay(100);
385                 err = gpio_get_value(usb_phy->gpio_vbus_det);
386         }
387
388         return err;
389 }
390
391 int sun4i_usb_phy_id_detect(struct phy *phy)
392 {
393         struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
394         struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
395
396         debug("%s: id_det = %d\n", __func__, usb_phy->gpio_id_det);
397
398         if (usb_phy->gpio_id_det < 0)
399                 return usb_phy->gpio_id_det;
400
401         return gpio_get_value(usb_phy->gpio_id_det);
402 }
403
404 void sun4i_usb_phy_set_squelch_detect(struct phy *phy, bool enabled)
405 {
406         sun4i_usb_phy_write(phy, PHY_SQUELCH_DETECT, enabled ? 0 : 2, 2);
407 }
408
409 static struct phy_ops sun4i_usb_phy_ops = {
410         .of_xlate = sun4i_usb_phy_xlate,
411         .init = sun4i_usb_phy_init,
412         .power_on = sun4i_usb_phy_power_on,
413         .power_off = sun4i_usb_phy_power_off,
414         .exit = sun4i_usb_phy_exit,
415 };
416
417 static int sun4i_usb_phy_probe(struct udevice *dev)
418 {
419         struct sun4i_usb_phy_plat *plat = dev_get_platdata(dev);
420         struct sun4i_usb_phy_data *data = dev_get_priv(dev);
421         int i, ret;
422
423         data->cfg = (const struct sun4i_usb_phy_cfg *)dev_get_driver_data(dev);
424         if (!data->cfg)
425                 return -EINVAL;
426
427         data->base = (void __iomem *)devfdt_get_addr_name(dev, "phy_ctrl");
428         if (IS_ERR(data->base))
429                 return PTR_ERR(data->base);
430
431         data->usb_phy = plat;
432         for (i = 0; i < data->cfg->num_phys; i++) {
433                 struct sun4i_usb_phy_plat *phy = &plat[i];
434                 struct sun4i_usb_phy_info *info = &phy_info[i];
435                 char name[16];
436
437                 if (data->cfg->missing_phys & BIT(i))
438                         continue;
439
440                 phy->gpio_vbus = sunxi_name_to_gpio(info->gpio_vbus);
441                 if (phy->gpio_vbus >= 0) {
442                         ret = gpio_request(phy->gpio_vbus, "usb_vbus");
443                         if (ret)
444                                 return ret;
445                         ret = gpio_direction_output(phy->gpio_vbus, 0);
446                         if (ret)
447                                 return ret;
448                 }
449
450                 phy->gpio_vbus_det = sunxi_name_to_gpio(info->gpio_vbus_det);
451                 if (phy->gpio_vbus_det >= 0) {
452                         ret = gpio_request(phy->gpio_vbus_det, "usb_vbus_det");
453                         if (ret)
454                                 return ret;
455                         ret = gpio_direction_input(phy->gpio_vbus_det);
456                         if (ret)
457                                 return ret;
458                 }
459
460                 phy->gpio_id_det = sunxi_name_to_gpio(info->gpio_id_det);
461                 if (phy->gpio_id_det >= 0) {
462                         ret = gpio_request(phy->gpio_id_det, "usb_id_det");
463                         if (ret)
464                                 return ret;
465                         ret = gpio_direction_input(phy->gpio_id_det);
466                         if (ret)
467                                 return ret;
468                         sunxi_gpio_set_pull(phy->gpio_id_det, SUNXI_GPIO_PULL_UP);
469                 }
470
471                 if (data->cfg->dedicated_clocks)
472                         snprintf(name, sizeof(name), "usb%d_phy", i);
473                 else
474                         strlcpy(name, "usb_phy", sizeof(name));
475
476                 ret = clk_get_by_name(dev, name, &phy->clocks);
477                 if (ret) {
478                         dev_err(dev, "failed to get usb%d_phy clock phandle\n", i);
479                         return ret;
480                 }
481
482                 snprintf(name, sizeof(name), "usb%d_reset", i);
483                 ret = reset_get_by_name(dev, name, &phy->resets);
484                 if (ret) {
485                         dev_err(dev, "failed to get usb%d_reset reset phandle\n", i);
486                         return ret;
487                 }
488
489                 if (i || data->cfg->phy0_dual_route) {
490                         snprintf(name, sizeof(name), "pmu%d", i);
491                         phy->pmu = (void __iomem *)devfdt_get_addr_name(dev, name);
492                         if (IS_ERR(phy->pmu))
493                                 return PTR_ERR(phy->pmu);
494                 }
495
496                 phy->id = i;
497         };
498
499         debug("Allwinner Sun4I USB PHY driver loaded\n");
500         return 0;
501 }
502
503 static const struct sun4i_usb_phy_cfg sun4i_a10_cfg = {
504         .num_phys = 3,
505         .type = sun4i_a10_phy,
506         .disc_thresh = 3,
507         .phyctl_offset = REG_PHYCTL_A10,
508         .dedicated_clocks = false,
509         .enable_pmu_unk1 = false,
510 };
511
512 static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
513         .num_phys = 2,
514         .type = sun4i_a10_phy,
515         .disc_thresh = 2,
516         .phyctl_offset = REG_PHYCTL_A10,
517         .dedicated_clocks = false,
518         .enable_pmu_unk1 = false,
519 };
520
521 static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = {
522         .num_phys = 3,
523         .type = sun6i_a31_phy,
524         .disc_thresh = 3,
525         .phyctl_offset = REG_PHYCTL_A10,
526         .dedicated_clocks = true,
527         .enable_pmu_unk1 = false,
528 };
529
530 static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = {
531         .num_phys = 3,
532         .type = sun4i_a10_phy,
533         .disc_thresh = 2,
534         .phyctl_offset = REG_PHYCTL_A10,
535         .dedicated_clocks = false,
536         .enable_pmu_unk1 = false,
537 };
538
539 static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = {
540         .num_phys = 2,
541         .type = sun4i_a10_phy,
542         .disc_thresh = 3,
543         .phyctl_offset = REG_PHYCTL_A10,
544         .dedicated_clocks = true,
545         .enable_pmu_unk1 = false,
546 };
547
548 static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = {
549         .num_phys = 2,
550         .type = sun8i_a33_phy,
551         .disc_thresh = 3,
552         .phyctl_offset = REG_PHYCTL_A33,
553         .dedicated_clocks = true,
554         .enable_pmu_unk1 = false,
555 };
556
557 static const struct sun4i_usb_phy_cfg sun8i_a83t_cfg = {
558         .num_phys = 3,
559         .type = sun8i_a83t_phy,
560         .phyctl_offset = REG_PHYCTL_A33,
561         .dedicated_clocks = true,
562 };
563
564 static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
565         .num_phys = 4,
566         .type = sun8i_h3_phy,
567         .disc_thresh = 3,
568         .phyctl_offset = REG_PHYCTL_A33,
569         .dedicated_clocks = true,
570         .enable_pmu_unk1 = true,
571         .phy0_dual_route = true,
572 };
573
574 static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
575         .num_phys = 1,
576         .type = sun8i_v3s_phy,
577         .disc_thresh = 3,
578         .phyctl_offset = REG_PHYCTL_A33,
579         .dedicated_clocks = true,
580         .enable_pmu_unk1 = true,
581         .phy0_dual_route = true,
582 };
583
584 static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
585         .num_phys = 2,
586         .type = sun50i_a64_phy,
587         .disc_thresh = 3,
588         .phyctl_offset = REG_PHYCTL_A33,
589         .dedicated_clocks = true,
590         .enable_pmu_unk1 = true,
591         .phy0_dual_route = true,
592 };
593
594 static const struct sun4i_usb_phy_cfg sun50i_h6_cfg = {
595         .num_phys = 4,
596         .type = sun50i_h6_phy,
597         .disc_thresh = 3,
598         .phyctl_offset = REG_PHYCTL_A33,
599         .dedicated_clocks = true,
600         .enable_pmu_unk1 = true,
601         .phy0_dual_route = true,
602         .missing_phys = BIT(1) | BIT(2),
603 };
604
605 static const struct udevice_id sun4i_usb_phy_ids[] = {
606         { .compatible = "allwinner,sun4i-a10-usb-phy", .data = (ulong)&sun4i_a10_cfg },
607         { .compatible = "allwinner,sun5i-a13-usb-phy", .data = (ulong)&sun5i_a13_cfg },
608         { .compatible = "allwinner,sun6i-a31-usb-phy", .data = (ulong)&sun6i_a31_cfg },
609         { .compatible = "allwinner,sun7i-a20-usb-phy", .data = (ulong)&sun7i_a20_cfg },
610         { .compatible = "allwinner,sun8i-a23-usb-phy", .data = (ulong)&sun8i_a23_cfg },
611         { .compatible = "allwinner,sun8i-a33-usb-phy", .data = (ulong)&sun8i_a33_cfg },
612         { .compatible = "allwinner,sun8i-a83t-usb-phy", .data = (ulong)&sun8i_a83t_cfg },
613         { .compatible = "allwinner,sun8i-h3-usb-phy", .data = (ulong)&sun8i_h3_cfg },
614         { .compatible = "allwinner,sun8i-v3s-usb-phy", .data = (ulong)&sun8i_v3s_cfg },
615         { .compatible = "allwinner,sun50i-a64-usb-phy", .data = (ulong)&sun50i_a64_cfg},
616         { .compatible = "allwinner,sun50i-h6-usb-phy", .data = (ulong)&sun50i_h6_cfg},
617         { }
618 };
619
620 U_BOOT_DRIVER(sun4i_usb_phy) = {
621         .name   = "sun4i_usb_phy",
622         .id     = UCLASS_PHY,
623         .of_match = sun4i_usb_phy_ids,
624         .ops = &sun4i_usb_phy_ops,
625         .probe = sun4i_usb_phy_probe,
626         .platdata_auto_alloc_size = sizeof(struct sun4i_usb_phy_plat[MAX_PHYS]),
627         .priv_auto_alloc_size = sizeof(struct sun4i_usb_phy_data),
628 };