[U-Boot] [RESEND][PATCH v5 0/5] Extend xhci-dwc3

From: Patrice Chotard patrice.chotard@st.com
This series extend xhci-dwc3.c drivers by : _ converting it to DM model, _ adding dual role mode support from DT _ adding new generic_phy_valid() method in PHY framework _ adding support of generic PHY framework
v5: _ rebase on top of dm/master in order to use the last livetree update _ replace dev_get_addr() by devfdt_get_addr() in patch 1 v4: _ set phy->dev to NULL in case of generic_phy_get_by_index() v3: _ introduce generic_phy_valid() method _ add Reviewed-by v2: _ use dev_get_addr() in PATCH 1 and removed useless piece of code
Patrice Chotard (5): usb: host: xhci-dwc3: Convert driver to DM usb: host: xhci-dwc3: Add dual role mode support from DT drivers: phy: Set phy->dev to NULL when generic_phy_get_by_index() fails drivers: phy: add generic_phy_valid() method usb: host: xhci-dwc3: Add generic PHY support
drivers/phy/phy-uclass.c | 6 +++ drivers/usb/host/xhci-dwc3.c | 91 ++++++++++++++++++++++++++++++++++++++++++++ include/generic-phy.h | 8 ++++ 3 files changed, 105 insertions(+)

