Title: [9222] trunk: move to mainline SPI locking API
Revision
9222
Author
vapier
Date
2010-10-16 17:40:24 -0400 (Sat, 16 Oct 2010)

Log Message

move to mainline SPI locking API

mainline merged their own spi locking api, so drop our local versions
and convert the spi core and mmc spi driver to the mainline code

also drop the locking support in the blackfin spi drivers until they
get updated.  that is tracked in [#6298].

Modified Paths

Diff

Modified: trunk/drivers/mmc/host/mmc_spi.c (9221 => 9222)


--- trunk/drivers/mmc/host/mmc_spi.c	2010-10-16 21:13:03 UTC (rev 9221)
+++ trunk/drivers/mmc/host/mmc_spi.c	2010-10-16 21:40:24 UTC (rev 9222)
@@ -182,7 +182,7 @@
 				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 @@
 				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 @@
 				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 @@
 				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 @@
 					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,
@@ -1086,14 +1086,11 @@
 	}
 #endif
 
-	/* issue command; then optionally data and stop */
-	status = spi_lock_bus(host->spi);
-	if (status == -ENOLCK) {
-		dev_err(&host->spi->dev, "failed to lock spi bus\n");
-		return;
-	}
+	/* request exclusive bus access */
+	spi_bus_lock(host->spi->master);
 
-crc_recover:
+ crc_recover:
+	/* issue command; then optionally data and stop */
 	status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL);
 	if (status == 0 && mrq->data) {
 		mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz);
@@ -1121,11 +1118,10 @@
 		else
 			mmc_cs_off(host);
 	}
-	status = spi_unlock_bus(host->spi);
-	if (status == -ENOLCK) {
-		dev_err(&host->spi->dev, "failed to unlock spi bus\n");
-		return;
-	}
+
+	/* release the bus */
+	spi_bus_unlock(host->spi->master);
+
 	mmc_request_done(host->mmc, mrq);
 }
 
@@ -1322,23 +1318,6 @@
 	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;
@@ -1370,41 +1349,6 @@
 		return status;
 	}
 
