This commit is contained in:
Pete Johanson 2024-09-02 10:07:56 -05:00 committed by GitHub
commit 84c6ce9c54
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 212 additions and 67 deletions

View file

@ -275,9 +275,16 @@ if ZMK_RGB_UNDERGLOW
config SPI config SPI
default y default y
config ZMK_RGB_UNDERGLOW_DEFAULT_POWER_DOMAIN
bool "Auto-assign the RGB underglow to the default power domain"
default y
depends on ZMK_POWER_DOMAINS_DYNAMIC_DEFAULT
config ZMK_RGB_UNDERGLOW_EXT_POWER config ZMK_RGB_UNDERGLOW_EXT_POWER
bool "RGB underglow toggling also controls external power" bool "RGB underglow toggling also controls external power"
default y default y
depends on !ZMK_POWER_DOMAINS
config ZMK_RGB_UNDERGLOW_BRT_MIN config ZMK_RGB_UNDERGLOW_BRT_MIN
int "RGB underglow minimum brightness in percent" int "RGB underglow minimum brightness in percent"
@ -340,6 +347,7 @@ config ZMK_RGB_UNDERGLOW_AUTO_OFF_USB
bool "Turn off RGB underglow when USB is disconnected" bool "Turn off RGB underglow when USB is disconnected"
depends on USB_DEVICE_STACK depends on USB_DEVICE_STACK
#ZMK_RGB_UNDERGLOW #ZMK_RGB_UNDERGLOW
endif endif
@ -414,23 +422,37 @@ config ZMK_SLEEP
depends on HAS_POWEROFF depends on HAS_POWEROFF
select POWEROFF select POWEROFF
select ZMK_PM_DEVICE_SUSPEND_RESUME select ZMK_PM_DEVICE_SUSPEND_RESUME
select PM_DEVICE
imply USB imply USB
if ZMK_SLEEP
config PM_DEVICE
default y
config ZMK_IDLE_SLEEP_TIMEOUT config ZMK_IDLE_SLEEP_TIMEOUT
int "Milliseconds of inactivity before entering deep sleep" int "Milliseconds of inactivity before entering deep sleep"
depends on ZMK_SLEEP
default 900000 default 900000
#ZMK_SLEEP config ZMK_POWER_DOMAINS
endif bool "Enable automatic power domain handling"
default n
select PM_DEVICE
select PM_DEVICE_POWER_DOMAIN
select PM_DEVICE_RUNTIME
select POWER_DOMAIN
select POWER_DOMAIN_GPIO
config ZMK_POWER_DOMAINS_DYNAMIC_DEFAULT
bool "Enable assigning peripherals to the chosen default power domain"
default n
depends on ZMK_POWER_DOMAINS
select PM_DEVICE_POWER_DOMAIN_DYNAMIC
select DEVICE_DEPS_DYNAMIC
# Default this to 2, the most common scenario for this for ZMK is RGB + OLED
config PM_DEVICE_POWER_DOMAIN_DYNAMIC_NUM
default 2
config ZMK_EXT_POWER config ZMK_EXT_POWER
bool "Enable support to control external power output" bool "Enable support to control external power output"
default y default y if !ZMK_POWER_DOMAINS
config ZMK_PM config ZMK_PM
bool bool

View file

@ -5,9 +5,13 @@
config BOARD_NICE_NANO config BOARD_NICE_NANO
bool "nice!nano" bool "nice!nano"
imply ZMK_POWER_DOMAINS
imply ZMK_POWER_DOMAINS_DYNAMIC_DEFAULT
depends on SOC_NRF52840_QIAA depends on SOC_NRF52840_QIAA
config BOARD_NICE_NANO_V2 config BOARD_NICE_NANO_V2
bool "nice!nano v2" bool "nice!nano v2"
imply ZMK_POWER_DOMAINS
imply ZMK_POWER_DOMAINS_DYNAMIC_DEFAULT
depends on SOC_NRF52840_QIAA depends on SOC_NRF52840_QIAA

View file

@ -55,3 +55,6 @@ pro_micro_d: &pro_micro {};
pro_micro_i2c: &i2c0 {}; pro_micro_i2c: &i2c0 {};
pro_micro_spi: &spi1 {}; pro_micro_spi: &spi1 {};
pro_micro_serial: &uart0 {}; pro_micro_serial: &uart0 {};
pro_micro_power_domain: &core_power_domain {};

