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