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