diff options
author | Wai-Hong Tam <waihong@google.com> | 2018-08-15 16:48:04 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-08-29 11:16:17 -0700 |
commit | 674a12a4fc0bd9bc13822045a3fbd91fab279644 (patch) | |
tree | 4bf70f26f200c98f90d497c3557de901c2cb0866 /board/cheza | |
parent | 2e4cd7bef7ef671d49ea7bb3ae55e9df970d8e25 (diff) | |
download | chrome-ec-674a12a4fc0bd9bc13822045a3fbd91fab279644.tar.gz |
cheza: Support base detection
The base detection logic is similar to Lux base. But Cheza one doesn't
have a battery inside. So skip the dual-battery charging logic and give
the power to the base right after it is plugged.
BRANCH=none
BUG=b:112614067
TEST=Remove the base battery. Plug and unplug the base. Check the EC
messages showing the base connected and disconnected.
Change-Id: I363860609b17ae74c09ccdb681c99123f7a38a06
Signed-off-by: Wai-Hong Tam <waihong@google.com>
Reviewed-on: https://chromium-review.googlesource.com/1176732
Reviewed-by: Stephen Boyd <swboyd@chromium.org>
Diffstat (limited to 'board/cheza')
-rw-r--r-- | board/cheza/base_detect.c | 186 | ||||
-rw-r--r-- | board/cheza/board.h | 5 | ||||
-rw-r--r-- | board/cheza/build.mk | 2 | ||||
-rw-r--r-- | board/cheza/gpio.inc | 3 |
4 files changed, 194 insertions, 2 deletions
diff --git a/board/cheza/base_detect.c b/board/cheza/base_detect.c new file mode 100644 index 0000000000..b70b6b3433 --- /dev/null +++ b/board/cheza/base_detect.c @@ -0,0 +1,186 @@ +/* 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. + */ + +/* Lux base without battery detection code */ + +#include "adc.h" +#include "adc_chip.h" +#include "board.h" +#include "chipset.h" +#include "common.h" +#include "console.h" +#include "extpower.h" +#include "gpio.h" +#include "hooks.h" +#include "host_command.h" +#include "system.h" +#include "tablet_mode.h" +#include "task.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) + +/* + * When base is disconnected, and gets connected: + * Lid has 1M pull-up, base has 200K pull-down, so the ADC + * value should be around 200/(200+1000)*3300 = 550. + * + * Idle value should be ~3300: lid has 1M pull-up, and nothing else (i.e. ADC + * maxing out at 2813). + */ +#define BASE_DISCONNECTED_CONNECT_MIN_MV 450 +#define BASE_DISCONNECTED_CONNECT_MAX_MV 650 + +#define BASE_DISCONNECTED_MIN_MV 2800 +#define BASE_DISCONNECTED_MAX_MV (ADC_MAX_VOLT+1) + +/* + * When base is connected, then gets disconnected: + * Lid has 1M pull-up, lid has 10.0K pull-down, so the ADC + * value should be around 10.0/(10.0+1000)*3300 = 33. + * + * Idle level when connected should be: + * Lid has 10K pull-down, base has 5.1K pull-up, so the ADC value should be + * around 10.0/(10.0+5.1)*3300 = 2185 (actual value is 2153 as there is still + * a 1M pull-up on lid, and 200K pull-down on base). + */ +#define BASE_CONNECTED_DISCONNECT_MIN_MV 20 +#define BASE_CONNECTED_DISCONNECT_MAX_MV 45 + +#define BASE_CONNECTED_MIN_MV 2050 +#define BASE_CONNECTED_MAX_MV 2300 + +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. Enable/disable pull-down on half-duplex UART line + * 2. Enable/disable power to base. + * 3. Indicate mode change to host. + * 4. 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; + + current_base_status = status; + + /* Enable pull-down if connected. */ + gpio_set_level(GPIO_EN_CC_LID_BASE_PULLDN, !connected); + + /* We don't enable dual-battery support. Set the base power directly. */ + gpio_set_level(GPIO_EN_PPVAR_VAR_BASE, connected); + + tablet_set_mode(!connected); +} + +static void print_base_detect_value(const char *str, int v) +{ + CPRINTS("Base %s. ADC: %d", str, v); +} + +static void base_detect_deferred(void) +{ + uint64_t time_now = get_time().val; + int v; + + 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) + goto retry; + + if (current_base_status == BASE_CONNECTED) { + if (v >= BASE_CONNECTED_DISCONNECT_MIN_MV && + v <= BASE_CONNECTED_DISCONNECT_MAX_MV) { + print_base_detect_value("disconnected", v); + base_detect_change(BASE_DISCONNECTED); + return; + } else if (v >= BASE_CONNECTED_MIN_MV && + v <= BASE_CONNECTED_MAX_MV) { + /* Still connected. */ + return; + } + } else { /* Disconnected or unknown. */ + if (v >= BASE_DISCONNECTED_CONNECT_MIN_MV && + v <= BASE_DISCONNECTED_CONNECT_MAX_MV) { + print_base_detect_value("connected", v); + base_detect_change(BASE_CONNECTED); + return; + } else if (v >= BASE_DISCONNECTED_MIN_MV && + v <= BASE_DISCONNECTED_MAX_MV) { + if (current_base_status == BASE_UNKNOWN) { + print_base_detect_value("disconnected", v); + base_detect_change(BASE_DISCONNECTED); + } + /* Still disconnected. */ + return; + } + } + +retry: + print_base_detect_value("status unclear", v); + /* Unclear base status, schedule again in a while. */ + hook_call_deferred(&base_detect_deferred_data, + BASE_DETECT_RETRY_US); +} + +void base_detect_interrupt(enum gpio_signal signal) +{ + uint64_t time_now = get_time().val; + + if (base_detect_debounce_time <= time_now) + hook_call_deferred(&base_detect_deferred_data, + BASE_DETECT_DEBOUNCE_US); + + base_detect_debounce_time = time_now + BASE_DETECT_DEBOUNCE_US; +} + +static void base_init(void) +{ + /* + * Make sure base power and pull-down are off. This will reset the base + * if it is already connected. + */ + gpio_set_level(GPIO_EN_PPVAR_VAR_BASE, 0); + gpio_set_level(GPIO_EN_CC_LID_BASE_PULLDN, 1); + + /* Enable base detection interrupt. */ + hook_call_deferred(&base_detect_deferred_data, BASE_DETECT_DEBOUNCE_US); + gpio_enable_interrupt(GPIO_CC_LID_BASE_ADC); +} +DECLARE_HOOK(HOOK_INIT, base_init, HOOK_PRIO_DEFAULT+1); diff --git a/board/cheza/board.h b/board/cheza/board.h index ab722c2aec..6c7ac79229 100644 --- a/board/cheza/board.h +++ b/board/cheza/board.h @@ -54,6 +54,9 @@ #define CONFIG_LID_SWITCH #define CONFIG_EXTPOWER_GPIO +#define CONFIG_TABLET_MODE +#define CONFIG_TABLET_MODE_SWITCH + /* Battery */ #define CONFIG_BATTERY_CUT_OFF #define CONFIG_BATTERY_PRESENT_GPIO GPIO_BATT_PRES_ODL @@ -183,6 +186,8 @@ int board_is_sourcing_vbus(int port); int board_vbus_sink_enable(int port, int enable); /* Reset all TCPCs. */ void board_reset_pd_mcu(void); +/* Base detection interrupt handler */ +void base_detect_interrupt(enum gpio_signal signal); #endif /* !defined(__ASSEMBLER__) */ diff --git a/board/cheza/build.mk b/board/cheza/build.mk index 3958fb483e..2e8e53ec88 100644 --- a/board/cheza/build.mk +++ b/board/cheza/build.mk @@ -10,4 +10,4 @@ CHIP:=npcx CHIP_FAMILY:=npcx7 CHIP_VARIANT:=npcx7m7wb -board-y=battery.o board.o led.o usb_pd_policy.o +board-y=battery.o board.o led.o usb_pd_policy.o base_detect.o diff --git a/board/cheza/gpio.inc b/board/cheza/gpio.inc index 707b51a850..d9e4aafb38 100644 --- a/board/cheza/gpio.inc +++ b/board/cheza/gpio.inc @@ -33,6 +33,7 @@ GPIO_INT(PS_HOLD, PIN(D, 4), GPIO_INT_BOTH | GPIO_SEL_1P8V, power_sign GPIO_INT(PMIC_FAULT_L, PIN(7, 6), GPIO_INT_BOTH | GPIO_SEL_1P8V, power_signal_interrupt) /* Any PMIC fault? */ GPIO_INT(POWER_GOOD, PIN(5, 4), GPIO_INT_BOTH | GPIO_SEL_1P8V, power_signal_interrupt) /* SRC_PP1800_S4A from PMIC */ GPIO_INT(SHI_CS_L, PIN(5, 3), GPIO_INT_FALLING | GPIO_PULL_DOWN | GPIO_SEL_1P8V, shi_cs_event) /* AP_EC_SPI_CS_L */ +GPIO_INT(CC_LID_BASE_ADC, PIN(4, 5), GPIO_INT_BOTH, base_detect_interrupt) /* Base detection */ GPIO(EC_SELF_RST, PIN(E, 0), GPIO_OUT_LOW) /* Self-reset EC */ GPIO(EC_RST_ODL, PIN(0, 2), GPIO_INPUT) /* Wake source: EC reset */ @@ -148,7 +149,7 @@ ALTERNATE(PIN_MASK(9, 0x07), 1, MODULE_I2C, 0) /* I2C1 SDA (GPIO90), ALTERNATE(PIN_MASK(8, 0x80), 1, MODULE_I2C, 0) /* I2C1 SCL (GPIO87) */ ALTERNATE(PIN_MASK(3, 0x48), 1, MODULE_I2C, 0) /* I2C5 (GPIO33/36) */ ALTERNATE(PIN_MASK(B, 0x0C), 1, MODULE_I2C, GPIO_SEL_1P8V) /* I2C7 (GPIOB2/B3) - 1.8V */ -ALTERNATE(PIN_MASK(4, 0x2C), 0, MODULE_ADC, 0) /* ADC0 (GPIO45), ADC2 (GPIO43), ADC3 (GPIO42) */ +ALTERNATE(PIN_MASK(4, 0x0C), 0, MODULE_ADC, 0) /* ADC2 (GPIO43), ADC3 (GPIO42) */ ALTERNATE(PIN_MASK(4, 0xC0), 1, MODULE_SPI, GPIO_SEL_1P8V) /* SHI_SDO (GPIO47), SHI_SDI (GPIO46) */ ALTERNATE(PIN_MASK(5, 0x28), 1, MODULE_SPI, GPIO_SEL_1P8V) /* SHI_SCLK (GPIO55), SHI_CS# (GPIO53) */ ALTERNATE(PIN_MASK(B, 0x80), 1, MODULE_PWM, 0) /* PWM5 (GPIOB7) */ |