From 8cf0feb3e2e9ac244ee2b36a0f4fdb4f27fc08f7 Mon Sep 17 00:00:00 2001 From: Mulin Chao Date: Mon, 18 Jul 2022 19:07:32 -0700 Subject: [PATCH] power: npcx: add leakage-io support for better power consumption This CL adds a DT node, 'power_leakage_io', which property, 'leak-gpios', contains GPIOs that have leakage current. In oerder to get better power consumption, npcx power driver will disable the connections between these io pads and input buffers before entering deep sleep. Then, restore the connections after ec wakes up. The users can overwrite this property at board DT file. Here is an example: &power_leakage_io { leak-gpios = <&gpio0 0 0 &gpiob 1 0>; }; Signed-off-by: Mulin Chao --- dts/arm/nuvoton/npcx.dtsi | 8 +++ .../pinctrl/nuvoton,npcx-leakage-io.yaml | 16 +++++ soc/arm/nuvoton_npcx/common/power.c | 65 +++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 dts/bindings/pinctrl/nuvoton,npcx-leakage-io.yaml diff --git a/dts/arm/nuvoton/npcx.dtsi b/dts/arm/nuvoton/npcx.dtsi index 19598e09baf..38369308a18 100644 --- a/dts/arm/nuvoton/npcx.dtsi +++ b/dts/arm/nuvoton/npcx.dtsi @@ -52,6 +52,14 @@ status = "okay"; }; + /* Dummy node of IOs that have leakage current. The user can override + * 'leak-gpios' prop. at board DT file to save more power consumption. + */ + power_leakage_io: power-leakage-io { + compatible = "nuvoton,npcx-leakage-io"; + status = "okay"; + }; + soc { bbram: bb-ram@400af000 { compatible = "nuvoton,npcx-bbram"; diff --git a/dts/bindings/pinctrl/nuvoton,npcx-leakage-io.yaml b/dts/bindings/pinctrl/nuvoton,npcx-leakage-io.yaml new file mode 100644 index 00000000000..f16f6083d18 --- /dev/null +++ b/dts/bindings/pinctrl/nuvoton,npcx-leakage-io.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2022 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton, NPCX power leakage IOs + +compatible: "nuvoton,npcx-leakage-io" + +include: [base.yaml] + +properties: + leak-gpios: + type: phandle-array + required: false + description: | + Array of IOs that have leakage current. The user can overwrite this + property at the board level DT file to save more power consumption. diff --git a/soc/arm/nuvoton_npcx/common/power.c b/soc/arm/nuvoton_npcx/common/power.c index 94363560669..0ab072b4a7b 100644 --- a/soc/arm/nuvoton_npcx/common/power.c +++ b/soc/arm/nuvoton_npcx/common/power.c @@ -47,10 +47,12 @@ #include #include +#include #include #include #include +#include "soc_gpio.h" #include "soc_host.h" #include "soc_power.h" @@ -84,6 +86,57 @@ enum { NPCX_STANDARD_WAKE_UP, }; +#define NODE_LEAKAGE_IO DT_INST(0, nuvoton_npcx_leakage_io) +#if DT_NODE_HAS_PROP(NODE_LEAKAGE_IO, leak_gpios) +struct npcx_leak_gpio { + const struct device *gpio; + gpio_pin_t pin; +}; + +#define NPCX_POWER_LEAKAGE_IO_INIT(node_id, prop, idx) { \ + .gpio = DEVICE_DT_GET(DT_GPIO_CTLR_BY_IDX(node_id, prop, idx)), \ + .pin = DT_GPIO_PIN_BY_IDX(node_id, prop, idx), \ +}, + +/* + * Get io array which have leakage current from 'leak-gpios' property of + * 'power_leakage_io' DT node. User can overwrite this prop. at board DT file to + * save power consumption when ec enter deep sleep. + * + * &power_leakage_io { + * leak-gpios = <&gpio0 0 0 + * &gpiob 1 0>; + * }; + */ +static struct npcx_leak_gpio leak_gpios[] = { + DT_FOREACH_PROP_ELEM(NODE_LEAKAGE_IO, leak_gpios, NPCX_POWER_LEAKAGE_IO_INIT) +}; + +static void npcx_power_suspend_leak_io_pads(void) +{ + for (int i = 0; i < ARRAY_SIZE(leak_gpios); i++) { + npcx_gpio_disable_io_pads(leak_gpios[i].gpio, leak_gpios[i].pin); + } +} + +static void npcx_power_restore_leak_io_pads(void) +{ + for (int i = 0; i < ARRAY_SIZE(leak_gpios); i++) { + npcx_gpio_enable_io_pads(leak_gpios[i].gpio, leak_gpios[i].pin); + } +} +#else +void npcx_power_suspend_leak_io_pads(void) +{ + /* do nothing */ +} + +void npcx_power_restore_leak_io_pads(void) +{ + /* do nothing */ +} +#endif /* DT_NODE_HAS_PROP(NODE_LEAKAGE_IO, leak_gpios) */ + static void npcx_power_enter_system_sleep(int slp_mode, int wk_mode) { /* Disable interrupts */ @@ -99,6 +152,12 @@ static void npcx_power_enter_system_sleep(int slp_mode, int wk_mode) npcx_clock_control_turn_on_system_sleep(slp_mode == NPCX_DEEP_SLEEP, wk_mode == NPCX_INSTANT_WAKE_UP); + /* + * Disable the connection between io pads that have leakage current and + * input buffer to save power consumption. + */ + npcx_power_suspend_leak_io_pads(); + /* Turn on eSPI/LPC host access wake-up interrupt. */ if (IS_ENABLED(CONFIG_ESPI_NPCX)) { npcx_host_enable_access_interrupt(); @@ -129,6 +188,12 @@ static void npcx_power_enter_system_sleep(int slp_mode, int wk_mode) npcx_host_disable_access_interrupt(); } + /* + * Restore the connection between io pads that have leakage current and + * input buffer. + */ + npcx_power_restore_leak_io_pads(); + /* Turn off system sleep mode. */ npcx_clock_control_turn_off_system_sleep(); }