-	/* We can use the bus safely if 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.
-	 *
-	 * spi_lock_bus() is used to guarantee exclusive access to spi bus. For
-	 * system without spi_lock_bus(), if mmc_spi is the only registered spi
-	 * device, we use spi bus based on the unsafe assumption that no other
-	 * spi devices will be added later.
-	 */
-
-	if (spi->master->num_chipselect > 1) {
-		struct count_children cc;
-
-		/* Test if spi master implementes spi_lock_bus() */
-		status = spi_lock_bus(spi);
-		spi_unlock_bus(spi);
-		if (status == -ENOSYS) {
-			/* No. Am I the only spi device registered? */
-			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;
-			}
-			/* REVISIT we can't guarantee another device
-			 * won't be added later... */
-			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.
 	 *

Modified: trunk/drivers/spi/Kconfig (9221 => 9222)


--- trunk/drivers/spi/Kconfig	2010-10-16 21:13:03 UTC (rev 9221)
+++ trunk/drivers/spi/Kconfig	2010-10-16 21:40:24 UTC (rev 9222)
@@ -66,14 +66,6 @@
 	help
 	  This is the SPI controller master driver for Blackfin 5xx processor.
 
-config SPI_BFIN_LOCK
-	bool "SPI bus lock"
-	depends on SPI_BFIN
-	default n
-	help
-	  Enable support for spi_lock_bus()/spi_unlock_bus(). Useful when multiple
-	  SPI devices share a bus, especially for devices like MMC_SPI.
-
 config SPI_BFIN_SPORT
 	tristate "emulate SPI bus with Blackfin SPORT"
 	depends on BLACKFIN

Modified: trunk/drivers/spi/bfin_sport_spi.c (9221 => 9222)


--- trunk/drivers/spi/bfin_sport_spi.c	2010-10-16 21:13:03 UTC (rev 9221)
+++ trunk/drivers/spi/bfin_sport_spi.c	2010-10-16 21:40:24 UTC (rev 9222)
@@ -70,10 +70,7 @@
 	struct list_head queue;
 	int busy;
 	bool run;
-#ifdef CONFIG_SPI_BFIN_LOCK
-	/* SPI bus is lock by a slave for exclusive access */
-	int locked;
-#endif
+
 	/* Message Transfer pump */
 	struct tasklet_struct pump_transfers;
 
@@ -474,10 +471,6 @@
 	struct master_data *drv_data;
 	unsigned long flags;
 	struct spi_message *next_msg;
-#ifdef CONFIG_SPI_BFIN_LOCK
-	int locked_cs = -1;
-	struct spi_message *msg = NULL;
-#endif
 
 	drv_data = container_of(work, struct master_data, pump_messages);
 
@@ -500,27 +493,6 @@
 	next_msg = list_entry(drv_data->queue.next,
 		struct spi_message, queue);
 
-#ifdef CONFIG_SPI_BFIN_LOCK
-	if (drv_data->locked)
-		locked_cs = drv_data->locked;
-
-	/* Someone has locked the bus */
-	if (drv_data->locked && next_msg->spi->chip_select != locked_cs) {
-		list_for_each_entry(msg, &drv_data->queue, queue) {
-			if (msg->spi->chip_select == locked_cs) {
-				next_msg = msg;
-				break;
-			}
-		}
-		/* Do nothing even if there are messages for other devices */
-		if (next_msg->spi->chip_select != locked_cs) {
-			drv_data->busy = 0;
-			spin_unlock_irqrestore(&drv_data->lock, flags);
-			return;
-		}
-	}
-#endif
-
 	drv_data->cur_msg = next_msg;
 
 	/* Setup the SSP using the per chip configuration */
@@ -550,42 +522,6 @@
 }
 
 /*
- * lock the spi bus for exclusive access
- */
-#ifdef CONFIG_SPI_BFIN_LOCK
-static int bfin_sport_spi_lock_bus(struct spi_device *spi)
-{
-	struct master_data *drv_data = spi_master_get_devdata(spi->master);
-	unsigned long flags;
-
-	spin_lock_irqsave(&drv_data->lock, flags);
-	if (drv_data->locked) {
-		spin_unlock_irqrestore(&drv_data->lock, flags);
-		return -ENOLCK;
-	}
-	drv_data->locked = spi->chip_select;
-	spin_unlock_irqrestore(&drv_data->lock, flags);
-
-	return 0;
-}
-
-static int bfin_sport_spi_unlock_bus(struct spi_device *spi)
-{
-	struct master_data *drv_data = spi_master_get_devdata(spi->master);
-	unsigned long flags;
-
-	spin_lock_irqsave(&drv_data->lock, flags);
-	drv_data->locked = 0;
-	spin_unlock_irqrestore(&drv_data->lock, flags);
-
-	return 0;
-}
-#else
-# define bfin_sport_spi_lock_bus   NULL
-# define bfin_sport_spi_unlock_bus NULL
-#endif
-
-/*
  * got a msg to transfer, queue it in drv_data->queue.
  * And kick off message pumper
  */
@@ -715,9 +651,6 @@
 	INIT_LIST_HEAD(&drv_data->queue);
 	spin_lock_init(&drv_data->lock);
 
-#ifdef CONFIG_SPI_BFIN_LOCK
-	drv_data->locked = 0;
-#endif
 	drv_data->run = false;
 	drv_data->busy = 0;
 
@@ -765,9 +698,6 @@
 
 	spin_lock_irqsave(&drv_data->lock, flags);
 
