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