144 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 4751c1c74bc7b596db5de0c93be1a22a570145c0 Mon Sep 17 00:00:00 2001
 | 
						|
From: Ernst Schwab <eschwab@online.de>
 | 
						|
Date: Thu, 18 Feb 2010 12:47:46 +0100
 | 
						|
Subject: [PATCH] spi/mmc_spi: mmc_spi adaptations for SPI bus locking API
 | 
						|
 | 
						|
Modification of the mmc_spi driver to use the SPI bus locking API.
 | 
						|
With this, the mmc_spi driver can be used together with other SPI
 | 
						|
devices on the same SPI bus. The exclusive access to the SPI bus is
 | 
						|
now managed in the SPI layer. The counting of chip selects in the probe
 | 
						|
function is no longer needed.
 | 
						|
 | 
						|
Signed-off-by: Ernst Schwab <eschwab@online.de>
 | 
						|
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
 | 
						|
Tested-by: Matt Fleming <matt@console-pimps.org>
 | 
						|
Tested-by: Antonio Ospite <ospite@studenti.unina.it>
 | 
						|
---
 | 
						|
 drivers/mmc/host/mmc_spi.c |   59 ++++++++-----------------------------------
 | 
						|
 1 files changed, 11 insertions(+), 48 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/mmc/host/mmc_spi.c
 | 
						|
+++ b/drivers/mmc/host/mmc_spi.c
 | 
						|
@@ -182,7 +182,7 @@ mmc_spi_readbytes(struct mmc_spi_host *h
 | 
						|
 				host->data_dma, sizeof(*host->data),
 | 
						|
 				DMA_FROM_DEVICE);
 | 
						|
 
 | 
						|
-	status = spi_sync(host->spi, &host->readback);
 | 
						|
+	status = spi_sync_locked(host->spi, &host->readback);
 | 
						|
 
 | 
						|
 	if (host->dma_dev)
 | 
						|
 		dma_sync_single_for_cpu(host->dma_dev,
 | 
						|
@@ -541,7 +541,7 @@ mmc_spi_command_send(struct mmc_spi_host
 | 
						|
 				host->data_dma, sizeof(*host->data),
 | 
						|
 				DMA_BIDIRECTIONAL);
 | 
						|
 	}
 | 
						|
-	status = spi_sync(host->spi, &host->m);
 | 
						|
