Merge branch 'ib-mfd-iio-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/lee...
[firefly-linux-kernel-4.4.55.git] / drivers / staging / vt6655 / power.c
1 /*
2  * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
3  * All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  *
20  * File: power.c
21  *
22  * Purpose: Handles 802.11 power management  functions
23  *
24  * Author: Lyndon Chen
25  *
26  * Date: July 17, 2002
27  *
28  * Functions:
29  *      PSvEnablePowerSaving - Enable Power Saving Mode
30  *      PSvDiasblePowerSaving - Disable Power Saving Mode
31  *      PSbConsiderPowerDown - Decide if we can Power Down
32  *      PSvSendPSPOLL - Send PS-POLL packet
33  *      PSbSendNullPacket - Send Null packet
34  *      PSbIsNextTBTTWakeUp - Decide if we need to wake up at next Beacon
35  *
36  * Revision History:
37  *
38  */
39
40 #include "ttype.h"
41 #include "mac.h"
42 #include "device.h"
43 #include "wmgr.h"
44 #include "power.h"
45 #include "wcmd.h"
46 #include "rxtx.h"
47 #include "card.h"
48
49 /*---------------------  Static Definitions -------------------------*/
50
51 /*---------------------  Static Classes  ----------------------------*/
52
53 /*---------------------  Static Functions  --------------------------*/
54
55 /*---------------------  Export Variables  --------------------------*/
56
57 /*---------------------  Export Functions  --------------------------*/
58
59 /*+
60  *
61  * Routine Description:
62  * Enable hw power saving functions
63  *
64  * Return Value:
65  *    None.
66  *
67  -*/
68
69 void
70 PSvEnablePowerSaving(
71         void *hDeviceContext,
72         unsigned short wListenInterval
73 )
74 {
75         struct vnt_private *pDevice = hDeviceContext;
76         PSMgmtObject    pMgmt = pDevice->pMgmt;
77         unsigned short wAID = pMgmt->wCurrAID | BIT14 | BIT15;
78
79         // set period of power up before TBTT
80         VNSvOutPortW(pDevice->PortOffset + MAC_REG_PWBT, C_PWBT);
81         if (pDevice->op_mode != NL80211_IFTYPE_ADHOC) {
82                 // set AID
83                 VNSvOutPortW(pDevice->PortOffset + MAC_REG_AIDATIM, wAID);
84         } else {
85                 // set ATIM Window
86                 MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow);
87         }
88         // Set AutoSleep
89         MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
90         // Set HWUTSF
91         MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
92
93         if (wListenInterval >= 2) {
94                 // clear always listen beacon
95                 MACvRegBitsOff(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
96                 // first time set listen next beacon
97                 MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN);
98                 pMgmt->wCountToWakeUp = wListenInterval;
99         } else {
100                 // always listen beacon
101                 MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
102                 pMgmt->wCountToWakeUp = 0;
103         }
104
105         // enable power saving hw function
106         MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
107         pDevice->bEnablePSMode = true;
108
109         /* We don't send null pkt in ad hoc mode since beacon will handle this. */
110         if (pDevice->op_mode != NL80211_IFTYPE_ADHOC &&
111             pDevice->op_mode == NL80211_IFTYPE_STATION)
112                 PSbSendNullPacket(pDevice);
113
114         pDevice->bPWBitOn = true;
115         pr_debug("PS:Power Saving Mode Enable...\n");
116 }
117
118 /*+
119  *
120  * Routine Description:
121  * Disable hw power saving functions
122  *
123  * Return Value:
124  *    None.
125  *
126  -*/
127
128 void
129 PSvDisablePowerSaving(
130         void *hDeviceContext
131 )
132 {
133         struct vnt_private *pDevice = hDeviceContext;
134
135         // disable power saving hw function
136         MACbPSWakeup(pDevice->PortOffset);
137         //clear AutoSleep
138         MACvRegBitsOff(pDevice->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
139         //clear HWUTSF
140         MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
141         // set always listen beacon
142         MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
143
144         pDevice->bEnablePSMode = false;
145
146         if (pDevice->op_mode == NL80211_IFTYPE_STATION)
147                 PSbSendNullPacket(pDevice);
148
149         pDevice->bPWBitOn = false;
150 }
151
152 /*+
153  *
154  * Routine Description:
155  * Consider to power down when no more packets to tx or rx.
156  *
157  * Return Value:
158  *    true, if power down success
159  *    false, if fail
160  -*/
161
162 bool
163 PSbConsiderPowerDown(
164         void *hDeviceContext,
165         bool bCheckRxDMA,
166         bool bCheckCountToWakeUp
167 )
168 {
169         struct vnt_private *pDevice = hDeviceContext;
170         PSMgmtObject    pMgmt = pDevice->pMgmt;
171         unsigned int uIdx;
172
173         // check if already in Doze mode
174         if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS))
175                 return true;
176
177         if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
178                 // check if in TIM wake period
179                 if (pMgmt->bInTIMWake)
180                         return false;
181         }
182
183         // check scan state
184         if (pDevice->bCmdRunning)
185                 return false;
186
187         // Force PSEN on
188         MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
189
190         // check if all TD are empty,
191         for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx++) {
192                 if (pDevice->iTDUsed[uIdx] != 0)
193                         return false;
194         }
195
196         // check if rx isr is clear
197         if (bCheckRxDMA &&
198             ((pDevice->dwIsr & ISR_RXDMA0) != 0) &&
199             ((pDevice->dwIsr & ISR_RXDMA1) != 0)) {
200                 return false;
201         }
202
203         if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
204                 if (bCheckCountToWakeUp &&
205                     (pMgmt->wCountToWakeUp == 0 || pMgmt->wCountToWakeUp == 1)) {
206                         return false;
207                 }
208         }
209
210         // no Tx, no Rx isr, now go to Doze
211         MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_GO2DOZE);
212         pr_debug("Go to Doze ZZZZZZZZZZZZZZZ\n");
213         return true;
214 }
215
216 /*+
217  *
218  * Routine Description:
219  * Send PS-POLL packet
220  *
221  * Return Value:
222  *    None.
223  *
224  -*/
225
226 void
227 PSvSendPSPOLL(
228         void *hDeviceContext
229 )
230 {
231         struct vnt_private *pDevice = hDeviceContext;
232         PSMgmtObject        pMgmt = pDevice->pMgmt;
233         PSTxMgmtPacket      pTxPacket = NULL;
234
235         memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_HDR_ADDR2_LEN);
236         pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
237         pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
238         pTxPacket->p80211Header->sA2.wFrameCtl = cpu_to_le16(
239                 (
240                         WLAN_SET_FC_FTYPE(WLAN_TYPE_CTL) |
241                         WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PSPOLL) |
242                         WLAN_SET_FC_PWRMGT(0)
243 ));
244         pTxPacket->p80211Header->sA2.wDurationID = pMgmt->wCurrAID | BIT14 | BIT15;
245         memcpy(pTxPacket->p80211Header->sA2.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
246         memcpy(pTxPacket->p80211Header->sA2.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
247         pTxPacket->cbMPDULen = WLAN_HDR_ADDR2_LEN;
248         pTxPacket->cbPayloadLen = 0;
249         // send the frame
250         if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING)
251                 pr_debug("Send PS-Poll packet failed..\n");
252 }
253
254 /*+
255  *
256  * Routine Description:
257  * Send NULL packet to AP for notification power state of STA
258  *
259  * Return Value:
260  *    None.
261  *
262  -*/
263 bool
264 PSbSendNullPacket(
265         void *hDeviceContext
266 )
267 {
268         struct vnt_private *pDevice = hDeviceContext;
269         PSTxMgmtPacket      pTxPacket = NULL;
270         PSMgmtObject        pMgmt = pDevice->pMgmt;
271         unsigned int uIdx;
272
273         if (!pDevice->bLinkPass)
274                 return false;
275
276         if (!pDevice->bEnablePSMode && !pDevice->fTxDataInSleep)
277                 return false;
278
279         if (pDevice->bEnablePSMode) {
280                 for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx++) {
281                         if (pDevice->iTDUsed[uIdx] != 0)
282                                 return false;
283                 }
284         }
285
286         memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_NULLDATA_FR_MAXLEN);
287         pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
288         pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
289
290         if (pDevice->bEnablePSMode) {
291                 pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(
292                         (
293                                 WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) |
294                                 WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL) |
295                                 WLAN_SET_FC_PWRMGT(1)
296 ));
297         } else {
298                 pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(
299                         (
300                                 WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) |
301                                 WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL) |
302                                 WLAN_SET_FC_PWRMGT(0)
303 ));
304         }
305
306         if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA)
307                 pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((unsigned short)WLAN_SET_FC_TODS(1));
308
309         memcpy(pTxPacket->p80211Header->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
310         memcpy(pTxPacket->p80211Header->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
311         memcpy(pTxPacket->p80211Header->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
312         pTxPacket->cbMPDULen = WLAN_HDR_ADDR3_LEN;
313         pTxPacket->cbPayloadLen = 0;
314         // send the frame
315         if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
316                 pr_debug("Send Null Packet failed !\n");
317                 return false;
318         }
319
320         return true;
321 }
322
323 /*+
324  *
325  * Routine Description:
326  * Check if Next TBTT must wake up
327  *
328  * Return Value:
329  *    None.
330  *
331  -*/
332
333 bool
334 PSbIsNextTBTTWakeUp(
335         void *hDeviceContext
336 )
337 {
338         struct vnt_private *pDevice = hDeviceContext;
339         PSMgmtObject        pMgmt = pDevice->pMgmt;
340         bool bWakeUp = false;
341
342         if (pMgmt->wListenInterval >= 2) {
343                 if (pMgmt->wCountToWakeUp == 0)
344                         pMgmt->wCountToWakeUp = pMgmt->wListenInterval;
345
346                 pMgmt->wCountToWakeUp--;
347
348                 if (pMgmt->wCountToWakeUp == 1) {
349                         // Turn on wake up to listen next beacon
350                         MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN);
351                         bWakeUp = true;
352                 }
353
354         }
355
356         return bWakeUp;
357 }