18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * of.c The helpers for hcd device tree support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016 Freescale Semiconductor, Inc. 68c2ecf20Sopenharmony_ci * Author: Peter Chen <peter.chen@freescale.com> 78c2ecf20Sopenharmony_ci * Copyright (C) 2017 Johan Hovold <johan@kernel.org> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/of.h> 118c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 128c2ecf20Sopenharmony_ci#include <linux/usb/of.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/** 158c2ecf20Sopenharmony_ci * usb_of_get_device_node() - get a USB device node 168c2ecf20Sopenharmony_ci * @hub: hub to which device is connected 178c2ecf20Sopenharmony_ci * @port1: one-based index of port 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Look up the node of a USB device given its parent hub device and one-based 208c2ecf20Sopenharmony_ci * port number. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Return: A pointer to the node with incremented refcount if found, or 238c2ecf20Sopenharmony_ci * %NULL otherwise. 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_cistruct device_node *usb_of_get_device_node(struct usb_device *hub, int port1) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct device_node *node; 288c2ecf20Sopenharmony_ci u32 reg; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci for_each_child_of_node(hub->dev.of_node, node) { 318c2ecf20Sopenharmony_ci if (of_property_read_u32(node, "reg", ®)) 328c2ecf20Sopenharmony_ci continue; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (reg == port1) 358c2ecf20Sopenharmony_ci return node; 368c2ecf20Sopenharmony_ci } 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci return NULL; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_of_get_device_node); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/** 438c2ecf20Sopenharmony_ci * usb_of_has_combined_node() - determine whether a device has a combined node 448c2ecf20Sopenharmony_ci * @udev: USB device 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * Determine whether a USB device has a so called combined node which is 478c2ecf20Sopenharmony_ci * shared with its sole interface. This is the case if and only if the device 488c2ecf20Sopenharmony_ci * has a node and its descriptors report the following: 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * 1) bDeviceClass is 0 or 9, and 518c2ecf20Sopenharmony_ci * 2) bNumConfigurations is 1, and 528c2ecf20Sopenharmony_ci * 3) bNumInterfaces is 1. 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * Return: True iff the device has a device node and its descriptors match the 558c2ecf20Sopenharmony_ci * criteria for a combined node. 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_cibool usb_of_has_combined_node(struct usb_device *udev) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct usb_device_descriptor *ddesc = &udev->descriptor; 608c2ecf20Sopenharmony_ci struct usb_config_descriptor *cdesc; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (!udev->dev.of_node) 638c2ecf20Sopenharmony_ci return false; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci switch (ddesc->bDeviceClass) { 668c2ecf20Sopenharmony_ci case USB_CLASS_PER_INTERFACE: 678c2ecf20Sopenharmony_ci case USB_CLASS_HUB: 688c2ecf20Sopenharmony_ci if (ddesc->bNumConfigurations == 1) { 698c2ecf20Sopenharmony_ci cdesc = &udev->config->desc; 708c2ecf20Sopenharmony_ci if (cdesc->bNumInterfaces == 1) 718c2ecf20Sopenharmony_ci return true; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return false; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_of_has_combined_node); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/** 808c2ecf20Sopenharmony_ci * usb_of_get_interface_node() - get a USB interface node 818c2ecf20Sopenharmony_ci * @udev: USB device of interface 828c2ecf20Sopenharmony_ci * @config: configuration value 838c2ecf20Sopenharmony_ci * @ifnum: interface number 848c2ecf20Sopenharmony_ci * 858c2ecf20Sopenharmony_ci * Look up the node of a USB interface given its USB device, configuration 868c2ecf20Sopenharmony_ci * value and interface number. 878c2ecf20Sopenharmony_ci * 888c2ecf20Sopenharmony_ci * Return: A pointer to the node with incremented refcount if found, or 898c2ecf20Sopenharmony_ci * %NULL otherwise. 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_cistruct device_node * 928c2ecf20Sopenharmony_ciusb_of_get_interface_node(struct usb_device *udev, u8 config, u8 ifnum) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci struct device_node *node; 958c2ecf20Sopenharmony_ci u32 reg[2]; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci for_each_child_of_node(udev->dev.of_node, node) { 988c2ecf20Sopenharmony_ci if (of_property_read_u32_array(node, "reg", reg, 2)) 998c2ecf20Sopenharmony_ci continue; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (reg[0] == ifnum && reg[1] == config) 1028c2ecf20Sopenharmony_ci return node; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci return NULL; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_of_get_interface_node); 108