#include "mac.h"
#include "coex.h"
#include "debug.h"
+#include "reg.h"
static int rtw_ips_pwr_up(struct rtw_dev *rtwdev)
{
rtw_hci_deep_ps(rtwdev, false);
}
+static void rtw_fw_leave_lps_state_check(struct rtw_dev *rtwdev)
+{
+ int i;
+
+ /* Driver needs to wait for firmware to leave LPS state
+ * successfully. Firmware will send null packet to inform AP,
+ * and see if AP sends an ACK back, then firmware will restore
+ * the REG_TCR register.
+ *
+ * If driver does not wait for firmware, null packet with
+ * PS bit could be sent due to incorrect REG_TCR setting.
+ *
+ * In our test, 100ms should be enough for firmware to finish
+ * the flow. If REG_TCR Register is still incorrect after 100ms,
+ * just modify it directly, and throw a warn message.
+ */
+ for (i = 0 ; i < LEAVE_LPS_TRY_CNT; i++) {
+ if (rtw_read32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN) == 0)
+ return;
+ msleep(20);
+ }
+
+ rtw_write32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN, 0);
+ rtw_warn(rtwdev, "firmware failed to restore hardware setting\n");
+}
+
static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
{
struct rtw_lps_conf *conf = &rtwdev->lps_conf;
conf->smart_ps = 0;
rtw_fw_set_pwr_mode(rtwdev);
+ rtw_fw_leave_lps_state_check(rtwdev);
+
clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE);