mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-08 00:21:46 +00:00
Instead of using a runtime callback to register the console commands, put them in a special linker section. So we can do a macro to "register" them during the build. It saves 684 bytes and a few microseconds at startup. Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BUG=None TEST=run a few commands from the BDS command line. Change-Id: Id33ea210b9035bf76ed720373c74c5dd24ccd1b1
159 lines
3.9 KiB
C
159 lines
3.9 KiB
C
/* Copyright (c) 2012 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.
|
|
*/
|
|
|
|
/* ADC module for Chrome EC */
|
|
|
|
#include "board.h"
|
|
#include "console.h"
|
|
#include "adc.h"
|
|
#include "timer.h"
|
|
#include "registers.h"
|
|
#include "uart.h"
|
|
#include "util.h"
|
|
|
|
|
|
static void configure_gpio(void)
|
|
{
|
|
volatile uint32_t scratch __attribute__((unused));
|
|
|
|
/* Enable GPIOE module and delay a few clocks */
|
|
LM4_SYSTEM_RCGCGPIO |= 0x0010;
|
|
scratch = LM4_SYSTEM_RCGCGPIO;
|
|
|
|
/* Use analog function for PE3 (AIN0) */
|
|
LM4_GPIO_DEN(LM4_GPIO_E) &= ~0x08;
|
|
LM4_GPIO_AMSEL(LM4_GPIO_E) |= 0x08;
|
|
}
|
|
|
|
|
|
int adc_read(enum adc_channel ch)
|
|
{
|
|
volatile uint32_t scratch __attribute__((unused));
|
|
|
|
/* TODO: right now we have only a single channel so this is
|
|
* simple. When we have multiple channels, should we...
|
|
*
|
|
* 1) Read them all using a timer interrupt, and then return
|
|
* the most recent value? This is lowest-latency for the
|
|
* caller, but won't return accurate data if read frequently.
|
|
*
|
|
* 2) Reserve SS3 for reading a single value, and configure it
|
|
* on each read? Needs mutex if we could have multiple
|
|
* callers; doesn't matter if just used for debugging.
|
|
*
|
|
* 3) Both? */
|
|
if (ch != ADC_CH_POT)
|
|
return ADC_READ_ERROR;
|
|
|
|
/* Empty the FIFO of any previous results */
|
|
while (!(LM4_ADC_SSFSTAT(0) & 0x100))
|
|
scratch = LM4_ADC_SSFIFO(0);
|
|
|
|
/* Clear the interrupt status */
|
|
LM4_ADC_ADCISC |= 0x01;
|
|
|
|
/* Initiate sample sequence */
|
|
LM4_ADC_ADCPSSI |= 0x01;
|
|
|
|
/* Wait for interrupt */
|
|
/* TODO: use a real interrupt */
|
|
while (!(LM4_ADC_ADCRIS & 0x01));
|
|
|
|
/* Read the FIFO */
|
|
return LM4_ADC_SSFIFO(0);
|
|
}
|
|
|
|
|
|
int adc_read_ec_temperature(void)
|
|
{
|
|
volatile uint32_t scratch __attribute__((unused));
|
|
int a;
|
|
|
|
/* Empty the FIFO of any previous results */
|
|
while (!(LM4_ADC_SSFSTAT(3) & 0x100))
|
|
scratch = LM4_ADC_SSFIFO(3);
|
|
|
|
/* Clear the interrupt status */
|
|
LM4_ADC_ADCISC |= 0x08;
|
|
|
|
/* Initiate sample sequence */
|
|
LM4_ADC_ADCPSSI |= 0x08;
|
|
|
|
/* Wait for interrupt */
|
|
/* TODO: use a real interrupt */
|
|
/* TODO: timeout */
|
|
while (!(LM4_ADC_ADCRIS & 0x08));
|
|
|
|
/* Read the FIFO and convert to temperature */
|
|
a = LM4_ADC_SSFIFO(3);
|
|
return 273 + (295 - (225 * 2 * a) / ADC_READ_MAX) / 2;
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* Console commands */
|
|
|
|
static int command_adc(int argc, char **argv)
|
|
{
|
|
uart_printf("ADC channel %d = 0x%03x\n", ADC_IN0,
|
|
adc_read(ADC_CH_POT));
|
|
return EC_SUCCESS;
|
|
}
|
|
DECLARE_CONSOLE_COMMAND(adc, command_adc);
|
|
|
|
|
|
static int command_ectemp(int argc, char **argv)
|
|
{
|
|
int t = adc_read_ec_temperature();
|
|
uart_printf("EC temperature is %d K = %d C\n", t, t-273);
|
|
return EC_SUCCESS;
|
|
}
|
|
DECLARE_CONSOLE_COMMAND(ectemp, command_ectemp);
|
|
|
|
|
|
/* Initialization */
|
|
|
|
int adc_init(void)
|
|
{
|
|
volatile uint32_t scratch __attribute__((unused));
|
|
|
|
/* Enable ADC0 module and delay a few clocks */
|
|
LM4_SYSTEM_RCGCADC |= 0x01;
|
|
scratch = LM4_SYSTEM_RCGCADC;
|
|
|
|
/* Configure GPIOs */
|
|
configure_gpio();
|
|
|
|
/* Use external voltage references (VREFA+, VREFA-) instead of
|
|
* VDDA and GNDA. */
|
|
LM4_ADC_ADCCTL = 0x01;
|
|
|
|
/* TODO: set up clock using ADCCC register? */
|
|
|
|
/* Configure sample sequencer 0 */
|
|
LM4_ADC_ADCACTSS &= ~0x01;
|
|
/* Trigger SS0 by processor request */
|
|
LM4_ADC_ADCEMUX = (LM4_ADC_ADCEMUX & 0xfffffff0) | 0x00;
|
|
/* Sample only our one channel */
|
|
LM4_ADC_SSMUX(0) = ADC_IN0 & 0x0f;
|
|
LM4_ADC_SSEMUX(0) = (ADC_IN0 >> 4) & 0x0f;
|
|
LM4_ADC_SSCTL(0) = 0x06; /* IE0 | END0 */
|
|
/* Enable sample sequencer 0 */
|
|
LM4_ADC_ADCACTSS |= 0x01;
|
|
|
|
/* Configure sample sequencer 3 */
|
|
LM4_ADC_ADCACTSS &= ~0x08;
|
|
/* Trigger SS3 by processor request */
|
|
LM4_ADC_ADCEMUX = (LM4_ADC_ADCEMUX & 0xffffff0f) | 0x00;
|
|
/* Sample internal temp sensor */
|
|
LM4_ADC_SSMUX(3) = 0x00;
|
|
LM4_ADC_SSEMUX(3) = 0x00;
|
|
LM4_ADC_SSCTL(3) = 0x0e; /* TS0 | IE0 | END0 */
|
|
/* Enable sample sequencer 3 */
|
|
LM4_ADC_ADCACTSS |= 0x08;
|
|
|
|
return EC_SUCCESS;
|
|
}
|