diff options
Diffstat (limited to 'drivers/spi/spi-sirf.c')
| -rw-r--r-- | drivers/spi/spi-sirf.c | 388 | 
1 files changed, 226 insertions, 162 deletions
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index a1f21b74773..95ac276eaaf 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -10,6 +10,7 @@  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/clk.h> +#include <linux/completion.h>  #include <linux/interrupt.h>  #include <linux/io.h>  #include <linux/of.h> @@ -22,7 +23,6 @@  #include <linux/dmaengine.h>  #include <linux/dma-direction.h>  #include <linux/dma-mapping.h> -#include <linux/sirfsoc_dma.h>  #define DRIVER_NAME "sirfsoc_spi" @@ -86,6 +86,7 @@  #define SIRFSOC_SPI_TX_DONE		BIT(1)  #define SIRFSOC_SPI_RX_OFLOW		BIT(2)  #define SIRFSOC_SPI_TX_UFLOW		BIT(3) +#define SIRFSOC_SPI_RX_IO_DMA		BIT(4)  #define SIRFSOC_SPI_RX_FIFO_FULL	BIT(6)  #define SIRFSOC_SPI_TXFIFO_EMPTY	BIT(7)  #define SIRFSOC_SPI_RXFIFO_THD_REACH	BIT(8) @@ -132,6 +133,8 @@  #define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \  	ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE)) +#define SIRFSOC_MAX_CMD_BYTES	4 +  struct sirfsoc_spi {  	struct spi_bitbang bitbang;  	struct completion rx_done; @@ -162,6 +165,12 @@ struct sirfsoc_spi {  	void *dummypage;  	int word_width; /* in bytes */ +	/* +	 * if tx size is not more than 4 and rx size is NULL, use +	 * command model +	 */ +	bool	tx_by_cmd; +  	int chipselect[0];  }; @@ -257,35 +266,34 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)  {  	struct sirfsoc_spi *sspi = dev_id;  	u32 spi_stat = readl(sspi->base + SIRFSOC_SPI_INT_STATUS); - -	writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS); +	if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) { +		complete(&sspi->tx_done); +		writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); +		writel(SIRFSOC_SPI_INT_MASK_ALL, +				sspi->base + SIRFSOC_SPI_INT_STATUS); +		return IRQ_HANDLED; +	}  	/* Error Conditions */  	if (spi_stat & SIRFSOC_SPI_RX_OFLOW ||  			spi_stat & SIRFSOC_SPI_TX_UFLOW) { +		complete(&sspi->tx_done);  		complete(&sspi->rx_done);  		writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); +		writel(SIRFSOC_SPI_INT_MASK_ALL, +				sspi->base + SIRFSOC_SPI_INT_STATUS); +		return IRQ_HANDLED;  	} +	if (spi_stat & SIRFSOC_SPI_TXFIFO_EMPTY) +		complete(&sspi->tx_done); +	while (!(readl(sspi->base + SIRFSOC_SPI_INT_STATUS) & +		SIRFSOC_SPI_RX_IO_DMA)) +		cpu_relax(); +	complete(&sspi->rx_done); +	writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); +	writel(SIRFSOC_SPI_INT_MASK_ALL, +			sspi->base + SIRFSOC_SPI_INT_STATUS); -	if (spi_stat & (SIRFSOC_SPI_FRM_END -			| SIRFSOC_SPI_RXFIFO_THD_REACH)) -		while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS) -				& SIRFSOC_SPI_FIFO_EMPTY)) && -				sspi->left_rx_word) -			sspi->rx_word(sspi); - -	if (spi_stat & (SIRFSOC_SPI_FIFO_EMPTY -			| SIRFSOC_SPI_TXFIFO_THD_REACH)) -		while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS) -				& SIRFSOC_SPI_FIFO_FULL)) && -				sspi->left_tx_word) -			sspi->tx_word(sspi); - -	/* Received all words */ -	if ((sspi->left_rx_word == 0) && (sspi->left_tx_word == 0)) { -		complete(&sspi->rx_done); -		writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); -	}  	return IRQ_HANDLED;  } @@ -296,31 +304,51 @@ static void spi_sirfsoc_dma_fini_callback(void *data)  	complete(dma_complete);  } -static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) +static int spi_sirfsoc_cmd_transfer(struct spi_device *spi, +	struct spi_transfer *t)  {  	struct sirfsoc_spi *sspi;  	int timeout = t->len * 10; +	u32 cmd; +  	sspi = spi_master_get_devdata(spi->master); +	memcpy(&cmd, sspi->tx, t->len); +	if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST)) +		cmd = cpu_to_be32(cmd) >> +			((SIRFSOC_MAX_CMD_BYTES - t->len) * 8); +	if (sspi->word_width == 2 && t->len == 4 && +			(!(spi->mode & SPI_LSB_FIRST))) +		cmd = ((cmd & 0xffff) << 16) | (cmd >> 16); +	writel(cmd, sspi->base + SIRFSOC_SPI_CMD); +	writel(SIRFSOC_SPI_FRM_END_INT_EN, +		sspi->base + SIRFSOC_SPI_INT_EN); +	writel(SIRFSOC_SPI_CMD_TX_EN, +		sspi->base + SIRFSOC_SPI_TX_RX_EN); +	if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { +		dev_err(&spi->dev, "cmd transfer timeout\n"); +		return 0; +	} -	sspi->tx = t->tx_buf ? t->tx_buf : sspi->dummypage; -	sspi->rx = t->rx_buf ? t->rx_buf : sspi->dummypage; -	sspi->left_tx_word = sspi->left_rx_word = t->len / sspi->word_width; -	INIT_COMPLETION(sspi->rx_done); -	INIT_COMPLETION(sspi->tx_done); +	return t->len; +} -	writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); +static void spi_sirfsoc_dma_transfer(struct spi_device *spi, +	struct spi_transfer *t) +{ +	struct sirfsoc_spi *sspi; +	struct dma_async_tx_descriptor *rx_desc, *tx_desc; +	int timeout = t->len * 10; -	if (sspi->left_tx_word == 1) { -		writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | -			SIRFSOC_SPI_ENA_AUTO_CLR, -			sspi->base + SIRFSOC_SPI_CTRL); -		writel(0, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); -		writel(0, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN); -	} else if ((sspi->left_tx_word > 1) && (sspi->left_tx_word < -				SIRFSOC_SPI_DAT_FRM_LEN_MAX)) { +	sspi = spi_master_get_devdata(spi->master); +	writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP); +	writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP); +	writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); +	writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); +	writel(0, sspi->base + SIRFSOC_SPI_INT_EN); +	writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); +	if (sspi->left_tx_word < SIRFSOC_SPI_DAT_FRM_LEN_MAX) {  		writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | -				SIRFSOC_SPI_MUL_DAT_MODE | -				SIRFSOC_SPI_ENA_AUTO_CLR, +			SIRFSOC_SPI_ENA_AUTO_CLR | SIRFSOC_SPI_MUL_DAT_MODE,  			sspi->base + SIRFSOC_SPI_CTRL);  		writel(sspi->left_tx_word - 1,  				sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); @@ -332,76 +360,122 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t)  		writel(0, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN);  		writel(0, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN);  	} - -	writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP); -	writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP); -	writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); -	writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); - -	if (IS_DMA_VALID(t)) { -		struct dma_async_tx_descriptor *rx_desc, *tx_desc; - -		sspi->dst_start = dma_map_single(&spi->dev, sspi->rx, t->len, DMA_FROM_DEVICE); -		rx_desc = dmaengine_prep_slave_single(sspi->rx_chan, -			sspi->dst_start, t->len, DMA_DEV_TO_MEM, -			DMA_PREP_INTERRUPT | DMA_CTRL_ACK); -		rx_desc->callback = spi_sirfsoc_dma_fini_callback; -		rx_desc->callback_param = &sspi->rx_done; - -		sspi->src_start = dma_map_single(&spi->dev, (void *)sspi->tx, t->len, DMA_TO_DEVICE); -		tx_desc = dmaengine_prep_slave_single(sspi->tx_chan, -			sspi->src_start, t->len, DMA_MEM_TO_DEV, -			DMA_PREP_INTERRUPT | DMA_CTRL_ACK); -		tx_desc->callback = spi_sirfsoc_dma_fini_callback; -		tx_desc->callback_param = &sspi->tx_done; - -		dmaengine_submit(tx_desc); -		dmaengine_submit(rx_desc); -		dma_async_issue_pending(sspi->tx_chan); -		dma_async_issue_pending(sspi->rx_chan); -	} else { -		/* Send the first word to trigger the whole tx/rx process */ -		sspi->tx_word(sspi); - -		writel(SIRFSOC_SPI_RX_OFLOW_INT_EN | SIRFSOC_SPI_TX_UFLOW_INT_EN | -			SIRFSOC_SPI_RXFIFO_THD_INT_EN | SIRFSOC_SPI_TXFIFO_THD_INT_EN | -			SIRFSOC_SPI_FRM_END_INT_EN | SIRFSOC_SPI_RXFIFO_FULL_INT_EN | -			SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN, sspi->base + SIRFSOC_SPI_INT_EN); -	} - -	writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, sspi->base + SIRFSOC_SPI_TX_RX_EN); - -	if (!IS_DMA_VALID(t)) { /* for PIO */ -		if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0) -			dev_err(&spi->dev, "transfer timeout\n"); -	} else if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0) { +	sspi->dst_start = dma_map_single(&spi->dev, sspi->rx, t->len, +					(t->tx_buf != t->rx_buf) ? +					DMA_FROM_DEVICE : DMA_BIDIRECTIONAL); +	rx_desc = dmaengine_prep_slave_single(sspi->rx_chan, +		sspi->dst_start, t->len, DMA_DEV_TO_MEM, +		DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +	rx_desc->callback = spi_sirfsoc_dma_fini_callback; +	rx_desc->callback_param = &sspi->rx_done; + +	sspi->src_start = dma_map_single(&spi->dev, (void *)sspi->tx, t->len, +					(t->tx_buf != t->rx_buf) ? +					DMA_TO_DEVICE : DMA_BIDIRECTIONAL); +	tx_desc = dmaengine_prep_slave_single(sspi->tx_chan, +		sspi->src_start, t->len, DMA_MEM_TO_DEV, +		DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +	tx_desc->callback = spi_sirfsoc_dma_fini_callback; +	tx_desc->callback_param = &sspi->tx_done; + +	dmaengine_submit(tx_desc); +	dmaengine_submit(rx_desc); +	dma_async_issue_pending(sspi->tx_chan); +	dma_async_issue_pending(sspi->rx_chan); +	writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, +			sspi->base + SIRFSOC_SPI_TX_RX_EN); +	if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0) {  		dev_err(&spi->dev, "transfer timeout\n");  		dmaengine_terminate_all(sspi->rx_chan);  	} else  		sspi->left_rx_word = 0; -  	/*  	 * we only wait tx-done event if transferring by DMA. for PIO,  	 * we get rx data by writing tx data, so if rx is done, tx has  	 * done earlier  	 */ -	if (IS_DMA_VALID(t)) { -		if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { -			dev_err(&spi->dev, "transfer timeout\n"); -			dmaengine_terminate_all(sspi->tx_chan); -		} -	} - -	if (IS_DMA_VALID(t)) { -		dma_unmap_single(&spi->dev, sspi->src_start, t->len, DMA_TO_DEVICE); -		dma_unmap_single(&spi->dev, sspi->dst_start, t->len, DMA_FROM_DEVICE); +	if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { +		dev_err(&spi->dev, "transfer timeout\n"); +		dmaengine_terminate_all(sspi->tx_chan);  	} - +	dma_unmap_single(&spi->dev, sspi->src_start, t->len, DMA_TO_DEVICE); +	dma_unmap_single(&spi->dev, sspi->dst_start, t->len, DMA_FROM_DEVICE);  	/* TX, RX FIFO stop */  	writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP);  	writel(0, sspi->base + SIRFSOC_SPI_TXFIFO_OP); -	writel(0, sspi->base + SIRFSOC_SPI_TX_RX_EN); -	writel(0, sspi->base + SIRFSOC_SPI_INT_EN); +	if (sspi->left_tx_word >= SIRFSOC_SPI_DAT_FRM_LEN_MAX) +		writel(0, sspi->base + SIRFSOC_SPI_TX_RX_EN); +} + +static void spi_sirfsoc_pio_transfer(struct spi_device *spi, +		struct spi_transfer *t) +{ +	struct sirfsoc_spi *sspi; +	int timeout = t->len * 10; + +	sspi = spi_master_get_devdata(spi->master); +	do { +		writel(SIRFSOC_SPI_FIFO_RESET, +			sspi->base + SIRFSOC_SPI_RXFIFO_OP); +		writel(SIRFSOC_SPI_FIFO_RESET, +			sspi->base + SIRFSOC_SPI_TXFIFO_OP); +		writel(SIRFSOC_SPI_FIFO_START, +			sspi->base + SIRFSOC_SPI_RXFIFO_OP); +		writel(SIRFSOC_SPI_FIFO_START, +			sspi->base + SIRFSOC_SPI_TXFIFO_OP); +		writel(0, sspi->base + SIRFSOC_SPI_INT_EN); +		writel(SIRFSOC_SPI_INT_MASK_ALL, +			sspi->base + SIRFSOC_SPI_INT_STATUS); +		writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | +			SIRFSOC_SPI_MUL_DAT_MODE | SIRFSOC_SPI_ENA_AUTO_CLR, +			sspi->base + SIRFSOC_SPI_CTRL); +		writel(min(sspi->left_tx_word, (u32)(256 / sspi->word_width)) +				- 1, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); +		writel(min(sspi->left_rx_word, (u32)(256 / sspi->word_width)) +				- 1, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN); +		while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS) +			& SIRFSOC_SPI_FIFO_FULL)) && sspi->left_tx_word) +			sspi->tx_word(sspi); +		writel(SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN | +			SIRFSOC_SPI_TX_UFLOW_INT_EN | +			SIRFSOC_SPI_RX_OFLOW_INT_EN, +			sspi->base + SIRFSOC_SPI_INT_EN); +		writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, +			sspi->base + SIRFSOC_SPI_TX_RX_EN); +		if (!wait_for_completion_timeout(&sspi->tx_done, timeout) || +			!wait_for_completion_timeout(&sspi->rx_done, timeout)) { +			dev_err(&spi->dev, "transfer timeout\n"); +			break; +		} +		while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS) +			& SIRFSOC_SPI_FIFO_EMPTY)) && sspi->left_rx_word) +			sspi->rx_word(sspi); +		writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP); +		writel(0, sspi->base + SIRFSOC_SPI_TXFIFO_OP); +	} while (sspi->left_tx_word != 0 || sspi->left_rx_word != 0); +} + +static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) +{ +	struct sirfsoc_spi *sspi; +	sspi = spi_master_get_devdata(spi->master); + +	sspi->tx = t->tx_buf ? t->tx_buf : sspi->dummypage; +	sspi->rx = t->rx_buf ? t->rx_buf : sspi->dummypage; +	sspi->left_tx_word = sspi->left_rx_word = t->len / sspi->word_width; +	reinit_completion(&sspi->rx_done); +	reinit_completion(&sspi->tx_done); +	/* +	 * in the transfer, if transfer data using command register with rx_buf +	 * null, just fill command data into command register and wait for its +	 * completion. +	 */ +	if (sspi->tx_by_cmd) +		spi_sirfsoc_cmd_transfer(spi, t); +	else if (IS_DMA_VALID(t)) +		spi_sirfsoc_dma_transfer(spi, t); +	else +		spi_sirfsoc_pio_transfer(spi, t);  	return t->len - sspi->left_rx_word * sspi->word_width;  } @@ -429,7 +503,16 @@ static void spi_sirfsoc_chipselect(struct spi_device *spi, int value)  		writel(regval, sspi->base + SIRFSOC_SPI_CTRL);  	} else {  		int gpio = sspi->chipselect[spi->chip_select]; -		gpio_direction_output(gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); +		switch (value) { +		case BITBANG_CS_ACTIVE: +			gpio_direction_output(gpio, +					spi->mode & SPI_CS_HIGH ? 1 : 0); +			break; +		case BITBANG_CS_INACTIVE: +			gpio_direction_output(gpio, +					spi->mode & SPI_CS_HIGH ? 0 : 1); +			break; +		}  	}  } @@ -459,38 +542,30 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)  		regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_8;  		sspi->rx_word = spi_sirfsoc_rx_word_u8;  		sspi->tx_word = spi_sirfsoc_tx_word_u8; -		txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | -					SIRFSOC_SPI_FIFO_WIDTH_BYTE; -		rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | -					SIRFSOC_SPI_FIFO_WIDTH_BYTE; -		sspi->word_width = 1;  		break;  	case 12:  	case 16: -		regval |= (bits_per_word ==  12) ? SIRFSOC_SPI_TRAN_DAT_FORMAT_12 : +		regval |= (bits_per_word ==  12) ? +			SIRFSOC_SPI_TRAN_DAT_FORMAT_12 :  			SIRFSOC_SPI_TRAN_DAT_FORMAT_16;  		sspi->rx_word = spi_sirfsoc_rx_word_u16;  		sspi->tx_word = spi_sirfsoc_tx_word_u16; -		txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | -					SIRFSOC_SPI_FIFO_WIDTH_WORD; -		rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | -					SIRFSOC_SPI_FIFO_WIDTH_WORD; -		sspi->word_width = 2;  		break;  	case 32:  		regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_32;  		sspi->rx_word = spi_sirfsoc_rx_word_u32;  		sspi->tx_word = spi_sirfsoc_tx_word_u32; -		txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | -					SIRFSOC_SPI_FIFO_WIDTH_DWORD; -		rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | -					SIRFSOC_SPI_FIFO_WIDTH_DWORD; -		sspi->word_width = 4;  		break;  	default:  		BUG();  	} +	sspi->word_width = DIV_ROUND_UP(bits_per_word, 8); +	txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | +					   sspi->word_width; +	rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | +					   sspi->word_width; +  	if (!(spi->mode & SPI_CS_HIGH))  		regval |= SIRFSOC_SPI_CS_IDLE_STAT;  	if (!(spi->mode & SPI_LSB_FIRST)) @@ -499,8 +574,8 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)  		regval |= SIRFSOC_SPI_CLK_IDLE_STAT;  	/* -	 * Data should be driven at least 1/2 cycle before the fetch edge to make -	 * sure that data gets stable at the fetch edge. +	 * Data should be driven at least 1/2 cycle before the fetch edge +	 * to make sure that data gets stable at the fetch edge.  	 */  	if (((spi->mode & SPI_CPOL) && (spi->mode & SPI_CPHA)) ||  	    (!(spi->mode & SPI_CPOL) && !(spi->mode & SPI_CPHA))) @@ -519,16 +594,32 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)  	writel(txfifo_ctrl, sspi->base + SIRFSOC_SPI_TXFIFO_CTRL);  	writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL); +	if (t && t->tx_buf && !t->rx_buf && (t->len <= SIRFSOC_MAX_CMD_BYTES)) { +		regval |= (SIRFSOC_SPI_CMD_BYTE_NUM((t->len - 1)) | +				SIRFSOC_SPI_CMD_MODE); +		sspi->tx_by_cmd = true; +	} else { +		regval &= ~SIRFSOC_SPI_CMD_MODE; +		sspi->tx_by_cmd = false; +	} +	/* +	 * set spi controller in RISC chipselect mode, we are controlling CS by +	 * software BITBANG_CS_ACTIVE and BITBANG_CS_INACTIVE. +	 */ +	regval |= SIRFSOC_SPI_CS_IO_MODE;  	writel(regval, sspi->base + SIRFSOC_SPI_CTRL);  	if (IS_DMA_VALID(t)) {  		/* Enable DMA mode for RX, TX */  		writel(0, sspi->base + SIRFSOC_SPI_TX_DMA_IO_CTRL); -		writel(SIRFSOC_SPI_RX_DMA_FLUSH, sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL); +		writel(SIRFSOC_SPI_RX_DMA_FLUSH, +			sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL);  	} else {  		/* Enable IO mode for RX, TX */ -		writel(SIRFSOC_SPI_IO_MODE_SEL, sspi->base + SIRFSOC_SPI_TX_DMA_IO_CTRL); -		writel(SIRFSOC_SPI_IO_MODE_SEL, sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL); +		writel(SIRFSOC_SPI_IO_MODE_SEL, +			sspi->base + SIRFSOC_SPI_TX_DMA_IO_CTRL); +		writel(SIRFSOC_SPI_IO_MODE_SEL, +			sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL);  	}  	return 0; @@ -536,16 +627,9 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)  static int spi_sirfsoc_setup(struct spi_device *spi)  { -	struct sirfsoc_spi *sspi; -  	if (!spi->max_speed_hz)  		return -EINVAL; -	sspi = spi_master_get_devdata(spi->master); - -	if (!spi->bits_per_word) -		spi->bits_per_word = 8; -  	return spi_sirfsoc_setup_transfer(spi, NULL);  } @@ -555,8 +639,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)  	struct spi_master *master;  	struct resource *mem_res;  	int num_cs, cs_gpio, irq; -	u32 rx_dma_ch, tx_dma_ch; -	dma_cap_mask_t dma_cap_mask;  	int i;  	int ret; @@ -567,21 +649,8 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)  		goto err_cs;  	} -	ret = of_property_read_u32(pdev->dev.of_node, -			"sirf,spi-dma-rx-channel", &rx_dma_ch); -	if (ret < 0) { -		dev_err(&pdev->dev, "Unable to get rx dma channel\n"); -		goto err_cs; -	} - -	ret = of_property_read_u32(pdev->dev.of_node, -			"sirf,spi-dma-tx-channel", &tx_dma_ch); -	if (ret < 0) { -		dev_err(&pdev->dev, "Unable to get tx dma channel\n"); -		goto err_cs; -	} - -	master = spi_alloc_master(&pdev->dev, sizeof(*sspi) + sizeof(int) * num_cs); +	master = spi_alloc_master(&pdev->dev, +			sizeof(*sspi) + sizeof(int) * num_cs);  	if (!master) {  		dev_err(&pdev->dev, "Unable to allocate SPI master\n");  		return -ENOMEM; @@ -632,7 +701,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)  	if (ret)  		goto free_master; -	sspi->bitbang.master = spi_master_get(master); +	sspi->bitbang.master = master;  	sspi->bitbang.chipselect = spi_sirfsoc_chipselect;  	sspi->bitbang.setup_transfer = spi_sirfsoc_setup_transfer;  	sspi->bitbang.txrx_bufs = spi_sirfsoc_transfer; @@ -644,18 +713,13 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)  	sspi->bitbang.master->dev.of_node = pdev->dev.of_node;  	/* request DMA channels */ -	dma_cap_zero(dma_cap_mask); -	dma_cap_set(DMA_INTERLEAVE, dma_cap_mask); - -	sspi->rx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id, -		(void *)rx_dma_ch); +	sspi->rx_chan = dma_request_slave_channel(&pdev->dev, "rx");  	if (!sspi->rx_chan) {  		dev_err(&pdev->dev, "can not allocate rx dma channel\n");  		ret = -ENODEV;  		goto free_master;  	} -	sspi->tx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id, -		(void *)tx_dma_ch); +	sspi->tx_chan = dma_request_slave_channel(&pdev->dev, "tx");  	if (!sspi->tx_chan) {  		dev_err(&pdev->dev, "can not allocate tx dma channel\n");  		ret = -ENODEV; @@ -731,11 +795,16 @@ static int  spi_sirfsoc_remove(struct platform_device *pdev)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int spi_sirfsoc_suspend(struct device *dev)  {  	struct spi_master *master = dev_get_drvdata(dev);  	struct sirfsoc_spi *sspi = spi_master_get_devdata(master); +	int ret; + +	ret = spi_master_suspend(master); +	if (ret) +		return ret;  	clk_disable(sspi->clk);  	return 0; @@ -752,15 +821,13 @@ static int spi_sirfsoc_resume(struct device *dev)  	writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP);  	writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); -	return 0; +	return spi_master_resume(master);  } - -static const struct dev_pm_ops spi_sirfsoc_pm_ops = { -	.suspend = spi_sirfsoc_suspend, -	.resume = spi_sirfsoc_resume, -};  #endif +static SIMPLE_DEV_PM_OPS(spi_sirfsoc_pm_ops, spi_sirfsoc_suspend, +			 spi_sirfsoc_resume); +  static const struct of_device_id spi_sirfsoc_of_match[] = {  	{ .compatible = "sirf,prima2-spi", },  	{ .compatible = "sirf,marco-spi", }, @@ -772,17 +839,14 @@ static struct platform_driver spi_sirfsoc_driver = {  	.driver = {  		.name = DRIVER_NAME,  		.owner = THIS_MODULE, -#ifdef CONFIG_PM  		.pm     = &spi_sirfsoc_pm_ops, -#endif  		.of_match_table = spi_sirfsoc_of_match,  	},  	.probe = spi_sirfsoc_probe,  	.remove = spi_sirfsoc_remove,  };  module_platform_driver(spi_sirfsoc_driver); -  MODULE_DESCRIPTION("SiRF SoC SPI master driver"); -MODULE_AUTHOR("Zhiwu Song <Zhiwu.Song@csr.com>, " -		"Barry Song <Baohua.Song@csr.com>"); +MODULE_AUTHOR("Zhiwu Song <Zhiwu.Song@csr.com>"); +MODULE_AUTHOR("Barry Song <Baohua.Song@csr.com>");  MODULE_LICENSE("GPL v2");  | 
