iwl-power.c revision a96a27f97f2bbfc1fca54bc3c0b0d41484152740
15da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas/******************************************************************************
25da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas *
35da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved.
45da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas *
55da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * Portions of this file are derived from the ipw3945 project, as well
65da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * as portions of the ieee80211 subsystem header files.
75da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas *
85da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * This program is free software; you can redistribute it and/or modify it
95da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * under the terms of version 2 of the GNU General Public License as
105da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * published by the Free Software Foundation.
115da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas *
125da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * This program is distributed in the hope that it will be useful, but WITHOUT
135da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
145da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
155da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * more details.
165da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas *
175da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * You should have received a copy of the GNU General Public License along with
185da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * this program; if not, write to the Free Software Foundation, Inc.,
195da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
205da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas *
215da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * The full GNU General Public License is included in this distribution in the
225da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * file called LICENSE.
235da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas *
245da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * Contact Information:
255da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * James P. Ketrenos <ipw2100-admin@linux.intel.com>
265da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
275da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas *****************************************************************************/
285da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
295da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
305da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#include <linux/kernel.h>
315da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#include <linux/module.h>
325da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#include <linux/init.h>
335da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
345da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#include <net/mac80211.h>
355da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
365da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#include "iwl-eeprom.h"
373e0d4cb12f6fd97193a455b49125398b2231c87cTomas Winkler#include "iwl-dev.h"
385da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#include "iwl-core.h"
395a36ba0e412a0e12a8bf2648a075226c1dd7870dTomas Winkler#include "iwl-commands.h"
405da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#include "iwl-debug.h"
415da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#include "iwl-power.h"
425da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#include "iwl-helpers.h"
435da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
445da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas/*
455da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * Setting power level allow the card to go to sleep when not busy
465da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * there are three factor that decide the power level to go to, they
475da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * are list here with its priority
485da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas *  1- critical_power_setting this will be set according to card temperature.
495da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas *  2- system_power_setting this will be set by system PM manager.
505da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas *  3- user_power_setting this will be set by user either by writing to sys or
515da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas *  	mac80211
525da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas *
535da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * if system_power_setting and user_power_setting is set to auto
545da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * the power level will be decided according to association status and battery
555da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * status.
565da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas *
575da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas */
585da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
595da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#define MSEC_TO_USEC 1024
605da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#define IWL_POWER_RANGE_0_MAX  (2)
615da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#define IWL_POWER_RANGE_1_MAX  (10)
625da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
635da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
645da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#define NOSLP __constant_cpu_to_le16(0), 0, 0
655da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
665da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#define SLP_TOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC)
675da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \
685da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas				     __constant_cpu_to_le32(X1), \
695da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas				     __constant_cpu_to_le32(X2), \
705da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas				     __constant_cpu_to_le32(X3), \
715da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas				     __constant_cpu_to_le32(X4)}
725da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
735da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#define IWL_POWER_ON_BATTERY		IWL_POWER_INDEX_5
745da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#define IWL_POWER_ON_AC_DISASSOC	IWL_POWER_MODE_CAM
755da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#define IWL_POWER_ON_AC_ASSOC		IWL_POWER_MODE_CAM
765da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
775da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
785da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#define IWL_CT_KILL_TEMPERATURE		110
795da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#define IWL_MIN_POWER_TEMPERATURE	100
805da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas#define IWL_REDUCED_POWER_TEMPERATURE	95
815da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
825da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas/* default power management (not Tx power) table values */
83a96a27f97f2bbfc1fca54bc3c0b0d41484152740Tomas Winkler/* for TIM  0-10 */
84298df1f62aa69881528bf0f1c3c14395bc447846Esti Kummerstatic struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = {
855da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
865da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
875da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
885da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0},
895da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 2, 4, 4, 0xFF)}, 1},
905da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 2, 4, 6, 0xFF)}, 2}
915da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas};
925da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
935da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
94a96a27f97f2bbfc1fca54bc3c0b0d41484152740Tomas Winkler/* for TIM = 3-10 */
95298df1f62aa69881528bf0f1c3c14395bc447846Esti Kummerstatic struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = {
965da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
975da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
985da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0},
995da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0},
1005da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 4, 6, 9, 10)}, 1},
1015da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2}
1025da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas};
1035da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
104a96a27f97f2bbfc1fca54bc3c0b0d41484152740Tomas Winkler/* for TIM > 11 */
105298df1f62aa69881528bf0f1c3c14395bc447846Esti Kummerstatic struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = {
1065da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
1075da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
1085da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
1095da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
1105da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
1115da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
1125da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas};
1135da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
114ca579617d81baf5865498eb5fae58e453ee77c2cMohamed Abbas/* set card power command */
115ca579617d81baf5865498eb5fae58e453ee77c2cMohamed Abbasstatic int iwl_set_power(struct iwl_priv *priv, void *cmd)
116ca579617d81baf5865498eb5fae58e453ee77c2cMohamed Abbas{
117ca579617d81baf5865498eb5fae58e453ee77c2cMohamed Abbas	return iwl_send_cmd_pdu_async(priv, POWER_TABLE_CMD,
118ca579617d81baf5865498eb5fae58e453ee77c2cMohamed Abbas				      sizeof(struct iwl_powertable_cmd),
119ca579617d81baf5865498eb5fae58e453ee77c2cMohamed Abbas				      cmd, NULL);
120ca579617d81baf5865498eb5fae58e453ee77c2cMohamed Abbas}
1215da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas/* decide the right power level according to association status
1225da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * and battery status
1235da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas */
1245da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbasstatic u16 iwl_get_auto_power_mode(struct iwl_priv *priv)
1255da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas{
126298df1f62aa69881528bf0f1c3c14395bc447846Esti Kummer	u16 mode;
1275da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
1285da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	switch (priv->power_data.user_power_setting) {
1295da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	case IWL_POWER_AUTO:
1305da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		/* if running on battery */
1315da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		if (priv->power_data.is_battery_active)
1325da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			mode = IWL_POWER_ON_BATTERY;
1335da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		else if (iwl_is_associated(priv))
1345da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			mode = IWL_POWER_ON_AC_ASSOC;
1355da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		else
1365da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			mode = IWL_POWER_ON_AC_DISASSOC;
1375da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		break;
138298df1f62aa69881528bf0f1c3c14395bc447846Esti Kummer	/* FIXME: remove battery and ac from here */
1395da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	case IWL_POWER_BATTERY:
1405da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		mode = IWL_POWER_INDEX_3;
1415da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		break;
1425da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	case IWL_POWER_AC:
1435da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		mode = IWL_POWER_MODE_CAM;
1445da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		break;
145298df1f62aa69881528bf0f1c3c14395bc447846Esti Kummer	default:
146298df1f62aa69881528bf0f1c3c14395bc447846Esti Kummer		mode = priv->power_data.user_power_setting;
147298df1f62aa69881528bf0f1c3c14395bc447846Esti Kummer		break;
1485da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	}
1495da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	return mode;
1505da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas}
1515da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
1525da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas/* initialize to default */
1535da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbasstatic int iwl_power_init_handle(struct iwl_priv *priv)
1545da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas{
1555da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	struct iwl_power_mgr *pow_data;
156298df1f62aa69881528bf0f1c3c14395bc447846Esti Kummer	int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_MAX;
157e7b635814b640c6fd9dca1c254dc22fac6fb9a1aTomas Winkler	struct iwl_powertable_cmd *cmd;
158e7b635814b640c6fd9dca1c254dc22fac6fb9a1aTomas Winkler	int i;
1595da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	u16 pci_pm;
1605da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
1615da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	IWL_DEBUG_POWER("Initialize power \n");
1625da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
1635da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	pow_data = &(priv->power_data);
1645da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
1655da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	memset(pow_data, 0, sizeof(*pow_data));
1665da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
1675da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
1685da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
1695da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	memcpy(&pow_data->pwr_range_2[0], &range_2[0], size);
1705da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
171e7b635814b640c6fd9dca1c254dc22fac6fb9a1aTomas Winkler	pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &pci_pm);
1725da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
173e7b635814b640c6fd9dca1c254dc22fac6fb9a1aTomas Winkler	IWL_DEBUG_POWER("adjust power command flags\n");
1745da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
175e7b635814b640c6fd9dca1c254dc22fac6fb9a1aTomas Winkler	for (i = 0; i < IWL_POWER_MAX; i++) {
176e7b635814b640c6fd9dca1c254dc22fac6fb9a1aTomas Winkler		cmd = &pow_data->pwr_range_0[i].cmd;
1775da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
178e7b635814b640c6fd9dca1c254dc22fac6fb9a1aTomas Winkler		if (pci_pm & PCI_CFG_LINK_CTRL_VAL_L0S_EN)
179e7b635814b640c6fd9dca1c254dc22fac6fb9a1aTomas Winkler			cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
180e7b635814b640c6fd9dca1c254dc22fac6fb9a1aTomas Winkler		else
181e7b635814b640c6fd9dca1c254dc22fac6fb9a1aTomas Winkler			cmd->flags |= IWL_POWER_PCI_PM_MSK;
1825da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	}
183e7b635814b640c6fd9dca1c254dc22fac6fb9a1aTomas Winkler	return 0;
1845da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas}
1855da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
186a96a27f97f2bbfc1fca54bc3c0b0d41484152740Tomas Winkler/* adjust power command according to DTIM period and power level*/
1875da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbasstatic int iwl_update_power_command(struct iwl_priv *priv,
188ca579617d81baf5865498eb5fae58e453ee77c2cMohamed Abbas				    struct iwl_powertable_cmd *cmd,
1895da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas				    u16 mode)
1905da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas{
1915da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	int ret = 0, i;
1925da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	u8 skip;
1935da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	u32 max_sleep = 0;
1945da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	struct iwl_power_vec_entry *range;
1955da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	u8 period = 0;
1965da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	struct iwl_power_mgr *pow_data;
1975da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
1985da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	if (mode > IWL_POWER_INDEX_5) {
1995da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		IWL_DEBUG_POWER("Error invalid power mode \n");
2005da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		return -1;
2015da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	}
2025da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	pow_data = &(priv->power_data);
2035da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
2045da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	if (pow_data->dtim_period <= IWL_POWER_RANGE_0_MAX)
2055da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		range = &pow_data->pwr_range_0[0];
2065da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	else if (pow_data->dtim_period <= IWL_POWER_RANGE_1_MAX)
2075da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		range = &pow_data->pwr_range_1[0];
2085da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	else
2095da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		range = &pow_data->pwr_range_2[0];
2105da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
2115da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	period = pow_data->dtim_period;
212ca579617d81baf5865498eb5fae58e453ee77c2cMohamed Abbas	memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd));
2135da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
2145da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	if (period == 0) {
2155da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		period = 1;
2165da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		skip = 0;
2175da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	} else
2185da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		skip = range[mode].no_dtim;
2195da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
2205da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	if (skip == 0) {
2215da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		max_sleep = period;
2225da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
2235da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	} else {
2245da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		__le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
2255da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		max_sleep = le32_to_cpu(slp_itrvl);
2265da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		if (max_sleep == 0xFF)
2275da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			max_sleep = period * (skip + 1);
2285da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		else if (max_sleep >  period)
2295da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
2305da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
2315da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	}
2325da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
2335da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	for (i = 0; i < IWL_POWER_VEC_SIZE; i++) {
2345da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
2355da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
2365da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	}
2375da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
2385da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags);
2395da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
2405da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
2415da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n",
2425da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			le32_to_cpu(cmd->sleep_interval[0]),
2435da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			le32_to_cpu(cmd->sleep_interval[1]),
2445da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			le32_to_cpu(cmd->sleep_interval[2]),
2455da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			le32_to_cpu(cmd->sleep_interval[3]),
2465da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			le32_to_cpu(cmd->sleep_interval[4]));
2475da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
2485da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	return ret;
2495da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas}
2505da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
2515da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
2525da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas/*
253a33c2f47bd4618b0483d5ec4c5bc793e6d02c1f7Emmanuel Grumbach * compute the final power mode index
2545da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas */
25504816448d8b77551834c9ea01e407ef5f0042f0fGrumbach, Emmanuelint iwl_power_update_mode(struct iwl_priv *priv, bool force)
2565da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas{
2575da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	struct iwl_power_mgr *setting = &(priv->power_data);
2585da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	int ret = 0;
2595da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	u16 uninitialized_var(final_mode);
2605da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
26104816448d8b77551834c9ea01e407ef5f0042f0fGrumbach, Emmanuel	/* Don't update the RX chain when chain noise calibration is running */
26204816448d8b77551834c9ea01e407ef5f0042f0fGrumbach, Emmanuel	if (priv->chain_noise_data.state != IWL_CHAIN_NOISE_DONE &&
26304816448d8b77551834c9ea01e407ef5f0042f0fGrumbach, Emmanuel	    priv->chain_noise_data.state != IWL_CHAIN_NOISE_ALIVE) {
26404816448d8b77551834c9ea01e407ef5f0042f0fGrumbach, Emmanuel		IWL_DEBUG_POWER("Cannot update the power, chain noise "
26504816448d8b77551834c9ea01e407ef5f0042f0fGrumbach, Emmanuel			"calibration running: %d\n",
26604816448d8b77551834c9ea01e407ef5f0042f0fGrumbach, Emmanuel			priv->chain_noise_data.state);
26704816448d8b77551834c9ea01e407ef5f0042f0fGrumbach, Emmanuel		return -EAGAIN;
26804816448d8b77551834c9ea01e407ef5f0042f0fGrumbach, Emmanuel	}
26904816448d8b77551834c9ea01e407ef5f0042f0fGrumbach, Emmanuel
270a33c2f47bd4618b0483d5ec4c5bc793e6d02c1f7Emmanuel Grumbach	/* If on battery, set to 3,
271a33c2f47bd4618b0483d5ec4c5bc793e6d02c1f7Emmanuel Grumbach	 * if plugged into AC power, set to CAM ("continuously aware mode"),
272a33c2f47bd4618b0483d5ec4c5bc793e6d02c1f7Emmanuel Grumbach	 * else user level */
2735da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
2745da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	switch (setting->system_power_setting) {
275298df1f62aa69881528bf0f1c3c14395bc447846Esti Kummer	case IWL_POWER_SYS_AUTO:
2765da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		final_mode = iwl_get_auto_power_mode(priv);
2775da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		break;
278298df1f62aa69881528bf0f1c3c14395bc447846Esti Kummer	case IWL_POWER_SYS_BATTERY:
2795da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		final_mode = IWL_POWER_INDEX_3;
2805da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		break;
281298df1f62aa69881528bf0f1c3c14395bc447846Esti Kummer	case IWL_POWER_SYS_AC:
2825da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		final_mode = IWL_POWER_MODE_CAM;
2835da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		break;
2845da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	default:
285298df1f62aa69881528bf0f1c3c14395bc447846Esti Kummer		final_mode = IWL_POWER_INDEX_3;
286298df1f62aa69881528bf0f1c3c14395bc447846Esti Kummer		WARN_ON(1);
2875da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	}
2885da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
2895da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	if (setting->critical_power_setting > final_mode)
2905da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		final_mode = setting->critical_power_setting;
2915da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
2925da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	/* driver only support CAM for non STA network */
29305c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg	if (priv->iw_mode != NL80211_IFTYPE_STATION)
2945da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		final_mode = IWL_POWER_MODE_CAM;
2955da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
2965da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	if (!iwl_is_rfkill(priv) && !setting->power_disabled &&
29704816448d8b77551834c9ea01e407ef5f0042f0fGrumbach, Emmanuel	    ((setting->power_mode != final_mode) || force)) {
298ca579617d81baf5865498eb5fae58e453ee77c2cMohamed Abbas		struct iwl_powertable_cmd cmd;
2995da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3005da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		if (final_mode != IWL_POWER_MODE_CAM)
3015da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			set_bit(STATUS_POWER_PMI, &priv->status);
3025da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3035da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		iwl_update_power_command(priv, &cmd, final_mode);
3045da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		cmd.keep_alive_beacons = 0;
3055da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3065da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		if (final_mode == IWL_POWER_INDEX_5)
3075da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			cmd.flags |= IWL_POWER_FAST_PD;
3085da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
309ca579617d81baf5865498eb5fae58e453ee77c2cMohamed Abbas		ret = iwl_set_power(priv, &cmd);
3105da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3115da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		if (final_mode == IWL_POWER_MODE_CAM)
3125da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			clear_bit(STATUS_POWER_PMI, &priv->status);
3135da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		else
3145da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			set_bit(STATUS_POWER_PMI, &priv->status);
3155da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3165da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		if (priv->cfg->ops->lib->update_chain_flags)
3175da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			priv->cfg->ops->lib->update_chain_flags(priv);
3185da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3195da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		if (!ret)
3205da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas			setting->power_mode = final_mode;
3215da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	}
3225da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3235da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	return ret;
3245da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas}
3255da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed AbbasEXPORT_SYMBOL(iwl_power_update_mode);
3265da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3275da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas/* Allow other iwl code to disable/enable power management active
328a96a27f97f2bbfc1fca54bc3c0b0d41484152740Tomas Winkler * this will be useful for rate scale to disable PM during heavy
3295da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * Tx/Rx activities
3305da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas */
331c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbachint iwl_power_disable_management(struct iwl_priv *priv, u32 ms)
3325da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas{
3335da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	u16 prev_mode;
3345da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	int ret = 0;
3355da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3365da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	if (priv->power_data.power_disabled)
3375da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		return -EBUSY;
3385da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3395da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	prev_mode = priv->power_data.user_power_setting;
3405da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	priv->power_data.user_power_setting = IWL_POWER_MODE_CAM;
3415da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	ret = iwl_power_update_mode(priv, 0);
3425da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	priv->power_data.power_disabled = 1;
3435da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	priv->power_data.user_power_setting = prev_mode;
344c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach	cancel_delayed_work(&priv->set_power_save);
345c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach	if (ms)
346c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach		queue_delayed_work(priv->workqueue, &priv->set_power_save,
347c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach				   msecs_to_jiffies(ms));
348c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach
3495da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3505da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	return ret;
3515da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas}
3525da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed AbbasEXPORT_SYMBOL(iwl_power_disable_management);
3535da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3545da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas/* Allow other iwl code to disable/enable power management active
355a96a27f97f2bbfc1fca54bc3c0b0d41484152740Tomas Winkler * this will be useful for rate scale to disable PM during high
356a96a27f97f2bbfc1fca54bc3c0b0d41484152740Tomas Winkler * volume activities
3575da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas */
3585da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbasint iwl_power_enable_management(struct iwl_priv *priv)
3595da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas{
3605da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	int ret = 0;
3615da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3625da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	priv->power_data.power_disabled = 0;
3635da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	ret = iwl_power_update_mode(priv, 0);
3645da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	return ret;
3655da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas}
3665da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed AbbasEXPORT_SYMBOL(iwl_power_enable_management);
3675da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3685da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas/* set user_power_setting */
3695da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbasint iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode)
3705da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas{
3715da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	if (mode > IWL_POWER_LIMIT)
3725da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		return -EINVAL;
3735da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3745da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	priv->power_data.user_power_setting = mode;
3755da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
37604816448d8b77551834c9ea01e407ef5f0042f0fGrumbach, Emmanuel	return iwl_power_update_mode(priv, 0);
3775da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas}
3785da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed AbbasEXPORT_SYMBOL(iwl_power_set_user_mode);
3795da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3805da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas/* set system_power_setting. This should be set by over all
3815da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas * PM application.
3825da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas */
3835da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbasint iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode)
3845da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas{
3855da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	if (mode > IWL_POWER_LIMIT)
3865da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		return -EINVAL;
3875da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3885da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	priv->power_data.system_power_setting = mode;
3895da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
39004816448d8b77551834c9ea01e407ef5f0042f0fGrumbach, Emmanuel	return iwl_power_update_mode(priv, 0);
3915da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas}
3925da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed AbbasEXPORT_SYMBOL(iwl_power_set_system_mode);
3935da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
394a96a27f97f2bbfc1fca54bc3c0b0d41484152740Tomas Winkler/* initialize to default */
3955da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbasvoid iwl_power_initialize(struct iwl_priv *priv)
3965da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas{
3975da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
3985da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	iwl_power_init_handle(priv);
3995da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	priv->power_data.user_power_setting = IWL_POWER_AUTO;
4005da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	priv->power_data.power_disabled = 0;
401298df1f62aa69881528bf0f1c3c14395bc447846Esti Kummer	priv->power_data.system_power_setting = IWL_POWER_SYS_AUTO;
4025da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	priv->power_data.is_battery_active = 0;
4035da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	priv->power_data.power_disabled = 0;
4045da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	priv->power_data.critical_power_setting = 0;
4055da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas}
4065da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed AbbasEXPORT_SYMBOL(iwl_power_initialize);
4075da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
4085da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas/* set critical_power_setting according to temperature value */
4095da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbasint iwl_power_temperature_change(struct iwl_priv *priv)
4105da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas{
4115da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	int ret = 0;
4125da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	u16 new_critical = priv->power_data.critical_power_setting;
4135da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	s32 temperature = KELVIN_TO_CELSIUS(priv->last_temperature);
4145da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
4155da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	if (temperature > IWL_CT_KILL_TEMPERATURE)
4165da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		return 0;
4175da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	else if (temperature > IWL_MIN_POWER_TEMPERATURE)
4185da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		new_critical = IWL_POWER_INDEX_5;
4195da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	else if (temperature > IWL_REDUCED_POWER_TEMPERATURE)
4205da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		new_critical = IWL_POWER_INDEX_3;
4215da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	else
4225da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		new_critical = IWL_POWER_MODE_CAM;
4235da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
4245da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	if (new_critical != priv->power_data.critical_power_setting)
4255da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		priv->power_data.critical_power_setting = new_critical;
4265da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
4275da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	if (priv->power_data.critical_power_setting >
4285da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas				priv->power_data.power_mode)
4295da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas		ret = iwl_power_update_mode(priv, 0);
4305da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas
4315da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas	return ret;
4325da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed Abbas}
4335da4b55f78fb2ed40926b775d4f7c791594ecbd7Mohamed AbbasEXPORT_SYMBOL(iwl_power_temperature_change);
434c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach
435c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbachstatic void iwl_bg_set_power_save(struct work_struct *work)
436c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach{
437c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach	struct iwl_priv *priv = container_of(work,
438c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach				struct iwl_priv, set_power_save.work);
439c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach	IWL_DEBUG(IWL_DL_STATE, "update power\n");
440c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach
441c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
442c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach		return;
443c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach
444c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach	mutex_lock(&priv->mutex);
445c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach
446a96a27f97f2bbfc1fca54bc3c0b0d41484152740Tomas Winkler	/* on starting association we disable power management
447c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach	 * until association, if association failed then this
448c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach	 * timer will expire and enable PM again.
449c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach	 */
450c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach	if (!iwl_is_associated(priv))
451c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach		iwl_power_enable_management(priv);
452c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach
453c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach	mutex_unlock(&priv->mutex);
454c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach}
455c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbachvoid iwl_setup_power_deferred_work(struct iwl_priv *priv)
456c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach{
457c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach	INIT_DELAYED_WORK(&priv->set_power_save, iwl_bg_set_power_save);
458c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach}
459c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel GrumbachEXPORT_SYMBOL(iwl_setup_power_deferred_work);
460c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach
461c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbachvoid iwl_power_cancel_timeout(struct iwl_priv *priv)
462c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach{
463c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach	cancel_delayed_work(&priv->set_power_save);
464c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel Grumbach}
465c90a74bae10dc2a4677d1bd06b6400db229d3e1eEmmanuel GrumbachEXPORT_SYMBOL(iwl_power_cancel_timeout);
466