ps.c revision 6b21a2cd315e2e56a1748bd3ef9d910fe4f2e711
12f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo/* 280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo * This file is part of wl1251 32f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * 42f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * Copyright (C) 2008 Nokia Corporation 52f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * 62f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * Contact: Kalle Valo <kalle.valo@nokia.com> 72f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * 82f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * This program is free software; you can redistribute it and/or 92f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * modify it under the terms of the GNU General Public License 102f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * version 2 as published by the Free Software Foundation. 112f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * 122f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * This program is distributed in the hope that it will be useful, but 132f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * WITHOUT ANY WARRANTY; without even the implied warranty of 142f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 152f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * General Public License for more details. 162f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * 172f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * You should have received a copy of the GNU General Public License 182f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * along with this program; if not, write to the Free Software 192f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 202f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * 02110-1301 USA 212f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * 222f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo */ 232f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 2429d904c452d466fbf51b2fde10f405b5c8f14c74Kalle Valo#include "wl1251_reg.h" 25ef2f8d45771490de5b8373c25e983ee1e3aee9eaKalle Valo#include "wl1251_ps.h" 260764de64c8628f653c7e8493017d6bd8d43f4e3bBob Copeland#include "wl1251_cmd.h" 270764de64c8628f653c7e8493017d6bd8d43f4e3bBob Copeland#include "wl1251_io.h" 282f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 2980301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo#define WL1251_WAKEUP_TIMEOUT 2000 302f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 312f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo/* Routines to toggle sleep mode while in ELP */ 3280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valovoid wl1251_ps_elp_sleep(struct wl1251 *wl) 332f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{ 342f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo if (wl->elp || !wl->psm) 352f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo return; 362f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 3780301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo wl1251_debug(DEBUG_PSM, "chip to elp"); 382f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 3980301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); 402f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 412f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo wl->elp = true; 422f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo} 432f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 4480301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valoint wl1251_ps_elp_wakeup(struct wl1251 *wl) 452f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{ 462f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo unsigned long timeout; 472f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo u32 elp_reg; 482f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 492f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo if (!wl->elp) 502f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo return 0; 512f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 5280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo wl1251_debug(DEBUG_PSM, "waking up chip from elp"); 532f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 5480301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT); 552f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 5680301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); 572f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 5880301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); 592f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 602f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo /* 612f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * FIXME: we should wait for irq from chip but, as a temporary 622f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * solution to simplify locking, let's poll instead 632f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo */ 642f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo while (!(elp_reg & ELPCTRL_WLAN_READY)) { 652f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo if (time_after(jiffies, timeout)) { 6680301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo wl1251_error("elp wakeup timeout"); 672f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo return -ETIMEDOUT; 682f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo } 692f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo msleep(1); 7080301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR); 712f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo } 722f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 7380301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo wl1251_debug(DEBUG_PSM, "wakeup time: %u ms", 742f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo jiffies_to_msecs(jiffies) - 7580301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo (jiffies_to_msecs(timeout) - WL1251_WAKEUP_TIMEOUT)); 762f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 772f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo wl->elp = false; 782f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 792f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo return 0; 802f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo} 812f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 8280301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valostatic int wl1251_ps_set_elp(struct wl1251 *wl, bool enable) 832f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{ 842f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo int ret; 852f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 862f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo if (enable) { 8780301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo wl1251_debug(DEBUG_PSM, "sleep auth psm/elp"); 882f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 8980301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); 902f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo if (ret < 0) 912f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo return ret; 922f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 9380301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo wl1251_ps_elp_sleep(wl); 942f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo } else { 9580301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo wl1251_debug(DEBUG_PSM, "sleep auth cam"); 962f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 972f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo /* 982f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * When the target is in ELP, we can only 992f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * access the ELP control register. Thus, 1002f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * we have to wake the target up before 1012f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo * changing the power authorization. 1022f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo */ 1032f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 10480301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo wl1251_ps_elp_wakeup(wl); 1052f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 10680301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); 1072f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo if (ret < 0) 1082f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo return ret; 1092f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo } 1102f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 1112f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo return 0; 1122f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo} 1132f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 11480301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valoint wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) 1152f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo{ 1162f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo int ret; 1172f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 1182f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo switch (mode) { 1192f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo case STATION_POWER_SAVE_MODE: 12080301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo wl1251_debug(DEBUG_PSM, "entering psm"); 1214a8189227fc4718a767ffca74d13a7d552e42189Kalle Valo 1226b21a2cd315e2e56a1748bd3ef9d910fe4f2e711Juuso Oikarinen /* enable beacon filtering */ 1236b21a2cd315e2e56a1748bd3ef9d910fe4f2e711Juuso Oikarinen ret = wl1251_acx_beacon_filter_opt(wl, true); 1246b21a2cd315e2e56a1748bd3ef9d910fe4f2e711Juuso Oikarinen if (ret < 0) 1256b21a2cd315e2e56a1748bd3ef9d910fe4f2e711Juuso Oikarinen return ret; 1266b21a2cd315e2e56a1748bd3ef9d910fe4f2e711Juuso Oikarinen 1274a8189227fc4718a767ffca74d13a7d552e42189Kalle Valo ret = wl1251_acx_wake_up_conditions(wl, 1284a8189227fc4718a767ffca74d13a7d552e42189Kalle Valo WAKE_UP_EVENT_DTIM_BITMAP, 1294a8189227fc4718a767ffca74d13a7d552e42189Kalle Valo wl->listen_int); 1304a8189227fc4718a767ffca74d13a7d552e42189Kalle Valo if (ret < 0) 1314a8189227fc4718a767ffca74d13a7d552e42189Kalle Valo return ret; 1324a8189227fc4718a767ffca74d13a7d552e42189Kalle Valo 13380301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); 1342f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo if (ret < 0) 1352f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo return ret; 1362f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 13780301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo ret = wl1251_ps_set_elp(wl, true); 1382f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo if (ret < 0) 1392f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo return ret; 1402f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 1412f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo wl->psm = 1; 1422f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo break; 1432f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo case STATION_ACTIVE_MODE: 1442f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo default: 14580301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo wl1251_debug(DEBUG_PSM, "leaving psm"); 14680301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo ret = wl1251_ps_set_elp(wl, false); 1472f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo if (ret < 0) 1482f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo return ret; 1492f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 1506b21a2cd315e2e56a1748bd3ef9d910fe4f2e711Juuso Oikarinen /* disable beacon filtering */ 1516b21a2cd315e2e56a1748bd3ef9d910fe4f2e711Juuso Oikarinen ret = wl1251_acx_beacon_filter_opt(wl, false); 1526b21a2cd315e2e56a1748bd3ef9d910fe4f2e711Juuso Oikarinen if (ret < 0) 1536b21a2cd315e2e56a1748bd3ef9d910fe4f2e711Juuso Oikarinen return ret; 1546b21a2cd315e2e56a1748bd3ef9d910fe4f2e711Juuso Oikarinen 1554a8189227fc4718a767ffca74d13a7d552e42189Kalle Valo ret = wl1251_acx_wake_up_conditions(wl, 1564a8189227fc4718a767ffca74d13a7d552e42189Kalle Valo WAKE_UP_EVENT_DTIM_BITMAP, 1574a8189227fc4718a767ffca74d13a7d552e42189Kalle Valo wl->listen_int); 1584a8189227fc4718a767ffca74d13a7d552e42189Kalle Valo if (ret < 0) 1594a8189227fc4718a767ffca74d13a7d552e42189Kalle Valo return ret; 1604a8189227fc4718a767ffca74d13a7d552e42189Kalle Valo 16180301cdcfe44e3533175be23d7d52a9fc8c3fdb0Kalle Valo ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); 1622f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo if (ret < 0) 1632f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo return ret; 1642f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 1652f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo wl->psm = 0; 1662f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo break; 1672f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo } 1682f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 1692f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo return ret; 1702f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo} 1712f01a1f58889fbfeb68b1bc1b52e4197f3333490Kalle Valo 172