Re: Device tree nodes for USB devices

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <johan@xxxxxxxxxx>
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 <johan@xxxxxxxxxx>
---
 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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux