diff --git a/.github/workflows/compliance.yml b/.github/workflows/compliance.yml
index 1322acb42b..4dd81fffd0 100644
--- a/.github/workflows/compliance.yml
+++ b/.github/workflows/compliance.yml
@@ -63,7 +63,7 @@ jobs:
         # debug
         ls -la
         git log --pretty=oneline | head -n 10
-        $ZEPHYR_BASE/scripts/ci/check_compliance.py -m Codeowners -m Devicetree -m Gitlint -m Identity -m Nits -m pylint -m checkpatch -m KconfigBasic -c origin/${BASE_REF}..
+        $ZEPHYR_BASE/scripts/ci/check_compliance.py -m Codeowners -m Devicetree -m Gitlint -m Identity -m Nits -m pylint -m checkpatch -c origin/${BASE_REF}..
 
     - name: Upload Results
       uses: actions/upload-artifact@master
diff --git a/nrf_wifi/fw_bins/default/nrf70.bin b/nrf_wifi/fw_bins/default/nrf70.bin
index 2a3f210217..901da75b52 100644
Binary files a/nrf_wifi/fw_bins/default/nrf70.bin and b/nrf_wifi/fw_bins/default/nrf70.bin differ
diff --git a/nrf_wifi/fw_bins/radio_test/nrf70.bin b/nrf_wifi/fw_bins/radio_test/nrf70.bin
index a3168e2559..100c6d65c6 100644
Binary files a/nrf_wifi/fw_bins/radio_test/nrf70.bin and b/nrf_wifi/fw_bins/radio_test/nrf70.bin differ
diff --git a/nrf_wifi/fw_bins/scan_only/nrf70.bin b/nrf_wifi/fw_bins/scan_only/nrf70.bin
index 8513073cb0..909aaf50f8 100644
Binary files a/nrf_wifi/fw_bins/scan_only/nrf70.bin and b/nrf_wifi/fw_bins/scan_only/nrf70.bin differ
diff --git a/nrf_wifi/fw_if/umac_if/inc/default/fmac_api.h b/nrf_wifi/fw_if/umac_if/inc/default/fmac_api.h
index f483fbc584..34eb6a4f37 100644
--- a/nrf_wifi/fw_if/umac_if/inc/default/fmac_api.h
+++ b/nrf_wifi/fw_if/umac_if/inc/default/fmac_api.h
@@ -1036,6 +1036,13 @@ bool nrf_wifi_util_is_rawpktmode_enabled(struct nrf_wifi_fmac_vif_ctx *vif);
  *@retval      WIFI_NRF_STATUS_FAIL On failure
  */
 enum nrf_wifi_status nrf_wifi_check_mode_validity(unsigned char mode);
+#if defined(CONFIG_NRF_WIFI_RPU_RECOVERY) || defined(__DOXYGEN__)
+/** @cond INTERNAL_HIDDEN */
+enum nrf_wifi_status nrf_wifi_fmac_rpu_recovery_callback(void *mac_dev_ctx,
+						void *event_data,
+						unsigned int len);
+/** @endcond */
+#endif /* CONFIG_NRF_RPU_RECOVERY */
 /**
  * @}
  */
diff --git a/nrf_wifi/fw_if/umac_if/inc/default/fmac_structs.h b/nrf_wifi/fw_if/umac_if/inc/default/fmac_structs.h
index 1c42e55ea1..7e3a1e01f8 100644
--- a/nrf_wifi/fw_if/umac_if/inc/default/fmac_structs.h
+++ b/nrf_wifi/fw_if/umac_if/inc/default/fmac_structs.h
@@ -99,6 +99,11 @@ struct raw_rx_pkt_header {
  * the UMAC IF layer needs to invoke for various events.
  */
 struct nrf_wifi_fmac_callbk_fns {
+	/** Callback function to be called when RPU recovery is required. */
+	void (*rpu_recovery_callbk_fn)(void *os_vif_ctx,
+		void *event_data,
+		unsigned int event_len);
+
 	/** Callback function to be called when a scan is started. */
 	void (*scan_start_callbk_fn)(void *os_vif_ctx,
 				     struct nrf_wifi_umac_event_trigger_scan *scan_start_event,
diff --git a/nrf_wifi/fw_if/umac_if/inc/fw/host_rpu_sys_if.h b/nrf_wifi/fw_if/umac_if/inc/fw/host_rpu_sys_if.h
index f3c8b0c508..f20ab5c289 100644
--- a/nrf_wifi/fw_if/umac_if/inc/fw/host_rpu_sys_if.h
+++ b/nrf_wifi/fw_if/umac_if/inc/fw/host_rpu_sys_if.h
@@ -828,6 +828,30 @@ enum op_band {
 	BAND_24G
 };
 
+/**
+ * @brief This enum defines keep alive state
+ *
+ */
+enum keep_alive_status {
+	/** Keep alive feature disabled */
+	KEEP_ALIVE_DISABLED = 0,
+	/** Keep alive feature enabled */
+	KEEP_ALIVE_ENABLED = 1
+};
+
+/**
+ * @brief This enum specifies the type of frames used to retrieve buffered data
+ *  from the AP in power save mode.
+ */
+enum data_retrieve_mechanism {
+	/** Retrieves data from the AP using a PS-Poll frame */
+	PS_POLL_FRAME,
+	/** Retrieves data from the AP using a QoS Null frame */
+	QOS_NULL_FRAME,
+	/** For future implementation. The RPU will decide which frame to use */
+	AUTOMATIC
+};
+
 #define TWT_EXTEND_SP_EDCA  0x1
 #define DISABLE_DFS_CHANNELS 0x2
 
@@ -872,6 +896,20 @@ struct nrf_wifi_cmd_sys_init {
 	 *  without receiving beacons before disconnection.
 	 */
 	unsigned int discon_timeout;
+	/** RPU uses QoS null frame or PS-Poll frame to retrieve buffered frames
+	 * from the AP in power save @ref data_retrieve_mechanism.
+	 */
+	unsigned char ps_data_retrieval_mech;
+	/** The RPU uses this value to configure watchdog timer */
+	unsigned int watchdog_timer_val;
+	/** The RPU uses this value to decide whether keep alive
+	 *  feature is enabled or not see enum keep_alive_status
+	 */
+	unsigned char keep_alive_enable;
+	/** The RPU uses this value(in seconds) for periodicity of the keep
+	 *  alive frame.
+	 */
+	unsigned int keep_alive_period;
 } __NRF_WIFI_PKD;
 
 /**
diff --git a/nrf_wifi/fw_if/umac_if/inc/fw/lmac_if_common.h b/nrf_wifi/fw_if/umac_if/inc/fw/lmac_if_common.h
index f3ddb04ad1..e903b96b65 100644
--- a/nrf_wifi/fw_if/umac_if/inc/fw/lmac_if_common.h
+++ b/nrf_wifi/fw_if/umac_if/inc/fw/lmac_if_common.h
@@ -19,7 +19,7 @@
 #define RPU_MEM_LMAC_VER 0xB7000D54
 
 #define RPU_MEM_LMAC_PATCH_BIN 0x80044000
-#define RPU_MEM_LMAC_PATCH_BIMG 0x8004B000
+#define RPU_MEM_LMAC_PATCH_BIMG 0x8004B400
 
 #define NRF_WIFI_LMAC_VER(ver) ((ver & 0xFF000000) >> 24)
 #define NRF_WIFI_LMAC_VER_MAJ(ver) ((ver & 0x00FF0000) >> 16)
diff --git a/nrf_wifi/fw_if/umac_if/src/cmd.c b/nrf_wifi/fw_if/umac_if/src/cmd.c
index cb4847be75..063c520599 100644
--- a/nrf_wifi/fw_if/umac_if/src/cmd.c
+++ b/nrf_wifi/fw_if/umac_if/src/cmd.c
@@ -149,10 +149,30 @@ enum nrf_wifi_status umac_cmd_init(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
 	umac_cmd_data->tcp_ip_checksum_offload = 1;
 #endif /* CONFIG_NRF700X_TCP_IP_CHECKSUM_OFFLOAD */
 	umac_cmd_data->discon_timeout = CONFIG_NRF_WIFI_AP_DEAD_DETECT_TIMEOUT;
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY
+	umac_cmd_data->watchdog_timer_val =
+		(CONFIG_NRF_WIFI_RPU_RECOVERY_PS_ACTIVE_TIMEOUT_MS) / 1000;
+#else
+	/* Disable watchdog */
+	umac_cmd_data->watchdog_timer_val = 0xFFFFFF;
+#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */
 
 	nrf_wifi_osal_log_dbg(fmac_dev_ctx->fpriv->opriv, "RPU LPM type: %s",
 		umac_cmd_data->sys_params.sleep_enable == 2 ? "HW" :
 		umac_cmd_data->sys_params.sleep_enable == 1 ? "SW" : "DISABLED");
+#ifdef CONFIG_NRF_WIFI_MGMT_BUFF_OFFLOAD
+	umac_cmd_data->mgmt_buff_offload =  1;
+	nrf_wifi_osal_log_info(fmac_dev_ctx->fpriv->opriv,
+			       "Management buffer offload enabled\n");
+#endif /* CONFIG_NRF_WIFI_MGMT_BUFF_OFFLOAD */
+#ifdef CONFIG_NRF_WIFI_FEAT_KEEPALIVE
+	umac_cmd_data->keep_alive_enable = KEEP_ALIVE_ENABLED;
+	umac_cmd_data->keep_alive_period = CONFIG_NRF_WIFI_KEEPALIVE_PERIOD_S;
+	nrf_wifi_osal_log_dbg(fmac_dev_ctx->fpriv->opriv,
+			       "Keepalive enabled with period %d\n",
+				   umac_cmd_data->keepalive_period);
+#endif /* CONFIG_NRF_WIFI_FEAT_KEEPALIVE */
+
 #ifndef CONFIG_NRF700X_RADIO_TEST
 	nrf_wifi_osal_mem_cpy(fmac_dev_ctx->fpriv->opriv,
 			      umac_cmd_data->rx_buf_pools,
@@ -202,7 +222,13 @@ enum nrf_wifi_status umac_cmd_init(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
 		umac_cmd_data->disable_beamforming = 1;
 	}
 
-	 status = nrf_wifi_hal_ctrl_cmd_send(fmac_dev_ctx->hal_dev_ctx,
+#if defined(CONFIG_NRF_WIFI_QOS_NULL_BASED_RETRIEVAL)
+	umac_cmd_data->ps_data_retrieval_mech = QOS_NULL_FRAME;
+#else
+	umac_cmd_data->ps_data_retrieval_mech = PS_POLL_FRAME;
+#endif  /* CONFIG_NRF_WIFI_QOS_NULL_BASED_RETRIEVAL */
+
+	status = nrf_wifi_hal_ctrl_cmd_send(fmac_dev_ctx->hal_dev_ctx,
 					    umac_cmd,
 					    (sizeof(*umac_cmd) + len));
 
diff --git a/nrf_wifi/fw_if/umac_if/src/default/fmac_api.c b/nrf_wifi/fw_if/umac_if/src/default/fmac_api.c
index 40a34134d0..dc9ee7b8c0 100644
--- a/nrf_wifi/fw_if/umac_if/src/default/fmac_api.c
+++ b/nrf_wifi/fw_if/umac_if/src/default/fmac_api.c
@@ -433,13 +433,50 @@ enum nrf_wifi_status nrf_wifi_fmac_dev_init(struct nrf_wifi_fmac_dev_ctx *fmac_d
 
 void nrf_wifi_fmac_dev_deinit(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx)
 {
-	nrf_wifi_hal_lock_rx(fmac_dev_ctx->hal_dev_ctx);
+	nrf_wifi_hal_dev_deinit(fmac_dev_ctx->hal_dev_ctx);
 	nrf_wifi_fmac_fw_deinit(fmac_dev_ctx);
 	nrf_wifi_osal_mem_free(fmac_dev_ctx->fpriv->opriv,
 			       fmac_dev_ctx->tx_pwr_ceil_params);
-	nrf_wifi_hal_unlock_rx(fmac_dev_ctx->hal_dev_ctx);
 }
 
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY
+enum nrf_wifi_status nrf_wifi_fmac_rpu_recovery_callback(void *mac_dev_ctx,
+						void *event_data,
+						unsigned int len)
+{
+	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
+	struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
+	struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL;
+	struct nrf_wifi_fmac_priv *fpriv = NULL;
+	struct nrf_wifi_fmac_priv_def *def_priv = NULL;
+
+	fmac_dev_ctx = mac_dev_ctx;
+	if (!fmac_dev_ctx) {
+		nrf_wifi_osal_log_err(fpriv->opriv,
+				      "%s: Invalid device context",
+				      __func__);
+		goto out;
+	}
+	def_dev_ctx = wifi_dev_priv(fmac_dev_ctx);
+	if (!def_dev_ctx) {
+		nrf_wifi_osal_log_err(fpriv->opriv,
+				      "%s: Invalid device context",
+				      __func__);
+		goto out;
+	}
+	fpriv = fmac_dev_ctx->fpriv;
+	def_priv = wifi_fmac_priv(fpriv);
+
+	/* Here we only care about FMAC, so, just use VIF0 */
+	def_priv->callbk_fns.rpu_recovery_callbk_fn(def_dev_ctx->vif_ctx[0],
+			event_data, len);
+
+	status = NRF_WIFI_STATUS_SUCCESS;
+out:
+	return status;
+}
+#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */
+
 struct nrf_wifi_fmac_priv *nrf_wifi_fmac_init(struct nrf_wifi_data_config_params *data_config,
 					      struct rx_buf_pool_params *rx_buf_pools,
 					      struct nrf_wifi_fmac_callbk_fns *callbk_fns)
@@ -525,7 +562,12 @@ struct nrf_wifi_fmac_priv *nrf_wifi_fmac_init(struct nrf_wifi_data_config_params
 
 	fpriv->hpriv = nrf_wifi_hal_init(opriv,
 					 &hal_cfg_params,
-					 &nrf_wifi_fmac_event_callback);
+					 &nrf_wifi_fmac_event_callback,
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY
+					 &nrf_wifi_fmac_rpu_recovery_callback);
+#else
+					 NULL);
+#endif
 
 	if (!fpriv->hpriv) {
 		nrf_wifi_osal_log_err(opriv,
diff --git a/nrf_wifi/fw_if/umac_if/src/event.c b/nrf_wifi/fw_if/umac_if/src/event.c
index 41ca50ccc7..06dfbaaad4 100644
--- a/nrf_wifi/fw_if/umac_if/src/event.c
+++ b/nrf_wifi/fw_if/umac_if/src/event.c
@@ -194,10 +194,17 @@ static enum nrf_wifi_status umac_event_ctrl_process(struct nrf_wifi_fmac_dev_ctx
 	callbk_fns = &def_priv->callbk_fns;
 #endif /* !CONFIG_NRF700X_RADIO_TEST */
 
+#ifdef CONFIG_NRF_WIFI_CMD_EVENT_LOG
+	nrf_wifi_osal_log_info(fmac_dev_ctx->fpriv->opriv,
+			      "%s: Event %d received from UMAC\n",
+			      __func__,
+			      event_num);
+#else
 	nrf_wifi_osal_log_dbg(fmac_dev_ctx->fpriv->opriv,
 			      "%s: Event %d received from UMAC",
 			      __func__,
 			      event_num);
+#endif /* CONFIG_NRF_WIFI_CMD_EVENT_LOG */
 
 	switch (umac_hdr->cmd_evnt) {
 	case NRF_WIFI_UMAC_EVENT_GET_REG:
@@ -631,10 +638,17 @@ nrf_wifi_fmac_data_event_process(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
 
 	event = ((struct nrf_wifi_umac_head *)umac_head)->cmd;
 
+#ifdef CONFIG_NRF_WIFI_CMD_EVENT_LOG
+	nrf_wifi_osal_log_info(fmac_dev_ctx->fpriv->opriv,
+			      "%s: Event %d received from UMAC\n",
+			      __func__,
+			      event);
+#else
 	nrf_wifi_osal_log_dbg(fmac_dev_ctx->fpriv->opriv,
 			      "%s: Event %d received from UMAC",
 			      __func__,
 			      event);
+#endif /* CONFIG_NRF_WIFI_CMD_EVENT_LOG */
 
 	switch (event) {
 	case NRF_WIFI_CMD_RX_BUFF:
@@ -1121,10 +1135,17 @@ enum nrf_wifi_status nrf_wifi_fmac_event_callback(void *mac_dev_ctx,
 	umac_msg_len = rpu_msg->hdr.len;
 	umac_msg_type = umac_hdr->cmd_evnt;
 
+#ifdef CONFIG_NRF_WIFI_CMD_EVENT_LOG
+	nrf_wifi_osal_log_info(fmac_dev_ctx->fpriv->opriv,
+			      "%s: Event type %d recd\n",
+			      __func__,
+			      rpu_msg->type);
+#else
 	nrf_wifi_osal_log_dbg(fmac_dev_ctx->fpriv->opriv,
 			      "%s: Event type %d recd",
 			      __func__,
 			      rpu_msg->type);
+#endif /* CONFIG_NRF_WIFI_CMD_EVENT_LOG */
 
 	switch (rpu_msg->type) {
 #ifndef CONFIG_NRF700X_RADIO_TEST
diff --git a/nrf_wifi/fw_if/umac_if/src/radio_test/fmac_api.c b/nrf_wifi/fw_if/umac_if/src/radio_test/fmac_api.c
index 6579460892..0c616b15b4 100644
--- a/nrf_wifi/fw_if/umac_if/src/radio_test/fmac_api.c
+++ b/nrf_wifi/fw_if/umac_if/src/radio_test/fmac_api.c
@@ -229,7 +229,8 @@ struct nrf_wifi_fmac_priv *nrf_wifi_fmac_init_rt(void)
 
 	fpriv->hpriv = nrf_wifi_hal_init(opriv,
 					 &hal_cfg_params,
-					 &nrf_wifi_fmac_event_callback);
+					 &nrf_wifi_fmac_event_callback,
+					 NULL);
 
 	if (!fpriv->hpriv) {
 		nrf_wifi_osal_log_err(opriv,
diff --git a/nrf_wifi/fw_if/umac_if/src/rx.c b/nrf_wifi/fw_if/umac_if/src/rx.c
index 01f6d3d468..cdb6c206cb 100644
--- a/nrf_wifi/fw_if/umac_if/src/rx.c
+++ b/nrf_wifi/fw_if/umac_if/src/rx.c
@@ -375,6 +375,9 @@ enum nrf_wifi_status nrf_wifi_fmac_rx_event_process(struct nrf_wifi_fmac_dev_ctx
 #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */
 			nrf_wifi_osal_nbuf_free(fmac_dev_ctx->fpriv->opriv,
 						nwb);
+#ifdef CONFIG_NRF_WIFI_MGMT_BUFF_OFFLOAD
+			goto out;
+#endif /* CONFIG_NRF_WIFI_MGMT_BUFF_OFFLOAD */
 		}
 #if defined(CONFIG_NRF700X_RAW_DATA_RX) || defined(CONFIG_NRF700X_PROMISC_DATA_RX)
 		else if (config->rx_pkt_type == NRF_WIFI_RAW_RX_PKT) {
diff --git a/nrf_wifi/fw_if/umac_if/src/tx.c b/nrf_wifi/fw_if/umac_if/src/tx.c
index b0bf63b753..8335a73ba4 100644
--- a/nrf_wifi/fw_if/umac_if/src/tx.c
+++ b/nrf_wifi/fw_if/umac_if/src/tx.c
@@ -1452,6 +1452,14 @@ enum nrf_wifi_status nrf_wifi_fmac_rawtx_done_event_process(
 		goto out;
 	}
 
+	def_dev_ctx = wifi_dev_priv(fmac_dev_ctx);
+	if (!def_dev_ctx || !def_dev_ctx->tx_config.tx_lock) {
+		/* This is a valid case when the TX_DONE event is received
+		 * during the driver deinit, so, silently ignore the failure.
+		 */
+		return NRF_WIFI_STATUS_SUCCESS;
+	}
+
 	nrf_wifi_osal_spinlock_take(fmac_dev_ctx->fpriv->opriv,
 				    def_dev_ctx->tx_config.tx_lock);
 
@@ -1790,6 +1798,12 @@ void tx_deinit(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx)
 
 	for (i = 0; i < def_priv->num_tx_tokens; i++) {
 		if (def_dev_ctx->tx_config.pkt_info_p) {
+			while (nrf_wifi_utils_q_len(fpriv->opriv,
+				   def_dev_ctx->tx_config.pkt_info_p[i].pkt)) {
+				nrf_wifi_osal_nbuf_free(fpriv->opriv,
+					nrf_wifi_utils_q_dequeue(fpriv->opriv,
+						def_dev_ctx->tx_config.pkt_info_p[i].pkt));
+			}
 			nrf_wifi_utils_list_free(fpriv->opriv,
 						 def_dev_ctx->tx_config.pkt_info_p[i].pkt);
 		}
@@ -1800,6 +1814,12 @@ void tx_deinit(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx)
 
 	for (i = 0; i < NRF_WIFI_FMAC_AC_MAX; i++) {
 		for (j = 0; j < MAX_SW_PEERS; j++) {
+			while (nrf_wifi_utils_q_len(fpriv->opriv,
+				   def_dev_ctx->tx_config.data_pending_txq[j][i])) {
+				nrf_wifi_osal_nbuf_free(fpriv->opriv,
+					nrf_wifi_utils_q_dequeue(fpriv->opriv,
+						def_dev_ctx->tx_config.data_pending_txq[j][i]));
+			}
 			nrf_wifi_utils_q_free(fpriv->opriv,
 					      def_dev_ctx->tx_config.data_pending_txq[j][i]);
 		}
diff --git a/nrf_wifi/hw_if/hal/inc/fw/rpu_if.h b/nrf_wifi/hw_if/hal/inc/fw/rpu_if.h
index 88e3ea83cf..0fa1dc69bf 100644
--- a/nrf_wifi/hw_if/hal/inc/fw/rpu_if.h
+++ b/nrf_wifi/hw_if/hal/inc/fw/rpu_if.h
@@ -101,6 +101,12 @@ struct rpu_mcu_boot_vectors {
 #define RPU_REG_BIT_MIPS_WATCHDOG_INT_STATUS 1
 
 #define RPU_REG_MIPS_MCU_TIMER_CONTROL 0xA4000048
+#define RPU_REG_MIPS_MCU_TIMER 0xA400004C /* 24 bit timer@core clock ticks*/
+#define RPU_REG_MIPS_MCU_TIMER_RESET_VAL 0xFFFFFF
+
+#define RPU_REG_MIPS_MCU_UCCP_INT_CLEAR 0xA400000C
+#define RPU_REG_BIT_MIPS_UCCP_INT_CLEAR 0
+#define RPU_REG_BIT_MIPS_WATCHDOG_INT_CLEAR 1
 
 #define RPU_REG_MIPS_MCU_SYS_CORE_MEM_CTRL 0xA4000030 /* 13.1.10 */
 #define RPU_REG_MIPS_MCU_SYS_CORE_MEM_WDATA 0xA4000034 /* 13.1.11 */
diff --git a/nrf_wifi/hw_if/hal/inc/hal_api.h b/nrf_wifi/hw_if/hal/inc/hal_api.h
index 0604a3ec46..0fa58fc1e5 100644
--- a/nrf_wifi/hw_if/hal/inc/hal_api.h
+++ b/nrf_wifi/hw_if/hal/inc/hal_api.h
@@ -36,6 +36,8 @@ extern const struct nrf70_fw_addr_info nrf70_fw_addr_info[];
  * @cfg_params: Parameters needed to configure the HAL for WLAN operation.
  * @intr_callbk_fn: Pointer to the callback function which the user of this
  *                  layer needs to implement to handle events from the RPU.
+ * @rpu_recovery_callbk_fn: Pointer to the callback function which the user of
+ *                          this layer needs to implement to handle RPU recovery.
  *
  * This API is used to initialize the HAL layer and is expected to be called
  * before using the HAL layer. This API returns a pointer to the HAL context
@@ -48,7 +50,10 @@ nrf_wifi_hal_init(struct nrf_wifi_osal_priv *opriv,
 		  struct nrf_wifi_hal_cfg_params *cfg_params,
 		  enum nrf_wifi_status (*intr_callbk_fn)(void *mac_ctx,
 							 void *event_data,
-							 unsigned int len));
+							 unsigned int len),
+		  enum nrf_wifi_status (*rpu_recovery_callbk_fn)(void *mac_ctx,
+							     void *event_data,
+							     unsigned int len));
 
 /**
  * nrf_wifi_hal_deinit() - Deinitialize the HAL layer.
diff --git a/nrf_wifi/hw_if/hal/inc/hal_interrupt.h b/nrf_wifi/hw_if/hal/inc/hal_interrupt.h
index c21e0e6781..849eef3617 100644
--- a/nrf_wifi/hw_if/hal/inc/hal_interrupt.h
+++ b/nrf_wifi/hw_if/hal/inc/hal_interrupt.h
@@ -43,6 +43,8 @@ enum nrf_wifi_status hal_rpu_irq_disable(struct nrf_wifi_hal_dev_ctx *hal_dev_ct
 /**
  * hal_rpu_irq_process() - Processes an interrupt from the RPU.
  * @hal_dev_ctx: Pointer to HAL context.
+ * @do_rpu_recovery: Pointer to a boolean variable that indicates if the RPU recovery
+ *                  is required.
  *
  * This function is an interrupt handler for the interrupts generated by the
  * RPU. This function does the following:
@@ -57,5 +59,6 @@ enum nrf_wifi_status hal_rpu_irq_disable(struct nrf_wifi_hal_dev_ctx *hal_dev_ct
  *		Pass : %NRF_WIFI_STATUS_SUCCESS
  *		Error: %NRF_WIFI_STATUS_FAIL
  */
-enum nrf_wifi_status hal_rpu_irq_process(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx);
+enum nrf_wifi_status hal_rpu_irq_process(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx,
+	bool *do_rpu_recovery);
 #endif /* __HAL_INTERRUPT_H__ */
diff --git a/nrf_wifi/hw_if/hal/inc/hal_structs.h b/nrf_wifi/hw_if/hal/inc/hal_structs.h
index ba5076d680..ba81691d8c 100644
--- a/nrf_wifi/hw_if/hal/inc/hal_structs.h
+++ b/nrf_wifi/hw_if/hal/inc/hal_structs.h
@@ -126,6 +126,9 @@ struct nrf_wifi_hal_priv {
 	enum nrf_wifi_status (*intr_callbk_fn)(void *mac_ctx,
 					       void *event_data,
 					       unsigned int len);
+	enum nrf_wifi_status (*rpu_recovery_callbk_fn)(void *mac_ctx,
+							void *event_data,
+							unsigned int len);
 	struct nrf_wifi_hal_cfg_params cfg_params;
 	unsigned long addr_pktram_base;
 };
@@ -223,6 +226,12 @@ struct nrf_wifi_hal_dev_ctx {
 	unsigned long addr_rpu_pktram_base_rx;
 	unsigned long addr_rpu_pktram_base_rx_pool[MAX_NUM_OF_RX_QUEUES];
 	unsigned long tx_frame_offset;
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY
+	unsigned long last_wakeup_now_asserted_time_ms;
+	unsigned long last_wakeup_now_deasserted_time_ms;
+	unsigned long last_rpu_sleep_opp_time_ms;
+	bool is_wakup_now_asserted;
+#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */
 #ifdef CONFIG_NRF_WIFI_LOW_POWER
 	enum RPU_PS_STATE rpu_ps_state;
 	void *rpu_ps_timer;
@@ -237,6 +246,8 @@ struct nrf_wifi_hal_dev_ctx {
 	unsigned int event_data_pending;
 	unsigned int event_resubmit;
 	enum NRF_WIFI_HAL_STATUS hal_status;
+	void *recovery_tasklet;
+	void *lock_recovery;
 };
 
 
diff --git a/nrf_wifi/hw_if/hal/src/hal_api.c b/nrf_wifi/hw_if/hal/src/hal_api.c
index ae44a90fd2..c886dc248a 100644
--- a/nrf_wifi/hw_if/hal/src/hal_api.c
+++ b/nrf_wifi/hw_if/hal/src/hal_api.c
@@ -66,6 +66,13 @@ unsigned long nrf_wifi_hal_buf_map_rx(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx,
 	unsigned long bounce_buf_addr = 0;
 	unsigned long rpu_addr = 0;
 
+	if (!hal_dev_ctx || !hal_dev_ctx->rx_buf_info[pool_id]) {
+		nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv,
+				      "%s: Invalid parameters\n",
+				      __func__);
+		goto out;
+	}
+
 	rx_buf_info = &hal_dev_ctx->rx_buf_info[pool_id][buf_id];
 
 	if (rx_buf_info->mapped) {
@@ -300,6 +307,20 @@ unsigned long nrf_wifi_hal_buf_unmap_tx(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx
 
 
 #ifdef CONFIG_NRF_WIFI_LOW_POWER
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY
+static void did_rpu_had_sleep_opp(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx)
+{
+	unsigned int deassert_time_diff_ms = nrf_wifi_osal_time_elapsed_ms(
+		hal_dev_ctx->hpriv->opriv,
+		hal_dev_ctx->last_wakeup_now_deasserted_time_ms);
+
+	if (deassert_time_diff_ms > CONFIG_NRF_WIFI_RPU_MIN_TIME_TO_ENTER_SLEEP_MS) {
+		hal_dev_ctx->last_rpu_sleep_opp_time_ms =
+			hal_dev_ctx->last_wakeup_now_deasserted_time_ms;
+	}
+}
+#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */
+
 enum nrf_wifi_status hal_rpu_ps_wake(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx)
 {
 	unsigned int reg_val = 0;
@@ -332,7 +353,11 @@ enum nrf_wifi_status hal_rpu_ps_wake(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx)
 	}
 
 	nrf_wifi_bal_rpu_ps_wake(hal_dev_ctx->bal_dev_ctx);
-
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY
+	hal_dev_ctx->is_wakup_now_asserted = true;
+	hal_dev_ctx->last_wakeup_now_asserted_time_ms =
+		nrf_wifi_osal_time_get_curr_ms(hal_dev_ctx->hpriv->opriv);
+#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */
 	start_time_us = nrf_wifi_osal_time_get_curr_us(hal_dev_ctx->hpriv->opriv);
 
 	rpu_ps_state_mask = ((1 << RPU_REG_BIT_PS_STATE) |
@@ -372,9 +397,21 @@ enum nrf_wifi_status hal_rpu_ps_wake(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx)
 				      RPU_PS_WAKE_TIMEOUT_S,
 				      reg_val,
 				      rpu_ps_state_mask);
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY
+		nrf_wifi_osal_tasklet_schedule(hal_dev_ctx->hpriv->opriv,
+					       hal_dev_ctx->recovery_tasklet);
+#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */
 		goto out;
 	}
 	hal_dev_ctx->rpu_ps_state = RPU_PS_STATE_AWAKE;
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY
+	did_rpu_had_sleep_opp(hal_dev_ctx);
+#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY_PS_STATE_DEBUG
+	nrf_wifi_osal_log_info(hal_dev_ctx->hpriv->opriv,
+			       "%s: RPU PS state is AWAKE\n",
+			       __func__);
+#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY_PS_STATE_DEBUG */
 
 out:
 	if (!hal_dev_ctx->irq_ctx) {
@@ -398,9 +435,18 @@ static void hal_rpu_ps_sleep(unsigned long data)
 					&flags);
 
 	nrf_wifi_bal_rpu_ps_sleep(hal_dev_ctx->bal_dev_ctx);
-
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY
+	hal_dev_ctx->is_wakup_now_asserted = false;
+	hal_dev_ctx->last_wakeup_now_deasserted_time_ms =
+		nrf_wifi_osal_time_get_curr_ms(hal_dev_ctx->hpriv->opriv);
+#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */
 	hal_dev_ctx->rpu_ps_state = RPU_PS_STATE_ASLEEP;
 
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY_PS_STATE_DEBUG
+	nrf_wifi_osal_log_info(hal_dev_ctx->hpriv->opriv,
+			       "%s: RPU PS state is ASLEEP\n",
+			       __func__);
+#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY_PS_STATE_DEBUG */
 	nrf_wifi_osal_spinlock_irq_rel(hal_dev_ctx->hpriv->opriv,
 				       hal_dev_ctx->rpu_ps_lock,
 				       &flags);
@@ -881,6 +927,17 @@ enum nrf_wifi_status nrf_wifi_hal_ctrl_cmd_send(struct nrf_wifi_hal_dev_ctx *hal
 {
 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
 
+#ifdef CONFIG_NRF_WIFI_CMD_EVENT_LOG
+	nrf_wifi_osal_log_info(hal_dev_ctx->hpriv->opriv,
+			      "%s: caller %p\n",
+			      __func__,
+			      __builtin_return_address(0));
+#else
+	nrf_wifi_osal_log_dbg(hal_dev_ctx->hpriv->opriv,
+			     "%s: caller %p\n",
+			     __func__,
+			     __builtin_return_address(0));
+#endif
 	nrf_wifi_osal_spinlock_take(hal_dev_ctx->hpriv->opriv,
 				    hal_dev_ctx->lock_hal);
 
@@ -986,6 +1043,12 @@ static void event_tasklet_fn(unsigned long data)
 	unsigned long flags = 0;
 
 	hal_dev_ctx = (struct nrf_wifi_hal_dev_ctx *)data;
+	if (!hal_dev_ctx) {
+		nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv,
+				      "%s: Invalid hal_dev_ctx\n",
+				      __func__);
+		return;
+	}
 
 	nrf_wifi_osal_spinlock_irq_take(hal_dev_ctx->hpriv->opriv,
 					hal_dev_ctx->lock_rx,
@@ -1089,8 +1152,6 @@ void hal_rpu_eventq_drain(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx)
 	return;
 }
 
-
-
 void nrf_wifi_hal_proc_ctx_set(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx,
 			       enum RPU_PROC_TYPE proc)
 {
@@ -1098,6 +1159,51 @@ void nrf_wifi_hal_proc_ctx_set(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx,
 }
 
 
+static enum nrf_wifi_status hal_rpu_recovery(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx)
+{
+	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
+
+	if (!hal_dev_ctx->hpriv->rpu_recovery_callbk_fn) {
+		nrf_wifi_osal_log_dbg(hal_dev_ctx->hpriv->opriv,
+				      "%s: RPU recovery callback not registered",
+				      __func__);
+		goto out;
+	}
+
+	status = hal_dev_ctx->hpriv->rpu_recovery_callbk_fn(hal_dev_ctx->mac_dev_ctx, NULL, 0);
+	if (status != NRF_WIFI_STATUS_SUCCESS) {
+		nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv,
+				      "%s: RPU recovery failed",
+				      __func__);
+		goto out;
+	}
+
+out:
+	return status;
+}
+
+static void recovery_tasklet_fn(unsigned long data)
+{
+	struct nrf_wifi_hal_dev_ctx *hal_dev_ctx = NULL;
+	unsigned long flags = 0;
+
+	hal_dev_ctx = (struct nrf_wifi_hal_dev_ctx *)data;
+	if (!hal_dev_ctx) {
+		nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv,
+				      "%s: Invalid hal_dev_ctx",
+				      __func__);
+		return;
+	}
+
+	nrf_wifi_osal_spinlock_irq_take(hal_dev_ctx->hpriv->opriv,
+					hal_dev_ctx->lock_recovery,
+					&flags);
+	hal_rpu_recovery(hal_dev_ctx);
+	nrf_wifi_osal_spinlock_irq_rel(hal_dev_ctx->hpriv->opriv,
+				       hal_dev_ctx->lock_recovery,
+				       &flags);
+}
+
 struct nrf_wifi_hal_dev_ctx *nrf_wifi_hal_dev_add(struct nrf_wifi_hal_priv *hpriv,
 						  void *mac_dev_ctx)
 {
@@ -1182,6 +1288,29 @@ struct nrf_wifi_hal_dev_ctx *nrf_wifi_hal_dev_add(struct nrf_wifi_hal_priv *hpri
 				   event_tasklet_fn,
 				   (unsigned long)hal_dev_ctx);
 
+	hal_dev_ctx->recovery_tasklet = nrf_wifi_osal_tasklet_alloc(hpriv->opriv,
+		NRF_WIFI_TASKLET_TYPE_BH);
+	if (!hal_dev_ctx->recovery_tasklet) {
+		nrf_wifi_osal_log_err(hpriv->opriv,
+				      "%s: Unable to allocate recovery_tasklet",
+				      __func__);
+		goto event_tasklet_free;
+	}
+	nrf_wifi_osal_tasklet_init(hpriv->opriv,
+				   hal_dev_ctx->recovery_tasklet,
+				   recovery_tasklet_fn,
+				   (unsigned long)hal_dev_ctx);
+
+	hal_dev_ctx->lock_recovery = nrf_wifi_osal_spinlock_alloc(hpriv->opriv);
+	if (!hal_dev_ctx->lock_recovery) {
+		nrf_wifi_osal_log_err(hpriv->opriv,
+				      "%s: Unable to allocate recovery lock",
+				      __func__);
+		goto recovery_tasklet_free;
+	}
+
+	nrf_wifi_osal_spinlock_init(hpriv->opriv,
+				    hal_dev_ctx->lock_recovery);
 #ifdef CONFIG_NRF_WIFI_LOW_POWER
 	status = hal_rpu_ps_init(hal_dev_ctx);
 
@@ -1189,7 +1318,7 @@ struct nrf_wifi_hal_dev_ctx *nrf_wifi_hal_dev_add(struct nrf_wifi_hal_priv *hpri
 		nrf_wifi_osal_log_err(hpriv->opriv,
 				      "%s: hal_rpu_ps_init failed",
 				      __func__);
-		goto tasklet_free;
+		goto lock_recovery_free;
 	}
 #endif /* CONFIG_NRF_WIFI_LOW_POWER */
 
@@ -1200,7 +1329,7 @@ struct nrf_wifi_hal_dev_ctx *nrf_wifi_hal_dev_add(struct nrf_wifi_hal_priv *hpri
 		nrf_wifi_osal_log_err(hpriv->opriv,
 				      "%s: nrf_wifi_bal_dev_add failed",
 				      __func__);
-		goto tasklet_free;
+		goto lock_recovery_free;
 	}
 
 	status = hal_rpu_irq_enable(hal_dev_ctx);
@@ -1274,7 +1403,13 @@ struct nrf_wifi_hal_dev_ctx *nrf_wifi_hal_dev_add(struct nrf_wifi_hal_priv *hpri
 #endif /* !CONFIG_NRF700X_RADIO_TEST */
 bal_dev_free:
 	nrf_wifi_bal_dev_rem(hal_dev_ctx->bal_dev_ctx);
-tasklet_free:
+lock_recovery_free:
+	nrf_wifi_osal_spinlock_free(hpriv->opriv,
+					hal_dev_ctx->lock_recovery);
+recovery_tasklet_free:
+	nrf_wifi_osal_tasklet_free(hpriv->opriv,
+					hal_dev_ctx->recovery_tasklet);
+event_tasklet_free:
 	nrf_wifi_osal_tasklet_free(hpriv->opriv,
 					hal_dev_ctx->event_tasklet);
 lock_rx_free:
@@ -1302,6 +1437,14 @@ void nrf_wifi_hal_dev_rem(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx)
 {
 	unsigned int i = 0;
 
+
+	nrf_wifi_osal_tasklet_kill(hal_dev_ctx->hpriv->opriv,
+				   hal_dev_ctx->recovery_tasklet);
+	nrf_wifi_osal_tasklet_free(hal_dev_ctx->hpriv->opriv,
+				   hal_dev_ctx->recovery_tasklet);
+	nrf_wifi_osal_spinlock_free(hal_dev_ctx->hpriv->opriv,
+					hal_dev_ctx->lock_recovery);
+
 	nrf_wifi_osal_tasklet_kill(hal_dev_ctx->hpriv->opriv,
 				   hal_dev_ctx->event_tasklet);
 
@@ -1395,10 +1538,11 @@ enum nrf_wifi_status nrf_wifi_hal_dev_init(struct nrf_wifi_hal_dev_ctx *hal_dev_
 
 void nrf_wifi_hal_dev_deinit(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx)
 {
+	nrf_wifi_hal_disable(hal_dev_ctx);
 	nrf_wifi_bal_dev_deinit(hal_dev_ctx->bal_dev_ctx);
+	hal_rpu_eventq_drain(hal_dev_ctx);
 }
 
-
 void nrf_wifi_hal_lock_rx(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx)
 {
 	unsigned long flags = 0;
@@ -1425,17 +1569,23 @@ enum nrf_wifi_status nrf_wifi_hal_irq_handler(void *data)
 #ifdef CONFIG_NRF_WIFI_LOW_POWER
 	enum RPU_PS_STATE ps_state = RPU_PS_STATE_ASLEEP;
 #endif /* CONFIG_NRF_WIFI_LOW_POWER */
+	bool do_rpu_recovery = false;
 
 	hal_dev_ctx = (struct nrf_wifi_hal_dev_ctx *)data;
+	if (!hal_dev_ctx) {
+		nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv,
+				      "%s: Invalid hal_dev_ctx\n",
+				      __func__);
+		goto out;
+	}
 
 	nrf_wifi_osal_spinlock_irq_take(hal_dev_ctx->hpriv->opriv,
 					hal_dev_ctx->lock_rx,
 					&flags);
 
 	if (hal_dev_ctx->hal_status != NRF_WIFI_HAL_STATUS_ENABLED) {
-		/* Ignore the interrupt if the HAL is not enabled */
 		status = NRF_WIFI_STATUS_SUCCESS;
-		goto out;
+		goto unlock;
 	}
 
 #ifdef CONFIG_NRF_WIFI_LOW_POWER
@@ -1447,7 +1597,7 @@ enum nrf_wifi_status nrf_wifi_hal_irq_handler(void *data)
 #endif /* CONFIG_NRF_WIFI_LOW_POWER_DBG */
 #endif /* CONFIG_NRF_WIFI_LOW_POWER */
 
-	status = hal_rpu_irq_process(hal_dev_ctx);
+	status = hal_rpu_irq_process(hal_dev_ctx, &do_rpu_recovery);
 
 #ifdef CONFIG_NRF_WIFI_LOW_POWER
 	hal_rpu_ps_set_state(hal_dev_ctx,
@@ -1458,16 +1608,23 @@ enum nrf_wifi_status nrf_wifi_hal_irq_handler(void *data)
 #endif /* CONFIG_NRF_WIFI_LOW_POWER */
 
 	if (status != NRF_WIFI_STATUS_SUCCESS) {
-		goto out;
+		goto unlock;
+	}
+
+	if (do_rpu_recovery) {
+		nrf_wifi_osal_tasklet_schedule(hal_dev_ctx->hpriv->opriv,
+					       hal_dev_ctx->recovery_tasklet);
+		goto unlock;
 	}
 
 	nrf_wifi_osal_tasklet_schedule(hal_dev_ctx->hpriv->opriv,
 				       hal_dev_ctx->event_tasklet);
 
-out:
+unlock:
 	nrf_wifi_osal_spinlock_irq_rel(hal_dev_ctx->hpriv->opriv,
 				       hal_dev_ctx->lock_rx,
 				       &flags);
+out:
 	return status;
 }
 
@@ -1671,7 +1828,10 @@ nrf_wifi_hal_init(struct nrf_wifi_osal_priv *opriv,
 		  struct nrf_wifi_hal_cfg_params *cfg_params,
 		  enum nrf_wifi_status (*intr_callbk_fn)(void *dev_ctx,
 							 void *event_data,
-							 unsigned int len))
+							 unsigned int len),
+		  enum nrf_wifi_status (*rpu_recovery_callbk_fn)(void *mac_ctx,
+							     void *event_data,
+							     unsigned int len))
 {
 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
 	struct nrf_wifi_hal_priv *hpriv = NULL;
@@ -1695,6 +1855,7 @@ nrf_wifi_hal_init(struct nrf_wifi_osal_priv *opriv,
 			      sizeof(hpriv->cfg_params));
 
 	hpriv->intr_callbk_fn = intr_callbk_fn;
+	hpriv->rpu_recovery_callbk_fn = rpu_recovery_callbk_fn;
 
 	status = pal_rpu_addr_offset_get(opriv,
 					 RPU_ADDR_PKTRAM_START,
diff --git a/nrf_wifi/hw_if/hal/src/hal_interrupt.c b/nrf_wifi/hw_if/hal/src/hal_interrupt.c
index 91771a5b0e..22419b7cd9 100644
--- a/nrf_wifi/hw_if/hal/src/hal_interrupt.c
+++ b/nrf_wifi/hw_if/hal/src/hal_interrupt.c
@@ -158,11 +158,10 @@ static bool hal_rpu_irq_wdog_chk(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx)
 static enum nrf_wifi_status hal_rpu_irq_wdog_ack(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx)
 {
 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
-	unsigned int val = 0;
 
 	status = hal_rpu_reg_write(hal_dev_ctx,
-				   RPU_REG_MIPS_MCU_TIMER_CONTROL,
-				   val);
+				   RPU_REG_MIPS_MCU_UCCP_INT_CLEAR,
+				   1 << RPU_REG_BIT_MIPS_WATCHDOG_INT_CLEAR);
 
 	if (status != NRF_WIFI_STATUS_SUCCESS) {
 		nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv,
@@ -176,6 +175,24 @@ static enum nrf_wifi_status hal_rpu_irq_wdog_ack(struct nrf_wifi_hal_dev_ctx *ha
 
 }
 
+static enum nrf_wifi_status hal_rpu_irq_wdog_rearm(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx)
+{
+	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
+
+	status = hal_rpu_reg_write(hal_dev_ctx,
+				  RPU_REG_MIPS_MCU_TIMER,
+				  RPU_REG_MIPS_MCU_TIMER_RESET_VAL);
+
+	if (status != NRF_WIFI_STATUS_SUCCESS) {
+		nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv,
+				      "%s: Rearming watchdog interrupt failed",
+				      __func__);
+		goto out;
+	}
+out:
+	return status;
+}
+
 
 static enum nrf_wifi_status hal_rpu_event_free(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx,
 					       unsigned int event_addr)
@@ -388,8 +405,8 @@ static enum nrf_wifi_status hal_rpu_event_get(struct nrf_wifi_hal_dev_ctx *hal_d
 
 		if (!event) {
 			nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv,
-					      "%s: Unable to alloc HAL msg for event",
-					      __func__);
+					      "%s: Unable to alloc HAL msg for event, len %d\n",
+					      __func__, hal_dev_ctx->event_data_len);
 			nrf_wifi_osal_mem_free(hal_dev_ctx->hpriv->opriv,
 					       hal_dev_ctx->event_data);
 			hal_dev_ctx->event_data = NULL;
@@ -480,12 +497,90 @@ static unsigned int hal_rpu_event_get_all(struct nrf_wifi_hal_dev_ctx *hal_dev_c
 	return num_events;
 }
 
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY
+static inline bool is_rpu_recovery_needed(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx)
+{
+	unsigned int rpu_sleep_opp_diff_ms = nrf_wifi_osal_time_elapsed_ms(
+		hal_dev_ctx->hpriv->opriv,
+		hal_dev_ctx->last_rpu_sleep_opp_time_ms);
+
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY_DEBUG
+	nrf_wifi_osal_log_info(hal_dev_ctx->hpriv->opriv,
+			      "RPU sleep opp diff: %d ms, last RPU sleep opp time: %lu",
+			      rpu_sleep_opp_diff_ms,
+			      hal_dev_ctx->last_rpu_sleep_opp_time_ms);
+#else
+	nrf_wifi_osal_log_dbg(hal_dev_ctx->hpriv->opriv,
+			      "RPU sleep opp diff: %d ms, last RPU sleep opp time: %lu",
+			      rpu_sleep_opp_diff_ms,
+			      hal_dev_ctx->last_rpu_sleep_opp_time_ms);
+#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY_DEBUG */
+
+	if (rpu_sleep_opp_diff_ms >= CONFIG_NRF_WIFI_RPU_RECOVERY_PS_ACTIVE_TIMEOUT_MS) {
+		return false;
+	}
+
+	return true;
+}
+#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */
 
-enum nrf_wifi_status hal_rpu_irq_process(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx)
+static enum nrf_wifi_status hal_rpu_process_wdog(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx,
+						  bool *do_rpu_recovery)
 {
-	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
-	unsigned int num_events = 0;
+	enum nrf_wifi_status nrf_wifi_status = NRF_WIFI_STATUS_FAIL;
+	bool rpu_recovery = false;
+
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY_DEBUG
+	nrf_wifi_osal_log_info(hal_dev_ctx->hpriv->opriv,
+			      "Processing watchdog interrupt");
+#else
+	nrf_wifi_osal_log_dbg(hal_dev_ctx->hpriv->opriv,
+			      "Processing watchdog interrupt");
+#endif
+
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY
+	/* Check if host has asserted WAKEUP_NOW or if the RPU has been in
+	 * PS_ACTIVE state for more than the timeout period
+	 */
+	if (!is_rpu_recovery_needed(hal_dev_ctx)) {
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY_DEBUG
+		nrf_wifi_osal_log_info(hal_dev_ctx->hpriv->opriv,
+				      "Ignore watchdog interrupt, RPU recovery not needed");
+#else
+		nrf_wifi_osal_log_dbg(hal_dev_ctx->hpriv->opriv,
+				      "Ignore watchdog interrupt, RPU recovery not needed");
+#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY_DEBUG */
+		goto out;
+	}
+
+	rpu_recovery = true;
+#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */
+
+	if (!rpu_recovery) {
+		hal_rpu_irq_wdog_rearm(hal_dev_ctx);
+		goto out;
+	}
 
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY
+#ifdef CONFIG_NRF_WIFI_RPU_RECOVERY_DEBUG
+	nrf_wifi_osal_log_info(hal_dev_ctx->hpriv->opriv,
+			      "RPU recovery needed");
+#else
+	nrf_wifi_osal_log_dbg(hal_dev_ctx->hpriv->opriv,
+			      "RPU recovery needed");
+#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY_DEBUG */
+#endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */
+out:
+	nrf_wifi_status = NRF_WIFI_STATUS_SUCCESS;
+	*do_rpu_recovery = rpu_recovery;
+
+	return nrf_wifi_status;
+}
+
+enum nrf_wifi_status hal_rpu_irq_process(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx,
+		bool *do_rpu_recovery)
+{
+	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
 
 	/* Get all the events in the queue. It is possible that there are no
 	 * events in the queue. This is a valid scenario as per our present
@@ -498,29 +593,29 @@ enum nrf_wifi_status hal_rpu_irq_process(struct nrf_wifi_hal_dev_ctx *hal_dev_ct
 	 * the interrupt source. This will be a problem in shared interrupt
 	 * scenarios and has to be taken care by the SOC designers.
 	 */
-	num_events = hal_rpu_event_get_all(hal_dev_ctx);
+	(void)hal_rpu_event_get_all(hal_dev_ctx);
 
-	/* If we received an interrupt without any associated event(s) it is a
-	 * likely indication that the RPU is stuck and this interrupt has been
-	 * raised by the watchdog
+	/* Check the if this interrupt has been raised by the
+	 * RPU watchdog
 	 */
-	if (!num_events) {
-		/* Check the if this interrupt has been raised by the
-		 * RPU watchdog
-		 */
-		if (hal_rpu_irq_wdog_chk(hal_dev_ctx)) {
-			/* TODO: Perform RPU recovery */
-			nrf_wifi_osal_log_dbg(hal_dev_ctx->hpriv->opriv,
-					      "Received watchdog interrupt");
+	if (hal_rpu_irq_wdog_chk(hal_dev_ctx)) {
+		nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv,
+						"Received watchdog interrupt");
 
-			status = hal_rpu_irq_wdog_ack(hal_dev_ctx);
+		status = hal_rpu_process_wdog(hal_dev_ctx, do_rpu_recovery);
+		if (status == NRF_WIFI_STATUS_FAIL) {
+			nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv,
+							"%s: hal_rpu_process_wdog failed",
+							__func__);
+			goto out;
+		}
 
-			if (status == NRF_WIFI_STATUS_FAIL) {
-				nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv,
-						      "%s: hal_rpu_irq_wdog_ack failed",
-						      __func__);
-				goto out;
-			}
+		status = hal_rpu_irq_wdog_ack(hal_dev_ctx);
+		if (status == NRF_WIFI_STATUS_FAIL) {
+			nrf_wifi_osal_log_err(hal_dev_ctx->hpriv->opriv,
+							"%s: hal_rpu_irq_wdog_ack failed",
+							__func__);
+			goto out;
 		}
 	}
 
diff --git a/nrf_wifi/os_if/inc/osal_api.h b/nrf_wifi/os_if/inc/osal_api.h
index 1b2b447c5c..61b837948a 100644
--- a/nrf_wifi/os_if/inc/osal_api.h
+++ b/nrf_wifi/os_if/inc/osal_api.h
@@ -884,7 +884,29 @@ unsigned long nrf_wifi_osal_time_get_curr_us(struct nrf_wifi_osal_priv *opriv);
 unsigned int nrf_wifi_osal_time_elapsed_us(struct nrf_wifi_osal_priv *opriv,
 					    unsigned long start_time_us);
 
+/**
+ * nrf_wifi_osal_time_get_curr_ms() - Get current system uptime in milliseconds.
+ * @opriv: Pointer to the OSAL context returned by the @nrf_wifi_osal_init API.
+ *
+ * Gets the current system uptime in milliseconds.
+ *
+ * Return: System uptime in milliseconds.
+ */
+unsigned long nrf_wifi_osal_time_get_curr_ms(struct nrf_wifi_osal_priv *opriv);
 
+/**
+ * nrf_wifi_osal_time_elapsed_ms() - Get elapsed time in milliseconds
+ * @opriv: Pointer to the OSAL context returned by the @nrf_wifi_osal_init API.
+ * @start_time_ms: The timestamp in milliseconds from which elapsed
+ *			   time is to be measured.
+ *
+ * Returns the time elapsed in milliseconds since some
+ * time instant (@start_time_ms).
+ *
+ * Return: Elapsed time in milliseconds.
+ */
+unsigned int nrf_wifi_osal_time_elapsed_ms(struct nrf_wifi_osal_priv *opriv,
+					    unsigned long start_time_ms);
 
 /**
  * nrf_wifi_osal_bus_pcie_init() - Initialize a PCIe driver.
diff --git a/nrf_wifi/os_if/inc/osal_ops.h b/nrf_wifi/os_if/inc/osal_ops.h
index 63186ed785..a29d525f8d 100644
--- a/nrf_wifi/os_if/inc/osal_ops.h
+++ b/nrf_wifi/os_if/inc/osal_ops.h
@@ -258,6 +258,8 @@ struct nrf_wifi_osal_ops {
 	int (*delay_us)(int usecs);
 	unsigned long (*time_get_curr_us)(void);
 	unsigned int (*time_elapsed_us)(unsigned long start_time_us);
+	unsigned long (*time_get_curr_ms)(void);
+	unsigned int (*time_elapsed_ms)(unsigned long start_time_us);
 
 	void *(*bus_pcie_init)(const char *dev_name,
 			       unsigned int vendor_id,
diff --git a/nrf_wifi/os_if/src/osal.c b/nrf_wifi/os_if/src/osal.c
index 5abeae7a00..cf650daed2 100644
--- a/nrf_wifi/os_if/src/osal.c
+++ b/nrf_wifi/os_if/src/osal.c
@@ -508,6 +508,16 @@ unsigned int nrf_wifi_osal_time_elapsed_us(struct nrf_wifi_osal_priv *opriv,
 	return opriv->ops->time_elapsed_us(start_time_us);
 }
 
+unsigned long nrf_wifi_osal_time_get_curr_ms(struct nrf_wifi_osal_priv *opriv)
+{
+	return opriv->ops->time_get_curr_ms();
+}
+
+unsigned int nrf_wifi_osal_time_elapsed_ms(struct nrf_wifi_osal_priv *opriv,
+					   unsigned long start_time_ms)
+{
+	return opriv->ops->time_elapsed_ms(start_time_ms);
+}
 
 void *nrf_wifi_osal_bus_pcie_init(struct nrf_wifi_osal_priv *opriv,
 				  const char *dev_name,