0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/errno.h>
0011 #include <linux/init.h>
0012 #include <linux/module.h>
0013 #include <linux/mii.h>
0014 #include <linux/phy.h>
0015
0016 #define PHY_ID_AM79C874 0x0022561b
0017
0018 #define MII_AM79C_IR 17
0019 #define MII_AM79C_IR_EN_LINK 0x0400
0020 #define MII_AM79C_IR_EN_ANEG 0x0100
0021 #define MII_AM79C_IR_IMASK_INIT (MII_AM79C_IR_EN_LINK | MII_AM79C_IR_EN_ANEG)
0022
0023 #define MII_AM79C_IR_LINK_DOWN BIT(2)
0024 #define MII_AM79C_IR_ANEG_DONE BIT(0)
0025 #define MII_AM79C_IR_IMASK_STAT (MII_AM79C_IR_LINK_DOWN | MII_AM79C_IR_ANEG_DONE)
0026
0027 MODULE_DESCRIPTION("AMD PHY driver");
0028 MODULE_AUTHOR("Heiko Schocher <hs@denx.de>");
0029 MODULE_LICENSE("GPL");
0030
0031 static int am79c_ack_interrupt(struct phy_device *phydev)
0032 {
0033 int err;
0034
0035 err = phy_read(phydev, MII_BMSR);
0036 if (err < 0)
0037 return err;
0038
0039 err = phy_read(phydev, MII_AM79C_IR);
0040 if (err < 0)
0041 return err;
0042
0043 return 0;
0044 }
0045
0046 static int am79c_config_init(struct phy_device *phydev)
0047 {
0048 return 0;
0049 }
0050
0051 static int am79c_config_intr(struct phy_device *phydev)
0052 {
0053 int err;
0054
0055 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
0056 err = am79c_ack_interrupt(phydev);
0057 if (err)
0058 return err;
0059
0060 err = phy_write(phydev, MII_AM79C_IR, MII_AM79C_IR_IMASK_INIT);
0061 } else {
0062 err = phy_write(phydev, MII_AM79C_IR, 0);
0063 if (err)
0064 return err;
0065
0066 err = am79c_ack_interrupt(phydev);
0067 }
0068
0069 return err;
0070 }
0071
0072 static irqreturn_t am79c_handle_interrupt(struct phy_device *phydev)
0073 {
0074 int irq_status;
0075
0076 irq_status = phy_read(phydev, MII_AM79C_IR);
0077 if (irq_status < 0) {
0078 phy_error(phydev);
0079 return IRQ_NONE;
0080 }
0081
0082 if (!(irq_status & MII_AM79C_IR_IMASK_STAT))
0083 return IRQ_NONE;
0084
0085 phy_trigger_machine(phydev);
0086
0087 return IRQ_HANDLED;
0088 }
0089
0090 static struct phy_driver am79c_driver[] = { {
0091 .phy_id = PHY_ID_AM79C874,
0092 .name = "AM79C874",
0093 .phy_id_mask = 0xfffffff0,
0094
0095 .config_init = am79c_config_init,
0096 .config_intr = am79c_config_intr,
0097 .handle_interrupt = am79c_handle_interrupt,
0098 } };
0099
0100 module_phy_driver(am79c_driver);
0101
0102 static struct mdio_device_id __maybe_unused amd_tbl[] = {
0103 { PHY_ID_AM79C874, 0xfffffff0 },
0104 { }
0105 };
0106
0107 MODULE_DEVICE_TABLE(mdio, amd_tbl);