xref: /openbmc/linux/drivers/usb/core/of.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
269bec725SPeter Chen /*
369bec725SPeter Chen  * of.c		The helpers for hcd device tree support
469bec725SPeter Chen  *
569bec725SPeter Chen  * Copyright (C) 2016 Freescale Semiconductor, Inc.
669bec725SPeter Chen  *	Author: Peter Chen <peter.chen@freescale.com>
71a7e3948SJohan Hovold  * Copyright (C) 2017 Johan Hovold <johan@kernel.org>
869bec725SPeter Chen  */
969bec725SPeter Chen 
1069bec725SPeter Chen #include <linux/of.h>
110573f2c5SPeter Chen #include <linux/usb/of.h>
1269bec725SPeter Chen 
1369bec725SPeter Chen /**
147739376eSJohan Hovold  * usb_of_get_device_node() - get a USB device node
157739376eSJohan Hovold  * @hub: hub to which device is connected
167739376eSJohan Hovold  * @port1: one-based index of port
1769bec725SPeter Chen  *
187739376eSJohan Hovold  * Look up the node of a USB device given its parent hub device and one-based
197739376eSJohan Hovold  * port number.
2069bec725SPeter Chen  *
2160a93cffSJohan Hovold  * Return: A pointer to the node with incremented refcount if found, or
2260a93cffSJohan Hovold  * %NULL otherwise.
2369bec725SPeter Chen  */
usb_of_get_device_node(struct usb_device * hub,int port1)247739376eSJohan Hovold struct device_node *usb_of_get_device_node(struct usb_device *hub, int port1)
2569bec725SPeter Chen {
2669bec725SPeter Chen 	struct device_node *node;
277739376eSJohan Hovold 	u32 reg;
2869bec725SPeter Chen 
297739376eSJohan Hovold 	for_each_child_of_node(hub->dev.of_node, node) {
307739376eSJohan Hovold 		if (of_property_read_u32(node, "reg", &reg))
317739376eSJohan Hovold 			continue;
327739376eSJohan Hovold 
337739376eSJohan Hovold 		if (reg == port1)
3469bec725SPeter Chen 			return node;
3569bec725SPeter Chen 	}
3669bec725SPeter Chen 
3769bec725SPeter Chen 	return NULL;
3869bec725SPeter Chen }
397739376eSJohan Hovold EXPORT_SYMBOL_GPL(usb_of_get_device_node);
4069bec725SPeter Chen 
415095cb89SYoshihiro Shimoda /**
421a7e3948SJohan Hovold  * usb_of_has_combined_node() - determine whether a device has a combined node
431a7e3948SJohan Hovold  * @udev: USB device
441a7e3948SJohan Hovold  *
451a7e3948SJohan Hovold  * Determine whether a USB device has a so called combined node which is
461a7e3948SJohan Hovold  * shared with its sole interface. This is the case if and only if the device
47*9f3aedbeSKieran Bingham  * has a node and its descriptors report the following:
481a7e3948SJohan Hovold  *
491a7e3948SJohan Hovold  *	1) bDeviceClass is 0 or 9, and
501a7e3948SJohan Hovold  *	2) bNumConfigurations is 1, and
511a7e3948SJohan Hovold  *	3) bNumInterfaces is 1.
521a7e3948SJohan Hovold  *
531a7e3948SJohan Hovold  * Return: True iff the device has a device node and its descriptors match the
541a7e3948SJohan Hovold  * criteria for a combined node.
551a7e3948SJohan Hovold  */
usb_of_has_combined_node(struct usb_device * udev)561a7e3948SJohan Hovold bool usb_of_has_combined_node(struct usb_device *udev)
571a7e3948SJohan Hovold {
581a7e3948SJohan Hovold 	struct usb_device_descriptor *ddesc = &udev->descriptor;
591a7e3948SJohan Hovold 	struct usb_config_descriptor *cdesc;
601a7e3948SJohan Hovold 
611a7e3948SJohan Hovold 	if (!udev->dev.of_node)
621a7e3948SJohan Hovold 		return false;
631a7e3948SJohan Hovold 
641a7e3948SJohan Hovold 	switch (ddesc->bDeviceClass) {
651a7e3948SJohan Hovold 	case USB_CLASS_PER_INTERFACE:
661a7e3948SJohan Hovold 	case USB_CLASS_HUB:
671a7e3948SJohan Hovold 		if (ddesc->bNumConfigurations == 1) {
681a7e3948SJohan Hovold 			cdesc = &udev->config->desc;
691a7e3948SJohan Hovold 			if (cdesc->bNumInterfaces == 1)
701a7e3948SJohan Hovold 				return true;
711a7e3948SJohan Hovold 		}
721a7e3948SJohan Hovold 	}
731a7e3948SJohan Hovold 
741a7e3948SJohan Hovold 	return false;
751a7e3948SJohan Hovold }
761a7e3948SJohan Hovold EXPORT_SYMBOL_GPL(usb_of_has_combined_node);
771a7e3948SJohan Hovold 
781a7e3948SJohan Hovold /**
791a7e3948SJohan Hovold  * usb_of_get_interface_node() - get a USB interface node
801a7e3948SJohan Hovold  * @udev: USB device of interface
811a7e3948SJohan Hovold  * @config: configuration value
821a7e3948SJohan Hovold  * @ifnum: interface number
831a7e3948SJohan Hovold  *
841a7e3948SJohan Hovold  * Look up the node of a USB interface given its USB device, configuration
851a7e3948SJohan Hovold  * value and interface number.
861a7e3948SJohan Hovold  *
871a7e3948SJohan Hovold  * Return: A pointer to the node with incremented refcount if found, or
881a7e3948SJohan Hovold  * %NULL otherwise.
891a7e3948SJohan Hovold  */
901a7e3948SJohan Hovold struct device_node *
usb_of_get_interface_node(struct usb_device * udev,u8 config,u8 ifnum)911a7e3948SJohan Hovold usb_of_get_interface_node(struct usb_device *udev, u8 config, u8 ifnum)
921a7e3948SJohan Hovold {
931a7e3948SJohan Hovold 	struct device_node *node;
941a7e3948SJohan Hovold 	u32 reg[2];
951a7e3948SJohan Hovold 
961a7e3948SJohan Hovold 	for_each_child_of_node(udev->dev.of_node, node) {
971a7e3948SJohan Hovold 		if (of_property_read_u32_array(node, "reg", reg, 2))
981a7e3948SJohan Hovold 			continue;
991a7e3948SJohan Hovold 
1001a7e3948SJohan Hovold 		if (reg[0] == ifnum && reg[1] == config)
1011a7e3948SJohan Hovold 			return node;
1021a7e3948SJohan Hovold 	}
1031a7e3948SJohan Hovold 
1041a7e3948SJohan Hovold 	return NULL;
1051a7e3948SJohan Hovold }
1061a7e3948SJohan Hovold EXPORT_SYMBOL_GPL(usb_of_get_interface_node);
107