On Mon, May 29, 2017 at 04:15:36PM +0200, Johan Hovold wrote:
> On Mon, May 29, 2017 at 11:01:52AM +0200, Martin Fuzzey wrote:

> > However my larger question is that I don't see how to associate a DT 
> > node with a USB *interface* rather than a USB *device*.
> 
> I started looking into this a while back but got interrupted. I have
> some preliminary code, mostly lacking associated documentation.

> I'll post my work as an RFC shortly, and add you on CC.

Here's a preview.

Johan


>From 5db86d55975ef0e047ab3157d59de0869aa88acf Mon Sep 17 00:00:00 2001
From: Johan Hovold <jo...@kernel.org>
Date: Fri, 21 Apr 2017 19:55:59 +0200
Subject: [RFC] USB: of: add support for interface nodes

Add support for USB-interface OF-nodes. Interfaces are children of
USB-device nodes and are identified by a configuration value and an
interface number:

        &usb1 {                 /* root hub */
                device@1 {      /* device at port 1 */
                        compatible = <usb1234,5678>;
                        reg = <1>;

                        device@1,0 { /* interface 0 of configuration 1 */
                                compatible = <usbif1234,5678,config1.0>;
                                reg = <1 0>;
                        };
                };
        };

FIXME: documentation, mention spec

Not-Signed-off-yet-by: Johan Hovold <jo...@kernel.org>
---
 drivers/usb/core/message.c | 14 +++++++++-----
 drivers/usb/core/of.c      | 30 ++++++++++++++++++++++++++++++
 include/linux/usb/of.h     |  9 +++++++++
 3 files changed, 48 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 4c38ea41ae96..921b66e34a03 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -18,6 +18,7 @@
 #include <linux/usb/cdc.h>
 #include <linux/usb/quirks.h>
 #include <linux/usb/hcd.h>     /* for usbcore internals */
+#include <linux/usb/of.h>
 #include <asm/byteorder.h>
 
 #include "usb.h"
@@ -1548,6 +1549,7 @@ static void usb_release_interface(struct device *dev)
 
        kref_put(&intfc->ref, usb_release_interface_cache);
        usb_put_dev(interface_to_usbdev(intf));
+       of_node_put(dev->of_node);
        kfree(intf);
 }
 
@@ -1833,6 +1835,7 @@ int usb_set_configuration(struct usb_device *dev, int 
configuration)
                struct usb_interface_cache *intfc;
                struct usb_interface *intf;
                struct usb_host_interface *alt;
+               u8 ifnum;
 
                cp->interface[i] = intf = new_interfaces[i];
                intfc = cp->intf_cache[i];
@@ -1851,11 +1854,13 @@ int usb_set_configuration(struct usb_device *dev, int 
configuration)
                if (!alt)
                        alt = &intf->altsetting[0];
 
-               intf->intf_assoc =
-                       find_iad(dev, cp, alt->desc.bInterfaceNumber);
+               ifnum = alt->desc.bInterfaceNumber;
+               intf->intf_assoc = find_iad(dev, cp, ifnum);
                intf->cur_altsetting = alt;
                usb_enable_interface(dev, intf, true);
                intf->dev.parent = &dev->dev;
+               intf->dev.of_node = usb_of_find_interface_node(dev,
+                               configuration, ifnum);
                intf->dev.driver = NULL;
                intf->dev.bus = &usb_bus_type;
                intf->dev.type = &usb_if_device_type;
@@ -1870,9 +1875,8 @@ int usb_set_configuration(struct usb_device *dev, int 
configuration)
                intf->minor = -1;
                device_initialize(&intf->dev);
                pm_runtime_no_callbacks(&intf->dev);
-               dev_set_name(&intf->dev, "%d-%s:%d.%d",
-                       dev->bus->busnum, dev->devpath,
-                       configuration, alt->desc.bInterfaceNumber);
+               dev_set_name(&intf->dev, "%d-%s:%d.%d", dev->bus->busnum,
+                               dev->devpath, configuration, ifnum);
                usb_get_dev(dev);
        }
        kfree(new_interfaces);
diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c
index 17a4af02cf5b..87e257eb8eeb 100644
--- a/drivers/usb/core/of.c
+++ b/drivers/usb/core/of.c
@@ -51,6 +51,36 @@ struct device_node *usb_of_get_child_node(struct device_node 
*parent,
 EXPORT_SYMBOL_GPL(usb_of_get_child_node);
 
 /**
+ * usb_of_find_interface_node() - find a USB-interface device node
+ * @udev: USB device of interface
+ * @config: configuration value
+ * @ifnum: interface number
+ *
+ * Look up the device node of an interface given its USB device, configuration
+ * value, and interface number.
+ *
+ * Return: A pointer to the node with incremented refcount if found, or
+ * %NULL otherwise.
+ */
+struct device_node *usb_of_find_interface_node(struct usb_device *udev,
+               u8 config, u8 ifnum)
+{
+       struct device_node *node;
+       u32 reg[2];
+
+       for_each_child_of_node(udev->dev.of_node, node) {
+               if (of_property_read_u32_array(node, "reg", reg, 2))
+                       continue;
+
+               if (reg[0] == config && reg[1] == ifnum)
+                       return node;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(usb_of_find_interface_node);
+
+/**
  * usb_of_get_companion_dev - Find the companion device
  * @dev: the device pointer to find a companion
  *
diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h
index 4031f47629ec..27d9ed28e734 100644
--- a/include/linux/usb/of.h
+++ b/include/linux/usb/of.h
@@ -11,6 +11,8 @@
 #include <linux/usb/otg.h>
 #include <linux/usb/phy.h>
 
+struct usb_device;
+
 #if IS_ENABLED(CONFIG_OF)
 enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0);
 bool of_usb_host_tpl_support(struct device_node *np);
@@ -18,6 +20,8 @@ int of_usb_update_otg_caps(struct device_node *np,
                        struct usb_otg_caps *otg_caps);
 struct device_node *usb_of_get_child_node(struct device_node *parent,
                        int portnum);
+struct device_node *usb_of_find_interface_node(struct usb_device *udev,
+               u8 config, u8 ifnum);
 struct device *usb_of_get_companion_dev(struct device *dev);
 #else
 static inline enum usb_dr_mode
@@ -39,6 +43,11 @@ static inline struct device_node *usb_of_get_child_node
 {
        return NULL;
 }
+struct device_node *usb_of_find_interface_node(struct usb_device *udev,
+               u8 config, u8 ifnum);
+{
+       return NULL;
+}
 static inline struct device *usb_of_get_companion_dev(struct device *dev)
 {
        return NULL;
-- 
2.13.0

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to