commit
56932e84ea
@ -0,0 +1,73 @@ |
||||
STMicroelectronics STM32 USB HS PHY controller |
||||
|
||||
The STM32 USBPHYC block contains a dual port High Speed UTMI+ PHY and a UTMI |
||||
switch. It controls PHY configuration and status, and the UTMI+ switch that |
||||
selects either OTG or HOST controller for the second PHY port. It also sets |
||||
PLL configuration. |
||||
|
||||
USBPHYC |
||||
|_ PLL |
||||
| |
||||
|_ PHY port#1 _________________ HOST controller |
||||
| _ | |
||||
| / 1|________________| |
||||
|_ PHY port#2 ----| |________________ |
||||
| \_0| | |
||||
|_ UTMI switch_______| OTG controller |
||||
|
||||
|
||||
Phy provider node |
||||
================= |
||||
|
||||
Required properties: |
||||
- compatible: must be "st,stm32mp1-usbphyc" |
||||
- reg: address and length of the usb phy control register set |
||||
- clocks: phandle + clock specifier for the PLL phy clock |
||||
- #address-cells: number of address cells for phys sub-nodes, must be <1> |
||||
- #size-cells: number of size cells for phys sub-nodes, must be <0> |
||||
|
||||
Optional properties: |
||||
- assigned-clocks: phandle + clock specifier for the PLL phy clock |
||||
- assigned-clock-parents: the PLL phy clock parent |
||||
- resets: phandle + reset specifier |
||||
|
||||
Required nodes: one sub-node per port the controller provides. |
||||
|
||||
Phy sub-nodes |
||||
============== |
||||
|
||||
Required properties: |
||||
- reg: phy port index |
||||
- phy-supply: phandle to the regulator providing 3V3 power to the PHY, |
||||
see phy-bindings.txt in the same directory. |
||||
- vdda1v1-supply: phandle to the regulator providing 1V1 power to the PHY |
||||
- vdda1v8-supply: phandle to the regulator providing 1V8 power to the PHY |
||||
- #phy-cells: see phy-bindings.txt in the same directory, must be <0> for PHY |
||||
port#1 and must be <1> for PHY port#2, to select USB controller |
||||
|
||||
|
||||
Example: |
||||
usbphyc: usb-phy@5a006000 { |
||||
compatible = "st,stm32mp1-usbphyc"; |
||||
reg = <0x5a006000 0x1000>; |
||||
clocks = <&rcc_clk USBPHY_K>; |
||||
resets = <&rcc_rst USBPHY_R>; |
||||
#address-cells = <1>; |
||||
#size-cells = <0>; |
||||
|
||||
usbphyc_port0: usb-phy@0 { |
||||
reg = <0>; |
||||
phy-supply = <&vdd_usb>; |
||||
vdda1v1-supply = <®11>; |
||||
vdda1v8-supply = <®18> |
||||
#phy-cells = <0>; |
||||
}; |
||||
|
||||
usbphyc_port1: usb-phy@1 { |
||||
reg = <1>; |
||||
phy-supply = <&vdd_usb>; |
||||
vdda1v1-supply = <®11>; |
||||
vdda1v8-supply = <®18> |
||||
#phy-cells = <1>; |
||||
}; |
||||
}; |
@ -0,0 +1,402 @@ |
||||
// SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <clk.h> |
||||
#include <div64.h> |
||||
#include <dm.h> |
||||
#include <fdtdec.h> |
||||
#include <generic-phy.h> |
||||
#include <reset.h> |
||||
#include <syscon.h> |
||||
#include <usb.h> |
||||
#include <asm/io.h> |
||||
#include <linux/bitops.h> |
||||
#include <power/regulator.h> |
||||
|
||||
/* USBPHYC registers */ |
||||
#define STM32_USBPHYC_PLL 0x0 |
||||
#define STM32_USBPHYC_MISC 0x8 |
||||
|
||||
/* STM32_USBPHYC_PLL bit fields */ |
||||
#define PLLNDIV GENMASK(6, 0) |
||||
#define PLLNDIV_SHIFT 0 |
||||
#define PLLFRACIN GENMASK(25, 10) |
||||
#define PLLFRACIN_SHIFT 10 |
||||
#define PLLEN BIT(26) |
||||
#define PLLSTRB BIT(27) |
||||
#define PLLSTRBYP BIT(28) |
||||
#define PLLFRACCTL BIT(29) |
||||
#define PLLDITHEN0 BIT(30) |
||||
#define PLLDITHEN1 BIT(31) |
||||
|
||||
/* STM32_USBPHYC_MISC bit fields */ |
||||
#define SWITHOST BIT(0) |
||||
|
||||
#define MAX_PHYS 2 |
||||
|
||||
#define PLL_LOCK_TIME_US 100 |
||||
#define PLL_PWR_DOWN_TIME_US 5 |
||||
#define PLL_FVCO 2880 /* in MHz */ |
||||
#define PLL_INFF_MIN_RATE 19200000 /* in Hz */ |
||||
#define PLL_INFF_MAX_RATE 38400000 /* in Hz */ |
||||
|
||||
struct pll_params { |
||||
u8 ndiv; |
||||
u16 frac; |
||||
}; |
||||
|
||||
struct stm32_usbphyc { |
||||
fdt_addr_t base; |
||||
struct clk clk; |
||||
struct stm32_usbphyc_phy { |
||||
struct udevice *vdd; |
||||
struct udevice *vdda1v1; |
||||
struct udevice *vdda1v8; |
||||
int index; |
||||
bool init; |
||||
bool powered; |
||||
} phys[MAX_PHYS]; |
||||
}; |
||||
|
||||
void stm32_usbphyc_get_pll_params(u32 clk_rate, struct pll_params *pll_params) |
||||
{ |
||||
unsigned long long fvco, ndiv, frac; |
||||
|
||||
/*
|
||||
* | FVCO = INFF*2*(NDIV + FRACT/2^16 ) when DITHER_DISABLE[1] = 1 |
||||
* | FVCO = 2880MHz |
||||
* | NDIV = integer part of input bits to set the LDF |
||||
* | FRACT = fractional part of input bits to set the LDF |
||||
* => PLLNDIV = integer part of (FVCO / (INFF*2)) |
||||
* => PLLFRACIN = fractional part of(FVCO / INFF*2) * 2^16 |
||||
* <=> PLLFRACIN = ((FVCO / (INFF*2)) - PLLNDIV) * 2^16 |
||||
*/ |
||||
fvco = (unsigned long long)PLL_FVCO * 1000000; /* In Hz */ |
||||
|
||||
ndiv = fvco; |
||||
do_div(ndiv, (clk_rate * 2)); |
||||
pll_params->ndiv = (u8)ndiv; |
||||
|
||||
frac = fvco * (1 << 16); |
||||
do_div(frac, (clk_rate * 2)); |
||||
frac = frac - (ndiv * (1 << 16)); |
||||
pll_params->frac = (u16)frac; |
||||
} |
||||
|
||||
static int stm32_usbphyc_pll_init(struct stm32_usbphyc *usbphyc) |
||||
{ |
||||
struct pll_params pll_params; |
||||
u32 clk_rate = clk_get_rate(&usbphyc->clk); |
||||
u32 usbphyc_pll; |
||||
|
||||
if ((clk_rate < PLL_INFF_MIN_RATE) || (clk_rate > PLL_INFF_MAX_RATE)) { |
||||
pr_debug("%s: input clk freq (%dHz) out of range\n", |
||||
__func__, clk_rate); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
stm32_usbphyc_get_pll_params(clk_rate, &pll_params); |
||||
|
||||
usbphyc_pll = PLLDITHEN1 | PLLDITHEN0 | PLLSTRBYP; |
||||
usbphyc_pll |= ((pll_params.ndiv << PLLNDIV_SHIFT) & PLLNDIV); |
||||
|
||||
if (pll_params.frac) { |
||||
usbphyc_pll |= PLLFRACCTL; |
||||
usbphyc_pll |= ((pll_params.frac << PLLFRACIN_SHIFT) |
||||
& PLLFRACIN); |
||||
} |
||||
|
||||
writel(usbphyc_pll, usbphyc->base + STM32_USBPHYC_PLL); |
||||
|
||||
pr_debug("%s: input clk freq=%dHz, ndiv=%d, frac=%d\n", __func__, |
||||
clk_rate, pll_params.ndiv, pll_params.frac); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static bool stm32_usbphyc_is_init(struct stm32_usbphyc *usbphyc) |
||||
{ |
||||
int i; |
||||
|
||||
for (i = 0; i < MAX_PHYS; i++) { |
||||
if (usbphyc->phys[i].init) |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
static bool stm32_usbphyc_is_powered(struct stm32_usbphyc *usbphyc) |
||||
{ |
||||
int i; |
||||
|
||||
for (i = 0; i < MAX_PHYS; i++) { |
||||
if (usbphyc->phys[i].powered) |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
static int stm32_usbphyc_phy_init(struct phy *phy) |
||||
{ |
||||
struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev); |
||||
struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id; |
||||
bool pllen = readl(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN ? |
||||
true : false; |
||||
int ret; |
||||
|
||||
pr_debug("%s phy ID = %lu\n", __func__, phy->id); |
||||
/* Check if one phy port has already configured the pll */ |
||||
if (pllen && stm32_usbphyc_is_init(usbphyc)) |
||||
goto initialized; |
||||
|
||||
if (pllen) { |
||||
clrbits_le32(usbphyc->base + STM32_USBPHYC_PLL, PLLEN); |
||||
udelay(PLL_PWR_DOWN_TIME_US); |
||||
} |
||||
|
||||
ret = stm32_usbphyc_pll_init(usbphyc); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
setbits_le32(usbphyc->base + STM32_USBPHYC_PLL, PLLEN); |
||||
|
||||
/*
|
||||
* We must wait PLL_LOCK_TIME_US before checking that PLLEN |
||||
* bit is still set |
||||
*/ |
||||
udelay(PLL_LOCK_TIME_US); |
||||
|
||||
if (!(readl(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN)) |
||||
return -EIO; |
||||
|
||||
initialized: |
||||
usbphyc_phy->init = true; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int stm32_usbphyc_phy_exit(struct phy *phy) |
||||
{ |
||||
struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev); |
||||
struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id; |
||||
|
||||
pr_debug("%s phy ID = %lu\n", __func__, phy->id); |
||||
usbphyc_phy->init = false; |
||||
|
||||
/* Check if other phy port requires pllen */ |
||||
if (stm32_usbphyc_is_init(usbphyc)) |
||||
return 0; |
||||
|
||||
clrbits_le32(usbphyc->base + STM32_USBPHYC_PLL, PLLEN); |
||||
|
||||
/*
|
||||
* We must wait PLL_PWR_DOWN_TIME_US before checking that PLLEN |
||||
* bit is still clear |
||||
*/ |
||||
udelay(PLL_PWR_DOWN_TIME_US); |
||||
|
||||
if (readl(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN) |
||||
return -EIO; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int stm32_usbphyc_phy_power_on(struct phy *phy) |
||||
{ |
||||
struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev); |
||||
struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id; |
||||
int ret; |
||||
|
||||
pr_debug("%s phy ID = %lu\n", __func__, phy->id); |
||||
if (usbphyc_phy->vdda1v1) { |
||||
ret = regulator_set_enable(usbphyc_phy->vdda1v1, true); |
||||
if (ret) |
||||
return ret; |
||||
} |
||||
|
||||
if (usbphyc_phy->vdda1v8) { |
||||
ret = regulator_set_enable(usbphyc_phy->vdda1v8, true); |
||||
if (ret) |
||||
return ret; |
||||
} |
||||
if (usbphyc_phy->vdd) { |
||||
ret = regulator_set_enable(usbphyc_phy->vdd, true); |
||||
if (ret) |
||||
return ret; |
||||
} |
||||
|
||||
usbphyc_phy->powered = true; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int stm32_usbphyc_phy_power_off(struct phy *phy) |
||||
{ |
||||
struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev); |
||||
struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id; |
||||
int ret; |
||||
|
||||
pr_debug("%s phy ID = %lu\n", __func__, phy->id); |
||||
usbphyc_phy->powered = false; |
||||
|
||||
if (stm32_usbphyc_is_powered(usbphyc)) |
||||
return 0; |
||||
|
||||
if (usbphyc_phy->vdda1v1) { |
||||
ret = regulator_set_enable(usbphyc_phy->vdda1v1, false); |
||||
if (ret) |
||||
return ret; |
||||
} |
||||
|
||||
if (usbphyc_phy->vdda1v8) { |
||||
ret = regulator_set_enable(usbphyc_phy->vdda1v8, false); |
||||
if (ret) |
||||
return ret; |
||||
} |
||||
|
||||
if (usbphyc_phy->vdd) { |
||||
ret = regulator_set_enable(usbphyc_phy->vdd, false); |
||||
if (ret) |
||||
return ret; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int stm32_usbphyc_get_regulator(struct udevice *dev, ofnode node, |
||||
char *supply_name, |
||||
struct udevice **regulator) |
||||
{ |
||||
struct ofnode_phandle_args regulator_phandle; |
||||
int ret; |
||||
|
||||
ret = ofnode_parse_phandle_with_args(node, supply_name, |
||||
NULL, 0, 0, |
||||
®ulator_phandle); |
||||
if (ret) { |
||||
dev_err(dev, "Can't find %s property (%d)\n", supply_name, ret); |
||||
return ret; |
||||
} |
||||
|
||||
ret = uclass_get_device_by_ofnode(UCLASS_REGULATOR, |
||||
regulator_phandle.node, |
||||
regulator); |
||||
|
||||
if (ret) { |
||||
dev_err(dev, "Can't get %s regulator (%d)\n", supply_name, ret); |
||||
return ret; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int stm32_usbphyc_of_xlate(struct phy *phy, |
||||
struct ofnode_phandle_args *args) |
||||
{ |
||||
if (args->args_count > 1) { |
||||
pr_debug("%s: invalid args_count: %d\n", __func__, |
||||
args->args_count); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
if (args->args[0] >= MAX_PHYS) |
||||
return -ENODEV; |
||||
|
||||
if (args->args_count) |
||||
phy->id = args->args[0]; |
||||
else |
||||
phy->id = 0; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static const struct phy_ops stm32_usbphyc_phy_ops = { |
||||
.init = stm32_usbphyc_phy_init, |
||||
.exit = stm32_usbphyc_phy_exit, |
||||
.power_on = stm32_usbphyc_phy_power_on, |
||||
.power_off = stm32_usbphyc_phy_power_off, |
||||
.of_xlate = stm32_usbphyc_of_xlate, |
||||
}; |
||||
|
||||
static int stm32_usbphyc_probe(struct udevice *dev) |
||||
{ |
||||
struct stm32_usbphyc *usbphyc = dev_get_priv(dev); |
||||
struct reset_ctl reset; |
||||
ofnode node; |
||||
int i, ret; |
||||
|
||||
usbphyc->base = dev_read_addr(dev); |
||||
if (usbphyc->base == FDT_ADDR_T_NONE) |
||||
return -EINVAL; |
||||
|
||||
/* Enable clock */ |
||||
ret = clk_get_by_index(dev, 0, &usbphyc->clk); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
ret = clk_enable(&usbphyc->clk); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
/* Reset */ |
||||
ret = reset_get_by_index(dev, 0, &reset); |
||||
if (!ret) { |
||||
reset_assert(&reset); |
||||
udelay(2); |
||||
reset_deassert(&reset); |
||||
} |
||||
|
||||
/*
|
||||
* parse all PHY subnodes in order to populate regulator associated |
||||
* to each PHY port |
||||
*/ |
||||
node = dev_read_first_subnode(dev); |
||||
for (i = 0; i < MAX_PHYS; i++) { |
||||
struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + i; |
||||
|
||||
usbphyc_phy->index = i; |
||||
usbphyc_phy->init = false; |
||||
usbphyc_phy->powered = false; |
||||
ret = stm32_usbphyc_get_regulator(dev, node, "phy-supply", |
||||
&usbphyc_phy->vdd); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
ret = stm32_usbphyc_get_regulator(dev, node, "vdda1v1-supply", |
||||
&usbphyc_phy->vdda1v1); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
ret = stm32_usbphyc_get_regulator(dev, node, "vdda1v8-supply", |
||||
&usbphyc_phy->vdda1v8); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
node = dev_read_next_subnode(node); |
||||
} |
||||
|
||||
/* Check if second port has to be used for host controller */ |
||||
if (dev_read_bool(dev, "st,port2-switch-to-host")) |
||||
setbits_le32(usbphyc->base + STM32_USBPHYC_MISC, SWITHOST); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static const struct udevice_id stm32_usbphyc_of_match[] = { |
||||
{ .compatible = "st,stm32mp1-usbphyc", }, |
||||
{ }, |
||||
}; |
||||
|
||||
U_BOOT_DRIVER(stm32_usb_phyc) = { |
||||
.name = "stm32-usbphyc", |
||||
.id = UCLASS_PHY, |
||||
.of_match = stm32_usbphyc_of_match, |
||||
.ops = &stm32_usbphyc_phy_ops, |
||||
.probe = stm32_usbphyc_probe, |
||||
.priv_auto_alloc_size = sizeof(struct stm32_usbphyc), |
||||
}; |
@ -0,0 +1,157 @@ |
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Generic DWC3 Glue layer |
||||
* |
||||
* Copyright (C) 2016 - 2018 Xilinx, Inc. |
||||
* |
||||
* Based on dwc3-omap.c. |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <dm.h> |
||||
#include <dm/device-internal.h> |
||||
#include <dm/lists.h> |
||||
#include <linux/usb/otg.h> |
||||
#include <linux/compat.h> |
||||
#include <linux/usb/ch9.h> |
||||
#include <linux/usb/gadget.h> |
||||
#include <malloc.h> |
||||
#include <usb.h> |
||||
#include "core.h" |
||||
#include "gadget.h" |
||||
#include "linux-compat.h" |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
int usb_gadget_handle_interrupts(int index) |
||||
{ |
||||
struct dwc3 *priv; |
||||
struct udevice *dev; |
||||
int ret; |
||||
|
||||
ret = uclass_first_device(UCLASS_USB_DEV_GENERIC, &dev); |
||||
if (!dev || ret) { |
||||
pr_err("No USB device found\n"); |
||||
return -ENODEV; |
||||
} |
||||
|
||||
priv = dev_get_priv(dev); |
||||
|
||||
dwc3_gadget_uboot_handle_interrupt(priv); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int dwc3_generic_peripheral_probe(struct udevice *dev) |
||||
{ |
||||
struct dwc3 *priv = dev_get_priv(dev); |
||||
|
||||
return dwc3_init(priv); |
||||
} |
||||
|
||||
static int dwc3_generic_peripheral_remove(struct udevice *dev) |
||||
{ |
||||
struct dwc3 *priv = dev_get_priv(dev); |
||||
|
||||
dwc3_remove(priv); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int dwc3_generic_peripheral_ofdata_to_platdata(struct udevice *dev) |
||||
{ |
||||
struct dwc3 *priv = dev_get_priv(dev); |
||||
int node = dev_of_offset(dev); |
||||
|
||||
priv->regs = (void *)devfdt_get_addr(dev); |
||||
priv->regs += DWC3_GLOBALS_REGS_START; |
||||
|
||||
priv->maximum_speed = usb_get_maximum_speed(node); |
||||
if (priv->maximum_speed == USB_SPEED_UNKNOWN) { |
||||
pr_err("Invalid usb maximum speed\n"); |
||||
return -ENODEV; |
||||
} |
||||
|
||||
priv->dr_mode = usb_get_dr_mode(node); |
||||
if (priv->dr_mode == USB_DR_MODE_UNKNOWN) { |
||||
pr_err("Invalid usb mode setup\n"); |
||||
return -ENODEV; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int dwc3_generic_peripheral_bind(struct udevice *dev) |
||||
{ |
||||
return device_probe(dev); |
||||
} |
||||
|
||||
U_BOOT_DRIVER(dwc3_generic_peripheral) = { |
||||
.name = "dwc3-generic-peripheral", |
||||
.id = UCLASS_USB_DEV_GENERIC, |
||||
.ofdata_to_platdata = dwc3_generic_peripheral_ofdata_to_platdata, |
||||
.probe = dwc3_generic_peripheral_probe, |
||||
.remove = dwc3_generic_peripheral_remove, |
||||
.bind = dwc3_generic_peripheral_bind, |
||||
.platdata_auto_alloc_size = sizeof(struct usb_platdata), |
||||
.priv_auto_alloc_size = sizeof(struct dwc3), |
||||
.flags = DM_FLAG_ALLOC_PRIV_DMA, |
||||
}; |
||||
|
||||
static int dwc3_generic_bind(struct udevice *parent) |
||||
{ |
||||
const void *fdt = gd->fdt_blob; |
||||
int node; |
||||
int ret; |
||||
|
||||
for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0; |
||||
node = fdt_next_subnode(fdt, node)) { |
||||
const char *name = fdt_get_name(fdt, node, NULL); |
||||
enum usb_dr_mode dr_mode; |
||||
struct udevice *dev; |
||||
const char *driver; |
||||
|
||||
debug("%s: subnode name: %s\n", __func__, name); |
||||
if (strncmp(name, "dwc3@", 4)) |
||||
continue; |
||||
|
||||
dr_mode = usb_get_dr_mode(node); |
||||
|
||||
switch (dr_mode) { |
||||
case USB_DR_MODE_PERIPHERAL: |
||||
case USB_DR_MODE_OTG: |
||||
debug("%s: dr_mode: OTG or Peripheral\n", __func__); |
||||
driver = "dwc3-generic-peripheral"; |
||||
break; |
||||
case USB_DR_MODE_HOST: |
||||
debug("%s: dr_mode: HOST\n", __func__); |
||||
driver = "dwc3-generic-host"; |
||||
break; |
||||
default: |
||||
debug("%s: unsupported dr_mode\n", __func__); |
||||
return -ENODEV; |
||||
}; |
||||
|
||||
ret = device_bind_driver_to_node(parent, driver, name, |
||||
offset_to_ofnode(node), &dev); |
||||
if (ret) { |
||||
debug("%s: not able to bind usb device mode\n", |
||||
__func__); |
||||
return ret; |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static const struct udevice_id dwc3_generic_ids[] = { |
||||
{ .compatible = "xlnx,zynqmp-dwc3" }, |
||||
{ } |
||||
}; |
||||
|
||||
U_BOOT_DRIVER(dwc3_generic_wrapper) = { |
||||
.name = "dwc3-generic-wrapper", |
||||
.id = UCLASS_MISC, |
||||
.of_match = dwc3_generic_ids, |
||||
.bind = dwc3_generic_bind, |
||||
}; |
Loading…
Reference in new issue