Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,11 @@
multiplexing-mode = <0>;
};
};

&gpiote130 {
status = "okay";
};

&gpio2 {
status = "okay";
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,11 @@
multiplexing-mode = <0>;
};
};

&gpiote130 {
status = "okay";
};

&gpio2 {
status = "okay";
};
86 changes: 69 additions & 17 deletions subsys/bluetooth/controller/cs_antenna_switch.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/pm/device_runtime.h>

#include <hal/nrf_gpio.h>

#if DT_NODE_EXISTS(DT_NODELABEL(cs_antenna_switch))
#define ANTENNA_SWITCH_NODE DT_NODELABEL(cs_antenna_switch)
Expand Down Expand Up @@ -54,6 +57,48 @@ static const struct gpio_dt_spec gpio_dt_spec_table[] = {
#endif
};

#define ANT_GPIO_NODE(i) DT_PHANDLE_BY_IDX(ANTENNA_SWITCH_NODE, ant_gpios, i)
#define ANT_GPIO_PORT(i) DT_PROP(ANT_GPIO_NODE(i), port)
#define ANT_GPIO_FLAGS(i) DT_GPIO_FLAGS_BY_IDX(ANTENNA_SWITCH_NODE, ant_gpios, i)
#define ANT_GPIO_PIN(i) DT_GPIO_PIN_BY_IDX(ANTENNA_SWITCH_NODE, ant_gpios, i)
#define CONCAT_HELPER(prefix, value) prefix##value
#define CONCAT_MACRO(prefix, value) CONCAT_HELPER(prefix, value)

typedef struct {
NRF_GPIO_Type *port;
uint8_t pin;
uint32_t flags;
} antenna_pin;

static const antenna_pin pins_table[] = {
{.port = CONCAT_MACRO(NRF_P, ANT_GPIO_PORT(0)),
.pin = ANT_GPIO_PIN(0),
.flags = ANT_GPIO_FLAGS(0)},
{.port = CONCAT_MACRO(NRF_P, ANT_GPIO_PORT(1)),
.pin = ANT_GPIO_PIN(1),
.flags = ANT_GPIO_FLAGS(1)},
#if !MULTIPLEXED
{.port = CONCAT_MACRO(NRF_P, ANT_GPIO_PORT(2)),
.pin = ANT_GPIO_PIN(2),
.flags = ANT_GPIO_FLAGS(2)},
{.port = CONCAT_MACRO(NRF_P, ANT_GPIO_PORT(3)),
.pin = ANT_GPIO_PIN(3),
.flags = ANT_GPIO_FLAGS(3)},
#endif
};

static void m_gpio_pin_set(uint8_t pin_idx, uint32_t value)
{
/* Use nrf_gpio APIs here since this function can be called from
* interrupt context and must not use Zephyr APIs/blocking APIs.
*/
if (pins_table[pin_idx].flags & GPIO_ACTIVE_LOW) {
nrf_gpio_port_pin_write(pins_table[pin_idx].port, pins_table[pin_idx].pin, !value);
} else {
nrf_gpio_port_pin_write(pins_table[pin_idx].port, pins_table[pin_idx].pin, value);
}
}

/* Antenna control below is implemented as described in the CS documentation.
*
* Example valid device tree configuration for the nRF54L15:
Expand All @@ -73,24 +118,17 @@ static const struct gpio_dt_spec gpio_dt_spec_table[] = {
*/
void cs_antenna_switch_func(uint8_t antenna_number)
{
int err;
#if MULTIPLEXED
err = gpio_pin_set_dt(&gpio_dt_spec_table[0], antenna_number & (1 << 0));
__ASSERT_NO_MSG(err == 0);

m_gpio_pin_set(0, antenna_number & (1 << 0));
#if NUM_GPIOS > 1
err = gpio_pin_set_dt(&gpio_dt_spec_table[1], antenna_number & (1 << 1));
__ASSERT_NO_MSG(err == 0);
m_gpio_pin_set(1, antenna_number & (1 << 1));
#endif
#else
if (currently_active_antenna != antenna_number) {
if (currently_active_antenna != ANTENNA_NOT_SET) {
err = gpio_pin_set_dt(&gpio_dt_spec_table[currently_active_antenna], false);
__ASSERT_NO_MSG(err == 0);
m_gpio_pin_set(currently_active_antenna, false);
}

err = gpio_pin_set_dt(&gpio_dt_spec_table[antenna_number], true);
__ASSERT_NO_MSG(err == 0);
m_gpio_pin_set(antenna_number, true);
}

currently_active_antenna = antenna_number;
Expand All @@ -100,20 +138,34 @@ void cs_antenna_switch_func(uint8_t antenna_number)
void cs_antenna_switch_init(void)
{
int err;

for (uint8_t i = 0; i < NUM_GPIOS; i++) {
err = gpio_pin_configure_dt(&gpio_dt_spec_table[i], GPIO_OUTPUT_INACTIVE);
__ASSERT(err == 0, "Failed to initialize GPIOs for CS (%d)", err);
__ASSERT(err == 0, "Failed to initialize GPIOs for CS antenna pin (%d)", err);
#if defined(CONFIG_PM_DEVICE_RUNTIME)
/* Manually manage the PM for the antenna switch GPIOs,
* as this cannot be done by the cs_antenna_switch_func
* which is called from interrupt context.
*/
err = pm_device_runtime_get(gpio_dt_spec_table[i].port);
__ASSERT(err == 0, "Failed pm_device_runtime_get for CS antenna pin (%d)", err);
#endif
}
}

void cs_antenna_switch_clear(void)
{
int err;

for (uint8_t i = 0; i < NUM_GPIOS; i++) {
err = gpio_pin_set_dt(&gpio_dt_spec_table[i], false);
__ASSERT_NO_MSG(err == 0);
m_gpio_pin_set(i, false);
#if defined(CONFIG_PM_DEVICE_RUNTIME)
/* Manually manage the PM for the antenna switch GPIOs,
* as this cannot be done by the cs_antenna_switch_func
* which is called from interrupt context.
*/
int err;

err = pm_device_runtime_put(gpio_dt_spec_table[i].port);
__ASSERT(err == 0, "Failed pm_device_runtime_put for CS antenna pin (%d)", err);
#endif
}

currently_active_antenna = ANTENNA_NOT_SET;
Expand Down
2 changes: 2 additions & 0 deletions subsys/bluetooth/controller/cs_antenna_switch.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <stdint.h>

/** @brief Antenna switching Callback for use in Channel Sounding.
* @note This function is called from interrupt context and must not
* call Zephyr APIs or any blocking APIs.
*
* See also @ref sdc_support_channel_sounding
*
Expand Down