2009-02-05 03:42:12 +03:00
/*
* Freescale PowerQUICC Ethernet Driver - - MIIM bus implementation
* Provides Bus interface for MIIM regs
*
* Author : Andy Fleming < afleming @ freescale . com >
2009-11-02 10:03:22 +03:00
* Modifier : Sandeep Gopalpet < sandeep . kumar @ freescale . com >
2009-02-05 03:42:12 +03:00
*
2009-11-02 10:03:22 +03:00
* Copyright 2002 - 2004 , 2008 - 2009 Freescale Semiconductor , Inc .
2009-02-05 03:42:12 +03:00
*
* Based on gianfar_mii . c and ucc_geth_mii . c ( Li Yang , Kim Phillips )
*
* 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/string.h>
# include <linux/errno.h>
# include <linux/slab.h>
# include <linux/delay.h>
# include <linux/module.h>
# include <linux/mii.h>
2010-07-29 21:49:01 +04:00
# include <linux/of_address.h>
2009-04-25 16:53:07 +04:00
# include <linux/of_mdio.h>
2012-08-29 12:08:01 +04:00
# include <linux/of_device.h>
2009-02-05 03:42:12 +03:00
# include <asm/io.h>
2014-10-07 11:44:28 +04:00
# if IS_ENABLED(CONFIG_UCC_GETH)
2015-11-30 05:48:57 +03:00
# include <soc/fsl/qe/ucc.h>
2014-10-07 11:44:28 +04:00
# endif
2009-02-05 03:42:12 +03:00
# include "gianfar.h"
2012-08-29 12:07:57 +04:00
# define MIIMIND_BUSY 0x00000001
# define MIIMIND_NOTVALID 0x00000004
# define MIIMCFG_INIT_VALUE 0x00000007
# define MIIMCFG_RESET 0x80000000
# define MII_READ_COMMAND 0x00000001
2012-08-29 12:08:01 +04:00
struct fsl_pq_mii {
u32 miimcfg ; /* MII management configuration reg */
u32 miimcom ; /* MII management command reg */
u32 miimadd ; /* MII management address reg */
u32 miimcon ; /* MII management control reg */
u32 miimstat ; /* MII management status reg */
u32 miimind ; /* MII management indication reg */
} ;
2012-08-29 12:07:57 +04:00
struct fsl_pq_mdio {
u8 res1 [ 16 ] ;
u32 ieventm ; /* MDIO Interrupt event register (for etsec2)*/
u32 imaskm ; /* MDIO Interrupt mask register (for etsec2)*/
u8 res2 [ 4 ] ;
u32 emapm ; /* MDIO Event mapping register (for etsec2)*/
u8 res3 [ 1280 ] ;
2012-08-29 12:08:01 +04:00
struct fsl_pq_mii mii ;
2012-08-29 12:07:57 +04:00
u8 res4 [ 28 ] ;
u32 utbipar ; /* TBI phy address reg (only on UCC) */
u8 res5 [ 2728 ] ;
} __packed ;
2009-02-05 03:42:12 +03:00
2012-07-10 01:57:36 +04:00
/* Number of microseconds to wait for an MII register to respond */
# define MII_TIMEOUT 1000
2009-12-30 11:23:34 +03:00
struct fsl_pq_mdio_priv {
void __iomem * map ;
2012-08-29 12:08:01 +04:00
struct fsl_pq_mii __iomem * regs ;
} ;
/*
* Per - device - type data . Each type of device tree node that we support gets
* one of these .
*
* @ mii_offset : the offset of the MII registers within the memory map of the
* node . Some nodes define only the MII registers , and some define the whole
* MAC ( which includes the MII registers ) .
*
* @ get_tbipa : determines the address of the TBIPA register
*
* @ ucc_configure : a special function for extra QE configuration
*/
struct fsl_pq_mdio_data {
unsigned int mii_offset ; /* offset of the MII registers */
uint32_t __iomem * ( * get_tbipa ) ( void __iomem * p ) ;
void ( * ucc_configure ) ( phys_addr_t start , phys_addr_t end ) ;
2009-12-30 11:23:34 +03:00
} ;
2009-02-05 03:42:12 +03:00
/*
2012-08-29 12:07:59 +04:00
* Write value to the PHY at mii_id at register regnum , on the bus attached
* to the local interface , which may be different from the generic mdio bus
* ( tied to a single interface ) , waiting until the write is done before
* returning . This is helpful in programming interfaces like the TBI which
* control interfaces like onchip SERDES and are always tied to the local
* mdio pins , which may not be the same as system mdio bus , used for
2009-02-05 03:42:12 +03:00
* controlling the external PHYs , for example .
*/
2012-08-29 12:07:59 +04:00
static int fsl_pq_mdio_write ( struct mii_bus * bus , int mii_id , int regnum ,
u16 value )
2009-02-05 03:42:12 +03:00
{
2012-08-29 12:07:59 +04:00
struct fsl_pq_mdio_priv * priv = bus - > priv ;
2012-08-29 12:08:01 +04:00
struct fsl_pq_mii __iomem * regs = priv - > regs ;
2014-10-07 11:44:30 +04:00
unsigned int timeout ;
2012-07-10 01:57:36 +04:00
2009-02-05 03:42:12 +03:00
/* Set the PHY address and the register address we want to write */
2014-10-07 11:44:29 +04:00
iowrite32be ( ( mii_id < < 8 ) | regnum , & regs - > miimadd ) ;
2009-02-05 03:42:12 +03:00
/* Write out the value we want */
2014-10-07 11:44:29 +04:00
iowrite32be ( value , & regs - > miimcon ) ;
2009-02-05 03:42:12 +03:00
/* Wait for the transaction to finish */
2014-10-07 11:44:30 +04:00
timeout = MII_TIMEOUT ;
while ( ( ioread32be ( & regs - > miimind ) & MIIMIND_BUSY ) & & timeout ) {
cpu_relax ( ) ;
timeout - - ;
}
2009-02-05 03:42:12 +03:00
2014-10-07 11:44:30 +04:00
return timeout ? 0 : - ETIMEDOUT ;
2009-02-05 03:42:12 +03:00
}
/*
2012-08-29 12:07:59 +04:00
* Read the bus for PHY at addr mii_id , register regnum , and return the value .
* Clears miimcom first .
*
* All PHY operation done on the bus attached to the local interface , which
* may be different from the generic mdio bus . This is helpful in programming
* interfaces like the TBI which , in turn , control interfaces like on - chip
* SERDES and are always tied to the local mdio pins , which may not be the
2009-02-05 03:42:12 +03:00
* same as system mdio bus , used for controlling the external PHYs , for eg .
*/
2012-08-29 12:07:59 +04:00
static int fsl_pq_mdio_read ( struct mii_bus * bus , int mii_id , int regnum )
2009-02-05 03:42:12 +03:00
{
2012-08-29 12:07:59 +04:00
struct fsl_pq_mdio_priv * priv = bus - > priv ;
2012-08-29 12:08:01 +04:00
struct fsl_pq_mii __iomem * regs = priv - > regs ;
2014-10-07 11:44:30 +04:00
unsigned int timeout ;
2012-08-29 12:07:59 +04:00
u16 value ;
2009-02-05 03:42:12 +03:00
/* Set the PHY address and the register address we want to read */
2014-10-07 11:44:29 +04:00
iowrite32be ( ( mii_id < < 8 ) | regnum , & regs - > miimadd ) ;
2009-02-05 03:42:12 +03:00
/* Clear miimcom, and then initiate a read */
2014-10-07 11:44:29 +04:00
iowrite32be ( 0 , & regs - > miimcom ) ;
iowrite32be ( MII_READ_COMMAND , & regs - > miimcom ) ;
2009-02-05 03:42:12 +03:00
2012-07-10 01:57:36 +04:00
/* Wait for the transaction to finish, normally less than 100us */
2014-10-07 11:44:30 +04:00
timeout = MII_TIMEOUT ;
while ( ( ioread32be ( & regs - > miimind ) &
( MIIMIND_NOTVALID | MIIMIND_BUSY ) ) & & timeout ) {
cpu_relax ( ) ;
timeout - - ;
}
if ( ! timeout )
2012-07-10 01:57:36 +04:00
return - ETIMEDOUT ;
2009-02-05 03:42:12 +03:00
/* Grab the value of the register from miimstat */
2014-10-07 11:44:29 +04:00
value = ioread32be ( & regs - > miimstat ) ;
2009-02-05 03:42:12 +03:00
2012-08-29 12:08:01 +04:00
dev_dbg ( & bus - > dev , " read %04x from address %x/%x \n " , value , mii_id , regnum ) ;
2009-02-05 03:42:12 +03:00
return value ;
}
/* Reset the MIIM registers, and wait for the bus to free */
static int fsl_pq_mdio_reset ( struct mii_bus * bus )
{
2012-08-29 12:07:59 +04:00
struct fsl_pq_mdio_priv * priv = bus - > priv ;
2012-08-29 12:08:01 +04:00
struct fsl_pq_mii __iomem * regs = priv - > regs ;
2014-10-07 11:44:30 +04:00
unsigned int timeout ;
2009-02-05 03:42:12 +03:00
mutex_lock ( & bus - > mdio_lock ) ;
/* Reset the management interface */
2014-10-07 11:44:29 +04:00
iowrite32be ( MIIMCFG_RESET , & regs - > miimcfg ) ;
2009-02-05 03:42:12 +03:00
/* Setup the MII Mgmt clock speed */
2014-10-07 11:44:29 +04:00
iowrite32be ( MIIMCFG_INIT_VALUE , & regs - > miimcfg ) ;
2009-02-05 03:42:12 +03:00
/* Wait until the bus is free */
2014-10-07 11:44:30 +04:00
timeout = MII_TIMEOUT ;
while ( ( ioread32be ( & regs - > miimind ) & MIIMIND_BUSY ) & & timeout ) {
cpu_relax ( ) ;
timeout - - ;
}
2009-02-05 03:42:12 +03:00
mutex_unlock ( & bus - > mdio_lock ) ;
2014-10-07 11:44:30 +04:00
if ( ! timeout ) {
2012-08-29 12:08:00 +04:00
dev_err ( & bus - > dev , " timeout waiting for MII bus \n " ) ;
2009-02-05 03:42:12 +03:00
return - EBUSY ;
}
return 0 ;
}
2011-11-11 09:10:39 +04:00
# if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE)
2012-08-29 12:08:01 +04:00
/*
2015-10-12 10:18:41 +03:00
* Return the TBIPA address , starting from the address
* of the mapped GFAR MDIO registers ( struct gfar )
2012-08-29 12:08:01 +04:00
* This is mildly evil , but so is our hardware for doing this .
* Also , we have to cast back to struct gfar because of
* definition weirdness done in gianfar . h .
*/
2015-10-12 10:18:41 +03:00
static uint32_t __iomem * get_gfar_tbipa_from_mdio ( void __iomem * p )
2012-08-29 12:08:01 +04:00
{
struct gfar __iomem * enet_regs = p ;
2009-02-05 03:42:12 +03:00
2012-08-29 12:08:01 +04:00
return & enet_regs - > tbipa ;
2011-11-11 09:10:39 +04:00
}
2009-02-05 03:42:12 +03:00
2015-10-12 10:18:41 +03:00
/*
* Return the TBIPA address , starting from the address
* of the mapped GFAR MII registers ( gfar_mii_regs [ ] within struct gfar )
*/
static uint32_t __iomem * get_gfar_tbipa_from_mii ( void __iomem * p )
{
return get_gfar_tbipa_from_mdio ( container_of ( p , struct gfar , gfar_mii_regs ) ) ;
}
2012-08-29 12:08:01 +04:00
/*
* Return the TBIPAR address for an eTSEC2 node
*/
static uint32_t __iomem * get_etsec_tbipa ( void __iomem * p )
2009-02-05 03:42:12 +03:00
{
2012-08-29 12:08:01 +04:00
return p ;
}
# endif
2011-11-11 09:10:39 +04:00
# if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE)
2012-08-29 12:08:01 +04:00
/*
2015-10-12 10:18:41 +03:00
* Return the TBIPAR address for a QE MDIO node , starting from the address
* of the mapped MII registers ( struct fsl_pq_mii )
2012-08-29 12:08:01 +04:00
*/
static uint32_t __iomem * get_ucc_tbipa ( void __iomem * p )
{
2015-10-12 10:18:41 +03:00
struct fsl_pq_mdio __iomem * mdio = container_of ( p , struct fsl_pq_mdio , mii ) ;
2012-08-29 12:08:01 +04:00
return & mdio - > utbipar ;
}
/*
* Find the UCC node that controls the given MDIO node
*
* For some reason , the QE MDIO nodes are not children of the UCC devices
* that control them . Therefore , we need to scan all UCC nodes looking for
* the one that encompases the given MDIO node . We do this by comparing
* physical addresses . The ' start ' and ' end ' addresses of the MDIO node are
* passed , and the correct UCC node will cover the entire address range .
*
* This assumes that there is only one QE MDIO node in the entire device tree .
*/
static void ucc_configure ( phys_addr_t start , phys_addr_t end )
{
static bool found_mii_master ;
2009-02-05 03:42:12 +03:00
struct device_node * np = NULL ;
2012-08-29 12:08:01 +04:00
if ( found_mii_master )
return ;
2009-02-05 03:42:12 +03:00
2012-08-29 12:08:01 +04:00
for_each_compatible_node ( np , NULL , " ucc_geth " ) {
struct resource res ;
const uint32_t * iprop ;
uint32_t id ;
int ret ;
ret = of_address_to_resource ( np , 0 , & res ) ;
if ( ret < 0 ) {
pr_debug ( " fsl-pq-mdio: no address range in node %s \n " ,
np - > full_name ) ;
2009-02-05 03:42:12 +03:00
continue ;
2012-08-29 12:08:01 +04:00
}
2009-02-05 03:42:12 +03:00
/* if our mdio regs fall within this UCC regs range */
2012-08-29 12:08:01 +04:00
if ( ( start < res . start ) | | ( end > res . end ) )
continue ;
iprop = of_get_property ( np , " cell-index " , NULL ) ;
if ( ! iprop ) {
iprop = of_get_property ( np , " device-id " , NULL ) ;
if ( ! iprop ) {
pr_debug ( " fsl-pq-mdio: no UCC ID in node %s \n " ,
np - > full_name ) ;
continue ;
2009-02-05 03:42:12 +03:00
}
2012-08-29 12:08:01 +04:00
}
2009-02-05 03:42:12 +03:00
2012-08-29 12:08:01 +04:00
id = be32_to_cpup ( iprop ) ;
2009-02-05 03:42:12 +03:00
2012-08-29 12:08:01 +04:00
/*
* cell - index and device - id for QE nodes are
* numbered from 1 , not 0.
*/
if ( ucc_set_qe_mux_mii_mng ( id - 1 ) < 0 ) {
pr_debug ( " fsl-pq-mdio: invalid UCC ID in node %s \n " ,
np - > full_name ) ;
continue ;
2009-02-05 03:42:12 +03:00
}
2012-08-29 12:08:01 +04:00
pr_debug ( " fsl-pq-mdio: setting node UCC%u to MII master \n " , id ) ;
found_mii_master = true ;
2009-02-05 03:42:12 +03:00
}
2012-08-29 12:08:01 +04:00
}
2009-02-05 03:42:12 +03:00
# endif
2012-08-29 12:08:01 +04:00
2015-03-17 21:37:34 +03:00
static const struct of_device_id fsl_pq_mdio_match [ ] = {
2012-08-29 12:08:01 +04:00
# if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE)
{
. compatible = " fsl,gianfar-tbi " ,
. data = & ( struct fsl_pq_mdio_data ) {
. mii_offset = 0 ,
2015-10-12 10:18:41 +03:00
. get_tbipa = get_gfar_tbipa_from_mii ,
2012-08-29 12:08:01 +04:00
} ,
} ,
{
. compatible = " fsl,gianfar-mdio " ,
. data = & ( struct fsl_pq_mdio_data ) {
. mii_offset = 0 ,
2015-10-12 10:18:41 +03:00
. get_tbipa = get_gfar_tbipa_from_mii ,
2012-08-29 12:08:01 +04:00
} ,
} ,
{
. type = " mdio " ,
. compatible = " gianfar " ,
. data = & ( struct fsl_pq_mdio_data ) {
. mii_offset = offsetof ( struct fsl_pq_mdio , mii ) ,
2015-10-12 10:18:41 +03:00
. get_tbipa = get_gfar_tbipa_from_mdio ,
2012-08-29 12:08:01 +04:00
} ,
} ,
{
. compatible = " fsl,etsec2-tbi " ,
. data = & ( struct fsl_pq_mdio_data ) {
. mii_offset = offsetof ( struct fsl_pq_mdio , mii ) ,
. get_tbipa = get_etsec_tbipa ,
} ,
} ,
{
. compatible = " fsl,etsec2-mdio " ,
. data = & ( struct fsl_pq_mdio_data ) {
. mii_offset = offsetof ( struct fsl_pq_mdio , mii ) ,
. get_tbipa = get_etsec_tbipa ,
} ,
} ,
# endif
# if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE)
{
. compatible = " fsl,ucc-mdio " ,
. data = & ( struct fsl_pq_mdio_data ) {
. mii_offset = 0 ,
. get_tbipa = get_ucc_tbipa ,
. ucc_configure = ucc_configure ,
} ,
} ,
{
/* Legacy UCC MDIO node */
. type = " mdio " ,
. compatible = " ucc_geth_phy " ,
. data = & ( struct fsl_pq_mdio_data ) {
. mii_offset = 0 ,
. get_tbipa = get_ucc_tbipa ,
. ucc_configure = ucc_configure ,
} ,
} ,
# endif
2012-08-29 12:08:03 +04:00
/* No Kconfig option for Fman support yet */
{
. compatible = " fsl,fman-mdio " ,
. data = & ( struct fsl_pq_mdio_data ) {
. mii_offset = 0 ,
/* Fman TBI operations are handled elsewhere */
} ,
} ,
2012-08-29 12:08:01 +04:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , fsl_pq_mdio_match ) ;
2009-02-05 03:42:12 +03:00
2012-08-29 12:08:00 +04:00
static int fsl_pq_mdio_probe ( struct platform_device * pdev )
2009-02-05 03:42:12 +03:00
{
2012-08-29 12:08:01 +04:00
const struct of_device_id * id =
of_match_device ( fsl_pq_mdio_match , & pdev - > dev ) ;
const struct fsl_pq_mdio_data * data = id - > data ;
2012-08-29 12:08:00 +04:00
struct device_node * np = pdev - > dev . of_node ;
2012-08-29 12:08:01 +04:00
struct resource res ;
2009-02-05 03:42:12 +03:00
struct device_node * tbi ;
2009-12-30 11:23:34 +03:00
struct fsl_pq_mdio_priv * priv ;
2009-02-05 03:42:12 +03:00
struct mii_bus * new_bus ;
2010-05-14 08:27:30 +04:00
int err ;
2009-02-05 03:42:12 +03:00
2012-08-29 12:08:01 +04:00
dev_dbg ( & pdev - > dev , " found %s compatible node \n " , id - > compatible ) ;
2012-08-29 12:08:02 +04:00
new_bus = mdiobus_alloc_size ( sizeof ( * priv ) ) ;
if ( ! new_bus )
2009-12-30 11:23:34 +03:00
return - ENOMEM ;
2012-08-29 12:08:02 +04:00
priv = new_bus - > priv ;
2009-02-05 03:42:12 +03:00
new_bus - > name = " Freescale PowerQUICC MII Bus " ,
2012-08-29 12:08:00 +04:00
new_bus - > read = & fsl_pq_mdio_read ;
new_bus - > write = & fsl_pq_mdio_write ;
new_bus - > reset = & fsl_pq_mdio_reset ;
2009-02-05 03:42:12 +03:00
2012-08-29 12:08:01 +04:00
err = of_address_to_resource ( np , 0 , & res ) ;
if ( err < 0 ) {
dev_err ( & pdev - > dev , " could not obtain address information \n " ) ;
2012-08-29 12:08:02 +04:00
goto error ;
2010-04-23 11:12:35 +04:00
}
2012-08-29 12:07:59 +04:00
snprintf ( new_bus - > id , MII_BUS_ID_SIZE , " %s@%llx " , np - > name ,
2012-08-29 12:08:01 +04:00
( unsigned long long ) res . start ) ;
2012-08-29 12:07:59 +04:00
2012-08-29 12:08:01 +04:00
priv - > map = of_iomap ( np , 0 ) ;
if ( ! priv - > map ) {
2009-02-05 03:42:12 +03:00
err = - ENOMEM ;
2012-08-29 12:08:02 +04:00
goto error ;
2009-02-05 03:42:12 +03:00
}
2012-08-29 12:08:01 +04:00
/*
* Some device tree nodes represent only the MII registers , and
* others represent the MAC and MII registers . The ' mii_offset ' field
* contains the offset of the MII registers inside the mapped register
* space .
*/
if ( data - > mii_offset > resource_size ( & res ) ) {
dev_err ( & pdev - > dev , " invalid register map \n " ) ;
err = - EINVAL ;
2012-08-29 12:08:02 +04:00
goto error ;
2012-08-29 12:08:01 +04:00
}
priv - > regs = priv - > map + data - > mii_offset ;
2009-02-05 03:42:12 +03:00
2012-08-29 12:08:00 +04:00
new_bus - > parent = & pdev - > dev ;
2013-08-19 15:58:40 +04:00
platform_set_drvdata ( pdev , new_bus ) ;
2009-02-05 03:42:12 +03:00
2012-08-29 12:08:01 +04:00
if ( data - > get_tbipa ) {
for_each_child_of_node ( np , tbi ) {
if ( strcmp ( tbi - > type , " tbi-phy " ) = = 0 ) {
dev_dbg ( & pdev - > dev , " found TBI PHY node %s \n " ,
strrchr ( tbi - > full_name , ' / ' ) + 1 ) ;
break ;
}
2009-06-02 08:04:14 +04:00
}
2009-02-05 03:42:12 +03:00
2012-08-29 12:08:01 +04:00
if ( tbi ) {
const u32 * prop = of_get_property ( tbi , " reg " , NULL ) ;
uint32_t __iomem * tbipa ;
2009-02-05 03:42:12 +03:00
2012-08-29 12:08:01 +04:00
if ( ! prop ) {
dev_err ( & pdev - > dev ,
" missing 'reg' property in node %s \n " ,
tbi - > full_name ) ;
err = - EBUSY ;
goto error ;
}
2009-02-05 03:42:12 +03:00
2012-08-29 12:08:01 +04:00
tbipa = data - > get_tbipa ( priv - > map ) ;
2009-02-05 03:42:12 +03:00
2015-10-12 10:18:40 +03:00
/*
* Add consistency check to make sure TBI is contained
* within the mapped range ( not because we would get a
* segfault , rather to catch bugs in computing TBI
* address ) . Print error message but continue anyway .
*/
if ( ( void * ) tbipa > priv - > map + resource_size ( & res ) - 4 )
2015-12-08 18:17:29 +03:00
dev_err ( & pdev - > dev , " invalid register map (should be at least 0x%04zx to contain TBI address) \n " ,
2015-10-12 10:18:40 +03:00
( ( void * ) tbipa - priv - > map ) + 4 ) ;
2014-10-07 11:44:29 +04:00
iowrite32be ( be32_to_cpup ( prop ) , tbipa ) ;
2012-03-28 02:05:54 +04:00
}
2009-02-05 03:42:12 +03:00
}
2012-08-29 12:08:01 +04:00
if ( data - > ucc_configure )
data - > ucc_configure ( res . start , res . end ) ;
2009-04-25 16:53:07 +04:00
err = of_mdiobus_register ( new_bus , np ) ;
2009-02-05 03:42:12 +03:00
if ( err ) {
2012-08-29 12:08:00 +04:00
dev_err ( & pdev - > dev , " cannot register %s as MDIO bus \n " ,
new_bus - > name ) ;
2012-08-29 12:08:02 +04:00
goto error ;
2009-02-05 03:42:12 +03:00
}
return 0 ;
2012-08-29 12:08:02 +04:00
error :
if ( priv - > map )
iounmap ( priv - > map ) ;
2009-02-05 03:42:12 +03:00
kfree ( new_bus ) ;
2012-08-29 12:08:02 +04:00
2009-02-05 03:42:12 +03:00
return err ;
}
2012-08-29 12:08:00 +04:00
static int fsl_pq_mdio_remove ( struct platform_device * pdev )
2009-02-05 03:42:12 +03:00
{
2012-08-29 12:08:00 +04:00
struct device * device = & pdev - > dev ;
2009-02-05 03:42:12 +03:00
struct mii_bus * bus = dev_get_drvdata ( device ) ;
2009-12-30 11:23:34 +03:00
struct fsl_pq_mdio_priv * priv = bus - > priv ;
2009-02-05 03:42:12 +03:00
mdiobus_unregister ( bus ) ;
2009-12-30 11:23:34 +03:00
iounmap ( priv - > map ) ;
2009-02-05 03:42:12 +03:00
mdiobus_free ( bus ) ;
return 0 ;
}
2011-02-23 07:05:51 +03:00
static struct platform_driver fsl_pq_mdio_driver = {
2010-04-14 03:13:02 +04:00
. driver = {
. name = " fsl-pq_mdio " ,
. of_match_table = fsl_pq_mdio_match ,
} ,
2009-02-05 03:42:12 +03:00
. probe = fsl_pq_mdio_probe ,
. remove = fsl_pq_mdio_remove ,
} ;
2011-11-27 20:44:17 +04:00
module_platform_driver ( fsl_pq_mdio_driver ) ;
2009-02-05 03:42:12 +03:00
2009-11-06 11:50:28 +03:00
MODULE_LICENSE ( " GPL " ) ;