usb: dwc3-generic: Allow different controller DT node pattern
The most of devicetree has the following USB node structure.
The controller node is placed as a child node of the glue node.
Current dwc3-generic driver works on this premise.
glue {
/* glue node */
usb {
/* controller node */
};
};
However, UniPhier original devicetree has the following USB node structure.
The controller node is separately placed from the glue node.
usb {
/* controller node */
};
glue {
/* glue node */
};
In dwc_glue_bind(), this patch provides .glue_get_ctrl_dev() callback to
get such a controller node and binds the driver related to the node.
If this callback isn't defined, dwc_glue_bind() looks for the controller
nodes from the child nodes, as before.
Suggested-by: Marek Vasut <marex@denx.de>
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Reviewed-by: Marek Vasut <marex@denx.de>
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
index 42e9247..e32003d 100644
--- a/drivers/usb/dwc3/dwc3-generic.c
+++ b/drivers/usb/dwc3/dwc3-generic.c
@@ -276,6 +276,7 @@
#endif
struct dwc3_glue_ops {
+ int (*glue_get_ctrl_dev)(struct udevice *parent, ofnode *node);
void (*glue_configure)(struct udevice *dev, int index,
enum usb_dr_mode mode);
};
@@ -415,54 +416,74 @@
.glue_configure = dwc3_ti_glue_configure,
};
+static int dwc3_glue_bind_common(struct udevice *parent, ofnode node)
+{
+ const char *name = ofnode_get_name(node);
+ const char *driver = NULL;
+ enum usb_dr_mode dr_mode;
+ struct udevice *dev;
+ int ret;
+
+ debug("%s: subnode name: %s\n", __func__, name);
+
+ /* if the parent node doesn't have a mode check the leaf */
+ dr_mode = usb_get_dr_mode(dev_ofnode(parent));
+ if (!dr_mode)
+ dr_mode = usb_get_dr_mode(node);
+
+ switch (dr_mode) {
+ case USB_DR_MODE_PERIPHERAL:
+ case USB_DR_MODE_OTG:
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+ debug("%s: dr_mode: OTG or Peripheral\n", __func__);
+ driver = "dwc3-generic-peripheral";
+#endif
+ break;
+#if defined(CONFIG_SPL_USB_HOST) || !defined(CONFIG_SPL_BUILD)
+ case USB_DR_MODE_HOST:
+ debug("%s: dr_mode: HOST\n", __func__);
+ driver = "dwc3-generic-host";
+ break;
+#endif
+ default:
+ debug("%s: unsupported dr_mode\n", __func__);
+ return -ENODEV;
+ };
+
+ if (!driver)
+ return -ENXIO;
+
+ ret = device_bind_driver_to_node(parent, driver, name,
+ node, &dev);
+ if (ret) {
+ debug("%s: not able to bind usb device mode\n",
+ __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
static int dwc3_glue_bind(struct udevice *parent)
{
+ struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(parent);
ofnode node;
int ret;
- enum usb_dr_mode dr_mode;
- dr_mode = usb_get_dr_mode(dev_ofnode(parent));
+ if (ops && ops->glue_get_ctrl_dev) {
+ ret = ops->glue_get_ctrl_dev(parent, &node);
+ if (ret)
+ return ret;
+
+ return dwc3_glue_bind_common(parent, node);
+ }
ofnode_for_each_subnode(node, dev_ofnode(parent)) {
- const char *name = ofnode_get_name(node);
- struct udevice *dev;
- const char *driver = NULL;
-
- debug("%s: subnode name: %s\n", __func__, name);
-
- /* if the parent node doesn't have a mode check the leaf */
- if (!dr_mode)
- dr_mode = usb_get_dr_mode(node);
-
- switch (dr_mode) {
- case USB_DR_MODE_PERIPHERAL:
- case USB_DR_MODE_OTG:
-#if CONFIG_IS_ENABLED(DM_USB_GADGET)
- debug("%s: dr_mode: OTG or Peripheral\n", __func__);
- driver = "dwc3-generic-peripheral";
-#endif
- break;
-#if defined(CONFIG_SPL_USB_HOST) || !defined(CONFIG_SPL_BUILD)
- case USB_DR_MODE_HOST:
- debug("%s: dr_mode: HOST\n", __func__);
- driver = "dwc3-generic-host";
- break;
-#endif
- default:
- debug("%s: unsupported dr_mode\n", __func__);
- return -ENODEV;
- };
-
- if (!driver)
+ ret = dwc3_glue_bind_common(parent, node);
+ if (ret == -ENXIO)
continue;
-
- ret = device_bind_driver_to_node(parent, driver, name,
- node, &dev);
- if (ret) {
- debug("%s: not able to bind usb device mode\n",
- __func__);
+ if (ret)
return ret;
- }
}
return 0;