|
| 1 | +/* |
| 2 | + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or |
| 3 | + * an affiliate of Cypress Semiconductor Corporation |
| 4 | + * |
| 5 | + * SPDX-License-Identifier: Apache-2.0 |
| 6 | + */ |
| 7 | + |
| 8 | +/** |
| 9 | + * @brief PSoC 6 BLE (BLESS) driver. |
| 10 | + */ |
| 11 | + |
| 12 | +#include <errno.h> |
| 13 | +#include <stddef.h> |
| 14 | +#include <string.h> |
| 15 | + |
| 16 | +#include <zephyr/arch/cpu.h> |
| 17 | +#include <zephyr/bluetooth/bluetooth.h> |
| 18 | +#include <zephyr/bluetooth/hci.h> |
| 19 | +#include <zephyr/drivers/bluetooth/hci_driver.h> |
| 20 | +#include <zephyr/drivers/uart.h> |
| 21 | +#include <zephyr/init.h> |
| 22 | +#include <zephyr/sys/byteorder.h> |
| 23 | +#include <zephyr/sys/util.h> |
| 24 | +#include "zephyr/logging/log.h" |
| 25 | + |
| 26 | +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER) |
| 27 | +#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL |
| 28 | +#include <zephyr/logging/log.h> |
| 29 | +LOG_MODULE_REGISTER(psoc6_bless); |
| 30 | + |
| 31 | +#include "cy_ble_stack_pvt.h" |
| 32 | +#include "cycfg_ble.h" |
| 33 | + |
| 34 | +#define DT_DRV_COMPAT infineon_cat1_bless_hci |
| 35 | + |
| 36 | +#define PACKET_TYPE_HCI_COMMAND 0X1 |
| 37 | +#define PACKET_TYPE_HCI_ACL_DATA 0x2 |
| 38 | +#define PACKET_TYPE_HCI_SYNCHRONOUS 0X3 |
| 39 | +#define PACKET_TYPE_HCI_EVENT 0X4 |
| 40 | + |
| 41 | +#define BLE_LOCK_TMOUT_MS (1000) |
| 42 | +#define BLE_THREAD_SEM_TMOUT_MS (1000) |
| 43 | + |
| 44 | +#define CYBLE_STACK_SIZE (CY_BLE_STACK_RAM_SIZE + 4096) |
| 45 | + |
| 46 | +#define PSOC6_BLESS_OP_SET_PUBLIC_ADDR BT_OP(BT_OGF_VS, 0x1a0) |
| 47 | + |
| 48 | +static K_SEM_DEFINE(psoc6_bless_rx_sem, 0, 1); |
| 49 | +static K_SEM_DEFINE(psoc6_bless_operation_sem, 1, 1); |
| 50 | +static K_KERNEL_STACK_DEFINE(psoc6_bless_rx_thread_stack, CONFIG_BT_RX_STACK_SIZE); |
| 51 | +static struct k_thread psoc6_bless_rx_thread_data; |
| 52 | +static cy_stc_ble_hci_tx_packet_info_t hci_tx_pkt; |
| 53 | + |
| 54 | +extern void Cy_BLE_EnableLowPowerMode(void); |
| 55 | + |
| 56 | +CY_ALIGN(sizeof(uint32_t)) CY_NOINIT uint8_t psoc6_bless_stack_memory[CYBLE_STACK_SIZE]; |
| 57 | + |
| 58 | +/** BLE Stack parameters */ |
| 59 | +static cy_stc_ble_stack_params_t psoc6_bless_stack_param = { |
| 60 | + .memoryHeapPtr = psoc6_bless_stack_memory, |
| 61 | + .totalHeapSz = CYBLE_STACK_SIZE, |
| 62 | + .dleMaxTxCapability = CONFIG_BT_PSOC6_BLESS_MAX_TX_PAYLOAD, |
| 63 | + .dleMaxRxCapability = CONFIG_BT_PSOC6_BLESS_MAX_RX_PAYLOAD, |
| 64 | + .featureMask = (CY_BLE_DLE_FEATURE | CY_BLE_LL_PRIVACY_FEATURE | |
| 65 | + CY_BLE_SECURE_CONN_FEATURE | CY_BLE_PHY_UPDATE_FEATURE | |
| 66 | + CY_BLE_STORE_BONDLIST_FEATURE | CY_BLE_STORE_RESOLVING_LIST_FEATURE | |
| 67 | + CY_BLE_STORE_WHITELIST_FEATURE | CY_BLE_TX_POWER_CALIBRATION_FEATURE), |
| 68 | + .maxConnCount = CY_BLE_CONN_COUNT, |
| 69 | + .tx5dbmModeEn = CY_BLE_ENABLE_TX_5DBM, |
| 70 | +}; |
| 71 | + |
| 72 | +static const cy_stc_sysint_t psoc6_bless_isr_cfg = { |
| 73 | + .intrSrc = DT_INST_IRQN(0), |
| 74 | + .intrPriority = DT_INST_IRQ(0, priority), |
| 75 | +}; |
| 76 | + |
| 77 | +static cy_stc_ble_hw_config_t psoc6_bless_hw_config = { |
| 78 | + .blessIsrConfig = &psoc6_bless_isr_cfg, |
| 79 | +}; |
| 80 | + |
| 81 | +static const cy_stc_ble_config_t psoc6_bless_config = { |
| 82 | + .stackParam = &psoc6_bless_stack_param, |
| 83 | + .hw = &psoc6_bless_hw_config, |
| 84 | +}; |
| 85 | + |
| 86 | +static void psoc6_bless_rx_thread(void *, void *, void *) |
| 87 | +{ |
| 88 | + while (true) { |
| 89 | + k_sem_take(&psoc6_bless_rx_sem, K_MSEC(BLE_THREAD_SEM_TMOUT_MS)); |
| 90 | + Cy_BLE_ProcessEvents(); |
| 91 | + } |
| 92 | +} |
| 93 | + |
| 94 | +static void psoc6_bless_isr_handler(const struct device *dev) |
| 95 | +{ |
| 96 | + if (Cy_BLE_HAL_BlessInterruptHandler()) { |
| 97 | + k_sem_give(&psoc6_bless_rx_sem); |
| 98 | + } |
| 99 | +} |
| 100 | + |
| 101 | +static void psoc6_bless_events_handler(uint32_t eventCode, void *eventParam) |
| 102 | +{ |
| 103 | + cy_stc_ble_hci_tx_packet_info_t *hci_rx = NULL; |
| 104 | + struct net_buf *buf = NULL; |
| 105 | + size_t buf_tailroom = 0; |
| 106 | + |
| 107 | + if (eventCode != CY_BLE_EVT_HCI_PKT_RCVD) { |
| 108 | + LOG_DBG("Other EVENT 0x%X", eventCode); |
| 109 | + return; |
| 110 | + } |
| 111 | + |
| 112 | + hci_rx = eventParam; |
| 113 | + |
| 114 | + switch (hci_rx->packetType) { |
| 115 | + case PACKET_TYPE_HCI_EVENT: |
| 116 | + buf = bt_buf_get_evt(hci_rx->data[0], 0, K_NO_WAIT); |
| 117 | + if (!buf) { |
| 118 | + LOG_ERR("Failed to allocate the buffer for RX: EVENT "); |
| 119 | + return; |
| 120 | + } |
| 121 | + |
| 122 | + break; |
| 123 | + case PACKET_TYPE_HCI_ACL_DATA: |
| 124 | + buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT); |
| 125 | + if (!buf) { |
| 126 | + LOG_ERR("Failed to allocate the buffer for RX: ACL "); |
| 127 | + return; |
| 128 | + } |
| 129 | + bt_buf_set_type(buf, BT_BUF_ACL_IN); |
| 130 | + |
| 131 | + break; |
| 132 | + |
| 133 | + default: |
| 134 | + LOG_WRN("Unsupported HCI Packet Received"); |
| 135 | + return; |
| 136 | + } |
| 137 | + |
| 138 | + buf_tailroom = net_buf_tailroom(buf); |
| 139 | + if (buf_tailroom < hci_rx->dataLength) { |
| 140 | + LOG_WRN("Not enough space for rx data"); |
| 141 | + return; |
| 142 | + } |
| 143 | + net_buf_add_mem(buf, hci_rx->data, hci_rx->dataLength); |
| 144 | + bt_recv(buf); |
| 145 | +} |
| 146 | + |
| 147 | +static int psoc6_bless_open(void) |
| 148 | +{ |
| 149 | + k_tid_t tid; |
| 150 | + |
| 151 | + tid = k_thread_create(&psoc6_bless_rx_thread_data, psoc6_bless_rx_thread_stack, |
| 152 | + K_KERNEL_STACK_SIZEOF(psoc6_bless_rx_thread_stack), |
| 153 | + psoc6_bless_rx_thread, NULL, NULL, NULL, |
| 154 | + K_PRIO_COOP(CONFIG_BT_RX_PRIO), 0, K_NO_WAIT); |
| 155 | + k_thread_name_set(tid, "psoc6_bless_rx_thread"); |
| 156 | + |
| 157 | + return 0; |
| 158 | +} |
| 159 | + |
| 160 | +static int psoc6_bless_send(struct net_buf *buf) |
| 161 | +{ |
| 162 | + cy_en_ble_api_result_t result; |
| 163 | + |
| 164 | + memset(&hci_tx_pkt, 0, sizeof(cy_stc_ble_hci_tx_packet_info_t)); |
| 165 | + |
| 166 | + hci_tx_pkt.dataLength = buf->len; |
| 167 | + hci_tx_pkt.data = buf->data; |
| 168 | + |
| 169 | + switch (bt_buf_get_type(buf)) { |
| 170 | + case BT_BUF_ACL_OUT: |
| 171 | + hci_tx_pkt.packetType = PACKET_TYPE_HCI_ACL_DATA; |
| 172 | + break; |
| 173 | + case BT_BUF_CMD: |
| 174 | + hci_tx_pkt.packetType = PACKET_TYPE_HCI_COMMAND; |
| 175 | + break; |
| 176 | + default: |
| 177 | + net_buf_unref(buf); |
| 178 | + return -ENOTSUP; |
| 179 | + } |
| 180 | + |
| 181 | + if (k_sem_take(&psoc6_bless_operation_sem, K_MSEC(BLE_LOCK_TMOUT_MS)) != 0) { |
| 182 | + LOG_ERR("Failed to acquire BLE DRV Semaphore"); |
| 183 | + net_buf_unref(buf); |
| 184 | + return -EIO; |
| 185 | + } |
| 186 | + |
| 187 | + result = Cy_BLE_SoftHciSendAppPkt(&hci_tx_pkt); |
| 188 | + if (result != CY_BLE_SUCCESS) { |
| 189 | + LOG_ERR("Error in sending packet reason %d\r\n", result); |
| 190 | + } |
| 191 | + |
| 192 | + k_sem_give(&psoc6_bless_operation_sem); |
| 193 | + |
| 194 | + net_buf_unref(buf); |
| 195 | + |
| 196 | + return 0; |
| 197 | +} |
| 198 | + |
| 199 | +static int psoc6_bless_setup(void) |
| 200 | +{ |
| 201 | + struct net_buf *buf; |
| 202 | + int err; |
| 203 | + uint8_t *addr = (uint8_t *)&SFLASH_BLE_DEVICE_ADDRESS[0]; |
| 204 | + uint8_t hci_data[] = { |
| 205 | + addr[5], addr[4], addr[3], addr[2], addr[1], addr[0], BT_ADDR_LE_PUBLIC, |
| 206 | + }; |
| 207 | + |
| 208 | + buf = bt_hci_cmd_create(PSOC6_BLESS_OP_SET_PUBLIC_ADDR, sizeof(hci_data)); |
| 209 | + if (buf == NULL) { |
| 210 | + LOG_ERR("Unable to allocate command buffer"); |
| 211 | + return -ENOMEM; |
| 212 | + } |
| 213 | + |
| 214 | + /* Add data part of packet */ |
| 215 | + net_buf_add_mem(buf, hci_data, sizeof(hci_data)); |
| 216 | + |
| 217 | + err = bt_hci_cmd_send_sync(PSOC6_BLESS_OP_SET_PUBLIC_ADDR, buf, NULL); |
| 218 | + if (err) { |
| 219 | + return err; |
| 220 | + } |
| 221 | + |
| 222 | + return 0; |
| 223 | +} |
| 224 | + |
| 225 | +static int psoc6_bless_hci_init(void) |
| 226 | +{ |
| 227 | + cy_en_ble_api_result_t result; |
| 228 | + static const struct bt_hci_driver drv = { |
| 229 | + .name = "PSoC 6 BLESS", |
| 230 | + .bus = BT_HCI_DRIVER_BUS_VIRTUAL, |
| 231 | + .quirks = BT_QUIRK_NO_RESET, |
| 232 | + .open = psoc6_bless_open, |
| 233 | + .send = psoc6_bless_send, |
| 234 | + .setup = psoc6_bless_setup, |
| 235 | + }; |
| 236 | + |
| 237 | + /* Connect BLE interrupt to ISR */ |
| 238 | + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), psoc6_bless_isr_handler, 0, 0); |
| 239 | + |
| 240 | + /* Registers the generic callback functions. */ |
| 241 | + Cy_BLE_RegisterEventCallback(psoc6_bless_events_handler); |
| 242 | + |
| 243 | + /* Initializes the PSoC 6 BLESS Controller. */ |
| 244 | + result = Cy_BLE_InitController(&psoc6_bless_config); |
| 245 | + if (result != CY_BLE_SUCCESS) { |
| 246 | + LOG_ERR("Failed to init the BLE Controller"); |
| 247 | + return -EIO; |
| 248 | + } |
| 249 | + |
| 250 | + /* Enables the BLESS controller in HCI only mode. */ |
| 251 | + result = Cy_BLE_EnableHCIModeController(); |
| 252 | + if (result != CY_BLE_SUCCESS) { |
| 253 | + LOG_ERR("Failed to enable the BLE Controller in hci mode"); |
| 254 | + return -EIO; |
| 255 | + } |
| 256 | + |
| 257 | + /* Enables BLE Low-power mode (LPM)*/ |
| 258 | + Cy_BLE_EnableLowPowerMode(); |
| 259 | + |
| 260 | + /* Register a BLESS HCI driver to the Bluetooth stack. */ |
| 261 | + bt_hci_driver_register(&drv); |
| 262 | + |
| 263 | + return 0; |
| 264 | +} |
| 265 | + |
| 266 | +SYS_INIT(psoc6_bless_hci_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); |
0 commit comments