1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright(c) 2018-2019 Realtek Corporation
13 static int rtw_ips_pwr_up(struct rtw_dev *rtwdev)
17 ret = rtw_core_start(rtwdev);
19 rtw_err(rtwdev, "leave idle state failed\n");
21 rtw_set_channel(rtwdev);
22 clear_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags);
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);
38 static void rtw_restore_port_cfg_iter(void *data, u8 *mac,
39 struct ieee80211_vif *vif)
41 struct rtw_dev *rtwdev = data;
42 struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
45 rtw_vif_port_config(rtwdev, rtwvif, config);
48 int rtw_leave_ips(struct rtw_dev *rtwdev)
52 ret = rtw_ips_pwr_up(rtwdev);
54 rtw_err(rtwdev, "failed to leave ips state\n");
58 rtw_iterate_vifs_atomic(rtwdev, rtw_restore_port_cfg_iter, rtwdev);
60 rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE);
65 void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter)
67 u8 request, confirm, polling;
72 request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr);
73 confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
75 /* toggle to request power mode, others remain 0 */
76 request ^= request | BIT_RPWM_TOGGLE;
78 request |= POWER_MODE_ACK;
80 request |= POWER_MODE_LCLK;
82 rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request);
84 /* check confirm power mode has left power save state */
86 for (polling_cnt = 0; polling_cnt < 3; polling_cnt++) {
87 polling = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
88 if ((polling ^ confirm) & BIT_RPWM_TOGGLE)
93 /* in case of fw/hw missed the request, retry 3 times */
95 rtw_warn(rtwdev, "failed to leave deep PS, retry=%d\n",
101 /* Hit here means that driver failed to change hardware
102 * power mode to active state after retry 3 times.
103 * If the power state is locked at Deep sleep, most of
104 * the hardware circuits is not working, even register
105 * read/write. It should be treated as fatal error and
106 * requires an entire analysis about the firmware/hardware
108 WARN_ON("Hardware power state locked\n");
111 EXPORT_SYMBOL(rtw_power_mode_change);
113 static void __rtw_leave_lps_deep(struct rtw_dev *rtwdev)
115 rtw_hci_deep_ps(rtwdev, false);
118 static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
120 struct rtw_lps_conf *conf = &rtwdev->lps_conf;
122 conf->state = RTW_ALL_ON;
123 conf->awake_interval = 1;
127 rtw_fw_set_pwr_mode(rtwdev);
128 clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
130 rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE);
133 static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev)
135 if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) {
136 rtw_dbg(rtwdev, RTW_DBG_PS,
137 "Should enter LPS before entering deep PS\n");
141 rtw_hci_deep_ps(rtwdev, true);
144 static void rtw_enter_lps_core(struct rtw_dev *rtwdev)
146 struct rtw_lps_conf *conf = &rtwdev->lps_conf;
148 conf->state = RTW_RF_OFF;
149 conf->awake_interval = 1;
153 rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE);
155 rtw_fw_set_pwr_mode(rtwdev);
156 set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
159 static void __rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id)
161 struct rtw_lps_conf *conf = &rtwdev->lps_conf;
163 if (test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags))
166 conf->mode = RTW_MODE_LPS;
167 conf->port_id = port_id;
169 rtw_enter_lps_core(rtwdev);
172 static void __rtw_leave_lps(struct rtw_dev *rtwdev)
174 struct rtw_lps_conf *conf = &rtwdev->lps_conf;
176 if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) {
177 rtw_dbg(rtwdev, RTW_DBG_PS,
178 "Should leave deep PS before leaving LPS\n");
179 __rtw_leave_lps_deep(rtwdev);
182 if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags))
185 conf->mode = RTW_MODE_ACTIVE;
187 rtw_leave_lps_core(rtwdev);
190 void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id)
192 lockdep_assert_held(&rtwdev->mutex);
194 if (rtwdev->coex.stat.wl_force_lps_ctrl)
197 __rtw_enter_lps(rtwdev, port_id);
198 __rtw_enter_lps_deep(rtwdev);
201 void rtw_leave_lps(struct rtw_dev *rtwdev)
203 lockdep_assert_held(&rtwdev->mutex);
205 __rtw_leave_lps_deep(rtwdev);
206 __rtw_leave_lps(rtwdev);
209 void rtw_leave_lps_deep(struct rtw_dev *rtwdev)
211 lockdep_assert_held(&rtwdev->mutex);
213 __rtw_leave_lps_deep(rtwdev);