diff options
Diffstat (limited to 'drivers/spi')
| -rw-r--r-- | drivers/spi/spi-fsl-spi.c | 3 | ||||
| -rw-r--r-- | drivers/spi/spi-imx.c | 4 | ||||
| -rw-r--r-- | drivers/spi/spi-topcliff-pch.c | 93 | 
3 files changed, 72 insertions, 28 deletions
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index d2407558773..24cacff5778 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -825,6 +825,9 @@ static void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)  {  	struct device *dev = mspi->dev; +	if (!(mspi->flags & SPI_CPM_MODE)) +		return; +  	dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE);  	dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);  	cpm_muram_free(cpm_muram_offset(mspi->tx_bd)); diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 8ac6542aedc..fa594d604ac 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -786,9 +786,11 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)  		int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);  		if (cs_gpio < 0)  			cs_gpio = mxc_platform_info->chipselect[i]; + +		spi_imx->chipselect[i] = cs_gpio;  		if (cs_gpio < 0)  			continue; -		spi_imx->chipselect[i] = cs_gpio; +  		ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME);  		if (ret) {  			while (i > 0) { diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 1d23f383186..6a80749391d 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -50,6 +50,8 @@  #define PCH_RX_THOLD		7  #define PCH_RX_THOLD_MAX	15 +#define PCH_TX_THOLD		2 +  #define PCH_MAX_BAUDRATE	5000000  #define PCH_MAX_FIFO_DEPTH	16 @@ -58,6 +60,7 @@  #define PCH_SLEEP_TIME		10  #define SSN_LOW			0x02U +#define SSN_HIGH		0x03U  #define SSN_NO_CONTROL		0x00U  #define PCH_MAX_CS		0xFF  #define PCI_DEVICE_ID_GE_SPI	0x8816 @@ -316,16 +319,19 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,  	/* if transfer complete interrupt */  	if (reg_spsr_val & SPSR_FI_BIT) { -		if (tx_index < bpw_len) +		if ((tx_index == bpw_len) && (rx_index == tx_index)) { +			/* disable interrupts */ +			pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); + +			/* transfer is completed; +			   inform pch_spi_process_messages */ +			data->transfer_complete = true; +			data->transfer_active = false; +			wake_up(&data->wait); +		} else {  			dev_err(&data->master->dev,  				"%s : Transfer is not completed", __func__); -		/* disable interrupts */ -		pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); - -		/* transfer is completed;inform pch_spi_process_messages */ -		data->transfer_complete = true; -		data->transfer_active = false; -		wake_up(&data->wait); +		}  	}  } @@ -348,16 +354,26 @@ static irqreturn_t pch_spi_handler(int irq, void *dev_id)  			"%s returning due to suspend\n", __func__);  		return IRQ_NONE;  	} -	if (data->use_dma) -		return IRQ_NONE;  	io_remap_addr = data->io_remap_addr;  	spsr = io_remap_addr + PCH_SPSR;  	reg_spsr_val = ioread32(spsr); -	if (reg_spsr_val & SPSR_ORF_BIT) -		dev_err(&board_dat->pdev->dev, "%s Over run error", __func__); +	if (reg_spsr_val & SPSR_ORF_BIT) { +		dev_err(&board_dat->pdev->dev, "%s Over run error\n", __func__); +		if (data->current_msg->complete != 0) { +			data->transfer_complete = true; +			data->current_msg->status = -EIO; +			data->current_msg->complete(data->current_msg->context); +			data->bcurrent_msg_processing = false; +			data->current_msg = NULL; +			data->cur_trans = NULL; +		} +	} + +	if (data->use_dma) +		return IRQ_NONE;  	/* Check if the interrupt is for SPI device */  	if (reg_spsr_val & (SPSR_FI_BIT | SPSR_RFI_BIT)) { @@ -756,10 +772,6 @@ static void pch_spi_set_ir(struct pch_spi_data *data)  	wait_event_interruptible(data->wait, data->transfer_complete); -	pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); -	dev_dbg(&data->master->dev, -		"%s:no more control over SSN-writing 0 to SSNXCR.", __func__); -  	/* clear all interrupts */  	pch_spi_writereg(data->master, PCH_SPSR,  			 pch_spi_readreg(data->master, PCH_SPSR)); @@ -815,10 +827,11 @@ static void pch_spi_copy_rx_data_for_dma(struct pch_spi_data *data, int bpw)  	}  } -static void pch_spi_start_transfer(struct pch_spi_data *data) +static int pch_spi_start_transfer(struct pch_spi_data *data)  {  	struct pch_spi_dma_ctrl *dma;  	unsigned long flags; +	int rtn;  	dma = &data->dma; @@ -833,19 +846,23 @@ static void pch_spi_start_transfer(struct pch_spi_data *data)  				 initiating the transfer. */  	dev_dbg(&data->master->dev,  		"%s:waiting for transfer to get over\n", __func__); -	wait_event_interruptible(data->wait, data->transfer_complete); +	rtn = wait_event_interruptible_timeout(data->wait, +					       data->transfer_complete, +					       msecs_to_jiffies(2 * HZ));  	dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent,  			    DMA_FROM_DEVICE); + +	dma_sync_sg_for_cpu(&data->master->dev, dma->sg_tx_p, dma->nent, +			    DMA_FROM_DEVICE); +	memset(data->dma.tx_buf_virt, 0, PAGE_SIZE); +  	async_tx_ack(dma->desc_rx);  	async_tx_ack(dma->desc_tx);  	kfree(dma->sg_tx_p);  	kfree(dma->sg_rx_p);  	spin_lock_irqsave(&data->lock, flags); -	pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); -	dev_dbg(&data->master->dev, -		"%s:no more control over SSN-writing 0 to SSNXCR.", __func__);  	/* clear fifo threshold, disable interrupts, disable SPI transfer */  	pch_spi_setclr_reg(data->master, PCH_SPCR, 0, @@ -858,6 +875,8 @@ static void pch_spi_start_transfer(struct pch_spi_data *data)  	pch_spi_clear_fifo(data->master);  	spin_unlock_irqrestore(&data->lock, flags); + +	return rtn;  }  static void pch_dma_rx_complete(void *arg) @@ -1023,8 +1042,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)  	/* set receive fifo threshold and transmit fifo threshold */  	pch_spi_setclr_reg(data->master, PCH_SPCR,  			   ((size - 1) << SPCR_RFIC_FIELD) | -			   ((PCH_MAX_FIFO_DEPTH - PCH_DMA_TRANS_SIZE) << -			    SPCR_TFIC_FIELD), +			   (PCH_TX_THOLD << SPCR_TFIC_FIELD),  			   MASK_RFIC_SPCR_BITS | MASK_TFIC_SPCR_BITS);  	spin_unlock_irqrestore(&data->lock, flags); @@ -1035,13 +1053,20 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)  	/* offset, length setting */  	sg = dma->sg_rx_p;  	for (i = 0; i < num; i++, sg++) { -		if (i == 0) { -			sg->offset = 0; +		if (i == (num - 2)) { +			sg->offset = size * i; +			sg->offset = sg->offset * (*bpw / 8);  			sg_set_page(sg, virt_to_page(dma->rx_buf_virt), rem,  				    sg->offset);  			sg_dma_len(sg) = rem; +		} else if (i == (num - 1)) { +			sg->offset = size * (i - 1) + rem; +			sg->offset = sg->offset * (*bpw / 8); +			sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size, +				    sg->offset); +			sg_dma_len(sg) = size;  		} else { -			sg->offset = rem + size * (i - 1); +			sg->offset = size * i;  			sg->offset = sg->offset * (*bpw / 8);  			sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size,  				    sg->offset); @@ -1065,6 +1090,16 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)  	dma->desc_rx = desc_rx;  	/* TX */ +	if (data->bpw_len > PCH_DMA_TRANS_SIZE) { +		num = data->bpw_len / PCH_DMA_TRANS_SIZE; +		size = PCH_DMA_TRANS_SIZE; +		rem = 16; +	} else { +		num = 1; +		size = data->bpw_len; +		rem = data->bpw_len; +	} +  	dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);  	sg_init_table(dma->sg_tx_p, num); /* Initialize SG table */  	/* offset, length setting */ @@ -1162,6 +1197,7 @@ static void pch_spi_process_messages(struct work_struct *pwork)  	if (data->use_dma)  		pch_spi_request_dma(data,  				    data->current_msg->spi->bits_per_word); +	pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL);  	do {  		/* If we are already processing a message get the next  		transfer structure from the message otherwise retrieve @@ -1184,7 +1220,8 @@ static void pch_spi_process_messages(struct work_struct *pwork)  		if (data->use_dma) {  			pch_spi_handle_dma(data, &bpw); -			pch_spi_start_transfer(data); +			if (!pch_spi_start_transfer(data)) +				goto out;  			pch_spi_copy_rx_data_for_dma(data, bpw);  		} else {  			pch_spi_set_tx(data, &bpw); @@ -1222,6 +1259,8 @@ static void pch_spi_process_messages(struct work_struct *pwork)  	} while (data->cur_trans != NULL); +out: +	pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH);  	if (data->use_dma)  		pch_spi_release_dma(data);  }  |