View file

@ -10,12 +10,15 @@
/ { / {
chosen { chosen {
zmk,battery = &vbatt; zmk,battery = &vbatt;
zmk,default-power-domain = &core_power_domain;
}; };
// Node name must match original "EXT_POWER" label to preserve user settings. core_power_domain: core_power_domain {
EXT_POWER { compatible = "power-domain-gpio", "power-domain";
compatible = "zmk,ext-power-generic"; startup-delay-us = <50000>;
control-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; off-on-delay-us = <50000>;
enable-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
zephyr,pm-device-runtime-auto;
}; };
vbatt: vbatt { vbatt: vbatt {
@ -25,3 +28,5 @@
full-ohms = <(2000000 + 806000)>; full-ohms = <(2000000 + 806000)>;
}; };
}; };
#include "arduino_pro_micro_pins.dtsi"

View file

@ -6,7 +6,6 @@
#include <nordic/nrf52840_qiaa.dtsi> #include <nordic/nrf52840_qiaa.dtsi>
#include "nice_nano-pinctrl.dtsi" #include "nice_nano-pinctrl.dtsi"
#include "arduino_pro_micro_pins.dtsi"
/ { / {
model = "nice!nano"; model = "nice!nano";

View file

@ -10,16 +10,20 @@
/ { / {
chosen { chosen {
zmk,battery = &vbatt; zmk,battery = &vbatt;
zmk,default-power-domain = &core_power_domain;
}; };
// Node name must match original "EXT_POWER" label to preserve user settings. core_power_domain: core_power_domain {
EXT_POWER { compatible = "power-domain-gpio", "power-domain";
compatible = "zmk,ext-power-generic"; startup-delay-us = <50000>;
control-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; off-on-delay-us = <50000>;
init-delay-ms = <50>; enable-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
zephyr,pm-device-runtime-auto;
}; };
vbatt: vbatt { vbatt: vbatt {
compatible = "zmk,battery-nrf-vddh"; compatible = "zmk,battery-nrf-vddh";
}; };
}; };
#include "arduino_pro_micro_pins.dtsi"

View file

@ -5,4 +5,6 @@
config BOARD_PUCHI_BLE_v1 config BOARD_PUCHI_BLE_v1
bool "puchi_ble_v1" bool "puchi_ble_v1"
imply ZMK_POWER_DOMAINS
imply ZMK_POWER_DOMAINS_DYNAMIC_DEFAULT
depends on SOC_NRF52840_QIAA depends on SOC_NRF52840_QIAA

View file

@ -57,3 +57,5 @@ pro_micro_d: &pro_micro {};
pro_micro_i2c: &i2c0 {}; pro_micro_i2c: &i2c0 {};
pro_micro_spi: &spi0 {}; pro_micro_spi: &spi0 {};
pro_micro_serial: &uart0 {}; pro_micro_serial: &uart0 {};
pro_micro_power_domain: &core_power_domain {};

View file

@ -6,7 +6,6 @@
/dts-v1/; /dts-v1/;
#include <nordic/nrf52840_qiaa.dtsi> #include <nordic/nrf52840_qiaa.dtsi>
#include "arduino_pro_micro_pins.dtsi"
#include "puchi_ble_v1-pinctrl.dtsi" #include "puchi_ble_v1-pinctrl.dtsi"
/ { / {
@ -18,6 +17,7 @@
zephyr,sram = &sram0; zephyr,sram = &sram0;
zephyr,flash = &flash0; zephyr,flash = &flash0;
zmk,battery = &vbatt; zmk,battery = &vbatt;
zmk,default-power-domain = &core_power_domain;
}; };
leds { leds {
@ -33,6 +33,14 @@
control-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; control-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
}; };
core_power_domain: core_power_domain {
compatible = "power-domain-gpio", "power-domain";
startup-delay-us = <50000>;
off-on-delay-us = <50000>;
enable-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
zephyr,pm-device-runtime-auto;
};
vbatt: vbatt { vbatt: vbatt {
compatible = "zmk,battery-voltage-divider"; compatible = "zmk,battery-voltage-divider";
io-channels = <&adc 2>; io-channels = <&adc 2>;
@ -111,3 +119,6 @@ zephyr_udc0: &usbd {
}; };
}; };
}; };
// Included at the end to ensure the power domain DTS node exists
#include "arduino_pro_micro_pins.dtsi"

