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