diff options
Diffstat (limited to 'drivers/spi/spi-imx.c')
| -rw-r--r-- | drivers/spi/spi-imx.c | 162 | 
1 files changed, 101 insertions, 61 deletions
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index d3b21faf6b1f..08dd3a31a3e5 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -94,8 +94,7 @@ struct spi_imx_data {  	void *rx_buf;  	const void *tx_buf;  	unsigned int txfifo; /* number of words pushed in tx FIFO */ -	unsigned int dynamic_burst, read_u32; -	unsigned int word_mask; +	unsigned int dynamic_burst;  	/* Slave mode */  	bool slave_mode; @@ -140,6 +139,8 @@ static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx)		\  		*(type *)spi_imx->rx_buf = val;				\  		spi_imx->rx_buf += sizeof(type);			\  	}								\ +									\ +	spi_imx->remainder -= sizeof(type);				\  }  #define MXC_SPI_BUF_TX(type)						\ @@ -203,7 +204,12 @@ out:  static int spi_imx_bytes_per_word(const int bits_per_word)  { -	return DIV_ROUND_UP(bits_per_word, BITS_PER_BYTE); +	if (bits_per_word <= 8) +		return 1; +	else if (bits_per_word <= 16) +		return 2; +	else +		return 4;  }  static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, @@ -220,17 +226,11 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,  	bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word); -	if (bytes_per_word != 1 && bytes_per_word != 2 && bytes_per_word != 4) -		return false; -  	for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {  		if (!(transfer->len % (i * bytes_per_word)))  			break;  	} -	if (i == 0) -		return false; -  	spi_imx->wml = i;  	spi_imx->dynamic_burst = 0; @@ -291,26 +291,39 @@ static void spi_imx_buf_rx_swap_u32(struct spi_imx_data *spi_imx)  		else if (bytes_per_word == 2)  			val = (val << 16) | (val >> 16);  #endif -		val &= spi_imx->word_mask;  		*(u32 *)spi_imx->rx_buf = val;  		spi_imx->rx_buf += sizeof(u32);  	} + +	spi_imx->remainder -= sizeof(u32);  }  static void spi_imx_buf_rx_swap(struct spi_imx_data *spi_imx)  { -	unsigned int bytes_per_word; +	int unaligned; +	u32 val; -	bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word); -	if (spi_imx->read_u32) { +	unaligned = spi_imx->remainder % 4; + +	if (!unaligned) {  		spi_imx_buf_rx_swap_u32(spi_imx);  		return;  	} -	if (bytes_per_word == 1) -		spi_imx_buf_rx_u8(spi_imx); -	else if (bytes_per_word == 2) +	if (spi_imx_bytes_per_word(spi_imx->bits_per_word) == 2) {  		spi_imx_buf_rx_u16(spi_imx); +		return; +	} + +	val = readl(spi_imx->base + MXC_CSPIRXDATA); + +	while (unaligned--) { +		if (spi_imx->rx_buf) { +			*(u8 *)spi_imx->rx_buf = (val >> (8 * unaligned)) & 0xff; +			spi_imx->rx_buf++; +		} +		spi_imx->remainder--; +	}  }  static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx) @@ -322,7 +335,6 @@ static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx)  	if (spi_imx->tx_buf) {  		val = *(u32 *)spi_imx->tx_buf; -		val &= spi_imx->word_mask;  		spi_imx->tx_buf += sizeof(u32);  	} @@ -340,40 +352,30 @@ static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx)  static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)  { -	u32 ctrl, val; -	unsigned int bytes_per_word; +	int unaligned; +	u32 val = 0; -	if (spi_imx->count == spi_imx->remainder) { -		ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL); -		ctrl &= ~MX51_ECSPI_CTRL_BL_MASK; -		if (spi_imx->count > MX51_ECSPI_CTRL_MAX_BURST) { -			spi_imx->remainder = spi_imx->count % -					     MX51_ECSPI_CTRL_MAX_BURST; -			val = MX51_ECSPI_CTRL_MAX_BURST * 8 - 1; -		} else if (spi_imx->count >= sizeof(u32)) { -			spi_imx->remainder = spi_imx->count % sizeof(u32); -			val = (spi_imx->count - spi_imx->remainder) * 8 - 1; -		} else { -			spi_imx->remainder = 0; -			val = spi_imx->bits_per_word - 1; -			spi_imx->read_u32 = 0; -		} +	unaligned = spi_imx->count % 4; -		ctrl |= (val << MX51_ECSPI_CTRL_BL_OFFSET); -		writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); +	if (!unaligned) { +		spi_imx_buf_tx_swap_u32(spi_imx); +		return;  	} -	if (spi_imx->count >= sizeof(u32)) { -		spi_imx_buf_tx_swap_u32(spi_imx); +	if (spi_imx_bytes_per_word(spi_imx->bits_per_word) == 2) { +		spi_imx_buf_tx_u16(spi_imx);  		return;  	} -	bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word); +	while (unaligned--) { +		if (spi_imx->tx_buf) { +			val |= *(u8 *)spi_imx->tx_buf << (8 * unaligned); +			spi_imx->tx_buf++; +		} +		spi_imx->count--; +	} -	if (bytes_per_word == 1) -		spi_imx_buf_tx_u8(spi_imx); -	else if (bytes_per_word == 2) -		spi_imx_buf_tx_u16(spi_imx); +	writel(val, spi_imx->base + MXC_CSPITXDATA);  }  static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx) @@ -392,6 +394,8 @@ static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx)  		spi_imx->rx_buf += n_bytes;  		spi_imx->slave_burst -= n_bytes;  	} + +	spi_imx->remainder -= sizeof(u32);  }  static void mx53_ecspi_tx_slave(struct spi_imx_data *spi_imx) @@ -1001,12 +1005,52 @@ static void spi_imx_chipselect(struct spi_device *spi, int is_active)  	gpio_set_value(spi->cs_gpio, dev_is_lowactive ^ active);  } +static void spi_imx_set_burst_len(struct spi_imx_data *spi_imx, int n_bits) +{ +	u32 ctrl; + +	ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL); +	ctrl &= ~MX51_ECSPI_CTRL_BL_MASK; +	ctrl |= ((n_bits - 1) << MX51_ECSPI_CTRL_BL_OFFSET); +	writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); +} +  static void spi_imx_push(struct spi_imx_data *spi_imx)  { +	unsigned int burst_len, fifo_words; + +	if (spi_imx->dynamic_burst) +		fifo_words = 4; +	else +		fifo_words = spi_imx_bytes_per_word(spi_imx->bits_per_word); +	/* +	 * Reload the FIFO when the remaining bytes to be transferred in the +	 * current burst is 0. This only applies when bits_per_word is a +	 * multiple of 8. +	 */ +	if (!spi_imx->remainder) { +		if (spi_imx->dynamic_burst) { + +			/* We need to deal unaligned data first */ +			burst_len = spi_imx->count % MX51_ECSPI_CTRL_MAX_BURST; + +			if (!burst_len) +				burst_len = MX51_ECSPI_CTRL_MAX_BURST; + +			spi_imx_set_burst_len(spi_imx, burst_len * 8); + +			spi_imx->remainder = burst_len; +		} else { +			spi_imx->remainder = fifo_words; +		} +	} +  	while (spi_imx->txfifo < spi_imx->devtype_data->fifo_size) {  		if (!spi_imx->count)  			break; -		if (spi_imx->txfifo && (spi_imx->count == spi_imx->remainder)) +		if (spi_imx->dynamic_burst && +		    spi_imx->txfifo >=  DIV_ROUND_UP(spi_imx->remainder, +						     fifo_words))  			break;  		spi_imx->tx(spi_imx);  		spi_imx->txfifo++; @@ -1102,27 +1146,20 @@ static int spi_imx_setupxfer(struct spi_device *spi,  	spi_imx->bits_per_word = t->bits_per_word;  	spi_imx->speed_hz  = t->speed_hz; -	/* Initialize the functions for transfer */ -	if (spi_imx->devtype_data->dynamic_burst && !spi_imx->slave_mode) { -		u32 mask; - -		spi_imx->dynamic_burst = 0; -		spi_imx->remainder = 0; -		spi_imx->read_u32  = 1; +	/* +	 * Initialize the functions for transfer. To transfer non byte-aligned +	 * words, we have to use multiple word-size bursts, we can't use +	 * dynamic_burst in that case. +	 */ +	if (spi_imx->devtype_data->dynamic_burst && !spi_imx->slave_mode && +	    (spi_imx->bits_per_word == 8 || +	    spi_imx->bits_per_word == 16 || +	    spi_imx->bits_per_word == 32)) { -		mask = (1 << spi_imx->bits_per_word) - 1;  		spi_imx->rx = spi_imx_buf_rx_swap;  		spi_imx->tx = spi_imx_buf_tx_swap;  		spi_imx->dynamic_burst = 1; -		spi_imx->remainder = t->len; - -		if (spi_imx->bits_per_word <= 8) -			spi_imx->word_mask = mask << 24 | mask << 16 -					     | mask << 8 | mask; -		else if (spi_imx->bits_per_word <= 16) -			spi_imx->word_mask = mask << 16 | mask; -		else -			spi_imx->word_mask = mask; +  	} else {  		if (spi_imx->bits_per_word <= 8) {  			spi_imx->rx = spi_imx_buf_rx_u8; @@ -1134,6 +1171,7 @@ static int spi_imx_setupxfer(struct spi_device *spi,  			spi_imx->rx = spi_imx_buf_rx_u32;  			spi_imx->tx = spi_imx_buf_tx_u32;  		} +		spi_imx->dynamic_burst = 0;  	}  	if (spi_imx_can_dma(spi_imx->bitbang.master, spi, t)) @@ -1317,6 +1355,7 @@ static int spi_imx_pio_transfer(struct spi_device *spi,  	spi_imx->rx_buf = transfer->rx_buf;  	spi_imx->count = transfer->len;  	spi_imx->txfifo = 0; +	spi_imx->remainder = 0;  	reinit_completion(&spi_imx->xfer_done); @@ -1354,6 +1393,7 @@ static int spi_imx_pio_transfer_slave(struct spi_device *spi,  	spi_imx->rx_buf = transfer->rx_buf;  	spi_imx->count = transfer->len;  	spi_imx->txfifo = 0; +	spi_imx->remainder = 0;  	reinit_completion(&spi_imx->xfer_done);  	spi_imx->slave_aborted = false;  |