summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Mooney <charliemooney@chromium.org>2012-08-23 14:28:57 -0700
committerGerrit <chrome-bot@google.com>2012-08-27 09:27:43 -0700
commitecd4e1b5d6cc0530b3416ce626b4665ec298e4e4 (patch)
tree4ff004e1093d4e2e78a0cc30150ef649a9e341af
parentb11c1e234b86498311c340bd8b9b51b8d22e2ff5 (diff)
downloadchrome-ec-ecd4e1b5d6cc0530b3416ce626b4665ec298e4e4.tar.gz
Reset pmic registers to known safe values on boot
If a bug causes the pmic's internal registers to be overwritten with garbage, they won't go away and can cause long lasting problems. This change overwrites them all whenever the EC or AP turn on with known, safe values, so if that happens, a reboot will restore them instead of forcing the user to pull the battery. It also overwrites a few of them when the AP shuts down, to prevent AP bugs from leaving the pmu powering a bunch of peripherals that it doesn't need after it has turned off. BUG=chrome-os-partner:12913 TEST=from EC console run "i2c w 0x90 0x0c 0xff" to screw up one of the pmic registers. Reboot the EC, and the AP should be able to boot just fine. Once the AP is booted, run that command again. This time, just reboot the AP, it should come back on like normal. Try again with "i2c w 0x90 0x0c 0x00". Without the change, this fails to work. BRANCH=snow Change-Id: If3f0764f23e0112cc11be60b413f51e1b66e54a7 Signed-off-by: Charlie Mooney <charliemooney@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/31259 Reviewed-by: Doug Anderson <dianders@chromium.org> Reviewed-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-by: Puneet Kumar <puneetster@chromium.org>
-rw-r--r--common/gaia_power.c2
-rw-r--r--common/pmu_tps65090.c69
-rw-r--r--include/pmu_tpschrome.h6
3 files changed, 77 insertions, 0 deletions
diff --git a/common/gaia_power.c b/common/gaia_power.c
index aae1bd35b7..88936d18fb 100644
--- a/common/gaia_power.c
+++ b/common/gaia_power.c
@@ -31,6 +31,7 @@
#include "hooks.h"
#include "keyboard_scan.h"
#include "power_led.h"
+#include "pmu_tpschrome.h"
#include "system.h"
#include "task.h"
#include "timer.h"
@@ -446,6 +447,7 @@ static void power_off(void)
lid_changed = 0;
enable_sleep(SLEEP_MASK_AP_RUN);
powerled_set_state(POWERLED_STATE_OFF);
+ pmu_shutdown();
CPUTS("Shutdown complete.\n");
}
diff --git a/common/pmu_tps65090.c b/common/pmu_tps65090.c
index d9b72ec765..d26b855756 100644
--- a/common/pmu_tps65090.c
+++ b/common/pmu_tps65090.c
@@ -33,6 +33,19 @@
#define CG_CTRL5 0x09
#define CG_STATUS1 0x0a
#define CG_STATUS2 0x0b
+#define DCDC1_CTRL 0x0c
+#define DCDC2_CTRL 0x0d
+#define DCDC3_CTRL 0x0e
+#define FET1_CTRL 0x0f
+#define FET2_CTRL 0x10
+#define FET3_CTRL 0x11
+#define FET4_CTRL 0x12
+#define FET5_CTRL 0x13
+#define FET6_CTRL 0x14
+#define FET7_CTRL 0x15
+#define AD_CTRL 0x16
+#define AD_OUT1 0x17
+#define AD_OUT2 0x18
#define TPSCHROME_VER 0x19
/* Charger control */
@@ -334,8 +347,64 @@ int pmu_get_ac(void)
return ac_good;
}
+int pmu_shutdown(void)
+{
+ int offset, rv = 0;
+
+ /* Disable each of the DCDCs */
+ for (offset = DCDC1_CTRL; offset <= DCDC3_CTRL; offset++)
+ rv |= pmu_write(offset, 0x0e);
+ /* Disable each of the FETs */
+ for (offset = FET1_CTRL; offset <= FET7_CTRL; offset++)
+ rv |= pmu_write(offset, 0x02);
+ /* Clearing AD controls/status */
+ rv |= pmu_write(AD_CTRL, 0x00);
+
+ return rv ? 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)
+{
+ const struct {
+ uint8_t index;
+ uint8_t value;
+ } reg[] = {
+ {IRQ1MASK, 0x00},
+ {IRQ2MASK, 0x00},
+ {CG_CTRL0, 0x02},
+ {CG_CTRL1, 0x20},
+ {CG_CTRL2, 0x4b},
+ {CG_CTRL3, 0xbf},
+ {CG_CTRL4, 0xf3},
+ {CG_CTRL5, 0xc0},
+ {DCDC1_CTRL, 0x0e},
+ {DCDC2_CTRL, 0x0e},
+ {DCDC3_CTRL, 0x0e},
+ {FET1_CTRL, 0x02},
+ {FET2_CTRL, 0x02},
+ {FET3_CTRL, 0x02},
+ {FET4_CTRL, 0x02},
+ {FET5_CTRL, 0x02},
+ {FET6_CTRL, 0x02},
+ {FET7_CTRL, 0x02},
+ {AD_CTRL, 0x00},
+ {IRQ1_REG, 0x00}
+ };
+
+ uint8_t i;
+ for (i = 0; i < ARRAY_SIZE(reg); i++)
+ pmu_write(reg[i].index, reg[i].value);
+}
+
void pmu_init(void)
{
+ /* Reset everything to default, safe values */
+ pmu_init_registers();
+
#ifdef CONFIG_PMU_BOARD_INIT
board_pmu_init();
#else
diff --git a/include/pmu_tpschrome.h b/include/pmu_tpschrome.h
index 57fb84a4a4..5d65b73b45 100644
--- a/include/pmu_tpschrome.h
+++ b/include/pmu_tpschrome.h
@@ -184,5 +184,11 @@ int pmu_blink_led(int enable);
* */
void pmu_init(void);
+/**
+ * Shut down the pmu, by resetting it's registers to disable it's FETs,
+ * DCDCs and ADC.
+ */
+int pmu_shutdown(void);
+
#endif /* __CROS_EC_TPSCHROME_H */