lm4: Use a special task event for ADC conversions

This prevents other task events from continuing the ADC
conversion prematurely; potentially leading to a panic
if the conversion interrupt occurs after the ADC has
been powered down.

BUG=chrome-os-partner:26919
BRANCH=rambi
TEST=Perform ADC conversions while running a deferred function
calling itself on a 10mSec delay. Verify no panics after ~6 hours.

Change-Id: Ic3894849c154b3f058e812b2da816e7cffb12cbf
Signed-off-by: Dave Parker <dparker@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/191302
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
ChromeOS Developer
2014-03-23 09:25:03 -07:00
committed by chrome-internal-fetch
parent e2e2f5d848
commit 9d5432bc74
2 changed files with 19 additions and 6 deletions

View File

@@ -18,6 +18,9 @@
#include "timer.h"
#include "util.h"
/* Maximum time we allow for an ADC conversion */
#define ADC_TIMEOUT_US SECOND
static task_id_t task_waiting_on_ss[LM4_ADC_SEQ_COUNT];
static void configure_gpio(void)
@@ -74,13 +77,21 @@ static int flush_and_read(enum lm4_adc_sequencer seq)
/* Clear the interrupt status */
LM4_ADC_ADCISC |= 0x01 << seq;
/* Enable interrupt */
LM4_ADC_ADCIM |= 0x01 << seq;
/* Initiate sample sequence */
LM4_ADC_ADCPSSI |= 0x01 << seq;
/* Wait for interrupt */
event = task_wait_event(SECOND);
event = task_wait_event_mask(TASK_EVENT_ADC_DONE, ADC_TIMEOUT_US);
/* Disable interrupt */
LM4_ADC_ADCIM &= ~(0x01 << seq);
task_waiting_on_ss[seq] = TASK_ID_INVALID;
if (event == TASK_EVENT_TIMER)
if (!(event & TASK_EVENT_ADC_DONE))
return ADC_READ_ERROR;
/* Read the FIFO and convert to temperature */
@@ -159,6 +170,7 @@ int adc_read_channel(enum adc_channel ch)
if (rv == ADC_READ_ERROR)
return ADC_READ_ERROR;
return rv * adc->factor_mul / adc->factor_div + adc->shift;
}
@@ -189,7 +201,7 @@ static void handle_interrupt(int ss)
/* Wake up the task which was waiting on the interrupt, if any */
if (id != TASK_ID_INVALID)
task_wake(id);
task_set_event(id, TASK_EVENT_ADC_DONE, 0);
}
void ss0_interrupt(void) { handle_interrupt(0); }
@@ -255,8 +267,7 @@ static void adc_init(void)
for (i = 0; i < LM4_ADC_SEQ_COUNT; i++)
task_waiting_on_ss[i] = TASK_ID_INVALID;
/* Enable interrupt */
LM4_ADC_ADCIM = 0xF;
/* Enable IRQs */
task_enable_irq(LM4_IRQ_ADC0_SS0);
task_enable_irq(LM4_IRQ_ADC0_SS1);
task_enable_irq(LM4_IRQ_ADC0_SS2);

View File

@@ -13,7 +13,9 @@
/* Task event bitmasks */
/* Tasks may use the bits in TASK_EVENT_CUSTOM for their own events */
#define TASK_EVENT_CUSTOM(x) (x & 0x0fffffff)
#define TASK_EVENT_CUSTOM(x) (x & 0x07ffffff)
/* ADC interrupt handler event */
#define TASK_EVENT_ADC_DONE (1 << 27)
/* I2C interrupt handler event */
#define TASK_EVENT_I2C_IDLE (1 << 28)
/* task_wake() called on task */