From a9cca82c7e3a53338080764fb050a85fdd8e2751 Mon Sep 17 00:00:00 2001 From: Stevan Bowles Date: Tue, 24 Mar 2026 16:37:31 -0400 Subject: [PATCH] drivers: lora: add support for runtime power adjustments Make dts field power-amplifier-output optional. If defined, the radio will remain bound to the power mode defined. Otherwise, the radio will be free to dynamically switch between high and low power modes based off the power level input. Signed-off-by: Stevan Bowles --- drivers/lora/loramac_node/sx126x.c | 9 +----- drivers/lora/loramac_node/sx126x_common.h | 8 +++++ drivers/lora/loramac_node/sx126x_stm32wl.c | 31 ++++++++++++++++--- .../lora/st,stm32wl-subghz-radio.yaml | 1 - 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/drivers/lora/loramac_node/sx126x.c b/drivers/lora/loramac_node/sx126x.c index e37e8ceef6568..4b869ab8ecdd6 100644 --- a/drivers/lora/loramac_node/sx126x.c +++ b/drivers/lora/loramac_node/sx126x.c @@ -290,13 +290,6 @@ RadioOperatingModes_t SX126xGetOperatingMode(void) return dev_data.mode; } -#if HAVE_GPIO_FE_CTRL -static const enum { - RFO_LP, - RFO_HP, -} pa_output = DT_INST_STRING_UPPER_TOKEN(0, power_amplifier_output); -#endif - #define LORA_NODE DT_NODELABEL(lora) @@ -324,7 +317,7 @@ void SX126xSetOperatingMode(RadioOperatingModes_t mode) sx126x_set_tx_enable(1); #endif #if HAVE_GPIO_FE_CTRL - if (pa_output == RFO_LP) { + if (sx126x_get_tx_power_mode() == RFO_LP) { sx126x_set_fe_ctrl(txlp_fe_ctrl_lines[0], txlp_fe_ctrl_lines[1], txlp_fe_ctrl_lines[2]); } else { sx126x_set_fe_ctrl(txhp_fe_ctrl_lines[0], txhp_fe_ctrl_lines[1], txhp_fe_ctrl_lines[2]); diff --git a/drivers/lora/loramac_node/sx126x_common.h b/drivers/lora/loramac_node/sx126x_common.h index 8dbe8af620f04..d64d51a4a50cc 100644 --- a/drivers/lora/loramac_node/sx126x_common.h +++ b/drivers/lora/loramac_node/sx126x_common.h @@ -35,6 +35,7 @@ #define HAVE_GPIO_TX_ENABLE DT_INST_NODE_HAS_PROP(0, tx_enable_gpios) #define HAVE_GPIO_RX_ENABLE DT_INST_NODE_HAS_PROP(0, rx_enable_gpios) #define HAVE_GPIO_FE_CTRL (DT_INST_NODE_HAS_PROP(0, fe_ctrl1_enable_gpios) && !DT_INST_NODE_HAS_PROP(0, tx_enable_gpios)) +#define HAVE_PA_OUTPUT_LOCKED DT_INST_NODE_HAS_PROP(0, power_amplifier_output) struct sx126x_config { struct spi_dt_spec bus; @@ -74,6 +75,13 @@ void sx126x_dio1_irq_disable(struct sx126x_data *dev_data); void sx126x_set_tx_params(int8_t power, RadioRampTimes_t ramp_time); +enum sx126x_pa_output { + RFO_LP, + RFO_HP, +}; + +enum sx126x_pa_output sx126x_get_tx_power_mode(void); + int sx126x_variant_init(const struct device *dev); #endif /* ZEPHYR_DRIVERS_SX126X_COMMON_H_ */ diff --git a/drivers/lora/loramac_node/sx126x_stm32wl.c b/drivers/lora/loramac_node/sx126x_stm32wl.c index c6a484ab34f69..24c740f97a726 100644 --- a/drivers/lora/loramac_node/sx126x_stm32wl.c +++ b/drivers/lora/loramac_node/sx126x_stm32wl.c @@ -16,10 +16,14 @@ #include LOG_MODULE_DECLARE(sx126x, CONFIG_LORA_LOG_LEVEL); -static const enum { - RFO_LP, - RFO_HP, -} pa_output = DT_INST_STRING_UPPER_TOKEN(0, power_amplifier_output); +#if HAVE_PA_OUTPUT_LOCKED +static enum sx126x_pa_output pa_output = + DT_INST_STRING_UPPER_TOKEN(0, power_amplifier_output); +static const bool pa_output_locked = true; +#else +static enum sx126x_pa_output pa_output = RFO_LP; +static const bool pa_output_locked = false; +#endif void sx126x_reset(struct sx126x_data *dev_data) { @@ -53,6 +57,18 @@ void sx126x_dio1_irq_disable(struct sx126x_data *dev_data) void sx126x_set_tx_params(int8_t power, RadioRampTimes_t ramp_time) { uint8_t buf[2]; + const int8_t lp_max = DT_INST_PROP(0, rfo_lp_max_power); + + if (!pa_output_locked) { + /* Auto-select PA output based on requested power level */ + if (power > lp_max) { + pa_output = RFO_HP; + } else { + pa_output = RFO_LP; + } + } + + LOG_DBG("tx_params PA mode: %s", pa_output == RFO_LP ? "RFO_LP" : "RFO_HP"); if (pa_output == RFO_LP) { const int8_t max_power = DT_INST_PROP(0, rfo_lp_max_power); @@ -110,6 +126,8 @@ void sx126x_set_tx_params(int8_t power, RadioRampTimes_t ramp_time) SX126xWriteRegister(REG_OCP, 0x38); } + LOG_DBG("tx_params final: reg_power=%d ramp=%u", power, ramp_time); + buf[0] = power; buf[1] = (uint8_t)ramp_time; SX126xWriteCommand(RADIO_SET_TXPARAMS, buf, 2); @@ -123,6 +141,11 @@ static void radio_isr(const struct device *dev) k_work_submit(&dev_data->dio1_irq_work); } +enum sx126x_pa_output sx126x_get_tx_power_mode(void) +{ + return pa_output; +} + int sx126x_variant_init(const struct device *dev) { IRQ_CONNECT(DT_INST_IRQN(0), diff --git a/dts/bindings/lora/st,stm32wl-subghz-radio.yaml b/dts/bindings/lora/st,stm32wl-subghz-radio.yaml index 1eaa264cf2882..c68c4ddc08ecb 100644 --- a/dts/bindings/lora/st,stm32wl-subghz-radio.yaml +++ b/dts/bindings/lora/st,stm32wl-subghz-radio.yaml @@ -15,7 +15,6 @@ properties: power-amplifier-output: type: string - required: true description: | Selects between the low- and high-power power amplifier output pin. enum: