Skip to content

Commit d808d9e

Browse files
asm5878henrikbrixandersen
authored andcommitted
drivers: bluetooth: hci: stm32wba driver update for pm
Reworking pm implementation in stm32wba ble hci driver. Enabling "no-reset" quirk for stm32wba ble hci driver to maintain specific configuration required for pm. Signed-off-by: Alessandro Manganaro <[email protected]>
1 parent 75a7261 commit d808d9e

File tree

2 files changed

+157
-8
lines changed

2 files changed

+157
-8
lines changed

drivers/bluetooth/hci/hci_stm32wba.c

Lines changed: 155 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@
1313
#include <zephyr/drivers/bluetooth.h>
1414
#include <zephyr/bluetooth/addr.h>
1515
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
16+
#include <zephyr/pm/policy.h>
17+
#include <zephyr/pm/device.h>
18+
#include <zephyr/pm/pm.h>
19+
#ifdef CONFIG_PM_DEVICE
20+
#include "linklayer_plat.h"
21+
#endif /* CONFIG_PM_DEVICE */
1622
#include <linklayer_plat_local.h>
1723

1824
#include <zephyr/sys/byteorder.h>
@@ -64,13 +70,87 @@ struct aci_set_ble_addr {
6470
uint8_t length;
6571
uint8_t value[6];
6672
} __packed;
67-
#endif
73+
#endif /* CONFIG_BT_HCI_SETUP */
74+
75+
#ifdef CONFIG_PM_DEVICE
76+
/* Proprietary command to enable notification of radio events */
77+
#define ACI_HAL_WRITE_SET_RADIO_ACTIVITY_MASK BT_OP(BT_OGF_VS, 0xFC18)
78+
#define RADIO_ACTIVITY_MASK_ALL (0x7FFF)
79+
#define ACI_HAL_END_OF_RADIO_ACTIVITY_EVENT (0x0004)
80+
81+
struct aci_set_radio_activity_mask_params {
82+
uint16_t Radio_Activity_Mask;
83+
} __packed;
84+
85+
struct bt_hci_end_radio_activity_evt {
86+
uint8_t evt_code;
87+
uint8_t len;
88+
uint16_t vs_code;
89+
uint8_t last_state;
90+
uint8_t next_state;
91+
uint32_t next_state_sys_time;
92+
uint8_t last_state_slot;
93+
uint8_t next_state_slot;
94+
} __packed;
95+
#endif /* CONFIG_PM_DEVICE */
6896

6997
static uint32_t __noinit buffer[DIVC(BLE_DYN_ALLOC_SIZE, 4)];
7098
static uint32_t __noinit gatt_buffer[DIVC(BLE_GATT_BUF_SIZE, 4)];
7199

72100
extern uint8_t ll_state_busy;
73101

