summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/peripheral_charger.c167
-rw-r--r--driver/nfc/ctn730.c78
-rw-r--r--include/peripheral_charger.h11
3 files changed, 143 insertions, 113 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");
diff --git a/driver/nfc/ctn730.c b/driver/nfc/ctn730.c
index 75487fa701..6efb75efb4 100644
--- a/driver/nfc/ctn730.c
+++ b/driver/nfc/ctn730.c
@@ -56,12 +56,17 @@ static const int _detection_interval_ms = 100;
#define WLC_CHG_CTRL_CHARGING_INFO 0b010101
/* WLC_HOST_CTRL_RESET constants */
-#define WLC_HOST_CTRL_RESET_CMD_SIZE 1
-#define WLC_HOST_CTRL_RESET_RSP_SIZE 1
-#define WLC_HOST_CTRL_RESET_EVT_NORMAL_MODE 0x00
-#define WLC_HOST_CTRL_RESET_EVT_DOWNLOAD_MODE 0x01
-#define WLC_HOST_CTRL_RESET_CMD_MODE_NORMAL 0x00
-#define WLC_HOST_CTRL_RESET_CMD_MODE_DOWNLOAD 0x01
+#define WLC_HOST_CTRL_RESET_CMD_SIZE 1
+#define WLC_HOST_CTRL_RESET_RSP_SIZE 1
+#define WLC_HOST_CTRL_RESET_EVT_NORMAL_MODE 0x00
+#define WLC_HOST_CTRL_RESET_EVT_NORMAL_MODE_SIZE 3
+#define WLC_HOST_CTRL_RESET_EVT_DOWNLOAD_MODE 0x01
+#define WLC_HOST_CTRL_RESET_EVT_DOWNLOAD_MODE_SIZE 2
+#define WLC_HOST_CTRL_RESET_REASON_INTENDED 0x00
+#define WLC_HOST_CTRL_RESET_REASON_CORRUPTED 0x01
+#define WLC_HOST_CTRL_RESET_REASON_UNRECOVERABLE 0x02
+#define WLC_HOST_CTRL_RESET_CMD_MODE_NORMAL 0x00
+#define WLC_HOST_CTRL_RESET_CMD_MODE_DOWNLOAD 0x01
/* WLC_CHG_CTRL_ENABLE constants */
#define WLC_CHG_CTRL_ENABLE_CMD_SIZE 2
@@ -207,6 +212,20 @@ static const char *_text_status_code(uint8_t code)
}
}
+static const char *_text_reset_reason(uint8_t code)
+{
+ switch (code) {
+ case WLC_HOST_CTRL_RESET_REASON_INTENDED:
+ return "intended";
+ case WLC_HOST_CTRL_RESET_REASON_CORRUPTED:
+ return "corrupted";
+ case WLC_HOST_CTRL_RESET_REASON_UNRECOVERABLE:
+ return "unrecoverable";
+ default:
+ return "unknown";
+ }
+}
+
static int _i2c_read(int i2c_port, uint8_t *in, int in_len)
{
int rv;
@@ -269,7 +288,9 @@ static int ctn730_init(struct pchg *ctx)
cmd->message_type = CTN730_MESSAGE_TYPE_COMMAND;
cmd->instruction = WLC_HOST_CTRL_RESET;
cmd->length = WLC_HOST_CTRL_RESET_CMD_SIZE;
- cmd->payload[0] = WLC_HOST_CTRL_RESET_CMD_MODE_NORMAL;
+ cmd->payload[0] = ctx->mode == PCHG_MODE_NORMAL
+ ? WLC_HOST_CTRL_RESET_CMD_MODE_NORMAL
+ : WLC_HOST_CTRL_RESET_CMD_MODE_DOWNLOAD;
/* TODO: Run 1 sec timeout timer. */
rv = _send_command(ctx, cmd);
@@ -327,26 +348,36 @@ static int _process_payload_response(struct pchg *ctx, struct ctn730_msg *res)
switch (res->instruction) {
case WLC_HOST_CTRL_RESET:
- if (len != WLC_HOST_CTRL_RESET_RSP_SIZE
- || buf[0] != WLC_HOST_STATUS_OK)
+ if (len != WLC_HOST_CTRL_RESET_RSP_SIZE)
return EC_ERROR_UNKNOWN;
+ if (buf[0] != WLC_HOST_STATUS_OK)
+ ctx->event = PCHG_EVENT_OTHER_ERROR;
break;
case WLC_CHG_CTRL_ENABLE:
- if (len != WLC_CHG_CTRL_ENABLE_RSP_SIZE
- || buf[0] != WLC_HOST_STATUS_OK)
+ if (len != WLC_CHG_CTRL_ENABLE_RSP_SIZE)
return EC_ERROR_UNKNOWN;
- ctx->event = PCHG_EVENT_ENABLED;
+ if (buf[0] != WLC_HOST_STATUS_OK)
+ ctx->event = PCHG_EVENT_OTHER_ERROR;
+ else
+ ctx->event = PCHG_EVENT_ENABLED;
break;
case WLC_CHG_CTRL_DISABLE:
- if (len != WLC_CHG_CTRL_DISABLE_RSP_SIZE
- || buf[0] != WLC_HOST_STATUS_OK)
+ if (len != WLC_CHG_CTRL_DISABLE_RSP_SIZE)
return EC_ERROR_UNKNOWN;
+ if (buf[0] != WLC_HOST_STATUS_OK)
+ ctx->event = PCHG_EVENT_OTHER_ERROR;
+ else
+ ctx->event = PCHG_EVENT_DISABLED;
break;
case WLC_CHG_CTRL_CHARGING_INFO:
- if (len != WLC_CHG_CTRL_CHARGING_INFO_RSP_SIZE
- || buf[0] != WLC_HOST_STATUS_OK)
+ if (len != WLC_CHG_CTRL_CHARGING_INFO_RSP_SIZE)
return EC_ERROR_UNKNOWN;
- ctx->battery_percent = buf[1];
+ if (buf[0] != WLC_HOST_STATUS_OK) {
+ ctx->event = PCHG_EVENT_OTHER_ERROR;
+ } else {
+ ctx->battery_percent = buf[1];
+ ctx->event = PCHG_EVENT_CHARGE_UPDATE;
+ }
break;
default:
CPRINTS("Received unknown response (%d)", res->instruction);
@@ -374,16 +405,25 @@ static int _process_payload_event(struct pchg *ctx, struct ctn730_msg *res)
if (IS_ENABLED(CTN730_DEBUG))
CPRINTS("Payload: %ph", HEX_BUF(buf, len));
+ ctx->event = PCHG_EVENT_NONE;
+
switch (res->instruction) {
case WLC_HOST_CTRL_RESET:
if (buf[0] == WLC_HOST_CTRL_RESET_EVT_NORMAL_MODE) {
- ctx->event = PCHG_EVENT_INITIALIZED;
+ if (len != WLC_HOST_CTRL_RESET_EVT_NORMAL_MODE_SIZE)
+ return EC_ERROR_INVAL;
+ ctx->event = PCHG_EVENT_IN_NORMAL;
+ CPRINTS("Normal Mode (FW=0x%02x.%02x)", buf[1], buf[2]);
/*
* ctn730 isn't immediately ready for i2c write after
* normal mode initialization (b:178096436).
*/
msleep(5);
} else if (buf[0] == WLC_HOST_CTRL_RESET_EVT_DOWNLOAD_MODE) {
+ if (len != WLC_HOST_CTRL_RESET_EVT_DOWNLOAD_MODE_SIZE)
+ return EC_ERROR_INVAL;
+ CPRINTS("Download Mode (%s)",
+ _text_reset_reason(buf[1]));
ctx->event = PCHG_EVENT_RESET;
} else {
return EC_ERROR_INVAL;
@@ -481,7 +521,7 @@ static int ctn730_get_soc(struct pchg *ctx)
if (rv)
return rv;
- return EC_SUCCESS;
+ return EC_SUCCESS_IN_PROGRESS;
}
/**
diff --git a/include/peripheral_charger.h b/include/peripheral_charger.h
index a53fbb9104..2e535d4f3e 100644
--- a/include/peripheral_charger.h
+++ b/include/peripheral_charger.h
@@ -83,7 +83,11 @@ enum pchg_event {
PCHG_EVENT_CHARGE_UPDATE,
PCHG_EVENT_CHARGE_ENDED,
PCHG_EVENT_CHARGE_STOPPED,
+ PCHG_EVENT_IN_NORMAL,
+
+ /* Errors */
PCHG_EVENT_CHARGE_ERROR,
+ PCHG_EVENT_OTHER_ERROR,
/* Internal (a.k.a. Host) Events */
PCHG_EVENT_INITIALIZE,
@@ -103,6 +107,11 @@ enum pchg_error {
PCHG_ERROR_FOREIGN_OBJECT = BIT(3),
};
+enum pchg_mode {
+ PCHG_MODE_NORMAL = 0,
+ PCHG_MODE_DOWNLOAD,
+};
+
/**
* Data struct describing the configuration of a peripheral charging port.
*/
@@ -140,6 +149,8 @@ struct pchg {
uint8_t battery_percent;
/* Number of dropped events (due to queue overflow) */
uint32_t dropped_event_count;
+ /* enum pchg_mode */
+ uint8_t mode;
};
/**