summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/rambi/board.h3
-rw-r--r--board/samus/board.h2
-rw-r--r--board/samus/power_sequence.c13
-rw-r--r--common/wireless.c123
-rw-r--r--include/config.h6
-rw-r--r--include/ec_commands.h32
-rw-r--r--include/wireless.h16
-rw-r--r--power/baytrail.c18
-rw-r--r--power/haswell.c13
-rw-r--r--power/ivybridge.c11
-rw-r--r--util/ectool.c69
11 files changed, 252 insertions, 54 deletions
diff --git a/board/rambi/board.h b/board/rambi/board.h
index 091c9d9d04..3a19a55c71 100644
--- a/board/rambi/board.h
+++ b/board/rambi/board.h
@@ -42,7 +42,8 @@
#define CONFIG_USB_PORT_POWER_SMART_SIMPLE
#define CONFIG_VBOOT_HASH
#define CONFIG_WIRELESS
-#define CONFIG_WIRELESS_SUSPEND_ENABLE_WIFI
+#define CONFIG_WIRELESS_SUSPEND \
+ (EC_WIRELESS_SWITCH_WLAN | EC_WIRELESS_SWITCH_WLAN_POWER)
#ifndef __ASSEMBLER__
diff --git a/board/samus/board.h b/board/samus/board.h
index b892bd8d7c..6646f24152 100644
--- a/board/samus/board.h
+++ b/board/samus/board.h
@@ -50,6 +50,8 @@
#define CONFIG_USB_PORT_POWER_SMART
#define CONFIG_VBOOT_HASH
#define CONFIG_WIRELESS
+#define CONFIG_WIRELESS_SUSPEND \
+ (EC_WIRELESS_SWITCH_WLAN | EC_WIRELESS_SWITCH_WLAN_POWER)
#ifndef __ASSEMBLER__
diff --git a/board/samus/power_sequence.c b/board/samus/power_sequence.c
index 1c24ead274..e9bdbbb576 100644
--- a/board/samus/power_sequence.c
+++ b/board/samus/power_sequence.c
@@ -139,7 +139,7 @@ enum power_state power_chipset_init(void)
gpio_set_level(GPIO_PP5000_EN, 0);
gpio_set_level(GPIO_PCH_DPWROK, 0);
gpio_set_level(GPIO_PP3300_DSW_EN, 0);
- wireless_enable(0);
+ wireless_set_state(WIRELESS_OFF);
}
}
@@ -278,7 +278,7 @@ enum power_state power_handle_state(enum power_state state)
msleep(20);
/* Enable wireless. */
- wireless_enable(EC_WIRELESS_SWITCH_ALL);
+ wireless_set_state(WIRELESS_ON);
/*
* Make sure touchscreen is out if reset (even if the
@@ -290,7 +290,7 @@ enum power_state power_handle_state(enum power_state state)
/* Wait for non-core power rails good */
if (power_wait_signals(IN_PGOOD_S0)) {
chipset_force_shutdown();
- wireless_enable(0);
+ wireless_set_state(WIRELESS_OFF);
return POWER_S3;
}
@@ -322,9 +322,8 @@ enum power_state power_handle_state(enum power_state state)
/* Wait 40ns */
udelay(1);
- /* Disable WWAN, but leave WiFi on */
- wireless_enable(EC_WIRELESS_SWITCH_WLAN |
- EC_WIRELESS_SWITCH_WLAN_POWER);
+ /* Suspend wireless */
+ wireless_set_state(WIRELESS_SUSPEND);
/*
* Deassert prochot since CPU is off and we're about to drop
@@ -339,7 +338,7 @@ enum power_state power_handle_state(enum power_state state)
hook_notify(HOOK_CHIPSET_SHUTDOWN);
/* Disable wireless */
- wireless_enable(0);
+ wireless_set_state(WIRELESS_OFF);
/* Disable peripheral power */
gpio_set_level(GPIO_ENABLE_TOUCHPAD, 0);
diff --git a/common/wireless.c b/common/wireless.c
index 2344f08cd5..54a0689906 100644
--- a/common/wireless.c
+++ b/common/wireless.c
@@ -6,10 +6,32 @@
/* Wireless power management */
#include "common.h"
+#include "console.h"
#include "gpio.h"
#include "host_command.h"
+#include "util.h"
+#include "wireless.h"
-void wireless_enable(int flags)
+/* Unless told otherwise, disable wireless in suspend */
+#ifndef CONFIG_WIRELESS_SUSPEND
+#define CONFIG_WIRELESS_SUSPEND 0
+#endif
+
+/*
+ * Flags which will be left on when suspending. Other flags will be disabled
+ * when suspending.
+ */
+static int suspend_flags = CONFIG_WIRELESS_SUSPEND;
+
+/**
+ * Set wireless switch state.
+ *
+ * @param flags Enable flags from ec_commands.h (EC_WIRELESS_SWITCH_*),
+ * 0 to turn all wireless off, or -1 to turn all wireless
+ * on.
+ * @param mask Which of those flags to set
+ */
+static void wireless_enable(int flags)
{
#ifdef WIRELESS_GPIO_WLAN
gpio_set_level(WIRELESS_GPIO_WLAN,
@@ -33,14 +55,107 @@ void wireless_enable(int flags)
}
+static int wireless_get(void)
+{
+ int flags = 0;
+
+#ifdef WIRELESS_GPIO_WLAN
+ if (gpio_get_level(WIRELESS_GPIO_WLAN))
+ flags |= EC_WIRELESS_SWITCH_WLAN;
+#endif
+
+#ifdef WIRELESS_GPIO_WWAN
+ if (gpio_get_level(WIRELESS_GPIO_WWAN))
+ flags |= EC_WIRELESS_SWITCH_WWAN;
+#endif
+
+#ifdef WIRELESS_GPIO_BLUETOOTH
+ if (gpio_get_level(WIRELESS_GPIO_BLUETOOTH))
+ flags |= EC_WIRELESS_SWITCH_BLUETOOTH;
+#endif
+
+#ifdef WIRELESS_GPIO_WLAN_POWER
+ if (gpio_get_level(WIRELESS_GPIO_WLAN_POWER))
+ flags |= EC_WIRELESS_SWITCH_WLAN_POWER;
+#endif
+
+ return flags;
+}
+
+void wireless_set_state(enum wireless_power_state state)
+{
+ switch (state) {
+ case WIRELESS_OFF:
+ wireless_enable(0);
+ break;
+ case WIRELESS_SUSPEND:
+ /*
+ * When suspending, only turn things off. If the AP has
+ * disabled WiFi power, going into S3 should not re-enable it.
+ */
+ wireless_enable(wireless_get() & suspend_flags);
+ break;
+ case WIRELESS_ON:
+ wireless_enable(EC_WIRELESS_SWITCH_ALL);
+ break;
+ }
+}
+
static int wireless_enable_cmd(struct host_cmd_handler_args *args)
{
- const struct ec_params_switch_enable_wireless *p = args->params;
+ const struct ec_params_switch_enable_wireless_v1 *p = args->params;
+ struct ec_response_switch_enable_wireless_v1 *r = args->response;
+
+ if (args->version == 0) {
+ /* Ver.0 command just set all current flags */
+ wireless_enable(p->now_flags);
+ return EC_RES_SUCCESS;
+ }
- wireless_enable(p->enabled);
+ /* Ver.1 can set flags based on mask */
+ wireless_enable((wireless_get() & ~p->now_mask) |
+ (p->now_flags & p->now_mask));
+ suspend_flags = (suspend_flags & ~p->suspend_mask) |
+ (p->suspend_flags & p->suspend_mask);
+
+ /* And return the current flags */
+ r->now_flags = wireless_get();
+ r->suspend_flags = suspend_flags;
+ args->response_size = sizeof(*r);
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_SWITCH_ENABLE_WIRELESS,
wireless_enable_cmd,
- EC_VER_MASK(0));
+ EC_VER_MASK(0) | EC_VER_MASK(1));
+
+static int command_wireless(int argc, char **argv)
+{
+ char *e;
+ int i;
+
+ if (argc >= 2) {
+ i = strtoi(argv[1], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM1;
+
+ wireless_enable(i);
+ }
+
+ if (argc >= 3) {
+ i = strtoi(argv[2], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM2;
+
+ suspend_flags = i;
+ }
+
+ ccprintf("Wireless flags: now=0x%x, suspend=0x%x\n", wireless_get(),
+ suspend_flags);
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(wireless, command_wireless,
+ "[now [suspend]]",
+ "Get/set wireless flags",
+ NULL);
diff --git a/include/config.h b/include/config.h
index a2f2808009..a95f38e94b 100644
--- a/include/config.h
+++ b/include/config.h
@@ -821,9 +821,11 @@
#undef CONFIG_WIRELESS
/*
- * Support for WiFi devices that must remain powered in suspend.
+ * Support for WiFi devices that must remain powered in suspend. Set to the
+ * combination of EC_WIRELESS_SWITCH flags (from ec_commands.h) which should
+ * be set in suspend.
*/
-#undef CONFIG_WIRELESS_SUSPEND_ENABLE_WIFI
+#undef CONFIG_WIRELESS_SUSPEND
/*
* Write protect signal is active-high. If this is defined, there must be a
diff --git a/include/ec_commands.h b/include/ec_commands.h
index 86b421e76a..b3d221d7cf 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -1520,11 +1520,41 @@ struct ec_params_switch_enable_backlight {
/* Enable/disable WLAN/Bluetooth */
#define EC_CMD_SWITCH_ENABLE_WIRELESS 0x91
+#define EC_VER_SWITCH_ENABLE_WIRELESS 1
-struct ec_params_switch_enable_wireless {
+/* Version 0 params; no response */
+struct ec_params_switch_enable_wireless_v0 {
uint8_t enabled;
} __packed;
+/* Version 1 params */
+struct ec_params_switch_enable_wireless_v1 {
+ /* Flags to enable now */
+ uint8_t now_flags;
+
+ /* Which flags to copy from now_flags */
+ uint8_t now_mask;
+
+ /*
+ * Flags to leave enabled in S3, if they're on at the S0->S3
+ * transition. (Other flags will be disabled by the S0->S3
+ * transition.)
+ */
+ uint8_t suspend_flags;
+
+ /* Which flags to copy from suspend_flags */
+ uint8_t suspend_mask;
+} __packed;
+
+/* Version 1 response */
+struct ec_response_switch_enable_wireless_v1 {
+ /* Flags to enable now */
+ uint8_t now_flags;
+
+ /* Flags to leave enabled in S3 */
+ uint8_t suspend_flags;
+} __packed;
+
/*****************************************************************************/
/* GPIO commands. Only available on EC if write protect has been disabled. */
diff --git a/include/wireless.h b/include/wireless.h
index ca23832239..c8231d055c 100644
--- a/include/wireless.h
+++ b/include/wireless.h
@@ -9,15 +9,17 @@
#define __CROS_EC_WIRELESS_H
#include "common.h"
-#include "ec_commands.h"
+
+/* Wireless power state for wireless_set_state() */
+enum wireless_power_state {
+ WIRELESS_OFF,
+ WIRELESS_SUSPEND,
+ WIRELESS_ON
+};
/**
- * Set wireless switch state.
- *
- * @param flags Enable flags from ec_commands.h (EC_WIRELESS_SWITCH_*),
- * 0 to turn all wireless off, or -1 to turn all wireless
- * on.
+ * Set wireless power state.
*/
-void wireless_enable(int flags);
+void wireless_set_state(enum wireless_power_state state);
#endif /* __CROS_EC_WIRELESS_H */
diff --git a/power/baytrail.c b/power/baytrail.c
index 2d4aba1a36..b44e1b8e27 100644
--- a/power/baytrail.c
+++ b/power/baytrail.c
@@ -129,7 +129,7 @@ enum power_state power_chipset_init(void)
gpio_set_level(GPIO_PP5000_EN, 0);
gpio_set_level(GPIO_PCH_RSMRST_L, 0);
gpio_set_level(GPIO_PCH_SYS_PWROK, 0);
- wireless_enable(0);
+ wireless_set_state(WIRELESS_OFF);
}
}
@@ -233,7 +233,7 @@ enum power_state power_handle_state(enum power_state state)
gpio_set_level(GPIO_PP3300_DX_EN, 1);
/* Enable wireless */
- wireless_enable(EC_WIRELESS_SWITCH_ALL);
+ wireless_set_state(WIRELESS_ON);
/*
* Make sure touchscreen is out if reset (even if the lid is
@@ -245,7 +245,7 @@ enum power_state power_handle_state(enum power_state state)
/* Wait for non-core power rails good */
if (power_wait_signals(IN_PGOOD_S0)) {
chipset_force_shutdown();
- wireless_enable(0);
+ wireless_set_state(WIRELESS_OFF);
gpio_set_level(GPIO_PP3300_DX_EN, 0);
gpio_set_level(GPIO_PP5000_EN, 0);
gpio_set_level(GPIO_TOUCHSCREEN_RESET_L, 0);
@@ -298,14 +298,8 @@ enum power_state power_handle_state(enum power_state state)
/* Disable +CPU_CORE */
gpio_set_level(GPIO_VCORE_EN, 0);
-#ifdef CONFIG_WIRELESS_SUSPEND_ENABLE_WIFI
- /* Disable WWAN, but leave WiFi on */
- wireless_enable(EC_WIRELESS_SWITCH_WLAN |
- EC_WIRELESS_SWITCH_WLAN_POWER);
-#else
- /* Disable wireless */
- wireless_enable(0);
-#endif
+ /* Suspend wireless */
+ wireless_set_state(WIRELESS_SUSPEND);
/*
* Enable idle task deep sleep. Allow the low power idle task
@@ -343,7 +337,7 @@ enum power_state power_handle_state(enum power_state state)
gpio_set_level(GPIO_PP5000_EN, 0);
/* Disable wireless */
- wireless_enable(0);
+ wireless_set_state(WIRELESS_OFF);
/* Disable touchpad power and hold touchscreen in reset */
gpio_set_level(GPIO_ENABLE_TOUCHPAD, 0);
diff --git a/power/haswell.c b/power/haswell.c
index b51ac36ad8..b5250379ad 100644
--- a/power/haswell.c
+++ b/power/haswell.c
@@ -145,7 +145,7 @@ enum power_state power_chipset_init(void)
gpio_set_level(GPIO_PP5000_EN, 0);
gpio_set_level(GPIO_PCH_RSMRST_L, 0);
gpio_set_level(GPIO_PCH_DPWROK, 0);
- wireless_enable(0);
+ wireless_set_state(WIRELESS_OFF);
}
}
@@ -261,7 +261,7 @@ enum power_state power_handle_state(enum power_state state)
gpio_set_level(GPIO_PP3300_DX_EN, 1);
/* Enable wireless */
- wireless_enable(EC_WIRELESS_SWITCH_ALL);
+ wireless_set_state(WIRELESS_ON);
/*
* Make sure touchscreen is out if reset (even if the lid is
@@ -273,7 +273,7 @@ enum power_state power_handle_state(enum power_state state)
/* Wait for non-core power rails good */
if (power_wait_signals(IN_PGOOD_S0)) {
chipset_force_shutdown();
- wireless_enable(0);
+ wireless_set_state(WIRELESS_OFF);
gpio_set_level(GPIO_EC_EDP_VDD_EN, 0);
gpio_set_level(GPIO_PP3300_DX_EN, 0);
gpio_set_level(GPIO_TOUCHSCREEN_RESET_L, 0);
@@ -323,8 +323,8 @@ enum power_state power_handle_state(enum power_state state)
/* Disable +CPU_CORE */
gpio_set_level(GPIO_VCORE_EN, 0);
- /* Disable wireless */
- wireless_enable(0);
+ /* Suspend wireless */
+ wireless_set_state(WIRELESS_SUSPEND);
/*
* Enable idle task deep sleep. Allow the low power idle task
@@ -347,6 +347,9 @@ enum power_state power_handle_state(enum power_state state)
/* Call hooks before we remove power rails */
hook_notify(HOOK_CHIPSET_SHUTDOWN);
+ /* Disable wireless */
+ wireless_set_state(WIRELESS_OFF);
+
/* Disable touchpad power */
gpio_set_level(GPIO_ENABLE_TOUCHPAD, 0);
diff --git a/power/ivybridge.c b/power/ivybridge.c
index 587960bea8..10086a862a 100644
--- a/power/ivybridge.c
+++ b/power/ivybridge.c
@@ -239,7 +239,7 @@ enum power_state power_handle_state(enum power_state state)
gpio_set_level(GPIO_ENABLE_VS, 1);
/* Enable wireless */
- wireless_enable(EC_WIRELESS_SWITCH_ALL);
+ wireless_set_state(WIRELESS_ON);
/*
* Make sure touchscreen is out if reset (even if the lid is
@@ -252,7 +252,7 @@ enum power_state power_handle_state(enum power_state state)
if (power_wait_signals(IN_PGOOD_S0)) {
chipset_force_shutdown();
gpio_set_level(GPIO_TOUCHSCREEN_RESET_L, 0);
- wireless_enable(0);
+ wireless_set_state(WIRELESS_OFF);
gpio_set_level(GPIO_ENABLE_VS, 0);
return POWER_S3;
}
@@ -292,8 +292,8 @@ enum power_state power_handle_state(enum power_state state)
/* Disable +CPU_CORE and +VGFX_CORE */
gpio_set_level(GPIO_ENABLE_VCORE, 0);
- /* Disable wireless */
- wireless_enable(0);
+ /* Suspend wireless */
+ wireless_set_state(WIRELESS_SUSPEND);
/*
* Deassert prochot since CPU is off and we're about to drop
@@ -309,6 +309,9 @@ enum power_state power_handle_state(enum power_state state)
/* Call hooks before we remove power rails */
hook_notify(HOOK_CHIPSET_SHUTDOWN);
+ /* Disable wireless */
+ wireless_set_state(WIRELESS_OFF);
+
/* Disable touchpad power */
gpio_set_level(GPIO_ENABLE_TOUCHPAD, 0);
diff --git a/util/ectool.c b/util/ectool.c
index dedb617cf9..f0c3d3500f 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -158,7 +158,7 @@ const char help_str[] =
" Set USB mux switch state\n"
" version\n"
" Prints EC version\n"
- " wireless <mask>\n"
+ " wireless <flags> [<mask> [<suspend_flags> <suspend_mask>]]\n"
" Enable/disable WLAN/Bluetooth radio\n"
"\n"
"Not working for you? Make sure LPC I/O is configured:\n"
@@ -2316,30 +2316,77 @@ int cmd_switches(int argc, char *argv[])
int cmd_wireless(int argc, char *argv[])
{
- struct ec_params_switch_enable_wireless p;
char *e;
int rv;
+ int now_flags;
- if (argc != 2) {
- fprintf(stderr, "Usage: %s <mask>\n", argv[0]);
+ if (argc < 2) {
+ fprintf(stderr,
+ "Usage: %s <flags> [<mask> [<susflags> <susmask>]]\n",
+ argv[0]);
fprintf(stderr, " 0x1 = WLAN radio\n"
" 0x2 = Bluetooth radio\n"
" 0x4 = WWAN power\n"
" 0x8 = WLAN power\n");
return -1;
}
- p.enabled = strtol(argv[1], &e, 0);
+
+ now_flags = strtol(argv[1], &e, 0);
if (e && *e) {
- fprintf(stderr, "Bad value.\n");
+ fprintf(stderr, "Bad flags.\n");
return -1;
}
- rv = ec_command(EC_CMD_SWITCH_ENABLE_WIRELESS, 0,
- &p, sizeof(p), NULL, 0);
- if (rv < 0)
- return rv;
+ if (argc < 3) {
+ /* Old-style - current flags only */
+ struct ec_params_switch_enable_wireless_v0 p;
+
+ p.enabled = now_flags;
+ rv = ec_command(EC_CMD_SWITCH_ENABLE_WIRELESS, 0,
+ &p, sizeof(p), NULL, 0);
+ if (rv < 0)
+ return rv;
+
+ printf("Success.\n");
+ } else {
+ /* New-style - masks and suspend flags */
+ struct ec_params_switch_enable_wireless_v1 p;
+ struct ec_response_switch_enable_wireless_v1 r;
+
+ memset(&p, 0, sizeof(p));
+
+ p.now_flags = now_flags;
+
+ p.now_mask = strtol(argv[2], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad mask.\n");
+ return -1;
+ }
+
+ if (argc > 4) {
+ p.suspend_flags = strtol(argv[3], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad suspend flags.\n");
+ return -1;
+ }
+
+ p.suspend_mask = strtol(argv[4], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad suspend mask.\n");
+ return -1;
+ }
+ }
+
+ rv = ec_command(EC_CMD_SWITCH_ENABLE_WIRELESS,
+ EC_VER_SWITCH_ENABLE_WIRELESS,
+ &p, sizeof(p), &r, sizeof(r));
+ if (rv < 0)
+ return rv;
+
+ printf("Now=0x%x, suspend=0x%x\n",
+ r.now_flags, r.suspend_flags);
+ }
- printf("Success.\n");
return 0;
}