blob: 344669ac41515689968b893a6a6ea0d4538d65b1 [file] [log] [blame]
/****************************************************************************
* arch/arm/src/nrf52/nrf52_sdc.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <assert.h>
#include <debug.h>
#include <stdlib.h>
#include <nuttx/net/bluetooth.h>
#include <nuttx/wireless/bluetooth/bt_hci.h>
#include <nuttx/wireless/bluetooth/bt_driver.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/mutex.h>
#include <arch/armv7-m/nvicpri.h>
#include <arch/nrf52/nrf52_irq.h>
#include <nuttx/wqueue.h>
#if defined(CONFIG_UART_BTH4)
# include <nuttx/serial/uart_bth4.h>
#endif
#include "arm_internal.h"
#include "ram_vectors.h"
#include "hardware/nrf52_ficr.h"
#include <mpsl.h>
#include <sdc.h>
#include <sdc_hci.h>
#include <sdc_soc.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Connections configuration ************************************************/
/* If NET_BLUETOOTH not defined */
#ifndef CONFIG_BLUETOOTH_MAX_CONN
# define CONFIG_BLUETOOTH_MAX_CONN CONFIG_NRF52_SDC_MAX_COUNT
#endif
#if defined(CONFIG_SDC_PERIPHERAL_COUNT) && \
CONFIG_SDC_PERIPHERAL_COUNT > CONFIG_BLUETOOTH_MAX_CONN
# error "Cannot support more BLE peripheral roles than connections"
#endif
#define SDC_CENTRAL_COUNT (CONFIG_BLUETOOTH_MAX_CONN - \
CONFIG_NRF52_SDC_PERIPHERAL_COUNT)
/* Validate number of connections for Peripheral and Central roles */
#ifdef CONFIG_NRF52_SDC_PERIPHERAL
# if CONFIG_NRF52_SDC_PERIPHERAL_COUNT == 0
# error Peripheral role configured but peripheral count is 0
# endif
#endif
#ifdef CONFIG_NRF52_SDC_CENTRAL
# if SDC_CENTRAL_COUNT == 0
# error Central role configured but central count is 0
# endif
#endif
/* Memory configuration *****************************************************/
#define CENTRAL_MEM_SIZE (SDC_MEM_PER_CENTRAL_LINK( \
SDC_DEFAULT_TX_PACKET_SIZE, \
SDC_DEFAULT_RX_PACKET_SIZE, \
SDC_DEFAULT_TX_PACKET_COUNT, \
SDC_DEFAULT_RX_PACKET_COUNT) + \
SDC_MEM_CENTRAL_LINKS_SHARED)
#define PERIPHERAL_MEM_SIZE (SDC_MEM_PER_PERIPHERAL_LINK( \
SDC_DEFAULT_TX_PACKET_SIZE, \
SDC_DEFAULT_RX_PACKET_SIZE, \
SDC_DEFAULT_TX_PACKET_COUNT, \
SDC_DEFAULT_RX_PACKET_COUNT) + \
SDC_MEM_PERIPHERAL_LINKS_SHARED)
/* Scan supported if central present */
#ifdef CONFIG_NRF52_SDC_SCANNING
# if SDC_CENTRAL_COUNT == 0
# error Scanning enabled but central count is 0
# endif
#endif
/* Advertising supported if peripheral present */
#ifdef CONFIG_NRF52_SDC_ADVERTISING
# if CONFIG_NRF52_SDC_PERIPHERAL_COUNT == 0
# error Advertising enabled but peripheral count is 0
# endif
#endif
/* Observer configuration */
#ifdef CONFIG_NRF52_SDC_SCANNING
# if CONFIG_NRF52_SDC_SCAN_BUFFER_COUNT < 2
# error The minimum allowed number of scan buffers is 2.
# endif
# define SCAN_MEM_SIZE (SDC_MEM_SCAN_BUFFER(CONFIG_NRF52_SDC_SCAN_BUFFER_COUNT))
# define SCAN_MEM_COUNT (CONFIG_NRF52_SDC_SCAN_BUFFER_COUNT)
#else
# define SCAN_MEM_SIZE (0)
# define SCAN_MEM_COUNT (0)
#endif
/* Broadcaster configuration */
#ifdef CONFIG_NRF52_SDC_ADVERTISING
/* Advertising extensions not supported for now */
# define ADV_SET_COUNT (1)
# define ADV_BUF_SIZE (SDC_DEFAULT_ADV_BUF_SIZE)
# define ADV_MEM_SIZE (ADV_SET_COUNT * SDC_MEM_PER_ADV_SET(ADV_BUF_SIZE))
#else
# define ADV_SET_COUNT (0)
# define ADV_BUF_SIZE (0)
# define ADV_MEM_SIZE (0)
#endif
/* Periodic advertising not supported */
#define PERIODIC_ADV_MEM_SIZE (0)
#define PERIODIC_ADV_RESP_MEM_SIZE (0)
#define PERIODIC_ADV_LIST_MEM_SIZE (0)
#define PERIODIC_SYNC_MEM_SIZE (0)
/* Memory poll size */
#define MEMPOOL_SIZE ((CONFIG_NRF52_SDC_PERIPHERAL_COUNT * PERIPHERAL_MEM_SIZE) + \
(SDC_CENTRAL_COUNT * CENTRAL_MEM_SIZE)+ \
SCAN_MEM_SIZE+ \
ADV_MEM_SIZE + \
PERIODIC_ADV_MEM_SIZE + \
PERIODIC_ADV_RESP_MEM_SIZE + \
PERIODIC_ADV_LIST_MEM_SIZE +\
PERIODIC_SYNC_MEM_SIZE)
/* BT address configuration *************************************************/
#if (CONFIG_NRF52_SDC_PUB_ADDR > 0) || \
defined(CONFIG_NRF52_SDC_FICR_STATIC_ADDR)
# define HAVE_BTADDR_CONFIGURE
#endif
/* Calls to MPSL ************************************************************/
#define MPSL_IRQ_CLOCK_HANDLER MPSL_IRQ_CLOCK_Handler
#define MPSL_IRQ_RTC0_HANDLER MPSL_IRQ_RTC0_Handler
#define MPSL_IRQ_TIMER0_HANDLER MPSL_IRQ_TIMER0_Handler
#define MPSL_IRQ_RADIO_HANDLER MPSL_IRQ_RADIO_Handler
/****************************************************************************
* Private Types
****************************************************************************/
struct nrf52_sdc_dev_s
{
uint8_t *mempool; /* Must be 8 bytes aligned */
uint8_t msg_buffer[HCI_MSG_BUFFER_MAX_SIZE];
mutex_t lock;
struct work_s work;
};
begin_packed_struct struct sdc_hci_cmd_vs_zephyr_write_bd_addr_s
{
uint8_t bd_addr[6];
} end_packed_struct;
begin_packed_struct struct sdc_hci_cmd_le_set_random_address_s
{
uint8_t bd_addr[6];
} end_packed_struct;
/****************************************************************************
* External Function Prototypes
****************************************************************************/
uint8_t sdc_hci_cmd_vs_zephyr_write_bd_addr(
const struct sdc_hci_cmd_vs_zephyr_write_bd_addr_s *p_params);
uint8_t sdc_hci_cmd_le_set_random_address(
const struct sdc_hci_cmd_le_set_random_address_s *p_params);
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static void mpsl_assert_handler(const char *const file, const uint32_t line);
static void sdc_fault_handler(const char *file, const uint32_t line);
static int bt_open(struct bt_driver_s *btdev);
static int bt_hci_send(struct bt_driver_s *btdev,
enum bt_buf_type_e type,
void *data, size_t len);
static void on_hci(void);
static void on_hci_worker(void *arg);
static void low_prio_worker(void *arg);
static int swi_isr(int irq, void *context, void *arg);
static int power_clock_isr(int irq, void *context, void *arg);
static void rtc0_handler(void);
static void timer0_handler(void);
static void radio_handler(void);
/****************************************************************************
* Private Data
****************************************************************************/
static struct bt_driver_s g_bt_driver =
{
.head_reserve = 0,
.open = bt_open,
.send = bt_hci_send
};
static const mpsl_clock_lfclk_cfg_t g_clock_config =
{
.source = MPSL_CLOCK_LF_SRC_XTAL,
.rc_ctiv = 0,
.rc_temp_ctiv = 0,
.accuracy_ppm = CONFIG_NRF52_SDC_CLOCK_ACCURACY,
.skip_wait_lfclk_started = false
};
/* Must be 8 bytes aligned */
static uint8_t g_sdc_mempool[MEMPOOL_SIZE] aligned_data(8);
static struct nrf52_sdc_dev_s g_sdc_dev =
{
.mempool = g_sdc_mempool,
.lock = NXMUTEX_INITIALIZER,
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: bt_open
****************************************************************************/
static int bt_open(struct bt_driver_s *btdev)
{
return 0;
}
/****************************************************************************
* Name: bt_hci_send
****************************************************************************/
static int bt_hci_send(struct bt_driver_s *btdev,
enum bt_buf_type_e type,
void *data, size_t len)
{
int ret = -EIO;
/* Pass HCI CMD/DATA to SDC */
if (type == BT_CMD || type == BT_ACL_OUT)
{
wlinfo("passing type %s to softdevice\n",
(type == BT_CMD) ? "CMD" : "ACL");
/* Ensure non-concurrent access to SDC operations */
nxmutex_lock(&g_sdc_dev.lock);
if (type == BT_CMD)
{
ret = sdc_hci_cmd_put(data);
}
else
{
ret = sdc_hci_data_put(data);
}
nxmutex_unlock(&g_sdc_dev.lock);
if (ret >= 0)
{
ret = len;
work_queue(LPWORK, &g_sdc_dev.work, on_hci_worker, NULL, 0);
}
}
return ret;
}
/****************************************************************************
* Name: sdc_fault_handler
****************************************************************************/
static void sdc_fault_handler(const char *file, const uint32_t line)
{
__assert(file, line, "SoftDevice Controller Fault");
}
/****************************************************************************
* Name: mpsl_assert_handler
****************************************************************************/
static void mpsl_assert_handler(const char *const file, const uint32_t line)
{
__assert(file, line, "MPSL assertion failed");
}
/****************************************************************************
* Name: low_prio_worker
****************************************************************************/
static void low_prio_worker(void *arg)
{
/* Invoke MPSL low priority process handler. This will call on_hci()
* internally when required.
*/
nxmutex_lock(&g_sdc_dev.lock);
mpsl_low_priority_process();
nxmutex_unlock(&g_sdc_dev.lock);
}
/****************************************************************************
* Name: on_hci_worker
****************************************************************************/
static void on_hci_worker(void *arg)
{
/* We use this worker to force a call to on_hci() right after sending
* an HCI command as MPSL/SDC does not always signal the low priority
* worker
*/
nxmutex_lock(&g_sdc_dev.lock);
on_hci();
nxmutex_unlock(&g_sdc_dev.lock);
}
/****************************************************************************
* Name: on_hci
****************************************************************************/
static void on_hci(void)
{
sdc_hci_msg_type_t type;
bool check_again;
size_t len;
int ret;
do
{
check_again = false;
/* Check for EVT by trying to get pending data into a generic
* buffer and then create an actual bt_buf_s, depending on msg length
*/
ret = sdc_hci_get(g_sdc_dev.msg_buffer, &type);
if (ret == 0)
{
if (type == SDC_HCI_MSG_TYPE_EVT)
{
struct bt_hci_evt_hdr_s *hdr =
(struct bt_hci_evt_hdr_s *)g_sdc_dev.msg_buffer;
len = sizeof(*hdr) + hdr->len;
#ifdef CONFIG_DEBUG_WIRELESS_INFO
if (hdr->evt == BT_HCI_EVT_CMD_COMPLETE)
{
struct hci_evt_cmd_complete_s *cmd_complete =
(struct hci_evt_cmd_complete_s *)
(g_sdc_dev.msg_buffer + sizeof(*hdr));
uint8_t *status = (uint8_t *)cmd_complete + 3;
wlinfo("received CMD_COMPLETE from softdevice "
"(opcode: 0x%x, status: 0x%x)\n",
cmd_complete->opcode, *status);
}
else
{
wlinfo("received HCI EVT from softdevice "
"(evt: %d, len: %zu)\n", hdr->evt, len);
}
#endif
bt_netdev_receive(&g_bt_driver, BT_EVT,
g_sdc_dev.msg_buffer, len);
check_again = true;
}
if (type == SDC_HCI_MSG_TYPE_DATA)
{
struct bt_hci_acl_hdr_s *hdr =
(struct bt_hci_acl_hdr_s *)g_sdc_dev.msg_buffer;
wlinfo("received HCI ACL from softdevice (handle: %d)\n",
hdr->handle);
len = sizeof(*hdr) + hdr->len;
bt_netdev_receive(&g_bt_driver, BT_ACL_IN,
g_sdc_dev.msg_buffer, len);
check_again = true;
}
}
}
while (check_again);
}
/****************************************************************************
* Name: swi_isr
****************************************************************************/
static int swi_isr(int irq, void *context, void *arg)
{
work_queue(LPWORK, &g_sdc_dev.work, low_prio_worker, NULL, 0);
return 0;
}
/****************************************************************************
* Name: power_clock_isr
****************************************************************************/
static int power_clock_isr(int irq, void *context, void *arg)
{
MPSL_IRQ_CLOCK_HANDLER();
return 0;
}
/****************************************************************************
* Name: rtc0_handler
****************************************************************************/
static void rtc0_handler(void)
{
MPSL_IRQ_RTC0_HANDLER();
}
/****************************************************************************
* Name: timer0_handler
****************************************************************************/
static void timer0_handler(void)
{
MPSL_IRQ_TIMER0_HANDLER();
}
/****************************************************************************
* Name: radio_handler
****************************************************************************/
static void radio_handler(void)
{
MPSL_IRQ_RADIO_HANDLER();
}
#ifdef HAVE_BTADDR_CONFIGURE
/****************************************************************************
* Name: nrf52_sdc_btaddr_configure
****************************************************************************/
static int nrf52_sdc_btaddr_configure(void)
{
#if CONFIG_NRF52_SDC_PUB_ADDR > 0
struct sdc_hci_cmd_vs_zephyr_write_bd_addr_s pub_addr;
#endif
#ifdef CONFIG_NRF52_SDC_FICR_STATIC_ADDR
struct sdc_hci_cmd_le_set_random_address_s rand_addr;
uint32_t addr[2];
uint32_t addrtype = 0;
#endif
int ret = OK;
#ifdef CONFIG_NRF52_SDC_FICR_STATIC_ADDR
/* Get device address type */
addrtype = getreg32(NRF52_FICR_DEVICEADDRTYPE);
/* Get device addr from FICR */
addr[0] = getreg32(NRF52_FICR_DEVICEADDR0);
addr[1] = getreg32(NRF52_FICR_DEVICEADDR1);
if ((addrtype & 0x01) == FICR_DEVICEADDRTYPE_RANDOM)
{
/* Configure static random address */
memcpy(&rand_addr.bd_addr[0], &addr[0], 4);
memcpy(&rand_addr.bd_addr[4], &addr[1], 2);
/* The two most significant bits of the address shall be set */
rand_addr.bd_addr[4] |= 0x0c;
ret = sdc_hci_cmd_le_set_random_address(&rand_addr);
if (ret < 0)
{
wlerr("sdc_hci_cmd_le_set_random_address failed: %d\n", ret);
goto errout;
}
}
else
{
wlerr("Static random address not available\n");
ret = -EINVAL;
goto errout;
}
#endif
#if CONFIG_NRF52_SDC_PUB_ADDR > 0
/* Configure public address if available */
pub_addr.bd_addr[0] = (CONFIG_NRF52_SDC_PUB_ADDR >> (8 * 5)) & 0xff;
pub_addr.bd_addr[1] = (CONFIG_NRF52_SDC_PUB_ADDR >> (8 * 4)) & 0xff;
pub_addr.bd_addr[2] = (CONFIG_NRF52_SDC_PUB_ADDR >> (8 * 3)) & 0xff;
pub_addr.bd_addr[3] = (CONFIG_NRF52_SDC_PUB_ADDR >> (8 * 2)) & 0xff;
pub_addr.bd_addr[4] = (CONFIG_NRF52_SDC_PUB_ADDR >> (8 * 1)) & 0xff;
pub_addr.bd_addr[5] = (CONFIG_NRF52_SDC_PUB_ADDR >> (8 * 0)) & 0xff;
ret = sdc_hci_cmd_vs_zephyr_write_bd_addr(&pub_addr);
if (ret < 0)
{
wlerr("sdc_hci_cmd_vs_zephyr_write_bd_addr failed: %d\n", ret);
goto errout;
}
#endif
errout:
return ret;
}
#endif
/****************************************************************************
* Name: nrf52_rand_prio_low_get
****************************************************************************/
static uint8_t nrf52_rand_prio_low_get(uint8_t *p_buff, uint8_t length)
{
arc4random_buf(p_buff, length);
return length;
}
/****************************************************************************
* Name: nrf52_rand_prio_high_get
****************************************************************************/
static uint8_t nrf52_rand_prio_high_get(uint8_t *p_buff, uint8_t length)
{
arc4random_buf(p_buff, length);
return length;
}
/****************************************************************************
* Name: nrf52_rand_poll
****************************************************************************/
static void nrf52_rand_poll(uint8_t *p_buff, uint8_t length)
{
arc4random_buf(p_buff, length);
}
/****************************************************************************
* Name: nrf52_configure_features
****************************************************************************/
static int nrf52_configure_features(void)
{
int ret = OK;
/* Turn on specific features */
#ifdef CONFIG_NRF52_SDC_ADVERTISING
ret = sdc_support_adv();
if (ret < 0)
{
wlerr("Could not enable advertising feature: %d\n", ret);
goto errout;
}
#endif
#ifdef CONFIG_NRF52_SDC_SCANNING
ret = sdc_support_scan();
if (ret < 0)
{
wlerr("Could not enable scanning feature: %d\n", ret);
goto errout;
}
#endif
#if SDC_CENTRAL_COUNT > 0
ret = sdc_support_central();
if (ret < 0)
{
wlerr("Could not enable central feature: %d\n", ret);
goto errout;
}
#endif
#if CONFIG_NRF52_SDC_PERIPHERAL_COUNT > 0
ret = sdc_support_peripheral();
if (ret < 0)
{
wlerr("Could not enable peripheral feature: %d\n", ret);
goto errout;
}
#endif
#ifdef CONFIG_NRF52_SDC_DLE
# if SDC_CENTRAL_COUNT > 0
ret = sdc_support_dle_central();
if (ret < 0)
{
wlerr("Could not enable DLE central feature: %d\n", ret);
goto errout;
}
# endif
# if CONFIG_NRF52_SDC_PERIPHERAL_COUNT > 0
ret = sdc_support_dle_peripheral();
if (ret < 0)
{
wlerr("Could not enable DLE peripheral feature: %d\n", ret);
goto errout;
}
# endif
#endif
#ifdef CONFIG_NRF52_SDC_LE_2M_PHY
ret = sdc_support_le_2m_phy();
if (ret < 0)
{
wlerr("Could not enable 2M PHY feature: %d\n", ret);
goto errout;
}
#endif
#ifdef CONFIG_NRF52_SDC_LE_CODED_PHY
ret = sdc_support_le_coded_phy();
if (ret < 0)
{
wlerr("Could not enable Coded PHY feature: %d\n", ret);
goto errout;
}
#endif
#ifdef HAVE_BTADDR_CONFIGURE
/* Configure BT address */
ret = nrf52_sdc_btaddr_configure();
if (ret < 0)
{
wlerr("Could not configure BT addr: %d\n", ret);
goto errout;
}
#endif
errout:
return ret;
}
/****************************************************************************
* Name: nrf52_configure_memory
****************************************************************************/
static int nrf52_configure_memory(void)
{
int32_t required_memory = 0;
int ret = OK;
sdc_cfg_t cfg;
/* Configure SoftDevice memory.
* NOTE: sdc_cfg_set() API must be set before sdc_enable() and
* sdc_support_*() calls.
*/
#ifndef CONFIG_NRF52_SDC_PERIPHERAL
/* Configure scanner memory */
cfg.scan_buffer_cfg.count = SCAN_MEM_COUNT;
ret = sdc_cfg_set(SDC_DEFAULT_RESOURCE_CFG_TAG,
SDC_CFG_TYPE_SCAN_BUFFER_CFG, &cfg);
if (ret < 0)
{
wlerr("Failed to set scan count: %d\n", ret);
goto errout;
}
#endif
#ifndef CONFIG_NRF52_SDC_CENTRAL
/* Configure advertisers memory */
cfg.adv_count.count = ADV_SET_COUNT;
ret = sdc_cfg_set(SDC_DEFAULT_RESOURCE_CFG_TAG,
SDC_CFG_TYPE_ADV_COUNT, &cfg);
if (ret < 0)
{
wlerr("Failed to set advertising count: %d\n", ret);
goto errout;
}
cfg.adv_buffer_cfg.max_adv_data = ADV_BUF_SIZE;
ret = sdc_cfg_set(SDC_DEFAULT_RESOURCE_CFG_TAG,
SDC_CFG_TYPE_ADV_BUFFER_CFG, &cfg);
if (ret < 0)
{
wlerr("Failed to set advertising buffer: %d\n", ret);
goto errout;
}
#endif
#ifndef CONFIG_NRF52_SDC_PERIPHERAL
/* Configure central connections memory */
cfg.central_count.count = SDC_CENTRAL_COUNT;
ret = sdc_cfg_set(SDC_DEFAULT_RESOURCE_CFG_TAG,
SDC_CFG_TYPE_CENTRAL_COUNT, &cfg);
if (ret < 0)
{
wlerr("Failed to set central role count: %d\n", ret);
goto errout;
}
#endif
#ifndef CONFIG_NRF52_SDC_CENTRAL
/* Configure peripheral connections memory */
cfg.peripheral_count.count = CONFIG_NRF52_SDC_PERIPHERAL_COUNT;
ret = sdc_cfg_set(SDC_DEFAULT_RESOURCE_CFG_TAG,
SDC_CFG_TYPE_PERIPHERAL_COUNT, &cfg);
if (ret < 0)
{
wlerr("Failed to set peripheral role count: %d\n", ret);
goto errout;
}
#endif
/* Configure buffers memory and get the final required memory */
cfg.buffer_cfg.rx_packet_size = SDC_DEFAULT_RX_PACKET_SIZE;
cfg.buffer_cfg.tx_packet_size = SDC_DEFAULT_TX_PACKET_SIZE;
cfg.buffer_cfg.rx_packet_count = SDC_DEFAULT_RX_PACKET_COUNT;
cfg.buffer_cfg.tx_packet_count = SDC_DEFAULT_TX_PACKET_COUNT;
required_memory =
sdc_cfg_set(SDC_DEFAULT_RESOURCE_CFG_TAG,
SDC_CFG_TYPE_BUFFER_CFG, &cfg);
if (required_memory < 0)
{
wlerr("Failed to set packet size/count: %ld\n", required_memory);
goto errout;
}
/* Verify we have enough memory for our configuration */
ASSERT(required_memory <= MEMPOOL_SIZE);
errout:
return ret;
}
/****************************************************************************
* Name: nrf52_configure_rand
****************************************************************************/
static int nrf52_configure_rand(void)
{
sdc_rand_source_t rand_func;
int ret = OK;
/* REVISIT: should we feed entropy poll with some data,
* or leave it to be handled by user ?
*/
/* Enable rand source */
rand_func.rand_prio_low_get = nrf52_rand_prio_low_get;
rand_func.rand_prio_high_get = nrf52_rand_prio_high_get;
rand_func.rand_poll = nrf52_rand_poll;
ret = sdc_rand_source_register(&rand_func);
if (ret < 0)
{
wlerr("sdc_rand_source_register failed %d\n", ret);
goto errout;
}
errout:
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: nrf52_sdc_initialize
****************************************************************************/
int nrf52_sdc_initialize(void)
{
int ret = OK;
/* Register interrupt handler for normal-priority events. SWI5 will be
* used by MPSL to delegate low-priority work
*/
irq_attach(NRF52_IRQ_SWI5_EGU5, swi_isr, NULL);
irq_attach(NRF52_IRQ_POWER_CLOCK, power_clock_isr, NULL);
up_enable_irq(NRF52_IRQ_SWI5_EGU5);
up_enable_irq(NRF52_IRQ_POWER_CLOCK);
up_prioritize_irq(NRF52_IRQ_SWI5_EGU5, NVIC_SYSH_PRIORITY_DEFAULT);
up_prioritize_irq(NRF52_IRQ_POWER_CLOCK, NVIC_SYSH_PRIORITY_DEFAULT);
/* Configure SoftDevice random sources */
ret = nrf52_configure_rand();
if (ret < 0)
{
wlerr("nrf52_configure_rand failed: %d\n", ret);
return ret;
}
/* Register high-priority interrupts for specific peripherals */
arm_ramvec_attach(NRF52_IRQ_RTC0, rtc0_handler);
arm_ramvec_attach(NRF52_IRQ_TIMER0, timer0_handler);
arm_ramvec_attach(NRF52_IRQ_RADIO, radio_handler);
up_prioritize_irq(NRF52_IRQ_RTC0, MPSL_HIGH_IRQ_PRIORITY);
up_prioritize_irq(NRF52_IRQ_TIMER0, MPSL_HIGH_IRQ_PRIORITY);
up_prioritize_irq(NRF52_IRQ_RADIO, MPSL_HIGH_IRQ_PRIORITY);
up_enable_irq(NRF52_IRQ_RTC0);
up_enable_irq(NRF52_IRQ_TIMER0);
up_enable_irq(NRF52_IRQ_RADIO);
/* TODO: how do WFI again after high priority interrupt wakes MCU up? */
/* Initialize MPSL */
ret = mpsl_init(&g_clock_config, NRF52_IRQ_SWI5_EGU5 - NRF52_IRQ_EXTINT,
&mpsl_assert_handler);
if (ret < 0)
{
wlerr("mpsl_init failed: %d\n", ret);
return ret;
}
/* Initialize SDC */
ret = sdc_init(&sdc_fault_handler);
if (ret < 0)
{
wlerr("sdc_init failed: %d\n", ret);
return ret;
}
/* Configure SoftDevice features */
ret = nrf52_configure_features();
if (ret < 0)
{
wlerr("nrf52_configure_features failed: %d\n", ret);
return ret;
}
/* Configure SoftDevice memory */
ret = nrf52_configure_memory();
if (ret < 0)
{
wlerr("nrf52_configure_memory failed: %d\n", ret);
return ret;
}
/* Finally enable SoftDevice Controller */
ret = sdc_enable(on_hci, g_sdc_dev.mempool);
if (ret < 0)
{
wlerr("sdc_enable failed: %d\n", ret);
return ret;
}
#ifdef CONFIG_UART_BTH4
/* Register UART BT H4 device */
ret = uart_bth4_register(CONFIG_NRF52_BLE_TTY_NAME, &g_bt_driver);
if (ret < 0)
{
wlerr("bt_bth4_register error: %d\n", ret);
return ret;
}
#elif defined(CONFIG_NET_BLUETOOTH)
/* Register network device */
ret = bt_netdev_register(&g_bt_driver);
if (ret < 0)
{
wlerr("bt_netdev_register error: %d\n", ret);
return ret;
}
#else
# error
#endif
return ret;
}