diff options
Diffstat (limited to 'board/cr50/ec_state.c')
-rw-r--r-- | board/cr50/ec_state.c | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/board/cr50/ec_state.c b/board/cr50/ec_state.c new file mode 100644 index 0000000000..5958ea3b79 --- /dev/null +++ b/board/cr50/ec_state.c @@ -0,0 +1,112 @@ +/* Copyright 2017 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. + * + * EC detect state machine. + */ +#include "common.h" +#include "console.h" +#include "gpio.h" +#include "hooks.h" +#include "uart_bitbang.h" +#include "uartn.h" + +#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) + +static enum device_state state = DEVICE_STATE_INIT; + +int ec_is_on(void) +{ + /* Debouncing and on are both still on */ + return (state == DEVICE_STATE_DEBOUNCING || state == DEVICE_STATE_ON); +} + +/** + * Move the EC to the ON state. + * + * This can be deferred from the interrupt handler, or called from the state + * machine which also runs in HOOK task, so it needs to check the current state + * to determine whether we're already on. + */ +static void set_ec_on(void) +{ + if (state == DEVICE_STATE_INIT || + state == DEVICE_STATE_INIT_DEBOUNCING) { + /* + * Enable the UART peripheral so we start receiving on EC RX, + * but do not call uartn_tx_connect() to connect EC TX yet. We + * need to be able to use EC TX to detect servo, so if we drive + * it right away that blocks us from detecting servo. + */ + CPRINTS("EC RX only"); + if (!uart_bitbang_is_enabled(UART_EC)) + uartn_enable(UART_EC); + state = DEVICE_STATE_INIT_RX_ONLY; + return; + } + + /* If we were debouncing ON->OFF, cancel it because we're still on */ + if (state == DEVICE_STATE_DEBOUNCING) + state = DEVICE_STATE_ON; + + /* If we're already on, done */ + if (state == DEVICE_STATE_ON) + return; + + /* We were previously off */ + CPRINTS("EC on"); + state = DEVICE_STATE_ON; + + /* Enable UART RX if we're not bit-banging */ + if (!uart_bitbang_is_enabled(UART_EC)) + enable_ccd_uart(UART_EC); +} +DECLARE_DEFERRED(set_ec_on); + +/** + * Interrupt handler for EC detect asserted. + */ +void ec_detect_asserted(enum gpio_signal signal) +{ + gpio_disable_interrupt(GPIO_DETECT_EC); + hook_call_deferred(&set_ec_on_data, 0); +} + +/** + * Detect state machine + */ +static void ec_detect(void) +{ + /* Disable interrupts if we had them on for debouncing */ + gpio_disable_interrupt(GPIO_DETECT_EC); + + /* If we detect the EC, make sure it's on */ + if (gpio_get_level(GPIO_DETECT_EC)) { + set_ec_on(); + return; + } + + /* EC wasn't detected. If we're already off, done. */ + if (state == DEVICE_STATE_OFF) + return; + + /* If we were debouncing, we're now sure we're off */ + if (state == DEVICE_STATE_DEBOUNCING || + state == DEVICE_STATE_INIT_DEBOUNCING) { + CPRINTS("EC off"); + state = DEVICE_STATE_OFF; + disable_ccd_uart(UART_EC); + return; + } + + /* + * Otherwise, we were on or initializing, and we're not sure if the EC + * is actually off or just sending a 0-bit. So start debouncing. + */ + if (state == DEVICE_STATE_INIT) + state = DEVICE_STATE_INIT_DEBOUNCING; + else + state = DEVICE_STATE_DEBOUNCING; + gpio_enable_interrupt(GPIO_DETECT_EC); +} +DECLARE_HOOK(HOOK_SECOND, ec_detect, HOOK_PRIO_DEFAULT); |