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