diff options
author | Stefan Adolfsson <sadolfsson@google.com> | 2018-04-26 11:52:21 +0200 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2018-06-19 19:58:35 +0000 |
commit | 741d9be8c0f3124bb4382d07e91ae6f15b703e73 (patch) | |
tree | 1ffa2941d17579ab1801e1db8ddf39e710b5078f | |
parent | b13a588a968f503ccb603fa0df08c84ff663d492 (diff) | |
download | chrome-ec-741d9be8c0f3124bb4382d07e91ae6f15b703e73.tar.gz |
npcx: CEC: Handle enable/disable command
The Linux kernel has enable/disable hooks in the CEC
driver API. Make it possible to use those calls on
the EC CEC implementation.
Signed-off-by: Stefan Adolfsson <sadolfsson@chromium.org>
BUG=b:76467407
BRANCH=none
TEST=Verify with logical analyzer that nothing happens on
the bus in disable mode and it still works in enable mode.
CQ-DEPEND=CL:1030223
Reviewed-on: https://chromium-review.googlesource.com/1030224
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Change-Id: Ib5255d76427f288862740cd2e3299ba47f39d998
Reviewed-on: https://chromium-review.googlesource.com/1055523
Tested-by: Stefan Adolfsson <sadolfsson@chromium.org>
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Commit-Queue: Stefan Adolfsson <sadolfsson@chromium.org>
-rw-r--r-- | chip/npcx/cec.c | 95 |
1 files changed, 87 insertions, 8 deletions
diff --git a/chip/npcx/cec.c b/chip/npcx/cec.c index 1c945f09ca..f1dabcfc70 100644 --- a/chip/npcx/cec.c +++ b/chip/npcx/cec.c @@ -83,7 +83,8 @@ * for receiving. */ enum cec_state { - CEC_STATE_IDLE = 0, + CEC_STATE_DISABLED = 0, + CEC_STATE_IDLE, CEC_STATE_INITIATOR_FREE_TIME, CEC_STATE_INITIATOR_START_LOW, CEC_STATE_INITIATOR_START_HIGH, @@ -194,6 +195,11 @@ void enter_state(enum cec_state new_state) cec_state = new_state; switch (new_state) { + case CEC_STATE_DISABLED: + gpio = 1; + memset(&cec_tx, 0, sizeof(struct cec_tx)); + cec_events = 0; + break; case CEC_STATE_IDLE: cec_tx.msgt.bit = 0; cec_tx.msgt.byte = 0; @@ -272,6 +278,7 @@ void enter_state(enum cec_state new_state) static void cec_event_timeout(void) { switch (cec_state) { + case CEC_STATE_DISABLED: case CEC_STATE_IDLE: break; case CEC_STATE_INITIATOR_FREE_TIME: @@ -407,6 +414,9 @@ static int hc_cec_write(struct host_cmd_handler_args *args) { const struct ec_params_cec_write *params = args->params; + if (cec_state == CEC_STATE_DISABLED) + return EC_RES_UNAVAILABLE; + if (args->params_size == 0 || args->params_size > MAX_CEC_MSG_LEN) return EC_RES_INVALID_PARAM; @@ -417,6 +427,82 @@ static int hc_cec_write(struct host_cmd_handler_args *args) } DECLARE_HOST_COMMAND(EC_CMD_CEC_WRITE_MSG, hc_cec_write, EC_VER_MASK(0)); +static int cec_set_enable(uint8_t enable) +{ + int mdl = NPCX_MFT_MODULE_1; + + if (enable != 0 && enable != 1) + return EC_RES_INVALID_PARAM; + + /* Enabling when already enabled? */ + if (enable && cec_state != CEC_STATE_DISABLED) + return EC_RES_SUCCESS; + + /* Disabling when already disabled? */ + if (!enable && cec_state == CEC_STATE_DISABLED) + return EC_RES_SUCCESS; + + if (enable) { + enter_state(CEC_STATE_IDLE); + + /* Enable timer interrupts */ + SET_BIT(NPCX_TIEN(mdl), NPCX_TIEN_TCIEN); + SET_BIT(NPCX_TIEN(mdl), NPCX_TIEN_TDIEN); + + /* Enable multifunction timer interrupt */ + task_enable_irq(NPCX_IRQ_MFT_1); + + CPRINTF("CEC enabled\n"); + } else { + /* Disable timer interrupts */ + CLEAR_BIT(NPCX_TIEN(mdl), NPCX_TIEN_TCIEN); + CLEAR_BIT(NPCX_TIEN(mdl), NPCX_TIEN_TDIEN); + + tmr2_stop(); + + task_disable_irq(NPCX_IRQ_MFT_1); + + enter_state(CEC_STATE_DISABLED); + + CPRINTF("CEC disabled\n"); + } + + return EC_RES_SUCCESS; +} + +static int hc_cec_set(struct host_cmd_handler_args *args) +{ + const struct ec_params_cec_set *params = args->params; + + switch (params->cmd) { + case CEC_CMD_ENABLE: + return cec_set_enable(params->val); + } + + return EC_RES_INVALID_PARAM; +} +DECLARE_HOST_COMMAND(EC_CMD_CEC_SET, hc_cec_set, EC_VER_MASK(0)); + + +static int hc_cec_get(struct host_cmd_handler_args *args) +{ + struct ec_response_cec_get *response = args->response; + const struct ec_params_cec_get *params = args->params; + + switch (params->cmd) { + case CEC_CMD_ENABLE: + response->val = cec_state == CEC_STATE_DISABLED ? 0 : 1; + break; + default: + return EC_RES_INVALID_PARAM; + } + + args->response_size = sizeof(*response); + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_CEC_GET, hc_cec_get, EC_VER_MASK(0)); + static int cec_get_next_event(uint8_t *out) { uint32_t event_out = atomic_read_clear(&cec_events); @@ -440,13 +526,6 @@ static void cec_init(void) /* Mode 2 - Dual-input capture */ SET_FIELD(NPCX_TMCTRL(mdl), NPCX_TMCTRL_MDSEL_FIELD, NPCX_MFT_MDSEL_2); - /* Enable timer interrupts */ - SET_BIT(NPCX_TIEN(mdl), NPCX_TIEN_TCIEN); - SET_BIT(NPCX_TIEN(mdl), NPCX_TIEN_TDIEN); - - /* Enable multifunction timer interrupt */ - task_enable_irq(NPCX_IRQ_MFT_1); - CPRINTS("CEC initialized"); } DECLARE_HOOK(HOOK_INIT, cec_init, HOOK_PRIO_LAST); |