1 /*
2  * Copyright (c) 2024, STRIM, ALC
3  * Copyright 2024 NXP
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #define DT_DRV_COMPAT nxp_flexio_spi
9 
10 #include <errno.h>
11 #include <zephyr/drivers/spi.h>
12 #include <zephyr/drivers/spi/rtio.h>
13 #include <zephyr/drivers/clock_control.h>
14 #include <fsl_flexio_spi.h>
15 #include <zephyr/logging/log.h>
16 #include <zephyr/drivers/pinctrl.h>
17 #include <zephyr/drivers/misc/nxp_flexio/nxp_flexio.h>
18 
19 LOG_MODULE_REGISTER(spi_mcux_flexio_spi, CONFIG_SPI_LOG_LEVEL);
20 
21 #include "spi_context.h"
22 
23 
24 struct spi_mcux_flexio_config {
25 	FLEXIO_SPI_Type *flexio_spi;
26 	const struct device *flexio_dev;
27 	const struct pinctrl_dev_config *pincfg;
28 	const struct nxp_flexio_child *child;
29 };
30 
31 struct spi_mcux_flexio_data {
32 	const struct device *dev;
33 	flexio_spi_master_handle_t handle;
34 	struct spi_context ctx;
35 	size_t transfer_len;
36 	uint8_t transfer_flags;
37 };
38 
39 
spi_mcux_transfer_next_packet(const struct device * dev)40 static void spi_mcux_transfer_next_packet(const struct device *dev)
41 {
42 	const struct spi_mcux_flexio_config *config = dev->config;
43 	struct spi_mcux_flexio_data *data = dev->data;
44 	struct spi_context *ctx = &data->ctx;
45 	flexio_spi_transfer_t transfer;
46 	status_t status;
47 
48 	if ((ctx->tx_len == 0) && (ctx->rx_len == 0)) {
49 		/* nothing left to rx or tx, we're done! */
50 		spi_context_cs_control(&data->ctx, false);
51 		spi_context_complete(&data->ctx, dev, 0);
52 		return;
53 	}
54 
55 	transfer.flags = kFLEXIO_SPI_csContinuous | data->transfer_flags;
56 
57 	if (ctx->tx_len == 0) {
58 		/* rx only, nothing to tx */
59 		transfer.txData = NULL;
60 		transfer.rxData = ctx->rx_buf;
61 		transfer.dataSize = ctx->rx_len;
62 	} else if (ctx->rx_len == 0) {
63 		/* tx only, nothing to rx */
64 		transfer.txData = (uint8_t *) ctx->tx_buf;
65 		transfer.rxData = NULL;
66 		transfer.dataSize = ctx->tx_len;
67 	} else if (ctx->tx_len == ctx->rx_len) {
68 		/* rx and tx are the same length */
69 		transfer.txData = (uint8_t *) ctx->tx_buf;
70 		transfer.rxData = ctx->rx_buf;
71 		transfer.dataSize = ctx->tx_len;
72 	} else if (ctx->tx_len > ctx->rx_len) {
73 		/* Break up the tx into multiple transfers so we don't have to
74 		 * rx into a longer intermediate buffer. Leave chip select
75 		 * active between transfers.
76 		 */
77 		transfer.txData = (uint8_t *) ctx->tx_buf;
78 		transfer.rxData = ctx->rx_buf;
79 		transfer.dataSize = ctx->rx_len;
80 	} else {
81 		/* Break up the rx into multiple transfers so we don't have to
82 		 * tx from a longer intermediate buffer. Leave chip select
83 		 * active between transfers.
84 		 */
85 		transfer.txData = (uint8_t *) ctx->tx_buf;
86 		transfer.rxData = ctx->rx_buf;
87 		transfer.dataSize = ctx->tx_len;
88 	}
89 
90 	data->transfer_len = transfer.dataSize;
91 
92 	status = FLEXIO_SPI_MasterTransferNonBlocking(config->flexio_spi, &data->handle,
93 						 &transfer);
94 	if (status != kStatus_Success) {
95 		LOG_ERR("Transfer could not start");
96 	}
97 }
98 
spi_mcux_flexio_isr(void * user_data)99 static int spi_mcux_flexio_isr(void *user_data)
100 {
101 	const struct device *dev = (const struct device *)user_data;
102 	const struct spi_mcux_flexio_config *config = dev->config;
103 	struct spi_mcux_flexio_data *data = dev->data;
104 
105 #if defined(CONFIG_SOC_SERIES_KE1XZ)
106 	/* Wait until data transfer complete. */
107 	WAIT_FOR((0U == (FLEXIO_SPI_GetStatusFlags(config->flexio_spi)
108 		& (uint32_t)kFLEXIO_SPI_TxBufferEmptyFlag)), 100, NULL);
109 #endif
110 	FLEXIO_SPI_MasterTransferHandleIRQ(config->flexio_spi, &data->handle);
111 
112 	return 0;
113 }
114 
spi_mcux_master_transfer_callback(FLEXIO_SPI_Type * flexio_spi,flexio_spi_master_handle_t * handle,status_t status,void * userData)115 static void spi_mcux_master_transfer_callback(FLEXIO_SPI_Type *flexio_spi,
116 	flexio_spi_master_handle_t *handle, status_t status, void *userData)
117 {
118 	struct spi_mcux_flexio_data *data = userData;
119 
120 	spi_context_update_tx(&data->ctx, 1, data->transfer_len);
121 	spi_context_update_rx(&data->ctx, 1, data->transfer_len);
122 
123 	spi_mcux_transfer_next_packet(data->dev);
124 }
125 
spi_flexio_master_init(FLEXIO_SPI_Type * base,flexio_spi_master_config_t * masterConfig,uint8_t pol,uint32_t srcClock_Hz)126 static void spi_flexio_master_init(FLEXIO_SPI_Type *base, flexio_spi_master_config_t *masterConfig,
127 	uint8_t pol, uint32_t srcClock_Hz)
128 {
129 	assert(base != NULL);
130 	assert(masterConfig != NULL);
131 
132 	flexio_shifter_config_t shifterConfig;
133 	flexio_timer_config_t timerConfig;
134 	uint32_t ctrlReg  = 0;
135 	uint16_t timerDiv = 0;
136 	uint16_t timerCmp = 0;
137 
138 	/* Clear the shifterConfig & timerConfig struct. */
139 	(void)memset(&shifterConfig, 0, sizeof(shifterConfig));
140 	(void)memset(&timerConfig, 0, sizeof(timerConfig));
141 
142 	/* Configure FLEXIO SPI Master */
143 	ctrlReg = base->flexioBase->CTRL;
144 	ctrlReg &= ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK |
145 			FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK);
146 	ctrlReg |= (FLEXIO_CTRL_DBGE(masterConfig->enableInDebug) |
147 		FLEXIO_CTRL_FASTACC(masterConfig->enableFastAccess) |
148 		FLEXIO_CTRL_FLEXEN(masterConfig->enableMaster));
149 	if (!masterConfig->enableInDoze) {
150 		ctrlReg |= FLEXIO_CTRL_DOZEN_MASK;
151 	}
152 
153 	base->flexioBase->CTRL = ctrlReg;
154 
155 	/* Do hardware configuration. */
156 	/* 1. Configure the shifter 0 for tx. */
157 	shifterConfig.timerSelect = base->timerIndex[0];
158 	shifterConfig.pinConfig   = kFLEXIO_PinConfigOutput;
159 	shifterConfig.pinSelect   = base->SDOPinIndex;
160 	shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh;
161 	shifterConfig.shifterMode = kFLEXIO_ShifterModeTransmit;
162 	shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
163 	if (masterConfig->phase == kFLEXIO_SPI_ClockPhaseFirstEdge) {
164 		shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
165 		shifterConfig.shifterStop   = kFLEXIO_ShifterStopBitDisable;
166 		shifterConfig.shifterStart  = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
167 	} else {
168 		shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
169 		shifterConfig.shifterStop   = kFLEXIO_ShifterStopBitLow;
170 		shifterConfig.shifterStart  = kFLEXIO_ShifterStartBitDisabledLoadDataOnShift;
171 	}
172 
173 	FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[0], &shifterConfig);
174 
175 	/* 2. Configure the shifter 1 for rx. */
176 	shifterConfig.timerSelect  = base->timerIndex[0];
177 	shifterConfig.pinConfig    = kFLEXIO_PinConfigOutputDisabled;
178 	shifterConfig.pinSelect    = base->SDIPinIndex;
179 	shifterConfig.pinPolarity  = kFLEXIO_PinActiveHigh;
180 	shifterConfig.shifterMode  = kFLEXIO_ShifterModeReceive;
181 	shifterConfig.inputSource  = kFLEXIO_ShifterInputFromPin;
182 	shifterConfig.shifterStop  = kFLEXIO_ShifterStopBitDisable;
183 	shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
184 	if (masterConfig->phase == kFLEXIO_SPI_ClockPhaseFirstEdge) {
185 		shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
186 	} else {
187 		shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
188 	}
189 
190 	FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[1], &shifterConfig);
191 
192 	/*3. Configure the timer 0 for SCK. */
193 	timerConfig.triggerSelect   = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->shifterIndex[0]);
194 	timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
195 	timerConfig.triggerSource   = kFLEXIO_TimerTriggerSourceInternal;
196 	timerConfig.pinConfig       = kFLEXIO_PinConfigOutput;
197 	timerConfig.pinSelect       = base->SCKPinIndex;
198 	timerConfig.pinPolarity     = pol ? kFLEXIO_PinActiveLow : kFLEXIO_PinActiveHigh;
199 	timerConfig.timerMode       = kFLEXIO_TimerModeDual8BitBaudBit;
200 	timerConfig.timerOutput     = kFLEXIO_TimerOutputZeroNotAffectedByReset;
201 	timerConfig.timerDecrement  = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
202 	timerConfig.timerReset      = kFLEXIO_TimerResetNever;
203 	timerConfig.timerDisable    = kFLEXIO_TimerDisableOnTimerCompare;
204 	timerConfig.timerEnable     = kFLEXIO_TimerEnableOnTriggerHigh;
205 	timerConfig.timerStop       = kFLEXIO_TimerStopBitEnableOnTimerDisable;
206 	timerConfig.timerStart      = kFLEXIO_TimerStartBitEnabled;
207 	/* Low 8-bits are used to configure baudrate. */
208 	timerDiv = (uint16_t)(srcClock_Hz / masterConfig->baudRate_Bps);
209 	timerDiv = timerDiv / 2U - 1U;
210 	/* High 8-bits are used to configure shift clock edges(transfer width). */
211 	timerCmp = ((uint16_t)masterConfig->dataMode * 2U - 1U) << 8U;
212 	timerCmp |= timerDiv;
213 
214 	timerConfig.timerCompare = timerCmp;
215 
216 	FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[0], &timerConfig);
217 }
218 
spi_mcux_flexio_configure(const struct device * dev,const struct spi_config * spi_cfg)219 static int spi_mcux_flexio_configure(const struct device *dev,
220 	const struct spi_config *spi_cfg)
221 {
222 	const struct spi_mcux_flexio_config *config = dev->config;
223 	struct spi_mcux_flexio_data *data = dev->data;
224 
225 	flexio_spi_master_config_t master_config;
226 	uint32_t clock_freq;
227 	uint32_t word_size;
228 
229 	if (spi_context_configured(&data->ctx, spi_cfg)) {
230 		/* This configuration is already in use */
231 		return 0;
232 	}
233 
234 	if (spi_cfg->operation & SPI_HALF_DUPLEX) {
235 		LOG_ERR("Half-duplex not supported");
236 		return -ENOTSUP;
237 	}
238 
239 	if (SPI_OP_MODE_GET(spi_cfg->operation) != SPI_OP_MODE_MASTER) {
240 		LOG_ERR("Mode Slave not supported");
241 		return -ENOTSUP;
242 	}
243 
244 	FLEXIO_SPI_MasterGetDefaultConfig(&master_config);
245 
246 	word_size = SPI_WORD_SIZE_GET(spi_cfg->operation);
247 	if ((word_size != 8) && (word_size != 16) && (word_size != 32)) {
248 		LOG_ERR("Word size %d must be 8, 16 or 32", word_size);
249 		return -EINVAL;
250 	}
251 	master_config.dataMode = word_size;
252 
253 	if (spi_cfg->operation & SPI_TRANSFER_LSB) {
254 		if (word_size == 8) {
255 			data->transfer_flags = kFLEXIO_SPI_8bitLsb;
256 		} else if (word_size == 16) {
257 			data->transfer_flags = kFLEXIO_SPI_16bitLsb;
258 		} else {
259 			data->transfer_flags = kFLEXIO_SPI_32bitLsb;
260 		}
261 	} else {
262 		if (word_size == 8) {
263 			data->transfer_flags = kFLEXIO_SPI_8bitMsb;
264 		} else if (word_size == 16) {
265 			data->transfer_flags = kFLEXIO_SPI_16bitMsb;
266 		} else {
267 			data->transfer_flags = kFLEXIO_SPI_32bitMsb;
268 		}
269 	}
270 
271 	if (nxp_flexio_get_rate(config->flexio_dev, &clock_freq)) {
272 		return -EINVAL;
273 	}
274 
275 	master_config.phase =
276 		(SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPHA)
277 		? kFLEXIO_SPI_ClockPhaseSecondEdge
278 		: kFLEXIO_SPI_ClockPhaseFirstEdge;
279 
280 	master_config.baudRate_Bps = spi_cfg->frequency;
281 	spi_flexio_master_init(config->flexio_spi, &master_config,
282 		(SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPOL), clock_freq);
283 
284 	FLEXIO_SPI_MasterTransferCreateHandle(config->flexio_spi, &data->handle,
285 					spi_mcux_master_transfer_callback,
286 					data);
287 	/* No SetDummyData() for FlexIO_SPI */
288 
289 	data->ctx.config = spi_cfg;
290 
291 	return 0;
292 }
293 
294 
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 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_mcux_flexio_config *config = dev->config;
304 	struct spi_mcux_flexio_data *data = dev->data;
305 	int ret;
306 
307 	spi_context_lock(&data->ctx, asynchronous, cb, userdata, spi_cfg);
308 
309 	nxp_flexio_lock(config->flexio_dev);
310 	ret = spi_mcux_flexio_configure(dev, spi_cfg);
311 	nxp_flexio_unlock(config->flexio_dev);
312 	if (ret) {
313 		goto out;
314 	}
315 
316 	spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, 1);
317 
318 	spi_context_cs_control(&data->ctx, true);
319 
320 	nxp_flexio_lock(config->flexio_dev);
321 	nxp_flexio_irq_disable(config->flexio_dev);
322 
323 	spi_mcux_transfer_next_packet(dev);
324 
325 	nxp_flexio_irq_enable(config->flexio_dev);
326 	nxp_flexio_unlock(config->flexio_dev);
327 
328 	ret = spi_context_wait_for_completion(&data->ctx);
329 out:
330 	spi_context_release(&data->ctx, ret);
331 
332 	return ret;
333 }
334 
spi_mcux_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)335 static int spi_mcux_transceive(const struct device *dev,
336 				const struct spi_config *spi_cfg,
337 				const struct spi_buf_set *tx_bufs,
338 				const struct spi_buf_set *rx_bufs)
339 {
340 	return transceive(dev, spi_cfg, tx_bufs, rx_bufs, false, NULL, NULL);
341 }
342 
343 #ifdef CONFIG_SPI_ASYNC
spi_mcux_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)344 static int spi_mcux_transceive_async(const struct device *dev,
345 				const struct spi_config *spi_cfg,
346 				const struct spi_buf_set *tx_bufs,
347 				const struct spi_buf_set *rx_bufs,
348 				spi_callback_t cb,
349 				void *userdata)
350 {
351 	return transceive(dev, spi_cfg, tx_bufs, rx_bufs, true, cb, userdata);
352 }
353 #endif /* CONFIG_SPI_ASYNC */
354 
spi_mcux_release(const struct device * dev,const struct spi_config * spi_cfg)355 static int spi_mcux_release(const struct device *dev,
356 				const struct spi_config *spi_cfg)
357 {
358 	struct spi_mcux_flexio_data *data = dev->data;
359 
360 	spi_context_unlock_unconditionally(&data->ctx);
361 
362 	return 0;
363 }
364 
spi_mcux_init(const struct device * dev)365 static int spi_mcux_init(const struct device *dev)
366 {
367 	const struct spi_mcux_flexio_config *config = dev->config;
368 	struct spi_mcux_flexio_data *data = dev->data;
369 	int err;
370 
371 	err = nxp_flexio_child_attach(config->flexio_dev, config->child);
372 	if (err < 0) {
373 		return err;
374 	}
375 
376 	err = spi_context_cs_configure_all(&data->ctx);
377 	if (err < 0) {
378 		return err;
379 	}
380 
381 	spi_context_unlock_unconditionally(&data->ctx);
382 
383 	data->dev = dev;
384 
385 	/* TODO: DMA */
386 
387 	err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
388 	if (err) {
389 		return err;
390 	}
391 
392 	spi_context_unlock_unconditionally(&data->ctx);
393 
394 	return 0;
395 }
396 
397 static DEVICE_API(spi, spi_mcux_driver_api) = {
398 	.transceive = spi_mcux_transceive,
399 #ifdef CONFIG_SPI_ASYNC
400 	.transceive_async = spi_mcux_transceive_async,
401 #endif
402 #ifdef CONFIG_SPI_RTIO
403 	.iodev_submit = spi_rtio_iodev_default_submit,
404 #endif
405 	.release = spi_mcux_release,
406 };
407 
408 #define SPI_MCUX_FLEXIO_SPI_INIT(n)					\
409 	PINCTRL_DT_INST_DEFINE(n);					\
410 									\
411 	static FLEXIO_SPI_Type flexio_spi_##n = {			\
412 		.flexioBase = (FLEXIO_Type *)DT_REG_ADDR(DT_INST_PARENT(n)), \
413 		.SDOPinIndex = DT_INST_PROP(n, sdo_pin),		\
414 		.SDIPinIndex = DT_INST_PROP(n, sdi_pin),		\
415 		.SCKPinIndex = DT_INST_PROP(n, sck_pin),		\
416 	};								\
417 									\
418 	static const struct nxp_flexio_child nxp_flexio_spi_child_##n = { \
419 		.isr = spi_mcux_flexio_isr,				\
420 		.user_data = (void *)DEVICE_DT_INST_GET(n),		\
421 		.res = {						\
422 			.shifter_index = flexio_spi_##n.shifterIndex,	\
423 			.shifter_count = ARRAY_SIZE(flexio_spi_##n.shifterIndex), \
424 			.timer_index = flexio_spi_##n.timerIndex,	\
425 			.timer_count = ARRAY_SIZE(flexio_spi_##n.timerIndex) \
426 		}							\
427 	};								\
428 									\
429 	static const struct spi_mcux_flexio_config spi_mcux_flexio_config_##n = { \
430 		.flexio_spi = &flexio_spi_##n,				\
431 		.flexio_dev = DEVICE_DT_GET(DT_INST_PARENT(n)),		\
432 		.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),		\
433 		.child = &nxp_flexio_spi_child_##n,			\
434 	};								\
435 									\
436 	static struct spi_mcux_flexio_data spi_mcux_flexio_data_##n = {	\
437 		SPI_CONTEXT_INIT_LOCK(spi_mcux_flexio_data_##n, ctx),	\
438 		SPI_CONTEXT_INIT_SYNC(spi_mcux_flexio_data_##n, ctx),	\
439 		SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx)	\
440 	};								\
441 									\
442 	SPI_DEVICE_DT_INST_DEFINE(n, spi_mcux_init, NULL,		\
443 				&spi_mcux_flexio_data_##n,		\
444 				&spi_mcux_flexio_config_##n, POST_KERNEL, \
445 				CONFIG_SPI_INIT_PRIORITY,		\
446 				&spi_mcux_driver_api);			\
447 
448 DT_INST_FOREACH_STATUS_OKAY(SPI_MCUX_FLEXIO_SPI_INIT)
449