diff options
author | x0169938 <vasyl.yushchyshen@ti.com> | 2012-03-26 16:56:05 +0300 |
---|---|---|
committer | Dmytro Kedrovskyi <x0169235@ti.com> | 2012-05-03 16:15:55 +0300 |
commit | ca59d0fbbb349e8d0b826be7d730269195d8686a (patch) | |
tree | 51b25b3fddf6c02dd8f7d0f68f7ac0db03b1ca10 /drivers/mfd | |
parent | d548e4e4172f2a39f15fbaad7aa6d2fcafe14681 (diff) | |
download | kernel_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.c | 18 |
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 */ |