1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @brief File containing SPI device interface specific definitions for the
9  * Zephyr OS layer of the Wi-Fi driver.
10  */
11 
12 #include <string.h>
13 
14 #include <zephyr/drivers/spi.h>
15 #include <zephyr/logging/log.h>
16 #include <zephyr/drivers/wifi/nrf_wifi/bus/qspi_if.h>
17 
18 #include "spi_if.h"
19 
20 LOG_MODULE_DECLARE(wifi_nrf_bus, CONFIG_WIFI_NRF70_BUSLIB_LOG_LEVEL);
21 
22 #define NRF7002_NODE DT_NODELABEL(nrf70)
23 
24 static struct qspi_config *spim_config;
25 
26 static const struct spi_dt_spec spi_spec =
27 SPI_DT_SPEC_GET(NRF7002_NODE, SPI_WORD_SET(8) | SPI_TRANSFER_MSB, 0);
28 
spim_xfer_tx(unsigned int addr,void * data,unsigned int len)29 static int spim_xfer_tx(unsigned int addr, void *data, unsigned int len)
30 {
31 	int err;
32 	uint8_t hdr[4] = {
33 		0x02, /* PP opcode */
34 		(((addr >> 16) & 0xFF) | 0x80),
35 		(addr >> 8) & 0xFF,
36 		(addr & 0xFF)
37 	};
38 
39 	const struct spi_buf tx_buf[] = {
40 		{.buf = hdr,  .len = sizeof(hdr) },
41 		{.buf = data, .len = len },
42 	};
43 	const struct spi_buf_set tx = { .buffers = tx_buf, .count = 2 };
44 
45 
46 	err = spi_transceive_dt(&spi_spec, &tx, NULL);
47 
48 	return err;
49 }
50 
51 
spim_xfer_rx(unsigned int addr,void * data,unsigned int len,unsigned int discard_bytes)52 static int spim_xfer_rx(unsigned int addr, void *data, unsigned int len, unsigned int discard_bytes)
53 {
54 	uint8_t hdr[] = {
55 		0x0b, /* FASTREAD opcode */
56 		(addr >> 16) & 0xFF,
57 		(addr >> 8) & 0xFF,
58 		addr & 0xFF,
59 		0 /* dummy byte */
60 	};
61 	uint8_t discard[sizeof(hdr) + 2 * 4];
62 
63 	const struct spi_buf tx_buf[] = {
64 		{.buf = hdr,  .len = sizeof(hdr) },
65 		{.buf = NULL, .len = len },
66 	};
67 
68 	const struct spi_buf_set tx = { .buffers = tx_buf, .count = 2 };
69 
70 	const struct spi_buf rx_buf[] = {
71 		{.buf = discard,  .len = sizeof(hdr) + discard_bytes},
72 		{.buf = data, .len = len },
73 	};
74 
75 	const struct spi_buf_set rx = { .buffers = rx_buf, .count = 2 };
76 
77 	if (rx_buf[0].len > sizeof(discard)) {
78 		LOG_ERR("Discard bytes too large, please adjust buf size");
79 		return -EINVAL;
80 	}
81 
82 	return spi_transceive_dt(&spi_spec, &tx, &rx);
83 }
84 
spim_read_reg(uint32_t reg_addr,uint8_t * reg_value)85 int spim_read_reg(uint32_t reg_addr, uint8_t *reg_value)
86 {
87 	int err;
88 	uint8_t tx_buffer[6] = { reg_addr };
89 
90 	const struct spi_buf tx_buf = {
91 		.buf = tx_buffer,
92 		.len = sizeof(tx_buffer)
93 	};
94 
95 	const struct spi_buf_set tx = {
96 		.buffers = &tx_buf,
97 		.count = 1
98 	};
99 
100 	uint8_t sr[6];
101 
102 	struct spi_buf rx_buf = {
103 		.buf = &sr,
104 		.len = sizeof(sr),
105 	};
106 	const struct spi_buf_set rx = { .buffers = &rx_buf, .count = 1 };
107 
108 	err = spi_transceive_dt(&spi_spec, &tx, &rx);
109 
110 	LOG_DBG("err: %d -> %x %x %x %x %x %x", err, sr[0], sr[1], sr[2], sr[3], sr[4], sr[5]);
111 
112 	if (err == 0) {
113 		*reg_value = sr[1];
114 	}
115 
116 	return err;
117 }
118 
spim_write_reg(uint32_t reg_addr,const uint8_t reg_value)119 int spim_write_reg(uint32_t reg_addr, const uint8_t reg_value)
120 {
121 	int err;
122 	uint8_t tx_buffer[] = { reg_addr, reg_value };
123 
124 	const struct spi_buf tx_buf = { .buf = tx_buffer, .len = sizeof(tx_buffer) };
125 	const struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1 };
126 
127 	err = spi_transceive_dt(&spi_spec, &tx, NULL);
128 
129 	if (err) {
130 		LOG_ERR("SPI error: %d", err);
131 	}
132 
133 	return err;
134 }
135 
136 
spim_RDSR1(const struct device * dev,uint8_t * rdsr1)137 int spim_RDSR1(const struct device *dev, uint8_t *rdsr1)
138 {
139 	uint8_t val = 0;
140 
141 	return spim_read_reg(0x1F, &val);
142 }
143 
spim_RDSR2(const struct device * dev,uint8_t * rdsr1)144 int spim_RDSR2(const struct device *dev, uint8_t *rdsr1)
145 {
146 	uint8_t val = 0;
147 
148 	return spim_read_reg(0x2F, &val);
149 }
150 
spim_WRSR2(const struct device * dev,const uint8_t wrsr2)151 int spim_WRSR2(const struct device *dev, const uint8_t wrsr2)
152 {
153 	return spim_write_reg(0x3F, wrsr2);
154 }
155 
_spim_wait_while_rpu_awake(void)156 int _spim_wait_while_rpu_awake(void)
157 {
158 	int ret;
159 	uint8_t val = 0;
160 
161 	for (int ii = 0; ii < 10; ii++) {
162 
163 		ret = spim_read_reg(0x1F, &val);
164 
165 		LOG_DBG("RDSR1 = 0x%x", val);
166 
167 		if (!ret && (val & RPU_AWAKE_BIT)) {
168 			break;
169 		}
170 
171 		k_msleep(1);
172 	}
173 
174 	if (ret || !(val & RPU_AWAKE_BIT)) {
175 		LOG_ERR("RPU is not awake even after 10ms");
176 		return -1;
177 	}
178 
179 	return val;
180 }
181 
182 /* Wait until RDSR2 confirms RPU_WAKEUP_NOW write is successful */
spim_wait_while_rpu_wake_write(void)183 int spim_wait_while_rpu_wake_write(void)
184 {
185 	int ret;
186 	uint8_t val = 0;
187 
188 	for (int ii = 0; ii < 10; ii++) {
189 
190 		ret = spim_read_reg(0x2F, &val);
191 
192 		LOG_DBG("RDSR2 = 0x%x", val);
193 
194 		if (!ret && (val & RPU_WAKEUP_NOW)) {
195 			break;
196 		}
197 
198 		k_msleep(1);
199 	}
200 
201 	if (ret || !(val & RPU_WAKEUP_NOW)) {
202 		LOG_ERR("RPU wakeup write ACK failed even after 10ms");
203 		return -1;
204 	}
205 
206 	return ret;
207 }
208 
spim_cmd_rpu_wakeup(uint32_t data)209 int spim_cmd_rpu_wakeup(uint32_t data)
210 {
211 	return spim_write_reg(0x3F, data);
212 }
213 
spim_cmd_sleep_rpu(void)214 unsigned int spim_cmd_sleep_rpu(void)
215 {
216 	int err;
217 	uint8_t tx_buffer[] = { 0x3f, 0x0 };
218 
219 	const struct spi_buf tx_buf = { .buf = tx_buffer, .len = sizeof(tx_buffer) };
220 	const struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1 };
221 
222 	err = spi_transceive_dt(&spi_spec, &tx, NULL);
223 
224 	if (err) {
225 		LOG_ERR("SPI error: %d", err);
226 	}
227 
228 	return 0;
229 }
230 
spim_init(struct qspi_config * config)231 int spim_init(struct qspi_config *config)
232 {
233 	if (!spi_is_ready_dt(&spi_spec)) {
234 		LOG_ERR("Device %s is not ready", spi_spec.bus->name);
235 		return -ENODEV;
236 	}
237 
238 	spim_config = config;
239 
240 	k_sem_init(&spim_config->lock, 1, 1);
241 
242 	if (spi_spec.config.frequency >= MHZ(16)) {
243 		spim_config->qspi_slave_latency = 1;
244 	}
245 
246 	LOG_INF("SPIM %s: freq = %d MHz", spi_spec.bus->name,
247 		spi_spec.config.frequency / MHZ(1));
248 	LOG_INF("SPIM %s: latency = %d", spi_spec.bus->name, spim_config->qspi_slave_latency);
249 
250 	return 0;
251 }
252 
spim_deinit(void)253 int spim_deinit(void)
254 {
255 	LOG_DBG("TODO : %s", __func__);
256 
257 	return 0;
258 }
259 
spim_addr_check(unsigned int addr,const void * data,unsigned int len)260 static void spim_addr_check(unsigned int addr, const void *data, unsigned int len)
261 {
262 	if ((addr % 4 != 0) || (((unsigned int)data) % 4 != 0) || (len % 4 != 0)) {
263 		LOG_ERR("%s : Unaligned address %x %x %d %x %x", __func__, addr,
264 		       (unsigned int)data, (addr % 4 != 0), (((unsigned int)data) % 4 != 0),
265 		       (len % 4 != 0));
266 	}
267 }
268 
spim_write(unsigned int addr,const void * data,int len)269 int spim_write(unsigned int addr, const void *data, int len)
270 {
271 	int status;
272 
273 	spim_addr_check(addr, data, len);
274 
275 	addr |= spim_config->addrmask;
276 
277 	k_sem_take(&spim_config->lock, K_FOREVER);
278 
279 	status = spim_xfer_tx(addr, (void *)data, len);
280 
281 	k_sem_give(&spim_config->lock);
282 
283 	return status;
284 }
285 
spim_read(unsigned int addr,void * data,int len)286 int spim_read(unsigned int addr, void *data, int len)
287 {
288 	int status;
289 
290 	spim_addr_check(addr, data, len);
291 
292 	addr |= spim_config->addrmask;
293 
294 	k_sem_take(&spim_config->lock, K_FOREVER);
295 
296 	status = spim_xfer_rx(addr, data, len, 0);
297 
298 	k_sem_give(&spim_config->lock);
299 
300 	return status;
301 }
302 
spim_hl_readw(unsigned int addr,void * data)303 static int spim_hl_readw(unsigned int addr, void *data)
304 {
305 	int status = -1;
306 
307 	k_sem_take(&spim_config->lock, K_FOREVER);
308 
309 	status = spim_xfer_rx(addr, data, 4, 4 * spim_config->qspi_slave_latency);
310 
311 	k_sem_give(&spim_config->lock);
312 
313 	return status;
314 }
315 
spim_hl_read(unsigned int addr,void * data,int len)316 int spim_hl_read(unsigned int addr, void *data, int len)
317 {
318 	int count = 0;
319 
320 	spim_addr_check(addr, data, len);
321 
322 	while (count < (len / 4)) {
323 		spim_hl_readw(addr + (4 * count), (char *)data + (4 * count));
324 		count++;
325 	}
326 
327 	return 0;
328 }
329 
330 /* ------------------------------added for wifi utils -------------------------------- */
331 
spim_cmd_rpu_wakeup_fn(uint32_t data)332 int spim_cmd_rpu_wakeup_fn(uint32_t data)
333 {
334 	return spim_cmd_rpu_wakeup(data);
335 }
336 
spim_cmd_sleep_rpu_fn(void)337 int spim_cmd_sleep_rpu_fn(void)
338 {
339 	return spim_cmd_sleep_rpu();
340 }
341 
spim_wait_while_rpu_awake(void)342 int spim_wait_while_rpu_awake(void)
343 {
344 	return _spim_wait_while_rpu_awake();
345 }
346 
spi_validate_rpu_wake_writecmd(void)347 int spi_validate_rpu_wake_writecmd(void)
348 {
349 	return spim_wait_while_rpu_wake_write();
350 }
351