-#ifdef CONFIG_SPI_BFIN_LOCK
-	drv_data->locked = 0;
-#endif
 	/*
 	 * This is a bit lame, but is optimized for the common execution path.
 	 * A wait_queue on the drv_data->busy could be used, but then the common
@@ -831,8 +761,6 @@
 	master->cleanup = bfin_sport_spi_cleanup;
 	master->setup = bfin_sport_spi_setup;
 	master->transfer = bfin_sport_spi_transfer;
-	master->lock_bus = bfin_sport_spi_lock_bus;
-	master->unlock_bus = bfin_sport_spi_unlock_bus;
 
 	/* Find and map our resources */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

Modified: trunk/drivers/spi/spi.c (9221 => 9222)


--- trunk/drivers/spi/spi.c	2010-10-16 21:13:03 UTC (rev 9221)
+++ trunk/drivers/spi/spi.c	2010-10-16 21:40:24 UTC (rev 9222)
@@ -527,6 +527,10 @@
 		dynamic = 1;
 	}
 
+	spin_lock_init(&master->bus_lock_spinlock);
+	mutex_init(&master->bus_lock_mutex);
+	master->bus_lock_flag = 0;
+
 	/* register the device, then userspace will see it.
 	 * registration fails if the bus ID is in use.
 	 */
@@ -666,6 +670,35 @@
 }
 EXPORT_SYMBOL_GPL(spi_setup);
 
+static int __spi_async(struct spi_device *spi, struct spi_message *message)
+{
+	struct spi_master *master = spi->master;
+
+	/* Half-duplex links include original MicroWire, and ones with
+	 * only one data pin like SPI_3WIRE (switches direction) or where
+	 * either MOSI or MISO is missing.  They can also be caused by
+	 * software limitations.
+	 */
+	if ((master->flags & SPI_MASTER_HALF_DUPLEX)
+			|| (spi->mode & SPI_3WIRE)) {
+		struct spi_transfer *xfer;
+		unsigned flags = master->flags;
+
+		list_for_each_entry(xfer, &message->transfers, transfer_list) {
+			if (xfer->rx_buf && xfer->tx_buf)
+				return -EINVAL;
+			if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf)
+				return -EINVAL;
+			if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf)
+				return -EINVAL;
+		}
+	}
+
+	message->spi = spi;
+	message->status = -EINPROGRESS;
+	return master->transfer(spi, message);
+}
+
 /**
  * spi_async - asynchronous SPI transfer
  * @spi: device with which data will be exchanged
@@ -698,34 +731,69 @@
 int spi_async(struct spi_device *spi, struct spi_message *message)
 {
 	struct spi_master *master = spi->master;
+	int ret;
+	unsigned long flags;
 
-	/* Half-duplex links include original MicroWire, and ones with
-	 * only one data pin like SPI_3WIRE (switches direction) or where
-	 * either MOSI or MISO is missing.  They can also be caused by
-	 * software limitations.
-	 */
-	if ((master->flags & SPI_MASTER_HALF_DUPLEX)
-			|| (spi->mode & SPI_3WIRE)) {
-		struct spi_transfer *xfer;
-		unsigned flags = master->flags;
+	spin_lock_irqsave(&master->bus_lock_spinlock, flags);
 
-		list_for_each_entry(xfer, &message->transfers, transfer_list) {
-			if (xfer->rx_buf && xfer->tx_buf)
-				return -EINVAL;
-			if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf)
-				return -EINVAL;
-			if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf)
-				return -EINVAL;
-		}
-	}
+	if (master->bus_lock_flag)
+		ret = -EBUSY;
+	else
+		ret = __spi_async(spi, message);
 
-	message->spi = spi;
-	message->status = -EINPROGRESS;
-	return master->transfer(spi, message);
+	spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(spi_async);
 
