diff options
-rw-r--r-- | board/snow/board.c | 60 | ||||
-rw-r--r-- | board/snow/board.h | 6 | ||||
-rw-r--r-- | common/gaia_power.c | 3 | ||||
-rw-r--r-- | common/pmu_tps65090.c | 89 | ||||
-rw-r--r-- | include/pmu_tpschrome.h | 4 |
5 files changed, 118 insertions, 44 deletions
diff --git a/board/snow/board.c b/board/snow/board.c index 55edbedd2d..672df1002b 100644 --- a/board/snow/board.c +++ b/board/snow/board.c @@ -68,6 +68,7 @@ const struct gpio_info gpio_list[GPIO_COUNT] = { {"EN_PP5000", GPIO_A, (1<<11), GPIO_OUT_LOW, NULL}, {"EN_PP3300", GPIO_A, (1<<8), GPIO_OUT_LOW, NULL}, {"PMIC_PWRON_L",GPIO_A, (1<<12), GPIO_OUT_HIGH, NULL}, + {"PMIC_RESET", GPIO_A, (1<<15), GPIO_OUT_LOW, NULL}, {"ENTERING_RW", GPIO_D, (1<<0), GPIO_OUT_LOW, NULL}, {"CHARGER_EN", GPIO_B, (1<<2), GPIO_OUT_LOW, NULL}, {"EC_INT", GPIO_B, (1<<9), GPIO_HI_Z, NULL}, @@ -287,41 +288,63 @@ void board_i2c_release(int port) } #endif /* CONFIG_ARBITRATE_I2C */ +/* + * Force the pmic to reset completely. This forces an entire system reset, + * and therefore should never return + */ +void board_hard_reset(void) +{ + /* Force a hard reset of tps Chrome */ + gpio_set_level(GPIO_PMIC_RESET, 1); + /* Hang until the power is cut */ + while (1) + ; +} + #ifdef CONFIG_PMU_BOARD_INIT + /** * Initialize PMU register settings * * PMU init settings depend on board configuration. This function should be * called inside PMU init function. */ -void board_pmu_init(void) +int board_pmu_init(void) { - int ver; + int ver, failure = 0; /* Set fast charging timeout to 6 hours*/ - pmu_set_fastcharge(TIMEOUT_6HRS); + if (!failure) + failure = pmu_set_fastcharge(TIMEOUT_6HRS); /* Enable external gpio CHARGER_EN control */ - pmu_enable_ext_control(1); + if (!failure) + failure = pmu_enable_ext_control(1); /* Disable force charging */ - pmu_enable_charger(0); + if (!failure) + failure = pmu_enable_charger(0); /* Set NOITERM bit */ - pmu_low_current_charging(1); + if (!failure) + failure = pmu_low_current_charging(1); /* * High temperature charging * termination voltage: 2.1V * termination current: 100% */ - pmu_set_term_voltage(RANGE_T34, TERM_V2100); - pmu_set_term_current(RANGE_T34, TERM_I1000); + if (!failure) + failure = pmu_set_term_voltage(RANGE_T34, TERM_V2100); + if (!failure) + failure = pmu_set_term_current(RANGE_T34, TERM_I1000); /* * Standard temperature charging * termination voltage: 2.1V * termination current: 100% */ - pmu_set_term_voltage(RANGE_T23, TERM_V2100); - pmu_set_term_current(RANGE_T23, TERM_I1000); + if (!failure) + failure = pmu_set_term_voltage(RANGE_T23, TERM_V2100); + if (!failure) + failure = pmu_set_term_current(RANGE_T23, TERM_I1000); /* * Ignore TPSCHROME NTC reading in T40. This is snow board specific @@ -329,15 +352,22 @@ void board_pmu_init(void) * http://crosbug.com/p/12221 * http://crosbug.com/p/13171 */ - pmu_set_term_voltage(RANGE_T40, TERM_V2100); - pmu_set_term_current(RANGE_T40, TERM_I1000); + if (!failure) + failure = pmu_set_term_voltage(RANGE_T40, TERM_V2100); + if (!failure) + failure = pmu_set_term_current(RANGE_T40, TERM_I1000); /* Workaround init values before ES3 */ if (pmu_version(&ver) || ver < 3) { /* Termination current: 75% */ - pmu_set_term_current(RANGE_T34, TERM_I0750); - pmu_set_term_current(RANGE_T23, TERM_I0750); - pmu_set_term_current(RANGE_T40, TERM_I0750); + if (!failure) + failure = pmu_set_term_current(RANGE_T34, TERM_I0750); + if (!failure) + failure = pmu_set_term_current(RANGE_T23, TERM_I0750); + if (!failure) + failure = pmu_set_term_current(RANGE_T40, TERM_I0750); } + + return failure ? EC_ERROR_UNKNOWN : EC_SUCCESS; } #endif /* CONFIG_BOARD_PMU_INIT */ diff --git a/board/snow/board.h b/board/snow/board.h index 27eb5d7c6d..79d56ecb5b 100644 --- a/board/snow/board.h +++ b/board/snow/board.h @@ -91,6 +91,7 @@ enum gpio_signal { GPIO_EN_PP5000, /* 5.0v rail enable */ GPIO_EN_PP3300, /* 3.3v rail enable */ GPIO_PMIC_PWRON_L, /* 5v rail ready */ + GPIO_PMIC_RESET, /* Force hard reset of the pmic */ GPIO_EC_ENTERING_RW, /* EC is R/W mode for the kbc mux */ GPIO_CHARGER_EN, GPIO_EC_INT, @@ -123,7 +124,10 @@ void matrix_interrupt(enum gpio_signal signal); void board_interrupt_host(int active); /* Initialize PMU registers using board settings */ -void board_pmu_init(void); +int board_pmu_init(void); + +/* Force the pmu to reset everything on the board */ +void board_hard_reset(void); #endif /* !__ASSEMBLER__ */ diff --git a/common/gaia_power.c b/common/gaia_power.c index 88936d18fb..2ef6f3ddf5 100644 --- a/common/gaia_power.c +++ b/common/gaia_power.c @@ -447,7 +447,8 @@ static void power_off(void) lid_changed = 0; enable_sleep(SLEEP_MASK_AP_RUN); powerled_set_state(POWERLED_STATE_OFF); - pmu_shutdown(); + if (pmu_shutdown()) + board_hard_reset(); CPUTS("Shutdown complete.\n"); } diff --git a/common/pmu_tps65090.c b/common/pmu_tps65090.c index 0fdbef1d89..4ed7c5a5c6 100644 --- a/common/pmu_tps65090.c +++ b/common/pmu_tps65090.c @@ -77,6 +77,13 @@ /* Charger alarm */ #define CHARGER_ALARM 3 +void __board_hard_reset(void) +{ + CPRINTF("This board is not capable of a hard reset.\n"); +} +void board_hard_reset(void) + __attribute__((weak, alias("__board_hard_reset"))); + /* Charger temperature threshold table */ static const uint8_t const pmu_temp_threshold[] = { 1, /* 0b001, 0 degree C */ @@ -402,25 +409,30 @@ int pmu_get_ac(void) int pmu_shutdown(void) { - int offset, rv = 0; + int offset, failure = 0; /* Disable each of the DCDCs */ - for (offset = DCDC1_CTRL; offset <= DCDC3_CTRL; offset++) - rv |= pmu_write(offset, 0x0e); + for (offset = DCDC1_CTRL; offset <= DCDC3_CTRL; offset++) { + if (!failure) + failure = pmu_write(offset, 0x0e); + } /* Disable each of the FETs */ - for (offset = FET1_CTRL; offset <= FET7_CTRL; offset++) - rv |= pmu_write(offset, 0x02); + for (offset = FET1_CTRL; offset <= FET7_CTRL; offset++) { + if (!failure) + failure = pmu_write(offset, 0x02); + } /* Clearing AD controls/status */ - rv |= pmu_write(AD_CTRL, 0x00); + if (!failure) + failure = pmu_write(AD_CTRL, 0x00); - return rv ? EC_ERROR_UNKNOWN : EC_SUCCESS; + return failure ? EC_ERROR_UNKNOWN : EC_SUCCESS; } /* * Fill all of the pmu registers with known good values, this allows the * pmu to recover by rebooting the system if its registers were trashed. */ -static void pmu_init_registers(void) +static int pmu_init_registers(void) { const struct { uint8_t index; @@ -447,19 +459,28 @@ static void pmu_init_registers(void) {AD_CTRL, 0x00}, {IRQ1_REG, 0x00} }; + uint8_t i, rv; + + for (i = 0; i < ARRAY_SIZE(reg); i++) { + rv = pmu_write(reg[i].index, reg[i].value); + if (rv) + return rv; + } - uint8_t i; - for (i = 0; i < ARRAY_SIZE(reg); i++) - pmu_write(reg[i].index, reg[i].value); + return EC_SUCCESS; } void pmu_init(void) { + int failure = 0; + /* Reset everything to default, safe values */ - pmu_init_registers(); + if (!failure) + failure = pmu_init_registers(); #ifdef CONFIG_PMU_BOARD_INIT - board_pmu_init(); + if (!failure) + failure = board_pmu_init(); #else /* Init configuration * Fast charge timer : 2 hours @@ -468,28 +489,39 @@ void pmu_init(void) * * TODO: move settings to battery pack specific init */ - pmu_write(CG_CTRL0, 2); + if (!failure) + failure = pmu_write(CG_CTRL0, 2); /* Limit full charge current to 50% * TODO: remove this temporary hack. */ - pmu_write(CG_CTRL3, 0xbb); + if (!failure) + failure = pmu_write(CG_CTRL3, 0xbb); #endif /* Enable interrupts */ - pmu_write(IRQ1MASK, - EVENT_VACG | /* AC voltage good */ - EVENT_VSYSG | /* System voltage good */ - EVENT_VBATG | /* Battery voltage good */ - EVENT_CGACT | /* Charging status */ - EVENT_CGCPL); /* Charging complete */ - pmu_write(IRQ2MASK, 0); - pmu_clear_irq(); + if (!failure) { + failure = pmu_write(IRQ1MASK, + EVENT_VACG | /* AC voltage good */ + EVENT_VSYSG | /* System voltage good */ + EVENT_VBATG | /* Battery voltage good */ + EVENT_CGACT | /* Charging status */ + EVENT_CGCPL); /* Charging complete */ + } + if (!failure) + failure = pmu_write(IRQ2MASK, 0); + if (!failure) + failure = pmu_clear_irq(); /* Enable charger interrupt. */ - gpio_enable_interrupt(GPIO_CHARGER_INT); + if (!failure) + failure = gpio_enable_interrupt(GPIO_CHARGER_INT); #ifdef CONFIG_AC_POWER_STATUS - gpio_set_flags(GPIO_AC_STATUS, GPIO_OUT_HIGH); + if (!failure) + failure = gpio_set_flags(GPIO_AC_STATUS, GPIO_OUT_HIGH); #endif + + if (failure) + board_hard_reset(); } /* Initializes PMU when power is turned on. This is necessary because the TPS' @@ -532,6 +564,9 @@ static int command_pmu(int argc, char **argv) if (argc > 1) { repeat = strtoi(argv[1], &e, 0); if (*e) { + if (strlen(argv[1]) >= 1 && argv[1][0] == 'r') + board_hard_reset(); + ccputs("Invalid repeat count\n"); return EC_ERROR_INVAL; } @@ -554,7 +589,7 @@ static int command_pmu(int argc, char **argv) return rv ? EC_ERROR_UNKNOWN : EC_SUCCESS; } DECLARE_CONSOLE_COMMAND(pmu, command_pmu, - "<repeat_count>", - "Print PMU info", + "<repeat_count|reset>", + "Print PMU info or force a hard reset", NULL); #endif diff --git a/include/pmu_tpschrome.h b/include/pmu_tpschrome.h index 2f7c213d9d..1d60c6b1cd 100644 --- a/include/pmu_tpschrome.h +++ b/include/pmu_tpschrome.h @@ -216,6 +216,10 @@ int pmu_enable_ext_control(int enable); */ int pmu_set_fastcharge(enum FASTCHARGE_TIMEOUT timeout); +/** + * Reset the entire board if it is capable + */ +void board_hard_reset(void); #endif /* __CROS_EC_TPSCHROME_H */ |