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
);
103 struct xmit_priv
*pxmitpriv
= &(padapter
->xmitpriv
);
105 if (pwrpriv
->cpwm_tog
== ((preportpwrstate
->state
) & 0x80))
107 _cancel_timer_ex(&padapter
->pwrctrlpriv
. rpwm_check_timer
);
108 _enter_pwrlock(&pwrpriv
->lock
);
109 pwrpriv
->cpwm
= (preportpwrstate
->state
) & 0xf;
110 if (pwrpriv
->cpwm
>= PS_STATE_S2
) {
111 if (pwrpriv
->alives
& CMD_ALIVE
)
112 up(&(pcmdpriv
->cmd_queue_sema
));
113 if (pwrpriv
->alives
& XMIT_ALIVE
)
114 up(&(pxmitpriv
->xmit_sema
));
116 pwrpriv
->cpwm_tog
= (preportpwrstate
->state
) & 0x80;
120 static inline void register_task_alive(struct pwrctrl_priv
*pwrctrl
, uint tag
)
122 pwrctrl
->alives
|= tag
;
125 static inline void unregister_task_alive(struct pwrctrl_priv
*pwrctrl
, uint tag
)
127 if (pwrctrl
->alives
& tag
)
128 pwrctrl
->alives
^= tag
;
131 static void _rpwm_check_handler (struct _adapter
*padapter
)
133 struct pwrctrl_priv
*pwrpriv
= &padapter
->pwrctrlpriv
;
135 if (padapter
->bDriverStopped
== true ||
136 padapter
->bSurpriseRemoved
== true)
138 if (pwrpriv
->cpwm
!= pwrpriv
->rpwm
)
139 _set_workitem(&(pwrpriv
->rpwm_workitem
));
142 static void SetPSModeWorkItemCallback(struct work_struct
*work
)
144 struct pwrctrl_priv
*pwrpriv
= container_of(work
,
145 struct pwrctrl_priv
, SetPSModeWorkItem
);
146 struct _adapter
*padapter
= container_of(pwrpriv
,
147 struct _adapter
, pwrctrlpriv
);
148 _enter_pwrlock(&pwrpriv
->lock
);
149 if (!pwrpriv
->bSleep
) {
150 if (pwrpriv
->pwr_mode
== PS_MODE_ACTIVE
)
151 r8712_set_rpwm(padapter
, PS_STATE_S4
);
156 static void rpwm_workitem_callback(struct work_struct
*work
)
158 struct pwrctrl_priv
*pwrpriv
= container_of(work
,
159 struct pwrctrl_priv
, rpwm_workitem
);
160 struct _adapter
*padapter
= container_of(pwrpriv
,
161 struct _adapter
, pwrctrlpriv
);
162 u8 cpwm
= pwrpriv
->cpwm
;
163 _enter_pwrlock(&pwrpriv
->lock
);
164 if (pwrpriv
->cpwm
!= pwrpriv
->rpwm
) {
165 cpwm
= r8712_read8(padapter
, SDIO_HCPWM
);
166 pwrpriv
->rpwm_retry
= 1;
167 r8712_set_rpwm(padapter
, pwrpriv
->rpwm
);
172 static void rpwm_check_handler (void *FunctionContext
)
174 struct _adapter
*adapter
= (struct _adapter
*)FunctionContext
;
175 _rpwm_check_handler(adapter
);
178 void r8712_init_pwrctrl_priv(struct _adapter
*padapter
)
180 struct pwrctrl_priv
*pwrctrlpriv
= &padapter
->pwrctrlpriv
;
182 memset((unsigned char *)pwrctrlpriv
, 0, sizeof(struct pwrctrl_priv
));
183 sema_init(&pwrctrlpriv
->lock
, 1);
184 pwrctrlpriv
->cpwm
= PS_STATE_S4
;
185 pwrctrlpriv
->pwr_mode
= PS_MODE_ACTIVE
;
186 pwrctrlpriv
->smart_ps
= 0;
187 pwrctrlpriv
->tog
= 0x80;
188 /* clear RPWM to ensure driver and fw back to initial state. */
189 r8712_write8(padapter
, 0x1025FE58, 0);
190 _init_workitem(&(pwrctrlpriv
->SetPSModeWorkItem
),
191 SetPSModeWorkItemCallback
, padapter
);
192 _init_workitem(&(pwrctrlpriv
->rpwm_workitem
),
193 rpwm_workitem_callback
, padapter
);
194 _init_timer(&(pwrctrlpriv
->rpwm_check_timer
),
195 padapter
->pnetdev
, rpwm_check_handler
, (u8
*)padapter
);
199 Caller: r8712_cmd_thread
201 Check if the fw_pwrstate is okay for issuing cmd.
202 If not (cpwm should be is less than P2 state), then the sub-routine
203 will raise the cpwm to be greater than or equal to P2.
205 Calling Context: Passive
209 _SUCCESS: r8712_cmd_thread can issue cmds to firmware afterwards.
210 _FAIL: r8712_cmd_thread can not do anything.
212 sint
r8712_register_cmd_alive(struct _adapter
*padapter
)
215 struct pwrctrl_priv
*pwrctrl
= &padapter
->pwrctrlpriv
;
217 _enter_pwrlock(&pwrctrl
->lock
);
218 register_task_alive(pwrctrl
, CMD_ALIVE
);
219 if (pwrctrl
->cpwm
< PS_STATE_S2
) {
220 r8712_set_rpwm(padapter
, PS_STATE_S3
);
232 Then driver shall call this fun. to power down firmware again.
235 void r8712_unregister_cmd_alive(struct _adapter
*padapter
)
237 struct pwrctrl_priv
*pwrctrl
= &padapter
->pwrctrlpriv
;
239 _enter_pwrlock(&pwrctrl
->lock
);
240 unregister_task_alive(pwrctrl
, CMD_ALIVE
);
241 if ((pwrctrl
->cpwm
> PS_STATE_S2
) &&
242 (pwrctrl
->pwr_mode
> PS_MODE_ACTIVE
)) {
243 if ((pwrctrl
->alives
== 0) &&
244 (check_fwstate(&padapter
->mlmepriv
,
245 _FW_UNDER_LINKING
) != true)) {
246 r8712_set_rpwm(padapter
, PS_STATE_S0
);