+/**
+ * spi_async_locked - version of spi_async with exclusive bus usage
+ * @spi: device with which data will be exchanged
+ * @message: describes the data transfers, including completion callback
+ * Context: any (irqs may be blocked, etc)
+ *
+ * This call may be used in_irq and other contexts which can't sleep,
+ * as well as from task contexts which can sleep.
+ *
+ * The completion callback is invoked in a context which can't sleep.
+ * Before that invocation, the value of message->status is undefined.
+ * When the callback is issued, message->status holds either zero (to
+ * indicate complete success) or a negative error code.  After that
+ * callback returns, the driver which issued the transfer request may
+ * deallocate the associated memory; it's no longer in use by any SPI
+ * core or controller driver code.
+ *
+ * Note that although all messages to a spi_device are handled in
+ * FIFO order, messages may go to different devices in other orders.
+ * Some device might be higher priority, or have various "hard" access
+ * time requirements, for example.
+ *
+ * On detection of any fault during the transfer, processing of
+ * the entire message is aborted, and the device is deselected.
+ * Until returning from the associated message completion callback,
+ * no other spi_message queued to that device will be processed.
+ * (This rule applies equally to all the synchronous transfer calls,
+ * which are wrappers around this core asynchronous primitive.)
+ */
+int spi_async_locked(struct spi_device *spi, struct spi_message *message)
+{
+	struct spi_master *master = spi->master;
+	int ret;
+	unsigned long flags;
 
+	spin_lock_irqsave(&master->bus_lock_spinlock, flags);
+
+	ret = __spi_async(spi, message);
+
+	spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);
+
+	return ret;
+
+}
+EXPORT_SYMBOL_GPL(spi_async_locked);
+
+
 /*-------------------------------------------------------------------------*/
 
 /* Utility methods for SPI master protocol drivers, layered on
@@ -738,57 +806,31 @@
 	complete(arg);
 }
 
-/**
- * spi_lock_bus - lock SPI bus for exclusive access
- * @spi: device which want to lock the bus
- * Context: any
- *
- * Once the caller owns exclusive access to the SPI bus,
- * only messages for this device will be transferred.
- * Messages for other devices are queued but not transferred until
- * the bus owner unlock the bus.
- *
- * The caller may call spi_lock_bus() before spi_sync() or spi_async().
- * So this call may be used in irq and other contexts which can't sleep,
- * as well as from task contexts which can sleep.
- *
- * It returns zero on success, else a negative error code:
- * 	-ENOSYS: spi master driver does not implement this function
- * 	-ENOLCK: cannot lock the bus
- */
-int spi_lock_bus(struct spi_device *spi)
+static int __spi_sync(struct spi_device *spi, struct spi_message *message,
+		      int bus_locked)
 {
-	if (spi->master->lock_bus)
-		return spi->master->lock_bus(spi);
-	else
-		return -ENOSYS;
-}
-EXPORT_SYMBOL_GPL(spi_lock_bus);
+	DECLARE_COMPLETION_ONSTACK(done);
+	int status;
+	struct spi_master *master = spi->master;
 
-/**
- * spi_unlock_bus - unlock SPI bus
- * @spi: device which want to unlock the bus
- * Context: any
- *
- * The caller has called spi_lock_bus() to lock the bus. It calls
- * spi_unlock_bus() to release the bus so messages for other devices
- * can be transferred.
- *
- * If the caller did not call spi_lock_bus() before, spi_unlock_bus()
- * will return -ENOLCK.
- *
- * It returns zero on success, else a negative error code:
- * 	-ENOSYS: spi master driver does not implement this function
- *	-ENOLCK: cannot unlock the bus
- */
-int spi_unlock_bus(struct spi_device *spi)
-{
-	if (spi->master->unlock_bus)
-		return spi->master->unlock_bus(spi);
-	else
-		return -ENOSYS;
+	message->complete = spi_complete;
+	message->context = &done;
+
+	if (!bus_locked)
+		mutex_lock(&master->bus_lock_mutex);
+
+	status = spi_async_locked(spi, message);
+
+	if (!bus_locked)
+		mutex_unlock(&master->bus_lock_mutex);
+
+	if (status == 0) {
+		wait_for_completion(&done);
+		status = message->status;
+	}
+	message->context = NULL;
+	return status;
 }
