diff options
author | Gerrit <chrome-bot@google.com> | 2012-04-19 07:25:19 -0700 |
---|---|---|
committer | Gerrit Code Review <gerrit@gerrit.golo.chromium.org> | 2012-04-19 07:25:19 -0700 |
commit | 6ecbb86b6392fa0b11514903a9fb3d3a3b704391 (patch) | |
tree | 0b2bdf8ee326cd48500c0b5464815ad5e9c1dee3 | |
parent | 61ea623120defbc119a38e5b00ba3e1c7042fb02 (diff) | |
parent | 85885221af9c7fb072796875ee71a28cb36544f6 (diff) | |
download | chrome-ec-6ecbb86b6392fa0b11514903a9fb3d3a3b704391.tar.gz |
Merge "EC: Use interrupt for ADC"
-rw-r--r-- | chip/lm4/adc.c | 52 |
1 files changed, 49 insertions, 3 deletions
diff --git a/chip/lm4/adc.c b/chip/lm4/adc.c index ad2080eb94..eb09235351 100644 --- a/chip/lm4/adc.c +++ b/chip/lm4/adc.c @@ -10,12 +10,15 @@ #include "gpio.h" #include "lm4_adc.h" #include "registers.h" +#include "task.h" #include "timer.h" #include "uart.h" #include "util.h" extern const struct adc_t adc_channels[ADC_CH_COUNT]; +static task_id_t task_waiting_on_ss[LM4_ADC_SEQ_COUNT]; + /* GPIO port and mask for AINs. */ const uint32_t ain_port[24][2] = { {LM4_GPIO_E, (1<<3)}, @@ -78,11 +81,16 @@ int lm4_adc_flush_and_read(enum lm4_adc_sequencer seq) * * 3) Both? */ volatile uint32_t scratch __attribute__((unused)); + int event; /* Empty the FIFO of any previous results */ while (!(LM4_ADC_SSFSTAT(seq) & 0x100)) scratch = LM4_ADC_SSFIFO(seq); + /* TODO: This assumes we don't have multiple tasks accessing + * the same sequencer. Add mutex lock if needed. */ + task_waiting_on_ss[seq] = task_get_current(); + /* Clear the interrupt status */ LM4_ADC_ADCISC |= 0x01 << seq; @@ -90,9 +98,10 @@ int lm4_adc_flush_and_read(enum lm4_adc_sequencer seq) LM4_ADC_ADCPSSI |= 0x01 << seq; /* Wait for interrupt */ - /* TODO: use a real interrupt */ - /* TODO: timeout */ - while (!(LM4_ADC_ADCRIS & (0x01 << seq))); + event = task_wait_event(1000000); + task_waiting_on_ss[seq] = TASK_ID_INVALID; + if (event == TASK_EVENT_TIMER) + return ADC_READ_ERROR; /* Read the FIFO and convert to temperature */ return LM4_ADC_SSFIFO(seq); @@ -128,10 +137,40 @@ int adc_read_channel(enum adc_channel ch) { const struct adc_t *adc = adc_channels + ch; int rv = lm4_adc_flush_and_read(adc->sequencer); + + if (rv == ADC_READ_ERROR) + return ADC_READ_ERROR; return rv * adc->factor_mul / adc->factor_div + adc->shift; } /*****************************************************************************/ +/* Interrupt handlers */ + +/* Handles an interrupt on the specified sample sequencer. */ +static void handle_interrupt(int ss) +{ + int id = task_waiting_on_ss[ss]; + + /* Clear the interrupt status */ + LM4_ADC_ADCISC = (0x1 << ss); + + /* Wake up the task which was waiting on the interrupt, if any */ + if (id != TASK_ID_INVALID) + task_wake(id); +} + + +static void ss0_interrupt(void) { handle_interrupt(0); } +static void ss1_interrupt(void) { handle_interrupt(1); } +static void ss2_interrupt(void) { handle_interrupt(2); } +static void ss3_interrupt(void) { handle_interrupt(3); } + +DECLARE_IRQ(LM4_IRQ_ADC0_SS0, ss0_interrupt, 2); +DECLARE_IRQ(LM4_IRQ_ADC0_SS1, ss1_interrupt, 2); +DECLARE_IRQ(LM4_IRQ_ADC0_SS2, ss2_interrupt, 2); +DECLARE_IRQ(LM4_IRQ_ADC0_SS3, ss3_interrupt, 2); + +/*****************************************************************************/ /* Console commands */ static int command_ectemp(int argc, char **argv) @@ -177,6 +216,13 @@ int adc_init(void) /* Use internal oscillator */ LM4_ADC_ADCCC = 0x1; + /* Enable interrupt */ + LM4_ADC_ADCIM = 0xF; + task_enable_irq(LM4_IRQ_ADC0_SS0); + task_enable_irq(LM4_IRQ_ADC0_SS1); + task_enable_irq(LM4_IRQ_ADC0_SS2); + task_enable_irq(LM4_IRQ_ADC0_SS3); + /* Initialize ADC sequencer */ for (i = 0; i < ADC_CH_COUNT; ++i) { adc = adc_channels + i; |