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

Reply via email to