2019-01-21 19:05:50 +01:00
// SPDX-License-Identifier: GPL-2.0+
2016-08-10 11:20:08 +05:30
/* Xilinx GMII2RGMII Converter driver
*
* Copyright ( C ) 2016 Xilinx , Inc .
2016-08-16 11:58:29 +05:30
* Copyright ( C ) 2016 Andrew Lunn < andrew @ lunn . ch >
2016-08-10 11:20:08 +05:30
*
2016-08-16 11:58:29 +05:30
* Author : Andrew Lunn < andrew @ lunn . ch >
2016-08-10 11:20:08 +05:30
* Author : Kedareswara rao Appana < appanad @ xilinx . com >
*
* Description :
* This driver is developed for Xilinx GMII2RGMII Converter
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/mii.h>
# include <linux/mdio.h>
# include <linux/phy.h>
# include <linux/of_mdio.h>
# define XILINX_GMII2RGMII_REG 0x10
# define XILINX_GMII2RGMII_SPEED_MASK (BMCR_SPEED1000 | BMCR_SPEED100)
struct gmii2rgmii {
struct phy_device * phy_dev ;
struct phy_driver * phy_drv ;
struct phy_driver conv_phy_drv ;
2018-06-26 12:50:49 -05:00
struct mdio_device * mdio ;
2016-08-10 11:20:08 +05:30
} ;
static int xgmiitorgmii_read_status ( struct phy_device * phydev )
{
2019-09-04 19:30:21 +05:30
struct gmii2rgmii * priv = mdiodev_get_drvdata ( & phydev - > mdio ) ;
2018-06-26 12:50:49 -05:00
struct mii_bus * bus = priv - > mdio - > bus ;
int addr = priv - > mdio - > addr ;
2016-08-10 11:20:08 +05:30
u16 val = 0 ;
2018-06-26 12:50:50 -05:00
int err ;
2016-08-10 11:20:08 +05:30
2019-02-15 17:17:08 +01:00
if ( priv - > phy_drv - > read_status )
err = priv - > phy_drv - > read_status ( phydev ) ;
else
err = genphy_read_status ( phydev ) ;
2018-06-26 12:50:50 -05:00
if ( err < 0 )
return err ;
2016-08-10 11:20:08 +05:30
2018-06-26 12:50:49 -05:00
val = mdiobus_read ( bus , addr , XILINX_GMII2RGMII_REG ) ;
2017-09-15 12:01:58 +05:30
val & = ~ XILINX_GMII2RGMII_SPEED_MASK ;
2016-08-10 11:20:08 +05:30
if ( phydev - > speed = = SPEED_1000 )
val | = BMCR_SPEED1000 ;
else if ( phydev - > speed = = SPEED_100 )
val | = BMCR_SPEED100 ;
else
val | = BMCR_SPEED10 ;
2018-06-26 12:50:49 -05:00
mdiobus_write ( bus , addr , XILINX_GMII2RGMII_REG , val ) ;
2016-08-10 11:20:08 +05:30
return 0 ;
}
2016-08-23 15:06:05 +00:00
static int xgmiitorgmii_probe ( struct mdio_device * mdiodev )
2016-08-10 11:20:08 +05:30
{
struct device * dev = & mdiodev - > dev ;
struct device_node * np = dev - > of_node , * phy_node ;
struct gmii2rgmii * priv ;
priv = devm_kzalloc ( dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
phy_node = of_parse_phandle ( np , " phy-handle " , 0 ) ;
2016-08-15 22:34:57 +00:00
if ( ! phy_node ) {
2016-08-10 11:20:08 +05:30
dev_err ( dev , " Couldn't parse phy-handle \n " ) ;
return - ENODEV ;
}
priv - > phy_dev = of_phy_find_device ( phy_node ) ;
2016-08-21 22:46:15 +00:00
of_node_put ( phy_node ) ;
2016-08-10 11:20:08 +05:30
if ( ! priv - > phy_dev ) {
dev_info ( dev , " Couldn't find phydev \n " ) ;
return - EPROBE_DEFER ;
}
2018-06-26 12:50:48 -05:00
if ( ! priv - > phy_dev - > drv ) {
dev_info ( dev , " Attached phy not ready \n " ) ;
return - EPROBE_DEFER ;
}
2018-06-26 12:50:49 -05:00
priv - > mdio = mdiodev ;
2016-08-10 11:20:08 +05:30
priv - > phy_drv = priv - > phy_dev - > drv ;
memcpy ( & priv - > conv_phy_drv , priv - > phy_dev - > drv ,
sizeof ( struct phy_driver ) ) ;
priv - > conv_phy_drv . read_status = xgmiitorgmii_read_status ;
2019-09-04 19:30:21 +05:30
mdiodev_set_drvdata ( & priv - > phy_dev - > mdio , priv ) ;
2016-08-10 11:20:08 +05:30
priv - > phy_dev - > drv = & priv - > conv_phy_drv ;
return 0 ;
}
static const struct of_device_id xgmiitorgmii_of_match [ ] = {
{ . compatible = " xlnx,gmii-to-rgmii-1.0 " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , xgmiitorgmii_of_match ) ;
static struct mdio_driver xgmiitorgmii_driver = {
. probe = xgmiitorgmii_probe ,
. mdiodrv . driver = {
. name = " xgmiitorgmii " ,
. of_match_table = xgmiitorgmii_of_match ,
} ,
} ;
mdio_module_driver ( xgmiitorgmii_driver ) ;
MODULE_DESCRIPTION ( " Xilinx GMII2RGMII converter driver " ) ;
MODULE_LICENSE ( " GPL " ) ;