2014-01-05 04:18:27 +04:00
/* MDIO Bus interface
2005-07-31 03:31:23 +04:00
*
* Author : Andy Fleming
*
* Copyright ( c ) 2004 Freescale Semiconductor , Inc .
*
* 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 .
*
*/
2012-06-09 11:49:07 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-07-31 03:31:23 +04:00
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/errno.h>
# include <linux/unistd.h>
# include <linux/slab.h>
# include <linux/interrupt.h>
# include <linux/init.h>
# include <linux/delay.h>
2009-02-01 11:53:34 +03:00
# include <linux/device.h>
2012-06-27 11:33:37 +04:00
# include <linux/of_device.h>
2012-10-09 02:55:43 +04:00
# include <linux/of_mdio.h>
2005-07-31 03:31:23 +04:00
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/skbuff.h>
# include <linux/spinlock.h>
# include <linux/mm.h>
# include <linux/module.h>
# include <linux/mii.h>
# include <linux/ethtool.h>
# include <linux/phy.h>
2014-01-05 04:18:27 +04:00
# include <linux/io.h>
# include <linux/uaccess.h>
2005-07-31 03:31:23 +04:00
# include <asm/irq.h>
2016-01-06 22:11:18 +03:00
int mdiobus_register_device ( struct mdio_device * mdiodev )
{
if ( mdiodev - > bus - > mdio_map [ mdiodev - > addr ] )
return - EBUSY ;
mdiodev - > bus - > mdio_map [ mdiodev - > addr ] = mdiodev ;
return 0 ;
}
EXPORT_SYMBOL ( mdiobus_register_device ) ;
int mdiobus_unregister_device ( struct mdio_device * mdiodev )
{
if ( mdiodev - > bus - > mdio_map [ mdiodev - > addr ] ! = mdiodev )
return - EINVAL ;
mdiodev - > bus - > mdio_map [ mdiodev - > addr ] = NULL ;
return 0 ;
}
EXPORT_SYMBOL ( mdiobus_unregister_device ) ;
struct phy_device * mdiobus_get_phy ( struct mii_bus * bus , int addr )
{
struct mdio_device * mdiodev = bus - > mdio_map [ addr ] ;
if ( ! mdiodev )
return NULL ;
if ( ! ( mdiodev - > flags & MDIO_DEVICE_FLAG_PHY ) )
return NULL ;
return container_of ( mdiodev , struct phy_device , mdio ) ;
}
EXPORT_SYMBOL ( mdiobus_get_phy ) ;
bool mdiobus_is_registered_device ( struct mii_bus * bus , int addr )
{
return bus - > mdio_map [ addr ] ;
}
EXPORT_SYMBOL ( mdiobus_is_registered_device ) ;
2008-10-09 03:29:57 +04:00
/**
2012-01-13 03:23:04 +04:00
* mdiobus_alloc_size - allocate a mii_bus structure
2012-01-21 13:03:04 +04:00
* @ size : extra amount of memory to allocate for private storage .
* If non - zero , then bus - > priv is points to that memory .
2008-10-09 03:29:57 +04:00
*
* Description : called by a bus driver to allocate an mii_bus
* structure to fill in .
*/
2012-01-13 03:23:04 +04:00
struct mii_bus * mdiobus_alloc_size ( size_t size )
2008-10-09 03:29:57 +04:00
{
2008-10-09 03:33:40 +04:00
struct mii_bus * bus ;
2012-01-13 03:23:04 +04:00
size_t aligned_size = ALIGN ( sizeof ( * bus ) , NETDEV_ALIGN ) ;
size_t alloc_size ;
2016-01-06 22:11:15 +03:00
int i ;
2012-01-13 03:23:04 +04:00
/* If we alloc extra space, it should be aligned */
if ( size )
alloc_size = aligned_size + size ;
else
alloc_size = sizeof ( * bus ) ;
2008-10-09 03:33:40 +04:00
2012-01-13 03:23:04 +04:00
bus = kzalloc ( alloc_size , GFP_KERNEL ) ;
2016-01-12 12:34:36 +03:00
if ( ! bus )
return NULL ;
bus - > state = MDIOBUS_ALLOCATED ;
if ( size )
bus - > priv = ( void * ) bus + aligned_size ;
2008-10-09 03:33:40 +04:00
2016-01-06 22:11:15 +03:00
/* Initialise the interrupts to polling */
for ( i = 0 ; i < PHY_MAX_ADDR ; i + + )
bus - > irq [ i ] = PHY_POLL ;
2008-10-09 03:33:40 +04:00
return bus ;
2008-10-09 03:29:57 +04:00
}
2012-01-13 03:23:04 +04:00
EXPORT_SYMBOL ( mdiobus_alloc_size ) ;
2008-10-09 03:29:57 +04:00
2014-04-30 16:23:33 +04:00
static void _devm_mdiobus_free ( struct device * dev , void * res )
{
mdiobus_free ( * ( struct mii_bus * * ) res ) ;
}
static int devm_mdiobus_match ( struct device * dev , void * res , void * data )
{
struct mii_bus * * r = res ;
if ( WARN_ON ( ! r | | ! * r ) )
return 0 ;
return * r = = data ;
}
/**
* devm_mdiobus_alloc_size - Resource - managed mdiobus_alloc_size ( )
* @ dev : Device to allocate mii_bus for
* @ sizeof_priv : Space to allocate for private structure .
*
* Managed mdiobus_alloc_size . mii_bus allocated with this function is
* automatically freed on driver detach .
*
* If an mii_bus allocated with this function needs to be freed separately ,
* devm_mdiobus_free ( ) must be used .
*
* RETURNS :
* Pointer to allocated mii_bus on success , NULL on failure .
*/
struct mii_bus * devm_mdiobus_alloc_size ( struct device * dev , int sizeof_priv )
{
struct mii_bus * * ptr , * bus ;
ptr = devres_alloc ( _devm_mdiobus_free , sizeof ( * ptr ) , GFP_KERNEL ) ;
if ( ! ptr )
return NULL ;
/* use raw alloc_dr for kmalloc caller tracing */
bus = mdiobus_alloc_size ( sizeof_priv ) ;
if ( bus ) {
* ptr = bus ;
devres_add ( dev , ptr ) ;
} else {
devres_free ( ptr ) ;
}
return bus ;
}
2014-05-08 18:46:52 +04:00
EXPORT_SYMBOL_GPL ( devm_mdiobus_alloc_size ) ;
2014-04-30 16:23:33 +04:00
/**
* devm_mdiobus_free - Resource - managed mdiobus_free ( )
* @ dev : Device this mii_bus belongs to
* @ bus : the mii_bus associated with the device
*
* Free mii_bus allocated with devm_mdiobus_alloc_size ( ) .
*/
void devm_mdiobus_free ( struct device * dev , struct mii_bus * bus )
{
int rc ;
rc = devres_release ( dev , _devm_mdiobus_free ,
devm_mdiobus_match , bus ) ;
WARN_ON ( rc ) ;
}
EXPORT_SYMBOL_GPL ( devm_mdiobus_free ) ;
2008-10-09 03:33:40 +04:00
/**
* mdiobus_release - mii_bus device release callback
2008-10-14 05:46:22 +04:00
* @ d : the target struct device that contains the mii_bus
2008-10-09 03:33:40 +04:00
*
* Description : called when the last reference to an mii_bus is
* dropped , to free the underlying memory .
*/
static void mdiobus_release ( struct device * d )
{
struct mii_bus * bus = to_mii_bus ( d ) ;
2008-12-26 03:50:41 +03:00
BUG_ON ( bus - > state ! = MDIOBUS_RELEASED & &
/* for compatibility with error handling in drivers */
bus - > state ! = MDIOBUS_ALLOCATED ) ;
2008-10-09 03:33:40 +04:00
kfree ( bus ) ;
}
static struct class mdio_bus_class = {
. name = " mdio_bus " ,
. dev_release = mdiobus_release ,
} ;
2012-05-11 09:47:01 +04:00
# if IS_ENABLED(CONFIG_OF_MDIO)
2012-05-02 19:16:37 +04:00
/* Helper function for of_mdio_find_bus */
2013-02-01 23:40:17 +04:00
static int of_mdio_bus_match ( struct device * dev , const void * mdio_bus_np )
2012-05-02 19:16:37 +04:00
{
return dev - > of_node = = mdio_bus_np ;
}
/**
* of_mdio_find_bus - Given an mii_bus node , find the mii_bus .
2012-06-08 18:07:19 +04:00
* @ mdio_bus_np : Pointer to the mii_bus .
2012-05-02 19:16:37 +04:00
*
2015-09-24 22:35:52 +03:00
* Returns a reference to the mii_bus , or NULL if none found . The
* embedded struct device will have its reference count incremented ,
* and this must be put once the bus is finished with .
2012-05-02 19:16:37 +04:00
*
* Because the association of a device_node and mii_bus is made via
* of_mdiobus_register ( ) , the mii_bus cannot be found before it is
* registered with of_mdiobus_register ( ) .
*
*/
struct mii_bus * of_mdio_find_bus ( struct device_node * mdio_bus_np )
{
struct device * d ;
if ( ! mdio_bus_np )
return NULL ;
d = class_find_device ( & mdio_bus_class , NULL , mdio_bus_np ,
of_mdio_bus_match ) ;
return d ? to_mii_bus ( d ) : NULL ;
}
EXPORT_SYMBOL ( of_mdio_find_bus ) ;
2014-06-28 03:23:35 +04:00
2016-01-06 22:11:24 +03:00
/* Walk the list of subnodes of a mdio bus and look for a node that
* matches the mdio device ' s address with its ' reg ' property . If
* found , set the of_node pointer for the mdio device . This allows
* auto - probed phy devices to be supplied with information passed in
* via DT .
2014-06-28 03:23:35 +04:00
*/
2016-01-06 22:11:24 +03:00
static void of_mdiobus_link_mdiodev ( struct mii_bus * bus ,
struct mdio_device * mdiodev )
2014-06-28 03:23:35 +04:00
{
2016-01-06 22:11:24 +03:00
struct device * dev = & mdiodev - > dev ;
2014-06-28 03:23:35 +04:00
struct device_node * child ;
2016-01-06 22:11:16 +03:00
if ( dev - > of_node | | ! bus - > dev . of_node )
2014-06-28 03:23:35 +04:00
return ;
2016-01-06 22:11:16 +03:00
for_each_available_child_of_node ( bus - > dev . of_node , child ) {
2014-06-28 03:23:35 +04:00
int addr ;
int ret ;
ret = of_property_read_u32 ( child , " reg " , & addr ) ;
if ( ret < 0 ) {
2016-01-06 22:11:24 +03:00
dev_err ( dev , " %s has invalid MDIO address \n " ,
2014-06-28 03:23:35 +04:00
child - > full_name ) ;
continue ;
}
2016-01-06 22:11:24 +03:00
/* A MDIO device must have a reg property in the range [0-31] */
2014-06-28 03:23:35 +04:00
if ( addr > = PHY_MAX_ADDR ) {
2016-01-06 22:11:24 +03:00
dev_err ( dev , " %s MDIO address %i is too large \n " ,
2014-06-28 03:23:35 +04:00
child - > full_name , addr ) ;
continue ;
}
2016-01-06 22:11:24 +03:00
if ( addr = = mdiodev - > addr ) {
2014-06-28 03:23:35 +04:00
dev - > of_node = child ;
return ;
}
}
}
# else /* !IS_ENABLED(CONFIG_OF_MDIO) */
2016-01-06 22:11:24 +03:00
static inline void of_mdiobus_link_mdiodev ( struct mii_bus * mdio ,
struct mdio_device * mdiodev )
2014-06-28 03:23:35 +04:00
{
}
2012-05-02 19:16:37 +04:00
# endif
2007-03-06 13:41:48 +03:00
/**
2015-09-25 13:56:56 +03:00
* __mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
2007-03-06 13:41:48 +03:00
* @ bus : target mii_bus
2015-09-25 13:56:56 +03:00
* @ owner : module containing bus accessor functions
2005-08-25 03:46:21 +04:00
*
2007-03-06 13:41:48 +03:00
* Description : Called by a bus driver to bring up all the PHYs
2015-09-25 13:56:56 +03:00
* on a given bus , and attach them to the bus . Drivers should use
* mdiobus_register ( ) rather than __mdiobus_register ( ) unless they
2016-01-06 22:11:25 +03:00
* need to pass a specific owner module . MDIO devices which are not
* PHYs will not be brought up by this function . They are expected to
* to be explicitly listed in DT and instantiated by of_mdiobus_register ( ) .
2007-03-06 13:41:48 +03:00
*
* Returns 0 on success or < 0 on error .
2005-08-25 03:46:21 +04:00
*/
2015-09-24 22:36:02 +03:00
int __mdiobus_register ( struct mii_bus * bus , struct module * owner )
2005-08-25 03:46:21 +04:00
{
2016-01-06 22:11:27 +03:00
struct mdio_device * mdiodev ;
2008-12-26 03:50:41 +03:00
int i , err ;
2005-08-25 03:46:21 +04:00
if ( NULL = = bus | | NULL = = bus - > name | |
2014-01-05 04:18:27 +04:00
NULL = = bus - > read | | NULL = = bus - > write )
2005-08-25 03:46:21 +04:00
return - EINVAL ;
2008-10-09 03:33:40 +04:00
BUG_ON ( bus - > state ! = MDIOBUS_ALLOCATED & &
bus - > state ! = MDIOBUS_UNREGISTERED ) ;
2015-09-24 22:36:02 +03:00
bus - > owner = owner ;
2008-10-09 03:33:40 +04:00
bus - > dev . parent = bus - > parent ;
bus - > dev . class = & mdio_bus_class ;
bus - > dev . groups = NULL ;
2009-02-26 13:19:36 +03:00
dev_set_name ( & bus - > dev , " %s " , bus - > id ) ;
2008-10-09 03:33:40 +04:00
err = device_register ( & bus - > dev ) ;
if ( err ) {
2012-06-09 11:49:07 +04:00
pr_err ( " mii_bus %s failed to register \n " , bus - > id ) ;
2014-01-31 03:45:46 +04:00
put_device ( & bus - > dev ) ;
2008-10-09 03:33:40 +04:00
return - EINVAL ;
}
2008-02-20 03:13:53 +03:00
mutex_init ( & bus - > mdio_lock ) ;
2005-08-25 03:46:21 +04:00
if ( bus - > reset )
bus - > reset ( bus ) ;
for ( i = 0 ; i < PHY_MAX_ADDR ; i + + ) {
2008-08-26 15:08:46 +04:00
if ( ( bus - > phy_mask & ( 1 < < i ) ) = = 0 ) {
struct phy_device * phydev ;
2005-08-25 03:46:21 +04:00
2008-08-26 15:08:46 +04:00
phydev = mdiobus_scan ( bus , i ) ;
2016-05-02 03:47:31 +03:00
if ( IS_ERR ( phydev ) & & ( PTR_ERR ( phydev ) ! = - ENODEV ) ) {
2008-08-26 15:08:46 +04:00
err = PTR_ERR ( phydev ) ;
2008-12-26 03:50:41 +03:00
goto error ;
}
2006-05-10 20:12:57 +04:00
}
2005-08-25 03:46:21 +04:00
}
2008-12-26 03:50:41 +03:00
bus - > state = MDIOBUS_REGISTERED ;
2005-08-25 03:46:21 +04:00
pr_info ( " %s: probed \n " , bus - > name ) ;
2008-12-26 03:50:41 +03:00
return 0 ;
2005-08-25 03:46:21 +04:00
2008-12-26 03:50:41 +03:00
error :
while ( - - i > = 0 ) {
2016-01-06 22:11:27 +03:00
mdiodev = bus - > mdio_map [ i ] ;
if ( ! mdiodev )
continue ;
mdiodev - > device_remove ( mdiodev ) ;
mdiodev - > device_free ( mdiodev ) ;
2008-12-26 03:50:41 +03:00
}
device_del ( & bus - > dev ) ;
2005-08-25 03:46:21 +04:00
return err ;
}
2015-09-24 22:36:02 +03:00
EXPORT_SYMBOL ( __mdiobus_register ) ;
2005-08-25 03:46:21 +04:00
void mdiobus_unregister ( struct mii_bus * bus )
{
2016-01-06 22:11:26 +03:00
struct mdio_device * mdiodev ;
2005-08-25 03:46:21 +04:00
int i ;
2008-10-09 03:33:40 +04:00
BUG_ON ( bus - > state ! = MDIOBUS_REGISTERED ) ;
bus - > state = MDIOBUS_UNREGISTERED ;
2005-08-25 03:46:21 +04:00
for ( i = 0 ; i < PHY_MAX_ADDR ; i + + ) {
2016-01-06 22:11:26 +03:00
mdiodev = bus - > mdio_map [ i ] ;
if ( ! mdiodev )
continue ;
2016-01-06 22:11:27 +03:00
mdiodev - > device_remove ( mdiodev ) ;
mdiodev - > device_free ( mdiodev ) ;
2005-08-25 03:46:21 +04:00
}
2015-09-01 16:36:05 +03:00
device_del ( & bus - > dev ) ;
2005-08-25 03:46:21 +04:00
}
EXPORT_SYMBOL ( mdiobus_unregister ) ;
2008-10-09 03:29:57 +04:00
/**
* mdiobus_free - free a struct mii_bus
* @ bus : mii_bus to free
*
2008-10-09 03:33:40 +04:00
* This function releases the reference to the underlying device
* object in the mii_bus . If this is the last reference , the mii_bus
* will be freed .
2008-10-09 03:29:57 +04:00
*/
void mdiobus_free ( struct mii_bus * bus )
{
2014-01-05 04:18:27 +04:00
/* For compatibility with error handling in drivers. */
2008-10-09 03:33:40 +04:00
if ( bus - > state = = MDIOBUS_ALLOCATED ) {
kfree ( bus ) ;
return ;
}
BUG_ON ( bus - > state ! = MDIOBUS_UNREGISTERED ) ;
bus - > state = MDIOBUS_RELEASED ;
put_device ( & bus - > dev ) ;
2008-10-09 03:29:57 +04:00
}
EXPORT_SYMBOL ( mdiobus_free ) ;
2016-01-06 22:11:25 +03:00
/**
* mdiobus_scan - scan a bus for MDIO devices .
* @ bus : mii_bus to scan
* @ addr : address on bus to scan
*
* This function scans the MDIO bus , looking for devices which can be
* identified using a vendor / product ID in registers 2 and 3. Not all
* MDIO devices have such registers , but PHY devices typically
* do . Hence this function assumes anything found is a PHY , or can be
* treated as a PHY . Other MDIO devices , such as switches , will
* probably not be found during the scan .
*/
2008-08-26 15:08:46 +04:00
struct phy_device * mdiobus_scan ( struct mii_bus * bus , int addr )
{
struct phy_device * phydev ;
int err ;
2012-06-27 11:33:35 +04:00
phydev = get_phy_device ( bus , addr , false ) ;
2016-04-24 20:30:53 +03:00
if ( IS_ERR ( phydev ) )
2008-08-26 15:08:46 +04:00
return phydev ;
2014-05-24 11:34:26 +04:00
/*
* For DT , see if the auto - probed phy has a correspoding child
* in the bus node , and set the of_node pointer in this case .
*/
2016-01-06 22:11:24 +03:00
of_mdiobus_link_mdiodev ( bus , & phydev - > mdio ) ;
2014-05-24 11:34:26 +04:00
2009-04-25 16:52:46 +04:00
err = phy_device_register ( phydev ) ;
2008-08-26 15:08:46 +04:00
if ( err ) {
phy_device_free ( phydev ) ;
2016-05-03 23:14:41 +03:00
return ERR_PTR ( - ENODEV ) ;
2008-08-26 15:08:46 +04:00
}
return phydev ;
}
EXPORT_SYMBOL ( mdiobus_scan ) ;
2015-10-22 11:37:49 +03:00
/**
* mdiobus_read_nested - Nested version of the mdiobus_read function
* @ bus : the mii_bus struct
* @ addr : the phy address
* @ regnum : register number to read
*
* In case of nested MDIO bus access avoid lockdep false positives by
* using mutex_lock_nested ( ) .
*
* NOTE : MUST NOT be called from interrupt context ,
* because the bus read / write functions may wait for an interrupt
* to conclude the operation .
*/
int mdiobus_read_nested ( struct mii_bus * bus , int addr , u32 regnum )
{
int retval ;
BUG_ON ( in_interrupt ( ) ) ;
2016-04-11 22:40:05 +03:00
mutex_lock_nested ( & bus - > mdio_lock , MDIO_MUTEX_NESTED ) ;
2015-10-22 11:37:49 +03:00
retval = bus - > read ( bus , addr , regnum ) ;
mutex_unlock ( & bus - > mdio_lock ) ;
return retval ;
}
EXPORT_SYMBOL ( mdiobus_read_nested ) ;
2008-09-29 21:12:35 +04:00
/**
* mdiobus_read - Convenience function for reading a given MII mgmt register
* @ bus : the mii_bus struct
* @ addr : the phy address
* @ regnum : register number to read
*
* NOTE : MUST NOT be called from interrupt context ,
* because the bus read / write functions may wait for an interrupt
* to conclude the operation .
*/
2010-03-09 12:17:42 +03:00
int mdiobus_read ( struct mii_bus * bus , int addr , u32 regnum )
2008-09-29 21:12:35 +04:00
{
int retval ;
BUG_ON ( in_interrupt ( ) ) ;
mutex_lock ( & bus - > mdio_lock ) ;
retval = bus - > read ( bus , addr , regnum ) ;
mutex_unlock ( & bus - > mdio_lock ) ;
return retval ;
}
EXPORT_SYMBOL ( mdiobus_read ) ;
2015-10-22 11:37:49 +03:00
/**
* mdiobus_write_nested - Nested version of the mdiobus_write function
* @ bus : the mii_bus struct
* @ addr : the phy address
* @ regnum : register number to write
* @ val : value to write to @ regnum
*
* In case of nested MDIO bus access avoid lockdep false positives by
* using mutex_lock_nested ( ) .
*
* NOTE : MUST NOT be called from interrupt context ,
* because the bus read / write functions may wait for an interrupt
* to conclude the operation .
*/
int mdiobus_write_nested ( struct mii_bus * bus , int addr , u32 regnum , u16 val )
{
int err ;
BUG_ON ( in_interrupt ( ) ) ;
2016-04-11 22:40:05 +03:00
mutex_lock_nested ( & bus - > mdio_lock , MDIO_MUTEX_NESTED ) ;
2015-10-22 11:37:49 +03:00
err = bus - > write ( bus , addr , regnum , val ) ;
mutex_unlock ( & bus - > mdio_lock ) ;
return err ;
}
EXPORT_SYMBOL ( mdiobus_write_nested ) ;
2008-09-29 21:12:35 +04:00
/**
* mdiobus_write - Convenience function for writing a given MII mgmt register
* @ bus : the mii_bus struct
* @ addr : the phy address
* @ regnum : register number to write
* @ val : value to write to @ regnum
*
* NOTE : MUST NOT be called from interrupt context ,
* because the bus read / write functions may wait for an interrupt
* to conclude the operation .
*/
2010-03-09 12:17:42 +03:00
int mdiobus_write ( struct mii_bus * bus , int addr , u32 regnum , u16 val )
2008-09-29 21:12:35 +04:00
{
int err ;
BUG_ON ( in_interrupt ( ) ) ;
mutex_lock ( & bus - > mdio_lock ) ;
err = bus - > write ( bus , addr , regnum , val ) ;
mutex_unlock ( & bus - > mdio_lock ) ;
return err ;
}
EXPORT_SYMBOL ( mdiobus_write ) ;
2007-03-06 13:41:48 +03:00
/**
2016-01-06 22:11:23 +03:00
* mdio_bus_match - determine if given MDIO driver supports the given
* MDIO device
* @ dev : target MDIO device
* @ drv : given MDIO driver
2005-07-31 03:31:23 +04:00
*
2016-01-06 22:11:23 +03:00
* Description : Given a MDIO device , and a MDIO driver , return 1 if
* the driver supports the device . Otherwise , return 0. This may
* require calling the devices own match function , since different classes
* of MDIO devices have different match criteria .
2005-07-31 03:31:23 +04:00
*/
static int mdio_bus_match ( struct device * dev , struct device_driver * drv )
{
2016-01-06 22:11:23 +03:00
struct mdio_device * mdio = to_mdio_device ( dev ) ;
2005-07-31 03:31:23 +04:00
2012-06-27 11:33:37 +04:00
if ( of_driver_match_device ( dev , drv ) )
return 1 ;
2016-01-06 22:11:23 +03:00
if ( mdio - > bus_match )
return mdio - > bus_match ( dev , drv ) ;
2012-06-27 11:33:37 +04:00
2016-01-06 22:11:23 +03:00
return 0 ;
2005-07-31 03:31:23 +04:00
}
2009-12-30 11:23:30 +03:00
# ifdef CONFIG_PM
static int mdio_bus_suspend ( struct device * dev )
2005-07-31 03:31:23 +04:00
{
2016-01-06 22:11:21 +03:00
struct mdio_device * mdio = to_mdio_device ( dev ) ;
2005-07-31 03:31:23 +04:00
2016-01-06 22:11:21 +03:00
if ( mdio - > pm_ops & & mdio - > pm_ops - > suspend )
return mdio - > pm_ops - > suspend ( dev ) ;
2009-12-30 11:23:28 +03:00
2016-01-06 22:11:21 +03:00
return 0 ;
2005-07-31 03:31:23 +04:00
}
2009-12-30 11:23:30 +03:00
static int mdio_bus_resume ( struct device * dev )
2005-07-31 03:31:23 +04:00
{
2016-01-06 22:11:21 +03:00
struct mdio_device * mdio = to_mdio_device ( dev ) ;
2009-12-30 11:23:28 +03:00
2016-01-06 22:11:21 +03:00
if ( mdio - > pm_ops & & mdio - > pm_ops - > resume )
return mdio - > pm_ops - > resume ( dev ) ;
2009-12-30 11:23:28 +03:00
return 0 ;
2005-07-31 03:31:23 +04:00
}
2009-12-30 11:23:30 +03:00
static int mdio_bus_restore ( struct device * dev )
{
2016-01-06 22:11:21 +03:00
struct mdio_device * mdio = to_mdio_device ( dev ) ;
2009-12-30 11:23:30 +03:00
2016-01-06 22:11:21 +03:00
if ( mdio - > pm_ops & & mdio - > pm_ops - > restore )
return mdio - > pm_ops - > restore ( dev ) ;
2009-12-30 11:23:30 +03:00
return 0 ;
}
2014-01-05 04:18:27 +04:00
static const struct dev_pm_ops mdio_bus_pm_ops = {
2009-12-30 11:23:30 +03:00
. suspend = mdio_bus_suspend ,
. resume = mdio_bus_resume ,
. freeze = mdio_bus_suspend ,
. thaw = mdio_bus_resume ,
. restore = mdio_bus_restore ,
} ;
# define MDIO_BUS_PM_OPS (&mdio_bus_pm_ops)
# else
# define MDIO_BUS_PM_OPS NULL
# endif /* CONFIG_PM */
2005-07-31 03:31:23 +04:00
struct bus_type mdio_bus_type = {
. name = " mdio_bus " ,
. match = mdio_bus_match ,
2009-12-30 11:23:30 +03:00
. pm = MDIO_BUS_PM_OPS ,
2005-07-31 03:31:23 +04:00
} ;
2006-08-15 10:00:29 +04:00
EXPORT_SYMBOL ( mdio_bus_type ) ;
2005-07-31 03:31:23 +04:00
2005-08-11 10:07:25 +04:00
int __init mdio_bus_init ( void )
2005-07-31 03:31:23 +04:00
{
2008-10-09 03:33:40 +04:00
int ret ;
ret = class_register ( & mdio_bus_class ) ;
if ( ! ret ) {
ret = bus_register ( & mdio_bus_type ) ;
if ( ret )
class_unregister ( & mdio_bus_class ) ;
}
return ret ;
2005-07-31 03:31:23 +04:00
}
2005-09-04 01:05:06 +04:00
void mdio_bus_exit ( void )
2005-08-25 03:46:21 +04:00
{
2008-10-09 03:33:40 +04:00
class_unregister ( & mdio_bus_class ) ;
2005-08-25 03:46:21 +04:00
bus_unregister ( & mdio_bus_type ) ;
}