1 //*****************************************************************************
2 //
3 //! @file am_apollo3_bt_support.c
4 //!
5 //! @brief Bluetooth support for the Apollo3 Blue Series SOC.
6 //
7 //*****************************************************************************
8
9 //*****************************************************************************
10 //
11 // Copyright (c) 2024, Ambiq Micro, Inc.
12 // All rights reserved.
13 //
14 // Redistribution and use in source and binary forms, with or without
15 // modification, are permitted provided that the following conditions are met:
16 //
17 // 1. Redistributions of source code must retain the above copyright notice,
18 // this list of conditions and the following disclaimer.
19 //
20 // 2. Redistributions in binary form must reproduce the above copyright
21 // notice, this list of conditions and the following disclaimer in the
22 // documentation and/or other materials provided with the distribution.
23 //
24 // 3. Neither the name of the copyright holder nor the names of its
25 // contributors may be used to endorse or promote products derived from this
26 // software without specific prior written permission.
27 //
28 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
32 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 // POSSIBILITY OF SUCH DAMAGE.
39 //
40 //*****************************************************************************
41
42 #include <stdint.h>
43 #include <stdbool.h>
44 #include <string.h>
45
46 #include <zephyr/kernel.h>
47
48 #include "am_mcu_apollo.h"
49 #include "am_apollo3_bt_support.h"
50
51 #define XTAL_STABILITY_MAX_RETRIES 10
52
53 //*****************************************************************************
54 //
55 // Global variables.
56 //
57 //*****************************************************************************
58
59 // BLE module handle
60 static void *BLE;
61
62 extern am_hal_ble_state_t g_sBLEState[];
63
64 //*****************************************************************************
65 //
66 // Initialize the Apollo3x BLE controller driver.
67 //
68 //*****************************************************************************
am_apollo3_bt_controller_init(void)69 uint32_t am_apollo3_bt_controller_init(void)
70 {
71 uint32_t ui32NumXtalRetries = 0;
72
73 if (g_sBLEState[0].prefix.s.bInit)
74 {
75 BLE = &g_sBLEState[0];
76 }
77 else
78 {
79 am_hal_ble_initialize(0, &BLE);
80 am_hal_ble_power_control(BLE, AM_HAL_BLE_POWER_ACTIVE);
81 }
82
83 //
84 // Configure and enable the BLE interface.
85 //
86 uint32_t ui32Status = AM_HAL_STATUS_FAIL;
87 while (ui32Status != AM_HAL_STATUS_SUCCESS)
88 {
89 am_hal_ble_config(BLE, &am_hal_ble_default_config);
90 //
91 // Delay 1s for 32768Hz clock stability. This isn't required unless this is
92 // our first run immediately after a power-up.
93 //
94 k_sleep(K_SECONDS(1));
95
96 //
97 // Attempt to boot the radio.
98 //
99 ui32Status = am_hal_ble_boot(BLE);
100
101 //
102 // Check our status.
103 //
104 if (ui32Status == AM_HAL_STATUS_SUCCESS)
105 {
106 //
107 // If the radio is running, we can exit this loop.
108 //
109 break;
110 }
111 else if (ui32Status == AM_HAL_BLE_32K_CLOCK_UNSTABLE)
112 {
113 //
114 // If the radio is running, but the clock looks bad, we can try to
115 // restart.
116 //
117 am_hal_ble_power_control(BLE, AM_HAL_BLE_POWER_OFF);
118 am_hal_ble_deinitialize(BLE);
119
120 //
121 // We won't restart forever. After we hit the maximum number of
122 // retries, we'll just return with failure.
123 //
124 if (ui32NumXtalRetries++ < XTAL_STABILITY_MAX_RETRIES)
125 {
126 k_sleep(K_SECONDS(1));
127 am_hal_ble_initialize(0, &BLE);
128 am_hal_ble_power_control(BLE, AM_HAL_BLE_POWER_ACTIVE);
129 }
130 else
131 {
132 return AM_HAL_STATUS_FAIL;
133 }
134 }
135 else
136 {
137 am_hal_ble_power_control(BLE, AM_HAL_BLE_POWER_OFF);
138 am_hal_ble_deinitialize(BLE);
139 //
140 // If the radio failed for some reason other than 32K Clock
141 // instability, we should just report the failure and return.
142 //
143 return AM_HAL_STATUS_FAIL;
144 }
145 }
146
147 //
148 // Set the BLE TX Output power to 0dBm.
149 //
150 am_hal_ble_tx_power_set(BLE, TX_POWER_LEVEL_0P0_dBm);
151
152 am_hal_ble_int_clear(BLE, (AM_HAL_BLE_INT_CMDCMP |
153 AM_HAL_BLE_INT_DCMP |
154 AM_HAL_BLE_INT_BLECIRQ));
155
156 am_hal_ble_int_enable(BLE, (AM_HAL_BLE_INT_CMDCMP |
157 AM_HAL_BLE_INT_DCMP |
158 AM_HAL_BLE_INT_BLECIRQ));
159
160 return AM_HAL_STATUS_SUCCESS;
161 }
162
163 //*****************************************************************************
164 //
165 // Deinitialize the Apollo3x BLE controller driver.
166 //
167 //*****************************************************************************
am_apollo3_bt_controller_deinit(void)168 uint32_t am_apollo3_bt_controller_deinit(void)
169 {
170 uint32_t ui32Status;
171
172 ui32Status = am_hal_ble_power_control(BLE, AM_HAL_BLE_POWER_OFF);
173 if (ui32Status != AM_HAL_STATUS_SUCCESS)
174 {
175 return ui32Status;
176 }
177
178 //
179 // Give some time to power off the BLE controller
180 //
181 k_sleep(K_SECONDS(1));
182
183 ui32Status = am_hal_ble_deinitialize(BLE);
184
185 return ui32Status;
186 }
187
188 //*****************************************************************************
189 //
190 // BLE ISR preprocessing.
191 //
192 //*****************************************************************************
am_apollo3_bt_isr_pre(void)193 void am_apollo3_bt_isr_pre(void)
194 {
195 uint32_t ui32Status = am_hal_ble_int_status(BLE, true);
196 am_hal_ble_int_clear(BLE, ui32Status);
197 }
198