summaryrefslogtreecommitdiffstats
path: root/drivers/w1/slaves
diff options
context:
space:
mode:
authorMaciej Szmigiero <mhej@o2.pl>2011-11-16 00:43:16 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2011-11-17 11:47:56 -0800
commit377195c438fc5e9e4ca59e69382c10771d817d6a (patch)
tree64ae50d55bf8c36ba50ab16e19895ce9e1c985fe /drivers/w1/slaves
parent65e6757be42ddf0a9115ec0e6af268fec9727359 (diff)
downloadop-kernel-dev-377195c438fc5e9e4ca59e69382c10771d817d6a.zip
op-kernel-dev-377195c438fc5e9e4ca59e69382c10771d817d6a.tar.gz
W1: w1_therm: release the bus during conversion on externally powered devices
w1_therm devices can either be bus powered or externally powered. When device is bus powered during temperature conversion the bus have to be left high to provide necessary power. Some masters also allow strong power-up to be enabled in this case. Naturally, no communication over bus can occur during that time. However, if device has external power then there is no such restriction, and host can talk to other devices during temperature conversion. There is command which allows us to check how device is powered, this patch uses it to release the bus on externally w1_therm powered devices during temperature conversion. Also, this changes uninterruptible sleeps there into interruptible ones to avoid long uninterruptible sleep if w1 subsystem happens to grab bus for scan during w1_therm_read(). Signed-off-by: Maciej Szmigiero <mhej@o2.pl> Acked-by: Evgeniy Polyakov <zbr@ioremap.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/w1/slaves')
-rw-r--r--drivers/w1/slaves/w1_therm.c36
1 files changed, 31 insertions, 5 deletions
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index a1ef9b5..ff29ae7 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -175,11 +175,13 @@ static ssize_t w1_therm_read(struct device *device,
{
struct w1_slave *sl = dev_to_w1_slave(device);
struct w1_master *dev = sl->master;
- u8 rom[9], crc, verdict;
+ u8 rom[9], crc, verdict, external_power;
int i, max_trying = 10;
ssize_t c = PAGE_SIZE;
- mutex_lock(&dev->mutex);
+ i = mutex_lock_interruptible(&dev->mutex);
+ if (i != 0)
+ return i;
memset(rom, 0, sizeof(rom));
@@ -190,13 +192,37 @@ static ssize_t w1_therm_read(struct device *device,
if (!w1_reset_select_slave(sl)) {
int count = 0;
unsigned int tm = 750;
+ unsigned long sleep_rem;
+
+ w1_write_8(dev, W1_READ_PSUPPLY);
+ external_power = w1_read_8(dev);
+
+ if (w1_reset_select_slave(sl))
+ continue;
/* 750ms strong pullup (or delay) after the convert */
- if (w1_strong_pullup)
+ if (!external_power && w1_strong_pullup)
w1_next_pullup(dev, tm);
+
w1_write_8(dev, W1_CONVERT_TEMP);
- if (!w1_strong_pullup)
- msleep(tm);
+
+ if (external_power) {
+ mutex_unlock(&dev->mutex);
+
+ sleep_rem = msleep_interruptible(tm);
+ if (sleep_rem != 0)
+ return -EINTR;
+
+ i = mutex_lock_interruptible(&dev->mutex);
+ if (i != 0)
+ return i;
+ } else if (!w1_strong_pullup) {
+ sleep_rem = msleep_interruptible(tm);
+ if (sleep_rem != 0) {
+ mutex_unlock(&dev->mutex);
+ return -EINTR;
+ }
+ }
if (!w1_reset_select_slave(sl)) {
OpenPOWER on IntegriCloud