@ -7,6 +7,8 @@
*
* Copyright ( c ) 2004 Freescale Semiconductor , Inc .
*
* Copyright ( c ) 2013 Michael Stapelberg < michael @ stapelberg . de >
*
* 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
@ -80,6 +82,28 @@
# define MII_88E1318S_PHY_MSCR1_REG 16
# define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6)
/* Copper Specific Interrupt Enable Register */
# define MII_88E1318S_PHY_CSIER 0x12
/* WOL Event Interrupt Enable */
# define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7)
/* LED Timer Control Register */
# define MII_88E1318S_PHY_LED_PAGE 0x03
# define MII_88E1318S_PHY_LED_TCR 0x12
# define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15)
# define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7)
# define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW BIT(11)
/* Magic Packet MAC address registers */
# define MII_88E1318S_PHY_MAGIC_PACKET_WORD2 0x17
# define MII_88E1318S_PHY_MAGIC_PACKET_WORD1 0x18
# define MII_88E1318S_PHY_MAGIC_PACKET_WORD0 0x19
# define MII_88E1318S_PHY_WOL_PAGE 0x11
# define MII_88E1318S_PHY_WOL_CTRL 0x10
# define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12)
# define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14)
# define MII_88E1121_PHY_LED_CTRL 16
# define MII_88E1121_PHY_LED_PAGE 3
# define MII_88E1121_PHY_LED_DEF 0x0030
@ -696,6 +720,107 @@ static int m88e1121_did_interrupt(struct phy_device *phydev)
return 0 ;
}
static void m88e1318_get_wol ( struct phy_device * phydev , struct ethtool_wolinfo * wol )
{
wol - > supported = WAKE_MAGIC ;
wol - > wolopts = 0 ;
if ( phy_write ( phydev , MII_MARVELL_PHY_PAGE ,
MII_88E1318S_PHY_WOL_PAGE ) < 0 )
return ;
if ( phy_read ( phydev , MII_88E1318S_PHY_WOL_CTRL ) &
MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE )
wol - > wolopts | = WAKE_MAGIC ;
if ( phy_write ( phydev , MII_MARVELL_PHY_PAGE , 0x00 ) < 0 )
return ;
}
static int m88e1318_set_wol ( struct phy_device * phydev , struct ethtool_wolinfo * wol )
{
int err , oldpage , temp ;
oldpage = phy_read ( phydev , MII_MARVELL_PHY_PAGE ) ;
if ( wol - > wolopts & WAKE_MAGIC ) {
/* Explicitly switch to page 0x00, just to be sure */
err = phy_write ( phydev , MII_MARVELL_PHY_PAGE , 0x00 ) ;
if ( err < 0 )
return err ;
/* Enable the WOL interrupt */
temp = phy_read ( phydev , MII_88E1318S_PHY_CSIER ) ;
temp | = MII_88E1318S_PHY_CSIER_WOL_EIE ;
err = phy_write ( phydev , MII_88E1318S_PHY_CSIER , temp ) ;
if ( err < 0 )
return err ;
err = phy_write ( phydev , MII_MARVELL_PHY_PAGE ,
MII_88E1318S_PHY_LED_PAGE ) ;
if ( err < 0 )
return err ;
/* Setup LED[2] as interrupt pin (active low) */
temp = phy_read ( phydev , MII_88E1318S_PHY_LED_TCR ) ;
temp & = ~ MII_88E1318S_PHY_LED_TCR_FORCE_INT ;
temp | = MII_88E1318S_PHY_LED_TCR_INTn_ENABLE ;
temp | = MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW ;
err = phy_write ( phydev , MII_88E1318S_PHY_LED_TCR , temp ) ;
if ( err < 0 )
return err ;
err = phy_write ( phydev , MII_MARVELL_PHY_PAGE ,
MII_88E1318S_PHY_WOL_PAGE ) ;
if ( err < 0 )
return err ;
/* Store the device address for the magic packet */
err = phy_write ( phydev , MII_88E1318S_PHY_MAGIC_PACKET_WORD2 ,
( ( phydev - > attached_dev - > dev_addr [ 5 ] < < 8 ) |
phydev - > attached_dev - > dev_addr [ 4 ] ) ) ;
if ( err < 0 )
return err ;
err = phy_write ( phydev , MII_88E1318S_PHY_MAGIC_PACKET_WORD1 ,
( ( phydev - > attached_dev - > dev_addr [ 3 ] < < 8 ) |
phydev - > attached_dev - > dev_addr [ 2 ] ) ) ;
if ( err < 0 )
return err ;
err = phy_write ( phydev , MII_88E1318S_PHY_MAGIC_PACKET_WORD0 ,
( ( phydev - > attached_dev - > dev_addr [ 1 ] < < 8 ) |
phydev - > attached_dev - > dev_addr [ 0 ] ) ) ;
if ( err < 0 )
return err ;
/* Clear WOL status and enable magic packet matching */
temp = phy_read ( phydev , MII_88E1318S_PHY_WOL_CTRL ) ;
temp | = MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS ;
temp | = MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE ;
err = phy_write ( phydev , MII_88E1318S_PHY_WOL_CTRL , temp ) ;
if ( err < 0 )
return err ;
} else {
err = phy_write ( phydev , MII_MARVELL_PHY_PAGE ,
MII_88E1318S_PHY_WOL_PAGE ) ;
if ( err < 0 )
return err ;
/* Clear WOL status and disable magic packet matching */
temp = phy_read ( phydev , MII_88E1318S_PHY_WOL_CTRL ) ;
temp | = MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS ;
temp & = ~ MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE ;
err = phy_write ( phydev , MII_88E1318S_PHY_WOL_CTRL , temp ) ;
if ( err < 0 )
return err ;
}
err = phy_write ( phydev , MII_MARVELL_PHY_PAGE , oldpage ) ;
if ( err < 0 )
return err ;
return 0 ;
}
static struct phy_driver marvell_drivers [ ] = {
{
. phy_id = MARVELL_PHY_ID_88E1101 ,
@ -772,6 +897,8 @@ static struct phy_driver marvell_drivers[] = {
. ack_interrupt = & marvell_ack_interrupt ,
. config_intr = & marvell_config_intr ,
. did_interrupt = & m88e1121_did_interrupt ,
. get_wol = & m88e1318_get_wol ,
. set_wol = & m88e1318_set_wol ,
. driver = { . owner = THIS_MODULE } ,
} ,
{