예제 #1
0
파일: spi.c 프로젝트: siro20/coreboot
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs)
{
	struct tegra_spi_channel *channel = to_tegra_spi(bus);
	if (!channel)
		return NULL;

	return &channel->slave;
}
예제 #2
0
int spi_setup_slave(unsigned int bus, unsigned int cs, struct spi_slave *slave)
{
	struct tegra_spi_channel *channel = to_tegra_spi(bus);
	if (!channel)
		return -1;

	slave->bus = channel->slave.bus;
	slave->cs = channel->slave.cs;
	slave->ctrlr = &spi_ctrlr;

	return 0;
}
예제 #3
0
파일: spi.c 프로젝트: canistation/coreboot
static void spi_ctrlr_release_bus(const struct spi_slave *slave)
{
	struct tegra_spi_regs *regs = to_tegra_spi(slave->bus)->regs;
	u32 val;

	val = read32(&regs->command1);

	if (val & (SPI_CMD1_CS_POL_INACTIVE0 << slave->cs))
		val |= SPI_CMD1_CS_SW_VAL;
	else
		val &= ~SPI_CMD1_CS_SW_VAL;

	write32(&regs->command1, val);
}
예제 #4
0
파일: spi.c 프로젝트: canistation/coreboot
static int spi_ctrlr_claim_bus(const struct spi_slave *slave)
{
	struct tegra_spi_regs *regs = to_tegra_spi(slave->bus)->regs;
	u32 val;

	tegra_spi_init(slave->bus);

	val = read32(&regs->command1);

	/* select appropriate chip-select line */
	val &= ~(SPI_CMD1_CS_SEL_MASK << SPI_CMD1_CS_SEL_SHIFT);
	val |= (slave->cs << SPI_CMD1_CS_SEL_SHIFT);

	/* drive chip-select with the inverse of the "inactive" value */
	if (val & (SPI_CMD1_CS_POL_INACTIVE0 << slave->cs))
		val &= ~SPI_CMD1_CS_SW_VAL;
	else
		val |= SPI_CMD1_CS_SW_VAL;

	write32(&regs->command1, val);
	return 0;
}
예제 #5
0
파일: spi.c 프로젝트: canistation/coreboot
static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
			  size_t out_bytes, void *din, size_t in_bytes)
{
	struct tegra_spi_channel *spi = to_tegra_spi(slave->bus);
	u8 *out_buf = (u8 *)dout;
	u8 *in_buf = (u8 *)din;
	size_t todo;
	int ret = 0;

	/* tegra bus numbers start at 1 */
	ASSERT(slave->bus >= 1 && slave->bus <= ARRAY_SIZE(tegra_spi_channels));

	while (out_bytes || in_bytes) {
		int x = 0;

		if (out_bytes == 0)
			todo = in_bytes;
		else if (in_bytes == 0)
			todo = out_bytes;
		else
			todo = MIN(out_bytes, in_bytes);

		if (out_bytes) {
			x = xfer_setup(spi, out_buf, todo, SPI_SEND);
			if (x < 0) {
				if (spi->xfer_mode == XFER_MODE_NONE) {
					spi->xfer_mode = XFER_MODE_PIO;
					continue;
				} else {
					ret = -1;
					break;
				}
			}
		}
		if (in_bytes) {
			x = xfer_setup(spi, in_buf, todo, SPI_RECEIVE);
			if (x < 0) {
				if (spi->xfer_mode == XFER_MODE_NONE) {
					spi->xfer_mode = XFER_MODE_PIO;
					continue;
				} else {
					ret = -1;
					break;
				}
			}
		}

		/*
		 * Note: Some devices (such as Chrome EC) are sensitive to
		 * delays, so be careful when adding debug prints not to
		 * cause timeouts between transfers.
		 */
		xfer_start(spi);
		xfer_wait(spi);
		if (xfer_finish(spi)) {
			ret = -1;
			break;
		}

		/* Post-processing. */
		if (out_bytes) {
			out_bytes -= x;
			out_buf += x;
		}
		if (in_bytes) {
			in_bytes -= x;
			in_buf += x;
		}
	}

	if (ret < 0) {
		printk(BIOS_ERR, "%s: Error detected\n", __func__);
		printk(BIOS_ERR, "Transaction size: %u, bytes remaining: "
				"%u out / %u in\n", todo, out_bytes, in_bytes);
		clear_fifo_status(spi);
	}
	return ret;
}