2019-01-21 21:05:50 +03:00
// SPDX-License-Identifier: GPL-2.0+
2012-03-18 15:03:05 +04:00
/*
* Driver for AMD am79c PHYs
*
* Author : Heiko Schocher < hs @ denx . de >
*
* Copyright ( c ) 2011 DENX Software Engineering GmbH
*/
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/mii.h>
# include <linux/phy.h>
# define PHY_ID_AM79C874 0x0022561b
# define MII_AM79C_IR 17 /* Interrupt Status/Control Register */
# define MII_AM79C_IR_EN_LINK 0x0400 /* IR enable Linkstate */
# define MII_AM79C_IR_EN_ANEG 0x0100 /* IR enable Aneg Complete */
# define MII_AM79C_IR_IMASK_INIT (MII_AM79C_IR_EN_LINK | MII_AM79C_IR_EN_ANEG)
2020-11-13 19:52:19 +03:00
# define MII_AM79C_IR_LINK_DOWN BIT(2)
# define MII_AM79C_IR_ANEG_DONE BIT(0)
# define MII_AM79C_IR_IMASK_STAT (MII_AM79C_IR_LINK_DOWN | MII_AM79C_IR_ANEG_DONE)
2012-03-18 15:03:05 +04:00
MODULE_DESCRIPTION ( " AMD PHY driver " ) ;
MODULE_AUTHOR ( " Heiko Schocher <hs@denx.de> " ) ;
MODULE_LICENSE ( " GPL " ) ;
static int am79c_ack_interrupt ( struct phy_device * phydev )
{
int err ;
err = phy_read ( phydev , MII_BMSR ) ;
if ( err < 0 )
return err ;
err = phy_read ( phydev , MII_AM79C_IR ) ;
if ( err < 0 )
return err ;
return 0 ;
}
static int am79c_config_init ( struct phy_device * phydev )
{
return 0 ;
}
static int am79c_config_intr ( struct phy_device * phydev )
{
int err ;
2020-11-13 19:52:20 +03:00
if ( phydev - > interrupts = = PHY_INTERRUPT_ENABLED ) {
err = am79c_ack_interrupt ( phydev ) ;
if ( err )
return err ;
2012-03-18 15:03:05 +04:00
err = phy_write ( phydev , MII_AM79C_IR , MII_AM79C_IR_IMASK_INIT ) ;
2020-11-13 19:52:20 +03:00
} else {
2012-03-18 15:03:05 +04:00
err = phy_write ( phydev , MII_AM79C_IR , 0 ) ;
2020-11-13 19:52:20 +03:00
if ( err )
return err ;
err = am79c_ack_interrupt ( phydev ) ;
}
2012-03-18 15:03:05 +04:00
return err ;
}
2020-11-13 19:52:19 +03:00
static irqreturn_t am79c_handle_interrupt ( struct phy_device * phydev )
{
int irq_status ;
irq_status = phy_read ( phydev , MII_AM79C_IR ) ;
if ( irq_status < 0 ) {
phy_error ( phydev ) ;
return IRQ_NONE ;
}
if ( ! ( irq_status & MII_AM79C_IR_IMASK_STAT ) )
return IRQ_NONE ;
phy_trigger_machine ( phydev ) ;
return IRQ_HANDLED ;
}
2014-11-11 21:45:58 +03:00
static struct phy_driver am79c_driver [ ] = { {
2012-03-18 15:03:05 +04:00
. phy_id = PHY_ID_AM79C874 ,
. name = " AM79C874 " ,
. phy_id_mask = 0xfffffff0 ,
2019-04-12 21:47:03 +03:00
/* PHY_BASIC_FEATURES */
2012-03-18 15:03:05 +04:00
. config_init = am79c_config_init ,
. config_intr = am79c_config_intr ,
2020-11-13 19:52:19 +03:00
. handle_interrupt = am79c_handle_interrupt ,
2014-11-11 21:45:58 +03:00
} } ;
2012-03-18 15:03:05 +04:00
2014-11-11 21:45:58 +03:00
module_phy_driver ( am79c_driver ) ;
2012-03-18 15:03:05 +04:00
static struct mdio_device_id __maybe_unused amd_tbl [ ] = {
{ PHY_ID_AM79C874 , 0xfffffff0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( mdio , amd_tbl ) ;