diff options
author | Nicolas Boichat <drinkcat@chromium.org> | 2018-01-05 13:59:03 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-01-05 12:10:01 -0800 |
commit | 13f3e27c80598cd066696cd413ac6b651f7a8006 (patch) | |
tree | 70164eca90c8285789c17c30e93e77f09d2fd0bf /board/poppy | |
parent | 1c0d70d1b0796fc339e7b59eeeed118a081f5908 (diff) | |
download | chrome-ec-13f3e27c80598cd066696cd413ac6b651f7a8006.tar.gz |
poppy: Move base detection logic to separate file
wand will have a very different detection logic: moving this to
a separate file will make it easier and cleaner to implement.
BRANCH=none
BUG=b:67029560
TEST=make buildall -j
TEST=soraka: Base detection still works, power is cut in S5.
Change-Id: Ibc4ad0d9f5ad9a0df7834c712145035f7c62f335
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/851554
Reviewed-by: Furquan Shaikh <furquan@chromium.org>
Diffstat (limited to 'board/poppy')
-rw-r--r-- | board/poppy/base_detect_poppy.c | 219 | ||||
-rw-r--r-- | board/poppy/board.c | 202 | ||||
-rw-r--r-- | board/poppy/board.h | 2 | ||||
-rw-r--r-- | board/poppy/build.mk | 2 |
4 files changed, 223 insertions, 202 deletions
diff --git a/board/poppy/base_detect_poppy.c b/board/poppy/base_detect_poppy.c new file mode 100644 index 0000000000..0361e89c66 --- /dev/null +++ b/board/poppy/base_detect_poppy.c @@ -0,0 +1,219 @@ +/* Copyright 2018 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Poppy/Soraka base detection code */ + +#include "adc.h" +#include "adc_chip.h" +#include "board.h" +#include "chipset.h" +#include "common.h" +#include "console.h" +#include "gpio.h" +#include "hooks.h" +#include "host_command.h" +#include "system.h" +#include "tablet_mode.h" +#include "timer.h" +#include "util.h" + +#define CPRINTS(format, args...) cprints(CC_USB, format, ## args) +#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args) + +/* Base detection and debouncing */ +#define BASE_DETECT_DEBOUNCE_US (20 * MSEC) + +/* + * If the base status is unclear (i.e. not within expected ranges, read + * the ADC value again every 500ms. + */ +#define BASE_DETECT_RETRY_US (500 * MSEC) + +/* + * rev0: Lid has 100K pull-up, base has 5.1K pull-down, so the ADC + * value should be around 5.1/(100+5.1)*3300 = 160. + * >=rev1: Lid has 604K pull-up, base has 30.1K pull-down, so the + * ADC value should be around 30.1/(604+30.1)*3300 = 156 + * + * We add a significant marging on the maximum value, due to noise on the line, + * especially when PWM is active. See b/64193554 for details. + */ +#define BASE_DETECT_MIN_MV 120 +#define BASE_DETECT_MAX_MV 300 + +/* + * When the base is connected in reverse, it presents a 100K pull-down, + * so the ADC value should be around 100/(604+100)*3300 = 469 + * + * TODO(b:64370797): Do something with these values. + */ +#define BASE_DETECT_REVERSE_MIN_MV 450 +#define BASE_DETECT_REVERSE_MAX_MV 500 + +/* Minimum ADC value to indicate base is disconnected for sure */ +#define BASE_DETECT_DISCONNECT_MIN_MV 1500 + +/* + * Base EC pulses detection pin for 500 us to signal out of band USB wake (that + * can be used to wake system from deep S3). + */ +#define BASE_DETECT_PULSE_MIN_US 400 +#define BASE_DETECT_PULSE_MAX_US 650 + +static uint64_t base_detect_debounce_time; + +static void base_detect_deferred(void); +DECLARE_DEFERRED(base_detect_deferred); + +enum base_status { + BASE_UNKNOWN = 0, + BASE_DISCONNECTED = 1, + BASE_CONNECTED = 2, +}; + +static enum base_status current_base_status; + +/* + * This function is called whenever there is a change in the base detect + * status. Actions taken include: + * 1. Change in power to base + * 2. Indicate mode change to host. + * 3. Indicate tablet mode to host. Current assumption is that if base is + * disconnected then the system is in tablet mode, else if the base is + * connected, then the system is not in tablet mode. + */ +static void base_detect_change(enum base_status status) +{ + int connected = (status == BASE_CONNECTED); + + if (current_base_status == status) + return; + + CPRINTS("Base %sconnected", connected ? "" : "not "); + gpio_set_level(GPIO_PP3300_DX_BASE, connected); + host_set_single_event(EC_HOST_EVENT_MODE_CHANGE); + tablet_set_mode(!connected); + current_base_status = status; +} + +/* Measure detection pin pulse duration (used to wake AP from deep S3). */ +static uint64_t pulse_start; +static uint32_t pulse_width; + +static void print_base_detect_value(int v, int tmp_pulse_width) +{ + CPRINTS("%s = %d (pulse %d)", adc_channels[ADC_BASE_DET].name, + v, tmp_pulse_width); +} + +static void base_detect_deferred(void) +{ + uint64_t time_now = get_time().val; + int v; + uint32_t tmp_pulse_width = pulse_width; + + if (base_detect_debounce_time > time_now) { + hook_call_deferred(&base_detect_deferred_data, + base_detect_debounce_time - time_now); + return; + } + + v = adc_read_channel(ADC_BASE_DET); + if (v == ADC_READ_ERROR) + return; + + if (v >= BASE_DETECT_MIN_MV && v <= BASE_DETECT_MAX_MV) { + if (current_base_status != BASE_CONNECTED) { + print_base_detect_value(v, tmp_pulse_width); + base_detect_change(BASE_CONNECTED); + } else if (tmp_pulse_width >= BASE_DETECT_PULSE_MIN_US && + tmp_pulse_width <= BASE_DETECT_PULSE_MAX_US) { + print_base_detect_value(v, tmp_pulse_width); + CPRINTS("Sending event to AP"); + host_set_single_event(EC_HOST_EVENT_KEY_PRESSED); + } + } else if ((v >= BASE_DETECT_REVERSE_MIN_MV && + v <= BASE_DETECT_REVERSE_MAX_MV) || + v >= BASE_DETECT_DISCONNECT_MIN_MV) { + /* TODO(b/35585396): Handle reverse connection separately. */ + + print_base_detect_value(v, tmp_pulse_width); + + base_detect_change(BASE_DISCONNECTED); + } else { + /* Unclear base status, schedule again in a while. */ + hook_call_deferred(&base_detect_deferred_data, + BASE_DETECT_RETRY_US); + } +} + +static inline int detect_pin_connected(enum gpio_signal det_pin) +{ + return gpio_get_level(det_pin) == 0; +} + +void base_detect_interrupt(enum gpio_signal signal) +{ + uint64_t time_now = get_time().val; + + if (base_detect_debounce_time <= time_now) { + /* + * Detect and measure detection pin pulse, when base is + * connected. Only a single pulse is measured over a debounce + * period. If no pulse, or multiple pulses are detected, + * pulse_width is set to 0. + */ + if (current_base_status == BASE_CONNECTED && + !detect_pin_connected(signal)) { + pulse_start = time_now; + } else { + pulse_start = 0; + } + pulse_width = 0; + + hook_call_deferred(&base_detect_deferred_data, + BASE_DETECT_DEBOUNCE_US); + } else { + if (current_base_status == BASE_CONNECTED && + detect_pin_connected(signal) && !pulse_width && + pulse_start) { + /* First pulse within period. */ + pulse_width = time_now - pulse_start; + } else { + pulse_start = 0; + pulse_width = 0; + } + } + + base_detect_debounce_time = time_now + BASE_DETECT_DEBOUNCE_US; +} + +static void base_enable(void) +{ + /* Enable base detection interrupt. */ + base_detect_debounce_time = get_time().val; + hook_call_deferred(&base_detect_deferred_data, 0); + gpio_enable_interrupt(GPIO_BASE_DET_A); +} +DECLARE_HOOK(HOOK_CHIPSET_STARTUP, base_enable, HOOK_PRIO_DEFAULT); + +static void base_disable(void) +{ + /* Disable base detection interrupt and disable power to base. */ + gpio_disable_interrupt(GPIO_BASE_DET_A); + base_detect_change(BASE_DISCONNECTED); +} +DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, base_disable, HOOK_PRIO_DEFAULT); + +static void base_init(void) +{ + /* + * If we jumped to this image and chipset is already in S0, enable + * base. + */ + if (system_jumped_to_this_image() && chipset_in_state(CHIPSET_STATE_ON)) + base_enable(); +} +DECLARE_HOOK(HOOK_INIT, base_init, HOOK_PRIO_DEFAULT+1); diff --git a/board/poppy/board.c b/board/poppy/board.c index ce54be5e97..3cc8100728 100644 --- a/board/poppy/board.c +++ b/board/poppy/board.c @@ -139,86 +139,6 @@ void anx74xx_cable_det_interrupt(enum gpio_signal signal) } #endif -/* Base detection and debouncing */ -#define BASE_DETECT_DEBOUNCE_US (20 * MSEC) - -/* - * If the base status is unclear (i.e. not within expected ranges, read - * the ADC value again every 500ms. - */ -#define BASE_DETECT_RETRY_US (500 * MSEC) - -/* - * rev0: Lid has 100K pull-up, base has 5.1K pull-down, so the ADC - * value should be around 5.1/(100+5.1)*3300 = 160. - * >=rev1: Lid has 604K pull-up, base has 30.1K pull-down, so the - * ADC value should be around 30.1/(604+30.1)*3300 = 156 - * - * We add a significant marging on the maximum value, due to noise on the line, - * especially when PWM is active. See b/64193554 for details. - */ -#define BASE_DETECT_MIN_MV 120 -#define BASE_DETECT_MAX_MV 300 - -/* - * When the base is connected in reverse, it presents a 100K pull-down, - * so the ADC value should be around 100/(604+100)*3300 = 469 - * - * TODO(b:64370797): Do something with these values. - */ -#define BASE_DETECT_REVERSE_MIN_MV 450 -#define BASE_DETECT_REVERSE_MAX_MV 500 - -/* Minimum ADC value to indicate base is disconnected for sure */ -#define BASE_DETECT_DISCONNECT_MIN_MV 1500 - -/* - * Base EC pulses detection pin for 500 us to signal out of band USB wake (that - * can be used to wake system from deep S3). - */ -#define BASE_DETECT_PULSE_MIN_US 400 -#define BASE_DETECT_PULSE_MAX_US 650 - -static uint64_t base_detect_debounce_time; - -static void base_detect_deferred(void); -DECLARE_DEFERRED(base_detect_deferred); - -enum base_status { - BASE_UNKNOWN = 0, - BASE_DISCONNECTED = 1, - BASE_CONNECTED = 2, -}; - -static enum base_status current_base_status; - -/* - * This function is called whenever there is a change in the base detect - * status. Actions taken include: - * 1. Change in power to base - * 2. Indicate mode change to host. - * 3. Indicate tablet mode to host. Current assumption is that if base is - * disconnected then the system is in tablet mode, else if the base is - * connected, then the system is not in tablet mode. - */ -static void base_detect_change(enum base_status status) -{ - int connected = (status == BASE_CONNECTED); - - if (current_base_status == status) - return; - - CPRINTS("Base %sconnected", connected ? "" : "not "); - gpio_set_level(GPIO_PP3300_DX_BASE, connected); - host_set_single_event(EC_HOST_EVENT_MODE_CHANGE); - tablet_set_mode(!connected); - current_base_status = status; -} - -/* Measure detection pin pulse duration (used to wake AP from deep S3). */ -static uint64_t pulse_start; -static uint32_t pulse_width; - static int command_attach_base(int argc, char **argv) { host_set_single_event(EC_HOST_EVENT_MODE_CHANGE); @@ -237,109 +157,6 @@ static int command_detach_base(int argc, char **argv) DECLARE_CONSOLE_COMMAND(detachbase, command_detach_base, NULL, "Simulate detach base"); -static void print_base_detect_value(int v, int tmp_pulse_width) -{ - CPRINTS("%s = %d (pulse %d)", adc_channels[ADC_BASE_DET].name, - v, tmp_pulse_width); -} - -static void base_detect_deferred(void) -{ - uint64_t time_now = get_time().val; - int v; - uint32_t tmp_pulse_width = pulse_width; - - if (base_detect_debounce_time > time_now) { - hook_call_deferred(&base_detect_deferred_data, - base_detect_debounce_time - time_now); - return; - } - - v = adc_read_channel(ADC_BASE_DET); - if (v == ADC_READ_ERROR) - return; - - if (v >= BASE_DETECT_MIN_MV && v <= BASE_DETECT_MAX_MV) { - if (current_base_status != BASE_CONNECTED) { - print_base_detect_value(v, tmp_pulse_width); - base_detect_change(BASE_CONNECTED); - } else if (tmp_pulse_width >= BASE_DETECT_PULSE_MIN_US && - tmp_pulse_width <= BASE_DETECT_PULSE_MAX_US) { - print_base_detect_value(v, tmp_pulse_width); - CPRINTS("Sending event to AP"); - host_set_single_event(EC_HOST_EVENT_KEY_PRESSED); - } - } else if ((v >= BASE_DETECT_REVERSE_MIN_MV && - v <= BASE_DETECT_REVERSE_MAX_MV) || - v >= BASE_DETECT_DISCONNECT_MIN_MV) { - /* TODO(b/35585396): Handle reverse connection separately. */ - - print_base_detect_value(v, tmp_pulse_width); - - base_detect_change(BASE_DISCONNECTED); - } else { - /* Unclear base status, schedule again in a while. */ - hook_call_deferred(&base_detect_deferred_data, - BASE_DETECT_RETRY_US); - } -} - -static inline int detect_pin_connected(enum gpio_signal det_pin) -{ - return gpio_get_level(det_pin) == 0; -} - -void base_detect_interrupt(enum gpio_signal signal) -{ - uint64_t time_now = get_time().val; - - if (base_detect_debounce_time <= time_now) { - /* - * Detect and measure detection pin pulse, when base is - * connected. Only a single pulse is measured over a debounce - * period. If no pulse, or multiple pulses are detected, - * pulse_width is set to 0. - */ - if (current_base_status == BASE_CONNECTED && - !detect_pin_connected(signal)) { - pulse_start = time_now; - } else { - pulse_start = 0; - } - pulse_width = 0; - - hook_call_deferred(&base_detect_deferred_data, - BASE_DETECT_DEBOUNCE_US); - } else { - if (current_base_status == BASE_CONNECTED && - detect_pin_connected(signal) && !pulse_width && - pulse_start) { - /* First pulse within period. */ - pulse_width = time_now - pulse_start; - } else { - pulse_start = 0; - pulse_width = 0; - } - } - - base_detect_debounce_time = time_now + BASE_DETECT_DEBOUNCE_US; -} - -static void base_enable(void) -{ - /* Enable base detection interrupt. */ - base_detect_debounce_time = get_time().val; - hook_call_deferred(&base_detect_deferred_data, 0); - gpio_enable_interrupt(GPIO_BASE_DET_A); -} - -static void base_disable(void) -{ - /* Disable base detection interrupt and disable power to base. */ - gpio_disable_interrupt(GPIO_BASE_DET_A); - base_detect_change(BASE_DISCONNECTED); -} - #include "gpio_list.h" /* power signal list. Must match order of enum power_signal. */ @@ -730,13 +547,6 @@ static void board_init(void) gpio_enable_interrupt(GPIO_USB_C1_BC12_INT_L); /* - * If we jumped to this image and chipset is already in S0, enable - * base. - */ - if (system_jumped_to_this_image() && chipset_in_state(CHIPSET_STATE_ON)) - base_enable(); - - /* * Set unused GPIO_LED_YELLO_C0[_OLD] as INPUT | PULL_UP * for better S0ix/S3 power */ @@ -1120,18 +930,6 @@ static void board_chipset_suspend(void) } DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, board_chipset_suspend, HOOK_PRIO_DEFAULT); -static void board_chipset_startup(void) -{ - base_enable(); -} -DECLARE_HOOK(HOOK_CHIPSET_STARTUP, board_chipset_startup, HOOK_PRIO_DEFAULT); - -static void board_chipset_shutdown(void) -{ - base_disable(); -} -DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, board_chipset_shutdown, HOOK_PRIO_DEFAULT); - int board_has_working_reset_flags(void) { int version = system_get_board_version(); diff --git a/board/poppy/board.h b/board/poppy/board.h index 083f764c17..41aa1f19d9 100644 --- a/board/poppy/board.h +++ b/board/poppy/board.h @@ -250,6 +250,8 @@ int board_get_version(void); void board_reset_pd_mcu(void); void board_set_tcpc_power_mode(int port, int mode); +void base_detect_interrupt(enum gpio_signal signal); + #endif /* !__ASSEMBLER__ */ #endif /* __CROS_EC_BOARD_H */ diff --git a/board/poppy/build.mk b/board/poppy/build.mk index d8ae2af836..194869ba1b 100644 --- a/board/poppy/build.mk +++ b/board/poppy/build.mk @@ -13,3 +13,5 @@ board-y=board.o board-$(CONFIG_BATTERY_SMART)+=battery.o board-$(CONFIG_LED_COMMON)+=led.o board-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_policy.o +board-$(BOARD_POPPY)+=base_detect_poppy.o +board-$(BOARD_SORAKA)+=base_detect_poppy.o |