Skip to content

Commit 7c2ec0d

Browse files
olivier-le-sagenordicjm
authored andcommitted
bluetooth: controller: Use GPIO driver for CS antenna switching
Adds relevant DTS bindings and uses zephyr/gpio.h to provide a generic API for multiantenna channel sounding. Signed-off-by: Olivier Lesage <olivier.lesage@nordicsemi.no>
1 parent 522c8d1 commit 7c2ec0d

File tree

8 files changed

+178
-24
lines changed

8 files changed

+178
-24
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright (c) 2025 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
3+
4+
description: |
5+
This is an abstract representation of a generic antenna switching circuit
6+
which is controlled by GPIO pins. Up to four antenna ports (ANT1-4) are defined.
7+
8+
compatible: "nordic,bt-cs-antenna-switch"
9+
10+
include: base.yaml
11+
12+
properties:
13+
multiplexing-mode:
14+
type: int
15+
description: |
16+
Multiplexing mode. This setting determines whether or not the switching circuit
17+
is controlled using a one-to-one mapping between pins and antennas.
18+
The possible values are:
19+
0: (default) One-to-one mapping. Each pin selects one antenna.
20+
Only one pin is active at a time.
21+
1: Multiplexed mapping. Antenna selection is derived from the state of all
22+
pins. Example: two pins select between four antennas.
23+
24+
ant-gpios:
25+
type: phandle-array
26+
required: true
27+
description: |
28+
Array of pins corresponding to <ANT1, ANT2, ANT3, ANT4>.
29+
At least one pin is needed.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
/ {
8+
cs_antenna_switch: cs-antenna-config {
9+
status = "okay";
10+
compatible = "nordic,bt-cs-antenna-switch";
11+
ant-gpios = <&gpio1 11 (GPIO_ACTIVE_HIGH)>,
12+
<&gpio1 12 (GPIO_ACTIVE_HIGH)>,
13+
<&gpio1 13 (GPIO_ACTIVE_HIGH)>,
14+
<&gpio1 14 (GPIO_ACTIVE_HIGH)>;
15+
multiplexing-mode = <0>;
16+
};
17+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
/ {
8+
cs_antenna_switch: cs-antenna-config {
9+
status = "okay";
10+
compatible = "nordic,bt-cs-antenna-switch";
11+
ant-gpios = <&gpio1 11 (GPIO_ACTIVE_HIGH)>,
12+
<&gpio1 12 (GPIO_ACTIVE_HIGH)>,
13+
<&gpio1 13 (GPIO_ACTIVE_HIGH)>,
14+
<&gpio1 14 (GPIO_ACTIVE_HIGH)>;
15+
multiplexing-mode = <0>;
16+
};
17+
};

subsys/bluetooth/controller/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ zephyr_library_sources_ifdef(
2323
)
2424

2525
zephyr_library_sources_ifdef(
26-
CONFIG_BT_CTLR_CHANNEL_SOUNDING
26+
CONFIG_BT_CTLR_SDC_CS_MULTIPLE_ANTENNA_SUPPORT
2727
cs_antenna_switch.c
2828
)
2929

subsys/bluetooth/controller/Kconfig

+8
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,14 @@ config BT_CTLR_SDC_CS_NUM_ANTENNAS
604604
range 1 BT_CTLR_SDC_CS_MAX_ANTENNA_PATHS
605605
depends on BT_CTLR_CHANNEL_SOUNDING
606606

607+
config BT_CTLR_SDC_CS_MULTIPLE_ANTENNA_SUPPORT
608+
bool
609+
default y if BT_CTLR_SDC_CS_NUM_ANTENNAS > 1
610+
select GPIO
611+
depends on BT_CTLR_CHANNEL_SOUNDING
612+
help
613+
Internal helper config. Not intended for use.
614+
607615
config BT_CTLR_SDC_CS_STEP_MODE3
608616
bool "Enable optional step mode-3 capability [EXPERIMENTAL]"
609617
depends on BT_CTLR_CHANNEL_SOUNDING

subsys/bluetooth/controller/cs_antenna_switch.c

+95-19
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,110 @@
77
#include <stdint.h>
88
#include "cs_antenna_switch.h"
99

10-
#include <hal/nrf_gpio.h>
10+
#include <zephyr/device.h>
11+
#include <zephyr/devicetree.h>
12+
#include <zephyr/drivers/gpio.h>
1113

12-
#define DEFAULT_CS_ANTENNA_GPIO_PORT NRF_P1
13-
#define DEFAULT_CS_ANTENNA_BASE_PIN (11)
14-
#define DEFAULT_CS_ANTENNA_PIN_MASK (0xF << DEFAULT_CS_ANTENNA_BASE_PIN)
14+
#if DT_NODE_EXISTS(DT_NODELABEL(cs_antenna_switch))
15+
#define ANTENNA_SWITCH_NODE DT_NODELABEL(cs_antenna_switch)
16+
#else
17+
#define ANTENNA_SWITCH_NODE DT_INVALID_NODE
18+
#error No channel sounding antenna switch nodes registered in DTS.
19+
#endif
20+
21+
#if !DT_NODE_HAS_COMPAT(ANTENNA_SWITCH_NODE, nordic_bt_cs_antenna_switch)
22+
#error Configured antenna switch node is not compatible.
23+
#endif
24+
25+
#if DT_NODE_HAS_PROP(ANTENNA_SWITCH_NODE, multiplexing_mode)
26+
#define MULTIPLEXED DT_PROP(ANTENNA_SWITCH_NODE, multiplexing_mode)
27+
#else
28+
#define MULTIPLEXED false
29+
#endif
30+
31+
#define ANTENNA_NOT_SET 0xFF
32+
33+
BUILD_ASSERT(DT_NODE_HAS_PROP(ANTENNA_SWITCH_NODE, ant_gpios));
34+
35+
#if MULTIPLEXED
36+
#if CONFIG_BT_CTLR_SDC_CS_NUM_ANTENNAS == 2
37+
BUILD_ASSERT(DT_PROP_LEN(ANTENNA_SWITCH_NODE, ant_gpios) >= 1);
38+
#else
39+
BUILD_ASSERT(DT_PROP_LEN(ANTENNA_SWITCH_NODE, ant_gpios) >= 2);
40+
#endif
41+
#else
42+
BUILD_ASSERT(DT_PROP_LEN(ANTENNA_SWITCH_NODE, ant_gpios) >= CONFIG_BT_CTLR_SDC_CS_NUM_ANTENNAS);
43+
#endif /* MULTIPLEXED */
44+
45+
static uint8_t currently_active_antenna = ANTENNA_NOT_SET;
46+
static const struct gpio_dt_spec gpio_dt_spec_table[] = {
47+
GPIO_DT_SPEC_GET_BY_IDX_OR(ANTENNA_SWITCH_NODE, ant_gpios, 0, {0}),
48+
GPIO_DT_SPEC_GET_BY_IDX_OR(ANTENNA_SWITCH_NODE, ant_gpios, 1, {0}),
49+
#if !MULTIPLEXED
50+
GPIO_DT_SPEC_GET_BY_IDX_OR(ANTENNA_SWITCH_NODE, ant_gpios, 2, {0}),
51+
GPIO_DT_SPEC_GET_BY_IDX_OR(ANTENNA_SWITCH_NODE, ant_gpios, 3, {0}),
52+
#endif
53+
};
1554

1655
/* Antenna control below is implemented as described in the CS documentation.
17-
* https://docs.nordicsemi.com/bundle/ncs-latest/page/nrfxlib/softdevice_controller/doc/channel_sounding.html#multiple_antennas_support
18-
* The board has four antenna ports (ANT1-ANT4) that can be individually
19-
* enabled by setting the connected gpio pin high, while setting the gpio
20-
* pins for the other antenna ports low.
2156
*
22-
* Map of antenna ports to gpio pins for nrf54xDK:
23-
* ANT1 <----> P1.11
24-
* ANT2 <----> P1.12
25-
* ANT3 <----> P1.13
26-
* ANT4 <----> P1.14
57+
* Example valid device tree configuration for the nRF54L15:
58+
*
59+
* / {
60+
* cs_antenna_switch: cs-antenna-config {
61+
* status = "okay";
62+
* compatible = "nordic,bt-cs-antenna-switch";
63+
* ant-gpios = <&gpio1 11 (GPIO_ACTIVE_HIGH)>,
64+
* <&gpio1 12 (GPIO_ACTIVE_HIGH)>,
65+
* <&gpio1 13 (GPIO_ACTIVE_HIGH)>,
66+
* <&gpio1 14 (GPIO_ACTIVE_HIGH)>;
67+
* multiplexing-mode = <0>;
68+
* };
69+
* };
70+
*
2771
*/
2872
void cs_antenna_switch_func(uint8_t antenna_number)
2973
{
30-
uint32_t out = nrf_gpio_port_out_read(DEFAULT_CS_ANTENNA_GPIO_PORT);
74+
int err;
75+
#if MULTIPLEXED
76+
err = gpio_pin_set_dt(&gpio_dt_spec_table[0], antenna_number & (1 << 0));
77+
__ASSERT_NO_MSG(err == 0);
3178

32-
out &= ~DEFAULT_CS_ANTENNA_PIN_MASK;
33-
out |= 1 << (DEFAULT_CS_ANTENNA_BASE_PIN + antenna_number);
34-
nrf_gpio_port_out_write(DEFAULT_CS_ANTENNA_GPIO_PORT, out);
79+
err = gpio_pin_set_dt(&gpio_dt_spec_table[1], antenna_number & (1 << 1));
80+
__ASSERT_NO_MSG(err == 0);
81+
#else
82+
if (currently_active_antenna != antenna_number) {
83+
if (currently_active_antenna != ANTENNA_NOT_SET) {
84+
err = gpio_pin_set_dt(&gpio_dt_spec_table[currently_active_antenna], false);
85+
__ASSERT_NO_MSG(err == 0);
86+
}
87+
88+
err = gpio_pin_set_dt(&gpio_dt_spec_table[antenna_number], true);
89+
__ASSERT_NO_MSG(err == 0);
90+
}
91+
92+
currently_active_antenna = antenna_number;
93+
#endif
94+
}
95+
96+
void cs_antenna_switch_init(void)
97+
{
98+
int err;
99+
100+
for (uint8_t i = 0; i < DT_PROP_LEN(ANTENNA_SWITCH_NODE, ant_gpios); i++) {
101+
err = gpio_pin_configure_dt(&gpio_dt_spec_table[i], GPIO_OUTPUT_INACTIVE);
102+
__ASSERT(err == 0, "Failed to initialize GPIOs for CS (%d)", ret);
103+
}
35104
}
36105

37-
void cs_antenna_switch_enable(void)
106+
void cs_antenna_switch_clear(void)
38107
{
39-
nrf_gpio_port_dir_output_set(DEFAULT_CS_ANTENNA_GPIO_PORT, DEFAULT_CS_ANTENNA_PIN_MASK);
108+
int err;
109+
110+
for (uint8_t i = 0; i < DT_PROP_LEN(ANTENNA_SWITCH_NODE, ant_gpios); i++) {
111+
err = gpio_pin_set_dt(&gpio_dt_spec_table[i], false);
112+
__ASSERT_NO_MSG(err == 0);
113+
}
114+
115+
currently_active_antenna = ANTENNA_NOT_SET;
40116
}

subsys/bluetooth/controller/cs_antenna_switch.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,8 @@
1515
*/
1616
void cs_antenna_switch_func(uint8_t antenna_number);
1717

18-
/** @brief Function to enable the pins used by antenna switching in Channel Sounding. */
19-
void cs_antenna_switch_enable(void);
18+
/** @brief Function to initialize the pins used by antenna switching in Channel Sounding. */
19+
void cs_antenna_switch_init(void);
20+
21+
/** @brief Function to clear the pins used by antenna switching in Channel Sounding. */
22+
void cs_antenna_switch_clear(void);

subsys/bluetooth/controller/hci_driver.c

+6-2
Original file line numberDiff line numberDiff line change
@@ -984,9 +984,9 @@ static int configure_supported_features(void)
984984
if (err) {
985985
return -ENOTSUP;
986986
}
987-
#if CONFIG_BT_CTLR_SDC_CS_NUM_ANTENNAS > 1
987+
#if defined(CONFIG_BT_CTLR_SDC_CS_MULTIPLE_ANTENNA_SUPPORT)
988988
err = sdc_support_channel_sounding(cs_antenna_switch_func);
989-
cs_antenna_switch_enable();
989+
cs_antenna_switch_init();
990990
#else
991991
err = sdc_support_channel_sounding(NULL);
992992
#endif
@@ -1471,6 +1471,10 @@ static int hci_driver_close(const struct device *dev)
14711471
hci_ecdh_uninit();
14721472
}
14731473

1474+
if (IS_ENABLED(CONFIG_BT_CTLR_SDC_CS_MULTIPLE_ANTENNA_SUPPORT)) {
1475+
cs_antenna_switch_clear();
1476+
}
1477+
14741478
err = MULTITHREADING_LOCK_ACQUIRE();
14751479
if (err) {
14761480
return err;

0 commit comments

Comments
 (0)