rtl871x_pwrctrl.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /******************************************************************************
  2. * rtl871x_pwrctrl.c
  3. *
  4. * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
  5. * Linux device driver for RTL8192SU
  6. *
  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.
  10. *
  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
  14. * more details.
  15. *
  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
  19. *
  20. * Modifications for inclusion into the Linux staging tree are
  21. * Copyright(c) 2010 Larry Finger. All rights reserved.
  22. *
  23. * Contact information:
  24. * WLAN FAE <wlanfae@realtek.com>
  25. * Larry Finger <Larry.Finger@lwfinger.net>
  26. *
  27. ******************************************************************************/
  28. #define _RTL871X_PWRCTRL_C_
  29. #include "osdep_service.h"
  30. #include "drv_types.h"
  31. #include "osdep_intf.h"
  32. #define RTL8712_SDIO_LOCAL_BASE 0X10100000
  33. #define SDIO_HCPWM (RTL8712_SDIO_LOCAL_BASE + 0x0081)
  34. void r8712_set_rpwm(struct _adapter *padapter, u8 val8)
  35. {
  36. u8 rpwm;
  37. struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
  38. if (pwrpriv->rpwm == val8) {
  39. if (pwrpriv->rpwm_retry == 0)
  40. return;
  41. }
  42. if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
  43. return;
  44. rpwm = val8 | pwrpriv->tog;
  45. switch (val8) {
  46. case PS_STATE_S1:
  47. pwrpriv->cpwm = val8;
  48. break;
  49. case PS_STATE_S2:/* only for USB normal powersave mode use,
  50. * temp mark some code. */
  51. case PS_STATE_S3:
  52. case PS_STATE_S4:
  53. pwrpriv->cpwm = val8;
  54. break;
  55. default:
  56. break;
  57. }
  58. pwrpriv->rpwm_retry = 0;
  59. pwrpriv->rpwm = val8;
  60. r8712_write8(padapter, 0x1025FE58, rpwm);
  61. pwrpriv->tog += 0x80;
  62. }
  63. void r8712_set_ps_mode(struct _adapter *padapter, uint ps_mode, uint smart_ps)
  64. {
  65. struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
  66. if (ps_mode > PM_Card_Disable)
  67. return;
  68. /* if driver is in active state, we dont need set smart_ps.*/
  69. if (ps_mode == PS_MODE_ACTIVE)
  70. smart_ps = 0;
  71. if ((pwrpriv->pwr_mode != ps_mode) || (pwrpriv->smart_ps != smart_ps)) {
  72. if (pwrpriv->pwr_mode == PS_MODE_ACTIVE)
  73. pwrpriv->bSleep = true;
  74. else
  75. pwrpriv->bSleep = false;
  76. pwrpriv->pwr_mode = ps_mode;
  77. pwrpriv->smart_ps = smart_ps;
  78. schedule_work(&pwrpriv->SetPSModeWorkItem);
  79. }
  80. }
  81. /*
  82. * Caller:ISR handler...
  83. *
  84. * This will be called when CPWM interrupt is up.
  85. *
  86. * using to update cpwn of drv; and drv will make a decision to up or
  87. * down pwr level
  88. */
  89. void r8712_cpwm_int_hdl(struct _adapter *padapter,
  90. struct reportpwrstate_parm *preportpwrstate)
  91. {
  92. struct pwrctrl_priv *pwrpriv = &(padapter->pwrctrlpriv);
  93. struct cmd_priv *pcmdpriv = &(padapter->cmdpriv);
  94. if (pwrpriv->cpwm_tog == ((preportpwrstate->state) & 0x80))
  95. return;
  96. del_timer(&padapter->pwrctrlpriv.rpwm_check_timer);
  97. _enter_pwrlock(&pwrpriv->lock);
  98. pwrpriv->cpwm = (preportpwrstate->state) & 0xf;
  99. if (pwrpriv->cpwm >= PS_STATE_S2) {
  100. if (pwrpriv->alives & CMD_ALIVE)
  101. up(&(pcmdpriv->cmd_queue_sema));
  102. }
  103. pwrpriv->cpwm_tog = (preportpwrstate->state) & 0x80;
  104. up(&pwrpriv->lock);
  105. }
  106. static inline void register_task_alive(struct pwrctrl_priv *pwrctrl, uint tag)
  107. {
  108. pwrctrl->alives |= tag;
  109. }
  110. static inline void unregister_task_alive(struct pwrctrl_priv *pwrctrl, uint tag)
  111. {
  112. if (pwrctrl->alives & tag)
  113. pwrctrl->alives ^= tag;
  114. }
  115. static void _rpwm_check_handler (struct _adapter *padapter)
  116. {
  117. struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
  118. if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
  119. return;
  120. if (pwrpriv->cpwm != pwrpriv->rpwm)
  121. schedule_work(&pwrpriv->rpwm_workitem);
  122. }
  123. static void SetPSModeWorkItemCallback(struct work_struct *work)
  124. {
  125. struct pwrctrl_priv *pwrpriv = container_of(work,
  126. struct pwrctrl_priv, SetPSModeWorkItem);
  127. struct _adapter *padapter = container_of(pwrpriv,
  128. struct _adapter, pwrctrlpriv);
  129. if (!pwrpriv->bSleep) {
  130. _enter_pwrlock(&pwrpriv->lock);
  131. if (pwrpriv->pwr_mode == PS_MODE_ACTIVE)
  132. r8712_set_rpwm(padapter, PS_STATE_S4);
  133. up(&pwrpriv->lock);
  134. }
  135. }
  136. static void rpwm_workitem_callback(struct work_struct *work)
  137. {
  138. struct pwrctrl_priv *pwrpriv = container_of(work,
  139. struct pwrctrl_priv, rpwm_workitem);
  140. struct _adapter *padapter = container_of(pwrpriv,
  141. struct _adapter, pwrctrlpriv);
  142. if (pwrpriv->cpwm != pwrpriv->rpwm) {
  143. _enter_pwrlock(&pwrpriv->lock);
  144. r8712_read8(padapter, SDIO_HCPWM);
  145. pwrpriv->rpwm_retry = 1;
  146. r8712_set_rpwm(padapter, pwrpriv->rpwm);
  147. up(&pwrpriv->lock);
  148. }
  149. }
  150. static void rpwm_check_handler (unsigned long data)
  151. {
  152. struct _adapter *adapter = (struct _adapter *)data;
  153. _rpwm_check_handler(adapter);
  154. }
  155. void r8712_init_pwrctrl_priv(struct _adapter *padapter)
  156. {
  157. struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
  158. memset((unsigned char *)pwrctrlpriv, 0, sizeof(struct pwrctrl_priv));
  159. sema_init(&pwrctrlpriv->lock, 1);
  160. pwrctrlpriv->cpwm = PS_STATE_S4;
  161. pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE;
  162. pwrctrlpriv->smart_ps = 0;
  163. pwrctrlpriv->tog = 0x80;
  164. /* clear RPWM to ensure driver and fw back to initial state. */
  165. r8712_write8(padapter, 0x1025FE58, 0);
  166. INIT_WORK(&pwrctrlpriv->SetPSModeWorkItem, SetPSModeWorkItemCallback);
  167. INIT_WORK(&pwrctrlpriv->rpwm_workitem, rpwm_workitem_callback);
  168. setup_timer(&pwrctrlpriv->rpwm_check_timer, rpwm_check_handler,
  169. (unsigned long)padapter);
  170. }
  171. /*
  172. Caller: r8712_cmd_thread
  173. Check if the fw_pwrstate is okay for issuing cmd.
  174. If not (cpwm should be is less than P2 state), then the sub-routine
  175. will raise the cpwm to be greater than or equal to P2.
  176. Calling Context: Passive
  177. Return Value:
  178. _SUCCESS: r8712_cmd_thread can issue cmds to firmware afterwards.
  179. _FAIL: r8712_cmd_thread can not do anything.
  180. */
  181. sint r8712_register_cmd_alive(struct _adapter *padapter)
  182. {
  183. uint res = _SUCCESS;
  184. struct pwrctrl_priv *pwrctrl = &padapter->pwrctrlpriv;
  185. _enter_pwrlock(&pwrctrl->lock);
  186. register_task_alive(pwrctrl, CMD_ALIVE);
  187. if (pwrctrl->cpwm < PS_STATE_S2) {
  188. r8712_set_rpwm(padapter, PS_STATE_S3);
  189. res = _FAIL;
  190. }
  191. up(&pwrctrl->lock);
  192. return res;
  193. }
  194. /*
  195. Caller: ISR
  196. If ISR's txdone,
  197. No more pkts for TX,
  198. Then driver shall call this fun. to power down firmware again.
  199. */
  200. void r8712_unregister_cmd_alive(struct _adapter *padapter)
  201. {
  202. struct pwrctrl_priv *pwrctrl = &padapter->pwrctrlpriv;
  203. _enter_pwrlock(&pwrctrl->lock);
  204. unregister_task_alive(pwrctrl, CMD_ALIVE);
  205. if ((pwrctrl->cpwm > PS_STATE_S2) &&
  206. (pwrctrl->pwr_mode > PS_MODE_ACTIVE)) {
  207. if ((pwrctrl->alives == 0) &&
  208. (check_fwstate(&padapter->mlmepriv,
  209. _FW_UNDER_LINKING) != true)) {
  210. r8712_set_rpwm(padapter, PS_STATE_S0);
  211. }
  212. }
  213. up(&pwrctrl->lock);
  214. }