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", ®))
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