2017-11-03 11:28:30 +01:00
// SPDX-License-Identifier: GPL-2.0
2011-08-30 17:11:19 +02:00
/*
* Provides code common for host and device side USB .
*
* If either host side ( ie . CONFIG_USB = y ) or device side USB stack
* ( ie . CONFIG_USB_GADGET = y ) is compiled in the kernel , this module is
* compiled - in as well . Otherwise , if either of the two stacks is
* compiled as module , this file is compiled as module as well .
*/
# include <linux/kernel.h>
# include <linux/module.h>
2013-06-13 17:59:55 +03:00
# include <linux/of.h>
2023-07-18 08:30:23 -06:00
# include <linux/platform_device.h>
2011-08-30 17:11:19 +02:00
# include <linux/usb/ch9.h>
2013-06-13 17:59:55 +03:00
# include <linux/usb/of.h>
2013-03-07 10:45:56 +02:00
# include <linux/usb/otg.h>
2015-11-03 11:51:15 -06:00
# include <linux/of_platform.h>
2019-06-05 14:44:40 +02:00
# include <linux/debugfs.h>
# include "common.h"
2013-03-07 10:45:56 +02:00
2019-03-21 10:27:56 +08:00
static const char * const ep_type_names [ ] = {
[ USB_ENDPOINT_XFER_CONTROL ] = " ctrl " ,
[ USB_ENDPOINT_XFER_ISOC ] = " isoc " ,
[ USB_ENDPOINT_XFER_BULK ] = " bulk " ,
[ USB_ENDPOINT_XFER_INT ] = " intr " ,
} ;
2021-03-08 10:52:07 +08:00
/**
* usb_ep_type_string ( ) - Returns human readable - name of the endpoint type .
* @ ep_type : The endpoint type to return human - readable name for . If it ' s not
* any of the types : USB_ENDPOINT_XFER_ { CONTROL , ISOC , BULK , INT } ,
* usually got by usb_endpoint_type ( ) , the string ' unknown ' will be returned .
*/
2019-03-21 10:27:56 +08:00
const char * usb_ep_type_string ( int ep_type )
{
if ( ep_type < 0 | | ep_type > = ARRAY_SIZE ( ep_type_names ) )
return " unknown " ;
return ep_type_names [ ep_type ] ;
}
EXPORT_SYMBOL_GPL ( usb_ep_type_string ) ;
2013-03-07 10:45:56 +02:00
const char * usb_otg_state_string ( enum usb_otg_state state )
{
static const char * const names [ ] = {
[ OTG_STATE_A_IDLE ] = " a_idle " ,
[ OTG_STATE_A_WAIT_VRISE ] = " a_wait_vrise " ,
[ OTG_STATE_A_WAIT_BCON ] = " a_wait_bcon " ,
[ OTG_STATE_A_HOST ] = " a_host " ,
[ OTG_STATE_A_SUSPEND ] = " a_suspend " ,
[ OTG_STATE_A_PERIPHERAL ] = " a_peripheral " ,
[ OTG_STATE_A_WAIT_VFALL ] = " a_wait_vfall " ,
[ OTG_STATE_A_VBUS_ERR ] = " a_vbus_err " ,
[ OTG_STATE_B_IDLE ] = " b_idle " ,
[ OTG_STATE_B_SRP_INIT ] = " b_srp_init " ,
[ OTG_STATE_B_PERIPHERAL ] = " b_peripheral " ,
[ OTG_STATE_B_WAIT_ACON ] = " b_wait_acon " ,
[ OTG_STATE_B_HOST ] = " b_host " ,
} ;
if ( state < 0 | | state > = ARRAY_SIZE ( names ) )
return " UNDEFINED " ;
return names [ state ] ;
}
EXPORT_SYMBOL_GPL ( usb_otg_state_string ) ;
2011-08-30 17:11:19 +02:00
2013-06-30 13:56:45 +03:00
static const char * const speed_names [ ] = {
[ USB_SPEED_UNKNOWN ] = " UNKNOWN " ,
[ USB_SPEED_LOW ] = " low-speed " ,
[ USB_SPEED_FULL ] = " full-speed " ,
[ USB_SPEED_HIGH ] = " high-speed " ,
[ USB_SPEED_WIRELESS ] = " wireless " ,
[ USB_SPEED_SUPER ] = " super-speed " ,
2015-12-10 09:59:25 +02:00
[ USB_SPEED_SUPER_PLUS ] = " super-speed-plus " ,
2013-06-30 13:56:45 +03:00
} ;
2021-01-19 17:36:14 -08:00
static const char * const ssp_rate [ ] = {
[ USB_SSP_GEN_UNKNOWN ] = " UNKNOWN " ,
[ USB_SSP_GEN_2x1 ] = " super-speed-plus-gen2x1 " ,
[ USB_SSP_GEN_1x2 ] = " super-speed-plus-gen1x2 " ,
[ USB_SSP_GEN_2x2 ] = " super-speed-plus-gen2x2 " ,
} ;
2021-03-08 10:52:07 +08:00
/**
* usb_speed_string ( ) - Returns human readable - name of the speed .
* @ speed : The speed to return human - readable name for . If it ' s not
* any of the speeds defined in usb_device_speed enum , string for
* USB_SPEED_UNKNOWN will be returned .
*/
2011-08-30 17:11:19 +02:00
const char * usb_speed_string ( enum usb_device_speed speed )
{
2013-06-30 13:56:45 +03:00
if ( speed < 0 | | speed > = ARRAY_SIZE ( speed_names ) )
2011-08-30 17:11:19 +02:00
speed = USB_SPEED_UNKNOWN ;
2013-06-30 13:56:45 +03:00
return speed_names [ speed ] ;
2011-08-30 17:11:19 +02:00
}
EXPORT_SYMBOL_GPL ( usb_speed_string ) ;
2021-03-08 10:52:07 +08:00
/**
* usb_get_maximum_speed - Get maximum requested speed for a given USB
* controller .
* @ dev : Pointer to the given USB controller device
*
* The function gets the maximum speed string from property " maximum-speed " ,
* and returns the corresponding enum usb_device_speed .
*/
2015-09-21 11:14:32 +03:00
enum usb_device_speed usb_get_maximum_speed ( struct device * dev )
{
const char * maximum_speed ;
2016-03-17 14:22:38 -07:00
int ret ;
2015-09-21 11:14:32 +03:00
2016-03-17 14:22:38 -07:00
ret = device_property_read_string ( dev , " maximum-speed " , & maximum_speed ) ;
if ( ret < 0 )
2015-09-21 11:14:32 +03:00
return USB_SPEED_UNKNOWN ;
2021-01-19 17:36:14 -08:00
ret = match_string ( ssp_rate , ARRAY_SIZE ( ssp_rate ) , maximum_speed ) ;
if ( ret > 0 )
return USB_SPEED_SUPER_PLUS ;
2015-09-21 11:14:32 +03:00
2021-01-19 17:36:14 -08:00
ret = match_string ( speed_names , ARRAY_SIZE ( speed_names ) , maximum_speed ) ;
2016-03-17 14:22:38 -07:00
return ( ret < 0 ) ? USB_SPEED_UNKNOWN : ret ;
2015-09-21 11:14:32 +03:00
}
EXPORT_SYMBOL_GPL ( usb_get_maximum_speed ) ;
2021-03-08 10:52:07 +08:00
/**
* usb_get_maximum_ssp_rate - Get the signaling rate generation and lane count
* of a SuperSpeed Plus capable device .
* @ dev : Pointer to the given USB controller device
*
* If the string from " maximum-speed " property is super - speed - plus - genXxY where
* ' X ' is the generation number and ' Y ' is the number of lanes , then this
* function returns the corresponding enum usb_ssp_rate .
*/
2021-01-19 17:36:14 -08:00
enum usb_ssp_rate usb_get_maximum_ssp_rate ( struct device * dev )
{
const char * maximum_speed ;
int ret ;
ret = device_property_read_string ( dev , " maximum-speed " , & maximum_speed ) ;
if ( ret < 0 )
return USB_SSP_GEN_UNKNOWN ;
ret = match_string ( ssp_rate , ARRAY_SIZE ( ssp_rate ) , maximum_speed ) ;
return ( ret < 0 ) ? USB_SSP_GEN_UNKNOWN : ret ;
}
EXPORT_SYMBOL_GPL ( usb_get_maximum_ssp_rate ) ;
2021-03-08 10:52:07 +08:00
/**
* usb_state_string - Returns human readable name for the state .
* @ state : The state to return a human - readable name for . If it ' s not
* any of the states devices in usb_device_state_string enum ,
* the string UNKNOWN will be returned .
*/
2013-01-24 22:29:48 +02:00
const char * usb_state_string ( enum usb_device_state state )
{
static const char * const names [ ] = {
[ USB_STATE_NOTATTACHED ] = " not attached " ,
[ USB_STATE_ATTACHED ] = " attached " ,
[ USB_STATE_POWERED ] = " powered " ,
[ USB_STATE_RECONNECTING ] = " reconnecting " ,
[ USB_STATE_UNAUTHENTICATED ] = " unauthenticated " ,
[ USB_STATE_DEFAULT ] = " default " ,
2014-04-09 14:48:58 +08:00
[ USB_STATE_ADDRESS ] = " addressed " ,
2013-01-24 22:29:48 +02:00
[ USB_STATE_CONFIGURED ] = " configured " ,
[ USB_STATE_SUSPENDED ] = " suspended " ,
} ;
if ( state < 0 | | state > = ARRAY_SIZE ( names ) )
return " UNKNOWN " ;
return names [ state ] ;
}
EXPORT_SYMBOL_GPL ( usb_state_string ) ;
2013-06-13 17:59:55 +03:00
static const char * const usb_dr_modes [ ] = {
[ USB_DR_MODE_UNKNOWN ] = " " ,
[ USB_DR_MODE_HOST ] = " host " ,
[ USB_DR_MODE_PERIPHERAL ] = " peripheral " ,
[ USB_DR_MODE_OTG ] = " otg " ,
} ;
2015-11-03 11:51:15 -06:00
static enum usb_dr_mode usb_get_dr_mode_from_string ( const char * str )
{
2016-03-17 14:22:38 -07:00
int ret ;
2015-11-03 11:51:15 -06:00
2016-03-17 14:22:38 -07:00
ret = match_string ( usb_dr_modes , ARRAY_SIZE ( usb_dr_modes ) , str ) ;
return ( ret < 0 ) ? USB_DR_MODE_UNKNOWN : ret ;
2015-11-03 11:51:15 -06:00
}
2015-09-21 11:14:34 +03:00
enum usb_dr_mode usb_get_dr_mode ( struct device * dev )
2013-06-13 17:59:55 +03:00
{
const char * dr_mode ;
2015-11-03 11:51:15 -06:00
int err ;
2013-06-13 17:59:55 +03:00
2015-09-21 11:14:34 +03:00
err = device_property_read_string ( dev , " dr_mode " , & dr_mode ) ;
2013-06-13 17:59:55 +03:00
if ( err < 0 )
return USB_DR_MODE_UNKNOWN ;
2015-11-03 11:51:15 -06:00
return usb_get_dr_mode_from_string ( dr_mode ) ;
2013-06-13 17:59:55 +03:00
}
2015-09-21 11:14:34 +03:00
EXPORT_SYMBOL_GPL ( usb_get_dr_mode ) ;
2013-06-30 13:56:45 +03:00
2021-07-15 17:07:50 +08:00
/**
* usb_get_role_switch_default_mode - Get default mode for given device
* @ dev : Pointer to the given device
*
* The function gets string from property ' role - switch - default - mode ' ,
* and returns the corresponding enum usb_dr_mode .
*/
enum usb_dr_mode usb_get_role_switch_default_mode ( struct device * dev )
{
const char * str ;
int ret ;
ret = device_property_read_string ( dev , " role-switch-default-mode " , & str ) ;
if ( ret < 0 )
return USB_DR_MODE_UNKNOWN ;
return usb_get_dr_mode_from_string ( str ) ;
}
EXPORT_SYMBOL_GPL ( usb_get_role_switch_default_mode ) ;
2021-03-08 10:52:05 +08:00
/**
* usb_decode_interval - Decode bInterval into the time expressed in 1u s unit
* @ epd : The descriptor of the endpoint
* @ speed : The speed that the endpoint works as
*
* Function returns the interval expressed in 1u s unit for servicing
* endpoint for data transfers .
*/
unsigned int usb_decode_interval ( const struct usb_endpoint_descriptor * epd ,
enum usb_device_speed speed )
{
unsigned int interval = 0 ;
switch ( usb_endpoint_type ( epd ) ) {
case USB_ENDPOINT_XFER_CONTROL :
/* uframes per NAK */
if ( speed = = USB_SPEED_HIGH )
interval = epd - > bInterval ;
break ;
case USB_ENDPOINT_XFER_ISOC :
interval = 1 < < ( epd - > bInterval - 1 ) ;
break ;
case USB_ENDPOINT_XFER_BULK :
/* uframes per NAK */
if ( speed = = USB_SPEED_HIGH & & usb_endpoint_dir_out ( epd ) )
interval = epd - > bInterval ;
break ;
case USB_ENDPOINT_XFER_INT :
if ( speed > = USB_SPEED_HIGH )
interval = 1 < < ( epd - > bInterval - 1 ) ;
else
interval = epd - > bInterval ;
break ;
}
interval * = ( speed > = USB_SPEED_HIGH ) ? 125 : 1000 ;
return interval ;
}
EXPORT_SYMBOL_GPL ( usb_decode_interval ) ;
2015-09-21 11:14:34 +03:00
# ifdef CONFIG_OF
2015-11-03 11:51:15 -06:00
/**
* of_usb_get_dr_mode_by_phy - Get dual role mode for the controller device
* which is associated with the given phy device_node
* @ np : Pointer to the given phy device_node
2016-06-10 11:46:25 +02:00
* @ arg0 : phandle args [ 0 ] for phy ' s with # phy - cells > = 1 , or - 1 for
* phys which do not have phy - cells
2015-11-03 11:51:15 -06:00
*
* In dts a usb controller associates with phy devices . The function gets
* the string from property ' dr_mode ' of the controller associated with the
* given phy device node , and returns the correspondig enum usb_dr_mode .
*/
2016-06-10 11:46:25 +02:00
enum usb_dr_mode of_usb_get_dr_mode_by_phy ( struct device_node * np , int arg0 )
2015-11-03 11:51:15 -06:00
{
struct device_node * controller = NULL ;
2016-06-10 11:46:25 +02:00
struct of_phandle_args args ;
2015-11-03 11:51:15 -06:00
const char * dr_mode ;
int index ;
int err ;
do {
controller = of_find_node_with_property ( controller , " phys " ) ;
2019-03-01 11:05:45 +00:00
if ( ! of_device_is_available ( controller ) )
continue ;
2015-11-03 11:51:15 -06:00
index = 0 ;
do {
2016-06-10 11:46:25 +02:00
if ( arg0 = = - 1 ) {
args . np = of_parse_phandle ( controller , " phys " ,
index ) ;
args . args_count = 0 ;
} else {
err = of_parse_phandle_with_args ( controller ,
" phys " , " #phy-cells " ,
index , & args ) ;
if ( err )
break ;
}
of_node_put ( args . np ) ;
if ( args . np = = np & & ( args . args_count = = 0 | |
args . args [ 0 ] = = arg0 ) )
2015-11-03 11:51:15 -06:00
goto finish ;
index + + ;
2016-06-10 11:46:25 +02:00
} while ( args . np ) ;
2015-11-03 11:51:15 -06:00
} while ( controller ) ;
finish :
err = of_property_read_string ( controller , " dr_mode " , & dr_mode ) ;
of_node_put ( controller ) ;
if ( err < 0 )
return USB_DR_MODE_UNKNOWN ;
return usb_get_dr_mode_from_string ( dr_mode ) ;
}
EXPORT_SYMBOL_GPL ( of_usb_get_dr_mode_by_phy ) ;
2014-08-19 09:51:55 +08:00
/**
* of_usb_host_tpl_support - to get if Targeted Peripheral List is supported
* for given targeted hosts ( non - PC hosts )
* @ np : Pointer to the given device_node
*
* The function gets if the targeted hosts support TPL or not
*/
bool of_usb_host_tpl_support ( struct device_node * np )
{
2017-08-20 21:06:52 +03:00
return of_property_read_bool ( np , " tpl-support " ) ;
2014-08-19 09:51:55 +08:00
}
EXPORT_SYMBOL_GPL ( of_usb_host_tpl_support ) ;
2015-07-09 15:18:44 +08:00
/**
* of_usb_update_otg_caps - to update usb otg capabilities according to
* the passed properties in DT .
* @ np : Pointer to the given device_node
* @ otg_caps : Pointer to the target usb_otg_caps to be set
*
* The function updates the otg capabilities
*/
int of_usb_update_otg_caps ( struct device_node * np ,
struct usb_otg_caps * otg_caps )
{
u32 otg_rev ;
if ( ! otg_caps )
return - EINVAL ;
if ( ! of_property_read_u32 ( np , " otg-rev " , & otg_rev ) ) {
switch ( otg_rev ) {
case 0x0100 :
case 0x0120 :
case 0x0130 :
case 0x0200 :
/* Choose the lesser one if it's already been set */
if ( otg_caps - > otg_rev )
otg_caps - > otg_rev = min_t ( u16 , otg_rev ,
otg_caps - > otg_rev ) ;
else
otg_caps - > otg_rev = otg_rev ;
break ;
default :
2017-07-18 16:43:35 -05:00
pr_err ( " %pOF: unsupported otg-rev: 0x%x \n " ,
np , otg_rev ) ;
2015-07-09 15:18:44 +08:00
return - EINVAL ;
}
} else {
/*
* otg - rev is mandatory for otg properties , if not passed
* we set it to be 0 and assume it ' s a legacy otg device .
* Non - dt platform can set it afterwards .
*/
otg_caps - > otg_rev = 0 ;
}
2017-08-20 21:06:52 +03:00
if ( of_property_read_bool ( np , " hnp-disable " ) )
2015-07-09 15:18:44 +08:00
otg_caps - > hnp_support = false ;
2017-08-20 21:06:52 +03:00
if ( of_property_read_bool ( np , " srp-disable " ) )
2015-07-09 15:18:44 +08:00
otg_caps - > srp_support = false ;
2017-08-20 21:06:52 +03:00
if ( of_property_read_bool ( np , " adp-disable " ) | |
2015-07-09 15:18:44 +08:00
( otg_caps - > otg_rev < 0x0200 ) )
otg_caps - > adp_support = false ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( of_usb_update_otg_caps ) ;
2018-08-20 12:10:26 +09:00
/**
* usb_of_get_companion_dev - Find the companion device
* @ dev : the device pointer to find a companion
*
* Find the companion device from platform bus .
*
* Takes a reference to the returned struct device which needs to be dropped
* after use .
*
* Return : On success , a pointer to the companion device , % NULL on failure .
*/
struct device * usb_of_get_companion_dev ( struct device * dev )
{
struct device_node * node ;
struct platform_device * pdev = NULL ;
node = of_parse_phandle ( dev - > of_node , " companion " , 0 ) ;
if ( node )
pdev = of_find_device_by_node ( node ) ;
of_node_put ( node ) ;
return pdev ? & pdev - > dev : NULL ;
}
EXPORT_SYMBOL_GPL ( usb_of_get_companion_dev ) ;
2013-06-13 17:59:55 +03:00
# endif
2019-06-05 14:44:40 +02:00
struct dentry * usb_debug_root ;
EXPORT_SYMBOL_GPL ( usb_debug_root ) ;
static int __init usb_common_init ( void )
{
usb_debug_root = debugfs_create_dir ( " usb " , NULL ) ;
ledtrig_usb_init ( ) ;
return 0 ;
}
static void __exit usb_common_exit ( void )
{
ledtrig_usb_exit ( ) ;
debugfs_remove_recursive ( usb_debug_root ) ;
}
subsys_initcall ( usb_common_init ) ;
module_exit ( usb_common_exit ) ;
2011-08-30 17:11:19 +02:00
MODULE_LICENSE ( " GPL " ) ;