1 /*
2 * Copyright (C) 2023 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * 4. Any redistribution, use, or modification is done solely for
17 * personal benefit and not for any commercial purpose or for
18 * monetary gain.
19 *
20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Please inquire about commercial licensing options at
34 * [email protected]
35 *
36 */
37
38 #define BTSTACK_FILE__ "btstack_chipset_nxp.c"
39
40 #include "btstack_chipset_nxp.h"
41 #include "btstack_debug.h"
42 #include "btstack_event.h"
43 #include "hci_cmd.h"
44
45 #include <stdio.h>
46
47 #ifdef _MSC_VER
48 // ignore deprecated warning for fopen
49 #pragma warning(disable : 4996)
50 #endif
51
52 // Firmware download protocol constants
53 #define NXP_V1_FIRMWARE_REQUEST_PACKET 0xa5
54 #define NXP_V1_CHIP_VERION_PACKET 0xaa
55 #define NXP_V3_FIRMWARE_REQUEST_PACKET 0xa7
56 #define NXP_V3_CHIP_VERSION_PACKET 0xab
57
58 #define NXP_ACK_V1 0x5a
59 #define NXP_NAK_V1 0xbf
60 #define NXP_ACK_V3 0x7a
61 #define NXP_NAK_V3 0x7b
62 #define NXP_CRC_ERROR_V3 0x7c
63
64 // chip ids
65 #define NXP_CHIP_ID_W9098 0x5c03
66 #define NXP_CHIP_ID_IW416 0x7201
67 #define NXP_CHIP_ID_IW612 0x7601
68
69 // firmwares
70 #define NXP_FIRMWARE_W9098 "uartuart9098_bt_v1.bin"
71 #define NXP_FIRMWARE_IW416 "uartiw416_bt_v0.bin"
72 #define NXP_FIRMWARE_IW612 "uartspi_n61x_v1.bin.se"
73
74 #define NXP_MAX_RESEND_COUNT 5
75
76 // prototypes
77 static void nxp_done_with_status(uint8_t status);
78 static void nxp_read_uart_handler(void);
79 static void nxp_send_chunk_v1(void);
80 static void nxp_send_chunk_v3(void);
81 static void nxp_start(void);
82 static void nxp_run(void);
83
84 // globals
85 static void (*nxp_download_complete_callback)(uint8_t status);
86 static const btstack_uart_t * nxp_uart_driver;
87 static btstack_timer_source_t nxp_timer;
88
89 static uint16_t nxp_chip_id;
90
91 static const uint8_t * nxp_fw_data;
92 static uint32_t nxp_fw_size;
93 static uint32_t nxp_fw_offset;
94
95 static uint8_t nxp_input_buffer[10];
96 static uint16_t nxp_input_pos;
97 static uint16_t nxp_input_bytes_requested;
98
99 static uint8_t nxp_output_buffer[2048 + 1];
100
101 static const uint8_t nxp_ack_buffer_v1[] = {NXP_ACK_V1 };
102 static const uint8_t nxp_ack_buffer_v3[] = {NXP_ACK_V3, 0x92 };
103
104 static uint16_t nxp_fw_request_len;
105 static uint8_t nxp_fw_resend_count;
106
107 // state / tasks
108 static bool nxp_have_firmware;
109 static bool nxp_tx_send_ack_v1;
110 static bool nxp_tx_send_ack_v3;
111 static bool nxp_tx_send_chunk_v1;
112 static bool nxp_tx_send_chunk_v3;
113 static bool nxp_tx_active;
114 static bool nxp_download_done;
115 static uint8_t nxp_download_statue;
116
117 #ifdef HAVE_POSIX_FILE_IO
118 static char nxp_firmware_path[1000];
119 static FILE * nxp_firmware_file;
120
nxp_fw_name_from_chipid(uint16_t chip_id)121 static char *nxp_fw_name_from_chipid(uint16_t chip_id)
122 {
123 switch (chip_id) {
124 case NXP_CHIP_ID_W9098:
125 return NXP_FIRMWARE_W9098;
126 case NXP_CHIP_ID_IW416:
127 return NXP_FIRMWARE_IW416;
128 case NXP_CHIP_ID_IW612:
129 return NXP_FIRMWARE_IW612;
130 default:
131 log_error("Unknown chip id 0x%04x", chip_id);
132 return NULL;
133 }
134 }
135
nxp_load_firmware(void)136 static void nxp_load_firmware(void) {
137 if (nxp_firmware_file == NULL){
138 log_info("open file %s", nxp_firmware_path);
139 nxp_firmware_file = fopen(nxp_firmware_path, "rb");
140 if (nxp_firmware_file != NULL){
141 printf("Open file '%s' failed\n", nxp_firmware_path);
142 nxp_have_firmware = true;
143 }
144 }
145
146 }
nxp_read_firmware(uint16_t bytes_to_read,uint8_t * buffer)147 static uint16_t nxp_read_firmware(uint16_t bytes_to_read, uint8_t * buffer) {
148 size_t bytes_read = fread(buffer, 1, bytes_to_read, nxp_firmware_file);
149 return bytes_read;
150 }
151
nxp_unload_firmware(void)152 static void nxp_unload_firmware(void) {
153 btstack_assert(nxp_firmware_file != NULL);
154 fclose(nxp_firmware_file);
155 nxp_firmware_file = NULL;
156 }
157 #else
nxp_load_firmware(void)158 void nxp_load_firmware(void){
159 nxp_have_firmware = true;
160 }
161
162 // read bytes from firmware file
nxp_read_firmware(uint16_t bytes_to_read,uint8_t * buffer)163 static uint16_t nxp_read_firmware(uint16_t bytes_to_read, uint8_t * buffer){
164 if (nxp_fw_request_len > nxp_fw_size - nxp_fw_offset){
165 printf("fw_request_len %u > remaining file len %u\n", nxp_fw_request_len, nxp_fw_size - nxp_fw_offset);
166 return nxp_fw_size - nxp_fw_offset;
167 }
168 memcpy(buffer, &nxp_fw_data[nxp_fw_offset], bytes_to_read);
169 nxp_fw_offset += nxp_fw_request_len;
170 return bytes_to_read;
171 }
nxp_unload_firmware(void)172 static void nxp_unload_firmware(void) {
173 }
174 #endif
175
nxp_send_ack_v1()176 static void nxp_send_ack_v1() {
177 printf("SEND: ack v1\n");
178 btstack_assert(nxp_tx_active == false);
179 nxp_tx_active = true;
180 nxp_uart_driver->send_block(nxp_ack_buffer_v1, sizeof(nxp_ack_buffer_v1));
181 }
182
nxp_send_ack_v3()183 static void nxp_send_ack_v3() {
184 printf("SEND: ack v3\n");
185 btstack_assert(nxp_tx_active == false);
186 nxp_tx_active = true;
187 nxp_uart_driver->send_block(nxp_ack_buffer_v3, sizeof(nxp_ack_buffer_v3));
188 }
189
nxp_valid_packet(void)190 static bool nxp_valid_packet(void){
191 switch (nxp_input_buffer[0]){
192 case NXP_V1_FIRMWARE_REQUEST_PACKET:
193 case NXP_V1_CHIP_VERION_PACKET:
194 // first two uint16_t should xor to 0xffff
195 return ((nxp_input_buffer[1] ^ nxp_input_buffer[3]) == 0xff) && ((nxp_input_buffer[2] ^ nxp_input_buffer [4]) == 0xff);
196 case NXP_V3_CHIP_VERSION_PACKET:
197 case NXP_V3_FIRMWARE_REQUEST_PACKET:
198 // TODO: check crc-8
199 return true;
200 default:
201 return false;
202 }
203 }
204
nxp_handle_chip_version_v1(void)205 static void nxp_handle_chip_version_v1(void){
206 printf("RECV: NXP_V1_CHIP_VER_PKT, id = 0x%x02, revision = 0x%02x\n", nxp_input_buffer[0], nxp_input_buffer[1]);
207 nxp_tx_send_ack_v1 = true;
208 nxp_run();
209 }
210
nxp_handle_chip_version_v3(void)211 static void nxp_handle_chip_version_v3(void){
212 nxp_chip_id = little_endian_read_16(nxp_input_buffer, 1);
213 btstack_strcpy(nxp_firmware_path, sizeof(nxp_firmware_path), nxp_fw_name_from_chipid(nxp_chip_id));
214 printf("RECV: NXP_V3_CHIP_VER_PKT, id = 0x%04x, loader 0x%02x -> firmware '%s'\n", nxp_chip_id, nxp_input_buffer[3], nxp_firmware_path);
215 nxp_tx_send_ack_v3 = true;
216 nxp_run();
217 }
218
nxp_prepare_firmware(void)219 static void nxp_prepare_firmware(void){
220 // get firmware
221 if (nxp_have_firmware == false){
222 nxp_load_firmware();
223 }
224 if (nxp_have_firmware == false){
225 printf("No firmware found, abort\n");
226 }
227 }
228
nxp_send_chunk_v1(void)229 static void nxp_send_chunk_v1(void){
230 if (nxp_fw_request_len == 0){
231 printf("last chunk sent!\n");
232 nxp_unload_firmware();
233 nxp_done_with_status(ERROR_CODE_SUCCESS);
234 return;
235 } else if ((nxp_fw_request_len & 1) == 0){
236 // update sttate
237 nxp_fw_offset += nxp_fw_request_len;
238 nxp_fw_resend_count = 0;
239 // read next firmware chunk
240 uint16_t bytes_read = nxp_read_firmware(nxp_fw_request_len, nxp_output_buffer);
241 if (bytes_read < nxp_fw_request_len){
242 printf("only %u of %u bytes available, abort.\n", bytes_read, nxp_fw_request_len);
243 nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE);
244 return;
245 }
246 } else {
247 // resend last chunk if request len is odd
248 if (nxp_fw_resend_count >= NXP_MAX_RESEND_COUNT){
249 printf("Resent last block %u times, abort.", nxp_fw_resend_count);
250 nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE);
251 return;
252 }
253 nxp_fw_resend_count++;
254 }
255 printf("SEND: firmware %08x - %u bytes (%u. try)\n", nxp_fw_offset, nxp_fw_request_len, nxp_fw_resend_count + 1);
256 btstack_assert(nxp_tx_active == false);
257 nxp_tx_active = true;
258 nxp_uart_driver->send_block(nxp_output_buffer, nxp_fw_request_len);
259 }
260
nxp_send_chunk_v3(void)261 static void nxp_send_chunk_v3(void){
262 // update state
263 nxp_fw_offset += nxp_fw_request_len;
264 nxp_fw_resend_count = 0;
265 if (nxp_fw_request_len == 0){
266 printf("last chunk sent!\n");
267 nxp_unload_firmware();
268 nxp_done_with_status(ERROR_CODE_SUCCESS);
269 return;
270 }
271 // read next firmware chunk
272 uint16_t bytes_read = nxp_read_firmware(nxp_fw_request_len, nxp_output_buffer);
273 if (bytes_read < nxp_fw_request_len){
274 printf("only %u of %u bytes available, abort.\n", bytes_read, nxp_fw_request_len);
275 nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE);
276 return;
277 }
278 printf("SEND: firmware %08x - %u bytes (%u. try)\n", nxp_fw_offset, nxp_fw_request_len, nxp_fw_resend_count + 1);
279 btstack_assert(nxp_tx_active == false);
280 nxp_tx_active = true;
281 nxp_uart_driver->send_block(nxp_output_buffer, nxp_fw_request_len);
282 }
283
nxp_handle_firmware_request_v1(void)284 static void nxp_handle_firmware_request_v1(void){
285 nxp_fw_request_len = little_endian_read_16(nxp_input_buffer, 1);
286 printf("RECV: NXP_V1_FW_REQ_PKT, len %u\n", nxp_fw_request_len);
287
288 nxp_prepare_firmware();
289 if (nxp_have_firmware == false){
290 return;
291 }
292 nxp_tx_send_ack_v1 = true;
293 nxp_tx_send_chunk_v1 = true;
294 nxp_run();
295 }
296
nxp_handle_firmware_request_v3(void)297 static void nxp_handle_firmware_request_v3(void){
298 nxp_fw_request_len = little_endian_read_16(nxp_input_buffer, 1);
299 printf("RECV: NXP_V3_FW_REQ_PKT, len %u\n", nxp_fw_request_len);
300
301 nxp_prepare_firmware();
302 if (nxp_have_firmware == false){
303 return;
304 }
305 nxp_tx_send_ack_v3 = true;
306 nxp_tx_send_chunk_v3 = true;
307 nxp_run();
308 }
309
nxp_start_read(uint16_t bytes_to_read)310 static void nxp_start_read(uint16_t bytes_to_read){
311 nxp_input_bytes_requested = bytes_to_read;
312 nxp_uart_driver->receive_block(&nxp_input_buffer[nxp_input_pos], bytes_to_read);
313 }
314
nxp_read_uart_handler(void)315 static void nxp_read_uart_handler(void){
316 uint16_t bytes_to_read;
317 if (nxp_input_pos == 0){
318 switch (nxp_input_buffer[0]){
319 case NXP_V1_CHIP_VERION_PACKET:
320 case NXP_V3_CHIP_VERSION_PACKET:
321 case NXP_V1_FIRMWARE_REQUEST_PACKET:
322 nxp_input_pos++;
323 bytes_to_read = 4;
324 break;
325 case NXP_V3_FIRMWARE_REQUEST_PACKET:
326 nxp_input_pos++;
327 bytes_to_read = 9;
328 break;
329 default:
330 // invalid packet type, skip and get next byte
331 bytes_to_read = 1;
332 break;
333 }
334 } else {
335 nxp_input_pos += nxp_input_bytes_requested;
336 printf("RECV: ");
337 printf_hexdump(nxp_input_buffer, nxp_input_pos);
338 switch (nxp_input_buffer[0]){
339 case NXP_V1_CHIP_VERION_PACKET:
340 nxp_handle_chip_version_v1();
341 break;
342 case NXP_V3_CHIP_VERSION_PACKET:
343 nxp_handle_chip_version_v3();
344 break;
345 case NXP_V1_FIRMWARE_REQUEST_PACKET:
346 nxp_handle_firmware_request_v1();
347 break;
348 case NXP_V3_FIRMWARE_REQUEST_PACKET:
349 nxp_handle_firmware_request_v3();
350 break;
351 default:
352 btstack_assert(false);
353 break;
354 }
355 nxp_input_pos = 0;
356 bytes_to_read = 1;
357
358 // stop timer
359 btstack_run_loop_remove_timer(&nxp_timer);
360 }
361 nxp_start_read(bytes_to_read);
362 }
363
nxp_run(void)364 static void nxp_run(void){
365 if (nxp_tx_active) {
366 return;
367 }
368 if (nxp_tx_send_ack_v1){
369 nxp_tx_send_ack_v1 = false;
370 nxp_send_ack_v1();
371 return;
372 }
373 if (nxp_tx_send_ack_v3){
374 nxp_tx_send_ack_v3 = false;
375 nxp_send_ack_v3();
376 return;
377 }
378 if (nxp_tx_send_chunk_v1){
379 nxp_tx_send_chunk_v1 = false;
380 nxp_send_chunk_v1();
381 return;
382 }
383 if (nxp_tx_send_chunk_v3){
384 nxp_tx_send_chunk_v3 = false;
385 nxp_send_chunk_v3();
386 return;
387 }
388 if (nxp_download_done){
389 nxp_download_done = false;
390 (*nxp_download_complete_callback)(nxp_download_statue);
391 }
392 }
393
nxp_write_uart_handler(void)394 static void nxp_write_uart_handler(void){
395 btstack_assert(nxp_tx_active == true);
396 printf("SEND: complete\n");
397 nxp_tx_active = false;
398 nxp_run();
399 }
400
nxp_start(void)401 static void nxp_start(void){
402 nxp_fw_resend_count = 0;
403 nxp_fw_offset = 0;
404 nxp_have_firmware = false;
405 nxp_uart_driver->set_block_received(&nxp_read_uart_handler);
406 nxp_uart_driver->set_block_sent(&nxp_write_uart_handler);
407 nxp_uart_driver->receive_block(nxp_input_buffer, 1);
408 }
409
nxp_done_with_status(uint8_t status)410 static void nxp_done_with_status(uint8_t status){
411 nxp_download_statue = status;
412 nxp_download_done = true;
413 printf("DONE! status 0x%02x\n", status);
414 nxp_run();
415 }
416
btstack_chipset_nxp_set_v1_firmware_path(const char * firmware_path)417 void btstack_chipset_nxp_set_v1_firmware_path(const char * firmware_path){
418 btstack_strcpy(nxp_firmware_path, sizeof(nxp_firmware_path), firmware_path);
419 }
420
btstack_chipset_nxp_set_firmware(const uint8_t * fw_data,uint32_t fw_size)421 void btstack_chipset_nxp_set_firmware(const uint8_t * fw_data, uint32_t fw_size){
422 nxp_fw_data = fw_data;
423 nxp_fw_size = fw_size;
424 }
425
nxp_timer_handler(btstack_timer_source_t * ts)426 void nxp_timer_handler(btstack_timer_source_t *ts) {
427 printf("No firmware request received, assuming firmware already loaded\n");
428 nxp_done_with_status(ERROR_CODE_SUCCESS);
429 nxp_run();
430 }
431
btstack_chipset_nxp_download_firmware_with_uart(const btstack_uart_t * uart_driver,void (* callback)(uint8_t status))432 void btstack_chipset_nxp_download_firmware_with_uart(const btstack_uart_t *uart_driver, void (*callback)(uint8_t status)) {
433 nxp_uart_driver = uart_driver;
434 nxp_download_complete_callback = callback;
435
436 int res = nxp_uart_driver->open();
437
438 if (res) {
439 log_error("uart_block init failed %u", res);
440 nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE);
441 nxp_run();
442 return;
443 }
444
445 // if firmware is loaded, there will be no firmware request
446 btstack_run_loop_set_timer(&nxp_timer, 250);
447 btstack_run_loop_set_timer_handler(&nxp_timer, &nxp_timer_handler);
448 btstack_run_loop_add_timer(&nxp_timer);
449
450 nxp_start();
451 }
452
453 // init script support
454 static enum {
455 NXP_INIT_SEND_SCO_CONFIG,
456 NXP_INIT_SEND_HOST_CONTROL_ENABLE,
457 NXP_INIT_SEND_WRITE_PCM_SETTINGS,
458 NXP_INIT_SEND_WRITE_PCM_SYNC_SETTINGS,
459 NXP_INIT_SEND_WRITE_PCM_LINK_SETTINGS,
460 NXP_INIT_DONE,
461 } nxp_init_state;
462
463 #ifdef ENABLE_SCO_OVER_HCI
464 // Voice Path: Host
465 static const uint8_t nxp_chipset_sco_routing_path = 0;
466 #endif
467
468 #ifdef ENABLE_SCO_OVER_PCM
469 // Voice Path: PCM/I2S
470 static const uint8_t nxp_chipset_sco_routing_path = 1;
471 #endif
472
nxp_init(const void * transport_config)473 static void nxp_init(const void *transport_config){
474 UNUSED(transport_config);
475 nxp_init_state = NXP_INIT_SEND_SCO_CONFIG;
476 }
477
nxp_next_command(uint8_t * hci_cmd_buffer)478 static btstack_chipset_result_t nxp_next_command(uint8_t * hci_cmd_buffer) {
479 switch (nxp_init_state){
480 case NXP_INIT_SEND_SCO_CONFIG:
481 #if defined(ENABLE_SCO_OVER_HCI) || defined(ENABLE_SCO_OVER_PCM)
482 #ifdef ENABLE_NXP_PCM_WBS
483 nxp_init_state = NXP_INIT_SEND_HOST_CONTROL_ENABLE;
484 #else
485 nxp_init_state = NXP_INIT_SEND_WRITE_PCM_SETTINGS;
486 #endif
487 hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_set_sco_data_path, nxp_chipset_sco_routing_path);
488 return BTSTACK_CHIPSET_VALID_COMMAND;
489 #endif
490 #ifdef ENABLE_SCO_OVER_PCM
491 case NXP_INIT_SEND_HOST_CONTROL_ENABLE:
492 nxp_init_state = NXP_INIT_SEND_WRITE_PCM_SETTINGS;
493 // Host Control enabled
494 hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_host_pcm_i2s_control_enable, 1);
495 return BTSTACK_CHIPSET_VALID_COMMAND;
496 case NXP_INIT_SEND_WRITE_PCM_SETTINGS:
497 nxp_init_state = NXP_INIT_SEND_WRITE_PCM_SYNC_SETTINGS;
498 // PCM/I2S master mode
499 hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_write_pcm_i2s_settings, 0x02);
500 return BTSTACK_CHIPSET_VALID_COMMAND;
501 case NXP_INIT_SEND_WRITE_PCM_SYNC_SETTINGS:
502 nxp_init_state = NXP_INIT_SEND_WRITE_PCM_LINK_SETTINGS;
503 #ifdef ENABLE_NXP_PCM_WBS
504 // 16 kHz sync, 2048 kHz, data in left channel, DIN sampled on rising edge, DOUT driven on falling edge, I2Sa
505 hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_write_pcm_i2s_sync_settings, 0x03, 0x071e);
506 #else
507 // 8 kHz sync, 2048 kHz, data in left channel, DIN sampled on rising edge, DOUT driven on falling edge, I2S
508 hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_write_pcm_i2s_sync_settings, 0x03, 0x031e);
509 #endif
510 return BTSTACK_CHIPSET_VALID_COMMAND;
511 case NXP_INIT_SEND_WRITE_PCM_LINK_SETTINGS:
512 nxp_init_state = NXP_INIT_DONE;
513 // 1st SCO Link PCM Logical Slot 0, PCM start slot 1
514 hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_write_pcm_link_settings, 0x0004);
515 return BTSTACK_CHIPSET_VALID_COMMAND;
516 #endif
517 default:
518 break;
519 }
520 return BTSTACK_CHIPSET_DONE;
521 }
522
523 static btstack_chipset_t btstack_chipset_nxp = {
524 .name = "NXP",
525 .init = nxp_init,
526 .next_command = nxp_next_command,
527 .set_baudrate_command = NULL,
528 .set_bd_addr_command = NULL
529 };
530
btstack_chipset_nxp_instance(void)531 const btstack_chipset_t *btstack_chipset_nxp_instance(void){
532 return &btstack_chipset_nxp;
533 }
534
btstack_chipset_nxp_get_initial_baudrate(void)535 uint32_t btstack_chipset_nxp_get_initial_baudrate(void){
536 switch (nxp_chip_id){
537 case NXP_CHIP_ID_IW612:
538 return 3000000;
539 default:
540 return 115200;
541 }
542 }
543