1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright (c) 2017, NXP
4  * Copyright (c) 2021, ATL Electronics.
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #define DT_DRV_COMPAT cypress_psoc6_spi
10 
11 #define LOG_LEVEL CONFIG_SPI_LOG_LEVEL
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(spi_psoc6);
14 
15 #include <errno.h>
16 #include <zephyr/drivers/pinctrl.h>
17 #include <zephyr/drivers/spi.h>
18 #include <zephyr/drivers/spi/rtio.h>
19 #include <soc.h>
20 
21 #include "spi_context.h"
22 
23 #include "cy_syslib.h"
24 #include "cy_sysclk.h"
25 #include "cy_scb_spi.h"
26 #include "cy_sysint.h"
27 
28 #define SPI_CHIP_SELECT_COUNT		4
29 #define SPI_MAX_DATA_WIDTH		16
30 #define SPI_PSOC6_CLK_DIV_NUMBER	1
31 
32 struct spi_psoc6_config {
33 	CySCB_Type *base;
34 	uint32_t periph_id;
35 	void (*irq_config_func)(const struct device *dev);
36 	const struct pinctrl_dev_config *pcfg;
37 };
38 
39 struct spi_psoc6_transfer {
40 	uint8_t *txData;
41 	uint8_t *rxData;
42 	size_t dataSize;
43 };
44 
45 struct spi_psoc6_data {
46 	struct spi_context ctx;
47 	struct cy_stc_scb_spi_config cfg;
48 	struct spi_psoc6_transfer xfer;
49 };
50 
spi_psoc6_transfer_next_packet(const struct device * dev)51 static void spi_psoc6_transfer_next_packet(const struct device *dev)
52 {
53 	const struct spi_psoc6_config *config = dev->config;
54 	struct spi_psoc6_data *data = dev->data;
55 	struct spi_context *ctx = &data->ctx;
56 	struct spi_psoc6_transfer *xfer = &data->xfer;
57 	uint32_t count;
58 
59 	LOG_DBG("TX L: %d, RX L: %d", ctx->tx_len, ctx->rx_len);
60 
61 	if ((ctx->tx_len == 0U) && (ctx->rx_len == 0U)) {
62 		/* nothing left to rx or tx, we're done! */
63 		xfer->dataSize = 0U;
64 
65 		spi_context_cs_control(ctx, false);
66 		spi_context_complete(ctx, dev, 0U);
67 		return;
68 	}
69 
70 	if (ctx->tx_len == 0U) {
71 		/* rx only, nothing to tx */
72 		xfer->txData = NULL;
73 		xfer->rxData = ctx->rx_buf;
74 		xfer->dataSize = ctx->rx_len;
75 	} else if (ctx->rx_len == 0U) {
76 		/* tx only, nothing to rx */
77 		xfer->txData = (uint8_t *) ctx->tx_buf;
78 		xfer->rxData = NULL;
79 		xfer->dataSize = ctx->tx_len;
80 	} else if (ctx->tx_len == ctx->rx_len) {
81 		/* rx and tx are the same length */
82 		xfer->txData = (uint8_t *) ctx->tx_buf;
83 		xfer->rxData = ctx->rx_buf;
84 		xfer->dataSize = ctx->tx_len;
85 	} else if (ctx->tx_len > ctx->rx_len) {
86 		/* Break up the tx into multiple transfers so we don't have to
87 		 * rx into a longer intermediate buffer. Leave chip select
88 		 * active between transfers.
89 		 */
90 		xfer->txData = (uint8_t *) ctx->tx_buf;
91 		xfer->rxData = ctx->rx_buf;
92 		xfer->dataSize = ctx->rx_len;
93 	} else {
94 		/* Break up the rx into multiple transfers so we don't have to
95 		 * tx from a longer intermediate buffer. Leave chip select
96 		 * active between transfers.
97 		 */
98 		xfer->txData = (uint8_t *) ctx->tx_buf;
99 		xfer->rxData = ctx->rx_buf;
100 		xfer->dataSize = ctx->tx_len;
101 	}
102 
103 	if (xfer->txData != NULL) {
104 		if (Cy_SCB_SPI_WriteArray(config->base, xfer->txData,
105 					  xfer->dataSize) != xfer->dataSize) {
106 			goto err;
107 		}
108 	} else {
109 		/* Need fill TX fifo with garbage to perform read.
110 		 * This keeps logic simple and saves stack.
111 		 * Use 0 as dummy data.
112 		 */
113 		for (count = 0U; count < xfer->dataSize; count++) {
114 			if (Cy_SCB_SPI_Write(config->base, 0U) == 0U) {
115 				goto err;
116 			}
117 		}
118 	}
119 
120 	LOG_DBG("TRX L: %d", xfer->dataSize);
121 
122 	return;
123 err:
124 	/* no FIFO available to run the transfer */
125 	xfer->dataSize = 0U;
126 
127 	spi_context_cs_control(ctx, false);
128 	spi_context_complete(ctx, dev, -ENOMEM);
129 }
130 
spi_psoc6_isr(const struct device * dev)131 static void spi_psoc6_isr(const struct device *dev)
132 {
133 	const struct spi_psoc6_config *config = dev->config;
134 	struct spi_psoc6_data *data = dev->data;
135 
136 	Cy_SCB_ClearMasterInterrupt(config->base,
137 				    CY_SCB_MASTER_INTR_SPI_DONE);
138 
139 	/* extract data from RX FIFO */
140 	if (data->xfer.rxData != NULL) {
141 		Cy_SCB_SPI_ReadArray(config->base,
142 				     data->xfer.rxData,
143 				     data->xfer.dataSize);
144 	} else {
145 		Cy_SCB_ClearRxFifo(config->base);
146 	}
147 
148 	/* Set next data block */
149 	spi_context_update_tx(&data->ctx, 1, data->xfer.dataSize);
150 	spi_context_update_rx(&data->ctx, 1, data->xfer.dataSize);
151 
152 	/* Start next block
153 	 * Since 1 byte at TX FIFO will start transfer data, let's try
154 	 * minimize ISR recursion disabling all interrupt sources when add
155 	 * data on TX FIFO
156 	 */
157 	Cy_SCB_SetMasterInterruptMask(config->base, 0U);
158 
159 	spi_psoc6_transfer_next_packet(dev);
160 
161 	if (data->xfer.dataSize > 0U) {
162 		Cy_SCB_SetMasterInterruptMask(config->base,
163 					      CY_SCB_MASTER_INTR_SPI_DONE);
164 	}
165 }
166 
spi_psoc6_get_freqdiv(uint32_t frequency)167 static uint32_t spi_psoc6_get_freqdiv(uint32_t frequency)
168 {
169 	uint32_t oversample;
170 	uint32_t bus_freq = 100000000UL;
171 	/*
172 	 * TODO: Get PerBusSpeed when clocks are available to PSOC 6.
173 	 * Currently the bus freq is fixed to 50Mhz and max SPI clk can be
174 	 * 12.5MHz.
175 	 */
176 
177 	for (oversample = 4; oversample < 16; oversample++) {
178 		if ((bus_freq / oversample) <= frequency) {
179 			break;
180 		}
181 	}
182 
183 	/* Oversample [4, 16] */
184 	return oversample;
185 }
186 
spi_psoc6_master_get_defaults(struct cy_stc_scb_spi_config * cfg)187 static void spi_psoc6_master_get_defaults(struct cy_stc_scb_spi_config *cfg)
188 {
189 	cfg->spiMode = CY_SCB_SPI_MASTER;
190 	cfg->subMode = CY_SCB_SPI_MOTOROLA;
191 	cfg->sclkMode = 0U;
192 	cfg->oversample = 0U;
193 	cfg->rxDataWidth = 0U;
194 	cfg->txDataWidth = 0U;
195 	cfg->enableMsbFirst = false;
196 	cfg->enableFreeRunSclk = false;
197 	cfg->enableInputFilter = false;
198 	cfg->enableMisoLateSample = false;
199 	cfg->enableTransferSeperation = false;
200 	cfg->ssPolarity = 0U;
201 	cfg->enableWakeFromSleep = false;
202 	cfg->rxFifoTriggerLevel = 0U;
203 	cfg->rxFifoIntEnableMask = 0U;
204 	cfg->txFifoTriggerLevel = 0U;
205 	cfg->txFifoIntEnableMask = 0U;
206 	cfg->masterSlaveIntEnableMask = 0U;
207 }
208 
spi_psoc6_configure(const struct device * dev,const struct spi_config * spi_cfg)209 static int spi_psoc6_configure(const struct device *dev,
210 			       const struct spi_config *spi_cfg)
211 {
212 	struct spi_psoc6_data *data = dev->data;
213 	uint32_t word_size;
214 
215 	if (spi_context_configured(&data->ctx, spi_cfg)) {
216 		/* This configuration is already in use */
217 		return 0;
218 	}
219 
220 	if (spi_cfg->operation & SPI_HALF_DUPLEX) {
221 		LOG_ERR("Half-duplex not supported");
222 		return -ENOTSUP;
223 	}
224 
225 	word_size = SPI_WORD_SIZE_GET(spi_cfg->operation);
226 	if (word_size > SPI_MAX_DATA_WIDTH) {
227 		LOG_ERR("Word size %d is greater than %d",
228 			word_size, SPI_MAX_DATA_WIDTH);
229 		return -EINVAL;
230 	}
231 
232 	if (SPI_OP_MODE_GET(spi_cfg->operation) == SPI_OP_MODE_MASTER) {
233 		spi_psoc6_master_get_defaults(&data->cfg);
234 
235 		if (spi_cfg->slave > SPI_CHIP_SELECT_COUNT) {
236 			LOG_ERR("Slave %d is greater than %d",
237 				spi_cfg->slave, SPI_CHIP_SELECT_COUNT);
238 			return -EINVAL;
239 		}
240 
241 		data->cfg.rxDataWidth = data->cfg.txDataWidth = word_size;
242 
243 		if (SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPHA) {
244 			if (SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPOL) {
245 				data->cfg.sclkMode = CY_SCB_SPI_CPHA1_CPOL1;
246 			} else {
247 				data->cfg.sclkMode = CY_SCB_SPI_CPHA1_CPOL0;
248 			}
249 		} else {
250 			if (SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPOL) {
251 				data->cfg.sclkMode = CY_SCB_SPI_CPHA0_CPOL1;
252 			} else {
253 				data->cfg.sclkMode = CY_SCB_SPI_CPHA0_CPOL0;
254 			}
255 		}
256 
257 		data->cfg.enableMsbFirst = !!!(spi_cfg->operation &
258 					       SPI_TRANSFER_LSB);
259 		data->cfg.oversample = spi_psoc6_get_freqdiv(spi_cfg->frequency);
260 
261 		data->ctx.config = spi_cfg;
262 	} else {
263 		/* Slave mode is not implemented yet. */
264 		return -ENOTSUP;
265 	}
266 
267 	return 0;
268 }
269 
spi_psoc6_transceive_sync_loop(const struct device * dev)270 static void spi_psoc6_transceive_sync_loop(const struct device *dev)
271 {
272 	const struct spi_psoc6_config *config = dev->config;
273 	struct spi_psoc6_data *data = dev->data;
274 
275 	while (data->xfer.dataSize > 0U) {
276 		while (!Cy_SCB_IsTxComplete(config->base)) {
277 			;
278 		}
279 
280 		if (data->xfer.rxData != NULL) {
281 			Cy_SCB_SPI_ReadArray(config->base,
282 					     data->xfer.rxData,
283 					     data->xfer.dataSize);
284 		} else {
285 			Cy_SCB_ClearRxFifo(config->base);
286 		}
287 
288 		spi_context_update_tx(&data->ctx, 1, data->xfer.dataSize);
289 		spi_context_update_rx(&data->ctx, 1, data->xfer.dataSize);
290 
291 		spi_psoc6_transfer_next_packet(dev);
292 	}
293 }
294 
spi_psoc6_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,bool asynchronous,spi_callback_t cb,void * userdata)295 static int spi_psoc6_transceive(const struct device *dev,
296 				const struct spi_config *spi_cfg,
297 				const struct spi_buf_set *tx_bufs,
298 				const struct spi_buf_set *rx_bufs,
299 				bool asynchronous,
300 				spi_callback_t cb,
301 				void *userdata)
302 {
303 	const struct spi_psoc6_config *config = dev->config;
304 	struct spi_psoc6_data *data = dev->data;
305 	int ret;
306 
307 	spi_context_lock(&data->ctx, asynchronous, cb, userdata, spi_cfg);
308 
309 	LOG_DBG("\n\n");
310 
311 	ret = spi_psoc6_configure(dev, spi_cfg);
312 	if (ret) {
313 		goto out;
314 	}
315 
316 	Cy_SCB_SPI_Init(config->base, &data->cfg, NULL);
317 	Cy_SCB_SPI_SetActiveSlaveSelect(config->base, spi_cfg->slave);
318 	Cy_SCB_SPI_Enable(config->base);
319 
320 	spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, 1);
321 
322 	spi_context_cs_control(&data->ctx, true);
323 
324 	spi_psoc6_transfer_next_packet(dev);
325 
326 	if (asynchronous) {
327 		Cy_SCB_SetMasterInterruptMask(config->base,
328 					      CY_SCB_MASTER_INTR_SPI_DONE);
329 	} else {
330 		spi_psoc6_transceive_sync_loop(dev);
331 	}
332 
333 	ret = spi_context_wait_for_completion(&data->ctx);
334 
335 	Cy_SCB_SPI_Disable(config->base, NULL);
336 
337 out:
338 	spi_context_release(&data->ctx, ret);
339 
340 	return ret;
341 }
342 
spi_psoc6_transceive_sync(const struct device * dev,const struct spi_config * spi_cfg,const struct spi_buf_set * tx_bufs,const struct spi_buf_set * rx_bufs)343 static int spi_psoc6_transceive_sync(const struct device *dev,
344 				     const struct spi_config *spi_cfg,
345 				     const struct spi_buf_set *tx_bufs,
346 				     const struct spi_buf_set *rx_bufs)
347 {
348 	return spi_psoc6_transceive(dev, spi_cfg, tx_bufs,
349 				    rx_bufs, false, NULL, NULL);
350 }
351 
352 #ifdef CONFIG_SPI_ASYNC
spi_psoc6_transceive_async(const struct device * dev,const struct spi_config * spi_cfg,const struct spi_buf_set * tx_bufs,const struct spi_buf_set * rx_bufs,spi_callback_t cb,void * userdata)353 static int spi_psoc6_transceive_async(const struct device *dev,
354 				      const struct spi_config *spi_cfg,
355 				      const struct spi_buf_set *tx_bufs,
356 				      const struct spi_buf_set *rx_bufs,
357 				      spi_callback_t cb,
358 				      void *userdata)
359 {
360 	return spi_psoc6_transceive(dev, spi_cfg, tx_bufs,
361 				    rx_bufs, true, cb, userdata);
362 }
363 #endif /* CONFIG_SPI_ASYNC */
364 
spi_psoc6_release(const struct device * dev,const struct spi_config * config)365 static int spi_psoc6_release(const struct device *dev,
366 			     const struct spi_config *config)
367 {
368 	struct spi_psoc6_data *data = dev->data;
369 
370 	spi_context_unlock_unconditionally(&data->ctx);
371 
372 	return 0;
373 }
374 
spi_psoc6_init(const struct device * dev)375 static int spi_psoc6_init(const struct device *dev)
376 {
377 	int err;
378 	const struct spi_psoc6_config *config = dev->config;
379 	struct spi_psoc6_data *data = dev->data;
380 
381 
382 	/* Configure dt provided device signals when available */
383 	err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
384 	if (err < 0) {
385 		return err;
386 	}
387 
388 	Cy_SysClk_PeriphAssignDivider(config->periph_id,
389 				      CY_SYSCLK_DIV_8_BIT,
390 				      SPI_PSOC6_CLK_DIV_NUMBER);
391 	Cy_SysClk_PeriphSetDivider(CY_SYSCLK_DIV_8_BIT,
392 				   SPI_PSOC6_CLK_DIV_NUMBER, 0U);
393 	Cy_SysClk_PeriphEnableDivider(CY_SYSCLK_DIV_8_BIT,
394 				      SPI_PSOC6_CLK_DIV_NUMBER);
395 
396 #ifdef CONFIG_SPI_ASYNC
397 	config->irq_config_func(dev);
398 #endif
399 
400 	err = spi_context_cs_configure_all(&data->ctx);
401 	if (err < 0) {
402 		return err;
403 	}
404 
405 	return spi_psoc6_release(dev, NULL);
406 }
407 
408 static DEVICE_API(spi, spi_psoc6_driver_api) = {
409 	.transceive = spi_psoc6_transceive_sync,
410 #ifdef CONFIG_SPI_ASYNC
411 	.transceive_async = spi_psoc6_transceive_async,
412 #endif
413 #ifdef CONFIG_SPI_RTIO
414 	.iodev_submit = spi_rtio_iodev_default_submit,
415 #endif
416 	.release = spi_psoc6_release,
417 };
418 
419 #define SPI_PSOC6_DEVICE_INIT(n)					\
420 	PINCTRL_DT_INST_DEFINE(n);					\
421 	static void spi_psoc6_spi##n##_irq_cfg(const struct device *port); \
422 	static const struct spi_psoc6_config spi_psoc6_config_##n = {	\
423 		.base = (CySCB_Type *)DT_INST_REG_ADDR(n),		\
424 		.periph_id = DT_INST_PROP(n, peripheral_id),		\
425 		.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),		\
426 		.irq_config_func = spi_psoc6_spi##n##_irq_cfg,		\
427 	};								\
428 	static struct spi_psoc6_data spi_psoc6_dev_data_##n = {		\
429 		SPI_CONTEXT_INIT_LOCK(spi_psoc6_dev_data_##n, ctx),	\
430 		SPI_CONTEXT_INIT_SYNC(spi_psoc6_dev_data_##n, ctx),	\
431 		SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx)	\
432 	};								\
433 	SPI_DEVICE_DT_INST_DEFINE(n, spi_psoc6_init, NULL,		\
434 			      &spi_psoc6_dev_data_##n,			\
435 			      &spi_psoc6_config_##n, POST_KERNEL,	\
436 			      CONFIG_SPI_INIT_PRIORITY,			\
437 			      &spi_psoc6_driver_api);			\
438 	static void spi_psoc6_spi##n##_irq_cfg(const struct device *port) \
439 	{								\
440 		CY_PSOC6_DT_INST_NVIC_INSTALL(n,			\
441 					      spi_psoc6_isr);		\
442 	};
443 
444 DT_INST_FOREACH_STATUS_OKAY(SPI_PSOC6_DEVICE_INIT)
445