-EXPORT_SYMBOL_GPL(spi_unlock_bus);
 
 /**
  * spi_sync - blocking/synchronous SPI data transfers
@@ -813,21 +855,86 @@
  */
 int spi_sync(struct spi_device *spi, struct spi_message *message)
 {
-	DECLARE_COMPLETION_ONSTACK(done);
-	int status;
-
-	message->complete = spi_complete;
-	message->context = &done;
-	status = spi_async(spi, message);
-	if (status == 0) {
-		wait_for_completion(&done);
-		status = message->status;
-	}
-	message->context = NULL;
-	return status;
+	return __spi_sync(spi, message, 0);
 }
 EXPORT_SYMBOL_GPL(spi_sync);
 
+/**
+ * spi_sync_locked - version of spi_sync with exclusive bus usage
+ * @spi: device with which data will be exchanged
+ * @message: describes the data transfers
+ * Context: can sleep
+ *
+ * This call may only be used from a context that may sleep.  The sleep
+ * is non-interruptible, and has no timeout.  Low-overhead controller
+ * drivers may DMA directly into and out of the message buffers.
+ *
+ * This call should be used by drivers that require exclusive access to the
+ * SPI bus. It has to be preceeded by a spi_bus_lock call. The SPI bus must
+ * be released by a spi_bus_unlock call when the exclusive access is over.
+ *
+ * It returns zero on success, else a negative error code.
+ */
+int spi_sync_locked(struct spi_device *spi, struct spi_message *message)
+{
+	return __spi_sync(spi, message, 1);
+}
+EXPORT_SYMBOL_GPL(spi_sync_locked);
+
+/**
+ * spi_bus_lock - obtain a lock for exclusive SPI bus usage
+ * @master: SPI bus master that should be locked for exclusive bus access
+ * Context: can sleep
+ *
+ * This call may only be used from a context that may sleep.  The sleep
+ * is non-interruptible, and has no timeout.
+ *
+ * This call should be used by drivers that require exclusive access to the
+ * SPI bus. The SPI bus must be released by a spi_bus_unlock call when the
+ * exclusive access is over. Data transfer must be done by spi_sync_locked
+ * and spi_async_locked calls when the SPI bus lock is held.
+ *
+ * It returns zero on success, else a negative error code.
+ */
+int spi_bus_lock(struct spi_master *master)
+{
+	unsigned long flags;
+
+	mutex_lock(&master->bus_lock_mutex);
+
+	spin_lock_irqsave(&master->bus_lock_spinlock, flags);
+	master->bus_lock_flag = 1;
+	spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);
+
+	/* mutex remains locked until spi_bus_unlock is called */
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(spi_bus_lock);
+
+/**
+ * spi_bus_unlock - release the lock for exclusive SPI bus usage
+ * @master: SPI bus master that was locked for exclusive bus access
+ * Context: can sleep
+ *
+ * This call may only be used from a context that may sleep.  The sleep
+ * is non-interruptible, and has no timeout.
+ *
+ * This call releases an SPI bus lock previously obtained by an spi_bus_lock
+ * call.
+ *
+ * It returns zero on success, else a negative error code.
+ */
+int spi_bus_unlock(struct spi_master *master)
+{
+	master->bus_lock_flag = 0;
+
+	mutex_unlock(&master->bus_lock_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(spi_bus_unlock);
+
 /* portable code must never pass more than 32 bytes */
 #define	SPI_BUFSIZ	max(32,SMP_CACHE_BYTES)
 

Modified: trunk/drivers/spi/spi_bfin5xx.c (9221 => 9222)


--- trunk/drivers/spi/spi_bfin5xx.c	2010-10-16 21:13:03 UTC (rev 9221)
+++ trunk/drivers/spi/spi_bfin5xx.c	2010-10-16 21:40:24 UTC (rev 9222)
@@ -73,10 +73,7 @@
 	struct list_head queue;
 	int busy;
 	bool running;
-#ifdef CONFIG_SPI_BFIN_LOCK
-	/* SPI bus is lock by a slave for exclusive access */
-	int locked;
-#endif
+
 	/* Message Transfer pump */
 	struct tasklet_struct pump_transfers;
 
@@ -882,12 +879,6 @@
 {
 	struct master_data *drv_data;
 	unsigned long flags;
-#ifdef CONFIG_SPI_BFIN_LOCK
-	int locked_cs = -1;
-	int next_cs = -1;
-	struct slave_data *chip = NULL;
-	struct spi_message *next_msg = NULL, *msg = NULL;
-#endif
 
 	drv_data = container_of(work, struct master_data, pump_messages);
 
@@ -906,42 +897,10 @@
 		return;
 	}
 
-#ifdef CONFIG_SPI_BFIN_LOCK
 	/* Extract head of queue */
-	next_msg = list_entry(drv_data->queue.next,
-		struct spi_message, queue);
-
-	if (drv_data->locked) {
-		locked_cs = drv_data->locked;
-		chip = spi_get_ctldata(next_msg->spi);
-		next_cs = next_msg->spi->chip_select ? next_msg->spi->chip_select :
-			chip->cs_gpio;
-	}
-
-	/* Someone has locked the bus */
-	if (drv_data->locked && next_cs != locked_cs) {
-		list_for_each_entry(msg, &drv_data->queue, queue) {
-			chip = spi_get_ctldata(msg->spi);
-			next_cs = msg->spi->chip_select ?
-					msg->spi->chip_select : chip->cs_gpio;
-			if (next_cs == locked_cs) {
-				next_msg = msg;
-				break;
-			}
-		}
-		/* Do nothing even if there are messages for other devices */
-		if (next_cs != locked_cs) {
-			drv_data->busy = 0;
-			spin_unlock_irqrestore(&drv_data->lock, flags);
-			return;
-		}
-	}
-	drv_data->cur_msg = next_msg;
-#else
-	/* Extract head of queue */
 	drv_data->cur_msg = list_entry(drv_data->queue.next,
-		struct spi_message, queue);
-#endif
+				       struct spi_message, queue);
+
 	/* Setup the SSP using the per chip configuration */
 	drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
 	bfin_spi_restore_state(drv_data);
@@ -970,54 +929,6 @@
 }
 
 /*
- * lock the spi bus for exclusive access
- */
-static int bfin_spi_lock_bus(struct spi_device *spi)
-{
-	int ret = -ENOSYS;
-#ifdef CONFIG_SPI_BFIN_LOCK
-	struct master_data *drv_data = spi_master_get_devdata(spi->master);
-	struct slave_data *chip = spi_get_ctldata(spi);
-	unsigned long flags;
-
-	spin_lock_irqsave(&drv_data->lock, flags);
-	if (!drv_data->locked) {
-		drv_data->locked = spi->chip_select ?
-			spi->chip_select : chip->cs_gpio;
-		ret = 0;
-	} else
-		ret = -ENOLCK;
-	spin_unlock_irqrestore(&drv_data->lock, flags);
-#endif
-	return ret;
-}
-
-static int bfin_spi_unlock_bus(struct spi_device *spi)
-{
-	int ret = -ENOSYS;
-#ifdef CONFIG_SPI_BFIN_LOCK
-	struct master_data *drv_data = spi_master_get_devdata(spi->master);
-	struct slave_data *chip = spi_get_ctldata(spi);
-	unsigned long flags;
-	int cs = spi->chip_select ? spi->chip_select : chip->cs_gpio;
-
-	spin_lock_irqsave(&drv_data->lock, flags);
-	if (cs == drv_data->locked) {
-		drv_data->locked = 0;
-		ret = 0;
-
-		/* kick off transfer of all pending messeages */
-		if (drv_data->running && !drv_data->busy &&
-			!list_empty(&drv_data->queue))
-			queue_work(drv_data->workqueue, &drv_data->pump_messages);
-	} else
-		ret = -ENOLCK;
-	spin_unlock_irqrestore(&drv_data->lock, flags);
-#endif
-	return ret;
-}
-
-/*
  * got a msg to transfer, queue it in drv_data->queue.
  * And kick off message pumper
  */
@@ -1286,9 +1197,6 @@
 	INIT_LIST_HEAD(&drv_data->queue);
 	spin_lock_init(&drv_data->lock);
 
-#ifdef CONFIG_SPI_BFIN_LOCK
-	drv_data->locked = 0;
-#endif
 	drv_data->running = false;
 	drv_data->busy = 0;
 
@@ -1336,9 +1244,6 @@
 
 	spin_lock_irqsave(&drv_data->lock, flags);
 
-#ifdef CONFIG_SPI_BFIN_LOCK
-	drv_data->locked = 0;
-#endif
 	/*
 	 * This is a bit lame, but is optimized for the common execution path.
 	 * A wait_queue on the drv_data->busy could be used, but then the common
@@ -1405,8 +1310,6 @@
 	master->cleanup = bfin_spi_cleanup;
 	master->setup = bfin_spi_setup;
 	master->transfer = bfin_spi_transfer;
-	master->lock_bus = bfin_spi_lock_bus;
-	master->unlock_bus = bfin_spi_unlock_bus;
 
 	/* Find and map our resources */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

Modified: trunk/include/linux/spi/spi.h (9221 => 9222)


--- trunk/include/linux/spi/spi.h	2010-10-16 21:13:03 UTC (rev 9221)
+++ trunk/include/linux/spi/spi.h	2010-10-16 21:40:24 UTC (rev 9222)
@@ -222,8 +222,6 @@
  *	the device whose settings are being modified.
  * @transfer: adds a message to the controller's transfer queue.
  * @cleanup: frees controller-specific state
