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.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 LOG_LEVEL      CONFIG_BT_HCI_DRIVER_LOG_LEVEL
27 #include <zephyr/logging/log.h>
28 LOG_MODULE_REGISTER(psoc6_bless);
29 
30 #include "cy_ble_stack_pvt.h"
31 #include "cycfg_ble.h"
32 
33 #define DT_DRV_COMPAT infineon_cat1_bless_hci
34 
35 struct psoc6_bless_data {
36 	bt_hci_recv_t recv;
37 };
38 
39 #define BLE_LOCK_TMOUT_MS       (1000)
40 #define BLE_THREAD_SEM_TMOUT_MS (1000)
41 
42 #define CYBLE_STACK_SIZE (CY_BLE_STACK_RAM_SIZE + 4096)
43 
44 #define PSOC6_BLESS_OP_SET_PUBLIC_ADDR BT_OP(BT_OGF_VS, 0x1a0)
45 
46 static K_SEM_DEFINE(psoc6_bless_rx_sem, 0, 1);
47 static K_SEM_DEFINE(psoc6_bless_operation_sem, 1, 1);
48 static K_KERNEL_STACK_DEFINE(psoc6_bless_rx_thread_stack, CONFIG_BT_RX_STACK_SIZE);
49 static struct k_thread psoc6_bless_rx_thread_data;
50 static cy_stc_ble_hci_tx_packet_info_t hci_tx_pkt;
51 
52 extern void Cy_BLE_EnableLowPowerMode(void);
53 
54 CY_ALIGN(sizeof(uint32_t)) CY_NOINIT uint8_t psoc6_bless_stack_memory[CYBLE_STACK_SIZE];
55 
56 /** BLE Stack parameters */
57 static cy_stc_ble_stack_params_t psoc6_bless_stack_param = {
58 	.memoryHeapPtr = psoc6_bless_stack_memory,
59 	.totalHeapSz = CYBLE_STACK_SIZE,
60 	.dleMaxTxCapability = CONFIG_BT_PSOC6_BLESS_MAX_TX_PAYLOAD,
61 	.dleMaxRxCapability = CONFIG_BT_PSOC6_BLESS_MAX_RX_PAYLOAD,
62 	.featureMask = (CY_BLE_DLE_FEATURE | CY_BLE_LL_PRIVACY_FEATURE |
63 			CY_BLE_SECURE_CONN_FEATURE | CY_BLE_PHY_UPDATE_FEATURE |
64 			CY_BLE_STORE_BONDLIST_FEATURE | CY_BLE_STORE_RESOLVING_LIST_FEATURE |
65 			CY_BLE_STORE_WHITELIST_FEATURE | CY_BLE_TX_POWER_CALIBRATION_FEATURE),
66 	.maxConnCount = CY_BLE_CONN_COUNT,
67 	.tx5dbmModeEn = CY_BLE_ENABLE_TX_5DBM,
68 };
69 
70 static const cy_stc_sysint_t psoc6_bless_isr_cfg = {
71 	.intrSrc = DT_INST_IRQN(0),
72 	.intrPriority = DT_INST_IRQ(0, priority),
73 };
74 
75 static cy_stc_ble_hw_config_t psoc6_bless_hw_config = {
76 	.blessIsrConfig = &psoc6_bless_isr_cfg,
77 };
78 
79 static const cy_stc_ble_config_t psoc6_bless_config = {
80 	.stackParam = &psoc6_bless_stack_param,
81 	.hw = &psoc6_bless_hw_config,
82 };
83 
psoc6_bless_rx_thread(void *,void *,void *)84 static void psoc6_bless_rx_thread(void *, void *, void *)
85 {
86 	while (true) {
87 		k_sem_take(&psoc6_bless_rx_sem, K_MSEC(BLE_THREAD_SEM_TMOUT_MS));
88 		Cy_BLE_ProcessEvents();
89 	}
90 }
91 
psoc6_bless_isr_handler(const struct device * dev)92 static void psoc6_bless_isr_handler(const struct device *dev)
93 {
94 	if (Cy_BLE_HAL_BlessInterruptHandler()) {
95 		k_sem_give(&psoc6_bless_rx_sem);
96 	}
97 }
98 
psoc6_bless_events_handler(uint32_t eventCode,void * eventParam)99 static void psoc6_bless_events_handler(uint32_t eventCode, void *eventParam)
100 {
101 	const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0));
102 	struct psoc6_bless_data *hci = dev->data;
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 BT_HCI_H4_EVT:
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 BT_HCI_H4_ACL:
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 	hci->recv(dev, buf);
145 }
146 
psoc6_bless_open(const struct device * dev,bt_hci_recv_t recv)147 static int psoc6_bless_open(const struct device *dev, bt_hci_recv_t recv)
148 {
149 	struct psoc6_bless_data *hci = dev->data;
150 	k_tid_t tid;
151 
152 	hci->recv = recv;
153 
154 	tid = k_thread_create(&psoc6_bless_rx_thread_data, psoc6_bless_rx_thread_stack,
155 			      K_KERNEL_STACK_SIZEOF(psoc6_bless_rx_thread_stack),
156 			      psoc6_bless_rx_thread, NULL, NULL, NULL,
157 			      K_PRIO_COOP(CONFIG_BT_RX_PRIO), 0, K_NO_WAIT);
158 	k_thread_name_set(tid, "psoc6_bless_rx_thread");
159 
160 	return 0;
161 }
162 
psoc6_bless_send(const struct device * dev,struct net_buf * buf)163 static int psoc6_bless_send(const struct device *dev, struct net_buf *buf)
164 {
165 	cy_en_ble_api_result_t result;
166 
167 	ARG_UNUSED(dev);
168 
169 	memset(&hci_tx_pkt, 0, sizeof(cy_stc_ble_hci_tx_packet_info_t));
170 
171 	hci_tx_pkt.dataLength = buf->len;
172 	hci_tx_pkt.data = buf->data;
173 
174 	switch (bt_buf_get_type(buf)) {
175 	case BT_BUF_ACL_OUT:
176 		hci_tx_pkt.packetType = BT_HCI_H4_ACL;
177 		break;
178 	case BT_BUF_CMD:
179 		hci_tx_pkt.packetType = BT_HCI_H4_CMD;
180 		break;
181 	default:
182 		net_buf_unref(buf);
183 		return -ENOTSUP;
184 	}
185 
186 	if (k_sem_take(&psoc6_bless_operation_sem, K_MSEC(BLE_LOCK_TMOUT_MS)) != 0) {
187 		LOG_ERR("Failed to acquire BLE DRV Semaphore");
188 		net_buf_unref(buf);
189 		return -EIO;
190 	}
191 
192 	result = Cy_BLE_SoftHciSendAppPkt(&hci_tx_pkt);
193 	if (result != CY_BLE_SUCCESS) {
194 		LOG_ERR("Error in sending packet reason %d\r\n", result);
195 	}
196 
197 	k_sem_give(&psoc6_bless_operation_sem);
198 
199 	net_buf_unref(buf);
200 
201 	/* Unblock psoc6 bless rx thread to process controller events
202 	 * (by calling Cy_BLE_ProcessEvents function)
203 	 */
204 	k_sem_give(&psoc6_bless_rx_sem);
205 	return 0;
206 }
207 
psoc6_bless_setup(const struct device * dev,const struct bt_hci_setup_params * params)208 static int psoc6_bless_setup(const struct device *dev, const struct bt_hci_setup_params *params)
209 {
210 	ARG_UNUSED(dev);
211 	ARG_UNUSED(params);
212 	struct net_buf *buf;
213 	int err;
214 	uint8_t *addr = (uint8_t *)&SFLASH_BLE_DEVICE_ADDRESS[0];
215 	uint8_t hci_data[] = {
216 		addr[5], addr[4], addr[3], addr[2], addr[1], addr[0], BT_ADDR_LE_PUBLIC,
217 	};
218 
219 	buf = bt_hci_cmd_create(PSOC6_BLESS_OP_SET_PUBLIC_ADDR, sizeof(hci_data));
220 	if (buf == NULL) {
221 		LOG_ERR("Unable to allocate command buffer");
222 		return -ENOMEM;
223 	}
224 
225 	/* Add data part of packet */
226 	net_buf_add_mem(buf, hci_data, sizeof(hci_data));
227 
228 	err = bt_hci_cmd_send_sync(PSOC6_BLESS_OP_SET_PUBLIC_ADDR, buf, NULL);
229 	if (err) {
230 		return err;
231 	}
232 
233 	return 0;
234 }
235 
psoc6_bless_hci_init(const struct device * dev)236 static int psoc6_bless_hci_init(const struct device *dev)
237 {
238 	cy_en_ble_api_result_t result;
239 
240 	ARG_UNUSED(dev);
241 
242 	/* Connect BLE interrupt to ISR */
243 	IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), psoc6_bless_isr_handler, 0, 0);
244 
245 	/* Registers the generic callback functions.  */
246 	Cy_BLE_RegisterEventCallback(psoc6_bless_events_handler);
247 
248 	/* Initializes the PSOC 6 BLESS Controller. */
249 	result = Cy_BLE_InitController(&psoc6_bless_config);
250 	if (result != CY_BLE_SUCCESS) {
251 		LOG_ERR("Failed to init the BLE Controller");
252 		return -EIO;
253 	}
254 
255 	/* Enables the BLESS controller in HCI only mode. */
256 	result = Cy_BLE_EnableHCIModeController();
257 	if (result != CY_BLE_SUCCESS) {
258 		LOG_ERR("Failed to enable the BLE Controller in hci mode");
259 		return -EIO;
260 	}
261 
262 	/* Enables BLE Low-power mode (LPM)*/
263 	Cy_BLE_EnableLowPowerMode();
264 
265 	return 0;
266 }
267 
268 static DEVICE_API(bt_hci, drv) = {
269 	.open = psoc6_bless_open,
270 	.send = psoc6_bless_send,
271 	.setup = psoc6_bless_setup,
272 };
273 
274 #define PSOC6_BLESS_DEVICE_INIT(inst) \
275 	static struct psoc6_bless_data psoc6_bless_data_##inst = { \
276 	}; \
277 	DEVICE_DT_INST_DEFINE(inst, psoc6_bless_hci_init, NULL, &psoc6_bless_data_##inst, NULL, \
278 			      POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &drv)
279 
280 /* Only one instance supported */
281 PSOC6_BLESS_DEVICE_INIT(0)
282