1e2f919a1SMichal Simek // SPDX-License-Identifier: GPL-2.0 2e2f919a1SMichal Simek /* 3e2f919a1SMichal Simek * Generic DWC3 Glue layer 4e2f919a1SMichal Simek * 5e2f919a1SMichal Simek * Copyright (C) 2016 - 2018 Xilinx, Inc. 6e2f919a1SMichal Simek * 7e2f919a1SMichal Simek * Based on dwc3-omap.c. 8e2f919a1SMichal Simek */ 9e2f919a1SMichal Simek 10e2f919a1SMichal Simek #include <common.h> 11c08fbf46SJean-Jacques Hiblot #include <asm-generic/io.h> 12e2f919a1SMichal Simek #include <dm.h> 13e2f919a1SMichal Simek #include <dm/device-internal.h> 14e2f919a1SMichal Simek #include <dm/lists.h> 15bb4f93a7SJean-Jacques Hiblot #include <dwc3-uboot.h> 16e2f919a1SMichal Simek #include <linux/usb/ch9.h> 17e2f919a1SMichal Simek #include <linux/usb/gadget.h> 18e2f919a1SMichal Simek #include <malloc.h> 19e2f919a1SMichal Simek #include <usb.h> 20e2f919a1SMichal Simek #include "core.h" 21e2f919a1SMichal Simek #include "gadget.h" 22bb4f93a7SJean-Jacques Hiblot #include <reset.h> 23bb4f93a7SJean-Jacques Hiblot #include <clk.h> 24e2f919a1SMichal Simek 25c28d0fe2SJean-Jacques Hiblot struct dwc3_generic_plat { 26c28d0fe2SJean-Jacques Hiblot fdt_addr_t base; 27c28d0fe2SJean-Jacques Hiblot u32 maximum_speed; 28c28d0fe2SJean-Jacques Hiblot enum usb_dr_mode dr_mode; 29c28d0fe2SJean-Jacques Hiblot }; 30c28d0fe2SJean-Jacques Hiblot 31c28d0fe2SJean-Jacques Hiblot struct dwc3_generic_priv { 32*0d25c40aSJean-Jacques Hiblot void *base; 33bb4f93a7SJean-Jacques Hiblot struct dwc3 dwc3; 34bb4f93a7SJean-Jacques Hiblot struct phy *phys; 35bb4f93a7SJean-Jacques Hiblot int num_phys; 36bb4f93a7SJean-Jacques Hiblot }; 37bb4f93a7SJean-Jacques Hiblot 38*0d25c40aSJean-Jacques Hiblot static int dwc3_generic_probe(struct udevice *dev, 39*0d25c40aSJean-Jacques Hiblot struct dwc3_generic_priv *priv) 40e2f919a1SMichal Simek { 41bb4f93a7SJean-Jacques Hiblot int rc; 42c28d0fe2SJean-Jacques Hiblot struct dwc3_generic_plat *plat = dev_get_platdata(dev); 43bb4f93a7SJean-Jacques Hiblot struct dwc3 *dwc3 = &priv->dwc3; 44e2f919a1SMichal Simek 45c28d0fe2SJean-Jacques Hiblot dwc3->maximum_speed = plat->maximum_speed; 46c28d0fe2SJean-Jacques Hiblot dwc3->dr_mode = plat->dr_mode; 47c28d0fe2SJean-Jacques Hiblot 48bb4f93a7SJean-Jacques Hiblot rc = dwc3_setup_phy(dev, &priv->phys, &priv->num_phys); 49bb4f93a7SJean-Jacques Hiblot if (rc) 50bb4f93a7SJean-Jacques Hiblot return rc; 51bb4f93a7SJean-Jacques Hiblot 52*0d25c40aSJean-Jacques Hiblot priv->base = map_physmem(plat->base, DWC3_OTG_REGS_END, MAP_NOCACHE); 53*0d25c40aSJean-Jacques Hiblot dwc3->regs = priv->base + DWC3_GLOBALS_REGS_START; 54bb4f93a7SJean-Jacques Hiblot dwc3->dev = dev; 55bb4f93a7SJean-Jacques Hiblot 56bb4f93a7SJean-Jacques Hiblot rc = dwc3_init(dwc3); 57bb4f93a7SJean-Jacques Hiblot if (rc) { 58*0d25c40aSJean-Jacques Hiblot unmap_physmem(priv->base, MAP_NOCACHE); 59bb4f93a7SJean-Jacques Hiblot return rc; 60bb4f93a7SJean-Jacques Hiblot } 61bb4f93a7SJean-Jacques Hiblot 62bb4f93a7SJean-Jacques Hiblot return 0; 63e2f919a1SMichal Simek } 64e2f919a1SMichal Simek 65*0d25c40aSJean-Jacques Hiblot static int dwc3_generic_remove(struct udevice *dev, 66*0d25c40aSJean-Jacques Hiblot struct dwc3_generic_priv *priv) 67e2f919a1SMichal Simek { 68bb4f93a7SJean-Jacques Hiblot struct dwc3 *dwc3 = &priv->dwc3; 69e2f919a1SMichal Simek 70bb4f93a7SJean-Jacques Hiblot dwc3_remove(dwc3); 71bb4f93a7SJean-Jacques Hiblot dwc3_shutdown_phy(dev, priv->phys, priv->num_phys); 72bb4f93a7SJean-Jacques Hiblot unmap_physmem(dwc3->regs, MAP_NOCACHE); 73e2f919a1SMichal Simek 74e2f919a1SMichal Simek return 0; 75e2f919a1SMichal Simek } 76e2f919a1SMichal Simek 77*0d25c40aSJean-Jacques Hiblot static int dwc3_generic_ofdata_to_platdata(struct udevice *dev) 78e2f919a1SMichal Simek { 79c28d0fe2SJean-Jacques Hiblot struct dwc3_generic_plat *plat = dev_get_platdata(dev); 80e2f919a1SMichal Simek int node = dev_of_offset(dev); 81e2f919a1SMichal Simek 82c28d0fe2SJean-Jacques Hiblot plat->base = devfdt_get_addr(dev); 83e2f919a1SMichal Simek 84c28d0fe2SJean-Jacques Hiblot plat->maximum_speed = usb_get_maximum_speed(node); 85c28d0fe2SJean-Jacques Hiblot if (plat->maximum_speed == USB_SPEED_UNKNOWN) { 86e2f919a1SMichal Simek pr_err("Invalid usb maximum speed\n"); 87e2f919a1SMichal Simek return -ENODEV; 88e2f919a1SMichal Simek } 89e2f919a1SMichal Simek 90c28d0fe2SJean-Jacques Hiblot plat->dr_mode = usb_get_dr_mode(node); 91c28d0fe2SJean-Jacques Hiblot if (plat->dr_mode == USB_DR_MODE_UNKNOWN) { 92e2f919a1SMichal Simek pr_err("Invalid usb mode setup\n"); 93e2f919a1SMichal Simek return -ENODEV; 94e2f919a1SMichal Simek } 95e2f919a1SMichal Simek 96e2f919a1SMichal Simek return 0; 97e2f919a1SMichal Simek } 98e2f919a1SMichal Simek 99*0d25c40aSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_USB_GADGET) 100*0d25c40aSJean-Jacques Hiblot int dm_usb_gadget_handle_interrupts(struct udevice *dev) 101*0d25c40aSJean-Jacques Hiblot { 102*0d25c40aSJean-Jacques Hiblot struct dwc3_generic_priv *priv = dev_get_priv(dev); 103*0d25c40aSJean-Jacques Hiblot struct dwc3 *dwc3 = &priv->dwc3; 104*0d25c40aSJean-Jacques Hiblot 105*0d25c40aSJean-Jacques Hiblot dwc3_gadget_uboot_handle_interrupt(dwc3); 106*0d25c40aSJean-Jacques Hiblot 107*0d25c40aSJean-Jacques Hiblot return 0; 108*0d25c40aSJean-Jacques Hiblot } 109*0d25c40aSJean-Jacques Hiblot 110*0d25c40aSJean-Jacques Hiblot static int dwc3_generic_peripheral_probe(struct udevice *dev) 111*0d25c40aSJean-Jacques Hiblot { 112*0d25c40aSJean-Jacques Hiblot struct dwc3_generic_priv *priv = dev_get_priv(dev); 113*0d25c40aSJean-Jacques Hiblot 114*0d25c40aSJean-Jacques Hiblot return dwc3_generic_probe(dev, priv); 115*0d25c40aSJean-Jacques Hiblot } 116*0d25c40aSJean-Jacques Hiblot 117*0d25c40aSJean-Jacques Hiblot static int dwc3_generic_peripheral_remove(struct udevice *dev) 118*0d25c40aSJean-Jacques Hiblot { 119*0d25c40aSJean-Jacques Hiblot struct dwc3_generic_priv *priv = dev_get_priv(dev); 120*0d25c40aSJean-Jacques Hiblot 121*0d25c40aSJean-Jacques Hiblot return dwc3_generic_remove(dev, priv); 122*0d25c40aSJean-Jacques Hiblot } 123*0d25c40aSJean-Jacques Hiblot 124e2f919a1SMichal Simek U_BOOT_DRIVER(dwc3_generic_peripheral) = { 125e2f919a1SMichal Simek .name = "dwc3-generic-peripheral", 12620828bbaSJean-Jacques Hiblot .id = UCLASS_USB_GADGET_GENERIC, 127*0d25c40aSJean-Jacques Hiblot .ofdata_to_platdata = dwc3_generic_ofdata_to_platdata, 128e2f919a1SMichal Simek .probe = dwc3_generic_peripheral_probe, 129e2f919a1SMichal Simek .remove = dwc3_generic_peripheral_remove, 130c28d0fe2SJean-Jacques Hiblot .priv_auto_alloc_size = sizeof(struct dwc3_generic_priv), 131c28d0fe2SJean-Jacques Hiblot .platdata_auto_alloc_size = sizeof(struct dwc3_generic_plat), 132e2f919a1SMichal Simek }; 133717f5765SJean-Jacques Hiblot #endif 134e2f919a1SMichal Simek 135bb4f93a7SJean-Jacques Hiblot struct dwc3_glue_data { 136bb4f93a7SJean-Jacques Hiblot struct clk_bulk clks; 137bb4f93a7SJean-Jacques Hiblot struct reset_ctl_bulk resets; 138c08fbf46SJean-Jacques Hiblot fdt_addr_t regs; 139c08fbf46SJean-Jacques Hiblot }; 140c08fbf46SJean-Jacques Hiblot 141c08fbf46SJean-Jacques Hiblot struct dwc3_glue_ops { 142c08fbf46SJean-Jacques Hiblot void (*select_dr_mode)(struct udevice *dev, int index, 143c08fbf46SJean-Jacques Hiblot enum usb_dr_mode mode); 144bb4f93a7SJean-Jacques Hiblot }; 145bb4f93a7SJean-Jacques Hiblot 146bb24d586SJean-Jacques Hiblot void dwc3_ti_select_dr_mode(struct udevice *dev, int index, 147bb24d586SJean-Jacques Hiblot enum usb_dr_mode mode) 148bb24d586SJean-Jacques Hiblot { 149bb24d586SJean-Jacques Hiblot #define USBOTGSS_UTMI_OTG_STATUS 0x0084 150bb24d586SJean-Jacques Hiblot #define USBOTGSS_UTMI_OTG_OFFSET 0x0480 151bb24d586SJean-Jacques Hiblot 152bb24d586SJean-Jacques Hiblot /* UTMI_OTG_STATUS REGISTER */ 153bb24d586SJean-Jacques Hiblot #define USBOTGSS_UTMI_OTG_STATUS_SW_MODE BIT(31) 154bb24d586SJean-Jacques Hiblot #define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT BIT(9) 155bb24d586SJean-Jacques Hiblot #define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE BIT(8) 156bb24d586SJean-Jacques Hiblot #define USBOTGSS_UTMI_OTG_STATUS_IDDIG BIT(4) 157bb24d586SJean-Jacques Hiblot #define USBOTGSS_UTMI_OTG_STATUS_SESSEND BIT(3) 158bb24d586SJean-Jacques Hiblot #define USBOTGSS_UTMI_OTG_STATUS_SESSVALID BIT(2) 159bb24d586SJean-Jacques Hiblot #define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID BIT(1) 160bb24d586SJean-Jacques Hiblot enum dwc3_omap_utmi_mode { 161bb24d586SJean-Jacques Hiblot DWC3_OMAP_UTMI_MODE_UNKNOWN = 0, 162bb24d586SJean-Jacques Hiblot DWC3_OMAP_UTMI_MODE_HW, 163bb24d586SJean-Jacques Hiblot DWC3_OMAP_UTMI_MODE_SW, 164bb24d586SJean-Jacques Hiblot }; 165bb24d586SJean-Jacques Hiblot 166bb24d586SJean-Jacques Hiblot u32 use_id_pin; 167bb24d586SJean-Jacques Hiblot u32 host_mode; 168bb24d586SJean-Jacques Hiblot u32 reg; 169bb24d586SJean-Jacques Hiblot u32 utmi_mode; 170bb24d586SJean-Jacques Hiblot u32 utmi_status_offset = USBOTGSS_UTMI_OTG_STATUS; 171bb24d586SJean-Jacques Hiblot 172bb24d586SJean-Jacques Hiblot struct dwc3_glue_data *glue = dev_get_platdata(dev); 173bb24d586SJean-Jacques Hiblot void *base = map_physmem(glue->regs, 0x10000, MAP_NOCACHE); 174bb24d586SJean-Jacques Hiblot 175bb24d586SJean-Jacques Hiblot if (device_is_compatible(dev, "ti,am437x-dwc3")) 176bb24d586SJean-Jacques Hiblot utmi_status_offset += USBOTGSS_UTMI_OTG_OFFSET; 177bb24d586SJean-Jacques Hiblot 178bb24d586SJean-Jacques Hiblot utmi_mode = dev_read_u32_default(dev, "utmi-mode", 179bb24d586SJean-Jacques Hiblot DWC3_OMAP_UTMI_MODE_UNKNOWN); 180bb24d586SJean-Jacques Hiblot if (utmi_mode != DWC3_OMAP_UTMI_MODE_HW) { 181bb24d586SJean-Jacques Hiblot debug("%s: OTG is not supported. defaulting to PERIPHERAL\n", 182bb24d586SJean-Jacques Hiblot dev->name); 183bb24d586SJean-Jacques Hiblot mode = USB_DR_MODE_PERIPHERAL; 184bb24d586SJean-Jacques Hiblot } 185bb24d586SJean-Jacques Hiblot 186bb24d586SJean-Jacques Hiblot switch (mode) { 187bb24d586SJean-Jacques Hiblot case USB_DR_MODE_PERIPHERAL: 188bb24d586SJean-Jacques Hiblot use_id_pin = 0; 189bb24d586SJean-Jacques Hiblot host_mode = 0; 190bb24d586SJean-Jacques Hiblot break; 191bb24d586SJean-Jacques Hiblot case USB_DR_MODE_HOST: 192bb24d586SJean-Jacques Hiblot use_id_pin = 0; 193bb24d586SJean-Jacques Hiblot host_mode = 1; 194bb24d586SJean-Jacques Hiblot break; 195bb24d586SJean-Jacques Hiblot case USB_DR_MODE_OTG: 196bb24d586SJean-Jacques Hiblot default: 197bb24d586SJean-Jacques Hiblot use_id_pin = 1; 198bb24d586SJean-Jacques Hiblot host_mode = 0; 199bb24d586SJean-Jacques Hiblot break; 200bb24d586SJean-Jacques Hiblot } 201bb24d586SJean-Jacques Hiblot 202bb24d586SJean-Jacques Hiblot reg = readl(base + utmi_status_offset); 203bb24d586SJean-Jacques Hiblot 204bb24d586SJean-Jacques Hiblot reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SW_MODE); 205bb24d586SJean-Jacques Hiblot if (!use_id_pin) 206bb24d586SJean-Jacques Hiblot reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE; 207bb24d586SJean-Jacques Hiblot 208bb24d586SJean-Jacques Hiblot writel(reg, base + utmi_status_offset); 209bb24d586SJean-Jacques Hiblot 210bb24d586SJean-Jacques Hiblot reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SESSEND | 211bb24d586SJean-Jacques Hiblot USBOTGSS_UTMI_OTG_STATUS_VBUSVALID | 212bb24d586SJean-Jacques Hiblot USBOTGSS_UTMI_OTG_STATUS_IDDIG); 213bb24d586SJean-Jacques Hiblot 214bb24d586SJean-Jacques Hiblot reg |= USBOTGSS_UTMI_OTG_STATUS_SESSVALID | 215bb24d586SJean-Jacques Hiblot USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT; 216bb24d586SJean-Jacques Hiblot 217bb24d586SJean-Jacques Hiblot if (!host_mode) 218bb24d586SJean-Jacques Hiblot reg |= USBOTGSS_UTMI_OTG_STATUS_IDDIG | 219bb24d586SJean-Jacques Hiblot USBOTGSS_UTMI_OTG_STATUS_VBUSVALID; 220bb24d586SJean-Jacques Hiblot 221bb24d586SJean-Jacques Hiblot writel(reg, base + utmi_status_offset); 222bb24d586SJean-Jacques Hiblot 223bb24d586SJean-Jacques Hiblot unmap_physmem(base, MAP_NOCACHE); 224bb24d586SJean-Jacques Hiblot } 225bb24d586SJean-Jacques Hiblot 226bb24d586SJean-Jacques Hiblot struct dwc3_glue_ops ti_ops = { 227bb24d586SJean-Jacques Hiblot .select_dr_mode = dwc3_ti_select_dr_mode, 228bb24d586SJean-Jacques Hiblot }; 229bb24d586SJean-Jacques Hiblot 230bb4f93a7SJean-Jacques Hiblot static int dwc3_glue_bind(struct udevice *parent) 231e2f919a1SMichal Simek { 232e2f919a1SMichal Simek const void *fdt = gd->fdt_blob; 233e2f919a1SMichal Simek int node; 234e2f919a1SMichal Simek int ret; 235e2f919a1SMichal Simek 236e2f919a1SMichal Simek for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0; 237e2f919a1SMichal Simek node = fdt_next_subnode(fdt, node)) { 238e2f919a1SMichal Simek const char *name = fdt_get_name(fdt, node, NULL); 239e2f919a1SMichal Simek enum usb_dr_mode dr_mode; 240e2f919a1SMichal Simek struct udevice *dev; 241bb4f93a7SJean-Jacques Hiblot const char *driver = NULL; 242e2f919a1SMichal Simek 243e2f919a1SMichal Simek debug("%s: subnode name: %s\n", __func__, name); 244e2f919a1SMichal Simek 245e2f919a1SMichal Simek dr_mode = usb_get_dr_mode(node); 246e2f919a1SMichal Simek 247e2f919a1SMichal Simek switch (dr_mode) { 248e2f919a1SMichal Simek case USB_DR_MODE_PERIPHERAL: 249e2f919a1SMichal Simek case USB_DR_MODE_OTG: 250bb4f93a7SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_USB_GADGET) 251e2f919a1SMichal Simek debug("%s: dr_mode: OTG or Peripheral\n", __func__); 252e2f919a1SMichal Simek driver = "dwc3-generic-peripheral"; 253bb4f93a7SJean-Jacques Hiblot #endif 254e2f919a1SMichal Simek break; 255e2f919a1SMichal Simek case USB_DR_MODE_HOST: 256e2f919a1SMichal Simek debug("%s: dr_mode: HOST\n", __func__); 257bb4f93a7SJean-Jacques Hiblot driver = "xhci-dwc3"; 258e2f919a1SMichal Simek break; 259e2f919a1SMichal Simek default: 260e2f919a1SMichal Simek debug("%s: unsupported dr_mode\n", __func__); 261e2f919a1SMichal Simek return -ENODEV; 262e2f919a1SMichal Simek }; 263e2f919a1SMichal Simek 264bb4f93a7SJean-Jacques Hiblot if (!driver) 265bb4f93a7SJean-Jacques Hiblot continue; 266bb4f93a7SJean-Jacques Hiblot 267e2f919a1SMichal Simek ret = device_bind_driver_to_node(parent, driver, name, 268e2f919a1SMichal Simek offset_to_ofnode(node), &dev); 269e2f919a1SMichal Simek if (ret) { 270e2f919a1SMichal Simek debug("%s: not able to bind usb device mode\n", 271e2f919a1SMichal Simek __func__); 272e2f919a1SMichal Simek return ret; 273e2f919a1SMichal Simek } 274e2f919a1SMichal Simek } 275e2f919a1SMichal Simek 276e2f919a1SMichal Simek return 0; 277e2f919a1SMichal Simek } 278e2f919a1SMichal Simek 279bb4f93a7SJean-Jacques Hiblot static int dwc3_glue_reset_init(struct udevice *dev, 280bb4f93a7SJean-Jacques Hiblot struct dwc3_glue_data *glue) 281bb4f93a7SJean-Jacques Hiblot { 282bb4f93a7SJean-Jacques Hiblot int ret; 283bb4f93a7SJean-Jacques Hiblot 284bb4f93a7SJean-Jacques Hiblot ret = reset_get_bulk(dev, &glue->resets); 285bb4f93a7SJean-Jacques Hiblot if (ret == -ENOTSUPP) 286bb4f93a7SJean-Jacques Hiblot return 0; 287bb4f93a7SJean-Jacques Hiblot else if (ret) 288bb4f93a7SJean-Jacques Hiblot return ret; 289bb4f93a7SJean-Jacques Hiblot 290bb4f93a7SJean-Jacques Hiblot ret = reset_deassert_bulk(&glue->resets); 291bb4f93a7SJean-Jacques Hiblot if (ret) { 292bb4f93a7SJean-Jacques Hiblot reset_release_bulk(&glue->resets); 293bb4f93a7SJean-Jacques Hiblot return ret; 294bb4f93a7SJean-Jacques Hiblot } 295bb4f93a7SJean-Jacques Hiblot 296bb4f93a7SJean-Jacques Hiblot return 0; 297bb4f93a7SJean-Jacques Hiblot } 298bb4f93a7SJean-Jacques Hiblot 299bb4f93a7SJean-Jacques Hiblot static int dwc3_glue_clk_init(struct udevice *dev, 300bb4f93a7SJean-Jacques Hiblot struct dwc3_glue_data *glue) 301bb4f93a7SJean-Jacques Hiblot { 302bb4f93a7SJean-Jacques Hiblot int ret; 303bb4f93a7SJean-Jacques Hiblot 304bb4f93a7SJean-Jacques Hiblot ret = clk_get_bulk(dev, &glue->clks); 305bb4f93a7SJean-Jacques Hiblot if (ret == -ENOSYS) 306bb4f93a7SJean-Jacques Hiblot return 0; 307bb4f93a7SJean-Jacques Hiblot if (ret) 308bb4f93a7SJean-Jacques Hiblot return ret; 309bb4f93a7SJean-Jacques Hiblot 310bb4f93a7SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(CLK) 311bb4f93a7SJean-Jacques Hiblot ret = clk_enable_bulk(&glue->clks); 312bb4f93a7SJean-Jacques Hiblot if (ret) { 313bb4f93a7SJean-Jacques Hiblot clk_release_bulk(&glue->clks); 314bb4f93a7SJean-Jacques Hiblot return ret; 315bb4f93a7SJean-Jacques Hiblot } 316bb4f93a7SJean-Jacques Hiblot #endif 317bb4f93a7SJean-Jacques Hiblot 318bb4f93a7SJean-Jacques Hiblot return 0; 319bb4f93a7SJean-Jacques Hiblot } 320bb4f93a7SJean-Jacques Hiblot 321bb4f93a7SJean-Jacques Hiblot static int dwc3_glue_probe(struct udevice *dev) 322bb4f93a7SJean-Jacques Hiblot { 323c08fbf46SJean-Jacques Hiblot struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev); 324bb4f93a7SJean-Jacques Hiblot struct dwc3_glue_data *glue = dev_get_platdata(dev); 325c08fbf46SJean-Jacques Hiblot struct udevice *child = NULL; 326c08fbf46SJean-Jacques Hiblot int index = 0; 327bb4f93a7SJean-Jacques Hiblot int ret; 328bb4f93a7SJean-Jacques Hiblot 329c08fbf46SJean-Jacques Hiblot glue->regs = dev_read_addr(dev); 330c08fbf46SJean-Jacques Hiblot 331bb4f93a7SJean-Jacques Hiblot ret = dwc3_glue_clk_init(dev, glue); 332bb4f93a7SJean-Jacques Hiblot if (ret) 333bb4f93a7SJean-Jacques Hiblot return ret; 334bb4f93a7SJean-Jacques Hiblot 335bb4f93a7SJean-Jacques Hiblot ret = dwc3_glue_reset_init(dev, glue); 336bb4f93a7SJean-Jacques Hiblot if (ret) 337bb4f93a7SJean-Jacques Hiblot return ret; 338bb4f93a7SJean-Jacques Hiblot 339c08fbf46SJean-Jacques Hiblot ret = device_find_first_child(dev, &child); 340c08fbf46SJean-Jacques Hiblot if (ret) 341c08fbf46SJean-Jacques Hiblot return ret; 342c08fbf46SJean-Jacques Hiblot 343c08fbf46SJean-Jacques Hiblot while (child) { 344c08fbf46SJean-Jacques Hiblot enum usb_dr_mode dr_mode; 345c08fbf46SJean-Jacques Hiblot 346c08fbf46SJean-Jacques Hiblot dr_mode = usb_get_dr_mode(dev_of_offset(child)); 347c08fbf46SJean-Jacques Hiblot device_find_next_child(&child); 348c08fbf46SJean-Jacques Hiblot if (ops && ops->select_dr_mode) 349c08fbf46SJean-Jacques Hiblot ops->select_dr_mode(dev, index, dr_mode); 350c08fbf46SJean-Jacques Hiblot index++; 351c08fbf46SJean-Jacques Hiblot } 352c08fbf46SJean-Jacques Hiblot 353bb4f93a7SJean-Jacques Hiblot return 0; 354bb4f93a7SJean-Jacques Hiblot } 355bb4f93a7SJean-Jacques Hiblot 356bb4f93a7SJean-Jacques Hiblot static int dwc3_glue_remove(struct udevice *dev) 357bb4f93a7SJean-Jacques Hiblot { 358bb4f93a7SJean-Jacques Hiblot struct dwc3_glue_data *glue = dev_get_platdata(dev); 359bb4f93a7SJean-Jacques Hiblot 360bb4f93a7SJean-Jacques Hiblot reset_release_bulk(&glue->resets); 361bb4f93a7SJean-Jacques Hiblot 362bb4f93a7SJean-Jacques Hiblot clk_release_bulk(&glue->clks); 363bb4f93a7SJean-Jacques Hiblot 3648fff75baSJean-Jacques Hiblot return 0; 365bb4f93a7SJean-Jacques Hiblot } 366bb4f93a7SJean-Jacques Hiblot 367bb4f93a7SJean-Jacques Hiblot static const struct udevice_id dwc3_glue_ids[] = { 368e2f919a1SMichal Simek { .compatible = "xlnx,zynqmp-dwc3" }, 3694323bebbSJean-Jacques Hiblot { .compatible = "ti,keystone-dwc3"}, 370bb24d586SJean-Jacques Hiblot { .compatible = "ti,dwc3", .data = (ulong)&ti_ops }, 371f7334c81SJean-Jacques Hiblot { .compatible = "ti,am437x-dwc3", .data = (ulong)&ti_ops }, 372e2f919a1SMichal Simek { } 373e2f919a1SMichal Simek }; 374e2f919a1SMichal Simek 375e2f919a1SMichal Simek U_BOOT_DRIVER(dwc3_generic_wrapper) = { 376e2f919a1SMichal Simek .name = "dwc3-generic-wrapper", 377f44c88f1SJean-Jacques Hiblot .id = UCLASS_NOP, 378bb4f93a7SJean-Jacques Hiblot .of_match = dwc3_glue_ids, 379bb4f93a7SJean-Jacques Hiblot .bind = dwc3_glue_bind, 380bb4f93a7SJean-Jacques Hiblot .probe = dwc3_glue_probe, 381bb4f93a7SJean-Jacques Hiblot .remove = dwc3_glue_remove, 382bb4f93a7SJean-Jacques Hiblot .platdata_auto_alloc_size = sizeof(struct dwc3_glue_data), 383bb4f93a7SJean-Jacques Hiblot 384e2f919a1SMichal Simek }; 385