13
13
#include <zephyr/drivers/bluetooth.h>
14
14
#include <zephyr/bluetooth/addr.h>
15
15
#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 */
16
22
#include <linklayer_plat_local.h>
17
23
18
24
#include <zephyr/sys/byteorder.h>
@@ -64,13 +70,87 @@ struct aci_set_ble_addr {
64
70
uint8_t length ;
65
71
uint8_t value [6 ];
66
72
} __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 */
68
96
69
97
static uint32_t __noinit buffer [DIVC (BLE_DYN_ALLOC_SIZE , 4 )];
70
98
static uint32_t __noinit gatt_buffer [DIVC (BLE_GATT_BUF_SIZE , 4 )];
71
99
72
100
extern uint8_t ll_state_busy ;
73
101
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
+
74
154
static bool is_hci_event_discardable (const uint8_t * evt_data )
75
155
{
76
156
uint8_t evt_type = evt_data [0 ];
@@ -80,7 +160,7 @@ static bool is_hci_event_discardable(const uint8_t *evt_data)
80
160
case BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI :
81
161
case BT_HCI_EVT_EXTENDED_INQUIRY_RESULT :
82
162
return true;
83
- #endif
163
+ #endif /* CONFIG_BT_CLASSIC */
84
164
case BT_HCI_EVT_LE_META_EVENT : {
85
165
uint8_t subevt_type = evt_data [sizeof (struct bt_hci_evt_hdr )];
86
166
@@ -247,6 +327,17 @@ static int receive_data(const struct device *dev, const uint8_t *data, size_t le
247
327
248
328
switch (pkt_indicator ) {
249
329
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 */
250
341
buf = treat_evt (data , len );
251
342
break ;
252
343
case BT_HCI_H4_ACL :
@@ -450,23 +541,79 @@ static int bt_hci_stm32wba_setup(const struct device *dev,
450
541
return err ;
451
542
}
452
543
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 ;
454
552
}
455
553
#endif /* CONFIG_BT_HCI_SETUP */
456
554
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
+
457
604
static DEVICE_API (bt_hci , drv ) = {
458
605
#if defined(CONFIG_BT_HCI_SETUP )
459
606
.setup = bt_hci_stm32wba_setup ,
460
- #endif
607
+ #endif /* CONFIG_BT_HCI_SETUP */
461
608
.open = bt_hci_stm32wba_open ,
462
609
.send = bt_hci_stm32wba_send ,
463
610
};
464
611
465
612
#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);
470
617
471
618
/* Only one instance supported */
472
619
HCI_DEVICE_INIT (0 )
0 commit comments