summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAseda Aboagye <aaboagye@google.com>2020-06-05 17:25:08 -0700
committerCommit Bot <commit-bot@chromium.org>2020-06-21 06:33:31 +0000
commit33aa3c9a732fccefba54d5bd15c321ce6cbc8d80 (patch)
treeeaf62bc673e15d2a45f7966ff71b682dab439663
parent36cf95c854f00a6457c85edb97cedf6891cc1f6c (diff)
downloadchrome-ec-33aa3c9a732fccefba54d5bd15c321ce6cbc8d80.tar.gz
dedede: npcx7: Toggle ADC interrupts to save power
In order to save EC power and allow deep sleep to be entered, this change disables the ADC interrupts after booting up into S0, and then enables them when the system is attempting to power on. (Via power button or lid open or something else). BUG=b:157887329 BRANCH=None TEST=Build and flash waddledoo. Boot DUT, verify it can boot to S0. Enter `apshutdown` command on the EC console, verify that DUT shuts down. Verify that 15s later all power signals indicate low. Press power button, verify DUT boots up again. Repeat shutdown but initiated from the AP, verify power button can boot DUT again. Repeat shutdown and verify that a lid open can wake the DUT. TEST=Verify that suspend and resume continue to work. Verify that ADC interrupts remain disabled in suspend. TEST=Setup an RTC wake and shutdown to S5. Verify that AP wakes up after RTC alarm and boots all the way back up. TEST=Verify that power consumption is reduced when ADC interrupts are disabled. Change-Id: Ib9f6c30533afe8f354d731bb0f30ea207b44c601 Signed-off-by: Aseda Aboagye <aaboagye@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2233847 Tested-by: Aseda Aboagye <aaboagye@chromium.org> Reviewed-by: Diana Z <dzigterman@chromium.org> Commit-Queue: Diana Z <dzigterman@chromium.org> Auto-Submit: Aseda Aboagye <aaboagye@chromium.org>
-rw-r--r--baseboard/dedede/variant_ec_npcx796fc.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/baseboard/dedede/variant_ec_npcx796fc.c b/baseboard/dedede/variant_ec_npcx796fc.c
index 4ef55cf682..98ba57b70b 100644
--- a/baseboard/dedede/variant_ec_npcx796fc.c
+++ b/baseboard/dedede/variant_ec_npcx796fc.c
@@ -7,17 +7,24 @@
#include "adc_chip.h"
#include "atomic.h"
+#include "chipset.h"
#include "common.h"
#include "compile_time_macros.h"
#include "console.h"
#include "gpio.h"
#include "hooks.h"
#include "i2c.h"
+#include "lid_switch.h"
#include "power.h"
#include "pwm.h"
#include "pwm_chip.h"
#include "registers.h"
#include "task.h"
+#include "timer.h"
+
+/* Console output macros */
+#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args)
+#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
/* ADC channels */
const struct adc_t adc_channels[] = {
@@ -95,6 +102,81 @@ static void set_up_adc_irqs(void)
}
DECLARE_HOOK(HOOK_INIT, set_up_adc_irqs, HOOK_PRIO_INIT_ADC+1);
+static void disable_adc_irqs_deferred(void)
+{
+ CPRINTS("%s", __func__);
+ npcx_adc_thresh_int_enable(NPCX_ADC_THRESH1, 0);
+ npcx_adc_thresh_int_enable(NPCX_ADC_THRESH2, 0);
+ npcx_set_adc_repetitive(adc_channels[ADC_VSNS_PP3300_A].input_ch, 0);
+
+ /*
+ * If we're already in G3, PP3300_A is already off. Since the ADC
+ * interrupts were already disabled, this data is stale. Therefore,
+ * force the PGOOD value to 0 and have the chipset task re-evaluate.
+ * This should help prevent leakage.
+ */
+ if (chipset_in_state(CHIPSET_STATE_HARD_OFF))
+ pp3300_a_pgood = 0;
+ power_signal_interrupt(GPIO_PG_EC_DSW_PWROK);
+}
+DECLARE_DEFERRED(disable_adc_irqs_deferred);
+
+/*
+ * The ADC interrupts are only needed for booting up. The assumption is that
+ * the PP3300_A rail will not go down during runtime. Therefore, we'll disable
+ * the ADC interrupts shortly after booting up and also after shutting down.
+ */
+static void disable_adc_irqs(void)
+{
+ int delay = 200 * MSEC;
+
+ /*
+ * The EC stays in S5 for about 10s after shutting before heading down
+ * to G3. Therefore, we'll postpone disabling the ADC IRQs until after
+ * this occurs.
+ */
+ if (chipset_in_or_transitioning_to_state(CHIPSET_STATE_ANY_OFF))
+ delay = 15 * SECOND;
+ hook_call_deferred(&disable_adc_irqs_deferred_data, delay);
+}
+DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, disable_adc_irqs, HOOK_PRIO_DEFAULT);
+DECLARE_HOOK(HOOK_CHIPSET_RESUME, disable_adc_irqs, HOOK_PRIO_DEFAULT);
+
+/*
+ * We only need the ADC interrupts functional when powering up. Therefore, only
+ * enable them from our wake sources. These will be the power button, or lid
+ * open. Below is a summary of the ADC interrupt action per power state and
+ * wake source.
+ *
+ * Powering up to S0: ADC interrupts will be disabled after ~200ms.
+ * S0ix/S3: No action as ADC interrupts are already disabled if suspending.
+ * Powering down to S5/G3: ADC interrupts will be disabled after ~15s.
+ * Powering up from S5/G3: ADC interrupts will be enabled. They will be
+ * disabled ~200ms after passing thru S3.
+ * Power button press: If the system is in S5/G3, ADC interrupts will be
+ * enabled.
+ * Lid open: ADC interrupts will be enabled.
+ */
+static void enable_adc_irqs(void)
+{
+ if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) {
+ CPRINTS("%s", __func__);
+ hook_call_deferred(&disable_adc_irqs_deferred_data, -1);
+ npcx_set_adc_repetitive(adc_channels[ADC_VSNS_PP3300_A].input_ch,
+ 1);
+ npcx_adc_thresh_int_enable(NPCX_ADC_THRESH1, 1);
+ npcx_adc_thresh_int_enable(NPCX_ADC_THRESH2, 1);
+ }
+}
+DECLARE_HOOK(HOOK_CHIPSET_STARTUP, enable_adc_irqs, HOOK_PRIO_DEFAULT);
+DECLARE_HOOK(HOOK_POWER_BUTTON_CHANGE, enable_adc_irqs, HOOK_PRIO_DEFAULT);
+
+static void enable_adc_irqs_via_lid(void)
+{
+ if (lid_is_open())
+ enable_adc_irqs();
+}
+DECLARE_HOOK(HOOK_LID_CHANGE, enable_adc_irqs_via_lid, HOOK_PRIO_DEFAULT);
/* I2C Ports */
const struct i2c_port_t i2c_ports[] = {