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", &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