summaryrefslogtreecommitdiff
path: root/common/peripheral_charger.c
diff options
context:
space:
mode:
authorDaisuke Nojiri <dnojiri@chromium.org>2021-03-11 13:17:35 -0800
committerCommit Bot <commit-bot@chromium.org>2021-03-18 19:28:06 +0000
commit1c5ff6f4d1ddfd3862f9bcfc85a4564eac63d16f (patch)
tree18b1f49685261f099409180c62bc5e70c361420a /common/peripheral_charger.c
parent4126a065489fe40668186c5f5b4dee4797388b25 (diff)
downloadchrome-ec-1c5ff6f4d1ddfd3862f9bcfc85a4564eac63d16f.tar.gz
PCHG: Support reset to firmware update mode
This patch allows a charger chip to reset to firmware update mode (a.k.a. download mode). Actual firmware update will be added in a separate patch. Currently, a reset event causes the state machine to unconditionally transition to normal mode. This patch makes the state machine check 'mode' field in the context to decide whether it transitions to normal mode or not. This patch also makes ctn730 driver explicitly return PCHG_EVENT_*_ERROR while PCHG_EVENT_NONE was returned previously. BUG=b:173235954 BRANCH=trogdor TEST=Stylus connect, disconnect, charge events are triggered as expected. Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org> Change-Id: I10dbd25d0b3d5284952e57d4ade2949e9594c8d1 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2770503
Diffstat (limited to 'common/peripheral_charger.c')
-rw-r--r--common/peripheral_charger.c167
1 files changed, 73 insertions, 94 deletions
diff --git a/common/peripheral_charger.c b/common/peripheral_charger.c
index 3c11c68be1..d176b75603 100644
--- a/common/peripheral_charger.c
+++ b/common/peripheral_charger.c
@@ -58,6 +58,7 @@ static const char *_text_event(enum pchg_event event)
[PCHG_EVENT_CHARGE_UPDATE] = "CHARGE_UPDATE",
[PCHG_EVENT_CHARGE_ENDED] = "CHARGE_ENDED",
[PCHG_EVENT_CHARGE_STOPPED] = "CHARGE_STOPPED",
+ [PCHG_EVENT_IN_NORMAL] = "IN_NORMAL",
[PCHG_EVENT_CHARGE_ERROR] = "CHARGE_ERROR",
[PCHG_EVENT_INITIALIZE] = "INITIALIZE",
[PCHG_EVENT_ENABLE] = "ENABLE",
@@ -71,62 +72,57 @@ static const char *_text_event(enum pchg_event event)
return event_names[event];
}
-static enum pchg_state pchg_reset(struct pchg *ctx)
+static void _clear_port(struct pchg *ctx)
{
mutex_lock(&ctx->mtx);
queue_init(&ctx->events);
mutex_unlock(&ctx->mtx);
atomic_clear(&ctx->irq);
-
- /* When fw update is implemented, this will be the branch point. */
- pchg_queue_event(ctx, PCHG_EVENT_INITIALIZE);
- return PCHG_STATE_RESET;
+ ctx->battery_percent = 0;
+ ctx->error = 0;
}
-static enum pchg_state pchg_initialize(struct pchg *ctx, enum pchg_state state)
+static enum pchg_state pchg_reset(struct pchg *ctx)
{
- int rv = ctx->cfg->drv->init(ctx);
+ enum pchg_state state = PCHG_STATE_RESET;
+ int rv;
- if (rv == EC_SUCCESS) {
- pchg_queue_event(ctx, PCHG_EVENT_ENABLE);
- state = PCHG_STATE_INITIALIZED;
- } else if (rv == EC_SUCCESS_IN_PROGRESS) {
- state = PCHG_STATE_RESET;
- } else {
- CPRINTS("ERR: Failed to initialize");
- }
+ /*
+ * In case we get asynchronous reset, clear port though it's redundant
+ * for a synchronous reset.
+ */
+ _clear_port(ctx);
- ctx->battery_percent = 0;
- ctx->error = 0;
+ if (ctx->mode == PCHG_MODE_NORMAL) {
+ rv = ctx->cfg->drv->init(ctx);
+ if (rv == EC_SUCCESS) {
+ state = PCHG_STATE_INITIALIZED;
+ pchg_queue_event(ctx, PCHG_EVENT_ENABLE);
+ } else if (rv != EC_SUCCESS_IN_PROGRESS) {
+ CPRINTS("ERR: Failed to reset to normal mode");
+ }
+ }
return state;
}
-static enum pchg_state pchg_state_reset(struct pchg *ctx)
+static void pchg_state_reset(struct pchg *ctx)
{
- enum pchg_state state = PCHG_STATE_RESET;
-
switch (ctx->event) {
case PCHG_EVENT_RESET:
- state = pchg_reset(ctx);
- break;
- case PCHG_EVENT_INITIALIZE:
- state = pchg_initialize(ctx, state);
+ ctx->state = pchg_reset(ctx);
break;
- case PCHG_EVENT_INITIALIZED:
+ case PCHG_EVENT_IN_NORMAL:
+ ctx->state = PCHG_STATE_INITIALIZED;
pchg_queue_event(ctx, PCHG_EVENT_ENABLE);
- state = PCHG_STATE_INITIALIZED;
break;
default:
break;
}
-
- return state;
}
-static enum pchg_state pchg_state_initialized(struct pchg *ctx)
+static void pchg_state_initialized(struct pchg *ctx)
{
- enum pchg_state state = PCHG_STATE_INITIALIZED;
int rv;
if (ctx->event == PCHG_EVENT_ENABLE)
@@ -134,54 +130,45 @@ static enum pchg_state pchg_state_initialized(struct pchg *ctx)
/* Spin in INITIALIZED until error condition is cleared. */
if (ctx->error)
- return state;
+ return;
switch (ctx->event) {
case PCHG_EVENT_RESET:
- state = pchg_reset(ctx);
- break;
- case PCHG_EVENT_INITIALIZE:
- state = pchg_initialize(ctx, state);
+ ctx->state = pchg_reset(ctx);
break;
case PCHG_EVENT_ENABLE:
rv = ctx->cfg->drv->enable(ctx, true);
if (rv == EC_SUCCESS)
- state = PCHG_STATE_ENABLED;
+ ctx->state = PCHG_STATE_ENABLED;
else if (rv != EC_SUCCESS_IN_PROGRESS)
CPRINTS("ERR: Failed to enable");
break;
case PCHG_EVENT_ENABLED:
- state = PCHG_STATE_ENABLED;
+ ctx->state = PCHG_STATE_ENABLED;
break;
default:
break;
}
-
- return state;
}
-static enum pchg_state pchg_state_enabled(struct pchg *ctx)
+static void pchg_state_enabled(struct pchg *ctx)
{
- enum pchg_state state = PCHG_STATE_ENABLED;
int rv;
switch (ctx->event) {
case PCHG_EVENT_RESET:
- state = pchg_reset(ctx);
- break;
- case PCHG_EVENT_INITIALIZE:
- state = pchg_initialize(ctx, state);
+ ctx->state = pchg_reset(ctx);
break;
case PCHG_EVENT_DISABLE:
ctx->error |= PCHG_ERROR_HOST;
rv = ctx->cfg->drv->enable(ctx, false);
if (rv == EC_SUCCESS)
- state = PCHG_STATE_INITIALIZED;
+ ctx->state = PCHG_STATE_INITIALIZED;
else if (rv != EC_SUCCESS_IN_PROGRESS)
CPRINTS("ERR: Failed to disable");
break;
case PCHG_EVENT_DISABLED:
- state = PCHG_STATE_INITIALIZED;
+ ctx->state = PCHG_STATE_INITIALIZED;
break;
case PCHG_EVENT_DEVICE_DETECTED:
/*
@@ -189,100 +176,86 @@ static enum pchg_state pchg_state_enabled(struct pchg *ctx)
* because device is already charged.
*/
ctx->cfg->drv->get_soc(ctx);
- state = PCHG_STATE_DETECTED;
+ ctx->state = PCHG_STATE_DETECTED;
break;
case PCHG_EVENT_CHARGE_STARTED:
- state = PCHG_STATE_CHARGING;
+ ctx->state = PCHG_STATE_CHARGING;
break;
default:
break;
}
-
- return state;
}
-static enum pchg_state pchg_state_detected(struct pchg *ctx)
+static void pchg_state_detected(struct pchg *ctx)
{
- enum pchg_state state = PCHG_STATE_DETECTED;
int rv;
switch (ctx->event) {
case PCHG_EVENT_RESET:
- state = pchg_reset(ctx);
- break;
- case PCHG_EVENT_INITIALIZE:
- state = pchg_initialize(ctx, state);
+ ctx->state = pchg_reset(ctx);
break;
case PCHG_EVENT_DISABLE:
ctx->error |= PCHG_ERROR_HOST;
rv = ctx->cfg->drv->enable(ctx, false);
if (rv == EC_SUCCESS)
- state = PCHG_STATE_INITIALIZED;
+ ctx->state = PCHG_STATE_INITIALIZED;
else if (rv != EC_SUCCESS_IN_PROGRESS)
CPRINTS("ERR: Failed to disable");
break;
case PCHG_EVENT_DISABLED:
- state = PCHG_STATE_INITIALIZED;
+ ctx->state = PCHG_STATE_INITIALIZED;
break;
case PCHG_EVENT_CHARGE_STARTED:
- state = PCHG_STATE_CHARGING;
+ ctx->state = PCHG_STATE_CHARGING;
break;
case PCHG_EVENT_DEVICE_LOST:
ctx->battery_percent = 0;
- state = PCHG_STATE_ENABLED;
+ ctx->state = PCHG_STATE_ENABLED;
break;
case PCHG_EVENT_CHARGE_ERROR:
- state = PCHG_STATE_INITIALIZED;
+ ctx->state = PCHG_STATE_INITIALIZED;
break;
default:
break;
}
-
- return state;
}
-static enum pchg_state pchg_state_charging(struct pchg *ctx)
+static void pchg_state_charging(struct pchg *ctx)
{
- enum pchg_state state = PCHG_STATE_CHARGING;
int rv;
switch (ctx->event) {
case PCHG_EVENT_RESET:
- pchg_reset(ctx);
- break;
- case PCHG_EVENT_INITIALIZE:
- state = pchg_initialize(ctx, state);
+ ctx->state = pchg_reset(ctx);
break;
case PCHG_EVENT_DISABLE:
ctx->error |= PCHG_ERROR_HOST;
rv = ctx->cfg->drv->enable(ctx, false);
if (rv == EC_SUCCESS)
- state = PCHG_STATE_INITIALIZED;
+ ctx->state = PCHG_STATE_INITIALIZED;
else if (rv != EC_SUCCESS_IN_PROGRESS)
CPRINTS("ERR: Failed to disable");
break;
case PCHG_EVENT_DISABLED:
- state = PCHG_STATE_INITIALIZED;
+ ctx->state = PCHG_STATE_INITIALIZED;
break;
case PCHG_EVENT_CHARGE_UPDATE:
CPRINTS("Battery %d%%", ctx->battery_percent);
break;
case PCHG_EVENT_DEVICE_LOST:
ctx->battery_percent = 0;
- state = PCHG_STATE_ENABLED;
+ ctx->state = PCHG_STATE_ENABLED;
break;
case PCHG_EVENT_CHARGE_ERROR:
- state = PCHG_STATE_INITIALIZED;
+ ctx->state = PCHG_STATE_INITIALIZED;
break;
case PCHG_EVENT_CHARGE_ENDED:
case PCHG_EVENT_CHARGE_STOPPED:
- state = PCHG_STATE_DETECTED;
+ ctx->state = PCHG_STATE_DETECTED;
break;
default:
break;
}
-
- return state;
}
static int pchg_run(struct pchg *ctx)
@@ -311,21 +284,24 @@ static int pchg_run(struct pchg *ctx)
CPRINTS("IRQ:EVENT_%s", _text_event(ctx->event));
}
+ if (ctx->event == PCHG_EVENT_NONE)
+ return 0;
+
switch (ctx->state) {
case PCHG_STATE_RESET:
- ctx->state = pchg_state_reset(ctx);
+ pchg_state_reset(ctx);
break;
case PCHG_STATE_INITIALIZED:
- ctx->state = pchg_state_initialized(ctx);
+ pchg_state_initialized(ctx);
break;
case PCHG_STATE_ENABLED:
- ctx->state = pchg_state_enabled(ctx);
+ pchg_state_enabled(ctx);
break;
case PCHG_STATE_DETECTED:
- ctx->state = pchg_state_detected(ctx);
+ pchg_state_detected(ctx);
break;
case PCHG_STATE_CHARGING:
- ctx->state = pchg_state_charging(ctx);
+ pchg_state_charging(ctx);
break;
default:
CPRINTS("ERR: Unknown state (%d)", ctx->state);
@@ -374,6 +350,8 @@ static void pchg_startup(void)
for (p = 0; p < pchg_count; p++) {
ctx = &pchgs[p];
+ _clear_port(ctx);
+ ctx->mode = PCHG_MODE_NORMAL;
ctx->cfg->drv->reset(ctx);
gpio_enable_interrupt(ctx->cfg->irq_pin);
}
@@ -392,9 +370,6 @@ static void pchg_shutdown(void)
for (p = 0; p < pchg_count; p++) {
ctx = &pchgs[0];
gpio_disable_interrupt(ctx->cfg->irq_pin);
- mutex_lock(&ctx->mtx);
- queue_init(&ctx->events);
- mutex_unlock(&ctx->mtx);
}
}
DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, pchg_shutdown, HOOK_PRIO_DEFAULT);
@@ -490,26 +465,30 @@ static int cc_pchg(int argc, char **argv)
return EC_SUCCESS;
}
- if (!strcasecmp(argv[2], "reset"))
- pchg_queue_event(ctx, PCHG_EVENT_RESET);
- else if (!strcasecmp(argv[2], "init"))
- pchg_queue_event(ctx, PCHG_EVENT_INITIALIZE);
- else if (!strcasecmp(argv[2], "enable"))
+ if (!strcasecmp(argv[2], "reset")) {
+ if (argc == 3)
+ ctx->mode = PCHG_MODE_NORMAL;
+ else
+ return EC_ERROR_PARAM3;
+ gpio_disable_interrupt(ctx->cfg->irq_pin);
+ _clear_port(ctx);
+ ctx->cfg->drv->reset(ctx);
+ gpio_enable_interrupt(ctx->cfg->irq_pin);
+ } else if (!strcasecmp(argv[2], "enable")) {
pchg_queue_event(ctx, PCHG_EVENT_ENABLE);
- else if (!strcasecmp(argv[2], "disable"))
+ } else if (!strcasecmp(argv[2], "disable")) {
pchg_queue_event(ctx, PCHG_EVENT_DISABLE);
- else
+ } else {
return EC_ERROR_PARAM2;
+ }
task_wake(TASK_ID_PCHG);
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(pchg, cc_pchg,
- "<port> [init/enable/disable]"
"\n\t<port>"
"\n\t<port> reset"
- "\n\t<port> init"
"\n\t<port> enable"
"\n\t<port> disable",
"Control peripheral chargers");