1 /*
2  * Copyright (c) 2023 Ambiq Micro Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @brief Ambiq Apollox Blue SoC extended driver for SPI based HCI.
9  */
10 
11 #define DT_DRV_COMPAT ambiq_bt_hci_spi
12 
13 #include <zephyr/init.h>
14 #include <zephyr/sys/byteorder.h>
15 #include <zephyr/drivers/gpio.h>
16 #include <zephyr/drivers/pinctrl.h>
17 #include <zephyr/drivers/bluetooth/hci_driver.h>
18 #include <zephyr/bluetooth/hci.h>
19 #include <zephyr/bluetooth/hci_raw.h>
20 
21 #define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL
22 #include <zephyr/logging/log.h>
23 LOG_MODULE_REGISTER(bt_apollox_driver);
24 
25 #include <zephyr/drivers/clock_control.h>
26 #include <zephyr/drivers/clock_control/clock_control_ambiq.h>
27 
28 #include "apollox_blue.h"
29 #include "am_devices_cooper.h"
30 
31 #define HCI_SPI_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(ambiq_bt_hci_spi)
32 #define SPI_DEV_NODE DT_BUS(HCI_SPI_NODE)
33 #define CLK_32M_NODE DT_NODELABEL(xo32m)
34 #define CLK_32K_NODE DT_NODELABEL(xo32k)
35 
36 /* Command/response for SPI operation */
37 #define SPI_WRITE   0x80
38 #define SPI_READ    0x04
39 #define READY_BYTE0 0x68
40 #define READY_BYTE1 0xA8
41 
42 /* Maximum attempts of SPI write */
43 #define SPI_WRITE_TIMEOUT 200
44 
45 #define SPI_MAX_RX_MSG_LEN 258
46 
47 static const struct gpio_dt_spec irq_gpio = GPIO_DT_SPEC_GET(HCI_SPI_NODE, irq_gpios);
48 static const struct gpio_dt_spec rst_gpio = GPIO_DT_SPEC_GET(HCI_SPI_NODE, reset_gpios);
49 static const struct gpio_dt_spec cs_gpio = GPIO_DT_SPEC_GET(SPI_DEV_NODE, cs_gpios);
50 static const struct gpio_dt_spec clkreq_gpio = GPIO_DT_SPEC_GET(HCI_SPI_NODE, clkreq_gpios);
51 
52 static struct gpio_callback irq_gpio_cb;
53 static struct gpio_callback clkreq_gpio_cb;
54 
55 static const struct device *clk32m_dev = DEVICE_DT_GET(CLK_32M_NODE);
56 static const struct device *clk32k_dev = DEVICE_DT_GET(CLK_32K_NODE);
57 
58 extern void bt_packet_irq_isr(const struct device *unused1, struct gpio_callback *unused2,
59 			      uint32_t unused3);
60 
irq_pin_state(void)61 static bool irq_pin_state(void)
62 {
63 	int pin_state;
64 
65 	pin_state = gpio_pin_get_dt(&irq_gpio);
66 	LOG_DBG("IRQ Pin: %d", pin_state);
67 	return pin_state > 0;
68 }
69 
clkreq_pin_state(void)70 static bool clkreq_pin_state(void)
71 {
72 	int pin_state;
73 
74 	pin_state = gpio_pin_get_dt(&clkreq_gpio);
75 	LOG_DBG("CLKREQ Pin: %d", pin_state);
76 	return pin_state > 0;
77 }
78 
bt_clkreq_isr(const struct device * unused1,struct gpio_callback * unused2,uint32_t unused3)79 static void bt_clkreq_isr(const struct device *unused1, struct gpio_callback *unused2,
80 			  uint32_t unused3)
81 {
82 	if (clkreq_pin_state()) {
83 		/* Enable XO32MHz */
84 		clock_control_on(clk32m_dev,
85 				 (clock_control_subsys_t)CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_BLE);
86 		gpio_pin_interrupt_configure_dt(&clkreq_gpio, GPIO_INT_EDGE_FALLING);
87 	} else {
88 		/* Disable XO32MHz */
89 		clock_control_off(clk32m_dev,
90 				  (clock_control_subsys_t)CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_BLE);
91 		gpio_pin_interrupt_configure_dt(&clkreq_gpio, GPIO_INT_EDGE_RISING);
92 	}
93 }
94 
bt_apollo_controller_ready_wait(void)95 static void bt_apollo_controller_ready_wait(void)
96 {
97 	/* The CS pin is used to wake up the controller as well. If the controller is not ready
98 	 * to receive the SPI packet, need to inactivate the CS at first and reconfigure the pin
99 	 * to CS function again before next sending attempt.
100 	 */
101 	gpio_pin_configure_dt(&cs_gpio, GPIO_OUTPUT_INACTIVE);
102 	k_busy_wait(200);
103 	PINCTRL_DT_DEFINE(SPI_DEV_NODE);
104 	pinctrl_apply_state(PINCTRL_DT_DEV_CONFIG_GET(SPI_DEV_NODE), PINCTRL_STATE_DEFAULT);
105 	k_busy_wait(2000);
106 }
107 
bt_apollo_controller_reset(void)108 static void bt_apollo_controller_reset(void)
109 {
110 	/* Reset the controller*/
111 	gpio_pin_set_dt(&rst_gpio, 1);
112 
113 	/* Take controller out of reset */
114 	k_sleep(K_MSEC(10));
115 	gpio_pin_set_dt(&rst_gpio, 0);
116 
117 	/* Give the controller some time to boot */
118 	k_sleep(K_MSEC(500));
119 }
120 
bt_apollo_spi_send(uint8_t * data,uint16_t len,bt_spi_transceive_fun transceive)121 int bt_apollo_spi_send(uint8_t *data, uint16_t len, bt_spi_transceive_fun transceive)
122 {
123 	int ret;
124 	uint8_t command[1] = {SPI_WRITE};
125 	uint8_t response[2] = {0, 0};
126 	uint16_t fail_count = 0;
127 
128 	do {
129 		/* Check if the controller is ready to receive the HCI packets. */
130 		ret = transceive(command, 1, response, 2);
131 		if ((response[0] != READY_BYTE0) || (response[1] != READY_BYTE1) || ret) {
132 			bt_apollo_controller_ready_wait();
133 		} else {
134 			/* Transmit the message */
135 			ret = transceive(data, len, NULL, 0);
136 			if (ret) {
137 				LOG_ERR("SPI write error %d", ret);
138 			}
139 			break;
140 		}
141 	} while (fail_count++ < SPI_WRITE_TIMEOUT);
142 
143 	return ret;
144 }
145 
bt_apollo_spi_rcv(uint8_t * data,uint16_t * len,bt_spi_transceive_fun transceive)146 int bt_apollo_spi_rcv(uint8_t *data, uint16_t *len, bt_spi_transceive_fun transceive)
147 {
148 	int ret;
149 	uint8_t command[1] = {SPI_READ};
150 	uint8_t response[2] = {0, 0};
151 	uint16_t read_size = 0;
152 
153 	do {
154 		/* Skip if the IRQ pin is not in high state */
155 		if (!irq_pin_state()) {
156 			ret = -1;
157 			break;
158 		}
159 
160 		/* Check the available packet bytes */
161 		ret = transceive(command, 1, response, 2);
162 		if (ret) {
163 			break;
164 		}
165 
166 		/* Check if the read size is acceptable */
167 		read_size = (uint16_t)(response[0] | response[1] << 8);
168 		if ((read_size == 0) || (read_size > SPI_MAX_RX_MSG_LEN)) {
169 			ret = -1;
170 			break;
171 		}
172 
173 		*len = read_size;
174 
175 		/* Read the HCI data from controller */
176 		ret = transceive(NULL, 0, data, read_size);
177 
178 		if (ret) {
179 			LOG_ERR("SPI read error %d", ret);
180 			break;
181 		}
182 	} while (0);
183 
184 	return ret;
185 }
186 
bt_apollo_vnd_rcv_ongoing(uint8_t * data,uint16_t len)187 bool bt_apollo_vnd_rcv_ongoing(uint8_t *data, uint16_t len)
188 {
189 	/* The vendor specific handshake command/response is incompatible with
190 	 * standard Bluetooth HCI format, need to handle the received packets
191 	 * specifically.
192 	 */
193 	if (am_devices_cooper_get_initialize_state() != AM_DEVICES_COOPER_STATE_INITIALIZED) {
194 		am_devices_cooper_handshake_recv(data, len);
195 		return true;
196 	} else {
197 		return false;
198 	}
199 }
200 
bt_hci_transport_setup(const struct device * dev)201 int bt_hci_transport_setup(const struct device *dev)
202 {
203 	ARG_UNUSED(dev);
204 
205 	int ret;
206 
207 	/* Configure the XO32MHz and XO32kHz clocks.*/
208 	clock_control_configure(clk32k_dev, NULL, NULL);
209 	clock_control_configure(clk32m_dev, NULL, NULL);
210 
211 	/* Enable XO32kHz for Controller */
212 	clock_control_on(clk32k_dev, (clock_control_subsys_t)CLOCK_CONTROL_AMBIQ_TYPE_LFXTAL);
213 
214 	/* Enable XO32MHz for Controller */
215 	clock_control_on(clk32m_dev, (clock_control_subsys_t)CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_BLE);
216 
217 	/* Configure RST pin and hold BLE in Reset */
218 	ret = gpio_pin_configure_dt(&rst_gpio, GPIO_OUTPUT_ACTIVE);
219 	if (ret) {
220 		return ret;
221 	}
222 
223 	/* Configure IRQ pin and register the callback */
224 	ret = gpio_pin_configure_dt(&irq_gpio, GPIO_INPUT);
225 	if (ret) {
226 		return ret;
227 	}
228 
229 	gpio_init_callback(&irq_gpio_cb, bt_packet_irq_isr, BIT(irq_gpio.pin));
230 	ret = gpio_add_callback(irq_gpio.port, &irq_gpio_cb);
231 	if (ret) {
232 		return ret;
233 	}
234 
235 	/* Configure CLKREQ pin and register the callback */
236 	ret = gpio_pin_configure_dt(&clkreq_gpio, GPIO_INPUT);
237 	if (ret) {
238 		return ret;
239 	}
240 
241 	gpio_init_callback(&clkreq_gpio_cb, bt_clkreq_isr, BIT(clkreq_gpio.pin));
242 	ret = gpio_add_callback(clkreq_gpio.port, &clkreq_gpio_cb);
243 	if (ret) {
244 		return ret;
245 	}
246 
247 	/* Configure the interrupt edge for CLKREQ pin */
248 	gpio_pin_interrupt_configure_dt(&clkreq_gpio, GPIO_INT_EDGE_RISING);
249 
250 	/* Take controller out of reset */
251 	k_sleep(K_MSEC(10));
252 	gpio_pin_set_dt(&rst_gpio, 0);
253 
254 	/* Give the controller some time to boot */
255 	k_sleep(K_MSEC(500));
256 
257 	/* Configure the interrupt edge for IRQ pin */
258 	gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_EDGE_RISING);
259 
260 	return 0;
261 }
262 
bt_apollo_controller_init(spi_transmit_fun transmit)263 int bt_apollo_controller_init(spi_transmit_fun transmit)
264 {
265 	int ret;
266 	am_devices_cooper_callback_t cb = {
267 		.write = transmit,
268 		.reset = bt_apollo_controller_reset,
269 	};
270 
271 	/* Initialize the BLE controller */
272 	ret = am_devices_cooper_init(&cb);
273 	if (ret == AM_DEVICES_COOPER_STATUS_SUCCESS) {
274 		am_devices_cooper_set_initialize_state(AM_DEVICES_COOPER_STATE_INITIALIZED);
275 		LOG_INF("BT controller initialized");
276 	} else {
277 		am_devices_cooper_set_initialize_state(AM_DEVICES_COOPER_STATE_INITIALIZE_FAIL);
278 		LOG_ERR("BT controller initialization fail");
279 	}
280 
281 	return ret;
282 }
283 
bt_apollo_set_nvds(void)284 static int bt_apollo_set_nvds(void)
285 {
286 	int ret;
287 	struct net_buf *buf;
288 
289 #if defined(CONFIG_BT_HCI_RAW)
290 	struct bt_hci_cmd_hdr hdr;
291 
292 	hdr.opcode = sys_cpu_to_le16(HCI_VSC_UPDATE_NVDS_CFG_CMD_OPCODE);
293 	hdr.param_len = HCI_VSC_UPDATE_NVDS_CFG_CMD_LENGTH;
294 	buf = bt_buf_get_tx(BT_BUF_CMD, K_NO_WAIT, &hdr, sizeof(hdr));
295 	if (!buf) {
296 		return -ENOBUFS;
297 	}
298 
299 	net_buf_add_mem(buf, &am_devices_cooper_nvds[0], HCI_VSC_UPDATE_NVDS_CFG_CMD_LENGTH);
300 	ret = bt_send(buf);
301 
302 	if (!ret) {
303 		/* Give some time to make NVDS take effect in BLE controller */
304 		k_sleep(K_MSEC(5));
305 
306 		/* Need to send reset command to make the NVDS take effect */
307 		hdr.opcode = sys_cpu_to_le16(BT_HCI_OP_RESET);
308 		hdr.param_len = 0;
309 		buf = bt_buf_get_tx(BT_BUF_CMD, K_NO_WAIT, &hdr, sizeof(hdr));
310 		if (!buf) {
311 			return -ENOBUFS;
312 		}
313 
314 		ret = bt_send(buf);
315 	}
316 #else
317 	uint8_t *p;
318 
319 	buf = bt_hci_cmd_create(HCI_VSC_UPDATE_NVDS_CFG_CMD_OPCODE,
320 				HCI_VSC_UPDATE_NVDS_CFG_CMD_LENGTH);
321 	if (!buf) {
322 		return -ENOBUFS;
323 	}
324 
325 	p = net_buf_add(buf, HCI_VSC_UPDATE_NVDS_CFG_CMD_LENGTH);
326 	memcpy(p, &am_devices_cooper_nvds[0], HCI_VSC_UPDATE_NVDS_CFG_CMD_LENGTH);
327 	ret = bt_hci_cmd_send_sync(HCI_VSC_UPDATE_NVDS_CFG_CMD_OPCODE, buf, NULL);
328 
329 	if (!ret) {
330 		/* Give some time to make NVDS take effect in BLE controller */
331 		k_sleep(K_MSEC(5));
332 	}
333 #endif /* defined(CONFIG_BT_HCI_RAW) */
334 
335 	return ret;
336 }
337 
bt_apollo_vnd_setup(void)338 int bt_apollo_vnd_setup(void)
339 {
340 	int ret;
341 
342 	/* Set the NVDS parameters to BLE controller */
343 	ret = bt_apollo_set_nvds();
344 
345 	return ret;
346 }
347 
bt_apollo_dev_init(void)348 int bt_apollo_dev_init(void)
349 {
350 	if (!gpio_is_ready_dt(&irq_gpio)) {
351 		LOG_ERR("IRQ GPIO device not ready");
352 		return -ENODEV;
353 	}
354 
355 	if (!gpio_is_ready_dt(&rst_gpio)) {
356 		LOG_ERR("Reset GPIO device not ready");
357 		return -ENODEV;
358 	}
359 
360 	if (!gpio_is_ready_dt(&clkreq_gpio)) {
361 		LOG_ERR("CLKREQ GPIO device not ready");
362 		return -ENODEV;
363 	}
364 
365 	return 0;
366 }
367