static int spi_dw_configure(struct device *dev, struct spi_config *config) { const struct spi_dw_config *info = dev->config->config_info; struct spi_dw_data *spi = dev->driver_data; u32_t flags = config->config; u32_t ctrlr0 = 0; u32_t mode; SYS_LOG_DBG("%p (0x%x), %p", dev, info->regs, config); /* Check status */ if (!_spi_dw_is_controller_ready(dev)) { SYS_LOG_DBG("Controller is busy"); return -EBUSY; } /* Word size */ ctrlr0 |= DW_SPI_CTRLR0_DFS(SPI_WORD_SIZE_GET(flags)); /* Determine how many bytes are required per-frame */ spi->dfs = SPI_WS_TO_DFS(SPI_WORD_SIZE_GET(flags)); /* SPI mode */ mode = SPI_MODE(flags); if (mode & SPI_MODE_CPOL) { ctrlr0 |= DW_SPI_CTRLR0_SCPOL; } if (mode & SPI_MODE_CPHA) { ctrlr0 |= DW_SPI_CTRLR0_SCPH; } if (mode & SPI_MODE_LOOP) { ctrlr0 |= DW_SPI_CTRLR0_SRL; } /* Installing the configuration */ write_ctrlr0(ctrlr0, info->regs); /* * Configure the rate. Use this small hack to allow the user to call * spi_configure() with both a divider (as the driver was initially * written) and a frequency (as the SPI API suggests to). The clock * divider is a 16bit value, hence we can fairly, and safely, assume * that everything above this value is a frequency. The trade-off is * that if one wants to use a bus frequency of 64kHz (or less), it has * the use a divider... */ if (config->max_sys_freq > 0xffff) { write_baudr(SPI_DW_CLK_DIVIDER(config->max_sys_freq), info->regs); } else { write_baudr(config->max_sys_freq, info->regs); } return 0; }
static int spi_dw_configure(struct device *dev, struct spi_config *config) { struct spi_dw_config *info = dev->config->config_info; struct spi_dw_data *spi = dev->driver_data; uint32_t flags = config->config; uint32_t ctrlr0 = 0; uint32_t mode; DBG("%s: %p (0x%x), %p\n", __func__, dev, info->regs, config); /* Check status */ if (!_spi_dw_is_controller_ready(dev)) { DBG("%s: Controller is busy\n", __func__); return DEV_USED; } /* Word size */ ctrlr0 |= DW_SPI_CTRLR0_DFS(SPI_WORD_SIZE_GET(flags)); /* Determine how many bytes are required per-frame */ spi->dfs = SPI_DFS_TO_BYTES(SPI_WORD_SIZE_GET(flags)); /* SPI mode */ mode = SPI_MODE(flags); if (mode & SPI_MODE_CPOL) { ctrlr0 |= DW_SPI_CTRLR0_SCPOL; } if (mode & SPI_MODE_CPHA) { ctrlr0 |= DW_SPI_CTRLR0_SCPH; } if (mode & SPI_MODE_LOOP) { ctrlr0 |= DW_SPI_CTRLR0_SRL; } /* Installing the configuration */ write_ctrlr0(ctrlr0, info->regs); /* Configuring the rate */ write_baudr(config->max_sys_freq, info->regs); return DEV_OK; }
static int transceive(struct device *dev, const struct spi_config *config, const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs, bool asynchronous, struct k_poll_signal *signal) { const struct spi_dw_config *info = dev->config->config_info; struct spi_dw_data *spi = dev->driver_data; u32_t tmod = DW_SPI_CTRLR0_TMOD_TX_RX; u32_t reg_data; int ret; spi_context_lock(&spi->ctx, asynchronous, signal); /* Configure */ ret = spi_dw_configure(info, spi, config); if (ret) { goto out; } if (!rx_bufs || !rx_bufs->buffers) { tmod = DW_SPI_CTRLR0_TMOD_TX; } else if (!tx_bufs || !tx_bufs->buffers) { tmod = DW_SPI_CTRLR0_TMOD_RX; } /* ToDo: add a way to determine EEPROM mode */ if (tmod >= DW_SPI_CTRLR0_TMOD_RX && !spi_dw_is_slave(spi)) { reg_data = spi_dw_compute_ndf(rx_bufs->buffers, rx_bufs->count, spi->dfs); if (reg_data == UINT32_MAX) { ret = -EINVAL; goto out; } write_ctrlr1(reg_data, info->regs); } else { write_ctrlr1(0, info->regs); } if (spi_dw_is_slave(spi)) { /* Enabling MISO line relevantly */ if (tmod == DW_SPI_CTRLR0_TMOD_RX) { tmod |= DW_SPI_CTRLR0_SLV_OE; } else { tmod &= ~DW_SPI_CTRLR0_SLV_OE; } } /* Updating TMOD in CTRLR0 register */ reg_data = read_ctrlr0(info->regs); reg_data &= ~DW_SPI_CTRLR0_TMOD_RESET; reg_data |= tmod; write_ctrlr0(reg_data, info->regs); /* Set buffers info */ spi_context_buffers_setup(&spi->ctx, tx_bufs, rx_bufs, spi->dfs); spi->fifo_diff = 0U; /* Tx Threshold */ spi_dw_update_txftlr(info, spi); /* Does Rx thresholds needs to be lower? */ reg_data = DW_SPI_RXFTLR_DFLT; if (spi_dw_is_slave(spi)) { if (spi->ctx.rx_len && spi->ctx.rx_len < DW_SPI_RXFTLR_DFLT) { reg_data = spi->ctx.rx_len - 1; } } else { if (spi->ctx.rx_len && spi->ctx.rx_len < DW_SPI_FIFO_DEPTH) { reg_data = spi->ctx.rx_len - 1; } } /* Rx Threshold */ write_rxftlr(reg_data, info->regs); /* Enable interrupts */ reg_data = !rx_bufs ? DW_SPI_IMR_UNMASK & DW_SPI_IMR_MASK_RX : DW_SPI_IMR_UNMASK; write_imr(reg_data, info->regs); spi_context_cs_control(&spi->ctx, true); LOG_DBG("Enabling controller"); set_bit_ssienr(info->regs); ret = spi_context_wait_for_completion(&spi->ctx); out: spi_context_release(&spi->ctx, ret); return ret; }
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; }