diff options
| author | Rajeshwari Shinde <rajeshwari.s@samsung.com> | 2013-05-28 20:10:38 +0000 | 
|---|---|---|
| committer | Jagannadha Sutradharudu Teki <jaganna@xilinx.com> | 2013-06-03 00:04:40 +0530 | 
| commit | e4eaef8910df805d511b1cb9b2caafa7d2827fdc (patch) | |
| tree | fc58af501f7a5e5e125133c99c349c3cc1c81d6b /drivers/spi/exynos_spi.c | |
| parent | bb786b84bdbcfe0474d53a54c82c5695494a6ab5 (diff) | |
| download | olio-uboot-2014.01-e4eaef8910df805d511b1cb9b2caafa7d2827fdc.tar.xz olio-uboot-2014.01-e4eaef8910df805d511b1cb9b2caafa7d2827fdc.zip | |
spi: exynos: Support SPI_PREAMBLE mode
Support interfaces with a preamble before each received message.
We handle this when the client has requested a SPI_XFER_END, meaning
that we must close of the transaction. In this case we read until we
see the preamble (or a timeout occurs), skipping all data before and
including the preamble. The client will receive only data bytes after
the preamble.
Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
Reviewed-by: Jagannadha Sutradharudu Teki <jagannadh.teki@gmail.com>
Diffstat (limited to 'drivers/spi/exynos_spi.c')
| -rw-r--r-- | drivers/spi/exynos_spi.c | 69 | 
1 files changed, 59 insertions, 10 deletions
| diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c index 607e1cdec..01378d098 100644 --- a/drivers/spi/exynos_spi.c +++ b/drivers/spi/exynos_spi.c @@ -51,6 +51,7 @@ struct exynos_spi_slave {  	unsigned int mode;  	enum periph_id periph_id;	/* Peripheral ID for this device */  	unsigned int fifo_size; +	int skip_preamble;  };  static struct spi_bus *spi_get_bus(unsigned dev_index) @@ -105,6 +106,8 @@ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,  	else  		spi_slave->fifo_size = 256; +	spi_slave->skip_preamble = 0; +  	spi_slave->freq = bus->frequency;  	if (max_hz)  		spi_slave->freq = min(max_hz, spi_slave->freq); @@ -217,17 +220,23 @@ static void spi_request_bytes(struct exynos_spi *regs, int count)  	writel(count | SPI_PACKET_CNT_EN, ®s->pkt_cnt);  } -static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo, -			void **dinp, void const **doutp) +static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo, +			void **dinp, void const **doutp, unsigned long flags)  {  	struct exynos_spi *regs = spi_slave->regs;  	uchar *rxp = *dinp;  	const uchar *txp = *doutp;  	int rx_lvl, tx_lvl;  	uint out_bytes, in_bytes; +	int toread; +	unsigned start = get_timer(0); +	int stopping;  	out_bytes = in_bytes = todo; +	stopping = spi_slave->skip_preamble && (flags & SPI_XFER_END) && +					!(spi_slave->mode & SPI_SLAVE); +  	/*  	 * If there's something to send, do a software reset and set a  	 * transaction size. @@ -238,6 +247,8 @@ static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,  	 * Bytes are transmitted/received in pairs. Wait to receive all the  	 * data because then transmission will be done as well.  	 */ +	toread = in_bytes; +  	while (in_bytes) {  		int temp; @@ -248,15 +259,43 @@ static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,  			writel(temp, ®s->tx_data);  			out_bytes--;  		} -		if (rx_lvl > 0 && in_bytes) { +		if (rx_lvl > 0) {  			temp = readl(®s->rx_data); -			if (rxp) -				*rxp++ = temp; -			in_bytes--; +			if (spi_slave->skip_preamble) { +				if (temp == SPI_PREAMBLE_END_BYTE) { +					spi_slave->skip_preamble = 0; +					stopping = 0; +				} +			} else { +				if (rxp || stopping) +					*rxp++ = temp; +				in_bytes--; +			} +			toread--; +		} else if (!toread) { +			/* +			 * We have run out of input data, but haven't read +			 * enough bytes after the preamble yet. Read some more, +			 * and make sure that we transmit dummy bytes too, to +			 * keep things going. +			 */ +			assert(!out_bytes); +			out_bytes = in_bytes; +			toread = in_bytes; +			txp = NULL; +			spi_request_bytes(regs, toread); +		} +		if (spi_slave->skip_preamble && get_timer(start) > 100) { +			printf("SPI timeout: in_bytes=%d, out_bytes=%d, ", +			       in_bytes, out_bytes); +			return -1;  		}  	} +  	*dinp = rxp;  	*doutp = txp; + +	return 0;  }  /** @@ -276,6 +315,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,  	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);  	int upto, todo;  	int bytelen; +	int ret = 0;  	/* spi core configured to do 8 bit transfers */  	if (bitlen % 8) { @@ -289,16 +329,24 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,  	/* Exynos SPI limits each transfer to 65535 bytes */  	bytelen =  bitlen / 8; -	for (upto = 0; upto < bytelen; upto += todo) { +	for (upto = 0; !ret && upto < bytelen; upto += todo) {  		todo = min(bytelen - upto, (1 << 16) - 1); -		spi_rx_tx(spi_slave, todo, &din, &dout); +		ret = spi_rx_tx(spi_slave, todo, &din, &dout, flags); +		if (ret) +			break;  	}  	/* Stop the transaction, if necessary. */ -	if ((flags & SPI_XFER_END)) +	if ((flags & SPI_XFER_END) && !(spi_slave->mode & SPI_SLAVE)) {  		spi_cs_deactivate(slave); +		if (spi_slave->skip_preamble) { +			assert(!spi_slave->skip_preamble); +			debug("Failed to complete premable transaction\n"); +			ret = -1; +		} +	} -	return 0; +	return ret;  }  /** @@ -325,6 +373,7 @@ void spi_cs_activate(struct spi_slave *slave)  	clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);  	debug("Activate CS, bus %d\n", spi_slave->slave.bus); +	spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE;  }  /** |