diff options
author | Aseda Aboagye <aaboagye@google.com> | 2020-06-05 17:25:08 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-06-21 06:33:31 +0000 |
commit | 33aa3c9a732fccefba54d5bd15c321ce6cbc8d80 (patch) | |
tree | eaf62bc673e15d2a45f7966ff71b682dab439663 /baseboard | |
parent | 36cf95c854f00a6457c85edb97cedf6891cc1f6c (diff) | |
download | chrome-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>
Diffstat (limited to 'baseboard')
-rw-r--r-- | baseboard/dedede/variant_ec_npcx796fc.c | 82 |
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[] = { |