#define AT803X_PSSR                            0x11    /*PHY-Specific Status Register*/
 #define AT803X_PSSR_MR_AN_COMPLETE             0x0200
 
-#define AT803X_DEBUG_REG_3C                    0x3C
-
-#define AT803X_DEBUG_REG_GREEN                 0x3D
-#define   AT803X_DEBUG_GATE_CLK_IN1000         BIT(6)
-
 #define AT803X_DEBUG_REG_1F                    0x1F
 #define AT803X_DEBUG_PLL_ON                    BIT(2)
 #define AT803X_DEBUG_RGMII_1V8                 BIT(3)
 
-#define MDIO_AZ_DEBUG                          0x800D
-
 /* AT803x supports either the XTAL input pad, an internal PLL or the
  * DSP as clock reference for the clock output pad. The XTAL reference
  * is only used for 25 MHz output, all other frequencies need the PLL.
 
 #define QCA8081_PHY_ID                         0x004dd101
 
-#define QCA8327_A_PHY_ID                       0x004dd033
-#define QCA8327_B_PHY_ID                       0x004dd034
-#define QCA8337_PHY_ID                         0x004dd036
 #define QCA9561_PHY_ID                         0x004dd042
-#define QCA8K_PHY_ID_MASK                      0xffffffff
-
-#define QCA8K_DEVFLAGS_REVISION_MASK           GENMASK(2, 0)
 
 #define AT803X_PAGE_FIBER                      0
 #define AT803X_PAGE_COPPER                     1
 MODULE_AUTHOR("Matus Ujhelyi");
 MODULE_LICENSE("GPL");
 
-static struct at803x_hw_stat qca83xx_hw_stats[] = {
-       { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
-       { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
-       { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
-};
-
 struct at803x_ss_mask {
        u16 speed_mask;
        u8 speed_shift;
        bool is_1000basex;
        struct regulator_dev *vddio_rdev;
        struct regulator_dev *vddh_rdev;
-       u64 stats[ARRAY_SIZE(qca83xx_hw_stats)];
        int led_polarity_mode;
 };
 
                wol->wolopts |= WAKE_MAGIC;
 }
 
-static int qca83xx_get_sset_count(struct phy_device *phydev)
-{
-       return ARRAY_SIZE(qca83xx_hw_stats);
-}
-
-static void qca83xx_get_strings(struct phy_device *phydev, u8 *data)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) {
-               strscpy(data + i * ETH_GSTRING_LEN,
-                       qca83xx_hw_stats[i].string, ETH_GSTRING_LEN);
-       }
-}
-
-static u64 qca83xx_get_stat(struct phy_device *phydev, int i)
-{
-       struct at803x_hw_stat stat = qca83xx_hw_stats[i];
-       struct at803x_priv *priv = phydev->priv;
-       int val;
-       u64 ret;
-
-       if (stat.access_type == MMD)
-               val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
-       else
-               val = phy_read(phydev, stat.reg);
-
-       if (val < 0) {
-               ret = U64_MAX;
-       } else {
-               val = val & stat.mask;
-               priv->stats[i] += val;
-               ret = priv->stats[i];
-       }
-
-       return ret;
-}
-
-static void qca83xx_get_stats(struct phy_device *phydev,
-                             struct ethtool_stats *stats, u64 *data)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++)
-               data[i] = qca83xx_get_stat(phydev, i);
-}
-
 static int at803x_suspend(struct phy_device *phydev)
 {
        int value;
        return at8035_parse_dt(phydev);
 }
 
-static int qca83xx_config_init(struct phy_device *phydev)
-{
-       u8 switch_revision;
-
-       switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
-
-       switch (switch_revision) {
-       case 1:
-               /* For 100M waveform */
-               at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea);
-               /* Turn on Gigabit clock */
-               at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0);
-               break;
-
-       case 2:
-               phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
-               fallthrough;
-       case 4:
-               phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
-               at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860);
-               at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46);
-               at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
-               break;
-       }
-
-       /* Following original QCA sourcecode set port to prefer master */
-       phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
-
-       return 0;
-}
-
-static int qca8327_config_init(struct phy_device *phydev)
-{
-       /* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
-        * Disable on init and enable only with 100m speed following
-        * qca original source code.
-        */
-       at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-                             QCA8327_DEBUG_MANU_CTRL_EN, 0);
-
-       return qca83xx_config_init(phydev);
-}
-
-static void qca83xx_link_change_notify(struct phy_device *phydev)
-{
-       /* Set DAC Amplitude adjustment to +6% for 100m on link running */
-       if (phydev->state == PHY_RUNNING) {
-               if (phydev->speed == SPEED_100)
-                       at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-                                             QCA8327_DEBUG_MANU_CTRL_EN,
-                                             QCA8327_DEBUG_MANU_CTRL_EN);
-       } else {
-               /* Reset DAC Amplitude adjustment */
-               at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
-                                     QCA8327_DEBUG_MANU_CTRL_EN, 0);
-       }
-}
-
-static int qca83xx_resume(struct phy_device *phydev)
-{
-       int ret, val;
-
-       /* Skip reset if not suspended */
-       if (!phydev->suspended)
-               return 0;
-
-       /* Reinit the port, reset values set by suspend */
-       qca83xx_config_init(phydev);
-
-       /* Reset the port on port resume */
-       phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
-
-       /* On resume from suspend the switch execute a reset and
-        * restart auto-negotiation. Wait for reset to complete.
-        */
-       ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
-                                   50000, 600000, true);
-       if (ret)
-               return ret;
-
-       usleep_range(1000, 2000);
-
-       return 0;
-}
-
-static int qca83xx_suspend(struct phy_device *phydev)
-{
-       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
-                             AT803X_DEBUG_GATE_CLK_IN1000, 0);
-
-       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
-                             AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE |
-                             AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0);
-
-       return 0;
-}
-
-static int qca8337_suspend(struct phy_device *phydev)
-{
-       /* Only QCA8337 support actual suspend. */
-       genphy_suspend(phydev);
-
-       return qca83xx_suspend(phydev);
-}
-
-static int qca8327_suspend(struct phy_device *phydev)
-{
-       u16 mask = 0;
-
-       /* QCA8327 cause port unreliability when phy suspend
-        * is set.
-        */
-       mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
-       phy_modify(phydev, MII_BMCR, mask, 0);
-
-       return qca83xx_suspend(phydev);
-}
-
 static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
 {
        int ret;
        .read_status            = at803x_read_status,
        .soft_reset             = genphy_soft_reset,
        .config_aneg            = at803x_config_aneg,
-}, {
-       /* QCA8337 */
-       .phy_id                 = QCA8337_PHY_ID,
-       .phy_id_mask            = QCA8K_PHY_ID_MASK,
-       .name                   = "Qualcomm Atheros 8337 internal PHY",
-       /* PHY_GBIT_FEATURES */
-       .probe                  = at803x_probe,
-       .flags                  = PHY_IS_INTERNAL,
-       .config_init            = qca83xx_config_init,
-       .soft_reset             = genphy_soft_reset,
-       .get_sset_count         = qca83xx_get_sset_count,
-       .get_strings            = qca83xx_get_strings,
-       .get_stats              = qca83xx_get_stats,
-       .suspend                = qca8337_suspend,
-       .resume                 = qca83xx_resume,
-}, {
-       /* QCA8327-A from switch QCA8327-AL1A */
-       .phy_id                 = QCA8327_A_PHY_ID,
-       .phy_id_mask            = QCA8K_PHY_ID_MASK,
-       .name                   = "Qualcomm Atheros 8327-A internal PHY",
-       /* PHY_GBIT_FEATURES */
-       .link_change_notify     = qca83xx_link_change_notify,
-       .probe                  = at803x_probe,
-       .flags                  = PHY_IS_INTERNAL,
-       .config_init            = qca8327_config_init,
-       .soft_reset             = genphy_soft_reset,
-       .get_sset_count         = qca83xx_get_sset_count,
-       .get_strings            = qca83xx_get_strings,
-       .get_stats              = qca83xx_get_stats,
-       .suspend                = qca8327_suspend,
-       .resume                 = qca83xx_resume,
-}, {
-       /* QCA8327-B from switch QCA8327-BL1A */
-       .phy_id                 = QCA8327_B_PHY_ID,
-       .phy_id_mask            = QCA8K_PHY_ID_MASK,
-       .name                   = "Qualcomm Atheros 8327-B internal PHY",
-       /* PHY_GBIT_FEATURES */
-       .link_change_notify     = qca83xx_link_change_notify,
-       .probe                  = at803x_probe,
-       .flags                  = PHY_IS_INTERNAL,
-       .config_init            = qca8327_config_init,
-       .soft_reset             = genphy_soft_reset,
-       .get_sset_count         = qca83xx_get_sset_count,
-       .get_strings            = qca83xx_get_strings,
-       .get_stats              = qca83xx_get_stats,
-       .suspend                = qca8327_suspend,
-       .resume                 = qca83xx_resume,
 }, {
        /* Qualcomm QCA8081 */
        PHY_ID_MATCH_EXACT(QCA8081_PHY_ID),
        { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
        { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
        { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
-       { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
-       { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
-       { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
        { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) },
        { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) },
        { }
 
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/phy.h>
+#include <linux/module.h>
+
+#include "qcom.h"
+
+#define AT803X_DEBUG_REG_3C                    0x3C
+
+#define AT803X_DEBUG_REG_GREEN                 0x3D
+#define   AT803X_DEBUG_GATE_CLK_IN1000         BIT(6)
+
+#define MDIO_AZ_DEBUG                          0x800D
+
+#define QCA8327_A_PHY_ID                       0x004dd033
+#define QCA8327_B_PHY_ID                       0x004dd034
+#define QCA8337_PHY_ID                         0x004dd036
+#define QCA8K_PHY_ID_MASK                      0xffffffff
+
+#define QCA8K_DEVFLAGS_REVISION_MASK           GENMASK(2, 0)
+
+static struct at803x_hw_stat qca83xx_hw_stats[] = {
+       { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
+       { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
+       { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
+};
+
+struct qca83xx_priv {
+       u64 stats[ARRAY_SIZE(qca83xx_hw_stats)];
+};
+
+MODULE_DESCRIPTION("Qualcomm Atheros QCA83XX PHY driver");
+MODULE_AUTHOR("Matus Ujhelyi");
+MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
+MODULE_LICENSE("GPL");
+
+static int qca83xx_get_sset_count(struct phy_device *phydev)
+{
+       return ARRAY_SIZE(qca83xx_hw_stats);
+}
+
+static void qca83xx_get_strings(struct phy_device *phydev, u8 *data)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) {
+               strscpy(data + i * ETH_GSTRING_LEN,
+                       qca83xx_hw_stats[i].string, ETH_GSTRING_LEN);
+       }
+}
+
+static u64 qca83xx_get_stat(struct phy_device *phydev, int i)
+{
+       struct at803x_hw_stat stat = qca83xx_hw_stats[i];
+       struct qca83xx_priv *priv = phydev->priv;
+       int val;
+       u64 ret;
+
+       if (stat.access_type == MMD)
+               val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
+       else
+               val = phy_read(phydev, stat.reg);
+
+       if (val < 0) {
+               ret = U64_MAX;
+       } else {
+               val = val & stat.mask;
+               priv->stats[i] += val;
+               ret = priv->stats[i];
+       }
+
+       return ret;
+}
+
+static void qca83xx_get_stats(struct phy_device *phydev,
+                             struct ethtool_stats *stats, u64 *data)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++)
+               data[i] = qca83xx_get_stat(phydev, i);
+}
+
+static int qca83xx_probe(struct phy_device *phydev)
+{
+       struct device *dev = &phydev->mdio.dev;
+       struct qca83xx_priv *priv;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       phydev->priv = priv;
+
+       return 0;
+}
+
+static int qca83xx_config_init(struct phy_device *phydev)
+{
+       u8 switch_revision;
+
+       switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
+
+       switch (switch_revision) {
+       case 1:
+               /* For 100M waveform */
+               at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea);
+               /* Turn on Gigabit clock */
+               at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0);
+               break;
+
+       case 2:
+               phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
+               fallthrough;
+       case 4:
+               phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
+               at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860);
+               at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46);
+               at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
+               break;
+       }
+
+       /* Following original QCA sourcecode set port to prefer master */
+       phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
+
+       return 0;
+}
+
+static int qca8327_config_init(struct phy_device *phydev)
+{
+       /* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
+        * Disable on init and enable only with 100m speed following
+        * qca original source code.
+        */
+       at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
+                             QCA8327_DEBUG_MANU_CTRL_EN, 0);
+
+       return qca83xx_config_init(phydev);
+}
+
+static void qca83xx_link_change_notify(struct phy_device *phydev)
+{
+       /* Set DAC Amplitude adjustment to +6% for 100m on link running */
+       if (phydev->state == PHY_RUNNING) {
+               if (phydev->speed == SPEED_100)
+                       at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
+                                             QCA8327_DEBUG_MANU_CTRL_EN,
+                                             QCA8327_DEBUG_MANU_CTRL_EN);
+       } else {
+               /* Reset DAC Amplitude adjustment */
+               at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
+                                     QCA8327_DEBUG_MANU_CTRL_EN, 0);
+       }
+}
+
+static int qca83xx_resume(struct phy_device *phydev)
+{
+       int ret, val;
+
+       /* Skip reset if not suspended */
+       if (!phydev->suspended)
+               return 0;
+
+       /* Reinit the port, reset values set by suspend */
+       qca83xx_config_init(phydev);
+
+       /* Reset the port on port resume */
+       phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
+
+       /* On resume from suspend the switch execute a reset and
+        * restart auto-negotiation. Wait for reset to complete.
+        */
+       ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
+                                   50000, 600000, true);
+       if (ret)
+               return ret;
+
+       usleep_range(1000, 2000);
+
+       return 0;
+}
+
+static int qca83xx_suspend(struct phy_device *phydev)
+{
+       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
+                             AT803X_DEBUG_GATE_CLK_IN1000, 0);
+
+       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
+                             AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE |
+                             AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0);
+
+       return 0;
+}
+
+static int qca8337_suspend(struct phy_device *phydev)
+{
+       /* Only QCA8337 support actual suspend. */
+       genphy_suspend(phydev);
+
+       return qca83xx_suspend(phydev);
+}
+
+static int qca8327_suspend(struct phy_device *phydev)
+{
+       u16 mask = 0;
+
+       /* QCA8327 cause port unreliability when phy suspend
+        * is set.
+        */
+       mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
+       phy_modify(phydev, MII_BMCR, mask, 0);
+
+       return qca83xx_suspend(phydev);
+}
+
+static struct phy_driver qca83xx_driver[] = {
+{
+       /* QCA8337 */
+       .phy_id                 = QCA8337_PHY_ID,
+       .phy_id_mask            = QCA8K_PHY_ID_MASK,
+       .name                   = "Qualcomm Atheros 8337 internal PHY",
+       /* PHY_GBIT_FEATURES */
+       .probe                  = qca83xx_probe,
+       .flags                  = PHY_IS_INTERNAL,
+       .config_init            = qca83xx_config_init,
+       .soft_reset             = genphy_soft_reset,
+       .get_sset_count         = qca83xx_get_sset_count,
+       .get_strings            = qca83xx_get_strings,
+       .get_stats              = qca83xx_get_stats,
+       .suspend                = qca8337_suspend,
+       .resume                 = qca83xx_resume,
+}, {
+       /* QCA8327-A from switch QCA8327-AL1A */
+       .phy_id                 = QCA8327_A_PHY_ID,
+       .phy_id_mask            = QCA8K_PHY_ID_MASK,
+       .name                   = "Qualcomm Atheros 8327-A internal PHY",
+       /* PHY_GBIT_FEATURES */
+       .link_change_notify     = qca83xx_link_change_notify,
+       .probe                  = qca83xx_probe,
+       .flags                  = PHY_IS_INTERNAL,
+       .config_init            = qca8327_config_init,
+       .soft_reset             = genphy_soft_reset,
+       .get_sset_count         = qca83xx_get_sset_count,
+       .get_strings            = qca83xx_get_strings,
+       .get_stats              = qca83xx_get_stats,
+       .suspend                = qca8327_suspend,
+       .resume                 = qca83xx_resume,
+}, {
+       /* QCA8327-B from switch QCA8327-BL1A */
+       .phy_id                 = QCA8327_B_PHY_ID,
+       .phy_id_mask            = QCA8K_PHY_ID_MASK,
+       .name                   = "Qualcomm Atheros 8327-B internal PHY",
+       /* PHY_GBIT_FEATURES */
+       .link_change_notify     = qca83xx_link_change_notify,
+       .probe                  = qca83xx_probe,
+       .flags                  = PHY_IS_INTERNAL,
+       .config_init            = qca8327_config_init,
+       .soft_reset             = genphy_soft_reset,
+       .get_sset_count         = qca83xx_get_sset_count,
+       .get_strings            = qca83xx_get_strings,
+       .get_stats              = qca83xx_get_stats,
+       .suspend                = qca8327_suspend,
+       .resume                 = qca83xx_resume,
+}, };
+
+module_phy_driver(qca83xx_driver);
+
+static struct mdio_device_id __maybe_unused qca83xx_tbl[] = {
+       { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
+       { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
+       { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, qca83xx_tbl);