summaryrefslogtreecommitdiff
path: root/drivers/net/phy/lxt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy/lxt.c')
-rw-r--r--drivers/net/phy/lxt.c157
1 files changed, 105 insertions, 52 deletions
diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c
index 09d215177fff..5251a61c8b0f 100644
--- a/drivers/net/phy/lxt.c
+++ b/drivers/net/phy/lxt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* drivers/net/phy/lxt.c
*
@@ -6,12 +7,6 @@
* Author: Andy Fleming
*
* Copyright (c) 2004 Freescale Semiconductor, Inc.
- *
- * 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/string.h>
@@ -42,6 +37,8 @@
#define MII_LXT970_ISR 18 /* Interrupt Status Register */
+#define MII_LXT970_IRS_MINT BIT(15)
+
#define MII_LXT970_CONFIG 19 /* Configuration Register */
/* ------------------------------------------------------------------------- */
@@ -52,6 +49,7 @@
#define MII_LXT971_IER_IEN 0x00f2
#define MII_LXT971_ISR 19 /* Interrupt Status Register */
+#define MII_LXT971_ISR_MASK 0x00f0
/* register definitions for the 973 */
#define MII_LXT973_PCR 16 /* Port Configuration Register */
@@ -80,10 +78,50 @@ static int lxt970_ack_interrupt(struct phy_device *phydev)
static int lxt970_config_intr(struct phy_device *phydev)
{
- if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
- return phy_write(phydev, MII_LXT970_IER, MII_LXT970_IER_IEN);
- else
- return phy_write(phydev, MII_LXT970_IER, 0);
+ int err;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ err = lxt970_ack_interrupt(phydev);
+ if (err)
+ return err;
+
+ err = phy_write(phydev, MII_LXT970_IER, MII_LXT970_IER_IEN);
+ } else {
+ err = phy_write(phydev, MII_LXT970_IER, 0);
+ if (err)
+ return err;
+
+ err = lxt970_ack_interrupt(phydev);
+ }
+
+ return err;
+}
+
+static irqreturn_t lxt970_handle_interrupt(struct phy_device *phydev)
+{
+ int irq_status;
+
+ /* The interrupt status register is cleared by reading BMSR
+ * followed by MII_LXT970_ISR
+ */
+ irq_status = phy_read(phydev, MII_BMSR);
+ if (irq_status < 0) {
+ phy_error(phydev);
+ return IRQ_NONE;
+ }
+
+ irq_status = phy_read(phydev, MII_LXT970_ISR);
+ if (irq_status < 0) {
+ phy_error(phydev);
+ return IRQ_NONE;
+ }
+
+ if (!(irq_status & MII_LXT970_IRS_MINT))
+ return IRQ_NONE;
+
+ phy_trigger_machine(phydev);
+
+ return IRQ_HANDLED;
}
static int lxt970_config_init(struct phy_device *phydev)
@@ -104,10 +142,41 @@ static int lxt971_ack_interrupt(struct phy_device *phydev)
static int lxt971_config_intr(struct phy_device *phydev)
{
- if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
- return phy_write(phydev, MII_LXT971_IER, MII_LXT971_IER_IEN);
- else
- return phy_write(phydev, MII_LXT971_IER, 0);
+ int err;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ err = lxt971_ack_interrupt(phydev);
+ if (err)
+ return err;
+
+ err = phy_write(phydev, MII_LXT971_IER, MII_LXT971_IER_IEN);
+ } else {
+ err = phy_write(phydev, MII_LXT971_IER, 0);
+ if (err)
+ return err;
+
+ err = lxt971_ack_interrupt(phydev);
+ }
+
+ return err;
+}
+
+static irqreturn_t lxt971_handle_interrupt(struct phy_device *phydev)
+{
+ int irq_status;
+
+ irq_status = phy_read(phydev, MII_LXT971_ISR);
+ if (irq_status < 0) {
+ phy_error(phydev);
+ return IRQ_NONE;
+ }
+
+ if (!(irq_status & MII_LXT971_ISR_MASK))
+ return IRQ_NONE;
+
+ phy_trigger_machine(phydev);
+
+ return IRQ_HANDLED;
}
/*
@@ -173,11 +242,11 @@ static int lxt973a2_read_status(struct phy_device *phydev)
return lpa;
/* If both registers are equal, it is suspect but not
- * impossible, hence a new try
- */
+ * impossible, hence a new try
+ */
} while (lpa == adv && retry--);
- phydev->lp_advertising = mii_lpa_to_ethtool_lpa_t(lpa);
+ mii_lpa_to_linkmode_lpa_t(phydev->lp_advertising, lpa);
lpa &= adv;
@@ -195,30 +264,14 @@ static int lxt973a2_read_status(struct phy_device *phydev)
phydev->duplex = DUPLEX_FULL;
}
- if (phydev->duplex == DUPLEX_FULL) {
- phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
- phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
- }
+ phy_resolve_aneg_pause(phydev);
} else {
- int bmcr = phy_read(phydev, MII_BMCR);
-
- if (bmcr < 0)
- return bmcr;
-
- if (bmcr & BMCR_FULLDPLX)
- phydev->duplex = DUPLEX_FULL;
- else
- phydev->duplex = DUPLEX_HALF;
-
- if (bmcr & BMCR_SPEED1000)
- phydev->speed = SPEED_1000;
- else if (bmcr & BMCR_SPEED100)
- phydev->speed = SPEED_100;
- else
- phydev->speed = SPEED_10;
+ err = genphy_read_status_fixed(phydev);
+ if (err < 0)
+ return err;
phydev->pause = phydev->asym_pause = 0;
- phydev->lp_advertising = 0;
+ linkmode_zero(phydev->lp_advertising);
}
return 0;
@@ -239,6 +292,7 @@ static int lxt973_probe(struct phy_device *phydev)
phy_write(phydev, MII_BMCR, val);
/* Remember that the port is in fiber mode. */
phydev->priv = lxt973_probe;
+ phydev->port = PORT_FIBRE;
} else {
phydev->priv = NULL;
}
@@ -256,46 +310,45 @@ static struct phy_driver lxt97x_driver[] = {
.phy_id = 0x78100000,
.name = "LXT970",
.phy_id_mask = 0xfffffff0,
- .features = PHY_BASIC_FEATURES,
- .flags = PHY_HAS_INTERRUPT,
+ /* PHY_BASIC_FEATURES */
.config_init = lxt970_config_init,
- .config_aneg = genphy_config_aneg,
- .read_status = genphy_read_status,
- .ack_interrupt = lxt970_ack_interrupt,
.config_intr = lxt970_config_intr,
+ .handle_interrupt = lxt970_handle_interrupt,
}, {
.phy_id = 0x001378e0,
.name = "LXT971",
.phy_id_mask = 0xfffffff0,
- .features = PHY_BASIC_FEATURES,
- .flags = PHY_HAS_INTERRUPT,
- .config_aneg = genphy_config_aneg,
- .read_status = genphy_read_status,
- .ack_interrupt = lxt971_ack_interrupt,
+ /* PHY_BASIC_FEATURES */
.config_intr = lxt971_config_intr,
+ .handle_interrupt = lxt971_handle_interrupt,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
}, {
.phy_id = 0x00137a10,
.name = "LXT973-A2",
.phy_id_mask = 0xffffffff,
- .features = PHY_BASIC_FEATURES,
+ /* PHY_BASIC_FEATURES */
.flags = 0,
.probe = lxt973_probe,
.config_aneg = lxt973_config_aneg,
.read_status = lxt973a2_read_status,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
}, {
.phy_id = 0x00137a10,
.name = "LXT973",
.phy_id_mask = 0xfffffff0,
- .features = PHY_BASIC_FEATURES,
+ /* PHY_BASIC_FEATURES */
.flags = 0,
.probe = lxt973_probe,
.config_aneg = lxt973_config_aneg,
- .read_status = genphy_read_status,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
} };
module_phy_driver(lxt97x_driver);
-static struct mdio_device_id __maybe_unused lxt_tbl[] = {
+static const struct mdio_device_id __maybe_unused lxt_tbl[] = {
{ 0x78100000, 0xfffffff0 },
{ 0x001378e0, 0xfffffff0 },
{ 0x00137a10, 0xfffffff0 },