102+
#ifdef CONFIG_PM_DEVICE
103+
static int bt_hci_stm32wba_set_radio_activity_mask(void)
104+
{
105+
struct net_buf *buf;
106+
struct aci_set_radio_activity_mask_params *params;
107+
int err;
108+
109+
buf = bt_hci_cmd_alloc(K_FOREVER);
110+
if (!buf) {
111+
return -ENOBUFS;
112+
}
113+
114+
params = net_buf_add(buf, sizeof(*params));
115+
params->Radio_Activity_Mask = RADIO_ACTIVITY_MASK_ALL;
116+
117+
err = bt_hci_cmd_send_sync(ACI_HAL_WRITE_SET_RADIO_ACTIVITY_MASK, buf, NULL);
118+
119+
return err;
120+
}
121+
122+
void register_radio_event(void)
123+
{
124+
int64_t value_ticks;
125+
static struct pm_policy_event radio_evt;
126+
static bool first_event = true;
127+
uint32_t cmd_status;
128+
/* Flag indicating that no radio events have been scheduled */
129+
uint32_t next_radio_event_us = 0;
130+
131+
/* Getting next radio event time if any */
132+
cmd_status = ll_intf_le_get_remaining_time_for_next_event(&next_radio_event_us);
133+
UNUSED(cmd_status);
134+
__ASSERT(cmd_staus, "Unable to retrieve next radio event");
135+
136+
if (next_radio_event_us == LL_DP_SLP_NO_WAKEUP) {
137+
/* No next radio event scheduled */
138+
if (!first_event) {
139+
first_event = true;
140+
pm_policy_event_unregister(&radio_evt);
141+
}
142+
} else {
143+
value_ticks = k_us_to_ticks_floor64(next_radio_event_us) + k_uptime_ticks();
144+
if (first_event) {
145+
pm_policy_event_register(&radio_evt, value_ticks);
146+
first_event = false;
147+
} else {
148+
pm_policy_event_update(&radio_evt, value_ticks);
149+
}
150+
}
151+
}
152+
#endif /* CONFIG_PM_DEVICE */
153+
74154
static bool is_hci_event_discardable(const uint8_t *evt_data)
75155
{
76156
uint8_t evt_type = evt_data[0];
@@ -80,7 +160,7 @@ static bool is_hci_event_discardable(const uint8_t *evt_data)
80160
case BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI:
81161
case BT_HCI_EVT_EXTENDED_INQUIRY_RESULT:
82162
return true;
83-
#endif
163+
#endif /* CONFIG_BT_CLASSIC */
84164
case BT_HCI_EVT_LE_META_EVENT: {
85165
uint8_t subevt_type = evt_data[sizeof(struct bt_hci_evt_hdr)];
86166

@@ -247,6 +327,17 @@ static int receive_data(const struct device *dev, const uint8_t *data, size_t le
247327

248328
switch (pkt_indicator) {
249329
case BT_HCI_H4_EVT:
330+
#ifdef CONFIG_PM_DEVICE
331+
/* Filtering on next radio events */
332+
const struct bt_hci_end_radio_activity_evt *evt_pckt =
333+
(const struct bt_hci_end_radio_activity_evt *)(data);
334+
335+
if ((evt_pckt->evt_code == BT_HCI_EVT_VENDOR) &&
336+
(evt_pckt->vs_code == ACI_HAL_END_OF_RADIO_ACTIVITY_EVENT)) {
337+
register_radio_event();
338+
return err;
339+
}
340+
#endif /* CONFIG_PM_DEVICE */
250341
buf = treat_evt(data, len);
251342
break;
252343
case BT_HCI_H4_ACL:
@@ -450,23 +541,79 @@ static int bt_hci_stm32wba_setup(const struct device *dev,
450541
return err;
451542
}
452543

453-
return 0;
544+
#ifdef CONFIG_PM_DEVICE
545+
err = bt_hci_stm32wba_set_radio_activity_mask();
546+
if (err) {
547+
return err;
548+
}
549+
#endif /* CONFIG_PM_DEVICE */
550+
551+
return err;
454552
}
455553
#endif /* CONFIG_BT_HCI_SETUP */
456554

555+
#ifdef CONFIG_PM_DEVICE
556+
static int radio_pm_action(const struct device *dev, enum pm_device_action action)
557+
{
558+
switch (action) {
559+
case PM_DEVICE_ACTION_RESUME:
560+
LL_AHB5_GRP1_EnableClock(LL_AHB5_GRP1_PERIPH_RADIO);
561+
#if defined(CONFIG_PM_S2RAM)
562+
if (LL_PWR_IsActiveFlag_SB() == 1U) {
563+
/* Put the radio in active state */
564+
link_layer_register_isr();
565+
}
566+
#endif /* CONFIG_PM_S2RAM */
567+
LINKLAYER_PLAT_NotifyWFIExit();
568+
ll_sys_dp_slp_exit();
569+
break;
570+
case PM_DEVICE_ACTION_SUSPEND:
571+
#if defined(CONFIG_PM_S2RAM)
572+
uint32_t radio_remaining_time = 0;
573+
enum pm_state state = pm_state_next_get(_current_cpu->id)->state;
574+
575+
if (state == PM_STATE_SUSPEND_TO_RAM) {
576+
/* Checking next radio schedulet event */
577+
uint32_t cmd_status =
578+
ll_intf_le_get_remaining_time_for_next_event(&radio_remaining_time);
579+
UNUSED(cmd_status);
580+
__ASSERT(cmd_status, "Unable to retrieve next radio event");
581+
582+
if (radio_remaining_time == LL_DP_SLP_NO_WAKEUP) {
583+
/* No radio event scheduled */
584+
(void)ll_sys_dp_slp_enter(LL_DP_SLP_NO_WAKEUP);
585+
} else if (radio_remaining_time > CFG_LPM_STDBY_WAKEUP_TIME) {
586+
/* No event in a "near" future */
587+
(void)ll_sys_dp_slp_enter(radio_remaining_time -
588+
CFG_LPM_STDBY_WAKEUP_TIME);
589+
} else {
590+
register_radio_event();
591+
}
592+
}
593+
#endif /* CONFIG_PM_S2RAM */
594+
LINKLAYER_PLAT_NotifyWFIEnter();
595+
break;
596+
default:
597+
return -ENOTSUP;
598+
}
599+
600+
return 0;
601+
}
602+
#endif /* CONFIG_PM_DEVICE */
603+
457604
static DEVICE_API(bt_hci, drv) = {
458605
#if defined(CONFIG_BT_HCI_SETUP)
459606
.setup = bt_hci_stm32wba_setup,
460-
#endif
607+
#endif /* CONFIG_BT_HCI_SETUP */
461608
.open = bt_hci_stm32wba_open,
462609
.send = bt_hci_stm32wba_send,
463610
};
464611

465612
#define HCI_DEVICE_INIT(inst) \
466-
static struct hci_data hci_data_##inst = { \
467-
}; \
468-
DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &hci_data_##inst, NULL, \
469-
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &drv)
613+
static struct hci_data hci_data_##inst = {}; \
614+
PM_DEVICE_DT_INST_DEFINE(inst, radio_pm_action); \
615+
DEVICE_DT_INST_DEFINE(inst, NULL, PM_DEVICE_DT_INST_GET(inst), &hci_data_##inst, NULL, \
616+
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &drv);
470617

471618
/* Only one instance supported */
472619
HCI_DEVICE_INIT(0)

dts/bindings/bluetooth/st,hci-stm32wba.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ properties:
99
default: "BT IPM"
1010
bt-hci-bus:
1111
default: "ipc"
12+
bt-hci-quirks:
13+
default: ["no-reset"]

0 commit comments

Comments
 (0)