On Wed, Jul 9, 2025 at 8:36 AM Tim Harvey <thar...@gateworks.com> wrote: > > If a usb host with dr_mode of "otg" has a usb-connector using a GPIO ID > pin use this to determine host vs peripheral. > > Signed-off-by: Tim Harvey <thar...@gateworks.com> > --- > v2 > - do not display error if 'port' node not found > - change print to debug > --- > drivers/usb/common/common.c | 94 ++++++++++++++++++++++++++++++++++++- > 1 file changed, 93 insertions(+), 1 deletion(-) > > diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c > index 13e9a61072a9..85865712bfcc 100644 > --- a/drivers/usb/common/common.c > +++ b/drivers/usb/common/common.c > @@ -8,6 +8,7 @@ > > #include <dm.h> > #include <asm/global_data.h> > +#include <asm/gpio.h> > #include <linux/printk.h> > #include <linux/usb/otg.h> > #include <linux/usb/ch9.h> > @@ -22,6 +23,97 @@ static const char *const usb_dr_modes[] = { > [USB_DR_MODE_OTG] = "otg", > }; > > +/** > + * get_remote_node_from_graph - Resolve the remote node from a graph binding > + * @node: Starting ofnode (e.g., connector) > + * @port_id: Port unit address (e.g., 0 for port@0, or -1 for first port) > + * @endpoint_id: Endpoint unit address (e.g., 0 for endpoint@0, or -1 for > first endpoint) > + * Return: ofnode of the remote node, or ofnode_null() on failure > + */ > +static ofnode get_remote_node_from_graph(ofnode node, int port_id, int > endpoint_id) > +{ > + ofnode port_node, endpoint_node, remote_node; > + u32 phandle_value; > + char port_name[16]; > + char endpoint_name[16]; > + > + /* Validate the starting node */ > + if (!ofnode_valid(node)) { > + debug("Invalid starting node\n"); > + return ofnode_null(); > + } > + > + /* Construct port name (e.g., "port" or "port@0") */ > + if (port_id == -1) > + strcpy(port_name, "port"); > + else > + snprintf(port_name, sizeof(port_name), "port@%d", port_id); > + > + /* look for a 'port' node */ > + port_node = ofnode_find_subnode(node, port_name); > + if (!ofnode_valid(port_node)) > + return ofnode_null(); > + > + /* Construct endpoint name (e.g., "endpoint" or "endpoint@0") */ > + if (endpoint_id == -1) > + strcpy(endpoint_name, "endpoint"); > + else > + snprintf(endpoint_name, sizeof(endpoint_name), "endpoint@%d", > endpoint_id); > + > + /* Find the 'endpoint' node */ > + endpoint_node = ofnode_find_subnode(port_node, endpoint_name); > + if (!ofnode_valid(endpoint_node)) { > + printf("No '%s' node found under '%s'\n", endpoint_name, > port_name); > + return ofnode_null(); > + } > + > + /* Read the remote-endpoint phandle */ > + phandle_value = ofnode_read_u32_default(endpoint_node, > "remote-endpoint", 0); > + if (phandle_value == 0) { > + printf("No valid 'remote-endpoint' phandle in '%s'\n", > endpoint_name); > + return ofnode_null(); > + } > + > + /* Resolve the phandle to the remote node */ > + remote_node = ofnode_get_by_phandle(phandle_value); > + if (!ofnode_valid(remote_node)) { > + printf("Failed to resolve phandle %u\n", phandle_value); > + return ofnode_null(); > + } > + > + return remote_node; > +} > + > +static enum usb_dr_mode get_connector_drmode(ofnode node) > +{ > + struct gpio_desc id; > + enum usb_dr_mode dr_mode = USB_DR_MODE_OTG; > + ofnode conn; > + > + /* get remote endpoint */ > + conn = get_remote_node_from_graph(node, -1, -1); > + /* get port endpoint */ > + if (ofnode_valid(conn)) > + conn = ofnode_get_parent(conn); > + /* get connector */ > + if (ofnode_valid(conn)) > + conn = ofnode_get_parent(conn); > + if (ofnode_valid(conn) && > + ofnode_device_is_compatible(conn, "gpio-usb-b-connector") && > + !gpio_request_by_name_nodev(conn, "id-gpios", 0, &id, > GPIOD_IS_IN)) { > + if (dm_gpio_get_value(&id)) > + dr_mode = USB_DR_MODE_PERIPHERAL; > + else > + dr_mode = USB_DR_MODE_HOST; > + gpio_free_list_nodev(&id, 1); > + pr_debug("%s got dr_mode from connector %s dr_mode=%s\n", > __func__, > + ofnode_get_name(node), > + dr_mode == USB_DR_MODE_HOST ? "host" : "peripheral"); > + } > + > + return dr_mode; > +} > + > enum usb_dr_mode usb_get_dr_mode(ofnode node) > { > const char *dr_mode; > @@ -35,7 +127,7 @@ enum usb_dr_mode usb_get_dr_mode(ofnode node) > > for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++) > if (!strcmp(dr_mode, usb_dr_modes[i])) > - return i; > + return (i == USB_DR_MODE_OTG) ? > get_connector_drmode(node) : i; > > return USB_DR_MODE_UNKNOWN; > } > -- > 2.25.1 >
Hi Marek, Have you had a chance to review this yet? Best Regards, Tim