summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Green <andy.green@linaro.org>2012-03-21 11:32:01 +0800
committerAndy Green <andy.green@linaro.org>2012-06-20 10:27:50 +0800
commit3acc7bb7cc85edd3d2929359afac54f4588fb3d4 (patch)
tree15eaa0a6f4e9715d2b90171d3b5f7827c3288eef
parentceca008fcfc4f27527b028a27072aa17d6fd8c35 (diff)
regulator palmas use the missing io_mutex stuff to protect nonatomic io
Palmas communications can get confused if multiple threads are wanting to do IO to it at the moment. Normally i2c layer would serialize it OK but in case of palmas_i2c_read_block(), the io is not atomic, it first sends dat and then performs a second transaction. This was seen to be occurring at boot when one thread is doing regulator_init_complete() which iterates all the regulator statuses calling palmas_i2c_read_block, and other things like mmc might want to set their regulator. Without any locking, the two actions can interrupt each other. This patch uses the already defined and inited but not used io_mutex member of palmas struct to protect palmas IO from itself. Signed-off-by: Andy Green <andy.green@linaro.org>
-rw-r--r--drivers/mfd/palmas.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c
index 7263e1c931a..5ee15de9271 100644
--- a/drivers/mfd/palmas.c
+++ b/drivers/mfd/palmas.c
@@ -125,6 +125,8 @@ static int palmas_i2c_read_block(struct palmas *palmas, int ipblock, u8 reg,
u8 addr;
int ret;
+ mutex_lock(&palmas->io_mutex);
+
i2c = palmas->palmas_clients[(ipblock >> 8) - 1].client;
addr = (ipblock & 0xFF) + reg;
@@ -138,6 +140,8 @@ static int palmas_i2c_read_block(struct palmas *palmas, int ipblock, u8 reg,
/* Read the result */
ret = i2c_master_recv(i2c, dest, length);
+ mutex_unlock(&palmas->io_mutex);
+
if (ret < 0)
return ret;
else if (ret != length)
@@ -165,6 +169,8 @@ static int palmas_i2c_write_block(struct palmas *palmas, int ipblock, u8 reg,
return -EINVAL;
}
+ mutex_lock(&palmas->io_mutex);
+
i2c = palmas->palmas_clients[(ipblock >> 8) - 1].client;
addr = (ipblock & 0xFF) + reg;
@@ -173,6 +179,9 @@ static int palmas_i2c_write_block(struct palmas *palmas, int ipblock, u8 reg,
/* Write the Address */
ret = i2c_master_send(i2c, buffer, length + 1);
+
+ mutex_unlock(&palmas->io_mutex);
+
if (ret < 0)
return ret;
if (ret != (length + 1))