示例#1
0
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;
}
示例#2
0
static void pull_data(struct device *dev)
{
	const struct spi_dw_config *info = dev->config->config_info;
	struct spi_dw_data *spi = dev->driver_data;
	u32_t data = 0;
	DBG_COUNTER_INIT();

	while (read_rxflr(info->regs)) {
		data = read_dr(info->regs);
		DBG_COUNTER_INC();

		if (spi->rx_buf && spi->rx_buf_len > 0) {
			switch (spi->dfs) {
			case 1:
				UNALIGNED_PUT(data, (u8_t *)spi->rx_buf);
				break;
			case 2:
				UNALIGNED_PUT(data, (u16_t *)spi->rx_buf);
				break;
#ifndef CONFIG_ARC
			case 4:
				UNALIGNED_PUT(data, (u32_t *)spi->rx_buf);
				break;
#endif
			}

			spi->rx_buf += spi->dfs;
			spi->rx_buf_len--;
		}

		spi->fifo_diff--;
	}

	if (!spi->rx_buf_len && spi->tx_buf_len < DW_SPI_FIFO_DEPTH) {
		write_rxftlr(spi->tx_buf_len - 1, info->regs);
	} else if (read_rxftlr(info->regs) >= spi->rx_buf_len) {
		write_rxftlr(spi->rx_buf_len - 1, info->regs);
	}

	SYS_LOG_DBG("Pulled: %d", DBG_COUNTER_RESULT());
}
示例#3
0
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;
}
示例#4
0
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;
}