aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorx0169938 <vasyl.yushchyshen@ti.com>2012-03-26 16:56:05 +0300
committerDmytro Kedrovskyi <x0169235@ti.com>2012-05-03 16:15:55 +0300
commitca59d0fbbb349e8d0b826be7d730269195d8686a (patch)
tree51b25b3fddf6c02dd8f7d0f68f7ac0db03b1ca10 /drivers/mfd
parentd548e4e4172f2a39f15fbaad7aa6d2fcafe14681 (diff)
downloadkernel_samsung_espresso10-ca59d0fbbb349e8d0b826be7d730269195d8686a.zip
kernel_samsung_espresso10-ca59d0fbbb349e8d0b826be7d730269195d8686a.tar.gz
kernel_samsung_espresso10-ca59d0fbbb349e8d0b826be7d730269195d8686a.tar.bz2
TWL6030: Fix false GPADC conversion timeout.
When scheduler preempts just started GPADC conversion, the timeout appears because a time is exhausted but actual status register value is not updated yet. Simple scenario: 1. GPADC convertion is started before this function starts to run. 2. reg = twl6030_gpadc_read(gpadc, status_reg); 3. if (!(reg & TWL6030_GPADC_BUSY) && (reg & TWL6030_GPADC_EOC_SW)) return 0; GPADC is not yet ready, so function does not return. 4. This moment the context is switched to another thread(s) -----------------------------------------------------------------------> 5. thread(s) work(s) for timeout_ms or more time. GPADC convertion is finished. 6. <----------------------------------------------------------------------- The context is switched back. 7. } while (!time_after(jiffies, timeout)) Next cycle pass does not start, even if GPADC is yet ready. 8. The Timeout Error is returned. Additional GPADC status register reading is added for such cases. modified: drivers/mfd/twl6030-gpadc.c Change-Id: I94b61bb8318c6a03972ad057ab3fd026d1b4c13f Signed-off-by: x0169938 <vasyl.yushchyshen@ti.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/twl6030-gpadc.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/drivers/mfd/twl6030-gpadc.c b/drivers/mfd/twl6030-gpadc.c
index df62a9e..932f50a 100644
--- a/drivers/mfd/twl6030-gpadc.c
+++ b/drivers/mfd/twl6030-gpadc.c
@@ -640,6 +640,13 @@ twl6030_gpadc_start_conversion(struct twl6030_gpadc_data *gpadc,
}
}
+static int twl6030_gpadc_is_conversion_ready(
+ struct twl6030_gpadc_data *gpadc, u8 status_reg)
+{
+ u8 reg = twl6030_gpadc_read(gpadc, status_reg);
+ return !(reg & TWL6030_GPADC_BUSY) && (reg & TWL6030_GPADC_EOC_SW);
+}
+
static int twl6030_gpadc_wait_conversion_ready(
struct twl6030_gpadc_data *gpadc,
unsigned int timeout_ms, u8 status_reg)
@@ -648,14 +655,15 @@ static int twl6030_gpadc_wait_conversion_ready(
timeout = jiffies + msecs_to_jiffies(timeout_ms);
do {
- u8 reg;
-
- reg = twl6030_gpadc_read(gpadc, status_reg);
- if (!(reg & TWL6030_GPADC_BUSY) && (reg & TWL6030_GPADC_EOC_SW))
+ if (twl6030_gpadc_is_conversion_ready(gpadc, status_reg))
return 0;
} while (!time_after(jiffies, timeout));
- return -EAGAIN;
+ /* one more checking against scheduler-caused timeout */
+ if (twl6030_gpadc_is_conversion_ready(gpadc, status_reg))
+ return 0;
+ else
+ return -EAGAIN;
}
/* locks held by caller */