1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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);
|