View file

@ -3,6 +3,17 @@
if SHIELD_ZMK_UNO_BASE if SHIELD_ZMK_UNO_BASE
config SHIELD_ZMK_UNO_PM
bool "ZMK Uno Automatic Power Management"
default y
select ZMK_POWER_DOMAINS
select ZMK_POWER_DOMAINS_DYNAMIC_DEFAULT
select PM_DEVICE
select PM_DEVICE_POWER_DOMAIN
select PM_DEVICE_RUNTIME
select POWER_DOMAIN
select POWER_DOMAIN_GPIO
config ZMK_KEYBOARD_NAME config ZMK_KEYBOARD_NAME
default "ZMK Uno" default "ZMK Uno"

View file

@ -0,0 +1 @@
CONFIG_ZMK_POWER_DOMAINS=y

View file

@ -20,11 +20,17 @@ nice_view_spi: &arduino_spi {
// on the bus, properly picking up the first `cs-gpios` specifier. // on the bus, properly picking up the first `cs-gpios` specifier.
ls0xx@0 { ls0xx@0 {
reg = <0>; reg = <0>;
power-domain = <&core_power_domain>;
zephyr,pm-device-runtime-auto;
}; };
led_strip: ws2812@0 { led_strip: ws2812@0 {
compatible = "worldsemi,ws2812-spi"; compatible = "worldsemi,ws2812-spi";
power-domain = <&rgb_power>;
zephyr,pm-device-runtime-auto;
/* SPI */ /* SPI */
reg = <0>; /* ignored, but necessary for SPI bindings */ reg = <0>; /* ignored, but necessary for SPI bindings */
spi-max-frequency = <4000000>; spi-max-frequency = <4000000>;
@ -35,6 +41,7 @@ nice_view_spi: &arduino_spi {
spi-zero-frame = <0x40>; spi-zero-frame = <0x40>;
color-mapping = <LED_COLOR_ID_GREEN LED_COLOR_ID_RED LED_COLOR_ID_BLUE>; color-mapping = <LED_COLOR_ID_GREEN LED_COLOR_ID_RED LED_COLOR_ID_BLUE>;
}; };
}; };
@ -42,19 +49,27 @@ nice_view_spi: &arduino_spi {
chosen { chosen {
zmk,backlight = &backlight; zmk,backlight = &backlight;
zmk,underglow = &led_strip; zmk,underglow = &led_strip;
zephyr,display = &oled;
zmk,display-default-power-domain = &core_power_domain;
}; };
// Commented out until we add more powerful power domain support core_power_domain: core_power_domain {
// external_power { // The "power-domain" compatible is needed for any PDs used for that have dynamic deps,
// compatible = "zmk,ext-power-generic"; // e.g. for displays or RGB not assigned to the PD in the devicetree statically.
// init-delay-ms = <200>; compatible = "power-domain-gpio", "power-domain";
// control-gpios = <&arduino_header 1 GPIO_ACTIVE_LOW>; startup-delay-us = <2000>;
// }; off-on-delay-us = <2000>;
enable-gpios = <&arduino_header 0 GPIO_ACTIVE_LOW>;
zephyr,pm-device-runtime-auto;
};
rgb_power { rgb_power: rgb_power {
compatible = "zmk,ext-power-generic"; compatible = "power-domain-gpio";
init-delay-ms = <200>; startup-delay-us = <200>;
control-gpios = <&arduino_header 1 GPIO_ACTIVE_LOW>; off-on-delay-us = <2000>;
enable-gpios = <&arduino_header 1 GPIO_ACTIVE_LOW>;
power-domain = <&core_power_domain>;
zephyr,pm-device-runtime-auto;
}; };
backlight: gpioleds { backlight: gpioleds {

View file

@ -13,6 +13,7 @@
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
#include <zephyr/pm/device.h> #include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>
#include <zephyr/sys/util.h> #include <zephyr/sys/util.h>
#include <zmk/debounce.h> #include <zmk/debounce.h>

View file

@ -11,6 +11,7 @@
#include <zephyr/drivers/gpio.h> #include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/kscan.h> #include <zephyr/drivers/kscan.h>
#include <zephyr/pm/device.h> #include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
#include <zephyr/sys/__assert.h> #include <zephyr/sys/__assert.h>

View file

@ -13,6 +13,11 @@ config ZMK_DISPLAY_BLANK_ON_IDLE
bool "Blank display on idle" bool "Blank display on idle"
default y if SSD1306 default y if SSD1306
config ZMK_DISPLAY_DEFAULT_POWER_DOMAIN
bool "Auto-assign the display to the default power domain"
default y
depends on ZMK_POWER_DOMAINS_DYNAMIC_DEFAULT
if LV_USE_THEME_MONO if LV_USE_THEME_MONO
config ZMK_DISPLAY_INVERT config ZMK_DISPLAY_INVERT

View file

@ -7,6 +7,8 @@
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <zephyr/init.h> #include <zephyr/init.h>
#include <zephyr/device.h> #include <zephyr/device.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>
#include <zephyr/devicetree.h> #include <zephyr/devicetree.h>
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
@ -55,7 +57,16 @@ void display_timer_cb() { k_work_submit_to_queue(zmk_display_work_q(), &display_
K_TIMER_DEFINE(display_timer, display_timer_cb, NULL); K_TIMER_DEFINE(display_timer, display_timer_cb, NULL);
void unblank_display_cb(struct k_work *work) { void unblank_display_cb(struct k_work *work) {
int err = pm_device_runtime_get(display);
if (err < 0) {
LOG_ERR("Failed to get the display device PM (%d)", err);
return;
}
display_blanking_off(display); display_blanking_off(display);
lv_obj_invalidate(lv_scr_act());
k_timer_start(&display_timer, K_MSEC(TICK_MS), K_MSEC(TICK_MS)); k_timer_start(&display_timer, K_MSEC(TICK_MS), K_MSEC(TICK_MS));
} }
@ -64,6 +75,7 @@ void unblank_display_cb(struct k_work *work) {
void blank_display_cb(struct k_work *work) { void blank_display_cb(struct k_work *work) {
k_timer_stop(&display_timer); k_timer_stop(&display_timer);
display_blanking_on(display); display_blanking_on(display);
pm_device_runtime_put(display);
} }
K_WORK_DEFINE(blank_display_work, blank_display_cb); K_WORK_DEFINE(blank_display_work, blank_display_cb);
K_WORK_DEFINE(unblank_display_work, unblank_display_cb); K_WORK_DEFINE(unblank_display_work, unblank_display_cb);
@ -99,6 +111,13 @@ static void initialize_theme() {
#endif // CONFIG_LV_USE_THEME_MONO #endif // CONFIG_LV_USE_THEME_MONO
} }
#define HAS_DISPLAY_PD \
(DT_HAS_CHOSEN(zmk_display_default_power_domain) || DT_HAS_CHOSEN(zmk_default_power_domain))
#define GET_DISPLAY_PD \
DEVICE_DT_GET(COND_CODE_1(DT_HAS_CHOSEN(zmk_display_default_power_domain), \
(DT_CHOSEN(zmk_display_default_power_domain)), \
(DT_CHOSEN(zmk_default_power_domain))))
void initialize_display(struct k_work *work) { void initialize_display(struct k_work *work) {
LOG_DBG(""); LOG_DBG("");
@ -107,6 +126,16 @@ void initialize_display(struct k_work *work) {
return; return;
} }
#if IS_ENABLED(CONFIG_ZMK_DISPLAY_DEFAULT_POWER_DOMAIN) && HAS_DISPLAY_PD
pm_device_runtime_enable(display);
if (!pm_device_on_power_domain(display)) {
int rc = pm_device_power_domain_add(display, GET_DISPLAY_PD);
if (rc < 0) {
LOG_ERR("Failed to add the display to the default power domain (0x%02x)", -rc);
}
}
#endif
initialized = true; initialized = true;
initialize_theme(); initialize_theme();

View file

@ -11,6 +11,7 @@
#include <zephyr/drivers/kscan.h> #include <zephyr/drivers/kscan.h>
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
#include <zephyr/pm/device.h> #include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>
#include <zmk/event_manager.h> #include <zmk/event_manager.h>
#include <zmk/behavior.h> #include <zmk/behavior.h>

View file

@ -7,6 +7,8 @@
#include <zephyr/device.h> #include <zephyr/device.h>
#include <zephyr/init.h> #include <zephyr/init.h>
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>
#include <zephyr/settings/settings.h> #include <zephyr/settings/settings.h>
#include <math.h> #include <math.h>
@ -60,7 +62,7 @@ struct rgb_underglow_state {
bool on; bool on;
}; };
static const struct device *led_strip; static const struct device *led_strip = DEVICE_DT_GET(STRIP_CHOSEN);
static struct led_rgb pixels[STRIP_NUM_PIXELS]; static struct led_rgb pixels[STRIP_NUM_PIXELS];
@ -243,9 +245,15 @@ static void zmk_rgb_underglow_save_state_work(struct k_work *_work) {
static struct k_work_delayable underglow_save_work; static struct k_work_delayable underglow_save_work;
#endif #endif
static int zmk_rgb_underglow_init(void) { #define HAS_RGB_UG_PD \
led_strip = DEVICE_DT_GET(STRIP_CHOSEN); (DT_HAS_CHOSEN(zmk_rgb_underglow_default_power_domain) || \
DT_HAS_CHOSEN(zmk_default_power_domain))
#define GET_RGB_UG_PD \
DEVICE_DT_GET(COND_CODE_1(DT_HAS_CHOSEN(zmk_rgb_underglow_default_power_domain), \
(DT_CHOSEN(zmk_rgb_underglow_default_power_domain)), \
(DT_CHOSEN(zmk_default_power_domain))))
static int zmk_rgb_underglow_init(void) {
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER) #if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER)
if (!device_is_ready(ext_power)) { if (!device_is_ready(ext_power)) {
LOG_ERR("External power device \"%s\" is not ready", ext_power->name); LOG_ERR("External power device \"%s\" is not ready", ext_power->name);
@ -253,6 +261,18 @@ static int zmk_rgb_underglow_init(void) {
} }
#endif #endif
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_DEFAULT_POWER_DOMAIN) && HAS_RGB_UG_PD
pm_device_runtime_enable(led_strip);
if (!pm_device_on_power_domain(led_strip)) {
int rc = pm_device_power_domain_add(led_strip, GET_RGB_UG_PD);
if (rc < 0) {
LOG_ERR("Failed to add the LED strip to the default power domain (0x%02x)", -rc);
}
}
#endif
state = (struct rgb_underglow_state){ state = (struct rgb_underglow_state){
color : { color : {
h : CONFIG_ZMK_RGB_UNDERGLOW_HUE_START, h : CONFIG_ZMK_RGB_UNDERGLOW_HUE_START,
@ -274,6 +294,7 @@ static int zmk_rgb_underglow_init(void) {
#endif #endif
if (state.on) { if (state.on) {
pm_device_runtime_get(led_strip);
k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50)); k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50));
} }
@ -298,8 +319,12 @@ int zmk_rgb_underglow_get_state(bool *on_off) {
} }
int zmk_rgb_underglow_on(void) { int zmk_rgb_underglow_on(void) {
if (!led_strip) // Newer PM device approach to ensuring powered on when used.
return -ENODEV; int rc = pm_device_runtime_get(led_strip);
if (rc < 0) {
LOG_ERR("Failed to enable/get the PM device (%d)", rc);
return rc;
}
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER) #if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER)
if (ext_power != NULL) { if (ext_power != NULL) {
@ -345,6 +370,8 @@ int zmk_rgb_underglow_off(void) {
k_timer_stop(&underglow_tick); k_timer_stop(&underglow_tick);
state.on = false; state.on = false;
pm_device_runtime_put(led_strip);
return zmk_rgb_underglow_save_state(); return zmk_rgb_underglow_save_state();
} }

View file

@ -4,10 +4,12 @@ manifest:
url-base: https://github.com/zephyrproject-rtos url-base: https://github.com/zephyrproject-rtos
- name: zmkfirmware - name: zmkfirmware
url-base: https://github.com/zmkfirmware url-base: https://github.com/zmkfirmware
- name: petejohanson
url-base: https://github.com/petejohanson
projects: projects:
- name: zephyr - name: zephyr
remote: zmkfirmware remote: petejohanson
revision: v3.5.0+zmk-fixes revision: v3.5-device-power-management
clone-depth: 1 clone-depth: 1
import: import:
name-blocklist: name-blocklist: