gpio: rcar: Fix runtime PM imbalance on error
[linux/fpc-iii.git] / drivers / net / wireless / realtek / rtw88 / ps.c
blob7a189a9926fef7e2c4eca3e8de9285f88e701a7b
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright(c) 2018-2019 Realtek Corporation
3 */
5 #include "main.h"
6 #include "reg.h"
7 #include "fw.h"
8 #include "ps.h"
9 #include "mac.h"
10 #include "coex.h"
11 #include "debug.h"
13 static int rtw_ips_pwr_up(struct rtw_dev *rtwdev)
15 int ret;
17 ret = rtw_core_start(rtwdev);
18 if (ret)
19 rtw_err(rtwdev, "leave idle state failed\n");
21 rtw_set_channel(rtwdev);
22 clear_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags);
24 return ret;
27 int rtw_enter_ips(struct rtw_dev *rtwdev)
29 set_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags);
31 rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER);
33 rtw_core_stop(rtwdev);
34 rtw_hci_link_ps(rtwdev, true);
36 return 0;
39 static void rtw_restore_port_cfg_iter(void *data, u8 *mac,
40 struct ieee80211_vif *vif)
42 struct rtw_dev *rtwdev = data;
43 struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
44 u32 config = ~0;
46 rtw_vif_port_config(rtwdev, rtwvif, config);
49 int rtw_leave_ips(struct rtw_dev *rtwdev)
51 int ret;
53 rtw_hci_link_ps(rtwdev, false);
55 ret = rtw_ips_pwr_up(rtwdev);
56 if (ret) {
57 rtw_err(rtwdev, "failed to leave ips state\n");
58 return ret;
61 rtw_iterate_vifs_atomic(rtwdev, rtw_restore_port_cfg_iter, rtwdev);
63 rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE);
65 return 0;
68 void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter)
70 u8 request, confirm, polling;
71 u8 polling_cnt;
72 u8 retry_cnt = 0;
74 for (retry_cnt = 0; retry_cnt < 3; retry_cnt++) {
75 request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr);
76 confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
78 /* toggle to request power mode, others remain 0 */
79 request ^= request | BIT_RPWM_TOGGLE;
80 if (!enter) {
81 request |= POWER_MODE_ACK;
82 } else {
83 request |= POWER_MODE_LCLK;
84 if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG)
85 request |= POWER_MODE_PG;
88 rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request);
90 if (enter)
91 return;
93 /* check confirm power mode has left power save state */
94 for (polling_cnt = 0; polling_cnt < 50; polling_cnt++) {
95 polling = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
96 if ((polling ^ confirm) & BIT_RPWM_TOGGLE)
97 return;
98 udelay(100);
101 /* in case of fw/hw missed the request, retry */
102 rtw_warn(rtwdev, "failed to leave deep PS, retry=%d\n",
103 retry_cnt);
106 /* Hit here means that driver failed to change hardware power mode to
107 * active state after retry 3 times. If the power state is locked at
108 * Deep sleep, most of the hardware circuits is not working, even
109 * register read/write. It should be treated as fatal error and
110 * requires an entire analysis about the firmware/hardware
112 WARN(1, "Hardware power state locked\n");
114 EXPORT_SYMBOL(rtw_power_mode_change);
116 static void __rtw_leave_lps_deep(struct rtw_dev *rtwdev)
118 rtw_hci_deep_ps(rtwdev, false);
121 static void rtw_fw_leave_lps_state_check(struct rtw_dev *rtwdev)
123 int i;
125 /* Driver needs to wait for firmware to leave LPS state
126 * successfully. Firmware will send null packet to inform AP,
127 * and see if AP sends an ACK back, then firmware will restore
128 * the REG_TCR register.
130 * If driver does not wait for firmware, null packet with
131 * PS bit could be sent due to incorrect REG_TCR setting.
133 * In our test, 100ms should be enough for firmware to finish
134 * the flow. If REG_TCR Register is still incorrect after 100ms,
135 * just modify it directly, and throw a warn message.
137 for (i = 0 ; i < LEAVE_LPS_TRY_CNT; i++) {
138 if (rtw_read32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN) == 0)
139 return;
140 msleep(20);
143 rtw_write32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN, 0);
144 rtw_warn(rtwdev, "firmware failed to restore hardware setting\n");
147 static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
149 struct rtw_lps_conf *conf = &rtwdev->lps_conf;
151 conf->state = RTW_ALL_ON;
152 conf->awake_interval = 1;
153 conf->rlbm = 0;
154 conf->smart_ps = 0;
156 rtw_hci_link_ps(rtwdev, false);
157 rtw_fw_set_pwr_mode(rtwdev);
158 rtw_fw_leave_lps_state_check(rtwdev);
160 clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
162 rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE);
165 static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev)
167 if (rtwdev->lps_conf.deep_mode == LPS_DEEP_MODE_NONE)
168 return;
170 if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) {
171 rtw_dbg(rtwdev, RTW_DBG_PS,
172 "Should enter LPS before entering deep PS\n");
173 return;
176 if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG)
177 rtw_fw_set_pg_info(rtwdev);
179 rtw_hci_deep_ps(rtwdev, true);
182 static void rtw_enter_lps_core(struct rtw_dev *rtwdev)
184 struct rtw_lps_conf *conf = &rtwdev->lps_conf;
186 conf->state = RTW_RF_OFF;
187 conf->awake_interval = 1;
188 conf->rlbm = 1;
189 conf->smart_ps = 2;
191 rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE);
193 rtw_fw_set_pwr_mode(rtwdev);
194 rtw_hci_link_ps(rtwdev, true);
196 set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
199 static void __rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id)
201 struct rtw_lps_conf *conf = &rtwdev->lps_conf;
203 if (test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags))
204 return;
206 conf->mode = RTW_MODE_LPS;
207 conf->port_id = port_id;
209 rtw_enter_lps_core(rtwdev);
212 static void __rtw_leave_lps(struct rtw_dev *rtwdev)
214 struct rtw_lps_conf *conf = &rtwdev->lps_conf;
216 if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) {
217 rtw_dbg(rtwdev, RTW_DBG_PS,
218 "Should leave deep PS before leaving LPS\n");
219 __rtw_leave_lps_deep(rtwdev);
222 if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags))
223 return;
225 conf->mode = RTW_MODE_ACTIVE;
227 rtw_leave_lps_core(rtwdev);
230 void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id)
232 lockdep_assert_held(&rtwdev->mutex);
234 if (rtwdev->coex.stat.wl_force_lps_ctrl)
235 return;
237 __rtw_enter_lps(rtwdev, port_id);
238 __rtw_enter_lps_deep(rtwdev);
241 void rtw_leave_lps(struct rtw_dev *rtwdev)
243 lockdep_assert_held(&rtwdev->mutex);
245 __rtw_leave_lps_deep(rtwdev);
246 __rtw_leave_lps(rtwdev);
249 void rtw_leave_lps_deep(struct rtw_dev *rtwdev)
251 lockdep_assert_held(&rtwdev->mutex);
253 __rtw_leave_lps_deep(rtwdev);