- * @lock_bus: lock SPI bus for exclusive access
- * @unlock_bus: unlock SPI bus so other devices can access
  *
  * Each SPI master controller can communicate with one or more @spi_device
  * children.  These make a small bus, sharing MOSI, MISO and SCK signals
@@ -266,6 +264,13 @@
 #define SPI_MASTER_NO_RX	BIT(1)		/* can't do buffer read */
 #define SPI_MASTER_NO_TX	BIT(2)		/* can't do buffer write */
 
+	/* lock and mutex for SPI bus locking */
+	spinlock_t		bus_lock_spinlock;
+	struct mutex		bus_lock_mutex;
+
+	/* flag indicating that the SPI bus is locked for exclusive use */
+	bool			bus_lock_flag;
+
 	/* Setup mode and clock, etc (spi driver may call many times).
 	 *
 	 * IMPORTANT:  this may be called when transfers to another
@@ -298,9 +303,6 @@
 
 	/* called on release() to free memory provided by spi_master */
 	void			(*cleanup)(struct spi_device *spi);
-
-	int			(*lock_bus)(struct spi_device *spi);
-	int			(*unlock_bus)(struct spi_device *spi);
 };
 
 static inline void *spi_master_get_devdata(struct spi_master *master)
@@ -549,6 +551,8 @@
 
 extern int spi_setup(struct spi_device *spi);
 extern int spi_async(struct spi_device *spi, struct spi_message *message);
+extern int spi_async_locked(struct spi_device *spi,
+			    struct spi_message *message);
 
 /*---------------------------------------------------------------------------*/
 
@@ -558,8 +562,9 @@
  */
 
 extern int spi_sync(struct spi_device *spi, struct spi_message *message);
-extern int spi_lock_bus(struct spi_device *spi);
-extern int spi_unlock_bus(struct spi_device *spi);
+extern int spi_sync_locked(struct spi_device *spi, struct spi_message *message);
+extern int spi_bus_lock(struct spi_master *master);
+extern int spi_bus_unlock(struct spi_master *master);
 
 /**
  * spi_write - SPI synchronous write
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to