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 _set_workitem(&(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 _cancel_timer_ex(&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 _set_workitem(&(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 u8 cpwm
= pwrpriv
->cpwm
;
160 if (pwrpriv
->cpwm
!= pwrpriv
->rpwm
) {
161 _enter_pwrlock(&pwrpriv
->lock
);
162 cpwm
= r8712_read8(padapter
, SDIO_HCPWM
);
163 pwrpriv
->rpwm_retry
= 1;
164 r8712_set_rpwm(padapter
, pwrpriv
->rpwm
);
169 static void rpwm_check_handler (void *FunctionContext
)
171 struct _adapter
*adapter
= (struct _adapter
*)FunctionContext
;
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_workitem(&(pwrctrlpriv
->SetPSModeWorkItem
),
188 SetPSModeWorkItemCallback
, padapter
);
189 _init_workitem(&(pwrctrlpriv
->rpwm_workitem
),
190 rpwm_workitem_callback
, padapter
);
191 _init_timer(&(pwrctrlpriv
->rpwm_check_timer
),
192 padapter
->pnetdev
, rpwm_check_handler
, (u8
*)padapter
);
196 Caller: r8712_cmd_thread
198 Check if the fw_pwrstate is okay for issuing cmd.
199 If not (cpwm should be is less than P2 state), then the sub-routine
200 will raise the cpwm to be greater than or equal to P2.
202 Calling Context: Passive
206 _SUCCESS: r8712_cmd_thread can issue cmds to firmware afterwards.
207 _FAIL: r8712_cmd_thread can not do anything.
209 sint
r8712_register_cmd_alive(struct _adapter
*padapter
)
212 struct pwrctrl_priv
*pwrctrl
= &padapter
->pwrctrlpriv
;
214 _enter_pwrlock(&pwrctrl
->lock
);
215 register_task_alive(pwrctrl
, CMD_ALIVE
);
216 if (pwrctrl
->cpwm
< PS_STATE_S2
) {
217 r8712_set_rpwm(padapter
, PS_STATE_S3
);
229 Then driver shall call this fun. to power down firmware again.
232 void r8712_unregister_cmd_alive(struct _adapter
*padapter
)
234 struct pwrctrl_priv
*pwrctrl
= &padapter
->pwrctrlpriv
;
236 _enter_pwrlock(&pwrctrl
->lock
);
237 unregister_task_alive(pwrctrl
, CMD_ALIVE
);
238 if ((pwrctrl
->cpwm
> PS_STATE_S2
) &&
239 (pwrctrl
->pwr_mode
> PS_MODE_ACTIVE
)) {
240 if ((pwrctrl
->alives
== 0) &&
241 (check_fwstate(&padapter
->mlmepriv
,
242 _FW_UNDER_LINKING
) != true)) {
243 r8712_set_rpwm(padapter
, PS_STATE_S0
);