summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Adolfsson <sadolfsson@google.com>2018-04-26 11:52:21 +0200
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2018-06-19 19:58:35 +0000
commit741d9be8c0f3124bb4382d07e91ae6f15b703e73 (patch)
tree1ffa2941d17579ab1801e1db8ddf39e710b5078f
parentb13a588a968f503ccb603fa0df08c84ff663d492 (diff)
downloadchrome-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.c95
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);