mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-09-02 23:24:11 +00:00
118 lines
5.4 KiB
Plaintext
118 lines
5.4 KiB
Plaintext
/*
|
|
* SPDX-License-Identifier: MIT
|
|
* Devicetree half of boards/common/pm_esp32.conf — auto-paired by
|
|
* zephcore_auto_pair_overlay() in CMakeLists.txt, so passing the .conf is
|
|
* enough; this file does not need to be listed separately.
|
|
*/
|
|
|
|
#include <zephyr/dt-bindings/gpio/gpio.h>
|
|
#include <zephyr/dt-bindings/gpio/espressif-esp32-gpio.h>
|
|
|
|
/*
|
|
* The RTC timer is the wake source for every timed sleep. Upstream leaves it
|
|
* status = "disabled" (zephyr/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi),
|
|
* and soc/espressif/common/power.c checks for it in rtc_wakeup_enable():
|
|
* without a ready rtc_timer device it logs "Sleep skipped. Make sure
|
|
* '&rtc_timer' is enabled as a wakeup source." and returns false — so
|
|
* CONFIG_PM=y on its own is a silent no-op. This is the single easiest thing
|
|
* to forget when enabling ESP32 PM.
|
|
*/
|
|
&rtc_timer {
|
|
status = "okay";
|
|
wakeup-source;
|
|
};
|
|
|
|
/*
|
|
* Arms the GPIO wake path. gpio_esp32_pm_action() calls
|
|
* esp_sleep_enable_gpio_wakeup() on PM_DEVICE_ACTION_RESUME, but only when the
|
|
* PORT is wakeup-capable — that is what pm_device_wakeup_is_capable() tests,
|
|
* and it is set by this property. Per-PIN arming is separate and comes from
|
|
* patches/zephyr/0003, which passes GPIO_INT_WAKEUP on the DIO1 configure.
|
|
* Both halves are needed: the port enables the wake source, the pin selects
|
|
* which line triggers it.
|
|
*
|
|
* gpio0 covers GPIO 0-31, which is where every RTC-capable pin lives on the
|
|
* S3 (0-21) — so this is also the only port that can carry a LoRa DIO1 wake.
|
|
*/
|
|
&gpio0 {
|
|
wakeup-source;
|
|
};
|
|
|
|
/*
|
|
* Hold the SX1262 chip-select across light sleep.
|
|
*
|
|
* Light sleep powers down RTC_PERIPH on this SoC, and every LoRa pin on the
|
|
* allowlisted boards is an RTC-capable pad (GPIO 0-21), so their levels are
|
|
* NOT retained unless explicitly held. The chain:
|
|
*
|
|
* 1. patches/zephyr/0003 passes GPIO_INT_WAKEUP on DIO1. On the S3 that
|
|
* lands on esp_sleep_enable_ext1_wakeup_io() (drivers/gpio/gpio_esp32.c,
|
|
* SOC_PM_SUPPORT_EXT1_WAKEUP), i.e. RTC_EXT1_TRIG_EN.
|
|
* 2. esp_sleep_start() only forces ESP_PD_DOMAIN_RTC_PERIPH on for
|
|
* RTC_EXT0_TRIG_EN | RTC_GPIO_TRIG_EN. EXT1 is not in that mask, so the
|
|
* domain is left AUTO and powered OFF for the whole sleep.
|
|
* 3. ext1_wakeup_prepare() then calls rtcio_hal_hold_enable() for the EXT1
|
|
* pin *only*, and only because RTC_PERIPH is off — IDF's own code
|
|
* treating "RTC_PERIPH down" as "this pad cannot hold its own state".
|
|
* DIO1 survives; nothing else does.
|
|
* 4. Zephyr's general mechanism, esp32_sleep_gpio_prepare(), holds only pins
|
|
* carrying ESP32_GPIO_SLEEP_HOLD_EN. Hence this override.
|
|
*
|
|
* NSS is the pin that matters. Undriven, it floats, and the SX1262 samples
|
|
* SPI commands whenever NSS is low — so a sleeping chip sitting in warm-start
|
|
* sleep with its entire configuration (PA config, OCP, SetTxParams) in
|
|
* retention RAM is exposed to whatever the floating bus does. Nothing in the
|
|
* driver ever re-issues SetTxParams: lora_config() is its only writer and
|
|
* LoRaRadioBase::configure() short-circuits on every transmit after the first,
|
|
* so a corrupted TX power persists until reboot or a `set tx <new value>`.
|
|
* Symptom is a node that still relays but transmits ~30 dB down.
|
|
*
|
|
* Holding NSS high for the duration deselects the chip, which also makes SCK
|
|
* and MOSI harmless — nothing can be clocked in while CS is deasserted, so
|
|
* those pins do not need the pinctrl-side `sleep-hold-en`.
|
|
*
|
|
* All five allowlisted boards (heltec_wifi_lora32_v3/v4/v43,
|
|
* heltec_wireless_tracker/_v2) wire the radio identically — &spi2, NSS GPIO8,
|
|
* RESET GPIO12 — which is what lets this live in one shared overlay. Re-check
|
|
* that before adding a board to the allowlist in CMakeLists.txt.
|
|
*/
|
|
&spi2 {
|
|
cs-gpios = <&gpio0 8 (GPIO_ACTIVE_LOW | ESP32_GPIO_SLEEP_HOLD_EN)>;
|
|
};
|
|
|
|
/*
|
|
* The user button must wake the SoC too.
|
|
*
|
|
* DIO1 is not the only thing that needs to interrupt a sleeping node — a person
|
|
* pressing the button expects the display to come on. Marking the PORT
|
|
* wakeup-source above only enables esp_sleep_enable_gpio_wakeup(); the PIN is
|
|
* armed separately, and until now only DIO1 got that (via patches/zephyr/0003).
|
|
* The result was a node that woke for packets and ignored its own button: press
|
|
* it, nothing happens, the display never lights. Reported from the field.
|
|
*
|
|
* GPIO_INT_WAKEUP is (1 << 6) in dt-bindings/gpio/gpio.h, so it fits the 16-bit
|
|
* gpio_dt_flags_t and can be set here in DT rather than needing a driver patch —
|
|
* gpio_pin_configure_dt() ORs spec->dt_flags into the flags it passes, so it
|
|
* reaches gpio_esp32_config() and arms the wake.
|
|
*
|
|
* All five allowlisted boards put the USER key on the same pad (&gpio0 0 =
|
|
* GPIO0, inside the S3's RTC-capable 0-21 range) under the same node label,
|
|
* which is what lets this be one shared override. Re-check when allowlisting
|
|
* a new board.
|
|
*/
|
|
&button0 {
|
|
gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW | GPIO_INT_WAKEUP)>;
|
|
};
|
|
|
|
/*
|
|
* RESET is open-drain active-low against the SX1262's internal pull-up, so an
|
|
* unheld pad going high-Z already reads as "not reset" and this is belt and
|
|
* braces rather than a known fault. It costs nothing and removes the question
|
|
* of what the pad does on the way into and out of power-down — a spurious low
|
|
* here would reset the radio outright.
|
|
*/
|
|
&lora0 {
|
|
reset-gpios = <&gpio0 12 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_LOW |
|
|
ESP32_GPIO_SLEEP_HOLD_EN)>;
|
|
};
|