2008-11-24 12:02:21 -08:00
/*
* otg . c - - USB OTG utility code
*
* Copyright ( C ) 2004 Texas Instruments
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*/
# include <linux/kernel.h>
2011-05-27 09:56:31 -04:00
# include <linux/export.h>
2012-06-22 17:02:46 +05:30
# include <linux/err.h>
2008-11-24 12:02:21 -08:00
# include <linux/device.h>
2013-01-25 08:03:25 +05:30
# include <linux/module.h>
2012-06-22 17:02:47 +05:30
# include <linux/slab.h>
2013-01-25 08:03:25 +05:30
# include <linux/of.h>
2008-11-24 12:02:21 -08:00
# include <linux/usb/otg.h>
2012-06-22 17:02:46 +05:30
static LIST_HEAD ( phy_list ) ;
2013-01-25 08:03:21 +05:30
static LIST_HEAD ( phy_bind_list ) ;
2012-06-22 17:02:46 +05:30
static DEFINE_SPINLOCK ( phy_lock ) ;
static struct usb_phy * __usb_find_phy ( struct list_head * list ,
enum usb_phy_type type )
{
struct usb_phy * phy = NULL ;
list_for_each_entry ( phy , list , head ) {
if ( phy - > type ! = type )
continue ;
return phy ;
}
return ERR_PTR ( - ENODEV ) ;
}
2008-11-24 12:02:21 -08:00
2013-01-25 08:03:22 +05:30
static struct usb_phy * __usb_find_phy_dev ( struct device * dev ,
struct list_head * list , u8 index )
{
struct usb_phy_bind * phy_bind = NULL ;
list_for_each_entry ( phy_bind , list , list ) {
if ( ! ( strcmp ( phy_bind - > dev_name , dev_name ( dev ) ) ) & &
phy_bind - > index = = index ) {
if ( phy_bind - > phy )
return phy_bind - > phy ;
else
return ERR_PTR ( - EPROBE_DEFER ) ;
}
}
return ERR_PTR ( - ENODEV ) ;
}
2013-01-25 08:03:25 +05:30
static struct usb_phy * __of_usb_find_phy ( struct device_node * node )
{
struct usb_phy * phy ;
list_for_each_entry ( phy , & phy_list , head ) {
if ( node ! = phy - > dev - > of_node )
continue ;
return phy ;
}
return ERR_PTR ( - ENODEV ) ;
}
2012-06-22 17:02:47 +05:30
static void devm_usb_phy_release ( struct device * dev , void * res )
{
struct usb_phy * phy = * ( struct usb_phy * * ) res ;
usb_put_phy ( phy ) ;
}
static int devm_usb_phy_match ( struct device * dev , void * res , void * match_data )
{
return res = = match_data ;
}
/**
* devm_usb_get_phy - find the USB PHY
* @ dev - device that requests this phy
* @ type - the type of the phy the controller requires
*
* Gets the phy using usb_get_phy ( ) , and associates a device with it using
* devres . On driver detach , release function is invoked on the devres data ,
* then , devres data is freed .
*
* For use by USB host and peripheral drivers .
*/
struct usb_phy * devm_usb_get_phy ( struct device * dev , enum usb_phy_type type )
{
struct usb_phy * * ptr , * phy ;
ptr = devres_alloc ( devm_usb_phy_release , sizeof ( * ptr ) , GFP_KERNEL ) ;
if ( ! ptr )
return NULL ;
phy = usb_get_phy ( type ) ;
2012-06-26 17:40:32 +05:30
if ( ! IS_ERR ( phy ) ) {
2012-06-22 17:02:47 +05:30
* ptr = phy ;
devres_add ( dev , ptr ) ;
} else
devres_free ( ptr ) ;
return phy ;
}
EXPORT_SYMBOL ( devm_usb_get_phy ) ;
2008-11-24 12:02:21 -08:00
/**
2012-06-22 17:02:46 +05:30
* usb_get_phy - find the USB PHY
* @ type - the type of the phy the controller requires
2008-11-24 12:02:21 -08:00
*
2012-06-22 17:02:45 +05:30
* Returns the phy driver , after getting a refcount to it ; or
2012-06-26 17:40:32 +05:30
* - ENODEV if there is no such phy . The caller is responsible for
2012-06-22 17:02:45 +05:30
* calling usb_put_phy ( ) to release that count .
2008-11-24 12:02:21 -08:00
*
* For use by USB host and peripheral drivers .
*/
2012-06-22 17:02:46 +05:30
struct usb_phy * usb_get_phy ( enum usb_phy_type type )
2008-11-24 12:02:21 -08:00
{
2012-06-22 17:02:46 +05:30
struct usb_phy * phy = NULL ;
unsigned long flags ;
spin_lock_irqsave ( & phy_lock , flags ) ;
phy = __usb_find_phy ( & phy_list , type ) ;
2013-02-27 15:11:13 +01:00
if ( IS_ERR ( phy ) | | ! try_module_get ( phy - > dev - > driver - > owner ) ) {
2012-06-22 17:02:46 +05:30
pr_err ( " unable to find transceiver of type %s \n " ,
usb_phy_type_string ( type ) ) ;
2012-07-02 12:20:24 +05:30
goto err0 ;
2012-06-22 17:02:46 +05:30
}
get_device ( phy - > dev ) ;
2012-07-02 12:20:24 +05:30
err0 :
2012-06-22 17:02:46 +05:30
spin_unlock_irqrestore ( & phy_lock , flags ) ;
2012-02-13 13:24:04 +02:00
return phy ;
2008-11-24 12:02:21 -08:00
}
2012-06-22 17:02:45 +05:30
EXPORT_SYMBOL ( usb_get_phy ) ;
2008-11-24 12:02:21 -08:00
2013-01-25 08:03:25 +05:30
/**
* devm_usb_get_phy_by_phandle - find the USB PHY by phandle
* @ dev - device that requests this phy
* @ phandle - name of the property holding the phy phandle value
* @ index - the index of the phy
*
* Returns the phy driver associated with the given phandle value ,
* after getting a refcount to it , - ENODEV if there is no such phy or
* - EPROBE_DEFER if there is a phandle to the phy , but the device is
* not yet loaded . While at that , it also associates the device with
* the phy using devres . On driver detach , release function is invoked
* on the devres data , then , devres data is freed .
*
* For use by USB host and peripheral drivers .
*/
struct usb_phy * devm_usb_get_phy_by_phandle ( struct device * dev ,
const char * phandle , u8 index )
{
struct usb_phy * phy = ERR_PTR ( - ENOMEM ) , * * ptr ;
unsigned long flags ;
struct device_node * node ;
if ( ! dev - > of_node ) {
dev_dbg ( dev , " device does not have a device node entry \n " ) ;
return ERR_PTR ( - EINVAL ) ;
}
node = of_parse_phandle ( dev - > of_node , phandle , index ) ;
if ( ! node ) {
dev_dbg ( dev , " failed to get %s phandle in %s node \n " , phandle ,
dev - > of_node - > full_name ) ;
return ERR_PTR ( - ENODEV ) ;
}
ptr = devres_alloc ( devm_usb_phy_release , sizeof ( * ptr ) , GFP_KERNEL ) ;
if ( ! ptr ) {
dev_dbg ( dev , " failed to allocate memory for devres \n " ) ;
goto err0 ;
}
spin_lock_irqsave ( & phy_lock , flags ) ;
phy = __of_usb_find_phy ( node ) ;
if ( IS_ERR ( phy ) | | ! try_module_get ( phy - > dev - > driver - > owner ) ) {
phy = ERR_PTR ( - EPROBE_DEFER ) ;
devres_free ( ptr ) ;
goto err1 ;
}
* ptr = phy ;
devres_add ( dev , ptr ) ;
get_device ( phy - > dev ) ;
err1 :
spin_unlock_irqrestore ( & phy_lock , flags ) ;
err0 :
of_node_put ( node ) ;
return phy ;
}
EXPORT_SYMBOL ( devm_usb_get_phy_by_phandle ) ;
2013-01-25 08:03:22 +05:30
/**
* usb_get_phy_dev - find the USB PHY
* @ dev - device that requests this phy
* @ index - the index of the phy
*
* Returns the phy driver , after getting a refcount to it ; or
* - ENODEV if there is no such phy . The caller is responsible for
* calling usb_put_phy ( ) to release that count .
*
* For use by USB host and peripheral drivers .
*/
struct usb_phy * usb_get_phy_dev ( struct device * dev , u8 index )
{
struct usb_phy * phy = NULL ;
unsigned long flags ;
spin_lock_irqsave ( & phy_lock , flags ) ;
phy = __usb_find_phy_dev ( dev , & phy_bind_list , index ) ;
2013-02-27 15:11:13 +01:00
if ( IS_ERR ( phy ) | | ! try_module_get ( phy - > dev - > driver - > owner ) ) {
2013-01-25 08:03:22 +05:30
pr_err ( " unable to find transceiver \n " ) ;
goto err0 ;
}
get_device ( phy - > dev ) ;
err0 :
spin_unlock_irqrestore ( & phy_lock , flags ) ;
return phy ;
}
EXPORT_SYMBOL ( usb_get_phy_dev ) ;
/**
* devm_usb_get_phy_dev - find the USB PHY using device ptr and index
* @ dev - device that requests this phy
* @ index - the index of the phy
*
* Gets the phy using usb_get_phy_dev ( ) , and associates a device with it using
* devres . On driver detach , release function is invoked on the devres data ,
* then , devres data is freed .
*
* For use by USB host and peripheral drivers .
*/
struct usb_phy * devm_usb_get_phy_dev ( struct device * dev , u8 index )
{
struct usb_phy * * ptr , * phy ;
ptr = devres_alloc ( devm_usb_phy_release , sizeof ( * ptr ) , GFP_KERNEL ) ;
if ( ! ptr )
return NULL ;
phy = usb_get_phy_dev ( dev , index ) ;
if ( ! IS_ERR ( phy ) ) {
* ptr = phy ;
devres_add ( dev , ptr ) ;
} else
devres_free ( ptr ) ;
return phy ;
}
EXPORT_SYMBOL ( devm_usb_get_phy_dev ) ;
2012-06-22 17:02:47 +05:30
/**
* devm_usb_put_phy - release the USB PHY
* @ dev - device that wants to release this phy
* @ phy - the phy returned by devm_usb_get_phy ( )
*
* destroys the devres associated with this phy and invokes usb_put_phy
* to release the phy .
*
* For use by USB host and peripheral drivers .
*/
void devm_usb_put_phy ( struct device * dev , struct usb_phy * phy )
{
int r ;
r = devres_destroy ( dev , devm_usb_phy_release , devm_usb_phy_match , phy ) ;
dev_WARN_ONCE ( dev , r , " couldn't find PHY resource \n " ) ;
}
EXPORT_SYMBOL ( devm_usb_put_phy ) ;
2008-11-24 12:02:21 -08:00
/**
2012-06-22 17:02:46 +05:30
* usb_put_phy - release the USB PHY
2012-06-22 17:02:45 +05:30
* @ x : the phy returned by usb_get_phy ( )
2008-11-24 12:02:21 -08:00
*
2012-06-22 17:02:45 +05:30
* Releases a refcount the caller received from usb_get_phy ( ) .
2008-11-24 12:02:21 -08:00
*
* For use by USB host and peripheral drivers .
*/
2012-06-22 17:02:45 +05:30
void usb_put_phy ( struct usb_phy * x )
2008-11-24 12:02:21 -08:00
{
2013-02-27 15:11:13 +01:00
if ( x ) {
struct module * owner = x - > dev - > driver - > owner ;
2009-04-21 20:33:10 -07:00
put_device ( x - > dev ) ;
2013-02-27 15:11:13 +01:00
module_put ( owner ) ;
}
2008-11-24 12:02:21 -08:00
}
2012-06-22 17:02:45 +05:30
EXPORT_SYMBOL ( usb_put_phy ) ;
2008-11-24 12:02:21 -08:00
/**
2012-06-22 17:02:46 +05:30
* usb_add_phy - declare the USB PHY
2012-06-22 17:02:45 +05:30
* @ x : the USB phy to be used ; or NULL
2012-06-22 17:02:46 +05:30
* @ type - the type of this PHY
2008-11-24 12:02:21 -08:00
*
2012-06-22 17:02:45 +05:30
* This call is exclusively for use by phy drivers , which
2008-11-24 12:02:21 -08:00
* coordinate the activities of drivers for host and peripheral
* controllers , and in some cases for VBUS current regulation .
*/
2012-06-22 17:02:46 +05:30
int usb_add_phy ( struct usb_phy * x , enum usb_phy_type type )
2008-11-24 12:02:21 -08:00
{
2012-06-22 17:02:46 +05:30
int ret = 0 ;
unsigned long flags ;
struct usb_phy * phy ;
2012-08-07 19:56:30 +05:30
if ( x - > type ! = USB_PHY_TYPE_UNDEFINED ) {
2012-06-22 17:02:46 +05:30
dev_err ( x - > dev , " not accepting initialized PHY %s \n " , x - > label ) ;
return - EINVAL ;
}
spin_lock_irqsave ( & phy_lock , flags ) ;
list_for_each_entry ( phy , & phy_list , head ) {
if ( phy - > type = = type ) {
ret = - EBUSY ;
dev_err ( x - > dev , " transceiver type %s already exists \n " ,
usb_phy_type_string ( type ) ) ;
goto out ;
}
}
x - > type = type ;
list_add_tail ( & x - > head , & phy_list ) ;
out :
spin_unlock_irqrestore ( & phy_lock , flags ) ;
return ret ;
2008-11-24 12:02:21 -08:00
}
2012-06-22 17:02:45 +05:30
EXPORT_SYMBOL ( usb_add_phy ) ;
2011-04-15 16:18:38 +02:00
2013-01-25 08:03:22 +05:30
/**
* usb_add_phy_dev - declare the USB PHY
* @ x : the USB phy to be used ; or NULL
*
* This call is exclusively for use by phy drivers , which
* coordinate the activities of drivers for host and peripheral
* controllers , and in some cases for VBUS current regulation .
*/
int usb_add_phy_dev ( struct usb_phy * x )
{
struct usb_phy_bind * phy_bind ;
unsigned long flags ;
if ( ! x - > dev ) {
dev_err ( x - > dev , " no device provided for PHY \n " ) ;
return - EINVAL ;
}
spin_lock_irqsave ( & phy_lock , flags ) ;
list_for_each_entry ( phy_bind , & phy_bind_list , list )
if ( ! ( strcmp ( phy_bind - > phy_dev_name , dev_name ( x - > dev ) ) ) )
phy_bind - > phy = x ;
list_add_tail ( & x - > head , & phy_list ) ;
spin_unlock_irqrestore ( & phy_lock , flags ) ;
return 0 ;
}
EXPORT_SYMBOL ( usb_add_phy_dev ) ;
2012-06-22 17:02:46 +05:30
/**
* usb_remove_phy - remove the OTG PHY
* @ x : the USB OTG PHY to be removed ;
*
* This reverts the effects of usb_add_phy
*/
void usb_remove_phy ( struct usb_phy * x )
{
unsigned long flags ;
2013-01-25 08:03:22 +05:30
struct usb_phy_bind * phy_bind ;
2012-06-22 17:02:46 +05:30
spin_lock_irqsave ( & phy_lock , flags ) ;
2013-01-25 08:03:22 +05:30
if ( x ) {
list_for_each_entry ( phy_bind , & phy_bind_list , list )
if ( phy_bind - > phy = = x )
phy_bind - > phy = NULL ;
2012-06-22 17:02:46 +05:30
list_del ( & x - > head ) ;
2013-01-25 08:03:22 +05:30
}
2012-06-22 17:02:46 +05:30
spin_unlock_irqrestore ( & phy_lock , flags ) ;
}
EXPORT_SYMBOL ( usb_remove_phy ) ;
2013-01-25 08:03:21 +05:30
/**
* usb_bind_phy - bind the phy and the controller that uses the phy
* @ dev_name : the device name of the device that will bind to the phy
* @ index : index to specify the port number
* @ phy_dev_name : the device name of the phy
*
* Fills the phy_bind structure with the dev_name and phy_dev_name . This will
* be used when the phy driver registers the phy and when the controller
* requests this phy .
*
* To be used by platform specific initialization code .
*/
int __init usb_bind_phy ( const char * dev_name , u8 index ,
const char * phy_dev_name )
{
struct usb_phy_bind * phy_bind ;
unsigned long flags ;
phy_bind = kzalloc ( sizeof ( * phy_bind ) , GFP_KERNEL ) ;
if ( ! phy_bind ) {
pr_err ( " phy_bind(): No memory for phy_bind " ) ;
return - ENOMEM ;
}
phy_bind - > dev_name = dev_name ;
phy_bind - > phy_dev_name = phy_dev_name ;
phy_bind - > index = index ;
spin_lock_irqsave ( & phy_lock , flags ) ;
list_add_tail ( & phy_bind - > list , & phy_bind_list ) ;
spin_unlock_irqrestore ( & phy_lock , flags ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( usb_bind_phy ) ;
2011-04-15 16:18:38 +02:00
const char * otg_state_string ( enum usb_otg_state state )
{
switch ( state ) {
case OTG_STATE_A_IDLE :
return " a_idle " ;
case OTG_STATE_A_WAIT_VRISE :
return " a_wait_vrise " ;
case OTG_STATE_A_WAIT_BCON :
return " a_wait_bcon " ;
case OTG_STATE_A_HOST :
return " a_host " ;
case OTG_STATE_A_SUSPEND :
return " a_suspend " ;
case OTG_STATE_A_PERIPHERAL :
return " a_peripheral " ;
case OTG_STATE_A_WAIT_VFALL :
return " a_wait_vfall " ;
case OTG_STATE_A_VBUS_ERR :
return " a_vbus_err " ;
case OTG_STATE_B_IDLE :
return " b_idle " ;
case OTG_STATE_B_SRP_INIT :
return " b_srp_init " ;
case OTG_STATE_B_PERIPHERAL :
return " b_peripheral " ;
case OTG_STATE_B_WAIT_ACON :
return " b_wait_acon " ;
case OTG_STATE_B_HOST :
return " b_host " ;
default :
return " UNDEFINED " ;
}
}
EXPORT_SYMBOL ( otg_state_string ) ;