diff options
-rw-r--r-- | board/rambi/board.h | 3 | ||||
-rw-r--r-- | board/samus/board.h | 2 | ||||
-rw-r--r-- | board/samus/power_sequence.c | 13 | ||||
-rw-r--r-- | common/wireless.c | 123 | ||||
-rw-r--r-- | include/config.h | 6 | ||||
-rw-r--r-- | include/ec_commands.h | 32 | ||||
-rw-r--r-- | include/wireless.h | 16 | ||||
-rw-r--r-- | power/baytrail.c | 18 | ||||
-rw-r--r-- | power/haswell.c | 13 | ||||
-rw-r--r-- | power/ivybridge.c | 11 | ||||
-rw-r--r-- | util/ectool.c | 69 |
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; } |