i2c: Support i2c_transfer in atomic contexts
Allow i2c_transfer to be called in contexts where sleeping is not allowed.
It is the reponsability of the caller to ensure that the underlying i2c bus
driver will not sleep either.
Signed-off-by: Mike Rapoport <mike@compulab.co.il>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 7161f91..ddd1b83 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -33,6 +33,8 @@
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/completion.h>
+#include <linux/hardirq.h>
+#include <linux/irqflags.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
@@ -861,7 +863,15 @@
}
#endif
- mutex_lock_nested(&adap->bus_lock, adap->level);
+ if (in_atomic() || irqs_disabled()) {
+ ret = mutex_trylock(&adap->bus_lock);
+ if (!ret)
+ /* I2C activity is ongoing. */
+ return -EAGAIN;
+ } else {
+ mutex_lock_nested(&adap->bus_lock, adap->level);
+ }
+
ret = adap->algo->master_xfer(adap,msgs,num);
mutex_unlock(&adap->bus_lock);