summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWai-Hong Tam <waihong@google.com>2018-08-15 16:48:04 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-08-29 11:16:17 -0700
commit674a12a4fc0bd9bc13822045a3fbd91fab279644 (patch)
tree4bf70f26f200c98f90d497c3557de901c2cb0866
parent2e4cd7bef7ef671d49ea7bb3ae55e9df970d8e25 (diff)
downloadchrome-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>
-rw-r--r--board/cheza/base_detect.c186
-rw-r--r--board/cheza/board.h5
-rw-r--r--board/cheza/build.mk2
-rw-r--r--board/cheza/gpio.inc3
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) */