[v2 PATCH 1/2] usb: common: allow dr_mode to come from gpio-id based usb-connector
Tim Harvey
tharvey at gateworks.com
Thu Jul 17 19:17:35 CEST 2025
On Wed, Jul 9, 2025 at 8:36 AM Tim Harvey <tharvey at 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 <tharvey at 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 at 0, or -1 for first port)
> + * @endpoint_id: Endpoint unit address (e.g., 0 for endpoint at 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 at 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 at 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
More information about the U-Boot
mailing list