drivers: lora: sx1276: support RFI/RFO/PA_BOOST antenna selection

There are several antenna path designs on SX1276 compatible boards in
the wild. B-L072Z-LRWAN1 board has dedicated enable pins for RFI, RFO
and PA_BOOST. This is exactly what this patch allows to
configure. Second variant of antenna selection is done with a single
GPIO pin, which controls RF SPDT switches (input or output). This is
also supported, when either 'rfo-enable-gpios' or
'pa-boost-enable-gpios' property is provided alone (RFO/PA_BOOST is
selected only when transmitting, so there is no need for explicit
'rfi-enable-gpios' configuration).

Drop requirement for 'power-amplifier-output' DT property when there is
either 'rfo-enable-gpios' or 'pa-boost-enable-gpios' configured. Fail
using BUILD_ASSERT() when neither is specified.

Make the SX1276SetAntSw() logic similar to loramac-node examples
implementation, so RFO/PA_BOOST is enabled only in
RFLR_OPMODE_TRANSMITTER.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
This commit is contained in:
Marcin Niestroj 2020-04-07 01:45:43 +02:00 committed by Carles Cufí
commit 2aa161a121
2 changed files with 193 additions and 25 deletions

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2019 Manivannan Sadhasivam
* Copyright (c) 2020 Grinn
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -23,8 +24,20 @@ LOG_MODULE_REGISTER(sx1276);
#define GPIO_RESET_FLAGS DT_INST_GPIO_FLAGS(0, reset_gpios)
#define GPIO_CS_PIN DT_INST_SPI_DEV_CS_GPIOS_PIN(0)
#define PA_PIN DT_ENUM_IDX(DT_DRV_INST(0), \
power_amplifier_output)
#define GPIO_RFI_ENABLE_PIN \
DT_INST_GPIO_PIN(0, rfi_enable_gpios)
#define GPIO_RFI_ENABLE_FLAGS \
DT_INST_GPIO_FLAGS(0, rfi_enable_gpios)
#define GPIO_RFO_ENABLE_PIN \
DT_INST_GPIO_PIN(0, rfo_enable_gpios)
#define GPIO_RFO_ENABLE_FLAGS \
DT_INST_GPIO_FLAGS(0, rfo_enable_gpios)
#define GPIO_PA_BOOST_ENABLE_PIN \
DT_INST_GPIO_PIN(0, pa_boost_enable_gpios)
#define GPIO_PA_BOOST_ENABLE_FLAGS \
DT_INST_GPIO_FLAGS(0, pa_boost_enable_gpios)
/*
* Those macros must be in sync with 'power-amplifier-output' dts property.
@ -32,6 +45,23 @@ LOG_MODULE_REGISTER(sx1276);
#define SX1276_PA_RFO 0
#define SX1276_PA_BOOST 1
#if DT_INST_NODE_HAS_PROP(0, rfo_enable_gpios) && \
DT_INST_NODE_HAS_PROP(0, pa_boost_enable_gpios)
#define SX1276_PA_OUTPUT(power) \
((power) > 14 ? SX1276_PA_BOOST : SX1276_PA_RFO)
#elif DT_INST_NODE_HAS_PROP(0, rfo_enable_gpios)
#define SX1276_PA_OUTPUT(power) SX1276_PA_RFO
#elif DT_INST_NODE_HAS_PROP(0, pa_boost_enable_gpios)
#define SX1276_PA_OUTPUT(power) SX1276_PA_BOOST
#elif DT_INST_NODE_HAS_PROP(0, power_amplifier_output)
#define SX1276_PA_OUTPUT(power) \
DT_ENUM_IDX(DT_DRV_INST(0), power_amplifier_output)
#else
BUILD_ASSERT(0, "None of rfo-enable-gpios, pa-boost-enable-gpios and "
"power-amplifier-output has been specified. "
"Look at semtech,sx1276.yaml to fix that.");
#endif
#define SX1276_REG_PA_CONFIG 0x09
#define SX1276_REG_PA_DAC 0x4d
#define SX1276_REG_VERSION 0x42
@ -63,6 +93,19 @@ static const struct sx1276_dio sx1276_dios[] = { SX1276_DIO_GPIO_INIT(0) };
static struct sx1276_data {
struct device *reset;
#if DT_INST_NODE_HAS_PROP(0, rfi_enable_gpios)
struct device *rfi_enable;
#endif
#if DT_INST_NODE_HAS_PROP(0, rfo_enable_gpios)
struct device *rfo_enable;
#endif
#if DT_INST_NODE_HAS_PROP(0, pa_boost_enable_gpios)
struct device *pa_boost_enable;
#endif
#if DT_INST_NODE_HAS_PROP(0, rfo_enable_gpios) && \
DT_INST_NODE_HAS_PROP(0, pa_boost_enable_gpios)
uint8_t tx_power;
#endif
struct device *spi;
struct spi_config spi_cfg;
struct device *dio_dev[SX1276_MAX_DIO];
@ -86,9 +129,38 @@ bool SX1276CheckRfFrequency(uint32_t frequency)
return true;
}
void SX1276SetAntSwLowPower(bool status)
static inline void sx1276_rfi_enable(int val)
{
/* TODO */
#if DT_INST_NODE_HAS_PROP(0, rfi_enable_gpios)
gpio_pin_set(dev_data.rfi_enable, GPIO_RFI_ENABLE_PIN, val);
#endif
}
static inline void sx1276_rfo_enable(int val)
{
#if DT_INST_NODE_HAS_PROP(0, rfo_enable_gpios)
gpio_pin_set(dev_data.rfo_enable, GPIO_RFO_ENABLE_PIN, val);
#endif
}
static inline void sx1276_pa_boost_enable(int val)
{
#if DT_INST_NODE_HAS_PROP(0, pa_boost_enable_gpios)
gpio_pin_set(dev_data.pa_boost_enable,
GPIO_PA_BOOST_ENABLE_PIN, val);
#endif
}
void SX1276SetAntSwLowPower(bool low_power)
{
if (low_power) {
/* force inactive (low power) state of all antenna paths */
sx1276_rfi_enable(0);
sx1276_rfo_enable(0);
sx1276_pa_boost_enable(0);
} else {
/* rely on SX1276SetAntSw() to configure proper antenna path */
}
}
void SX1276SetBoardTcxo(uint8_t state)
@ -98,7 +170,24 @@ void SX1276SetBoardTcxo(uint8_t state)
void SX1276SetAntSw(uint8_t opMode)
{
/* TODO */
switch (opMode) {
case RFLR_OPMODE_TRANSMITTER:
sx1276_rfi_enable(0);
if (SX1276_PA_OUTPUT(dev_data.tx_power) == SX1276_PA_BOOST) {
sx1276_rfo_enable(0);
sx1276_pa_boost_enable(1);
} else {
sx1276_pa_boost_enable(0);
sx1276_rfo_enable(1);
}
break;
default:
sx1276_rfo_enable(0);
sx1276_pa_boost_enable(0);
sx1276_rfi_enable(1);
break;
}
}
void SX1276Reset(void)
@ -248,7 +337,7 @@ void SX1276SetRfTxPower(int8_t power)
pa_dac &= RF_PADAC_20DBM_MASK;
#if PA_PIN == SX1276_PA_BOOST
if (SX1276_PA_OUTPUT(power) == SX1276_PA_BOOST) {
power = clamp_int8(power, 2, 20);
pa_config |= RF_PACONFIG_PASELECT_PABOOST;
@ -259,7 +348,7 @@ void SX1276SetRfTxPower(int8_t power)
pa_dac |= RF_PADAC_20DBM_OFF;
pa_config |= (power - 2) & 0x0F;
}
#elif PA_PIN == SX1276_PA_RFO
} else {
power = clamp_int8(power, -4, 15);
pa_dac |= RF_PADAC_20DBM_OFF;
@ -271,6 +360,11 @@ void SX1276SetRfTxPower(int8_t power)
/* Set the power range to -4.2 -- 10.8+0.6*0 dBm */
pa_config |= ((power + 4) & 0x0F);
}
}
#if DT_INST_NODE_HAS_PROP(0, rfo_enable_gpios) && \
DT_INST_NODE_HAS_PROP(0, pa_boost_enable_gpios)
dev_data.tx_power = power;
#endif
ret = sx1276_write(SX1276_REG_PA_CONFIG, &pa_config, 1);
@ -311,6 +405,54 @@ const struct Radio_s Radio = {
.SetTxContinuousWave = SX1276SetTxContinuousWave,
};
static int sx1276_antenna_configure(void)
{
int ret = 0;
#if DT_INST_NODE_HAS_PROP(0, rfi_enable_gpios)
dev_data.rfi_enable = device_get_binding(
DT_INST_GPIO_LABEL(0, rfi_enable_gpios));
if (!dev_data.rfi_enable) {
LOG_ERR("Cannot get pointer to %s device",
DT_INST_GPIO_LABEL(0, rfi_enable_gpios));
return -EIO;
}
ret = gpio_pin_configure(dev_data.rfi_enable, GPIO_RFI_ENABLE_PIN,
GPIO_OUTPUT_INACTIVE | GPIO_RFI_ENABLE_FLAGS);
#endif
#if DT_INST_NODE_HAS_PROP(0, rfo_enable_gpios)
dev_data.rfo_enable = device_get_binding(
DT_INST_GPIO_LABEL(0, rfo_enable_gpios));
if (!dev_data.rfo_enable) {
LOG_ERR("Cannot get pointer to %s device",
DT_INST_GPIO_LABEL(0, rfo_enable_gpios));
return -EIO;
}
ret = gpio_pin_configure(dev_data.rfo_enable, GPIO_RFO_ENABLE_PIN,
GPIO_OUTPUT_INACTIVE | GPIO_RFO_ENABLE_FLAGS);
#endif
#if DT_INST_NODE_HAS_PROP(0, pa_boost_enable_gpios)
dev_data.pa_boost_enable = device_get_binding(
DT_INST_GPIO_LABEL(0, pa_boost_enable_gpios));
if (!dev_data.pa_boost_enable) {
LOG_ERR("Cannot get pointer to %s device",
DT_INST_GPIO_LABEL(0, pa_boost_enable_gpios));
return -EIO;
}
ret = gpio_pin_configure(dev_data.pa_boost_enable,
GPIO_PA_BOOST_ENABLE_PIN,
GPIO_OUTPUT_INACTIVE |
GPIO_PA_BOOST_ENABLE_FLAGS);
#endif
return ret;
}
static int sx1276_lora_init(struct device *dev)
{
#if DT_INST_SPI_DEV_HAS_CS_GPIOS(0)
@ -366,6 +508,12 @@ static int sx1276_lora_init(struct device *dev)
return -EIO;
}
ret = sx1276_antenna_configure();
if (ret < 0) {
LOG_ERR("Unable to configure antenna");
return -EIO;
}
LOG_INF("SX1276 Version:%02x found", regval);
ret = sx12xx_init(dev);

View file

@ -28,9 +28,29 @@ properties:
power-amplifier-output:
type: string
required: true
required: false
description: |
Selects power amplifier output pin.
Selects power amplifier output pin. This is required when neither
'rfo-enable-gpios' nor 'pa-boost-enable-gpios' is specified. In other
case this property is simply ignored.
enum:
- "rfo"
- "pa-boost"
rfi-enable-gpios:
type: phandle-array
required: false
description: |
RFI antenna input enable pin.
rfo-enable-gpios:
type: phandle-array
required: false
description: |
RFO antenna output enable pin.
pa-boost-enable-gpios:
type: phandle-array
required: false
description: |
PA_BOOST antenna output enable pin.