summaryrefslogtreecommitdiff
path: root/chip/lm4/adc.c
diff options
context:
space:
mode:
authorVic Yang <victoryang@google.com>2012-04-16 21:58:58 +0800
committerVic Yang <victoryang@google.com>2012-04-16 22:50:22 +0800
commit85885221af9c7fb072796875ee71a28cb36544f6 (patch)
tree0b1fafa1f0f0f377db9c6ce73e6a8de861cafcb1 /chip/lm4/adc.c
parentf3301b4944e322afe48cb271ed5d47256e110072 (diff)
downloadchrome-ec-85885221af9c7fb072796875ee71a28cb36544f6.tar.gz
EC: Use interrupt for ADC
We used to wait in a loop for ADC conversion completion. This CL modify this to use real interrupt. Signed-off-by: Vic Yang <victoryang@google.com> BUG=chrome-os-partner:7492 TEST=See 'temps' still reporting EC internal temperature Change-Id: Iffd3cc3c021d82d3284bed198589be5b63d72d4d
Diffstat (limited to 'chip/lm4/adc.c')
-rw-r--r--chip/lm4/adc.c52
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;