2005-07-31 03:31:23 +04:00
/*
* drivers / net / phy / mdio_bus . c
*
* MDIO Bus interface
*
* 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 .
*
*/
# include <linux/kernel.h>
# include <linux/sched.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>
# 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>
# include <asm/io.h>
# include <asm/irq.h>
# include <asm/uaccess.h>
2005-08-25 03:46:21 +04:00
/* mdiobus_register
*
* description : Called by a bus driver to bring up all the PHYs
* on a given bus , and attach them to the bus
*/
int mdiobus_register ( struct mii_bus * bus )
{
int i ;
int err = 0 ;
spin_lock_init ( & bus - > mdio_lock ) ;
if ( NULL = = bus | | NULL = = bus - > name | |
NULL = = bus - > read | |
NULL = = bus - > write )
return - EINVAL ;
if ( bus - > reset )
bus - > reset ( bus ) ;
for ( i = 0 ; i < PHY_MAX_ADDR ; i + + ) {
struct phy_device * phydev ;
2006-05-10 20:12:57 +04:00
if ( bus - > phy_mask & ( 1 < < i ) ) {
bus - > phy_map [ i ] = NULL ;
2005-11-03 02:13:06 +03:00
continue ;
2006-05-10 20:12:57 +04:00
}
2005-11-03 02:13:06 +03:00
2005-08-25 03:46:21 +04:00
phydev = get_phy_device ( bus , i ) ;
if ( IS_ERR ( phydev ) )
return PTR_ERR ( phydev ) ;
/* There's a PHY at this address
* We need to set :
* 1 ) IRQ
* 2 ) bus_id
* 3 ) parent
* 4 ) bus
* 5 ) mii_bus
* And , we need to register it */
if ( phydev ) {
phydev - > irq = bus - > irq [ i ] ;
phydev - > dev . parent = bus - > dev ;
phydev - > dev . bus = & mdio_bus_type ;
2006-01-11 22:27:33 +03:00
snprintf ( phydev - > dev . bus_id , BUS_ID_SIZE , PHY_ID_FMT , bus - > id , i ) ;
2005-08-25 03:46:21 +04:00
phydev - > bus = bus ;
err = device_register ( & phydev - > dev ) ;
if ( err )
printk ( KERN_ERR " phy %d failed to register \n " ,
i ) ;
}
bus - > phy_map [ i ] = phydev ;
}
pr_info ( " %s: probed \n " , bus - > name ) ;
return err ;
}
EXPORT_SYMBOL ( mdiobus_register ) ;
void mdiobus_unregister ( struct mii_bus * bus )
{
int i ;
for ( i = 0 ; i < PHY_MAX_ADDR ; i + + ) {
if ( bus - > phy_map [ i ] ) {
device_unregister ( & bus - > phy_map [ i ] - > dev ) ;
kfree ( bus - > phy_map [ i ] ) ;
}
}
}
EXPORT_SYMBOL ( mdiobus_unregister ) ;
2005-07-31 03:31:23 +04:00
/* mdio_bus_match
*
* description : Given a PHY device , and a PHY driver , return 1 if
* the driver supports the device . Otherwise , return 0
*/
static int mdio_bus_match ( struct device * dev , struct device_driver * drv )
{
struct phy_device * phydev = to_phy_device ( dev ) ;
struct phy_driver * phydrv = to_phy_driver ( drv ) ;
return ( phydrv - > phy_id = = ( phydev - > phy_id & phydrv - > phy_id_mask ) ) ;
}
/* Suspend and resume. Copied from platform_suspend and
* platform_resume
*/
2005-09-04 02:56:56 +04:00
static int mdio_bus_suspend ( struct device * dev , pm_message_t state )
2005-07-31 03:31:23 +04:00
{
int ret = 0 ;
struct device_driver * drv = dev - > driver ;
2005-10-28 20:52:56 +04:00
if ( drv & & drv - > suspend )
ret = drv - > suspend ( dev , state ) ;
2005-07-31 03:31:23 +04:00
return ret ;
}
static int mdio_bus_resume ( struct device * dev )
{
int ret = 0 ;
struct device_driver * drv = dev - > driver ;
2005-10-28 20:52:56 +04:00
if ( drv & & drv - > resume )
ret = drv - > resume ( dev ) ;
2005-07-31 03:31:23 +04:00
return ret ;
}
struct bus_type mdio_bus_type = {
. name = " mdio_bus " ,
. match = mdio_bus_match ,
. suspend = mdio_bus_suspend ,
. resume = mdio_bus_resume ,
} ;
2005-08-11 10:07:25 +04:00
int __init mdio_bus_init ( void )
2005-07-31 03:31:23 +04:00
{
return bus_register ( & mdio_bus_type ) ;
}
2005-09-04 01:05:06 +04:00
void mdio_bus_exit ( void )
2005-08-25 03:46:21 +04:00
{
bus_unregister ( & mdio_bus_type ) ;
}