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         return AM_HAL_STATUS_FAIL;
80     }
81 
82     //
83     // Configure and enable the BLE interface.
84     //
85     uint32_t ui32Status = AM_HAL_STATUS_FAIL;
86     while (ui32Status != AM_HAL_STATUS_SUCCESS)
87     {
88         am_hal_ble_config(BLE, &am_hal_ble_default_config);
89         //
90         // Delay 1s for 32768Hz clock stability. This isn't required unless this is
91         // our first run immediately after a power-up.
92         //
93         k_sleep(K_SECONDS(1));
94 
95         //
96         // Attempt to boot the radio.
97         //
98         ui32Status = am_hal_ble_boot(BLE);
99 
100         //
101         // Check our status.
102         //
103         if (ui32Status == AM_HAL_STATUS_SUCCESS)
104         {
105             //
106             // If the radio is running, we can exit this loop.
107             //
108             break;
109         }
110         else if (ui32Status == AM_HAL_BLE_32K_CLOCK_UNSTABLE)
111         {
112             //
113             // If the radio is running, but the clock looks bad, we can try to
114             // restart.
115             //
116             am_hal_ble_power_control(BLE, AM_HAL_BLE_POWER_OFF);
117             am_hal_ble_deinitialize(BLE);
118 
119             //
120             // We won't restart forever. After we hit the maximum number of
121             // retries, we'll just return with failure.
122             //
123             if (ui32NumXtalRetries++ < XTAL_STABILITY_MAX_RETRIES)
124             {
125                 k_sleep(K_SECONDS(1));
126                 am_hal_ble_initialize(0, &BLE);
127                 am_hal_ble_power_control(BLE, AM_HAL_BLE_POWER_ACTIVE);
128             }
129             else
130             {
131                 return AM_HAL_STATUS_FAIL;
132             }
133         }
134         else
135         {
136             am_hal_ble_power_control(BLE, AM_HAL_BLE_POWER_OFF);
137             am_hal_ble_deinitialize(BLE);
138             //
139             // If the radio failed for some reason other than 32K Clock
140             // instability, we should just report the failure and return.
141             //
142             return AM_HAL_STATUS_FAIL;
143         }
144     }
145 
146     //
147     // Set the BLE TX Output power to 0dBm.
148     //
149     am_hal_ble_tx_power_set(BLE, TX_POWER_LEVEL_0P0_dBm);
150 
151     am_hal_ble_int_clear(BLE, (AM_HAL_BLE_INT_CMDCMP |
152                                AM_HAL_BLE_INT_DCMP |
153                                AM_HAL_BLE_INT_BLECIRQ));
154 
155     am_hal_ble_int_enable(BLE, (AM_HAL_BLE_INT_CMDCMP |
156                                 AM_HAL_BLE_INT_DCMP |
157                                 AM_HAL_BLE_INT_BLECIRQ));
158 
159     return AM_HAL_STATUS_SUCCESS;
160 }
161 
162 //*****************************************************************************
163 //
164 // BLE ISR preprocessing.
165 //
166 //*****************************************************************************
am_apollo3_bt_isr_pre(void)167 void am_apollo3_bt_isr_pre(void)
168 {
169     uint32_t ui32Status = am_hal_ble_int_status(BLE, true);
170     am_hal_ble_int_clear(BLE, ui32Status);
171 }
172