diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index 86373d6..acb8861 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: BSD-3-Clause-Clear
 /*
  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/module.h>
@@ -97,6 +97,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.alloc_cacheable_memory = true,
 		.supports_rssi_stats = false,
 		.fw_wmi_diag_event = false,
+		.non_wow_suspend = false,
 	},
 	{
 		.hw_rev = ATH11K_HW_IPQ6018_HW10,
@@ -160,6 +161,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.alloc_cacheable_memory = true,
 		.supports_rssi_stats = false,
 		.fw_wmi_diag_event = false,
+		.non_wow_suspend = false,
 	},
 	{
 		.name = "qca6390 hw2.0",
@@ -222,6 +224,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.alloc_cacheable_memory = false,
 		.supports_rssi_stats = true,
 		.fw_wmi_diag_event = true,
+		.non_wow_suspend = false,
 	},
 	{
 		.name = "qcn9074 hw1.0",
@@ -284,6 +287,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.alloc_cacheable_memory = true,
 		.supports_rssi_stats = false,
 		.fw_wmi_diag_event = false,
+		.non_wow_suspend = false,
 	},
 	{
 		.name = "wcn6855 hw2.0",
@@ -346,6 +350,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.alloc_cacheable_memory = false,
 		.supports_rssi_stats = true,
 		.fw_wmi_diag_event = true,
+		.non_wow_suspend = false,
 	},
 	{
 		.name = "wcn6855 hw2.1",
@@ -407,6 +412,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.alloc_cacheable_memory = false,
 		.supports_rssi_stats = true,
 		.fw_wmi_diag_event = true,
+		.non_wow_suspend = false,
 	},
 	{
 		.name = "wcn6750 hw1.0",
@@ -468,6 +474,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.alloc_cacheable_memory = false,
 		.supports_rssi_stats = true,
 		.fw_wmi_diag_event = false,
+		.non_wow_suspend = true,
 	},
 };
 
@@ -931,7 +938,6 @@ static int ath11k_core_soc_create(struct ath11k_base *ab)
 static void ath11k_core_soc_destroy(struct ath11k_base *ab)
 {
 	ath11k_debugfs_soc_destroy(ab);
-	ath11k_dp_free(ab);
 	ath11k_reg_free(ab);
 	ath11k_qmi_deinit_service(ab);
 }
@@ -987,11 +993,10 @@ static int ath11k_core_pdev_create(struct ath11k_base *ab)
 
 static void ath11k_core_pdev_destroy(struct ath11k_base *ab)
 {
-	ath11k_spectral_deinit(ab);
 	ath11k_thermal_unregister(ab);
 	ath11k_mac_unregister(ab);
-	ath11k_hif_irq_disable(ab);
-	ath11k_dp_pdev_free(ab);
+	if (!test_bit(ATH11K_FLAG_DEVICE_STOPPED, &ab->dev_flags))
+		ath11k_core_stop_device(ab);
 	ath11k_debugfs_pdev_destroy(ab);
 }
 
@@ -1205,6 +1210,9 @@ int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab)
 
 	mutex_unlock(&ab->core_lock);
 
+	if (!test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))
+		ath11k_core_stop_device(ab);
+
 	return 0;
 
 err_core_stop:
@@ -1221,10 +1229,7 @@ int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab)
 
 static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab)
 {
-	int ret;
-
 	mutex_lock(&ab->core_lock);
-	ath11k_thermal_unregister(ab);
 	ath11k_hif_irq_disable(ab);
 	ath11k_dp_pdev_free(ab);
 	ath11k_spectral_deinit(ab);
@@ -1234,27 +1239,11 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab)
 	mutex_unlock(&ab->core_lock);
 
 	ath11k_dp_free(ab);
-	ath11k_hal_srng_deinit(ab);
+	set_bit(ATH11K_FLAG_DEVICE_STOPPED, &ab->dev_flags);
 
 	ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS(ab))) - 1;
 
-	ret = ath11k_hal_srng_init(ab);
-	if (ret)
-		return ret;
-
-	clear_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags);
-
-	ret = ath11k_core_qmi_firmware_ready(ab);
-	if (ret)
-		goto err_hal_srng_deinit;
-
-	clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags);
-
 	return 0;
-
-err_hal_srng_deinit:
-	ath11k_hal_srng_deinit(ab);
-	return ret;
 }
 
 void ath11k_core_halt(struct ath11k *ar)
@@ -1465,7 +1454,6 @@ void ath11k_core_deinit(struct ath11k_base *ab)
 	mutex_lock(&ab->core_lock);
 
 	ath11k_core_pdev_destroy(ab);
-	ath11k_core_stop(ab);
 
 	mutex_unlock(&ab->core_lock);
 
@@ -1527,5 +1515,106 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size,
 }
 EXPORT_SYMBOL(ath11k_core_alloc);
 
+static int ath11k_core_suspend_target(struct ath11k_base *ab, u32 suspend_opt)
+{
+	struct ath11k *ar;
+	struct ath11k_pdev *pdev;
+	unsigned long time_left;
+	int ret;
+	int i;
+
+	for (i = 0; i < ab->num_radios; i++) {
+		pdev = &ab->pdevs[i];
+		ar = pdev->ar;
+
+		reinit_completion(&ab->htc_suspend);
+
+		ret = ath11k_wmi_pdev_suspend(ar, suspend_opt, pdev->pdev_id);
+		if (ret) {
+			ath11k_warn(ab, "could not suspend target (%d)\n", ret);
+			return ret;
+		}
+
+		time_left = wait_for_completion_timeout(&ab->htc_suspend, 3 * HZ);
+
+		if (!time_left) {
+			ath11k_warn(ab, "suspend timed out - target pause event never came\n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+void ath11k_core_stop_device(struct ath11k_base *ab)
+{
+	if (!ab->hw_params.non_wow_suspend &&
+	    !test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags))
+		return;
+
+	ath11k_core_suspend_target(ab, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);
+
+	ath11k_hif_irq_disable(ab);
+	ath11k_core_stop(ab);
+	ath11k_spectral_deinit(ab);
+	ath11k_dp_pdev_free(ab);
+	ath11k_dp_free(ab);
+
+	set_bit(ATH11K_FLAG_DEVICE_STOPPED, &ab->dev_flags);
+}
+
+int ath11k_core_start_device(struct ath11k_base *ab)
+{
+	int i;
+	int ret;
+	struct ath11k_pdev *pdev;
+	struct ath11k *ar;
+
+	if (!ab->hw_params.non_wow_suspend &&
+	    !test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags))
+		return 0;
+
+	for (i = 0; i < ab->num_radios; i++) {
+		pdev = &ab->pdevs[i];
+		ar = pdev->ar;
+		if (!ar)
+			continue;
+
+		if (ar->state == ATH11K_STATE_ON)
+			break;
+	}
+
+	if (i == ab->num_radios ||
+	    test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags)) {
+		if (!test_bit(ATH11K_FLAG_DEVICE_STOPPED, &ab->dev_flags))
+			return -EAGAIN;
+
+		ath11k_hal_srng_deinit(ab);
+
+		ret = ath11k_hal_srng_init(ab);
+		if (ret) {
+			ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
+			return ret;
+		}
+
+		clear_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags);
+
+		ret = ath11k_core_qmi_firmware_ready(ab);
+		if (ret) {
+			ath11k_err(ab, "failed to init core: %d\n", ret);
+			goto err_hal_srng_deinit;
+		}
+
+		clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags);
+		clear_bit(ATH11K_FLAG_DEVICE_STOPPED, &ab->dev_flags);
+	}
+
+	return 0;
+
+err_hal_srng_deinit:
+	ath11k_hal_srng_deinit(ab);
+	return ret;
+}
+
 MODULE_DESCRIPTION("Core module for Qualcomm Atheros 802.11ax wireless LAN cards.");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 76f5aef..758f271 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
 /*
  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef ATH11K_CORE_H
@@ -208,6 +208,7 @@ enum ath11k_dev_flags {
 	ATH11K_FLAG_FIXED_MEM_RGN,
 	ATH11K_FLAG_DEVICE_INIT_DONE,
 	ATH11K_FLAG_MULTI_MSI_VECTORS,
+	ATH11K_FLAG_DEVICE_STOPPED,
 };
 
 enum ath11k_monitor_flags {
@@ -1025,6 +1026,8 @@ int ath11k_core_check_dt(struct ath11k_base *ath11k);
 void ath11k_core_halt(struct ath11k *ar);
 int ath11k_core_resume(struct ath11k_base *ab);
 int ath11k_core_suspend(struct ath11k_base *ab);
+void ath11k_core_stop_device(struct ath11k_base *ab);
+int ath11k_core_start_device(struct ath11k_base *ab);
 
 const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab,
 						    const char *filename);
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index a220c9a..a38745e 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
 /*
  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef ATH11K_HW_H
@@ -192,6 +192,7 @@ struct ath11k_hw_params {
 	bool alloc_cacheable_memory;
 	bool supports_rssi_stats;
 	bool fw_wmi_diag_event;
+	bool non_wow_suspend;
 };
 
 struct ath11k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index ac6a192..2402405 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: BSD-3-Clause-Clear
 /*
  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <net/mac80211.h>
@@ -5726,6 +5726,14 @@ static int ath11k_mac_op_start(struct ieee80211_hw *hw)
 	int ret;
 
 	ath11k_mac_drain_tx(ar);
+
+	ret = ath11k_core_start_device(ab);
+	if (ret) {
+		if (ret != -EAGAIN)
+			ath11k_err(ab, "failed to start device : %d\n", ret);
+		return ret;
+	}
+
 	mutex_lock(&ar->conf_mutex);
 
 	switch (ar->state) {
@@ -5847,8 +5855,11 @@ static int ath11k_mac_op_start(struct ieee80211_hw *hw)
 static void ath11k_mac_op_stop(struct ieee80211_hw *hw)
 {
 	struct ath11k *ar = hw->priv;
+	struct ath11k_base *ab = ar->ab;
+	struct ath11k_pdev *pdev;
 	struct htt_ppdu_stats_info *ppdu_stats, *tmp;
 	int ret;
+	int i;
 
 	ath11k_mac_drain_tx(ar);
 
@@ -5879,6 +5890,20 @@ static void ath11k_mac_op_stop(struct ieee80211_hw *hw)
 	synchronize_rcu();
 
 	atomic_set(&ar->num_pending_mgmt_tx, 0);
+
+	for (i = 0; i < ab->num_radios; i++) {
+		pdev = &ab->pdevs[i];
+		ar = pdev->ar;
+		if (!ar || ar->state == ATH11K_STATE_OFF)
+			continue;
+		break;
+	}
+
+	/* All PDEVs on the SoC are down, time to power down
+	 * the device.
+	 */
+	if (i == ab->num_radios)
+		ath11k_core_stop_device(ab);
 }
 
 static void
