static int spi_dw_transceive(struct device *dev, const void *tx_buf, uint32_t tx_buf_len, void *rx_buf, uint32_t rx_buf_len) { struct spi_dw_config *info = dev->config->config_info; struct spi_dw_data *spi = dev->driver_data; uint32_t rx_thsld = DW_SPI_RXFTLR_DFLT; DBG("%s: %p, %p, %u, %p, %u\n", __func__, dev, tx_buf, tx_buf_len, rx_buf, rx_buf_len); /* Check status */ if (!_spi_dw_is_controller_ready(dev)) { DBG("%s: Controller is busy\n", __func__); return DEV_USED; } /* Set buffers info */ spi->tx_buf = tx_buf; spi->tx_buf_len = tx_buf_len/spi->dfs; spi->rx_buf = rx_buf; spi->rx_buf_len = rx_buf_len/spi->dfs; spi->fifo_diff = 0; /* Tx Threshold, always at default */ write_txftlr(DW_SPI_TXFTLR_DFLT, info->regs); /* Does Rx thresholds needs to be lower? */ if (rx_buf_len && spi->rx_buf_len < DW_SPI_FIFO_DEPTH) { rx_thsld = spi->rx_buf_len - 1; } else if (!rx_buf_len && spi->tx_buf_len < DW_SPI_FIFO_DEPTH) { rx_thsld = spi->tx_buf_len - 1; } write_rxftlr(rx_thsld, info->regs); /* Slave select */ write_ser(spi->slave, info->regs); _spi_control_cs(dev, 1); /* Enable interrupts */ write_imr(DW_SPI_IMR_UNMASK, info->regs); /* Enable the controller */ set_bit_ssienr(info->regs); device_sync_call_wait(&spi->sync); if (spi->error) { spi->error = 0; return DEV_FAIL; } return DEV_OK; }
static int spi_dw_transceive(struct device *dev, const void *tx_buf, u32_t tx_buf_len, void *rx_buf, u32_t rx_buf_len) { const struct spi_dw_config *info = dev->config->config_info; struct spi_dw_data *spi = dev->driver_data; u32_t rx_thsld = DW_SPI_RXFTLR_DFLT; u32_t imask; SYS_LOG_DBG("%p, %p, %u, %p, %u", dev, tx_buf, tx_buf_len, rx_buf, rx_buf_len); /* Check status */ if (!_spi_dw_is_controller_ready(dev)) { SYS_LOG_DBG("Controller is busy"); return -EBUSY; } /* Set buffers info */ spi->tx_buf = tx_buf; spi->tx_buf_len = tx_buf_len/spi->dfs; spi->rx_buf = rx_buf; if (rx_buf) { spi->rx_buf_len = rx_buf_len/spi->dfs; } else { spi->rx_buf_len = 0; /* must be zero if no buffer */ } spi->fifo_diff = 0; spi->last_tx = 0; /* Tx Threshold */ write_txftlr(DW_SPI_TXFTLR_DFLT, info->regs); /* Does Rx thresholds needs to be lower? */ if (spi->rx_buf_len && spi->rx_buf_len < DW_SPI_FIFO_DEPTH) { rx_thsld = spi->rx_buf_len - 1; } else if (!spi->rx_buf_len && spi->tx_buf_len < DW_SPI_FIFO_DEPTH) { rx_thsld = spi->tx_buf_len - 1; /* TODO: why? */ } write_rxftlr(rx_thsld, info->regs); /* Slave select */ write_ser(spi->slave, info->regs); _spi_control_cs(dev, 1); /* Enable interrupts */ imask = DW_SPI_IMR_UNMASK; if (!rx_buf) { /* if there is no rx buffer, keep all rx interrupts masked */ imask &= DW_SPI_IMR_MASK_RX; } write_imr(imask, info->regs); /* Enable the controller */ set_bit_ssienr(info->regs); k_sem_take(&spi->device_sync_sem, K_FOREVER); if (spi->error) { spi->error = 0; return -EIO; } return 0; }
static int spi_dw_configure(const struct spi_dw_config *info, struct spi_dw_data *spi, const struct spi_config *config) { u32_t ctrlr0 = 0U; LOG_DBG("%p (prev %p)", config, spi->ctx.config); if (spi_context_configured(&spi->ctx, config)) { /* Nothing to do */ return 0; } /* Verify if requested op mode is relevant to this controller */ if (config->operation & SPI_OP_MODE_SLAVE) { if (!(info->op_modes & SPI_CTX_RUNTIME_OP_MODE_SLAVE)) { LOG_ERR("Slave mode not supported"); return -ENOTSUP; } } else { if (!(info->op_modes & SPI_CTX_RUNTIME_OP_MODE_MASTER)) { LOG_ERR("Master mode not supported"); return -ENOTSUP; } } if (config->operation & (SPI_TRANSFER_LSB | SPI_LINES_DUAL | SPI_LINES_QUAD)) { LOG_ERR("Unsupported configuration"); return -EINVAL; } /* Word size */ ctrlr0 |= DW_SPI_CTRLR0_DFS(SPI_WORD_SIZE_GET(config->operation)); /* Determine how many bytes are required per-frame */ spi->dfs = SPI_WS_TO_DFS(SPI_WORD_SIZE_GET(config->operation)); /* SPI mode */ if (SPI_MODE_GET(config->operation) & SPI_MODE_CPOL) { ctrlr0 |= DW_SPI_CTRLR0_SCPOL; } if (SPI_MODE_GET(config->operation) & SPI_MODE_CPHA) { ctrlr0 |= DW_SPI_CTRLR0_SCPH; } if (SPI_MODE_GET(config->operation) & SPI_MODE_LOOP) { ctrlr0 |= DW_SPI_CTRLR0_SRL; } /* Installing the configuration */ write_ctrlr0(ctrlr0, info->regs); /* At this point, it's mandatory to set this on the context! */ spi->ctx.config = config; if (!spi_dw_is_slave(spi)) { /* Baud rate and Slave select, for master only */ write_baudr(SPI_DW_CLK_DIVIDER(config->frequency), info->regs); write_ser(1 << config->slave, info->regs); } spi_context_cs_configure(&spi->ctx); if (spi_dw_is_slave(spi)) { LOG_DBG("Installed slave config %p:" " ws/dfs %u/%u, mode %u/%u/%u", config, SPI_WORD_SIZE_GET(config->operation), spi->dfs, (SPI_MODE_GET(config->operation) & SPI_MODE_CPOL) ? 1 : 0, (SPI_MODE_GET(config->operation) & SPI_MODE_CPHA) ? 1 : 0, (SPI_MODE_GET(config->operation) & SPI_MODE_LOOP) ? 1 : 0); } else { LOG_DBG("Installed master config %p: freq %uHz (div = %u)," " ws/dfs %u/%u, mode %u/%u/%u, slave %u", config, config->frequency, SPI_DW_CLK_DIVIDER(config->frequency), SPI_WORD_SIZE_GET(config->operation), spi->dfs, (SPI_MODE_GET(config->operation) & SPI_MODE_CPOL) ? 1 : 0, (SPI_MODE_GET(config->operation) & SPI_MODE_CPHA) ? 1 : 0, (SPI_MODE_GET(config->operation) & SPI_MODE_LOOP) ? 1 : 0, config->slave); } return 0; }