diff options
author | Ernst Schwab <eschwab@online.de> | 2010-06-28 20:49:29 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2010-06-28 20:49:29 -0400 |
commit | cf32b71e981ca63e8f349d8585ca2a3583b556e0 (patch) | |
tree | e704942f6843114446c73478a79e615a57d2eb49 /include/linux/spi | |
parent | 7e27d6e778cd87b6f2415515d7127eba53fe5d02 (diff) |
spi/mmc_spi: SPI bus locking API, using mutex
SPI bus locking API to allow exclusive access to the SPI bus, especially, but
not limited to, for the mmc_spi driver.
Coded according to an outline from Grant Likely; here is his
specification (accidentally swapped function names corrected):
It requires 3 things to be added to struct spi_master.
- 1 Mutex
- 1 spin lock
- 1 flag.
The mutex protects spi_sync, and provides sleeping "for free"
The spinlock protects the atomic spi_async call.
The flag is set when the lock is obtained, and checked while holding
the spinlock in spi_async(). If the flag is checked, then spi_async()
must fail immediately.
The current runtime API looks like this:
spi_async(struct spi_device*, struct spi_message*);
spi_sync(struct spi_device*, struct spi_message*);
The API needs to be extended to this:
spi_async(struct spi_device*, struct spi_message*)
spi_sync(struct spi_device*, struct spi_message*)
spi_bus_lock(struct spi_master*) /* although struct spi_device* might
be easier */
spi_bus_unlock(struct spi_master*)
spi_async_locked(struct spi_device*, struct spi_message*)
spi_sync_locked(struct spi_device*, struct spi_message*)
Drivers can only call the last two if they already hold the spi_master_lock().
spi_bus_lock() obtains the mutex, obtains the spin lock, sets the
flag, and releases the spin lock before returning. It doesn't even
need to sleep while waiting for "in-flight" spi_transactions to
complete because its purpose is to guarantee no additional
transactions are added. It does not guarantee that the bus is idle.
spi_bus_unlock() clears the flag and releases the mutex, which will
wake up any waiters.
The difference between spi_async() and spi_async_locked() is that the
locked version bypasses the check of the lock flag. Both versions
need to obtain the spinlock.
The difference between spi_sync() and spi_sync_locked() is that
spi_sync() must hold the mutex while enqueuing a new transfer.
spi_sync_locked() doesn't because the mutex is already held. Note
however that spi_sync must *not* continue to hold the mutex while
waiting for the transfer to complete, otherwise only one transfer
could be queued up at a time!
Almost no code needs to be written. The current spi_async() and
spi_sync() can probably be renamed to __spi_async() and __spi_sync()
so that spi_async(), spi_sync(), spi_async_locked() and
spi_sync_locked() can just become wrappers around the common code.
spi_sync() is protected by a mutex because it can sleep
spi_async() needs to be protected with a flag and a spinlock because
it can be called atomically and must not sleep
Signed-off-by: Ernst Schwab <eschwab@online.de>
[grant.likely@secretlab.ca: use spin_lock_irqsave()]
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>
Diffstat (limited to 'include/linux/spi')
-rw-r--r-- | include/linux/spi/spi.h | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index af56071b06f9..ae0a5286f558 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h | |||
@@ -262,6 +262,13 @@ struct spi_master { | |||
262 | #define SPI_MASTER_NO_RX BIT(1) /* can't do buffer read */ | 262 | #define SPI_MASTER_NO_RX BIT(1) /* can't do buffer read */ |
263 | #define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */ | 263 | #define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */ |
264 | 264 | ||
265 | /* lock and mutex for SPI bus locking */ | ||
266 | spinlock_t bus_lock_spinlock; | ||
267 | struct mutex bus_lock_mutex; | ||
268 | |||
269 | /* flag indicating that the SPI bus is locked for exclusive use */ | ||
270 | bool bus_lock_flag; | ||
271 | |||
265 | /* Setup mode and clock, etc (spi driver may call many times). | 272 | /* Setup mode and clock, etc (spi driver may call many times). |
266 | * | 273 | * |
267 | * IMPORTANT: this may be called when transfers to another | 274 | * IMPORTANT: this may be called when transfers to another |
@@ -542,6 +549,8 @@ static inline void spi_message_free(struct spi_message *m) | |||
542 | 549 | ||
543 | extern int spi_setup(struct spi_device *spi); | 550 | extern int spi_setup(struct spi_device *spi); |
544 | extern int spi_async(struct spi_device *spi, struct spi_message *message); | 551 | extern int spi_async(struct spi_device *spi, struct spi_message *message); |
552 | extern int spi_async_locked(struct spi_device *spi, | ||
553 | struct spi_message *message); | ||
545 | 554 | ||
546 | /*---------------------------------------------------------------------------*/ | 555 | /*---------------------------------------------------------------------------*/ |
547 | 556 | ||
@@ -551,6 +560,9 @@ extern int spi_async(struct spi_device *spi, struct spi_message *message); | |||
551 | */ | 560 | */ |
552 | 561 | ||
553 | extern int spi_sync(struct spi_device *spi, struct spi_message *message); | 562 | extern int spi_sync(struct spi_device *spi, struct spi_message *message); |
563 | extern int spi_sync_locked(struct spi_device *spi, struct spi_message *message); | ||
564 | extern int spi_bus_lock(struct spi_master *master); | ||
565 | extern int spi_bus_unlock(struct spi_master *master); | ||
554 | 566 | ||
555 | /** | 567 | /** |
556 | * spi_write - SPI synchronous write | 568 | * spi_write - SPI synchronous write |