18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Provides code common for host and device side USB.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * If either host side (ie. CONFIG_USB=y) or device side USB stack
68c2ecf20Sopenharmony_ci * (ie. CONFIG_USB_GADGET=y) is compiled in the kernel, this module is
78c2ecf20Sopenharmony_ci * compiled-in as well.  Otherwise, if either of the two stacks is
88c2ecf20Sopenharmony_ci * compiled as module, this file is compiled as module as well.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/of.h>
148c2ecf20Sopenharmony_ci#include <linux/usb/ch9.h>
158c2ecf20Sopenharmony_ci#include <linux/usb/of.h>
168c2ecf20Sopenharmony_ci#include <linux/usb/otg.h>
178c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
188c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
198c2ecf20Sopenharmony_ci#include "common.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic const char *const ep_type_names[] = {
228c2ecf20Sopenharmony_ci	[USB_ENDPOINT_XFER_CONTROL] = "ctrl",
238c2ecf20Sopenharmony_ci	[USB_ENDPOINT_XFER_ISOC] = "isoc",
248c2ecf20Sopenharmony_ci	[USB_ENDPOINT_XFER_BULK] = "bulk",
258c2ecf20Sopenharmony_ci	[USB_ENDPOINT_XFER_INT] = "intr",
268c2ecf20Sopenharmony_ci};
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/**
298c2ecf20Sopenharmony_ci * usb_ep_type_string() - Returns human readable-name of the endpoint type.
308c2ecf20Sopenharmony_ci * @ep_type: The endpoint type to return human-readable name for.  If it's not
318c2ecf20Sopenharmony_ci *   any of the types: USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT},
328c2ecf20Sopenharmony_ci *   usually got by usb_endpoint_type(), the string 'unknown' will be returned.
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_ciconst char *usb_ep_type_string(int ep_type)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	if (ep_type < 0 || ep_type >= ARRAY_SIZE(ep_type_names))
378c2ecf20Sopenharmony_ci		return "unknown";
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	return ep_type_names[ep_type];
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_ep_type_string);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ciconst char *usb_otg_state_string(enum usb_otg_state state)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	static const char *const names[] = {
468c2ecf20Sopenharmony_ci		[OTG_STATE_A_IDLE] = "a_idle",
478c2ecf20Sopenharmony_ci		[OTG_STATE_A_WAIT_VRISE] = "a_wait_vrise",
488c2ecf20Sopenharmony_ci		[OTG_STATE_A_WAIT_BCON] = "a_wait_bcon",
498c2ecf20Sopenharmony_ci		[OTG_STATE_A_HOST] = "a_host",
508c2ecf20Sopenharmony_ci		[OTG_STATE_A_SUSPEND] = "a_suspend",
518c2ecf20Sopenharmony_ci		[OTG_STATE_A_PERIPHERAL] = "a_peripheral",
528c2ecf20Sopenharmony_ci		[OTG_STATE_A_WAIT_VFALL] = "a_wait_vfall",
538c2ecf20Sopenharmony_ci		[OTG_STATE_A_VBUS_ERR] = "a_vbus_err",
548c2ecf20Sopenharmony_ci		[OTG_STATE_B_IDLE] = "b_idle",
558c2ecf20Sopenharmony_ci		[OTG_STATE_B_SRP_INIT] = "b_srp_init",
568c2ecf20Sopenharmony_ci		[OTG_STATE_B_PERIPHERAL] = "b_peripheral",
578c2ecf20Sopenharmony_ci		[OTG_STATE_B_WAIT_ACON] = "b_wait_acon",
588c2ecf20Sopenharmony_ci		[OTG_STATE_B_HOST] = "b_host",
598c2ecf20Sopenharmony_ci	};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	if (state < 0 || state >= ARRAY_SIZE(names))
628c2ecf20Sopenharmony_ci		return "UNDEFINED";
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	return names[state];
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_otg_state_string);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic const char *const speed_names[] = {
698c2ecf20Sopenharmony_ci	[USB_SPEED_UNKNOWN] = "UNKNOWN",
708c2ecf20Sopenharmony_ci	[USB_SPEED_LOW] = "low-speed",
718c2ecf20Sopenharmony_ci	[USB_SPEED_FULL] = "full-speed",
728c2ecf20Sopenharmony_ci	[USB_SPEED_HIGH] = "high-speed",
738c2ecf20Sopenharmony_ci	[USB_SPEED_WIRELESS] = "wireless",
748c2ecf20Sopenharmony_ci	[USB_SPEED_SUPER] = "super-speed",
758c2ecf20Sopenharmony_ci	[USB_SPEED_SUPER_PLUS] = "super-speed-plus",
768c2ecf20Sopenharmony_ci};
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic const char *const ssp_rate[] = {
798c2ecf20Sopenharmony_ci	[USB_SSP_GEN_UNKNOWN] = "UNKNOWN",
808c2ecf20Sopenharmony_ci	[USB_SSP_GEN_2x1] = "super-speed-plus-gen2x1",
818c2ecf20Sopenharmony_ci	[USB_SSP_GEN_1x2] = "super-speed-plus-gen1x2",
828c2ecf20Sopenharmony_ci	[USB_SSP_GEN_2x2] = "super-speed-plus-gen2x2",
838c2ecf20Sopenharmony_ci};
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/**
868c2ecf20Sopenharmony_ci * usb_speed_string() - Returns human readable-name of the speed.
878c2ecf20Sopenharmony_ci * @speed: The speed to return human-readable name for.  If it's not
888c2ecf20Sopenharmony_ci *   any of the speeds defined in usb_device_speed enum, string for
898c2ecf20Sopenharmony_ci *   USB_SPEED_UNKNOWN will be returned.
908c2ecf20Sopenharmony_ci */
918c2ecf20Sopenharmony_ciconst char *usb_speed_string(enum usb_device_speed speed)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	if (speed < 0 || speed >= ARRAY_SIZE(speed_names))
948c2ecf20Sopenharmony_ci		speed = USB_SPEED_UNKNOWN;
958c2ecf20Sopenharmony_ci	return speed_names[speed];
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_speed_string);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci/**
1008c2ecf20Sopenharmony_ci * usb_get_maximum_speed - Get maximum requested speed for a given USB
1018c2ecf20Sopenharmony_ci * controller.
1028c2ecf20Sopenharmony_ci * @dev: Pointer to the given USB controller device
1038c2ecf20Sopenharmony_ci *
1048c2ecf20Sopenharmony_ci * The function gets the maximum speed string from property "maximum-speed",
1058c2ecf20Sopenharmony_ci * and returns the corresponding enum usb_device_speed.
1068c2ecf20Sopenharmony_ci */
1078c2ecf20Sopenharmony_cienum usb_device_speed usb_get_maximum_speed(struct device *dev)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	const char *maximum_speed;
1108c2ecf20Sopenharmony_ci	int ret;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	ret = device_property_read_string(dev, "maximum-speed", &maximum_speed);
1138c2ecf20Sopenharmony_ci	if (ret < 0)
1148c2ecf20Sopenharmony_ci		return USB_SPEED_UNKNOWN;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	ret = match_string(ssp_rate, ARRAY_SIZE(ssp_rate), maximum_speed);
1178c2ecf20Sopenharmony_ci	if (ret > 0)
1188c2ecf20Sopenharmony_ci		return USB_SPEED_SUPER_PLUS;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	ret = match_string(speed_names, ARRAY_SIZE(speed_names), maximum_speed);
1218c2ecf20Sopenharmony_ci	return (ret < 0) ? USB_SPEED_UNKNOWN : ret;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_get_maximum_speed);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci/**
1268c2ecf20Sopenharmony_ci * usb_get_maximum_ssp_rate - Get the signaling rate generation and lane count
1278c2ecf20Sopenharmony_ci *	of a SuperSpeed Plus capable device.
1288c2ecf20Sopenharmony_ci * @dev: Pointer to the given USB controller device
1298c2ecf20Sopenharmony_ci *
1308c2ecf20Sopenharmony_ci * If the string from "maximum-speed" property is super-speed-plus-genXxY where
1318c2ecf20Sopenharmony_ci * 'X' is the generation number and 'Y' is the number of lanes, then this
1328c2ecf20Sopenharmony_ci * function returns the corresponding enum usb_ssp_rate.
1338c2ecf20Sopenharmony_ci */
1348c2ecf20Sopenharmony_cienum usb_ssp_rate usb_get_maximum_ssp_rate(struct device *dev)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	const char *maximum_speed;
1378c2ecf20Sopenharmony_ci	int ret;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	ret = device_property_read_string(dev, "maximum-speed", &maximum_speed);
1408c2ecf20Sopenharmony_ci	if (ret < 0)
1418c2ecf20Sopenharmony_ci		return USB_SSP_GEN_UNKNOWN;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	ret = match_string(ssp_rate, ARRAY_SIZE(ssp_rate), maximum_speed);
1448c2ecf20Sopenharmony_ci	return (ret < 0) ? USB_SSP_GEN_UNKNOWN : ret;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_get_maximum_ssp_rate);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci/**
1498c2ecf20Sopenharmony_ci * usb_state_string - Returns human readable name for the state.
1508c2ecf20Sopenharmony_ci * @state: The state to return a human-readable name for. If it's not
1518c2ecf20Sopenharmony_ci *	any of the states devices in usb_device_state_string enum,
1528c2ecf20Sopenharmony_ci *	the string UNKNOWN will be returned.
1538c2ecf20Sopenharmony_ci */
1548c2ecf20Sopenharmony_ciconst char *usb_state_string(enum usb_device_state state)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	static const char *const names[] = {
1578c2ecf20Sopenharmony_ci		[USB_STATE_NOTATTACHED] = "not attached",
1588c2ecf20Sopenharmony_ci		[USB_STATE_ATTACHED] = "attached",
1598c2ecf20Sopenharmony_ci		[USB_STATE_POWERED] = "powered",
1608c2ecf20Sopenharmony_ci		[USB_STATE_RECONNECTING] = "reconnecting",
1618c2ecf20Sopenharmony_ci		[USB_STATE_UNAUTHENTICATED] = "unauthenticated",
1628c2ecf20Sopenharmony_ci		[USB_STATE_DEFAULT] = "default",
1638c2ecf20Sopenharmony_ci		[USB_STATE_ADDRESS] = "addressed",
1648c2ecf20Sopenharmony_ci		[USB_STATE_CONFIGURED] = "configured",
1658c2ecf20Sopenharmony_ci		[USB_STATE_SUSPENDED] = "suspended",
1668c2ecf20Sopenharmony_ci	};
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	if (state < 0 || state >= ARRAY_SIZE(names))
1698c2ecf20Sopenharmony_ci		return "UNKNOWN";
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	return names[state];
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_state_string);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic const char *const usb_dr_modes[] = {
1768c2ecf20Sopenharmony_ci	[USB_DR_MODE_UNKNOWN]		= "",
1778c2ecf20Sopenharmony_ci	[USB_DR_MODE_HOST]		= "host",
1788c2ecf20Sopenharmony_ci	[USB_DR_MODE_PERIPHERAL]	= "peripheral",
1798c2ecf20Sopenharmony_ci	[USB_DR_MODE_OTG]		= "otg",
1808c2ecf20Sopenharmony_ci};
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic enum usb_dr_mode usb_get_dr_mode_from_string(const char *str)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	int ret;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	ret = match_string(usb_dr_modes, ARRAY_SIZE(usb_dr_modes), str);
1878c2ecf20Sopenharmony_ci	return (ret < 0) ? USB_DR_MODE_UNKNOWN : ret;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cienum usb_dr_mode usb_get_dr_mode(struct device *dev)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	const char *dr_mode;
1938c2ecf20Sopenharmony_ci	int err;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	err = device_property_read_string(dev, "dr_mode", &dr_mode);
1968c2ecf20Sopenharmony_ci	if (err < 0)
1978c2ecf20Sopenharmony_ci		return USB_DR_MODE_UNKNOWN;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	return usb_get_dr_mode_from_string(dr_mode);
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_get_dr_mode);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci/**
2048c2ecf20Sopenharmony_ci * usb_decode_interval - Decode bInterval into the time expressed in 1us unit
2058c2ecf20Sopenharmony_ci * @epd: The descriptor of the endpoint
2068c2ecf20Sopenharmony_ci * @speed: The speed that the endpoint works as
2078c2ecf20Sopenharmony_ci *
2088c2ecf20Sopenharmony_ci * Function returns the interval expressed in 1us unit for servicing
2098c2ecf20Sopenharmony_ci * endpoint for data transfers.
2108c2ecf20Sopenharmony_ci */
2118c2ecf20Sopenharmony_ciunsigned int usb_decode_interval(const struct usb_endpoint_descriptor *epd,
2128c2ecf20Sopenharmony_ci				 enum usb_device_speed speed)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	unsigned int interval = 0;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	switch (usb_endpoint_type(epd)) {
2178c2ecf20Sopenharmony_ci	case USB_ENDPOINT_XFER_CONTROL:
2188c2ecf20Sopenharmony_ci		/* uframes per NAK */
2198c2ecf20Sopenharmony_ci		if (speed == USB_SPEED_HIGH)
2208c2ecf20Sopenharmony_ci			interval = epd->bInterval;
2218c2ecf20Sopenharmony_ci		break;
2228c2ecf20Sopenharmony_ci	case USB_ENDPOINT_XFER_ISOC:
2238c2ecf20Sopenharmony_ci		interval = 1 << (epd->bInterval - 1);
2248c2ecf20Sopenharmony_ci		break;
2258c2ecf20Sopenharmony_ci	case USB_ENDPOINT_XFER_BULK:
2268c2ecf20Sopenharmony_ci		/* uframes per NAK */
2278c2ecf20Sopenharmony_ci		if (speed == USB_SPEED_HIGH && usb_endpoint_dir_out(epd))
2288c2ecf20Sopenharmony_ci			interval = epd->bInterval;
2298c2ecf20Sopenharmony_ci		break;
2308c2ecf20Sopenharmony_ci	case USB_ENDPOINT_XFER_INT:
2318c2ecf20Sopenharmony_ci		if (speed >= USB_SPEED_HIGH)
2328c2ecf20Sopenharmony_ci			interval = 1 << (epd->bInterval - 1);
2338c2ecf20Sopenharmony_ci		else
2348c2ecf20Sopenharmony_ci			interval = epd->bInterval;
2358c2ecf20Sopenharmony_ci		break;
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	interval *= (speed >= USB_SPEED_HIGH) ? 125 : 1000;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	return interval;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_decode_interval);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
2458c2ecf20Sopenharmony_ci/**
2468c2ecf20Sopenharmony_ci * of_usb_get_dr_mode_by_phy - Get dual role mode for the controller device
2478c2ecf20Sopenharmony_ci * which is associated with the given phy device_node
2488c2ecf20Sopenharmony_ci * @np:	Pointer to the given phy device_node
2498c2ecf20Sopenharmony_ci * @arg0: phandle args[0] for phy's with #phy-cells >= 1, or -1 for
2508c2ecf20Sopenharmony_ci *        phys which do not have phy-cells
2518c2ecf20Sopenharmony_ci *
2528c2ecf20Sopenharmony_ci * In dts a usb controller associates with phy devices.  The function gets
2538c2ecf20Sopenharmony_ci * the string from property 'dr_mode' of the controller associated with the
2548c2ecf20Sopenharmony_ci * given phy device node, and returns the correspondig enum usb_dr_mode.
2558c2ecf20Sopenharmony_ci */
2568c2ecf20Sopenharmony_cienum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	struct device_node *controller = NULL;
2598c2ecf20Sopenharmony_ci	struct of_phandle_args args;
2608c2ecf20Sopenharmony_ci	const char *dr_mode;
2618c2ecf20Sopenharmony_ci	int index;
2628c2ecf20Sopenharmony_ci	int err;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	do {
2658c2ecf20Sopenharmony_ci		controller = of_find_node_with_property(controller, "phys");
2668c2ecf20Sopenharmony_ci		if (!of_device_is_available(controller))
2678c2ecf20Sopenharmony_ci			continue;
2688c2ecf20Sopenharmony_ci		index = 0;
2698c2ecf20Sopenharmony_ci		do {
2708c2ecf20Sopenharmony_ci			if (arg0 == -1) {
2718c2ecf20Sopenharmony_ci				args.np = of_parse_phandle(controller, "phys",
2728c2ecf20Sopenharmony_ci							index);
2738c2ecf20Sopenharmony_ci				args.args_count = 0;
2748c2ecf20Sopenharmony_ci			} else {
2758c2ecf20Sopenharmony_ci				err = of_parse_phandle_with_args(controller,
2768c2ecf20Sopenharmony_ci							"phys", "#phy-cells",
2778c2ecf20Sopenharmony_ci							index, &args);
2788c2ecf20Sopenharmony_ci				if (err)
2798c2ecf20Sopenharmony_ci					break;
2808c2ecf20Sopenharmony_ci			}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci			of_node_put(args.np);
2838c2ecf20Sopenharmony_ci			if (args.np == np && (args.args_count == 0 ||
2848c2ecf20Sopenharmony_ci					      args.args[0] == arg0))
2858c2ecf20Sopenharmony_ci				goto finish;
2868c2ecf20Sopenharmony_ci			index++;
2878c2ecf20Sopenharmony_ci		} while (args.np);
2888c2ecf20Sopenharmony_ci	} while (controller);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cifinish:
2918c2ecf20Sopenharmony_ci	err = of_property_read_string(controller, "dr_mode", &dr_mode);
2928c2ecf20Sopenharmony_ci	of_node_put(controller);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	if (err < 0)
2958c2ecf20Sopenharmony_ci		return USB_DR_MODE_UNKNOWN;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	return usb_get_dr_mode_from_string(dr_mode);
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_usb_get_dr_mode_by_phy);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci/**
3028c2ecf20Sopenharmony_ci * of_usb_host_tpl_support - to get if Targeted Peripheral List is supported
3038c2ecf20Sopenharmony_ci * for given targeted hosts (non-PC hosts)
3048c2ecf20Sopenharmony_ci * @np: Pointer to the given device_node
3058c2ecf20Sopenharmony_ci *
3068c2ecf20Sopenharmony_ci * The function gets if the targeted hosts support TPL or not
3078c2ecf20Sopenharmony_ci */
3088c2ecf20Sopenharmony_cibool of_usb_host_tpl_support(struct device_node *np)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	return of_property_read_bool(np, "tpl-support");
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_usb_host_tpl_support);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci/**
3158c2ecf20Sopenharmony_ci * of_usb_update_otg_caps - to update usb otg capabilities according to
3168c2ecf20Sopenharmony_ci * the passed properties in DT.
3178c2ecf20Sopenharmony_ci * @np: Pointer to the given device_node
3188c2ecf20Sopenharmony_ci * @otg_caps: Pointer to the target usb_otg_caps to be set
3198c2ecf20Sopenharmony_ci *
3208c2ecf20Sopenharmony_ci * The function updates the otg capabilities
3218c2ecf20Sopenharmony_ci */
3228c2ecf20Sopenharmony_ciint of_usb_update_otg_caps(struct device_node *np,
3238c2ecf20Sopenharmony_ci			struct usb_otg_caps *otg_caps)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	u32 otg_rev;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	if (!otg_caps)
3288c2ecf20Sopenharmony_ci		return -EINVAL;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (!of_property_read_u32(np, "otg-rev", &otg_rev)) {
3318c2ecf20Sopenharmony_ci		switch (otg_rev) {
3328c2ecf20Sopenharmony_ci		case 0x0100:
3338c2ecf20Sopenharmony_ci		case 0x0120:
3348c2ecf20Sopenharmony_ci		case 0x0130:
3358c2ecf20Sopenharmony_ci		case 0x0200:
3368c2ecf20Sopenharmony_ci			/* Choose the lesser one if it's already been set */
3378c2ecf20Sopenharmony_ci			if (otg_caps->otg_rev)
3388c2ecf20Sopenharmony_ci				otg_caps->otg_rev = min_t(u16, otg_rev,
3398c2ecf20Sopenharmony_ci							otg_caps->otg_rev);
3408c2ecf20Sopenharmony_ci			else
3418c2ecf20Sopenharmony_ci				otg_caps->otg_rev = otg_rev;
3428c2ecf20Sopenharmony_ci			break;
3438c2ecf20Sopenharmony_ci		default:
3448c2ecf20Sopenharmony_ci			pr_err("%pOF: unsupported otg-rev: 0x%x\n",
3458c2ecf20Sopenharmony_ci						np, otg_rev);
3468c2ecf20Sopenharmony_ci			return -EINVAL;
3478c2ecf20Sopenharmony_ci		}
3488c2ecf20Sopenharmony_ci	} else {
3498c2ecf20Sopenharmony_ci		/*
3508c2ecf20Sopenharmony_ci		 * otg-rev is mandatory for otg properties, if not passed
3518c2ecf20Sopenharmony_ci		 * we set it to be 0 and assume it's a legacy otg device.
3528c2ecf20Sopenharmony_ci		 * Non-dt platform can set it afterwards.
3538c2ecf20Sopenharmony_ci		 */
3548c2ecf20Sopenharmony_ci		otg_caps->otg_rev = 0;
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	if (of_property_read_bool(np, "hnp-disable"))
3588c2ecf20Sopenharmony_ci		otg_caps->hnp_support = false;
3598c2ecf20Sopenharmony_ci	if (of_property_read_bool(np, "srp-disable"))
3608c2ecf20Sopenharmony_ci		otg_caps->srp_support = false;
3618c2ecf20Sopenharmony_ci	if (of_property_read_bool(np, "adp-disable") ||
3628c2ecf20Sopenharmony_ci				(otg_caps->otg_rev < 0x0200))
3638c2ecf20Sopenharmony_ci		otg_caps->adp_support = false;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	return 0;
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_usb_update_otg_caps);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci/**
3708c2ecf20Sopenharmony_ci * usb_of_get_companion_dev - Find the companion device
3718c2ecf20Sopenharmony_ci * @dev: the device pointer to find a companion
3728c2ecf20Sopenharmony_ci *
3738c2ecf20Sopenharmony_ci * Find the companion device from platform bus.
3748c2ecf20Sopenharmony_ci *
3758c2ecf20Sopenharmony_ci * Takes a reference to the returned struct device which needs to be dropped
3768c2ecf20Sopenharmony_ci * after use.
3778c2ecf20Sopenharmony_ci *
3788c2ecf20Sopenharmony_ci * Return: On success, a pointer to the companion device, %NULL on failure.
3798c2ecf20Sopenharmony_ci */
3808c2ecf20Sopenharmony_cistruct device *usb_of_get_companion_dev(struct device *dev)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	struct device_node *node;
3838c2ecf20Sopenharmony_ci	struct platform_device *pdev = NULL;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	node = of_parse_phandle(dev->of_node, "companion", 0);
3868c2ecf20Sopenharmony_ci	if (node)
3878c2ecf20Sopenharmony_ci		pdev = of_find_device_by_node(node);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	of_node_put(node);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	return pdev ? &pdev->dev : NULL;
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_of_get_companion_dev);
3948c2ecf20Sopenharmony_ci#endif
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_cistruct dentry *usb_debug_root;
3978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_debug_root);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic int __init usb_common_init(void)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	usb_debug_root = debugfs_create_dir("usb", NULL);
4028c2ecf20Sopenharmony_ci	ledtrig_usb_init();
4038c2ecf20Sopenharmony_ci	return 0;
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_cistatic void __exit usb_common_exit(void)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	ledtrig_usb_exit();
4098c2ecf20Sopenharmony_ci	debugfs_remove_recursive(usb_debug_root);
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cisubsys_initcall(usb_common_init);
4138c2ecf20Sopenharmony_cimodule_exit(usb_common_exit);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
416