summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAseda Aboagye <aaboagye@google.com>2018-01-21 13:17:03 +0800
committerchrome-bot <chrome-bot@chromium.org>2018-03-20 00:00:31 -0700
commit84f8f46851d6a5ef56a10900919b00095413d0a0 (patch)
treec480bcf704a81267d3782dd9104a896e1daf0dde
parent48d6891db8b5b2b0825136f6f9013a110b2a98da (diff)
downloadchrome-ec-84f8f46851d6a5ef56a10900919b00095413d0a0.tar.gz
meowth: Add support for base detection.
Meowth has two analog detection pins with which it monitors to determine the base status: the attach, and detach pins. When the voltages cross a certain threshold, after some debouncing, the base is deemed connected. Meowth then applies the base power and monitors for power faults from the eFuse as well as base disconnection. Similarly, once the voltages cross a different threshold, after some debouncing, the base is deemed disconnected. At this point, Meowth disables the base power. BUG=b:69140200 BRANCH=None TEST=Verify that we can detect a base attach and detach. TEST=Verify that when base is attached, tablet mode goes to 0, and goes to 1 when the base is detached. TEST=Connect base, take a paper clip and short the attach pin to ground to trigger a fault 4 times in a row. Verify that base power is disabled yet base detect state machine still reports attached. Wait at least 1s, physically detach and reattach base, verify that base power is re-enabled. Change-Id: I2a069fc450c2232c7eae02b8e7459d38a049668a Signed-off-by: Aseda Aboagye <aaboagye@google.com> Reviewed-on: https://chromium-review.googlesource.com/923396 Commit-Ready: Aseda Aboagye <aaboagye@chromium.org> Tested-by: Aseda Aboagye <aaboagye@chromium.org> Reviewed-by: Nicolas Boichat <drinkcat@chromium.org>
-rw-r--r--board/zoombini/base_detect.c249
-rw-r--r--board/zoombini/board.c10
-rw-r--r--board/zoombini/board.h7
-rw-r--r--board/zoombini/build.mk1
-rw-r--r--board/zoombini/gpio.inc4
5 files changed, 268 insertions, 3 deletions
diff --git a/board/zoombini/base_detect.c b/board/zoombini/base_detect.c
new file mode 100644
index 0000000000..3d6f0a8015
--- /dev/null
+++ b/board/zoombini/base_detect.c
@@ -0,0 +1,249 @@
+/* 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.
+ */
+
+/*
+ * Meowth base detection code.
+ *
+ * Meowth has two analog detection pins with which it monitors to determine the
+ * base status: the attach, and detach pins.
+ *
+ * When the voltages cross a certain threshold, after some debouncing, the base
+ * is deemed connected. Meowth then applies the base power and monitors for
+ * power faults from the eFuse as well as base disconnection. Similarly, once
+ * the voltages cross a different threshold, after some debouncing, the base is
+ * deemed disconnected. At this point, Meowth disables the base power.
+ */
+
+#include "adc.h"
+#include "common.h"
+#include "console.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "tablet_mode.h"
+#include "timer.h"
+#include "util.h"
+
+#define CPRINTS(format, args...) cprints(CC_USB, format, ## args)
+
+#define DEFAULT_POLL_TIMEOUT_US (250 * MSEC)
+#define DEBOUNCE_TIMEOUT_US (20 * MSEC)
+#define POWER_FAULT_RETRY_INTERVAL_US (15 * MSEC)
+
+/*
+ * Number of times to attempt re-applying power within 1s when a fault occurs.
+ */
+#define POWER_FAULT_MAX_RETRIES 3
+
+/* Thresholds for attach pin reading when power is not applied. */
+#define ATTACH_MIN_MV 300
+#define ATTACH_MAX_MV 800
+
+/* Threshold for attach pin reading when power IS applied. */
+#define PWREN_ATTACH_MIN_MV 2300
+
+/* Threshold for detach pin reading. */
+#define DETACH_MIN_MV 10
+
+
+enum base_detect_state {
+ BASE_DETACHED = 0,
+ BASE_ATTACHED_DEBOUNCE,
+ BASE_ATTACHED,
+ BASE_DETACHED_DEBOUNCE,
+};
+
+static int debug;
+static enum base_detect_state state;
+
+static void base_detect_changed(void)
+{
+ switch (state) {
+ case BASE_DETACHED:
+ /* Indicate that we are in tablet mode. */
+ tablet_set_mode(1);
+
+ /*
+ * Disable power fault interrupt. It will read low when base
+ * power is removed.
+ */
+ gpio_disable_interrupt(GPIO_BASE_PWR_FLT_L);
+ /* Now, remove power to the base. */
+ gpio_set_level(GPIO_BASE_PWR_EN, 0);
+ break;
+
+ case BASE_ATTACHED:
+ /*
+ * TODO(b/73133611): Note, this simple logic may suffice for
+ * now, but we may have to revisit this.
+ */
+ tablet_set_mode(0);
+
+ /* Apply power to the base. */
+ gpio_set_level(GPIO_BASE_PWR_EN, 1);
+ /* Allow time for the fault line to rise. */
+ msleep(1);
+ /* Monitor for base power faults. */
+ gpio_enable_interrupt(GPIO_BASE_PWR_FLT_L);
+ break;
+
+ default:
+ return;
+ };
+}
+
+static int base_seems_attached(int attach_pin_mv, int detach_pin_mv)
+{
+ /* We can't tell if we don't have good readings. */
+ if (attach_pin_mv == ADC_READ_ERROR ||
+ detach_pin_mv == ADC_READ_ERROR)
+ return 0;
+
+ if (gpio_get_level(GPIO_BASE_PWR_EN))
+ return (attach_pin_mv >= PWREN_ATTACH_MIN_MV) &&
+ (detach_pin_mv >= DETACH_MIN_MV);
+ else
+ return (attach_pin_mv <= ATTACH_MAX_MV) &&
+ (attach_pin_mv >= ATTACH_MIN_MV) &&
+ (detach_pin_mv <= DETACH_MIN_MV);
+}
+
+static int base_seems_detached(int attach_pin_mv, int detach_pin_mv)
+{
+ /* We can't tell if we don't have good readings. */
+ if (attach_pin_mv == ADC_READ_ERROR ||
+ detach_pin_mv == ADC_READ_ERROR)
+ return 0;
+
+ return (attach_pin_mv >= PWREN_ATTACH_MIN_MV) &&
+ (detach_pin_mv <= DETACH_MIN_MV);
+}
+
+static void set_state(enum base_detect_state new_state)
+{
+ if (new_state != state) {
+ CPRINTS("BD: st%d", new_state);
+ state = new_state;
+ }
+}
+
+static void base_detect_deferred(void);
+DECLARE_DEFERRED(base_detect_deferred);
+static void base_detect_deferred(void)
+{
+ int attach_reading;
+ int detach_reading;
+ int timeout = DEFAULT_POLL_TIMEOUT_US;
+
+ attach_reading = adc_read_channel(ADC_BASE_ATTACH);
+ detach_reading = adc_read_channel(ADC_BASE_DETACH);
+
+ if (debug)
+ CPRINTS("BD st%d: att: %dmV det: %dmV", state,
+ attach_reading,
+ detach_reading);
+
+ switch (state) {
+ case BASE_DETACHED:
+ /* Check to see if a base may be attached. */
+ if (base_seems_attached(attach_reading, detach_reading)) {
+ timeout = DEBOUNCE_TIMEOUT_US;
+ set_state(BASE_ATTACHED_DEBOUNCE);
+ }
+ break;
+
+ case BASE_ATTACHED_DEBOUNCE:
+ /* Check to see if it's still attached. */
+ if (base_seems_attached(attach_reading, detach_reading)) {
+ set_state(BASE_ATTACHED);
+ base_detect_changed();
+ } else if (base_seems_detached(attach_reading,
+ detach_reading)) {
+ set_state(BASE_DETACHED);
+ }
+ break;
+
+ case BASE_ATTACHED:
+ /* Check to see if a base may be detached. */
+ if (base_seems_detached(attach_reading, detach_reading)) {
+ timeout = DEBOUNCE_TIMEOUT_US;
+ set_state(BASE_DETACHED_DEBOUNCE);
+ }
+ break;
+
+ case BASE_DETACHED_DEBOUNCE:
+ /* Check to see if a base is still detached. */
+ if (base_seems_detached(attach_reading, detach_reading)) {
+ set_state(BASE_DETACHED);
+ base_detect_changed();
+ } else if (base_seems_attached(attach_reading,
+ detach_reading)) {
+ set_state(BASE_ATTACHED);
+ }
+ break;
+ /* TODO(b/74239259): do you want to add an interrupt? */
+
+ default:
+ break;
+ };
+
+ /* Check again in the appropriate time. */
+ hook_call_deferred(&base_detect_deferred_data, timeout);
+};
+DECLARE_HOOK(HOOK_INIT, base_detect_deferred, HOOK_PRIO_INIT_ADC + 1);
+
+static uint8_t base_power_on_attempts;
+static void clear_base_power_on_attempts_deferred(void)
+{
+ base_power_on_attempts = 0;
+}
+DECLARE_DEFERRED(clear_base_power_on_attempts_deferred);
+
+static void check_and_reapply_base_power_deferred(void)
+{
+ if (state != BASE_ATTACHED)
+ return;
+
+ if (base_power_on_attempts < POWER_FAULT_MAX_RETRIES) {
+ CPRINTS("Reapply base pwr");
+ gpio_set_level(GPIO_BASE_PWR_EN, 1);
+ base_power_on_attempts++;
+
+ hook_call_deferred(&clear_base_power_on_attempts_deferred_data,
+ SECOND);
+ }
+
+}
+DECLARE_DEFERRED(check_and_reapply_base_power_deferred);
+
+void base_pwr_fault_interrupt(enum gpio_signal s)
+{
+ /* Inverted because active low. */
+ int fault_detected = !gpio_get_level(GPIO_BASE_PWR_FLT_L);
+
+ if (fault_detected) {
+ /* Turn off base power. */
+ CPRINTS("Base Pwr Flt!");
+ gpio_set_level(GPIO_BASE_PWR_EN, 0);
+
+ /*
+ * Try and apply power in a bit if maybe it was just a temporary
+ * condition.
+ */
+ hook_call_deferred(&check_and_reapply_base_power_deferred_data,
+ POWER_FAULT_RETRY_INTERVAL_US);
+ }
+}
+
+static int command_basedetectdebug(int argc, char **argv)
+{
+ if ((argc > 1) && !parse_bool(argv[1], &debug))
+ return EC_ERROR_PARAM1;
+
+ CPRINTS("BD: st%d", state);
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(basedebug, command_basedetectdebug, "[ena|dis]",
+ "En/Disable base detection debug");
diff --git a/board/zoombini/board.c b/board/zoombini/board.c
index 3a39aafa1e..2044f36a4e 100644
--- a/board/zoombini/board.c
+++ b/board/zoombini/board.c
@@ -3,7 +3,7 @@
* found in the LICENSE file.
*/
-/* Zoombini board-specific configuration */
+/* Meowth/Zoombini board-specific configuration */
#include "adc_chip.h"
#include "button.h"
@@ -123,6 +123,14 @@ const struct adc_t adc_channels[] = {
[ADC_TEMP_SENSOR_WIFI] = {
"WIFI", NPCX_ADC_CH8, ADC_MAX_VOLT, ADC_READ_MAX + 1, 0
},
+
+ [ADC_BASE_ATTACH] = {
+ "BASE ATTACH", NPCX_ADC_CH9, ADC_MAX_VOLT, ADC_READ_MAX + 1, 0
+ },
+
+ [ADC_BASE_DETACH] = {
+ "BASE DETACH", NPCX_ADC_CH4, ADC_MAX_VOLT, ADC_READ_MAX + 1, 0
+ },
#endif /* defined(BOARD_ZOOMBINI) */
};
diff --git a/board/zoombini/board.h b/board/zoombini/board.h
index b940a2275e..184a439ee2 100644
--- a/board/zoombini/board.h
+++ b/board/zoombini/board.h
@@ -3,7 +3,7 @@
* found in the LICENSE file.
*/
-/* Zoombini board configuration */
+/* Meowth/Zoombini board configuration */
#ifndef __CROS_EC_BOARD_H
#define __CROS_EC_BOARD_H
@@ -222,6 +222,8 @@ enum adc_channel {
ADC_TEMP_SENSOR_CHARGER,
#ifdef BOARD_MEOWTH
ADC_TEMP_SENSOR_WIFI,
+ ADC_BASE_ATTACH,
+ ADC_BASE_DETACH,
#endif /* defined(BOARD_MEOWTH) */
ADC_CH_COUNT
};
@@ -268,6 +270,9 @@ enum sensor_id {
#ifdef BOARD_MEOWTH
int board_get_version(void);
#endif /* defined(BOARD_MEOWTH) */
+
+void base_pwr_fault_interrupt(enum gpio_signal s);
+
/* Reset all TCPCs. */
void board_reset_pd_mcu(void);
diff --git a/board/zoombini/build.mk b/board/zoombini/build.mk
index 7f88bbfaa7..a24c848e65 100644
--- a/board/zoombini/build.mk
+++ b/board/zoombini/build.mk
@@ -11,3 +11,4 @@ CHIP_FAMILY:=npcx7
CHIP_VARIANT:=npcx7m6f
board-y=battery.o board.o led.o usb_pd_policy.o
+board-$(BOARD_MEOWTH)+=base_detect.o
diff --git a/board/zoombini/gpio.inc b/board/zoombini/gpio.inc
index 4cad17dd02..8f833bc9be 100644
--- a/board/zoombini/gpio.inc
+++ b/board/zoombini/gpio.inc
@@ -154,12 +154,14 @@ GPIO_INT(PMIC_DPWROK, PIN(F, 4), GPIO_INT_BOTH, power_signal_interrupt)
GPIO_INT(PMIC_INT_L, PIN(D, 5), GPIO_INT_FALLING | GPIO_PULL_UP, power_signal_interrupt)
GPIO_INT(VOLUME_UP_L, PIN(7, 5), GPIO_INT_BOTH | GPIO_PULL_UP, button_interrupt)
GPIO_INT(VOLUME_DOWN_L, PIN(6, 3), GPIO_INT_BOTH | GPIO_PULL_UP, button_interrupt)
+GPIO_INT(BASE_PWR_FLT_L, PIN(2, 4), GPIO_INT_FALLING, base_pwr_fault_interrupt)
/* Power Enables. */
GPIO(EN_PP3300_DSW, PIN(8, 2), GPIO_OUT_LOW)
GPIO(EN_PP5000, PIN(7, 3), GPIO_OUT_LOW)
GPIO(EN_PP1800_U, PIN(A, 0), GPIO_OUT_LOW)
GPIO(EN_PP3300_WLAN, PIN(8, 3), GPIO_OUT_HIGH)
+GPIO(BASE_PWR_EN, PIN(2, 2), GPIO_OUT_LOW)
GPIO(ENTERING_RW, PIN(E, 1), GPIO_OUT_LOW)
GPIO(CCD_MODE_ODL, PIN(E, 3), GPIO_INPUT) /* Case Closed Debug mode. */
@@ -219,7 +221,7 @@ ALTERNATE(PIN_MASK(C, 0x01), 1, MODULE_PWM, 0) /* DB1 Blue LED (M) */
/* ADC */
ALTERNATE(PIN_MASK(4, 0x32), 1, MODULE_ADC, 0) /* ADC0-1,4 */
-ALTERNATE(PIN_MASK(F, 0x02), 1, MODULE_ADC, 0) /* ADC8 */
+ALTERNATE(PIN_MASK(F, 0x03), 1, MODULE_ADC, 0) /* ADC8-9 */
/* Power Switch Logic (PSL) inputs */
ALTERNATE(PIN_MASK(0, 0x03), 1, MODULE_PMU, 0) /* GPIO00, GPIO01 */