2019-01-21 19:10:19 +01:00
// SPDX-License-Identifier: GPL-2.0
2015-06-02 09:34:37 -05:00
/*
* Driver for the Texas Instruments DP83867 PHY
*
* Copyright ( C ) 2015 Texas Instruments Inc .
*/
# include <linux/ethtool.h>
# include <linux/kernel.h>
# include <linux/mii.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/phy.h>
2019-02-25 12:15:10 +03:00
# include <linux/delay.h>
2015-06-02 09:34:37 -05:00
# include <dt-bindings/net/ti-dp83867.h>
# define DP83867_PHY_ID 0x2000a231
# define DP83867_DEVADDR 0x1f
# define MII_DP83867_PHYCTRL 0x10
# define MII_DP83867_MICR 0x12
# define MII_DP83867_ISR 0x13
# define DP83867_CTRL 0x1f
2017-01-05 14:48:07 -06:00
# define DP83867_CFG3 0x1e
2015-06-02 09:34:37 -05:00
/* Extended Registers */
2017-02-07 06:20:23 +01:00
# define DP83867_CFG4 0x0031
2019-05-28 13:00:50 +03:00
# define DP83867_CFG4_SGMII_ANEG_MASK (BIT(5) | BIT(6))
# define DP83867_CFG4_SGMII_ANEG_TIMER_11MS (3 << 5)
# define DP83867_CFG4_SGMII_ANEG_TIMER_800US (2 << 5)
# define DP83867_CFG4_SGMII_ANEG_TIMER_2US (1 << 5)
# define DP83867_CFG4_SGMII_ANEG_TIMER_16MS (0 << 5)
2015-06-02 09:34:37 -05:00
# define DP83867_RGMIICTL 0x0032
2017-02-07 06:20:24 +01:00
# define DP83867_STRAP_STS1 0x006E
2019-05-22 18:43:23 +00:00
# define DP83867_STRAP_STS2 0x006f
2015-06-02 09:34:37 -05:00
# define DP83867_RGMIIDCTL 0x0086
2016-10-18 16:50:18 +05:30
# define DP83867_IO_MUX_CFG 0x0170
2019-05-28 13:00:49 +03:00
# define DP83867_10M_SGMII_CFG 0x016F
# define DP83867_10M_SGMII_RATE_ADAPT_MASK BIT(7)
2015-06-02 09:34:37 -05:00
# define DP83867_SW_RESET BIT(15)
# define DP83867_SW_RESTART BIT(14)
/* MICR Interrupt bits */
# define MII_DP83867_MICR_AN_ERR_INT_EN BIT(15)
# define MII_DP83867_MICR_SPEED_CHNG_INT_EN BIT(14)
# define MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN BIT(13)
# define MII_DP83867_MICR_PAGE_RXD_INT_EN BIT(12)
# define MII_DP83867_MICR_AUTONEG_COMP_INT_EN BIT(11)
# define MII_DP83867_MICR_LINK_STS_CHNG_INT_EN BIT(10)
# define MII_DP83867_MICR_FALSE_CARRIER_INT_EN BIT(8)
# define MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN BIT(4)
# define MII_DP83867_MICR_WOL_INT_EN BIT(3)
# define MII_DP83867_MICR_XGMII_ERR_INT_EN BIT(2)
# define MII_DP83867_MICR_POL_CHNG_INT_EN BIT(1)
# define MII_DP83867_MICR_JABBER_INT_EN BIT(0)
/* RGMIICTL bits */
# define DP83867_RGMII_TX_CLK_DELAY_EN BIT(1)
# define DP83867_RGMII_RX_CLK_DELAY_EN BIT(0)
2017-02-07 06:20:24 +01:00
/* STRAP_STS1 bits */
# define DP83867_STRAP_STS1_RESERVED BIT(11)
2019-05-22 18:43:23 +00:00
/* STRAP_STS2 bits */
# define DP83867_STRAP_STS2_CLK_SKEW_TX_MASK GENMASK(6, 4)
# define DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT 4
# define DP83867_STRAP_STS2_CLK_SKEW_RX_MASK GENMASK(2, 0)
# define DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT 0
# define DP83867_STRAP_STS2_CLK_SKEW_NONE BIT(2)
2015-06-02 09:34:37 -05:00
/* PHY CTRL bits */
# define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14
2019-05-22 18:43:26 +00:00
# define DP83867_PHYCR_FIFO_DEPTH_MAX 0x03
# define DP83867_PHYCR_FIFO_DEPTH_MASK GENMASK(15, 14)
2017-02-07 06:20:24 +01:00
# define DP83867_PHYCR_RESERVED_MASK BIT(11)
2015-06-02 09:34:37 -05:00
/* RGMIIDCTL bits */
2019-05-22 18:43:23 +00:00
# define DP83867_RGMII_TX_CLK_DELAY_MAX 0xf
2015-06-02 09:34:37 -05:00
# define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4
2019-05-22 18:43:23 +00:00
# define DP83867_RGMII_RX_CLK_DELAY_MAX 0xf
# define DP83867_RGMII_RX_CLK_DELAY_SHIFT 0
2015-06-02 09:34:37 -05:00
2016-10-18 16:50:18 +05:30
/* IO_MUX_CFG bits */
2019-05-22 18:43:25 +00:00
# define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MASK 0x1f
2016-10-18 16:50:18 +05:30
# define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX 0x0
# define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN 0x1f
2019-05-22 18:43:22 +00:00
# define DP83867_IO_MUX_CFG_CLK_O_DISABLE BIT(6)
2018-02-14 17:07:11 +01:00
# define DP83867_IO_MUX_CFG_CLK_O_SEL_MASK (0x1f << 8)
# define DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT 8
2016-10-18 16:50:18 +05:30
2017-02-07 06:20:23 +01:00
/* CFG4 bits */
# define DP83867_CFG4_PORT_MIRROR_EN BIT(0)
enum {
DP83867_PORT_MIRROING_KEEP ,
DP83867_PORT_MIRROING_EN ,
DP83867_PORT_MIRROING_DIS ,
} ;
2015-06-02 09:34:37 -05:00
struct dp83867_private {
2019-05-22 18:43:24 +00:00
u32 rx_id_delay ;
u32 tx_id_delay ;
u32 fifo_depth ;
2016-10-18 16:50:18 +05:30
int io_impedance ;
2017-02-07 06:20:23 +01:00
int port_mirroring ;
2017-07-04 16:23:24 +05:30
bool rxctrl_strap_quirk ;
2019-05-22 18:43:22 +00:00
bool set_clk_output ;
u32 clk_output_sel ;
2015-06-02 09:34:37 -05:00
} ;
static int dp83867_ack_interrupt ( struct phy_device * phydev )
{
int err = phy_read ( phydev , MII_DP83867_ISR ) ;
if ( err < 0 )
return err ;
return 0 ;
}
static int dp83867_config_intr ( struct phy_device * phydev )
{
int micr_status ;
if ( phydev - > interrupts = = PHY_INTERRUPT_ENABLED ) {
micr_status = phy_read ( phydev , MII_DP83867_MICR ) ;
if ( micr_status < 0 )
return micr_status ;
micr_status | =
( MII_DP83867_MICR_AN_ERR_INT_EN |
MII_DP83867_MICR_SPEED_CHNG_INT_EN |
2017-01-05 14:48:07 -06:00
MII_DP83867_MICR_AUTONEG_COMP_INT_EN |
MII_DP83867_MICR_LINK_STS_CHNG_INT_EN |
2015-06-02 09:34:37 -05:00
MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN |
MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN ) ;
return phy_write ( phydev , MII_DP83867_MICR , micr_status ) ;
}
micr_status = 0x0 ;
return phy_write ( phydev , MII_DP83867_MICR , micr_status ) ;
}
2017-02-07 06:20:23 +01:00
static int dp83867_config_port_mirroring ( struct phy_device * phydev )
{
struct dp83867_private * dp83867 =
( struct dp83867_private * ) phydev - > priv ;
if ( dp83867 - > port_mirroring = = DP83867_PORT_MIRROING_EN )
2019-02-06 07:38:43 +01:00
phy_set_bits_mmd ( phydev , DP83867_DEVADDR , DP83867_CFG4 ,
DP83867_CFG4_PORT_MIRROR_EN ) ;
2017-02-07 06:20:23 +01:00
else
2019-02-06 07:38:43 +01:00
phy_clear_bits_mmd ( phydev , DP83867_DEVADDR , DP83867_CFG4 ,
DP83867_CFG4_PORT_MIRROR_EN ) ;
2017-02-07 06:20:23 +01:00
return 0 ;
}
2015-06-02 09:34:37 -05:00
# ifdef CONFIG_OF_MDIO
static int dp83867_of_init ( struct phy_device * phydev )
{
struct dp83867_private * dp83867 = phydev - > priv ;
2016-01-06 20:11:16 +01:00
struct device * dev = & phydev - > mdio . dev ;
2015-06-02 09:34:37 -05:00
struct device_node * of_node = dev - > of_node ;
int ret ;
2015-12-07 04:38:58 +01:00
if ( ! of_node )
2015-06-02 09:34:37 -05:00
return - ENODEV ;
2016-10-18 16:50:18 +05:30
/* Optional configuration */
2018-02-14 17:07:11 +01:00
ret = of_property_read_u32 ( of_node , " ti,clk-output-sel " ,
& dp83867 - > clk_output_sel ) ;
2019-05-22 18:43:22 +00:00
/* If not set, keep default */
if ( ! ret ) {
dp83867 - > set_clk_output = true ;
/* Valid values are 0 to DP83867_CLK_O_SEL_REF_CLK or
* DP83867_CLK_O_SEL_OFF .
2018-02-14 17:07:11 +01:00
*/
2019-05-22 18:43:22 +00:00
if ( dp83867 - > clk_output_sel > DP83867_CLK_O_SEL_REF_CLK & &
dp83867 - > clk_output_sel ! = DP83867_CLK_O_SEL_OFF ) {
phydev_err ( phydev , " ti,clk-output-sel value %u out of range \n " ,
dp83867 - > clk_output_sel ) ;
return - EINVAL ;
}
}
2018-02-14 17:07:11 +01:00
2016-10-18 16:50:18 +05:30
if ( of_property_read_bool ( of_node , " ti,max-output-impedance " ) )
dp83867 - > io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX ;
else if ( of_property_read_bool ( of_node , " ti,min-output-impedance " ) )
dp83867 - > io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN ;
2019-05-22 18:43:25 +00:00
else
dp83867 - > io_impedance = - 1 ; /* leave at default */
2016-10-18 16:50:18 +05:30
2017-07-04 16:23:24 +05:30
dp83867 - > rxctrl_strap_quirk = of_property_read_bool ( of_node ,
" ti,dp83867-rxctrl-strap-quirk " ) ;
2019-05-22 18:43:23 +00:00
/* Existing behavior was to use default pin strapping delay in rgmii
* mode , but rgmii should have meant no delay . Warn existing users .
*/
if ( phydev - > interface = = PHY_INTERFACE_MODE_RGMII ) {
const u16 val = phy_read_mmd ( phydev , DP83867_DEVADDR , DP83867_STRAP_STS2 ) ;
const u16 txskew = ( val & DP83867_STRAP_STS2_CLK_SKEW_TX_MASK ) > >
DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT ;
const u16 rxskew = ( val & DP83867_STRAP_STS2_CLK_SKEW_RX_MASK ) > >
DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT ;
if ( txskew ! = DP83867_STRAP_STS2_CLK_SKEW_NONE | |
rxskew ! = DP83867_STRAP_STS2_CLK_SKEW_NONE )
phydev_warn ( phydev ,
" PHY has delays via pin strapping, but phy-mode = 'rgmii' \n "
" Should be 'rgmii-id' to use internal delays \n " ) ;
}
2015-06-02 09:34:37 -05:00
2019-05-22 18:43:23 +00:00
/* RX delay *must* be specified if internal delay of RX is used. */
if ( phydev - > interface = = PHY_INTERFACE_MODE_RGMII_ID | |
phydev - > interface = = PHY_INTERFACE_MODE_RGMII_RXID ) {
ret = of_property_read_u32 ( of_node , " ti,rx-internal-delay " ,
& dp83867 - > rx_id_delay ) ;
if ( ret ) {
phydev_err ( phydev , " ti,rx-internal-delay must be specified \n " ) ;
return ret ;
}
if ( dp83867 - > rx_id_delay > DP83867_RGMII_RX_CLK_DELAY_MAX ) {
phydev_err ( phydev ,
" ti,rx-internal-delay value of %u out of range \n " ,
dp83867 - > rx_id_delay ) ;
return - EINVAL ;
}
}
/* TX delay *must* be specified if internal delay of RX is used. */
if ( phydev - > interface = = PHY_INTERFACE_MODE_RGMII_ID | |
phydev - > interface = = PHY_INTERFACE_MODE_RGMII_TXID ) {
ret = of_property_read_u32 ( of_node , " ti,tx-internal-delay " ,
& dp83867 - > tx_id_delay ) ;
if ( ret ) {
phydev_err ( phydev , " ti,tx-internal-delay must be specified \n " ) ;
return ret ;
}
if ( dp83867 - > tx_id_delay > DP83867_RGMII_TX_CLK_DELAY_MAX ) {
phydev_err ( phydev ,
" ti,tx-internal-delay value of %u out of range \n " ,
dp83867 - > tx_id_delay ) ;
return - EINVAL ;
}
}
2015-06-02 09:34:37 -05:00
2017-02-07 06:20:23 +01:00
if ( of_property_read_bool ( of_node , " enet-phy-lane-swap " ) )
dp83867 - > port_mirroring = DP83867_PORT_MIRROING_EN ;
if ( of_property_read_bool ( of_node , " enet-phy-lane-no-swap " ) )
dp83867 - > port_mirroring = DP83867_PORT_MIRROING_DIS ;
2019-05-22 18:43:26 +00:00
ret = of_property_read_u32 ( of_node , " ti,fifo-depth " ,
2015-06-02 09:34:37 -05:00
& dp83867 - > fifo_depth ) ;
2019-05-22 18:43:26 +00:00
if ( ret ) {
phydev_err ( phydev ,
" ti,fifo-depth property is required \n " ) ;
return ret ;
}
if ( dp83867 - > fifo_depth > DP83867_PHYCR_FIFO_DEPTH_MAX ) {
phydev_err ( phydev ,
" ti,fifo-depth value %u out of range \n " ,
dp83867 - > fifo_depth ) ;
return - EINVAL ;
}
return 0 ;
2015-06-02 09:34:37 -05:00
}
# else
static int dp83867_of_init ( struct phy_device * phydev )
{
return 0 ;
}
# endif /* CONFIG_OF_MDIO */
2019-05-22 18:43:27 +00:00
static int dp83867_probe ( struct phy_device * phydev )
2015-06-02 09:34:37 -05:00
{
struct dp83867_private * dp83867 ;
2019-05-22 18:43:27 +00:00
dp83867 = devm_kzalloc ( & phydev - > mdio . dev , sizeof ( * dp83867 ) ,
GFP_KERNEL ) ;
if ( ! dp83867 )
return - ENOMEM ;
phydev - > priv = dp83867 ;
return 0 ;
}
static int dp83867_config_init ( struct phy_device * phydev )
{
struct dp83867_private * dp83867 = phydev - > priv ;
2017-02-07 06:20:24 +01:00
int ret , val , bs ;
2016-07-01 22:35:03 +02:00
u16 delay ;
2015-06-02 09:34:37 -05:00
2019-05-22 18:43:27 +00:00
ret = dp83867_of_init ( phydev ) ;
if ( ret )
return ret ;
2015-06-02 09:34:37 -05:00
2017-07-04 16:23:24 +05:30
/* RX_DV/RX_CTRL strapped in mode 1 or mode 2 workaround */
2019-02-06 07:38:43 +01:00
if ( dp83867 - > rxctrl_strap_quirk )
phy_clear_bits_mmd ( phydev , DP83867_DEVADDR , DP83867_CFG4 ,
BIT ( 7 ) ) ;
2017-07-04 16:23:24 +05:30
2015-06-02 09:34:37 -05:00
if ( phy_interface_is_rgmii ( phydev ) ) {
2016-07-01 22:35:03 +02:00
val = phy_read ( phydev , MII_DP83867_PHYCTRL ) ;
if ( val < 0 )
return val ;
val & = ~ DP83867_PHYCR_FIFO_DEPTH_MASK ;
val | = ( dp83867 - > fifo_depth < < DP83867_PHYCR_FIFO_DEPTH_SHIFT ) ;
2017-02-07 06:20:24 +01:00
/* The code below checks if "port mirroring" N/A MODE4 has been
* enabled during power on bootstrap .
*
* Such N / A mode enabled by mistake can put PHY IC in some
* internal testing mode and disable RGMII transmission .
*
* In this particular case one needs to check STRAP_STS1
* register ' s bit 11 ( marked as RESERVED ) .
*/
2017-03-21 16:36:53 +00:00
bs = phy_read_mmd ( phydev , DP83867_DEVADDR , DP83867_STRAP_STS1 ) ;
2017-02-07 06:20:24 +01:00
if ( bs & DP83867_STRAP_STS1_RESERVED )
val & = ~ DP83867_PHYCR_RESERVED_MASK ;
2016-07-01 22:35:03 +02:00
ret = phy_write ( phydev , MII_DP83867_PHYCTRL , val ) ;
2015-06-02 09:34:37 -05:00
if ( ret )
return ret ;
2019-05-31 10:49:43 -07:00
/* If rgmii mode with no internal delay is selected, we do NOT use
* aligned mode as one might expect . Instead we use the PHY ' s default
* based on pin strapping . And the " mode 0 " default is to * use *
* internal delay with a value of 7 ( 2.00 ns ) .
*
* Set up RGMII delays
*/
2017-03-21 16:36:53 +00:00
val = phy_read_mmd ( phydev , DP83867_DEVADDR , DP83867_RGMIICTL ) ;
2015-06-02 09:34:37 -05:00
2019-05-22 18:43:23 +00:00
val & = ~ ( DP83867_RGMII_TX_CLK_DELAY_EN | DP83867_RGMII_RX_CLK_DELAY_EN ) ;
2015-06-02 09:34:37 -05:00
if ( phydev - > interface = = PHY_INTERFACE_MODE_RGMII_ID )
val | = ( DP83867_RGMII_TX_CLK_DELAY_EN | DP83867_RGMII_RX_CLK_DELAY_EN ) ;
if ( phydev - > interface = = PHY_INTERFACE_MODE_RGMII_TXID )
val | = DP83867_RGMII_TX_CLK_DELAY_EN ;
if ( phydev - > interface = = PHY_INTERFACE_MODE_RGMII_RXID )
val | = DP83867_RGMII_RX_CLK_DELAY_EN ;
2017-03-21 16:36:53 +00:00
phy_write_mmd ( phydev , DP83867_DEVADDR , DP83867_RGMIICTL , val ) ;
2015-06-02 09:34:37 -05:00
delay = ( dp83867 - > rx_id_delay |
( dp83867 - > tx_id_delay < < DP83867_RGMII_TX_CLK_DELAY_SHIFT ) ) ;
2017-03-21 16:36:53 +00:00
phy_write_mmd ( phydev , DP83867_DEVADDR , DP83867_RGMIIDCTL ,
delay ) ;
2015-06-02 09:34:37 -05:00
}
2019-05-22 18:43:25 +00:00
/* If specified, set io impedance */
if ( dp83867 - > io_impedance > = 0 )
phy_modify_mmd ( phydev , DP83867_DEVADDR , DP83867_IO_MUX_CFG ,
DP83867_IO_MUX_CFG_IO_IMPEDANCE_MASK ,
dp83867 - > io_impedance ) ;
2019-05-28 13:00:49 +03:00
if ( phydev - > interface = = PHY_INTERFACE_MODE_SGMII ) {
/* For support SPEED_10 in SGMII mode
* DP83867_10M_SGMII_RATE_ADAPT bit
* has to be cleared by software . That
* does not affect SPEED_100 and
* SPEED_1000 .
*/
ret = phy_modify_mmd ( phydev , DP83867_DEVADDR ,
DP83867_10M_SGMII_CFG ,
DP83867_10M_SGMII_RATE_ADAPT_MASK ,
0 ) ;
if ( ret )
return ret ;
2019-05-28 13:00:50 +03:00
/* After reset SGMII Autoneg timer is set to 2us (bits 6 and 5
* are 01 ) . That is not enough to finalize autoneg on some
* devices . Increase this timer duration to maximum 16 ms .
*/
ret = phy_modify_mmd ( phydev , DP83867_DEVADDR ,
DP83867_CFG4 ,
DP83867_CFG4_SGMII_ANEG_MASK ,
DP83867_CFG4_SGMII_ANEG_TIMER_16MS ) ;
if ( ret )
return ret ;
2019-05-28 13:00:49 +03:00
}
2017-01-05 14:48:07 -06:00
/* Enable Interrupt output INT_OE in CFG3 register */
if ( phy_interrupt_is_valid ( phydev ) ) {
val = phy_read ( phydev , DP83867_CFG3 ) ;
val | = BIT ( 7 ) ;
phy_write ( phydev , DP83867_CFG3 , val ) ;
}
2017-02-07 06:20:23 +01:00
if ( dp83867 - > port_mirroring ! = DP83867_PORT_MIRROING_KEEP )
dp83867_config_port_mirroring ( phydev ) ;
2018-02-14 17:07:11 +01:00
/* Clock output selection if muxing property is set */
2019-05-22 18:43:22 +00:00
if ( dp83867 - > set_clk_output ) {
u16 mask = DP83867_IO_MUX_CFG_CLK_O_DISABLE ;
if ( dp83867 - > clk_output_sel = = DP83867_CLK_O_SEL_OFF ) {
val = DP83867_IO_MUX_CFG_CLK_O_DISABLE ;
} else {
mask | = DP83867_IO_MUX_CFG_CLK_O_SEL_MASK ;
val = dp83867 - > clk_output_sel < <
DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT ;
}
2019-02-06 07:38:43 +01:00
phy_modify_mmd ( phydev , DP83867_DEVADDR , DP83867_IO_MUX_CFG ,
2019-05-22 18:43:22 +00:00
mask , val ) ;
}
2018-02-14 17:07:11 +01:00
2015-06-02 09:34:37 -05:00
return 0 ;
}
static int dp83867_phy_reset ( struct phy_device * phydev )
{
int err ;
err = phy_write ( phydev , DP83867_CTRL , DP83867_SW_RESET ) ;
if ( err < 0 )
return err ;
2019-02-25 12:15:10 +03:00
usleep_range ( 10 , 20 ) ;
2019-05-28 13:00:51 +03:00
return 0 ;
2015-06-02 09:34:37 -05:00
}
static struct phy_driver dp83867_driver [ ] = {
{
. phy_id = DP83867_PHY_ID ,
. phy_id_mask = 0xfffffff0 ,
. name = " TI DP83867 " ,
2019-04-12 20:47:03 +02:00
/* PHY_GBIT_FEATURES */
2015-06-02 09:34:37 -05:00
2019-05-22 18:43:27 +00:00
. probe = dp83867_probe ,
2015-06-02 09:34:37 -05:00
. config_init = dp83867_config_init ,
. soft_reset = dp83867_phy_reset ,
/* IRQ related */
. ack_interrupt = dp83867_ack_interrupt ,
. config_intr = dp83867_config_intr ,
. suspend = genphy_suspend ,
. resume = genphy_resume ,
} ,
} ;
module_phy_driver ( dp83867_driver ) ;
static struct mdio_device_id __maybe_unused dp83867_tbl [ ] = {
{ DP83867_PHY_ID , 0xfffffff0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( mdio , dp83867_tbl ) ;
MODULE_DESCRIPTION ( " Texas Instruments DP83867 PHY driver " ) ;
MODULE_AUTHOR ( " Dan Murphy <dmurphy@ti.com " ) ;
2019-01-21 19:10:19 +01:00
MODULE_LICENSE ( " GPL v2 " ) ;