summaryrefslogtreecommitdiff
path: root/drivers/net/phy/amd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy/amd.c')
-rw-r--r--drivers/net/phy/amd.c86
1 files changed, 55 insertions, 31 deletions
diff --git a/drivers/net/phy/amd.c b/drivers/net/phy/amd.c
index a3fb5ceb6487..75b5fe65500a 100644
--- a/drivers/net/phy/amd.c
+++ b/drivers/net/phy/amd.c
@@ -1,15 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for AMD am79c PHYs
*
* Author: Heiko Schocher <hs@denx.de>
*
* Copyright (c) 2011 DENX Software Engineering GmbH
- *
- * 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
- * option) any later version.
- *
*/
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -18,6 +13,7 @@
#include <linux/mii.h>
#include <linux/phy.h>
+#define PHY_ID_AC101L 0x00225520
#define PHY_ID_AM79C874 0x0022561b
#define MII_AM79C_IR 17 /* Interrupt Status/Control Register */
@@ -25,6 +21,10 @@
#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)
+#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)
+
MODULE_DESCRIPTION("AMD PHY driver");
MODULE_AUTHOR("Heiko Schocher <hs@denx.de>");
MODULE_LICENSE("GPL");
@@ -53,42 +53,66 @@ static int am79c_config_intr(struct phy_device *phydev)
{
int err;
- if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ err = am79c_ack_interrupt(phydev);
+ if (err)
+ return err;
+
err = phy_write(phydev, MII_AM79C_IR, MII_AM79C_IR_IMASK_INIT);
- else
+ } else {
err = phy_write(phydev, MII_AM79C_IR, 0);
+ if (err)
+ return err;
+
+ err = am79c_ack_interrupt(phydev);
+ }
return err;
}
-static struct phy_driver am79c_driver = {
- .phy_id = PHY_ID_AM79C874,
- .name = "AM79C874",
- .phy_id_mask = 0xfffffff0,
- .features = PHY_BASIC_FEATURES,
- .flags = PHY_HAS_INTERRUPT,
- .config_init = am79c_config_init,
- .config_aneg = genphy_config_aneg,
- .read_status = genphy_read_status,
- .ack_interrupt = am79c_ack_interrupt,
- .config_intr = am79c_config_intr,
- .driver = { .owner = THIS_MODULE,},
-};
-
-static int __init am79c_init(void)
+static irqreturn_t am79c_handle_interrupt(struct phy_device *phydev)
{
- return phy_driver_register(&am79c_driver);
-}
+ int irq_status;
-static void __exit am79c_exit(void)
-{
- phy_driver_unregister(&am79c_driver);
+ 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;
}
-module_init(am79c_init);
-module_exit(am79c_exit);
+static struct phy_driver am79c_drivers[] = {
+ {
+ .phy_id = PHY_ID_AM79C874,
+ .name = "AM79C874",
+ .phy_id_mask = 0xfffffff0,
+ /* PHY_BASIC_FEATURES */
+ .config_init = am79c_config_init,
+ .config_intr = am79c_config_intr,
+ .handle_interrupt = am79c_handle_interrupt,
+ },
+ {
+ .phy_id = PHY_ID_AC101L,
+ .name = "AC101L",
+ .phy_id_mask = 0xfffffff0,
+ /* PHY_BASIC_FEATURES */
+ .config_init = am79c_config_init,
+ .config_intr = am79c_config_intr,
+ .handle_interrupt = am79c_handle_interrupt,
+ },
+};
+
+module_phy_driver(am79c_drivers);
-static struct mdio_device_id __maybe_unused amd_tbl[] = {
+static const struct mdio_device_id __maybe_unused amd_tbl[] = {
+ { PHY_ID_AC101L, 0xfffffff0 },
{ PHY_ID_AM79C874, 0xfffffff0 },
{ }
};