summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/snow/board.c60
-rw-r--r--board/snow/board.h6
-rw-r--r--common/gaia_power.c3
-rw-r--r--common/pmu_tps65090.c89
-rw-r--r--include/pmu_tpschrome.h4
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 */