diff --git a/drivers/net/wireless/ath/ath11k/thermal.c b/drivers/net/wireless/ath/ath11k/thermal.c
index c96b26f..acb3b45 100644
--- a/drivers/net/wireless/ath/ath11k/thermal.c
+++ b/drivers/net/wireless/ath/ath11k/thermal.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: BSD-3-Clause-Clear
 /*
  * Copyright (c) 2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/device.h>
@@ -69,6 +70,11 @@ static ssize_t ath11k_thermal_show_temp(struct device *dev,
 
 	mutex_lock(&ar->conf_mutex);
 
+	if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) {
+		ret = -ESHUTDOWN;
+		goto out;
+	}
+
 	/* Can't get temperature when the card is off */
 	if (ar->state != ATH11K_STATE_ON) {
 		ret = -ENETDOWN;
@@ -131,6 +137,9 @@ int ath11k_thermal_set_throttling(struct ath11k *ar, u32 throttle_state)
 
 	lockdep_assert_held(&ar->conf_mutex);
 
+	if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
+		return 0;
+
 	if (ar->state != ATH11K_STATE_ON)
 		return 0;
 
@@ -162,6 +171,9 @@ int ath11k_thermal_register(struct ath11k_base *sc)
 	struct ath11k_pdev *pdev;
 	int i, ret;
 
+	if (test_bit(ATH11K_FLAG_REGISTERED, &sc->dev_flags))
+		return 0;
+
 	for (i = 0; i < sc->num_radios; i++) {
 		pdev = &sc->pdevs[i];
 		ar = pdev->ar;
