示例#1
0
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;
}
示例#2
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;
}
示例#3
0
static int spi_qmsi_configure(struct device *dev,
				struct spi_config *config)
{
	struct spi_qmsi_runtime *context = dev->driver_data;
	qm_spi_config_t *cfg = &context->cfg;

	cfg->frame_size = SPI_WORD_SIZE_GET(config->config) - 1;
	cfg->bus_mode = config_to_bmode(SPI_MODE(config->config));
	/* As loopback is implemented inside the controller,
	 * the bus mode doesn't matter.
	 */
	context->loopback = SPI_MODE(config->config) & SPI_MODE_LOOP;
	cfg->clk_divider = config->max_sys_freq;

	/* Will set the configuration before the transfer starts */
	return 0;
}
示例#4
0
static int configure(struct device *dev,
		     const struct spi_config *spi_cfg)
{
	struct spi_context *ctx = &get_dev_data(dev)->ctx;

	if (spi_context_configured(ctx, spi_cfg)) {
		/* Already configured. No need to do it again. */
		return 0;
	}

	if (SPI_OP_MODE_GET(spi_cfg->operation) == SPI_OP_MODE_MASTER) {
		LOG_ERR("Master mode is not supported on %s",
			    dev->config->name);
		return -EINVAL;
	}

	if (spi_cfg->operation & SPI_MODE_LOOP) {
		LOG_ERR("Loopback mode is not supported");
		return -EINVAL;
	}

	if ((spi_cfg->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) {
		LOG_ERR("Only single line mode is supported");
		return -EINVAL;
	}

	if (SPI_WORD_SIZE_GET(spi_cfg->operation) != 8) {
		LOG_ERR("Word sizes other than 8 bits"
			    " are not supported");
		return -EINVAL;
	}

	if (spi_cfg->cs) {
		LOG_ERR("CS control via GPIO is not supported");
		return -EINVAL;
	}

	ctx->config = spi_cfg;

	nrf_spis_configure(get_dev_config(dev)->spis.p_reg,
			   get_nrf_spis_mode(spi_cfg->operation),
			   get_nrf_spis_bit_order(spi_cfg->operation));

	return 0;
}
示例#5
0
static int spi_stm32_configure(struct spi_config *config)
{
	const struct spi_stm32_config *cfg = CONFIG_CFG(config);
	struct spi_stm32_data *data = CONFIG_DATA(config);
	const u32_t scaler[] = {
		LL_SPI_BAUDRATEPRESCALER_DIV2,
		LL_SPI_BAUDRATEPRESCALER_DIV4,
		LL_SPI_BAUDRATEPRESCALER_DIV8,
		LL_SPI_BAUDRATEPRESCALER_DIV16,
		LL_SPI_BAUDRATEPRESCALER_DIV32,
		LL_SPI_BAUDRATEPRESCALER_DIV64,
		LL_SPI_BAUDRATEPRESCALER_DIV128,
		LL_SPI_BAUDRATEPRESCALER_DIV256
	};
	SPI_TypeDef *spi = cfg->spi;
	u32_t clock;
	int br;

	if (spi_context_configured(&data->ctx, config)) {
		/* Nothing to do */
		return 0;
	}

	if (SPI_WORD_SIZE_GET(config->operation) != 8) {
		return -ENOTSUP;
	}

	clock_control_get_rate(device_get_binding(STM32_CLOCK_CONTROL_NAME),
			       (clock_control_subsys_t) &cfg->pclken, &clock);

	for (br = 1 ; br <= ARRAY_SIZE(scaler) ; ++br) {
		u32_t clk = clock >> br;

		if (clk < config->frequency) {
			break;
		}
	}

	if (br > ARRAY_SIZE(scaler)) {
		SYS_LOG_ERR("Unsupported frequency %uHz, max %uHz, min %uHz",
			    config->frequency,
			    clock >> 1,
			    clock >> ARRAY_SIZE(scaler));
		return -EINVAL;
	}
示例#6
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;
}
示例#7
0
/**
 * @brief Configure the SPI host controller for operating against slaves
 * @param dev Pointer to the device structure for the driver instance
 * @param config Pointer to the application provided configuration
 *
 * @return DEV_OK if successful, another DEV_* code otherwise.
 */
static int spi_k64_configure(struct device *dev, struct spi_config *config)
{
	struct spi_k64_config *info = dev->config->config_info;
	struct spi_k64_data *spi_data = dev->driver_data;
	uint32_t flags = config->config;
	uint32_t mcr;		/* mode configuration attributes, for MCR */
	uint32_t ctar = 0;	/* clocking and timing attributes, for CTAR */
	uint32_t frame_sz;	/* frame size, in bits */

	DBG("spi_k64_configure: dev %p (regs @ 0x%x), ", dev, info->regs);
	DBG("config 0x%x, freq 0x%x",
		config->config, config->max_sys_freq);

	 /* Disable transfer operations during configuration */

	spi_k64_halt(dev);

	/*
	 * Set the common configuration:
	 * Master mode, normal SPI transfers, PCS strobe disabled,
	 * Rx overflow data ignored, PCSx inactive low signal, Doze disabled,
	 * Rx/Tx FIFOs enabled.
	 *
	 * Also, keep transfers disabled.
	 */

	mcr = SPI_K64_MCR_MSTR | SPI_K64_MCR_HALT;

	/* Set PCSx signal polarities and continuous SCK, as requested */

	mcr |= (SPI_K64_MCR_PCSIS_SET(SPI_PCS_POL_GET(flags)) |
			SPI_K64_MCR_CONT_SCKE_SET(SPI_CONT_SCK_GET(flags)));

	sys_write32(mcr, (info->regs + SPI_K64_REG_MCR));


	/* Set clocking and timing parameters */


	/* SCK polarity and phase, and bit order of data */

	if (flags & SPI_MODE_CPOL) {
		ctar |= SPI_K64_CTAR_CPOL;
	}

	if (flags & SPI_MODE_CPHA) {
		ctar |= SPI_K64_CTAR_CPHA;
	}

	if (flags & SPI_TRANSFER_MASK) {
		ctar |= SPI_K64_CTAR_LSBFE;
	}

	/*
	 * Frame size is limited to 16 bits (vs. 8 bit value in struct spi_config),
	 * programmed as: (frame_size - 1)
	 */

	if ((frame_sz = SPI_WORD_SIZE_GET(flags)) > SPI_K64_WORD_SIZE_MAX) {
		return DEV_INVALID_OP;
	}

	spi_data->frame_sz = frame_sz;

	ctar |= (SPI_K64_CTAR_FRMSZ_SET(frame_sz - 1));

	/* Set baud rate and signal timing parameters (delays) */

	if (spi_k64_set_baud_rate(config->max_sys_freq, &ctar) == 0) {
		return DEV_INVALID_OP;
	}

	/*
	 * Set signal timing parameters (delays):
	 * - PCS to SCK delay is set to the minimum, CTAR[PCSSCK] = CTAR[CSSCK] = 0;
	 * - After SCK delay is set to at least half of the baud rate period,
	 *   (using the combination of CTAR[PASC] and CTAR[ASC]); and
	 * - Delay after transfer is set to the minimum, CTAR[PDT] = CTAR[DT] = 0.
	 */

	if (spi_k64_set_delay(DELAY_AFTER_SCK,
							(NSEC_PER_SEC / 2) / config->max_sys_freq,
							&ctar) == 0) {
		return DEV_INVALID_OP;
	}


	DBG("spi_k64_configure: MCR: 0x%x CTAR0: 0x%x\n", mcr, ctar);

	sys_write32(ctar, (info->regs + SPI_K64_REG_CTAR0));

	/* Initialize Tx/Rx parameters */

	spi_data->tx_buf = spi_data->rx_buf = NULL;
	spi_data->tx_buf_len = spi_data->rx_buf_len = 0;

	/* Store continuous slave/PCS signal selection mode */

	spi_data->cont_pcs_sel = SPI_CONT_PCS_GET(flags);

	return DEV_OK;
}