diff options
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; |