diff options
| author | jacopo mondi <j.mondi@voltaelectronics.com> | 2011-03-02 05:13:22 +0000 | 
|---|---|---|
| committer | Albert ARIBAUD <albert.u.boot@aribaud.net> | 2012-03-27 22:05:29 +0200 | 
| commit | 08b5ab073d4eb389ffd622f71094cf1c70253c00 (patch) | |
| tree | b20b4c8fd0c783e15219b5507811258bece354c9 /drivers/spi/omap3_spi.c | |
| parent | f8d6c50ead35574f69b58da1932b1a366940d5fc (diff) | |
| download | olio-uboot-2014.01-08b5ab073d4eb389ffd622f71094cf1c70253c00.tar.xz olio-uboot-2014.01-08b5ab073d4eb389ffd622f71094cf1c70253c00.zip | |
omap3_spi: receive transmit mode
Implementation of receive-transmit mode for
omap3 MCSPI.
Introduces full duplex communication, needed by
some spi devices (such as enc28j60).
Signed-off-by: jacopo mondi <mondi@cs.unibo.it> <j.mondi@voltaelectronics.com>
Diffstat (limited to 'drivers/spi/omap3_spi.c')
| -rw-r--r-- | drivers/spi/omap3_spi.c | 66 | 
1 files changed, 63 insertions, 3 deletions
| diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index af12c0e59..9346c0b5b 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -297,6 +297,65 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp,  	return 0;  } +/*McSPI Transmit Receive Mode*/ +int omap3_spi_txrx(struct spi_slave *slave, +		unsigned int len, const u8 *txp, u8 *rxp, unsigned long flags) +{ +	struct omap3_spi_slave *ds = to_omap3_spi(slave); +	int timeout = SPI_WAIT_TIMEOUT; +	int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); +	int irqstatus = readl(&ds->regs->irqstatus); +	int i=0; + +	/*Enable SPI channel*/ +	if (flags & SPI_XFER_BEGIN) +		writel(OMAP3_MCSPI_CHCTRL_EN, +		       &ds->regs->channel[ds->slave.cs].chctrl); + +	/*set TRANSMIT-RECEIVE Mode*/ +	chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK; +	chconf |= OMAP3_MCSPI_CHCONF_FORCE; +	writel(chconf, &ds->regs->channel[ds->slave.cs].chconf); + +	/*Shift in and out 1 byte at time*/ +	for (i=0; i < len; i++){ +		/* Write: wait for TX empty (TXS == 1)*/ +		irqstatus |= (1<< (4*(ds->slave.bus))); +		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & +			 OMAP3_MCSPI_CHSTAT_TXS)) { +			if (--timeout <= 0) { +				printf("SPI TXS timed out, status=0x%08x\n", +				       readl(&ds->regs->channel[ds->slave.cs].chstat)); +				return -1; +			} +		} +		/* Write the data */ +		writel(txp[i], &ds->regs->channel[ds->slave.cs].tx); + +		/*Read: wait for RX containing data (RXS == 1)*/ +		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & +			 OMAP3_MCSPI_CHSTAT_RXS)) { +			if (--timeout <= 0) { +				printf("SPI RXS timed out, status=0x%08x\n", +				       readl(&ds->regs->channel[ds->slave.cs].chstat)); +				return -1; +			} +		} +		/* Read the data */ +		rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx); +	} + +	/*if transfer must be terminated disable the channel*/ +	if (flags & SPI_XFER_END) { +		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; +		writel(chconf, &ds->regs->channel[ds->slave.cs].chconf); + +		writel(0, &ds->regs->channel[ds->slave.cs].chctrl); +	} + +	return 0; +} +  int spi_xfer(struct spi_slave *slave, unsigned int bitlen,  	     const void *dout, void *din, unsigned long flags)  { @@ -329,10 +388,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,  		}  		ret = 0;  	} else { -		if (dout != NULL) +		if (dout != NULL && din != NULL) +			ret = omap3_spi_txrx(slave, len, txp, rxp, flags); +		else if (dout != NULL)  			ret = omap3_spi_write(slave, len, txp, flags); - -		if (din != NULL) +		else if (din != NULL)  			ret = omap3_spi_read(slave, len, rxp, flags);  	}  	return ret; |