#define AT803X_DEBUG_REG_5                     0x05
 #define AT803X_DEBUG_TX_CLK_DLY_EN             BIT(8)
 
+#define AT803X_DEBUG_REG_HIB_CTRL              0x0b
+#define   AT803X_DEBUG_HIB_CTRL_SEL_RST_80U    BIT(10)
+#define   AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE  BIT(13)
+
 #define AT803X_DEBUG_REG_3C                    0x3C
 
 #define AT803X_DEBUG_REG_3D                    0x3D
+#define   AT803X_DEBUG_GATE_CLK_IN1000         BIT(6)
 
 #define AT803X_DEBUG_REG_1F                    0x1F
 #define AT803X_DEBUG_PLL_ON                    BIT(2)
        return 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;
+
+       msleep(1);
+
+       return 0;
+}
+
+static int qca83xx_suspend(struct phy_device *phydev)
+{
+       u16 mask = 0;
+
+       /* Only QCA8337 support actual suspend.
+        * QCA8327 cause port unreliability when phy suspend
+        * is set.
+        */
+       if (phydev->drv->phy_id == QCA8337_PHY_ID) {
+               genphy_suspend(phydev);
+       } else {
+               mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
+               phy_modify(phydev, MII_BMCR, mask, 0);
+       }
+
+       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_3D,
+                             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 struct phy_driver at803x_driver[] = {
 {
        /* Qualcomm Atheros AR8035 */
        .get_sset_count         = at803x_get_sset_count,
        .get_strings            = at803x_get_strings,
        .get_stats              = at803x_get_stats,
-       .suspend                = genphy_suspend,
-       .resume                 = genphy_resume,
+       .suspend                = qca83xx_suspend,
+       .resume                 = qca83xx_resume,
 }, {
        /* QCA8327-A from switch QCA8327-AL1A */
        .phy_id                 = QCA8327_A_PHY_ID,
        .get_sset_count         = at803x_get_sset_count,
        .get_strings            = at803x_get_strings,
        .get_stats              = at803x_get_stats,
-       .suspend                = genphy_suspend,
-       .resume                 = genphy_resume,
+       .suspend                = qca83xx_suspend,
+       .resume                 = qca83xx_resume,
 }, {
        /* QCA8327-B from switch QCA8327-BL1A */
        .phy_id                 = QCA8327_B_PHY_ID,
        .get_sset_count         = at803x_get_sset_count,
        .get_strings            = at803x_get_strings,
        .get_stats              = at803x_get_stats,
-       .suspend                = genphy_suspend,
-       .resume                 = genphy_resume,
+       .suspend                = qca83xx_suspend,
+       .resume                 = qca83xx_resume,
 }, };
 
 module_phy_driver(at803x_driver);