/* Copyright 2013 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "adc.h" #include "common.h" #include "console.h" #include "hooks.h" #include "registers.h" #include "task.h" #include "timer.h" #include "util.h" /* * Conversion on a single channel takes less than 12 ms. Set timeout to * 15 ms so that we have a 3-ms margin. */ #define ADC_SINGLE_READ_TIME 15000 struct mutex adc_lock; static volatile task_id_t task_waiting; static int start_single_and_wait(int timeout) { int event; task_waiting = task_get_current(); /* Start conversion */ MEC1322_ADC_CTRL |= BIT(1); /* Wait for interrupt */ event = task_wait_event(timeout); task_waiting = TASK_ID_INVALID; return event != TASK_EVENT_TIMER; } int adc_read_channel(enum adc_channel ch) { const struct adc_t *adc = adc_channels + ch; int value; mutex_lock(&adc_lock); MEC1322_ADC_SINGLE = 1 << adc->channel; if (start_single_and_wait(ADC_SINGLE_READ_TIME)) value = MEC1322_ADC_READ(adc->channel) * adc->factor_mul / adc->factor_div + adc->shift; else value = ADC_READ_ERROR; mutex_unlock(&adc_lock); return value; } static void adc_init(void) { /* Activate ADC module */ MEC1322_ADC_CTRL |= BIT(0); /* Enable interrupt */ task_waiting = TASK_ID_INVALID; MEC1322_INT_ENABLE(17) |= BIT(10); MEC1322_INT_BLK_EN |= BIT(17); task_enable_irq(MEC1322_IRQ_ADC_SNGL); } DECLARE_HOOK(HOOK_INIT, adc_init, HOOK_PRIO_INIT_ADC); void adc_interrupt(void) { /* Clear interrupt status bit */ MEC1322_ADC_CTRL |= BIT(7); if (task_waiting != TASK_ID_INVALID) task_wake(task_waiting); } DECLARE_IRQ(MEC1322_IRQ_ADC_SNGL, adc_interrupt, 2);