timer: Add wait_us/wait_ms helper macros to wait for conditions
A very common pattern in drivers is that we need to wait for a condition to become true (e.g. for a lock bit in a PLL status register to become set), but we still want to have a maximum timeout before we treat it as an error. coreboot uses the stopwatch API for this, but it's still a little verbose for the most simple cases. This patch introduces two new helper macros that wrap this common application of the stopwatch API in a single line: wait_ms(XXX, YYY) waits for up to XXX milliseconds to see if the C condition 'if (YYY)' becomes true. The return value is 0 on failure (i.e. timeout expires without the condition becoming true) and the amount of elapsed time on success, so it can be used both in a boolean context and to log the amount of time waited. Replace the custom version used in an MTK ADC driver with this new generic version. Change-Id: I6de38ee00673c46332ae92b8a11099485de5327a Signed-off-by: Tristan Shieh <tristan.shieh@mediatek.com> Signed-off-by: Julius Werner <jwerner@chromium.org> Reviewed-on: https://review.coreboot.org/29315 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Aaron Durbin <adurbin@chromium.org>
This commit is contained in:
parent
55a972236e
commit
5132570845
|
@ -15,6 +15,8 @@
|
||||||
#ifndef TIMER_H
|
#ifndef TIMER_H
|
||||||
#define TIMER_H
|
#define TIMER_H
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
#define NSECS_PER_SEC 1000000000
|
#define NSECS_PER_SEC 1000000000
|
||||||
#define USECS_PER_SEC 1000000
|
#define USECS_PER_SEC 1000000
|
||||||
#define MSECS_PER_SEC 1000
|
#define MSECS_PER_SEC 1000
|
||||||
|
@ -195,4 +197,36 @@ static inline long stopwatch_duration_msecs(struct stopwatch *sw)
|
||||||
return stopwatch_duration_usecs(sw) / USECS_PER_MSEC;
|
return stopwatch_duration_usecs(sw) / USECS_PER_MSEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper macro to wait until a condition becomes true or a timeout elapses.
|
||||||
|
*
|
||||||
|
* condition: a C expression to wait for
|
||||||
|
* timeout: timeout, in microseconds
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 if the condition still evaluates to false after the timeout elapsed,
|
||||||
|
* >0 if the condition evaluates to true. The return value is the amount of
|
||||||
|
* microseconds waited (at least 1).
|
||||||
|
*/
|
||||||
|
#define wait_us(timeout_us, condition) \
|
||||||
|
({ \
|
||||||
|
long __ret = 0; \
|
||||||
|
struct stopwatch __sw; \
|
||||||
|
stopwatch_init_usecs_expire(&__sw, timeout_us); \
|
||||||
|
do { \
|
||||||
|
if (condition) { \
|
||||||
|
stopwatch_tick(&__sw); \
|
||||||
|
__ret = stopwatch_duration_usecs(&__sw); \
|
||||||
|
if (!__ret) /* make sure it evaluates to true */\
|
||||||
|
__ret = 1; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} while (!stopwatch_expired(&__sw)); \
|
||||||
|
__ret; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define wait_ms(timeout_ms, condition) \
|
||||||
|
DIV_ROUND_UP(wait_us((timeout_ms) * USECS_PER_MSEC, condition), \
|
||||||
|
USECS_PER_MSEC)
|
||||||
|
|
||||||
#endif /* TIMER_H */
|
#endif /* TIMER_H */
|
||||||
|
|
|
@ -24,33 +24,17 @@
|
||||||
|
|
||||||
static struct mtk_auxadc_regs *const mtk_auxadc = (void *)AUXADC_BASE;
|
static struct mtk_auxadc_regs *const mtk_auxadc = (void *)AUXADC_BASE;
|
||||||
|
|
||||||
/*
|
|
||||||
* Wait until a condition becomes true or times out
|
|
||||||
*
|
|
||||||
* cond : a C expression to wait for
|
|
||||||
* timeout : msecs
|
|
||||||
*/
|
|
||||||
#define wait_ms(cond, timeout) \
|
|
||||||
({ \
|
|
||||||
struct stopwatch sw; \
|
|
||||||
int expired = 0; \
|
|
||||||
stopwatch_init_msecs_expire(&sw, timeout); \
|
|
||||||
while (!(cond) && !(expired = stopwatch_expired(&sw))) \
|
|
||||||
; /* wait */ \
|
|
||||||
assert(!expired); \
|
|
||||||
})
|
|
||||||
|
|
||||||
static uint32_t auxadc_get_rawdata(int channel)
|
static uint32_t auxadc_get_rawdata(int channel)
|
||||||
{
|
{
|
||||||
setbits_le32(&mt8183_infracfg->module_sw_cg_1_clr, 1 << 10);
|
setbits_le32(&mt8183_infracfg->module_sw_cg_1_clr, 1 << 10);
|
||||||
wait_ms(!(read32(&mtk_auxadc->con2) & 0x1), 300);
|
assert(wait_ms(300, !(read32(&mtk_auxadc->con2) & 0x1)));
|
||||||
|
|
||||||
clrbits_le32(&mtk_auxadc->con1, 1 << channel);
|
clrbits_le32(&mtk_auxadc->con1, 1 << channel);
|
||||||
wait_ms(!(read32(&mtk_auxadc->data[channel]) & (1 << 12)), 300);
|
assert(wait_ms(300, !(read32(&mtk_auxadc->data[channel]) & (1 << 12))));
|
||||||
|
|
||||||
setbits_le32(&mtk_auxadc->con1, 1 << channel);
|
setbits_le32(&mtk_auxadc->con1, 1 << channel);
|
||||||
udelay(25);
|
udelay(25);
|
||||||
wait_ms(read32(&mtk_auxadc->data[channel]) & (1 << 12), 300);
|
assert(wait_ms(300, read32(&mtk_auxadc->data[channel]) & (1 << 12)));
|
||||||
|
|
||||||
uint32_t value = read32(&mtk_auxadc->data[channel]) & 0x0FFF;
|
uint32_t value = read32(&mtk_auxadc->data[channel]) & 0x0FFF;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue