From e317b78cd39e852fe7f72f8f33ca6688413f73fd Mon Sep 17 00:00:00 2001 From: Stefan Adolfsson Date: Thu, 26 Apr 2018 11:52:21 +0200 Subject: [PATCH] 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 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 Change-Id: Ib5255d76427f288862740cd2e3299ba47f39d998 Reviewed-on: https://chromium-review.googlesource.com/1030224 Commit-Ready: Stefan Adolfsson Tested-by: Stefan Adolfsson Reviewed-by: Randall Spangler --- chip/npcx/cec.c | 95 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file 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);