From: Patrice Chotard patrice.chotard@st.com
Add Driver Model support with use of generic DT compatible string "snps,dwc3"
Signed-off-by: Patrice Chotard patrice.chotard@st.com Reviewed-by: Simon Glass sjg@chromium.org ---
v5: _ replace dev_get_addr() by devfdt_get_addr() v4: _ none v3: _ none v2: _ use dev_get_addr() and removed useless piece of code
drivers/usb/host/xhci-dwc3.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+)
diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 33961cd..8c90836 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -9,9 +9,19 @@ */
#include <common.h> +#include <dm.h> +#include <usb.h> + +#include "xhci.h" #include <asm/io.h> #include <linux/usb/dwc3.h>
+DECLARE_GLOBAL_DATA_PTR; + +struct xhci_dwc3_priv { + struct xhci_ctrl ctrl; +}; + void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) { clrsetbits_le32(&dwc3_reg->g_ctl, @@ -97,3 +107,43 @@ void dwc3_set_fladj(struct dwc3 *dwc3_reg, u32 val) setbits_le32(&dwc3_reg->g_fladj, GFLADJ_30MHZ_REG_SEL | GFLADJ_30MHZ(val)); } + +static int xhci_dwc3_probe(struct udevice *dev) +{ + struct xhci_dwc3_platdata *plat = dev_get_platdata(dev); + struct xhci_hcor *hcor; + struct xhci_hccr *hccr; + struct dwc3 *dwc3_reg; + + hccr = (struct xhci_hccr *)devfdt_get_addr(dev); + hcor = (struct xhci_hcor *)((phys_addr_t)hccr + + HC_LENGTH(xhci_readl(&(hccr)->cr_capbase))); + + dwc3_reg = (struct dwc3 *)((char *)(hccr) + DWC3_REG_OFFSET); + + dwc3_core_init(dwc3_reg); + + return xhci_register(dev, hccr, hcor); +} + +static int xhci_dwc3_remove(struct udevice *dev) +{ + return xhci_deregister(dev); +} + +static const struct udevice_id xhci_dwc3_ids[] = { + { .compatible = "snps,dwc3" }, + { } +}; + +U_BOOT_DRIVER(xhci_dwc3) = { + .name = "xhci-dwc3", + .id = UCLASS_USB, + .of_match = xhci_dwc3_ids, + .probe = xhci_dwc3_probe, + .remove = xhci_dwc3_remove, + .ops = &xhci_usb_ops, + .priv_auto_alloc_size = sizeof(struct xhci_dwc3_priv), + .platdata_auto_alloc_size = sizeof(struct xhci_dwc3_platdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +};

Hi Patrice,
On Thu, Jul 6, 2017 at 3:50 PM, patrice.chotard@st.com wrote:
From: Patrice Chotard patrice.chotard@st.com
Add Driver Model support with use of generic DT compatible string "snps,dwc3"
Signed-off-by: Patrice Chotard patrice.chotard@st.com Reviewed-by: Simon Glass sjg@chromium.org
v5: _ replace dev_get_addr() by devfdt_get_addr() v4: _ none v3: _ none v2: _ use dev_get_addr() and removed useless piece of code
drivers/usb/host/xhci-dwc3.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+)
diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 33961cd..8c90836 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -9,9 +9,19 @@ */
#include <common.h> +#include <dm.h> +#include <usb.h>
+#include "xhci.h" #include <asm/io.h> #include <linux/usb/dwc3.h>
+DECLARE_GLOBAL_DATA_PTR;
+struct xhci_dwc3_priv {
struct xhci_ctrl ctrl;
+};
Please use 'struct xhci_dwc3' directly for .priv_auto_alloc_size
void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) { clrsetbits_le32(&dwc3_reg->g_ctl, @@ -97,3 +107,43 @@ void dwc3_set_fladj(struct dwc3 *dwc3_reg, u32 val) setbits_le32(&dwc3_reg->g_fladj, GFLADJ_30MHZ_REG_SEL | GFLADJ_30MHZ(val)); }
+static int xhci_dwc3_probe(struct udevice *dev) +{
struct xhci_dwc3_platdata *plat = dev_get_platdata(dev);
struct xhci_hcor *hcor;
struct xhci_hccr *hccr;
struct dwc3 *dwc3_reg;
hccr = (struct xhci_hccr *)devfdt_get_addr(dev);
hcor = (struct xhci_hcor *)((phys_addr_t)hccr +
HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
dwc3_reg = (struct dwc3 *)((char *)(hccr) + DWC3_REG_OFFSET);
dwc3_core_init(dwc3_reg);
return xhci_register(dev, hccr, hcor);
+}
+static int xhci_dwc3_remove(struct udevice *dev) +{
return xhci_deregister(dev);
+}
Please nuke this xhci_dwc3_remove(), instead register xhci_deregister() directly.
+static const struct udevice_id xhci_dwc3_ids[] = {
{ .compatible = "snps,dwc3" },
{ }
+};
+U_BOOT_DRIVER(xhci_dwc3) = {
.name = "xhci-dwc3",
.id = UCLASS_USB,
.of_match = xhci_dwc3_ids,
.probe = xhci_dwc3_probe,
.remove = xhci_dwc3_remove,
.ops = &xhci_usb_ops,
.priv_auto_alloc_size = sizeof(struct xhci_dwc3_priv),
.platdata_auto_alloc_size = sizeof(struct xhci_dwc3_platdata),
.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
Regards, Bin

Hi Bin
On 07/06/2017 10:27 AM, Bin Meng wrote:
Hi Patrice,
On Thu, Jul 6, 2017 at 3:50 PM, patrice.chotard@st.com wrote:
From: Patrice Chotard patrice.chotard@st.com
Add Driver Model support with use of generic DT compatible string "snps,dwc3"
Signed-off-by: Patrice Chotard patrice.chotard@st.com Reviewed-by: Simon Glass sjg@chromium.org
v5: _ replace dev_get_addr() by devfdt_get_addr() v4: _ none v3: _ none v2: _ use dev_get_addr() and removed useless piece of code
drivers/usb/host/xhci-dwc3.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+)
diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 33961cd..8c90836 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -9,9 +9,19 @@ */
#include <common.h> +#include <dm.h> +#include <usb.h>
+#include "xhci.h" #include <asm/io.h> #include <linux/usb/dwc3.h>
+DECLARE_GLOBAL_DATA_PTR;
+struct xhci_dwc3_priv {
struct xhci_ctrl ctrl;
+};
Please use 'struct xhci_dwc3' directly for .priv_auto_alloc_size
You mean, rename struct xhci_dwc3_priv to struct xhci_dwc3 ?
- void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) { clrsetbits_le32(&dwc3_reg->g_ctl,
@@ -97,3 +107,43 @@ void dwc3_set_fladj(struct dwc3 *dwc3_reg, u32 val) setbits_le32(&dwc3_reg->g_fladj, GFLADJ_30MHZ_REG_SEL | GFLADJ_30MHZ(val)); }
+static int xhci_dwc3_probe(struct udevice *dev) +{
struct xhci_dwc3_platdata *plat = dev_get_platdata(dev);
struct xhci_hcor *hcor;
struct xhci_hccr *hccr;
struct dwc3 *dwc3_reg;
hccr = (struct xhci_hccr *)devfdt_get_addr(dev);
hcor = (struct xhci_hcor *)((phys_addr_t)hccr +
HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
dwc3_reg = (struct dwc3 *)((char *)(hccr) + DWC3_REG_OFFSET);
dwc3_core_init(dwc3_reg);
return xhci_register(dev, hccr, hcor);
+}
+static int xhci_dwc3_remove(struct udevice *dev) +{
return xhci_deregister(dev);
+}
Please nuke this xhci_dwc3_remove(), instead register xhci_deregister() directly.
Is it worth, as in patch 5, xhci_dwc3_remove() will be populated.
Thanks
Patrice
+static const struct udevice_id xhci_dwc3_ids[] = {
{ .compatible = "snps,dwc3" },
{ }
+};
+U_BOOT_DRIVER(xhci_dwc3) = {
.name = "xhci-dwc3",
.id = UCLASS_USB,
.of_match = xhci_dwc3_ids,
.probe = xhci_dwc3_probe,
.remove = xhci_dwc3_remove,
.ops = &xhci_usb_ops,
.priv_auto_alloc_size = sizeof(struct xhci_dwc3_priv),
.platdata_auto_alloc_size = sizeof(struct xhci_dwc3_platdata),
.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
Regards, Bin

Hi Patrice,
On Thu, Jul 6, 2017 at 4:47 PM, Patrice CHOTARD patrice.chotard@st.com wrote:
Hi Bin
On 07/06/2017 10:27 AM, Bin Meng wrote:
Hi Patrice,
On Thu, Jul 6, 2017 at 3:50 PM, patrice.chotard@st.com wrote:
From: Patrice Chotard patrice.chotard@st.com
Add Driver Model support with use of generic DT compatible string "snps,dwc3"
Signed-off-by: Patrice Chotard patrice.chotard@st.com Reviewed-by: Simon Glass sjg@chromium.org
v5: _ replace dev_get_addr() by devfdt_get_addr() v4: _ none v3: _ none v2: _ use dev_get_addr() and removed useless piece of code
drivers/usb/host/xhci-dwc3.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+)
diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 33961cd..8c90836 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -9,9 +9,19 @@ */
#include <common.h> +#include <dm.h> +#include <usb.h>
+#include "xhci.h" #include <asm/io.h> #include <linux/usb/dwc3.h>
+DECLARE_GLOBAL_DATA_PTR;
+struct xhci_dwc3_priv {
struct xhci_ctrl ctrl;
+};
Please use 'struct xhci_dwc3' directly for .priv_auto_alloc_size
You mean, rename struct xhci_dwc3_priv to struct xhci_dwc3 ?
I mean use .priv_auto_alloc_size = sizeof(struct xhci_ctrl) directly without adding a new struct
- void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) { clrsetbits_le32(&dwc3_reg->g_ctl,
@@ -97,3 +107,43 @@ void dwc3_set_fladj(struct dwc3 *dwc3_reg, u32 val) setbits_le32(&dwc3_reg->g_fladj, GFLADJ_30MHZ_REG_SEL | GFLADJ_30MHZ(val)); }
+static int xhci_dwc3_probe(struct udevice *dev) +{
struct xhci_dwc3_platdata *plat = dev_get_platdata(dev);
struct xhci_hcor *hcor;
struct xhci_hccr *hccr;
struct dwc3 *dwc3_reg;
hccr = (struct xhci_hccr *)devfdt_get_addr(dev);
hcor = (struct xhci_hcor *)((phys_addr_t)hccr +
HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
dwc3_reg = (struct dwc3 *)((char *)(hccr) + DWC3_REG_OFFSET);
dwc3_core_init(dwc3_reg);
return xhci_register(dev, hccr, hcor);
+}
+static int xhci_dwc3_remove(struct udevice *dev) +{
return xhci_deregister(dev);
+}
Please nuke this xhci_dwc3_remove(), instead register xhci_deregister() directly.
Is it worth, as in patch 5, xhci_dwc3_remove() will be populated.
Ah, I see. Then there is no need to do that. Thanks!
Regards, Bin

Hi Bin
On 07/06/2017 10:50 AM, Bin Meng wrote:
Hi Patrice,
On Thu, Jul 6, 2017 at 4:47 PM, Patrice CHOTARD patrice.chotard@st.com wrote:
Hi Bin
On 07/06/2017 10:27 AM, Bin Meng wrote:
Hi Patrice,
On Thu, Jul 6, 2017 at 3:50 PM, patrice.chotard@st.com wrote:
From: Patrice Chotard patrice.chotard@st.com
Add Driver Model support with use of generic DT compatible string "snps,dwc3"
Signed-off-by: Patrice Chotard patrice.chotard@st.com Reviewed-by: Simon Glass sjg@chromium.org
v5: _ replace dev_get_addr() by devfdt_get_addr() v4: _ none v3: _ none v2: _ use dev_get_addr() and removed useless piece of code
drivers/usb/host/xhci-dwc3.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+)
diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 33961cd..8c90836 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -9,9 +9,19 @@ */
#include <common.h> +#include <dm.h> +#include <usb.h>
+#include "xhci.h" #include <asm/io.h> #include <linux/usb/dwc3.h>
+DECLARE_GLOBAL_DATA_PTR;
+struct xhci_dwc3_priv {
struct xhci_ctrl ctrl;
+};
Please use 'struct xhci_dwc3' directly for .priv_auto_alloc_size
You mean, rename struct xhci_dwc3_priv to struct xhci_dwc3 ?
I mean use .priv_auto_alloc_size = sizeof(struct xhci_ctrl) directly without adding a new struct
Agree, i will fix this
Thanks
Patrice
- void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) { clrsetbits_le32(&dwc3_reg->g_ctl,
@@ -97,3 +107,43 @@ void dwc3_set_fladj(struct dwc3 *dwc3_reg, u32 val) setbits_le32(&dwc3_reg->g_fladj, GFLADJ_30MHZ_REG_SEL | GFLADJ_30MHZ(val)); }
+static int xhci_dwc3_probe(struct udevice *dev) +{
struct xhci_dwc3_platdata *plat = dev_get_platdata(dev);
struct xhci_hcor *hcor;
struct xhci_hccr *hccr;
struct dwc3 *dwc3_reg;
hccr = (struct xhci_hccr *)devfdt_get_addr(dev);
hcor = (struct xhci_hcor *)((phys_addr_t)hccr +
HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
dwc3_reg = (struct dwc3 *)((char *)(hccr) + DWC3_REG_OFFSET);
dwc3_core_init(dwc3_reg);
return xhci_register(dev, hccr, hcor);
+}
+static int xhci_dwc3_remove(struct udevice *dev) +{
return xhci_deregister(dev);
+}
Please nuke this xhci_dwc3_remove(), instead register xhci_deregister() directly.
Is it worth, as in patch 5, xhci_dwc3_remove() will be populated.
Ah, I see. Then there is no need to do that. Thanks!
Regards, Bin

From: Patrice Chotard patrice.chotard@st.com
DWC3 dual role mode is selected using DT "dr_mode" property. If not found, DWC3 controller is configured in HOST mode by default
Signed-off-by: Patrice Chotard patrice.chotard@st.com Reviewed-by: Marek Vasut marex@denx.de Reviewed-by: Simon Glass sjg@chromium.org --- v5: _ none v4: _ none v3: _ none v2: _ none
drivers/usb/host/xhci-dwc3.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 8c90836..7c32722 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -15,6 +15,7 @@ #include "xhci.h" #include <asm/io.h> #include <linux/usb/dwc3.h> +#include <linux/usb/otg.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -114,6 +115,7 @@ static int xhci_dwc3_probe(struct udevice *dev) struct xhci_hcor *hcor; struct xhci_hccr *hccr; struct dwc3 *dwc3_reg; + enum usb_dr_mode dr_mode;
hccr = (struct xhci_hccr *)devfdt_get_addr(dev); hcor = (struct xhci_hcor *)((phys_addr_t)hccr + @@ -123,6 +125,13 @@ static int xhci_dwc3_probe(struct udevice *dev)
dwc3_core_init(dwc3_reg);
+ dr_mode = usb_get_dr_mode(dev_of_offset(dev)); + if (dr_mode == USB_DR_MODE_UNKNOWN) + /* by default set dual role mode to HOST */ + dr_mode = USB_DR_MODE_HOST; + + dwc3_set_mode(dwc3_reg, dr_mode); + return xhci_register(dev, hccr, hcor); }

From: Patrice Chotard patrice.chotard@st.com
phy->dev need to be set to NULL in case of generic_phy_get_by_index() fails. Then phy->dev can be used to check if the phy is valid
Reported-by: Jean-Jacques Hiblot jjhiblot@ti.com Signed-off-by: Patrice Chotard patrice.chotard@st.com Reviewed-by: Simon Glass sjg@chromium.org Reviewed-by: Jean-Jacques Hiblot jjhiblot@ti.com
---
v5: _ none v4: _ ensure that phy->dev is set to NULL in case of generic_phy_get_by_index() fails
drivers/phy/phy-uclass.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index d8b8d58..68e518f 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -45,6 +45,7 @@ int generic_phy_get_by_index(struct udevice *dev, int index, debug("%s(dev=%p, index=%d, phy=%p)\n", __func__, dev, index, phy);
assert(phy); + phy->dev = NULL; ret = dev_read_phandle_with_args(dev, "phys", "#phy-cells", 0, index, &args); if (ret) {

From: Patrice Chotard patrice.chotard@st.com
This allow to check if a PHY has been correctly initialised and avoid to get access to phy struct.
Signed-off-by: Patrice Chotard patrice.chotard@st.com Reviewed-by: Marek Vasut marex@denx.de Reviewed-by: Simon Glass sjg@chromium.org ---
v5: _ none v4: _ none
drivers/phy/phy-uclass.c | 5 +++++ include/generic-phy.h | 8 ++++++++ 2 files changed, 13 insertions(+)
diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index 68e518f..8ccd9bc 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -131,6 +131,11 @@ int generic_phy_power_off(struct phy *phy) return ops->power_off ? ops->power_off(phy) : 0; }
+bool generic_phy_valid(struct phy *phy) +{ + return phy->dev != NULL; +} + UCLASS_DRIVER(phy) = { .id = UCLASS_PHY, .name = "phy", diff --git a/include/generic-phy.h b/include/generic-phy.h index 762704c..343ad03 100644 --- a/include/generic-phy.h +++ b/include/generic-phy.h @@ -220,4 +220,12 @@ int generic_phy_get_by_index(struct udevice *user, int index, int generic_phy_get_by_name(struct udevice *user, const char *phy_name, struct phy *phy);
+/** + * generic_phy_valid() - check if PHY port is valid + * + * @phy: the PHY port to check + * @return TRUE if valid, or FALSE + */ +bool generic_phy_valid(struct phy *phy); + #endif /*__GENERIC_PHY_H */

From: Patrice Chotard patrice.chotard@st.com
Add support of generic PHY framework support
Signed-off-by: Patrice Chotard patrice.chotard@st.com Reviewed-by: Marek Vasut marex@denx.de Reviewed-by: Simon Glass sjg@chromium.org ---
v5: _ none v4: _ none v3: _ use generic_phy_valid() method v2: _ none
drivers/usb/host/xhci-dwc3.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 7c32722..3c46378 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -10,6 +10,8 @@
#include <common.h> #include <dm.h> +#include <fdtdec.h> +#include <generic-phy.h> #include <usb.h>
#include "xhci.h" @@ -19,6 +21,10 @@
DECLARE_GLOBAL_DATA_PTR;
+struct xhci_dwc3_platdata { + struct phy usb_phy; +}; + struct xhci_dwc3_priv { struct xhci_ctrl ctrl; }; @@ -116,11 +122,26 @@ static int xhci_dwc3_probe(struct udevice *dev) struct xhci_hccr *hccr; struct dwc3 *dwc3_reg; enum usb_dr_mode dr_mode; + int ret;
hccr = (struct xhci_hccr *)devfdt_get_addr(dev); hcor = (struct xhci_hcor *)((phys_addr_t)hccr + HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
+ ret = generic_phy_get_by_index(dev, 0, &plat->usb_phy); + if (ret) { + if (ret != -ENOENT) { + error("Failed to get USB PHY for %s\n", dev->name); + return ret; + } + } else { + ret = generic_phy_init(&plat->usb_phy); + if (ret) { + error("Can't init USB PHY for %s\n", dev->name); + return ret; + } + } + dwc3_reg = (struct dwc3 *)((char *)(hccr) + DWC3_REG_OFFSET);
dwc3_core_init(dwc3_reg); @@ -137,6 +158,17 @@ static int xhci_dwc3_probe(struct udevice *dev)
static int xhci_dwc3_remove(struct udevice *dev) { + struct xhci_dwc3_platdata *plat = dev_get_platdata(dev); + int ret; + + if (generic_phy_valid(&plat->usb_phy)) { + ret = generic_phy_exit(&plat->usb_phy); + if (ret) { + error("Can't deinit USB PHY for %s\n", dev->name); + return ret; + } + } + return xhci_deregister(dev); }
participants (3)
-
Bin Meng
-
Patrice CHOTARD
-
patrice.chotard@st.com