diff options
Diffstat (limited to 'drivers/spi/dw_spi.c')
| -rw-r--r-- | drivers/spi/dw_spi.c | 202 | 
1 files changed, 66 insertions, 136 deletions
diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 871e337c917..919fa9d9e16 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -58,8 +58,6 @@ struct chip_data {  	u8 bits_per_word;  	u16 clk_div;		/* baud rate divider */  	u32 speed_hz;		/* baud rate */ -	int (*write)(struct dw_spi *dws); -	int (*read)(struct dw_spi *dws);  	void (*cs_control)(u32 command);  }; @@ -162,107 +160,70 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws)  }  #endif /* CONFIG_DEBUG_FS */ -static void wait_till_not_busy(struct dw_spi *dws) +/* Return the max entries we can fill into tx fifo */ +static inline u32 tx_max(struct dw_spi *dws)  { -	unsigned long end = jiffies + 1 + usecs_to_jiffies(5000); +	u32 tx_left, tx_room, rxtx_gap; -	while (time_before(jiffies, end)) { -		if (!(dw_readw(dws, sr) & SR_BUSY)) -			return; -		cpu_relax(); -	} -	dev_err(&dws->master->dev, -		"DW SPI: Status keeps busy for 5000us after a read/write!\n"); -} - -static void flush(struct dw_spi *dws) -{ -	while (dw_readw(dws, sr) & SR_RF_NOT_EMPT) { -		dw_readw(dws, dr); -		cpu_relax(); -	} - -	wait_till_not_busy(dws); -} - -static int null_writer(struct dw_spi *dws) -{ -	u8 n_bytes = dws->n_bytes; +	tx_left = (dws->tx_end - dws->tx) / dws->n_bytes; +	tx_room = dws->fifo_len - dw_readw(dws, txflr); -	if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL) -		|| (dws->tx == dws->tx_end)) -		return 0; -	dw_writew(dws, dr, 0); -	dws->tx += n_bytes; +	/* +	 * Another concern is about the tx/rx mismatch, we +	 * though to use (dws->fifo_len - rxflr - txflr) as +	 * one maximum value for tx, but it doesn't cover the +	 * data which is out of tx/rx fifo and inside the +	 * shift registers. So a control from sw point of +	 * view is taken. +	 */ +	rxtx_gap =  ((dws->rx_end - dws->rx) - (dws->tx_end - dws->tx)) +			/ dws->n_bytes; -	wait_till_not_busy(dws); -	return 1; +	return min3(tx_left, tx_room, (u32) (dws->fifo_len - rxtx_gap));  } -static int null_reader(struct dw_spi *dws) +/* Return the max entries we should read out of rx fifo */ +static inline u32 rx_max(struct dw_spi *dws)  { -	u8 n_bytes = dws->n_bytes; +	u32 rx_left = (dws->rx_end - dws->rx) / dws->n_bytes; -	while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT) -		&& (dws->rx < dws->rx_end)) { -		dw_readw(dws, dr); -		dws->rx += n_bytes; -	} -	wait_till_not_busy(dws); -	return dws->rx == dws->rx_end; +	return min(rx_left, (u32)dw_readw(dws, rxflr));  } -static int u8_writer(struct dw_spi *dws) +static void dw_writer(struct dw_spi *dws)  { -	if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL) -		|| (dws->tx == dws->tx_end)) -		return 0; +	u32 max = tx_max(dws); +	u16 txw = 0; -	dw_writew(dws, dr, *(u8 *)(dws->tx)); -	++dws->tx; - -	wait_till_not_busy(dws); -	return 1; -} - -static int u8_reader(struct dw_spi *dws) -{ -	while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT) -		&& (dws->rx < dws->rx_end)) { -		*(u8 *)(dws->rx) = dw_readw(dws, dr); -		++dws->rx; +	while (max--) { +		/* Set the tx word if the transfer's original "tx" is not null */ +		if (dws->tx_end - dws->len) { +			if (dws->n_bytes == 1) +				txw = *(u8 *)(dws->tx); +			else +				txw = *(u16 *)(dws->tx); +		} +		dw_writew(dws, dr, txw); +		dws->tx += dws->n_bytes;  	} - -	wait_till_not_busy(dws); -	return dws->rx == dws->rx_end;  } -static int u16_writer(struct dw_spi *dws) +static void dw_reader(struct dw_spi *dws)  { -	if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL) -		|| (dws->tx == dws->tx_end)) -		return 0; +	u32 max = rx_max(dws); +	u16 rxw; -	dw_writew(dws, dr, *(u16 *)(dws->tx)); -	dws->tx += 2; - -	wait_till_not_busy(dws); -	return 1; -} - -static int u16_reader(struct dw_spi *dws) -{ -	u16 temp; - -	while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT) -		&& (dws->rx < dws->rx_end)) { -		temp = dw_readw(dws, dr); -		*(u16 *)(dws->rx) = temp; -		dws->rx += 2; +	while (max--) { +		rxw = dw_readw(dws, dr); +		/* Care rx only if the transfer's original "rx" is not null */ +		if (dws->rx_end - dws->len) { +			if (dws->n_bytes == 1) +				*(u8 *)(dws->rx) = rxw; +			else +				*(u16 *)(dws->rx) = rxw; +		} +		dws->rx += dws->n_bytes;  	} - -	wait_till_not_busy(dws); -	return dws->rx == dws->rx_end;  }  static void *next_transfer(struct dw_spi *dws) @@ -334,8 +295,7 @@ static void giveback(struct dw_spi *dws)  static void int_error_stop(struct dw_spi *dws, const char *msg)  { -	/* Stop and reset hw */ -	flush(dws); +	/* Stop the hw */  	spi_enable_chip(dws, 0);  	dev_err(&dws->master->dev, "%s\n", msg); @@ -362,35 +322,28 @@ EXPORT_SYMBOL_GPL(dw_spi_xfer_done);  static irqreturn_t interrupt_transfer(struct dw_spi *dws)  { -	u16 irq_status, irq_mask = 0x3f; -	u32 int_level = dws->fifo_len / 2; -	u32 left; +	u16 irq_status = dw_readw(dws, isr); -	irq_status = dw_readw(dws, isr) & irq_mask;  	/* Error handling */  	if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) {  		dw_readw(dws, txoicr);  		dw_readw(dws, rxoicr);  		dw_readw(dws, rxuicr); -		int_error_stop(dws, "interrupt_transfer: fifo overrun"); +		int_error_stop(dws, "interrupt_transfer: fifo overrun/underrun");  		return IRQ_HANDLED;  	} +	dw_reader(dws); +	if (dws->rx_end == dws->rx) { +		spi_mask_intr(dws, SPI_INT_TXEI); +		dw_spi_xfer_done(dws); +		return IRQ_HANDLED; +	}  	if (irq_status & SPI_INT_TXEI) {  		spi_mask_intr(dws, SPI_INT_TXEI); - -		left = (dws->tx_end - dws->tx) / dws->n_bytes; -		left = (left > int_level) ? int_level : left; - -		while (left--) -			dws->write(dws); -		dws->read(dws); - -		/* Re-enable the IRQ if there is still data left to tx */ -		if (dws->tx_end > dws->tx) -			spi_umask_intr(dws, SPI_INT_TXEI); -		else -			dw_spi_xfer_done(dws); +		dw_writer(dws); +		/* Enable TX irq always, it will be disabled when RX finished */ +		spi_umask_intr(dws, SPI_INT_TXEI);  	}  	return IRQ_HANDLED; @@ -399,15 +352,13 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)  static irqreturn_t dw_spi_irq(int irq, void *dev_id)  {  	struct dw_spi *dws = dev_id; -	u16 irq_status, irq_mask = 0x3f; +	u16 irq_status = dw_readw(dws, isr) & 0x3f; -	irq_status = dw_readw(dws, isr) & irq_mask;  	if (!irq_status)  		return IRQ_NONE;  	if (!dws->cur_msg) {  		spi_mask_intr(dws, SPI_INT_TXEI); -		/* Never fail */  		return IRQ_HANDLED;  	} @@ -417,13 +368,11 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id)  /* Must be called inside pump_transfers() */  static void poll_transfer(struct dw_spi *dws)  { -	while (dws->write(dws)) -		dws->read(dws); -	/* -	 * There is a possibility that the last word of a transaction -	 * will be lost if data is not ready. Re-read to solve this issue. -	 */ -	dws->read(dws); +	do { +		dw_writer(dws); +		dw_reader(dws); +		cpu_relax(); +	} while (dws->rx_end > dws->rx);  	dw_spi_xfer_done(dws);  } @@ -483,8 +432,6 @@ static void pump_transfers(unsigned long data)  	dws->tx_end = dws->tx + transfer->len;  	dws->rx = transfer->rx_buf;  	dws->rx_end = dws->rx + transfer->len; -	dws->write = dws->tx ? chip->write : null_writer; -	dws->read = dws->rx ? chip->read : null_reader;  	dws->cs_change = transfer->cs_change;  	dws->len = dws->cur_transfer->len;  	if (chip != dws->prev_chip) @@ -518,20 +465,8 @@ static void pump_transfers(unsigned long data)  		switch (bits) {  		case 8: -			dws->n_bytes = 1; -			dws->dma_width = 1; -			dws->read = (dws->read != null_reader) ? -					u8_reader : null_reader; -			dws->write = (dws->write != null_writer) ? -					u8_writer : null_writer; -			break;  		case 16: -			dws->n_bytes = 2; -			dws->dma_width = 2; -			dws->read = (dws->read != null_reader) ? -					u16_reader : null_reader; -			dws->write = (dws->write != null_writer) ? -					u16_writer : null_writer; +			dws->n_bytes = dws->dma_width = bits >> 3;  			break;  		default:  			printk(KERN_ERR "MRST SPI0: unsupported bits:" @@ -575,7 +510,7 @@ static void pump_transfers(unsigned long data)  		txint_level = dws->fifo_len / 2;  		txint_level = (templen > txint_level) ? txint_level : templen; -		imask |= SPI_INT_TXEI; +		imask |= SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI;  		dws->transfer_handler = interrupt_transfer;  	} @@ -733,13 +668,9 @@ static int dw_spi_setup(struct spi_device *spi)  	if (spi->bits_per_word <= 8) {  		chip->n_bytes = 1;  		chip->dma_width = 1; -		chip->read = u8_reader; -		chip->write = u8_writer;  	} else if (spi->bits_per_word <= 16) {  		chip->n_bytes = 2;  		chip->dma_width = 2; -		chip->read = u16_reader; -		chip->write = u16_writer;  	} else {  		/* Never take >16b case for MRST SPIC */  		dev_err(&spi->dev, "invalid wordsize\n"); @@ -851,7 +782,6 @@ static void spi_hw_init(struct dw_spi *dws)  	spi_enable_chip(dws, 0);  	spi_mask_intr(dws, 0xff);  	spi_enable_chip(dws, 1); -	flush(dws);  	/*  	 * Try to detect the FIFO depth if not set by interface driver,  |