1 /******************************************************************************
4 * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
5 * Linux device driver for RTL8192SU
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
20 * Modifications for inclusion into the Linux staging tree are
21 * Copyright(c) 2010 Larry Finger. All rights reserved.
23 * Contact information:
24 * WLAN FAE <wlanfae@realtek.com>
25 * Larry Finger <Larry.Finger@lwfinger.net>
27 ******************************************************************************/
29 #define _RTL871X_PWRCTRL_C_
31 #include "osdep_service.h"
32 #include "drv_types.h"
33 #include "osdep_intf.h"
35 #define RTL8712_SDIO_LOCAL_BASE 0X10100000
36 #define SDIO_HCPWM (RTL8712_SDIO_LOCAL_BASE + 0x0081)
38 void r8712_set_rpwm(struct _adapter
*padapter
, u8 val8
)
41 struct pwrctrl_priv
*pwrpriv
= &padapter
->pwrctrlpriv
;
43 if (pwrpriv
->rpwm
== val8
) {
44 if (pwrpriv
->rpwm_retry
== 0)
47 if ((padapter
->bDriverStopped
== true) ||
48 (padapter
->bSurpriseRemoved
== true))
50 rpwm
= val8
| pwrpriv
->tog
;
55 case PS_STATE_S2
:/* only for USB normal powersave mode use,
56 * temp mark some code. */
64 pwrpriv
->rpwm_retry
= 0;
66 r8712_write8(padapter
, 0x1025FE58, rpwm
);
70 void r8712_set_ps_mode(struct _adapter
*padapter
, uint ps_mode
, uint smart_ps
)
72 struct pwrctrl_priv
*pwrpriv
= &padapter
->pwrctrlpriv
;
74 if (ps_mode
> PM_Card_Disable
)
76 /* if driver is in active state, we dont need set smart_ps.*/
77 if (ps_mode
== PS_MODE_ACTIVE
)
79 if ((pwrpriv
->pwr_mode
!= ps_mode
) || (pwrpriv
->smart_ps
!= smart_ps
)) {
80 if (pwrpriv
->pwr_mode
== PS_MODE_ACTIVE
)
81 pwrpriv
->bSleep
= true;
83 pwrpriv
->bSleep
= false;
84 pwrpriv
->pwr_mode
= ps_mode
;
85 pwrpriv
->smart_ps
= smart_ps
;
86 schedule_work(&pwrpriv
->SetPSModeWorkItem
);
91 * Caller:ISR handler...
93 * This will be called when CPWM interrupt is up.
95 * using to update cpwn of drv; and drv will make a decision to up or
98 void r8712_cpwm_int_hdl(struct _adapter
*padapter
,
99 struct reportpwrstate_parm
*preportpwrstate
)
101 struct pwrctrl_priv
*pwrpriv
= &(padapter
->pwrctrlpriv
);
102 struct cmd_priv
*pcmdpriv
= &(padapter
->cmdpriv
);
104 if (pwrpriv
->cpwm_tog
== ((preportpwrstate
->state
) & 0x80))
106 del_timer(&padapter
->pwrctrlpriv
.rpwm_check_timer
);
107 _enter_pwrlock(&pwrpriv
->lock
);
108 pwrpriv
->cpwm
= (preportpwrstate
->state
) & 0xf;
109 if (pwrpriv
->cpwm
>= PS_STATE_S2
) {
110 if (pwrpriv
->alives
& CMD_ALIVE
)
111 up(&(pcmdpriv
->cmd_queue_sema
));
113 pwrpriv
->cpwm_tog
= (preportpwrstate
->state
) & 0x80;
117 static inline void register_task_alive(struct pwrctrl_priv
*pwrctrl
, uint tag
)
119 pwrctrl
->alives
|= tag
;
122 static inline void unregister_task_alive(struct pwrctrl_priv
*pwrctrl
, uint tag
)
124 if (pwrctrl
->alives
& tag
)
125 pwrctrl
->alives
^= tag
;
128 static void _rpwm_check_handler (struct _adapter
*padapter
)
130 struct pwrctrl_priv
*pwrpriv
= &padapter
->pwrctrlpriv
;
132 if (padapter
->bDriverStopped
== true ||
133 padapter
->bSurpriseRemoved
== true)
135 if (pwrpriv
->cpwm
!= pwrpriv
->rpwm
)
136 schedule_work(&pwrpriv
->rpwm_workitem
);
139 static void SetPSModeWorkItemCallback(struct work_struct
*work
)
141 struct pwrctrl_priv
*pwrpriv
= container_of(work
,
142 struct pwrctrl_priv
, SetPSModeWorkItem
);
143 struct _adapter
*padapter
= container_of(pwrpriv
,
144 struct _adapter
, pwrctrlpriv
);
145 if (!pwrpriv
->bSleep
) {
146 _enter_pwrlock(&pwrpriv
->lock
);
147 if (pwrpriv
->pwr_mode
== PS_MODE_ACTIVE
)
148 r8712_set_rpwm(padapter
, PS_STATE_S4
);
153 static void rpwm_workitem_callback(struct work_struct
*work
)
155 struct pwrctrl_priv
*pwrpriv
= container_of(work
,
156 struct pwrctrl_priv
, rpwm_workitem
);
157 struct _adapter
*padapter
= container_of(pwrpriv
,
158 struct _adapter
, pwrctrlpriv
);
159 if (pwrpriv
->cpwm
!= pwrpriv
->rpwm
) {
160 _enter_pwrlock(&pwrpriv
->lock
);
161 r8712_read8(padapter
, SDIO_HCPWM
);
162 pwrpriv
->rpwm_retry
= 1;
163 r8712_set_rpwm(padapter
, pwrpriv
->rpwm
);
168 static void rpwm_check_handler (unsigned long data
)
170 struct _adapter
*adapter
= (struct _adapter
*)data
;
172 _rpwm_check_handler(adapter
);
175 void r8712_init_pwrctrl_priv(struct _adapter
*padapter
)
177 struct pwrctrl_priv
*pwrctrlpriv
= &padapter
->pwrctrlpriv
;
179 memset((unsigned char *)pwrctrlpriv
, 0, sizeof(struct pwrctrl_priv
));
180 sema_init(&pwrctrlpriv
->lock
, 1);
181 pwrctrlpriv
->cpwm
= PS_STATE_S4
;
182 pwrctrlpriv
->pwr_mode
= PS_MODE_ACTIVE
;
183 pwrctrlpriv
->smart_ps
= 0;
184 pwrctrlpriv
->tog
= 0x80;
185 /* clear RPWM to ensure driver and fw back to initial state. */
186 r8712_write8(padapter
, 0x1025FE58, 0);
187 INIT_WORK(&pwrctrlpriv
->SetPSModeWorkItem
, SetPSModeWorkItemCallback
);
188 INIT_WORK(&pwrctrlpriv
->rpwm_workitem
, rpwm_workitem_callback
);
189 setup_timer(&pwrctrlpriv
->rpwm_check_timer
, rpwm_check_handler
,
190 (unsigned long)padapter
);
194 Caller: r8712_cmd_thread
196 Check if the fw_pwrstate is okay for issuing cmd.
197 If not (cpwm should be is less than P2 state), then the sub-routine
198 will raise the cpwm to be greater than or equal to P2.
200 Calling Context: Passive
204 _SUCCESS: r8712_cmd_thread can issue cmds to firmware afterwards.
205 _FAIL: r8712_cmd_thread can not do anything.
207 sint
r8712_register_cmd_alive(struct _adapter
*padapter
)
210 struct pwrctrl_priv
*pwrctrl
= &padapter
->pwrctrlpriv
;
212 _enter_pwrlock(&pwrctrl
->lock
);
213 register_task_alive(pwrctrl
, CMD_ALIVE
);
214 if (pwrctrl
->cpwm
< PS_STATE_S2
) {
215 r8712_set_rpwm(padapter
, PS_STATE_S3
);
227 Then driver shall call this fun. to power down firmware again.
230 void r8712_unregister_cmd_alive(struct _adapter
*padapter
)
232 struct pwrctrl_priv
*pwrctrl
= &padapter
->pwrctrlpriv
;
234 _enter_pwrlock(&pwrctrl
->lock
);
235 unregister_task_alive(pwrctrl
, CMD_ALIVE
);
236 if ((pwrctrl
->cpwm
> PS_STATE_S2
) &&
237 (pwrctrl
->pwr_mode
> PS_MODE_ACTIVE
)) {
238 if ((pwrctrl
->alives
== 0) &&
239 (check_fwstate(&padapter
->mlmepriv
,
240 _FW_UNDER_LINKING
) != true)) {
241 r8712_set_rpwm(padapter
, PS_STATE_S0
);