1 /*
2  * Copyright (c) 2023 Stephen Boylan <stephen.boylan@beechwoods.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT raspberrypi_pico_spi_pio
8 
9 #define LOG_LEVEL CONFIG_SPI_LOG_LEVEL
10 #include <zephyr/logging/log.h>
11 LOG_MODULE_REGISTER(spi_pico_pio);
12 
13 #include <zephyr/sys/util.h>
14 #include <zephyr/sys/sys_io.h>
15 #include <zephyr/sys/byteorder.h>
16 #include <zephyr/drivers/clock_control.h>
17 #include <zephyr/drivers/spi.h>
18 #include <zephyr/drivers/pinctrl.h>
19 #include "spi_context.h"
20 
21 #include <zephyr/drivers/misc/pio_rpi_pico/pio_rpi_pico.h>
22 
23 #include <hardware/pio.h>
24 #include "hardware/clocks.h"
25 
26 #define SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED DT_ANY_INST_HAS_PROP_STATUS_OKAY(sio_gpios)
27 
28 #define PIO_CYCLES     (4)
29 #define PIO_FIFO_DEPTH (4)
30 
31 struct spi_pico_pio_config {
32 	const struct device *piodev;
33 	const struct pinctrl_dev_config *pin_cfg;
34 	struct gpio_dt_spec clk_gpio;
35 	struct gpio_dt_spec mosi_gpio;
36 	struct gpio_dt_spec miso_gpio;
37 	struct gpio_dt_spec sio_gpio;
38 	const struct device *clk_dev;
39 	clock_control_subsys_t clk_id;
40 };
41 
42 struct spi_pico_pio_data {
43 	struct spi_context spi_ctx;
44 	uint32_t tx_count;
45 	uint32_t rx_count;
46 	PIO pio;
47 	size_t pio_sm;
48 	uint32_t pio_tx_offset;
49 	uint32_t pio_rx_offset;
50 	uint32_t pio_rx_wrap_target;
51 	uint32_t pio_rx_wrap;
52 	uint32_t bits;
53 	uint32_t dfs;
54 };
55 
56 /* ------------ */
57 /* spi_mode_0_0 */
58 /* ------------ */
59 
60 #define SPI_MODE_0_0_WRAP_TARGET 0
61 #define SPI_MODE_0_0_WRAP        1
62 #define SPI_MODE_0_0_CYCLES      4
63 
64 RPI_PICO_PIO_DEFINE_PROGRAM(spi_mode_0_0, SPI_MODE_0_0_WRAP_TARGET, SPI_MODE_0_0_WRAP,
65 			    /*     .wrap_target */
66 			    0x6101, /*  0: out    pins, 1         side 0 [1] */
67 			    0x5101, /*  1: in     pins, 1         side 1 [1] */
68 				    /*     .wrap */
69 );
70 
71 /* ------------ */
72 /* spi_mode_0_1 */
73 /* ------------ */
74 
75 #define SPI_MODE_0_1_WRAP_TARGET 0
76 #define SPI_MODE_0_1_WRAP        2
77 #define SPI_MODE_0_1_CYCLES      4
78 
79 RPI_PICO_PIO_DEFINE_PROGRAM(spi_mode_0_1, SPI_MODE_0_1_WRAP_TARGET, SPI_MODE_0_1_WRAP,
80 			    /*     .wrap_target */
81 			    0x6021,   /* 0: out    x, 1            side 0 */
82 			    0xb101,   /* 1: mov    pins, x         side 1 [1] */
83 			    0x4001,   /* 2: in     pins, 1         side 0 */
84 				      /*     .wrap */
85 );
86 
87 /* ------------ */
88 /* spi_mode_1_1 */
89 /* ------------ */
90 
91 #define SPI_MODE_1_1_WRAP_TARGET 0
92 #define SPI_MODE_1_1_WRAP        2
93 #define SPI_MODE_1_1_CYCLES      4
94 
95 RPI_PICO_PIO_DEFINE_PROGRAM(spi_mode_1_1, SPI_MODE_1_1_WRAP_TARGET, SPI_MODE_1_1_WRAP,
96 			    /*     .wrap_target */
97 			    0x7021, /*  0: out    x, 1            side 1 */
98 			    0xa101, /*  1: mov    pins, x         side 0 [1] */
99 			    0x5001, /*  2: in     pins, 1         side 1 */
100 				    /*     .wrap */
101 );
102 
103 #if SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED
104 /* ------------------- */
105 /* spi_sio_mode_0_0_tx */
106 /* ------------------- */
107 
108 #define SPI_SIO_MODE_0_0_TX_WRAP_TARGET 0
109 #define SPI_SIO_MODE_0_0_TX_WRAP        2
110 #define SPI_SIO_MODE_0_0_TX_CYCLES      2
111 
112 RPI_PICO_PIO_DEFINE_PROGRAM(spi_sio_mode_0_0_tx, SPI_SIO_MODE_0_0_TX_WRAP_TARGET,
113 			    SPI_SIO_MODE_0_0_TX_WRAP,
114 			    /*     .wrap_target */
115 			    0x80a0, /*  0: pull   block           side 0  */
116 			    0x6001, /*  1: out    pins, 1         side 0  */
117 			    0x10e1, /*  2: jmp    !osre, 1        side 1  */
118 				    /*     .wrap */
119 );
120 
121 /* ------------------------- */
122 /* spi_sio_mode_0_0_rx */
123 /* ------------------------- */
124 
125 #define SPI_SIO_MODE_0_0_RX_WRAP_TARGET 0
126 #define SPI_SIO_MODE_0_0_RX_WRAP        3
127 #define SPI_SIO_MODE_0_0_RX_CYCLES      2
128 
129 RPI_PICO_PIO_DEFINE_PROGRAM(spi_sio_mode_0_0_rx, SPI_SIO_MODE_0_0_RX_WRAP_TARGET,
130 			    SPI_SIO_MODE_0_0_RX_WRAP,
131 			    /*     .wrap_target */
132 			    0x80a0, /*  0: pull   block           side 0 */
133 			    0x6020, /*  1: out    x, 32           side 0 */
134 			    0x5001, /*  2: in     pins, 1         side 1 */
135 			    0x0042, /*  3: jmp    x--, 2          side 0 */
136 				    /*     .wrap */
137 );
138 #endif /* SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED */
139 
spi_pico_pio_clock_divisor(const uint32_t clock_freq,int cycles,uint32_t spi_frequency)140 static float spi_pico_pio_clock_divisor(const uint32_t clock_freq, int cycles,
141 					uint32_t spi_frequency)
142 {
143 	return (float)clock_freq / (float)(cycles * spi_frequency);
144 }
145 
spi_pico_pio_maximum_clock_frequency(const uint32_t clock_freq,int cycles)146 static uint32_t spi_pico_pio_maximum_clock_frequency(const uint32_t clock_freq, int cycles)
147 {
148 	return clock_freq / cycles;
149 }
150 
spi_pico_pio_minimum_clock_frequency(const uint32_t clock_freq,int cycles)151 static uint32_t spi_pico_pio_minimum_clock_frequency(const uint32_t clock_freq, int cycles)
152 {
153 	return clock_freq / (cycles * 65536);
154 }
155 
spi_pico_pio_transfer_ongoing(struct spi_pico_pio_data * data)156 static inline bool spi_pico_pio_transfer_ongoing(struct spi_pico_pio_data *data)
157 {
158 	return spi_context_tx_on(&data->spi_ctx) || spi_context_rx_on(&data->spi_ctx);
159 }
160 
spi_pico_pio_sm_put8(PIO pio,uint sm,uint8_t data)161 static inline void spi_pico_pio_sm_put8(PIO pio, uint sm, uint8_t data)
162 {
163 	/* Do 8 bit accesses on FIFO, so that write data is byte-replicated. This */
164 	/* gets us the left-justification for free (for MSB-first shift-out) */
165 	io_rw_8 *txfifo = (io_rw_8 *)&pio->txf[sm];
166 
167 	*txfifo = data;
168 }
169 
spi_pico_pio_sm_get8(PIO pio,uint sm)170 static inline uint8_t spi_pico_pio_sm_get8(PIO pio, uint sm)
171 {
172 	/* Do 8 bit accesses on FIFO, so that write data is byte-replicated. This */
173 	/* gets us the left-justification for free (for MSB-first shift-out) */
174 	io_rw_8 *rxfifo = (io_rw_8 *)&pio->rxf[sm];
175 
176 	return *rxfifo;
177 }
178 
spi_pico_pio_sm_put16(PIO pio,uint sm,uint16_t data)179 static inline void spi_pico_pio_sm_put16(PIO pio, uint sm, uint16_t data)
180 {
181 	/* Do 16 bit accesses on FIFO, so that write data is halfword-replicated. This */
182 	/* gets us the left-justification for free (for MSB-first shift-out) */
183 	io_rw_16 *txfifo = (io_rw_16 *)&pio->txf[sm];
184 
185 	*txfifo = data;
186 }
187 
spi_pico_pio_sm_get16(PIO pio,uint sm)188 static inline uint16_t spi_pico_pio_sm_get16(PIO pio, uint sm)
189 {
190 	io_rw_16 *rxfifo = (io_rw_16 *)&pio->rxf[sm];
191 
192 	return *rxfifo;
193 }
194 
spi_pico_pio_sm_put32(PIO pio,uint sm,uint32_t data)195 static inline void spi_pico_pio_sm_put32(PIO pio, uint sm, uint32_t data)
196 {
197 	io_rw_32 *txfifo = (io_rw_32 *)&pio->txf[sm];
198 
199 	*txfifo = data;
200 }
201 
spi_pico_pio_sm_get32(PIO pio,uint sm)202 static inline uint32_t spi_pico_pio_sm_get32(PIO pio, uint sm)
203 {
204 	io_rw_32 *rxfifo = (io_rw_32 *)&pio->rxf[sm];
205 
206 	return *rxfifo;
207 }
208 
spi_pico_pio_sm_complete(struct spi_pico_pio_data * data)209 static inline int spi_pico_pio_sm_complete(struct spi_pico_pio_data *data)
210 {
211 	return ((data->pio->sm[data->pio_sm].addr == data->pio_tx_offset) &&
212 		pio_sm_is_tx_fifo_empty(data->pio, data->pio_sm));
213 }
214 
spi_pico_pio_configure(const struct spi_pico_pio_config * dev_cfg,struct spi_pico_pio_data * data,const struct spi_config * spi_cfg)215 static int spi_pico_pio_configure(const struct spi_pico_pio_config *dev_cfg,
216 				  struct spi_pico_pio_data *data, const struct spi_config *spi_cfg)
217 {
218 	const struct gpio_dt_spec *clk = NULL;
219 	pio_sm_config sm_config;
220 	bool lsb = false;
221 	uint32_t cpol = 0;
222 	uint32_t cpha = 0;
223 	uint32_t rc = 0;
224 	uint32_t clock_freq;
225 
226 	rc = clock_control_on(dev_cfg->clk_dev, dev_cfg->clk_id);
227 	if (rc < 0) {
228 		LOG_ERR("Failed to enable the clock");
229 		return rc;
230 	}
231 
232 	rc = clock_control_get_rate(dev_cfg->clk_dev, dev_cfg->clk_id, &clock_freq);
233 	if (rc < 0) {
234 		LOG_ERR("Failed to get clock frequency");
235 		return rc;
236 	}
237 
238 	if (spi_context_configured(&data->spi_ctx, spi_cfg)) {
239 		return 0;
240 	}
241 
242 	if (spi_cfg->operation & SPI_OP_MODE_SLAVE) {
243 		LOG_ERR("Slave mode not supported");
244 		return -ENOTSUP;
245 	}
246 
247 	/* Note that SPI_TRANSFER_LSB controls the direction of shift, not the */
248 	/* "endianness" of the data.  In MSB mode, the high-order bit of the   */
249 	/* most significant byte is sent first;  in LSB mode, the low-order    */
250 	/* bit of the least-significant byte is sent first.                    */
251 	if (spi_cfg->operation & SPI_TRANSFER_LSB) {
252 		lsb = true;
253 	}
254 
255 #if defined(CONFIG_SPI_EXTENDED_MODES)
256 	if (spi_cfg->operation & (SPI_LINES_DUAL | SPI_LINES_QUAD | SPI_LINES_OCTAL)) {
257 		LOG_ERR("Unsupported configuration");
258 		return -ENOTSUP;
259 	}
260 #endif /* CONFIG_SPI_EXTENDED_MODES */
261 
262 	data->bits = SPI_WORD_SIZE_GET(spi_cfg->operation);
263 
264 	if ((data->bits != 8) && (data->bits != 16) && (data->bits != 32)) {
265 		LOG_ERR("Only 8, 16, and 32 bit word sizes are supported");
266 		return -ENOTSUP;
267 	}
268 
269 	data->dfs = ((data->bits - 1) / 8) + 1;
270 
271 	if (spi_cfg->operation & SPI_CS_ACTIVE_HIGH) {
272 		gpio_set_outover(data->spi_ctx.config->cs.gpio.pin, GPIO_OVERRIDE_INVERT);
273 	}
274 
275 	if (SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPOL) {
276 		cpol = 1;
277 	}
278 	if (SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPHA) {
279 		cpha = 1;
280 	}
281 	if (SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_LOOP) {
282 		LOG_ERR("Loopback not supported");
283 		return -ENOTSUP;
284 	}
285 
286 #if SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED
287 	if (spi_cfg->operation & SPI_HALF_DUPLEX) {
288 		if ((cpol != 0) || (cpha != 0)) {
289 			LOG_ERR("Only mode (0, 0) supported in 3-wire SIO");
290 			return -ENOTSUP;
291 		}
292 
293 		if ((spi_cfg->frequency > spi_pico_pio_maximum_clock_frequency(
294 						  clock_freq, SPI_SIO_MODE_0_0_TX_CYCLES)) ||
295 		    (spi_cfg->frequency < spi_pico_pio_minimum_clock_frequency(
296 						  clock_freq, SPI_SIO_MODE_0_0_TX_CYCLES))) {
297 			LOG_ERR("clock-frequency out of range");
298 			return -EINVAL;
299 		}
300 	} else if (dev_cfg->sio_gpio.port) {
301 		LOG_ERR("SPI_HALF_DUPLEX operation needed for sio-gpios");
302 		return -EINVAL;
303 	}
304 #else
305 	if (spi_cfg->operation & SPI_HALF_DUPLEX) {
306 		LOG_ERR("No sio-gpios defined, half-duplex not enabled");
307 		return -EINVAL;
308 	}
309 #endif /* SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED */
310 
311 	clk = &dev_cfg->clk_gpio;
312 	data->pio = pio_rpi_pico_get_pio(dev_cfg->piodev);
313 	rc = pio_rpi_pico_allocate_sm(dev_cfg->piodev, &data->pio_sm);
314 	if (rc < 0) {
315 		return rc;
316 	}
317 
318 	if (dev_cfg->sio_gpio.port) {
319 #if SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED
320 		const struct gpio_dt_spec *sio = &dev_cfg->sio_gpio;
321 
322 		float clock_div = spi_pico_pio_clock_divisor(clock_freq, SPI_SIO_MODE_0_0_TX_CYCLES,
323 							     spi_cfg->frequency);
324 
325 		data->pio_tx_offset =
326 			pio_add_program(data->pio, RPI_PICO_PIO_GET_PROGRAM(spi_sio_mode_0_0_tx));
327 
328 		data->pio_rx_offset =
329 			pio_add_program(data->pio, RPI_PICO_PIO_GET_PROGRAM(spi_sio_mode_0_0_rx));
330 		data->pio_rx_wrap_target =
331 			data->pio_rx_offset + RPI_PICO_PIO_GET_WRAP_TARGET(spi_sio_mode_0_0_rx);
332 		data->pio_rx_wrap =
333 			data->pio_rx_offset + RPI_PICO_PIO_GET_WRAP(spi_sio_mode_0_0_rx);
334 
335 		sm_config = pio_get_default_sm_config();
336 
337 		sm_config_set_clkdiv(&sm_config, clock_div);
338 		sm_config_set_in_pins(&sm_config, sio->pin);
339 		sm_config_set_in_shift(&sm_config, lsb, true, data->bits);
340 		sm_config_set_out_pins(&sm_config, sio->pin, 1);
341 		sm_config_set_out_shift(&sm_config, lsb, false, data->bits);
342 		hw_set_bits(&data->pio->input_sync_bypass, 1u << sio->pin);
343 
344 		sm_config_set_sideset_pins(&sm_config, clk->pin);
345 		sm_config_set_sideset(&sm_config, 1, false, false);
346 		sm_config_set_wrap(
347 			&sm_config,
348 			data->pio_tx_offset + RPI_PICO_PIO_GET_WRAP_TARGET(spi_sio_mode_0_0_tx),
349 			data->pio_tx_offset + RPI_PICO_PIO_GET_WRAP(spi_sio_mode_0_0_tx));
350 
351 		pio_sm_set_pindirs_with_mask(data->pio, data->pio_sm,
352 					     (BIT(clk->pin) | BIT(sio->pin)),
353 					     (BIT(clk->pin) | BIT(sio->pin)));
354 		pio_sm_set_pins_with_mask(data->pio, data->pio_sm, 0,
355 					  BIT(clk->pin) | BIT(sio->pin));
356 		pio_gpio_init(data->pio, sio->pin);
357 		pio_gpio_init(data->pio, clk->pin);
358 
359 		pio_sm_init(data->pio, data->pio_sm, data->pio_tx_offset, &sm_config);
360 		pio_sm_set_enabled(data->pio, data->pio_sm, true);
361 #else
362 		LOG_ERR("SIO pin requires half-duplex support");
363 		return -EINVAL;
364 #endif /* SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED */
365 	} else {
366 		/* 4-wire mode */
367 		const struct gpio_dt_spec *miso = miso = &dev_cfg->miso_gpio;
368 		const struct gpio_dt_spec *mosi = &dev_cfg->mosi_gpio;
369 		const pio_program_t *program;
370 		uint32_t wrap_target;
371 		uint32_t wrap;
372 		int cycles;
373 
374 		if ((cpol == 0) && (cpha == 0)) {
375 			program = RPI_PICO_PIO_GET_PROGRAM(spi_mode_0_0);
376 			wrap_target = RPI_PICO_PIO_GET_WRAP_TARGET(spi_mode_0_0);
377 			wrap = RPI_PICO_PIO_GET_WRAP(spi_mode_0_0);
378 			cycles = SPI_MODE_0_0_CYCLES;
379 		} else if ((cpol == 1) && (cpha == 1)) {
380 			program = RPI_PICO_PIO_GET_PROGRAM(spi_mode_1_1);
381 			wrap_target = RPI_PICO_PIO_GET_WRAP_TARGET(spi_mode_1_1);
382 			wrap = RPI_PICO_PIO_GET_WRAP(spi_mode_1_1);
383 			cycles = SPI_MODE_1_1_CYCLES;
384 		} else if ((cpol == 0) && (cpha == 1)) {
385 			program = RPI_PICO_PIO_GET_PROGRAM(spi_mode_0_1);
386 			wrap_target = RPI_PICO_PIO_GET_WRAP_TARGET(spi_mode_0_1);
387 			wrap = RPI_PICO_PIO_GET_WRAP(spi_mode_0_1);
388 			cycles = SPI_MODE_0_1_CYCLES;
389 		} else {
390 			LOG_ERR("Not supported:  cpol=%d, cpha=%d", cpol, cpha);
391 			return -ENOTSUP;
392 		}
393 
394 		if ((spi_cfg->frequency >
395 		     spi_pico_pio_maximum_clock_frequency(clock_freq, cycles)) ||
396 		    (spi_cfg->frequency <
397 		     spi_pico_pio_minimum_clock_frequency(clock_freq, cycles))) {
398 			LOG_ERR("clock-frequency out of range");
399 			return -EINVAL;
400 		}
401 
402 		float clock_div =
403 			spi_pico_pio_clock_divisor(clock_freq, cycles, spi_cfg->frequency);
404 
405 		if (!pio_can_add_program(data->pio, program)) {
406 			return -EBUSY;
407 		}
408 
409 		data->pio_tx_offset = pio_add_program(data->pio, program);
410 		sm_config = pio_get_default_sm_config();
411 
412 		sm_config_set_clkdiv(&sm_config, clock_div);
413 		sm_config_set_in_pins(&sm_config, miso->pin);
414 		sm_config_set_in_shift(&sm_config, lsb, true, data->bits);
415 		sm_config_set_out_pins(&sm_config, mosi->pin, 1);
416 		sm_config_set_out_shift(&sm_config, lsb, true, data->bits);
417 		sm_config_set_sideset_pins(&sm_config, clk->pin);
418 		sm_config_set_sideset(&sm_config, 1, false, false);
419 		sm_config_set_wrap(&sm_config, data->pio_tx_offset + wrap_target,
420 				   data->pio_tx_offset + wrap);
421 
422 		pio_sm_set_consecutive_pindirs(data->pio, data->pio_sm, miso->pin, 1, false);
423 		pio_sm_set_pindirs_with_mask(data->pio, data->pio_sm,
424 					     (BIT(clk->pin) | BIT(mosi->pin)),
425 					     (BIT(clk->pin) | BIT(mosi->pin)));
426 		pio_sm_set_pins_with_mask(data->pio, data->pio_sm, (cpol << clk->pin),
427 					  BIT(clk->pin) | BIT(mosi->pin));
428 		pio_gpio_init(data->pio, mosi->pin);
429 		pio_gpio_init(data->pio, miso->pin);
430 		pio_gpio_init(data->pio, clk->pin);
431 
432 		pio_sm_init(data->pio, data->pio_sm, data->pio_tx_offset, &sm_config);
433 		pio_sm_set_enabled(data->pio, data->pio_sm, true);
434 	}
435 
436 	data->spi_ctx.config = spi_cfg;
437 
438 	return 0;
439 }
440 
spi_pico_pio_txrx_4_wire(const struct device * dev)441 static void spi_pico_pio_txrx_4_wire(const struct device *dev)
442 {
443 	struct spi_pico_pio_data *data = dev->data;
444 	const size_t chunk_len = spi_context_max_continuous_chunk(&data->spi_ctx);
445 	const uint8_t *txbuf = data->spi_ctx.tx_buf;
446 	uint8_t *rxbuf = data->spi_ctx.rx_buf;
447 	uint32_t txrx;
448 	size_t fifo_cnt = 0;
449 
450 	data->tx_count = 0;
451 	data->rx_count = 0;
452 
453 	pio_sm_clear_fifos(data->pio, data->pio_sm);
454 
455 	while (data->rx_count < chunk_len || data->tx_count < chunk_len) {
456 		/* Fill up fifo with available TX data */
457 		while ((!pio_sm_is_tx_fifo_full(data->pio, data->pio_sm)) &&
458 		       data->tx_count < chunk_len && fifo_cnt < PIO_FIFO_DEPTH) {
459 			/* Send 0 in the case of read only operation */
460 			txrx = 0;
461 
462 			switch (data->dfs) {
463 			case 4: {
464 				if (txbuf) {
465 					txrx = sys_get_be32(txbuf + (data->tx_count * 4));
466 				}
467 				spi_pico_pio_sm_put32(data->pio, data->pio_sm, txrx);
468 			} break;
469 
470 			case 2: {
471 				if (txbuf) {
472 					txrx = sys_get_be16(txbuf + (data->tx_count * 2));
473 				}
474 				spi_pico_pio_sm_put16(data->pio, data->pio_sm, txrx);
475 			} break;
476 
477 			case 1: {
478 				if (txbuf) {
479 					txrx = ((uint8_t *)txbuf)[data->tx_count];
480 				}
481 				spi_pico_pio_sm_put8(data->pio, data->pio_sm, txrx);
482 			} break;
483 
484 			default:
485 				LOG_ERR("Support fot %d bits not enabled", (data->dfs * 8));
486 				break;
487 			}
488 			data->tx_count++;
489 			fifo_cnt++;
490 		}
491 
492 		while ((!pio_sm_is_rx_fifo_empty(data->pio, data->pio_sm)) &&
493 		       data->rx_count < chunk_len && fifo_cnt > 0) {
494 			switch (data->dfs) {
495 			case 4: {
496 				txrx = spi_pico_pio_sm_get32(data->pio, data->pio_sm);
497 
498 				/* Discard received data if rx buffer not assigned */
499 				if (rxbuf) {
500 					sys_put_be32(txrx, rxbuf + (data->rx_count * 4));
501 				}
502 			} break;
503 
504 			case 2: {
505 				txrx = spi_pico_pio_sm_get16(data->pio, data->pio_sm);
506 
507 				/* Discard received data if rx buffer not assigned */
508 				if (rxbuf) {
509 					sys_put_be16(txrx, rxbuf + (data->rx_count * 2));
510 				}
511 			} break;
512 
513 			case 1: {
514 				txrx = spi_pico_pio_sm_get8(data->pio, data->pio_sm);
515 
516 				/* Discard received data if rx buffer not assigned */
517 				if (rxbuf) {
518 					((uint8_t *)rxbuf)[data->rx_count] = (uint8_t)txrx;
519 				}
520 			} break;
521 
522 			default:
523 				LOG_ERR("Support fot %d bits not enabled", (data->dfs * 8));
524 				break;
525 			}
526 			data->rx_count++;
527 			fifo_cnt--;
528 		}
529 	}
530 }
531 
spi_pico_pio_txrx_3_wire(const struct device * dev)532 static void spi_pico_pio_txrx_3_wire(const struct device *dev)
533 {
534 #if SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED
535 	struct spi_pico_pio_data *data = dev->data;
536 	const struct spi_pico_pio_config *dev_cfg = dev->config;
537 	const uint8_t *txbuf = data->spi_ctx.tx_buf;
538 	uint8_t *rxbuf = data->spi_ctx.rx_buf;
539 	uint32_t txrx;
540 	int sio_pin = dev_cfg->sio_gpio.pin;
541 	uint32_t tx_size = data->spi_ctx.tx_len; /* Number of WORDS to send */
542 	uint32_t rx_size = data->spi_ctx.rx_len; /* Number of WORDS to receive */
543 
544 	data->tx_count = 0;
545 	data->rx_count = 0;
546 
547 	if (txbuf) {
548 		pio_sm_set_enabled(data->pio, data->pio_sm, false);
549 		pio_sm_set_wrap(data->pio, data->pio_sm,
550 				data->pio_tx_offset +
551 					RPI_PICO_PIO_GET_WRAP_TARGET(spi_sio_mode_0_0_tx),
552 				data->pio_tx_offset + RPI_PICO_PIO_GET_WRAP(spi_sio_mode_0_0_tx));
553 		pio_sm_clear_fifos(data->pio, data->pio_sm);
554 		pio_sm_set_pindirs_with_mask(data->pio, data->pio_sm, BIT(sio_pin), BIT(sio_pin));
555 		pio_sm_restart(data->pio, data->pio_sm);
556 		pio_sm_clkdiv_restart(data->pio, data->pio_sm);
557 		pio_sm_exec(data->pio, data->pio_sm, pio_encode_jmp(data->pio_tx_offset));
558 		pio_sm_set_enabled(data->pio, data->pio_sm, true);
559 
560 		while (data->tx_count < tx_size) {
561 			/* Fill up fifo with available TX data */
562 			while ((!pio_sm_is_tx_fifo_full(data->pio, data->pio_sm)) &&
563 			       data->tx_count < tx_size) {
564 
565 				switch (data->dfs) {
566 				case 4: {
567 					txrx = sys_get_be32(txbuf + (data->tx_count * 4));
568 					spi_pico_pio_sm_put32(data->pio, data->pio_sm, txrx);
569 				} break;
570 
571 				case 2: {
572 					txrx = sys_get_be16(txbuf + (data->tx_count * 2));
573 					spi_pico_pio_sm_put16(data->pio, data->pio_sm, txrx);
574 				} break;
575 
576 				case 1: {
577 					txrx = ((uint8_t *)txbuf)[data->tx_count];
578 					spi_pico_pio_sm_put8(data->pio, data->pio_sm, txrx);
579 				} break;
580 
581 				default:
582 					LOG_ERR("Support fot %d bits not enabled", (data->dfs * 8));
583 					break;
584 				}
585 				data->tx_count++;
586 			}
587 		}
588 		/* Wait for the state machine to complete the cycle */
589 		/* before resetting the PIO for reading.            */
590 		while ((!pio_sm_is_tx_fifo_empty(data->pio, data->pio_sm)) ||
591 		       (!spi_pico_pio_sm_complete(data)))
592 			;
593 	}
594 
595 	if (rxbuf) {
596 		pio_sm_set_enabled(data->pio, data->pio_sm, false);
597 		pio_sm_set_wrap(data->pio, data->pio_sm, data->pio_rx_wrap_target,
598 				data->pio_rx_wrap);
599 		pio_sm_clear_fifos(data->pio, data->pio_sm);
600 		pio_sm_set_pindirs_with_mask(data->pio, data->pio_sm, 0, BIT(sio_pin));
601 		pio_sm_restart(data->pio, data->pio_sm);
602 		pio_sm_clkdiv_restart(data->pio, data->pio_sm);
603 		pio_sm_put(data->pio, data->pio_sm, (rx_size * data->bits) - 1);
604 		pio_sm_exec(data->pio, data->pio_sm, pio_encode_jmp(data->pio_rx_offset));
605 		pio_sm_set_enabled(data->pio, data->pio_sm, true);
606 
607 		while (data->rx_count < rx_size) {
608 			while ((!pio_sm_is_rx_fifo_empty(data->pio, data->pio_sm)) &&
609 			       data->rx_count < rx_size) {
610 
611 				switch (data->dfs) {
612 				case 4: {
613 					txrx = spi_pico_pio_sm_get32(data->pio, data->pio_sm);
614 					sys_put_be32(txrx, rxbuf + (data->rx_count * 4));
615 				} break;
616 
617 				case 2: {
618 					txrx = spi_pico_pio_sm_get16(data->pio, data->pio_sm);
619 					sys_put_be16(txrx, rxbuf + (data->rx_count * 2));
620 				} break;
621 
622 				case 1: {
623 					txrx = spi_pico_pio_sm_get8(data->pio, data->pio_sm);
624 					rxbuf[data->rx_count] = (uint8_t)txrx;
625 				} break;
626 
627 				default:
628 					LOG_ERR("Support fot %d bits not enabled", (data->dfs * 8));
629 					break;
630 				}
631 				data->rx_count++;
632 			}
633 		}
634 	}
635 #else
636 	LOG_ERR("SIO pin requires half-duplex support");
637 #endif /* SPI_RPI_PICO_PIO_HALF_DUPLEX_ENABLED */
638 }
639 
spi_pico_pio_txrx(const struct device * dev)640 static void spi_pico_pio_txrx(const struct device *dev)
641 {
642 	const struct spi_pico_pio_config *dev_cfg = dev->config;
643 
644 	/* 3-wire or 4-wire mode? */
645 	if (dev_cfg->sio_gpio.port) {
646 		spi_pico_pio_txrx_3_wire(dev);
647 	} else {
648 		spi_pico_pio_txrx_4_wire(dev);
649 	}
650 }
651 
spi_pico_pio_transceive_impl(const struct device * dev,const struct spi_config * spi_cfg,const struct spi_buf_set * tx_bufs,const struct spi_buf_set * rx_bufs,bool asynchronous,spi_callback_t cb,void * userdata)652 static int spi_pico_pio_transceive_impl(const struct device *dev, const struct spi_config *spi_cfg,
653 					const struct spi_buf_set *tx_bufs,
654 					const struct spi_buf_set *rx_bufs, bool asynchronous,
655 					spi_callback_t cb, void *userdata)
656 {
657 	const struct spi_pico_pio_config *dev_cfg = dev->config;
658 	struct spi_pico_pio_data *data = dev->data;
659 	struct spi_context *spi_ctx = &data->spi_ctx;
660 	int rc = 0;
661 
662 	spi_context_lock(spi_ctx, asynchronous, cb, userdata, spi_cfg);
663 
664 	rc = spi_pico_pio_configure(dev_cfg, data, spi_cfg);
665 	if (rc < 0) {
666 		goto error;
667 	}
668 
669 	spi_context_buffers_setup(spi_ctx, tx_bufs, rx_bufs, data->dfs);
670 	spi_context_cs_control(spi_ctx, true);
671 
672 	do {
673 		spi_pico_pio_txrx(dev);
674 		spi_context_update_tx(spi_ctx, 1, data->tx_count);
675 		spi_context_update_rx(spi_ctx, 1, data->rx_count);
676 	} while (spi_pico_pio_transfer_ongoing(data));
677 
678 	spi_context_cs_control(spi_ctx, false);
679 
680 error:
681 	spi_context_release(spi_ctx, rc);
682 
683 	return rc;
684 }
685 
spi_pico_pio_transceive(const struct device * dev,const struct spi_config * spi_cfg,const struct spi_buf_set * tx_bufs,const struct spi_buf_set * rx_bufs)686 static int spi_pico_pio_transceive(const struct device *dev, const struct spi_config *spi_cfg,
687 				   const struct spi_buf_set *tx_bufs,
688 				   const struct spi_buf_set *rx_bufs)
689 {
690 	return spi_pico_pio_transceive_impl(dev, spi_cfg, tx_bufs, rx_bufs, false, NULL, NULL);
691 }
692 
spi_pico_pio_release(const struct device * dev,const struct spi_config * spi_cfg)693 int spi_pico_pio_release(const struct device *dev, const struct spi_config *spi_cfg)
694 {
695 	struct spi_pico_pio_data *data = dev->data;
696 
697 	spi_context_unlock_unconditionally(&data->spi_ctx);
698 
699 	return 0;
700 }
701 
702 static DEVICE_API(spi, spi_pico_pio_api) = {
703 	.transceive = spi_pico_pio_transceive,
704 	.release = spi_pico_pio_release,
705 };
706 
config_gpio(const struct gpio_dt_spec * gpio,const char * tag,int mode)707 static int config_gpio(const struct gpio_dt_spec *gpio, const char *tag, int mode)
708 {
709 	int rc = 0;
710 
711 	if (!device_is_ready(gpio->port)) {
712 		LOG_ERR("GPIO port for %s pin is not ready", tag);
713 		return -ENODEV;
714 	}
715 
716 	rc = gpio_pin_configure_dt(gpio, mode);
717 	if (rc < 0) {
718 		LOG_ERR("Couldn't configure %s pin; (%d)", tag, rc);
719 		return rc;
720 	}
721 
722 	return 0;
723 }
724 
spi_pico_pio_init(const struct device * dev)725 int spi_pico_pio_init(const struct device *dev)
726 {
727 	const struct spi_pico_pio_config *dev_cfg = dev->config;
728 	struct spi_pico_pio_data *data = dev->data;
729 	int rc;
730 
731 	rc = pinctrl_apply_state(dev_cfg->pin_cfg, PINCTRL_STATE_DEFAULT);
732 	if (rc) {
733 		LOG_ERR("Failed to apply pinctrl state");
734 		return rc;
735 	}
736 
737 	rc = config_gpio(&dev_cfg->clk_gpio, "clk", GPIO_OUTPUT_ACTIVE);
738 	if (rc < 0) {
739 		return rc;
740 	}
741 
742 	if (dev_cfg->mosi_gpio.port != NULL) {
743 		rc = config_gpio(&dev_cfg->mosi_gpio, "mosi", GPIO_OUTPUT);
744 		if (rc < 0) {
745 			return rc;
746 		}
747 	}
748 
749 	if (dev_cfg->miso_gpio.port != NULL) {
750 		rc = config_gpio(&dev_cfg->miso_gpio, "miso", GPIO_INPUT);
751 		if (rc < 0) {
752 			return rc;
753 		}
754 	}
755 
756 	rc = spi_context_cs_configure_all(&data->spi_ctx);
757 	if (rc < 0) {
758 		LOG_ERR("Failed to configure CS pins: %d", rc);
759 		return rc;
760 	}
761 
762 	spi_context_unlock_unconditionally(&data->spi_ctx);
763 
764 	return 0;
765 }
766 
767 #define SPI_PICO_PIO_INIT(inst)                                                                    \
768 	PINCTRL_DT_INST_DEFINE(inst);                                                              \
769 	static struct spi_pico_pio_config spi_pico_pio_config_##inst = {                           \
770 		.piodev = DEVICE_DT_GET(DT_INST_PARENT(inst)),                                     \
771 		.pin_cfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst),                                   \
772 		.clk_gpio = GPIO_DT_SPEC_INST_GET(inst, clk_gpios),                                \
773 		.mosi_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, mosi_gpios, {0}),                      \
774 		.miso_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, miso_gpios, {0}),                      \
775 		.sio_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, sio_gpios, {0}),                        \
776 		.clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)),                               \
777 		.clk_id = (clock_control_subsys_t)DT_INST_PHA_BY_IDX(inst, clocks, 0, clk_id),     \
778 	};                                                                                         \
779 	static struct spi_pico_pio_data spi_pico_pio_data_##inst = {                               \
780 		SPI_CONTEXT_INIT_LOCK(spi_pico_pio_data_##inst, spi_ctx),                          \
781 		SPI_CONTEXT_INIT_SYNC(spi_pico_pio_data_##inst, spi_ctx),                          \
782 		SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(inst), spi_ctx)};                      \
783 	SPI_DEVICE_DT_INST_DEFINE(inst, spi_pico_pio_init, NULL, &spi_pico_pio_data_##inst,        \
784 			      &spi_pico_pio_config_##inst, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY,  \
785 			      &spi_pico_pio_api);                                                  \
786 	BUILD_ASSERT(DT_INST_NODE_HAS_PROP(inst, clk_gpios), "Missing clock GPIO");                \
787 	BUILD_ASSERT(((DT_INST_NODE_HAS_PROP(inst, mosi_gpios) ||                                  \
788 		       DT_INST_NODE_HAS_PROP(inst, miso_gpios)) &&                                 \
789 		      (!DT_INST_NODE_HAS_PROP(inst, sio_gpios))) ||                                \
790 			     (DT_INST_NODE_HAS_PROP(inst, sio_gpios) &&                            \
791 			      !(DT_INST_NODE_HAS_PROP(inst, mosi_gpios) ||                         \
792 				DT_INST_NODE_HAS_PROP(inst, miso_gpios))),                         \
793 		     "Invalid GPIO Configuration");
794 
795 DT_INST_FOREACH_STATUS_OKAY(SPI_PICO_PIO_INIT)
796