Lines Matching +full:spi +full:- +full:dev
6 * SPDX-License-Identifier: Apache-2.0
11 /* spi_dw.c - Designware SPI driver implementation */
33 #include <zephyr/drivers/spi.h>
34 #include <zephyr/drivers/spi/rtio.h>
44 static inline bool spi_dw_is_slave(struct spi_dw_data *spi) in spi_dw_is_slave() argument
47 spi_context_is_slave(&spi->ctx)); in spi_dw_is_slave()
50 static void completed(const struct device *dev, int error) in completed() argument
52 struct spi_dw_data *spi = dev->data; in completed() local
53 struct spi_context *ctx = &spi->ctx; in completed()
59 if (spi_context_tx_on(&spi->ctx) || in completed()
60 spi_context_rx_on(&spi->ctx)) { in completed()
66 while (test_bit_sr_busy(dev)) { in completed()
70 write_imr(dev, DW_SPI_IMR_MASK); in completed()
72 clear_bit_ssienr(dev); in completed()
74 if (!spi_dw_is_slave(spi)) { in completed()
75 if (spi_cs_is_gpio(ctx->config)) { in completed()
78 write_ser(dev, 0); in completed()
82 LOG_DBG("SPI transaction completed %s error", in completed()
85 spi_context_complete(&spi->ctx, dev, error); in completed()
88 static void push_data(const struct device *dev) in push_data() argument
90 const struct spi_dw_config *info = dev->config; in push_data()
91 struct spi_dw_data *spi = dev->data; in push_data() local
95 if (spi_context_rx_on(&spi->ctx)) { in push_data()
96 f_tx = info->fifo_depth - read_txflr(dev) - in push_data()
97 read_rxflr(dev); in push_data()
99 f_tx = 0U; /* if rx-fifo is full, hold off tx */ in push_data()
102 f_tx = info->fifo_depth - read_txflr(dev); in push_data()
106 if (spi_context_tx_buf_on(&spi->ctx)) { in push_data()
107 switch (spi->dfs) { in push_data()
110 (spi->ctx.tx_buf)); in push_data()
114 (spi->ctx.tx_buf)); in push_data()
118 (spi->ctx.tx_buf)); in push_data()
121 } else if (spi_context_rx_on(&spi->ctx)) { in push_data()
123 if ((int)(spi->ctx.rx_len - spi->fifo_diff) <= 0) { in push_data()
128 } else if (spi_context_tx_on(&spi->ctx)) { in push_data()
135 write_dr(dev, data); in push_data()
137 spi_context_update_tx(&spi->ctx, spi->dfs, 1); in push_data()
138 spi->fifo_diff++; in push_data()
140 f_tx--; in push_data()
143 if (!spi_context_tx_on(&spi->ctx)) { in push_data()
145 write_txftlr(dev, 0); in push_data()
149 static void pull_data(const struct device *dev) in pull_data() argument
151 const struct spi_dw_config *info = dev->config; in pull_data()
152 struct spi_dw_data *spi = dev->data; in pull_data() local
154 while (read_rxflr(dev)) { in pull_data()
155 uint32_t data = read_dr(dev); in pull_data()
157 if (spi_context_rx_buf_on(&spi->ctx)) { in pull_data()
158 switch (spi->dfs) { in pull_data()
160 UNALIGNED_PUT(data, (uint8_t *)spi->ctx.rx_buf); in pull_data()
163 UNALIGNED_PUT(data, (uint16_t *)spi->ctx.rx_buf); in pull_data()
166 UNALIGNED_PUT(data, (uint32_t *)spi->ctx.rx_buf); in pull_data()
171 spi_context_update_rx(&spi->ctx, spi->dfs, 1); in pull_data()
172 spi->fifo_diff--; in pull_data()
175 if (!spi->ctx.rx_len && spi->ctx.tx_len < info->fifo_depth) { in pull_data()
176 write_rxftlr(dev, spi->ctx.tx_len - 1); in pull_data()
177 } else if (read_rxftlr(dev) >= spi->ctx.rx_len) { in pull_data()
178 write_rxftlr(dev, spi->ctx.rx_len - 1); in pull_data()
182 static int spi_dw_configure(const struct device *dev, in spi_dw_configure() argument
183 struct spi_dw_data *spi, in spi_dw_configure() argument
186 const struct spi_dw_config *info = dev->config; in spi_dw_configure()
189 LOG_DBG("%p (prev %p)", config, spi->ctx.config); in spi_dw_configure()
191 if (spi_context_configured(&spi->ctx, config)) { in spi_dw_configure()
196 if (config->operation & SPI_HALF_DUPLEX) { in spi_dw_configure()
197 LOG_ERR("Half-duplex not supported"); in spi_dw_configure()
198 return -ENOTSUP; in spi_dw_configure()
202 if (config->operation & SPI_OP_MODE_SLAVE) { in spi_dw_configure()
203 if (!(info->serial_target)) { in spi_dw_configure()
205 return -ENOTSUP; in spi_dw_configure()
208 if (info->serial_target) { in spi_dw_configure()
210 return -ENOTSUP; in spi_dw_configure()
214 if ((config->operation & SPI_TRANSFER_LSB) || in spi_dw_configure()
216 (config->operation & (SPI_LINES_DUAL | in spi_dw_configure()
219 return -EINVAL; in spi_dw_configure()
222 if (info->max_xfer_size < SPI_WORD_SIZE_GET(config->operation)) { in spi_dw_configure()
224 info->max_xfer_size, SPI_WORD_SIZE_GET(config->operation)); in spi_dw_configure()
225 return -ENOTSUP; in spi_dw_configure()
229 if (info->max_xfer_size == 32) { in spi_dw_configure()
230 ctrlr0 |= DW_SPI_CTRLR0_DFS_32(SPI_WORD_SIZE_GET(config->operation)); in spi_dw_configure()
232 ctrlr0 |= DW_SPI_CTRLR0_DFS_16(SPI_WORD_SIZE_GET(config->operation)); in spi_dw_configure()
235 /* Determine how many bytes are required per-frame */ in spi_dw_configure()
236 spi->dfs = SPI_WS_TO_DFS(SPI_WORD_SIZE_GET(config->operation)); in spi_dw_configure()
238 /* SPI mode */ in spi_dw_configure()
239 if (SPI_MODE_GET(config->operation) & SPI_MODE_CPOL) { in spi_dw_configure()
243 if (SPI_MODE_GET(config->operation) & SPI_MODE_CPHA) { in spi_dw_configure()
247 if (SPI_MODE_GET(config->operation) & SPI_MODE_LOOP) { in spi_dw_configure()
252 write_ctrlr0(dev, ctrlr0); in spi_dw_configure()
255 spi->ctx.config = config; in spi_dw_configure()
257 if (!spi_dw_is_slave(spi)) { in spi_dw_configure()
259 write_baudr(dev, SPI_DW_CLK_DIVIDER(info->clock_frequency, in spi_dw_configure()
260 config->frequency)); in spi_dw_configure()
263 if (spi_dw_is_slave(spi)) { in spi_dw_configure()
267 SPI_WORD_SIZE_GET(config->operation), spi->dfs, in spi_dw_configure()
268 (SPI_MODE_GET(config->operation) & in spi_dw_configure()
270 (SPI_MODE_GET(config->operation) & in spi_dw_configure()
272 (SPI_MODE_GET(config->operation) & in spi_dw_configure()
277 config, config->frequency, in spi_dw_configure()
278 SPI_DW_CLK_DIVIDER(info->clock_frequency, in spi_dw_configure()
279 config->frequency), in spi_dw_configure()
280 SPI_WORD_SIZE_GET(config->operation), spi->dfs, in spi_dw_configure()
281 (SPI_MODE_GET(config->operation) & in spi_dw_configure()
283 (SPI_MODE_GET(config->operation) & in spi_dw_configure()
285 (SPI_MODE_GET(config->operation) & in spi_dw_configure()
287 config->slave); in spi_dw_configure()
298 for (; rx_count; rx_bufs++, rx_count--) { in spi_dw_compute_ndf()
299 if (len > (UINT16_MAX - rx_bufs->len)) { in spi_dw_compute_ndf()
303 len += rx_bufs->len; in spi_dw_compute_ndf()
307 return (len / dfs) - 1; in spi_dw_compute_ndf()
313 static void spi_dw_update_txftlr(const struct device *dev, in spi_dw_update_txftlr() argument
314 struct spi_dw_data *spi) in spi_dw_update_txftlr() argument
316 const struct spi_dw_config *info = dev->config; in spi_dw_update_txftlr()
317 uint32_t dw_spi_txftlr_dflt = (info->fifo_depth * 1) / 2; in spi_dw_update_txftlr()
320 if (spi_dw_is_slave(spi)) { in spi_dw_update_txftlr()
321 if (!spi->ctx.tx_len) { in spi_dw_update_txftlr()
323 } else if (spi->ctx.tx_len < dw_spi_txftlr_dflt) { in spi_dw_update_txftlr()
324 reg_data = spi->ctx.tx_len - 1; in spi_dw_update_txftlr()
330 write_txftlr(dev, reg_data); in spi_dw_update_txftlr()
333 static int transceive(const struct device *dev, in transceive() argument
341 const struct spi_dw_config *info = dev->config; in transceive()
342 struct spi_dw_data *spi = dev->data; in transceive() local
344 uint32_t dw_spi_rxftlr_dflt = (info->fifo_depth * 5) / 8; in transceive()
348 spi_context_lock(&spi->ctx, asynchronous, cb, userdata, config); in transceive()
351 if (!pm_device_is_busy(dev)) { in transceive()
352 pm_device_busy_set(dev); in transceive()
357 ret = spi_dw_configure(dev, spi, config); in transceive()
362 if (!rx_bufs || !rx_bufs->buffers) { in transceive()
364 } else if (!tx_bufs || !tx_bufs->buffers) { in transceive()
371 !spi_dw_is_slave(spi)) { in transceive()
372 reg_data = spi_dw_compute_ndf(rx_bufs->buffers, in transceive()
373 rx_bufs->count, in transceive()
374 spi->dfs); in transceive()
376 ret = -EINVAL; in transceive()
380 write_ctrlr1(dev, reg_data); in transceive()
382 write_ctrlr1(dev, 0); in transceive()
385 if (spi_dw_is_slave(spi)) { in transceive()
395 reg_data = read_ctrlr0(dev); in transceive()
399 write_ctrlr0(dev, reg_data); in transceive()
402 spi_context_buffers_setup(&spi->ctx, tx_bufs, rx_bufs, spi->dfs); in transceive()
404 spi->fifo_diff = 0U; in transceive()
407 spi_dw_update_txftlr(dev, spi); in transceive()
412 if (spi_dw_is_slave(spi)) { in transceive()
413 if (spi->ctx.rx_len && in transceive()
414 spi->ctx.rx_len < dw_spi_rxftlr_dflt) { in transceive()
415 reg_data = spi->ctx.rx_len - 1; in transceive()
418 if (spi->ctx.rx_len && spi->ctx.rx_len < info->fifo_depth) { in transceive()
419 reg_data = spi->ctx.rx_len - 1; in transceive()
424 write_rxftlr(dev, reg_data); in transceive()
430 write_imr(dev, reg_data); in transceive()
432 if (!spi_dw_is_slave(spi)) { in transceive()
435 spi_context_cs_control(&spi->ctx, true); in transceive()
437 write_ser(dev, BIT(config->slave)); in transceive()
442 set_bit_ssienr(dev); in transceive()
444 ret = spi_context_wait_for_completion(&spi->ctx); in transceive()
447 if (spi_context_is_slave(&spi->ctx) && !ret) { in transceive()
448 ret = spi->ctx.recv_frames; in transceive()
453 spi_context_release(&spi->ctx, ret); in transceive()
455 pm_device_busy_clear(dev); in transceive()
460 static int spi_dw_transceive(const struct device *dev, in spi_dw_transceive() argument
465 LOG_DBG("%p, %p, %p", dev, tx_bufs, rx_bufs); in spi_dw_transceive()
467 return transceive(dev, config, tx_bufs, rx_bufs, false, NULL, NULL); in spi_dw_transceive()
471 static int spi_dw_transceive_async(const struct device *dev, in spi_dw_transceive_async() argument
478 LOG_DBG("%p, %p, %p, %p, %p", dev, tx_bufs, rx_bufs, cb, userdata); in spi_dw_transceive_async()
480 return transceive(dev, config, tx_bufs, rx_bufs, true, cb, userdata); in spi_dw_transceive_async()
484 static int spi_dw_release(const struct device *dev, in spi_dw_release() argument
487 struct spi_dw_data *spi = dev->data; in spi_dw_release() local
489 if (!spi_context_configured(&spi->ctx, config)) { in spi_dw_release()
490 return -EINVAL; in spi_dw_release()
493 spi_context_unlock_unconditionally(&spi->ctx); in spi_dw_release()
498 void spi_dw_isr(const struct device *dev) in spi_dw_isr() argument
503 int_status = read_isr(dev); in spi_dw_isr()
505 LOG_DBG("SPI %p int_status 0x%x - (tx: %d, rx: %d)", dev, int_status, in spi_dw_isr()
506 read_txflr(dev), read_rxflr(dev)); in spi_dw_isr()
509 error = -EIO; in spi_dw_isr()
516 pull_data(dev); in spi_dw_isr()
520 push_data(dev); in spi_dw_isr()
524 clear_interrupts(dev); in spi_dw_isr()
525 completed(dev, error); in spi_dw_isr()
528 static DEVICE_API(spi, dw_spi_api) = {
539 int spi_dw_init(const struct device *dev) in spi_dw_init() argument
542 const struct spi_dw_config *info = dev->config; in spi_dw_init()
543 struct spi_dw_data *spi = dev->data; in spi_dw_init() local
546 pinctrl_apply_state(info->pcfg, PINCTRL_STATE_DEFAULT); in spi_dw_init()
549 DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); in spi_dw_init()
551 info->config_func(); in spi_dw_init()
554 write_imr(dev, DW_SPI_IMR_MASK); in spi_dw_init()
555 clear_bit_ssienr(dev); in spi_dw_init()
557 LOG_DBG("Designware SPI driver initialized on device: %p", dev); in spi_dw_init()
559 err = spi_context_cs_configure_all(&spi->ctx); in spi_dw_init()
564 spi_context_unlock_unconditionally(&spi->ctx); in spi_dw_init()