+	status = spi_sync_locked(host->spi, &host->m);
 | 
						|
 
 | 
						|
 	if (host->dma_dev)
 | 
						|
 		dma_sync_single_for_cpu(host->dma_dev,
 | 
						|
@@ -685,7 +685,7 @@ mmc_spi_writeblock(struct mmc_spi_host *
 | 
						|
 				host->data_dma, sizeof(*scratch),
 | 
						|
 				DMA_BIDIRECTIONAL);
 | 
						|
 
 | 
						|
-	status = spi_sync(spi, &host->m);
 | 
						|
+	status = spi_sync_locked(spi, &host->m);
 | 
						|
 
 | 
						|
 	if (status != 0) {
 | 
						|
 		dev_dbg(&spi->dev, "write error (%d)\n", status);
 | 
						|
@@ -822,7 +822,7 @@ mmc_spi_readblock(struct mmc_spi_host *h
 | 
						|
 				DMA_FROM_DEVICE);
 | 
						|
 	}
 | 
						|
 
 | 
						|
-	status = spi_sync(spi, &host->m);
 | 
						|
+	status = spi_sync_locked(spi, &host->m);
 | 
						|
 
 | 
						|
 	if (host->dma_dev) {
 | 
						|
 		dma_sync_single_for_cpu(host->dma_dev,
 | 
						|
@@ -1018,7 +1018,7 @@ mmc_spi_data_do(struct mmc_spi_host *hos
 | 
						|
 					host->data_dma, sizeof(*scratch),
 | 
						|
 					DMA_BIDIRECTIONAL);
 | 
						|
 
 | 
						|
-		tmp = spi_sync(spi, &host->m);
 | 
						|
+		tmp = spi_sync_locked(spi, &host->m);
 | 
						|
 
 | 
						|
 		if (host->dma_dev)
 | 
						|
 			dma_sync_single_for_cpu(host->dma_dev,
 | 
						|
@@ -1084,6 +1084,9 @@ static void mmc_spi_request(struct mmc_h
 | 
						|
 	}
 | 
						|
 #endif
 | 
						|
 
 | 
						|
+	/* request exclusive bus access */
 | 
						|
+	spi_bus_lock(host->spi->master);
 | 
						|
+
 | 
						|
 	/* issue command; then optionally data and stop */
 | 
						|
 	status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL);
 | 
						|
 	if (status == 0 && mrq->data) {
 | 
						|
@@ -1094,6 +1097,9 @@ static void mmc_spi_request(struct mmc_h
 | 
						|
 			mmc_cs_off(host);
 | 
						|
 	}
 | 
						|
 
 | 
						|
+	/* release the bus */
 | 
						|
+	spi_bus_unlock(host->spi->master);
 | 
						|
+
 | 
						|
 	mmc_request_done(host->mmc, mrq);
 | 
						|
 }
 | 
						|
 
 | 
						|
@@ -1290,23 +1296,6 @@ mmc_spi_detect_irq(int irq, void *mmc)
 | 
						|
 	return IRQ_HANDLED;
 | 
						|
 }
 | 
						|
 
 | 
						|
-struct count_children {
 | 
						|
-	unsigned	n;
 | 
						|
-	struct bus_type	*bus;
 | 
						|
-};
 | 
						|
-
 | 
						|
-static int maybe_count_child(struct device *dev, void *c)
 | 
						|
-{
 | 
						|
-	struct count_children *ccp = c;
 | 
						|
-
 | 
						|
-	if (dev->bus == ccp->bus) {
 | 
						|
-		if (ccp->n)
 | 
						|
-			return -EBUSY;
 | 
						|
-		ccp->n++;
 | 
						|
-	}
 | 
						|
-	return 0;
 | 
						|
-}
 | 
						|
-
 | 
						|
 static int mmc_spi_probe(struct spi_device *spi)
 | 
						|
 {
 | 
						|
 	void			*ones;
 | 
						|
@@ -1338,32 +1327,6 @@ static int mmc_spi_probe(struct spi_devi
 | 
						|
 		return status;
 | 
						|
 	}
 | 
						|
 
 | 
						|
-	/* We can use the bus safely iff nobody else will interfere with us.
 | 
						|
-	 * Most commands consist of one SPI message to issue a command, then
 | 
						|
-	 * several more to collect its response, then possibly more for data
 | 
						|
-	 * transfer.  Clocking access to other devices during that period will
 | 
						|
-	 * corrupt the command execution.
 | 
						|
-	 *
 | 
						|
-	 * Until we have software primitives which guarantee non-interference,
 | 
						|
-	 * we'll aim for a hardware-level guarantee.
 | 
						|
-	 *
 | 
						|
-	 * REVISIT we can't guarantee another device won't be added later...
 | 
						|
-	 */
 | 
						|
-	if (spi->master->num_chipselect > 1) {
 | 
						|
-		struct count_children cc;
 | 
						|
-
 | 
						|
-		cc.n = 0;
 | 
						|
-		cc.bus = spi->dev.bus;
 | 
						|
-		status = device_for_each_child(spi->dev.parent, &cc,
 | 
						|
-				maybe_count_child);
 | 
						|
-		if (status < 0) {
 | 
						|
-			dev_err(&spi->dev, "can't share SPI bus\n");
 | 
						|
-			return status;
 | 
						|
-		}
 | 
						|
-
 | 
						|
-		dev_warn(&spi->dev, "ASSUMING SPI bus stays unshared!\n");
 | 
						|
-	}
 | 
						|
-
 | 
						|
 	/* We need a supply of ones to transmit.  This is the only time
 | 
						|
 	 * the CPU touches these, so cache coherency isn't a concern.
 | 
						|
 	 *
 |