diff options
author | Randall Spangler <rspangler@chromium.org> | 2012-08-09 13:11:09 -0700 |
---|---|---|
committer | Gerrit <chrome-bot@google.com> | 2012-08-09 14:38:16 -0700 |
commit | 3c708cb802d395fc38350a8f856ae77e9a1315ba (patch) | |
tree | 7f62d8efa2929dd64373e130ae8e9de00dd3dbfc | |
parent | 37470f1e778157f5ca3680820ca68353f3c4ab38 (diff) | |
download | chrome-ec-3c708cb802d395fc38350a8f856ae77e9a1315ba.tar.gz |
Enable PLL only briefly during ADC init
It was previously only enabled for 1500us during boot, but in a way
that triggered a needless round of notifications to other modules.
This is cleaner.
This also fixes adc_init() not initializing the task IDs to wake when
interrupts come in, and removes some unneeded code from other init
functions.
BUG=chrome-os-partner:12472
TEST=boot system and run adc command. Should still provide reasonable data.
Change-Id: I9ae5857d988c727caf5d53f551a2f12b30974c0f
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/29806
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
-rw-r--r-- | chip/lm4/adc.c | 42 | ||||
-rw-r--r-- | chip/lm4/clock.c | 12 | ||||
-rw-r--r-- | common/main.c | 6 | ||||
-rw-r--r-- | include/clock.h | 32 |
4 files changed, 58 insertions, 34 deletions
diff --git a/chip/lm4/adc.c b/chip/lm4/adc.c index 03516a5eb3..57604d1204 100644 --- a/chip/lm4/adc.c +++ b/chip/lm4/adc.c @@ -6,6 +6,7 @@ /* LM4-specific ADC module for Chrome EC */ #include "adc.h" +#include "clock.h" #include "console.h" #include "gpio.h" #include "hooks.h" @@ -51,11 +52,6 @@ const uint32_t ain_port[24][2] = { static void configure_gpio(void) { int i; - 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 AIN */ for (i = 0; i < ADC_CH_COUNT; ++i) { @@ -114,22 +110,22 @@ int lm4_adc_configure(enum lm4_adc_sequencer seq, int ain_id, int ssctl) { - volatile uint32_t scratch __attribute__((unused)); - /* TODO: set up clock using ADCCC register? */ /* Configure sample sequencer */ LM4_ADC_ADCACTSS &= ~(0x01 << seq); + /* Trigger sequencer by processor request */ LM4_ADC_ADCEMUX = (LM4_ADC_ADCEMUX & ~(0xf << (seq * 4))) | 0x00; + /* Sample internal temp sensor */ if (ain_id != LM4_AIN_NONE) { LM4_ADC_SSMUX(seq) = ain_id & 0xf; LM4_ADC_SSEMUX(seq) = ain_id >> 4; - } - else { + } else { LM4_ADC_SSMUX(seq) = 0x00; LM4_ADC_SSEMUX(seq) = 0x00; } LM4_ADC_SSCTL(seq) = ssctl; + /* Enable sample sequencer */ LM4_ADC_ADCACTSS |= 0x01 << seq; @@ -214,20 +210,36 @@ static int adc_init(void) int i; const struct adc_t *adc; - /* Enable ADC0 module and delay a few clocks */ - LM4_SYSTEM_RCGCADC |= 0x01; - udelay(1); - /* Configure GPIOs */ configure_gpio(); - /* Use external voltage references (VREFA+, VREFA-) instead of - * VDDA and GNDA. */ + /* + * Temporarily enable the PLL when turning on the clock to the ADC + * module, to work around chip errata (10.4). No need to notify + * other modules; the PLL isn't enabled long enough to matter. + */ + clock_enable_pll(1, 0); + + /* Enable ADC0 module and delay a few clocks. */ + LM4_SYSTEM_RCGCADC = 1; + clock_wait_cycles(3); + + /* + * Use external voltage references (VREFA+, VREFA-) instead of + * VDDA and GNDA. + */ LM4_ADC_ADCCTL = 0x01; /* Use internal oscillator */ LM4_ADC_ADCCC = 0x1; + /* Disable the PLL now that the ADC is using the internal oscillator */ + clock_enable_pll(0, 0); + + /* No tasks waiting yet */ + for (i = 0; i < LM4_ADC_SEQ_COUNT; i++) + task_waiting_on_ss[i] = TASK_ID_INVALID; + /* Enable interrupt */ LM4_ADC_ADCIM = 0xF; task_enable_irq(LM4_IRQ_ADC0_SS0); diff --git a/chip/lm4/clock.c b/chip/lm4/clock.c index 6031767872..65dc62d069 100644 --- a/chip/lm4/clock.c +++ b/chip/lm4/clock.c @@ -64,7 +64,7 @@ static void enable_pll(void) } -int clock_enable_pll(int enable) +int clock_enable_pll(int enable, int notify) { if (enable) enable_pll(); @@ -72,7 +72,7 @@ int clock_enable_pll(int enable) disable_pll(); /* Notify modules of frequency change */ - return hook_notify(HOOK_FREQ_CHANGE, 0); + return notify ? hook_notify(HOOK_FREQ_CHANGE, 0) : EC_SUCCESS; } @@ -211,9 +211,9 @@ static int command_pll(int argc, char **argv) /* Toggle the PLL */ if (argc > 1) { if (!strcasecmp(argv[1], "off")) - clock_enable_pll(0); + clock_enable_pll(0, 1); else if (!strcasecmp(argv[1], "on")) - clock_enable_pll(1); + clock_enable_pll(1, 1); else { /* Disable PLL and set extra divider */ char *e; @@ -279,8 +279,8 @@ int clock_init(void) if (!system_jumped_to_this_image()) clock_wait_cycles(500000); - /* Start out with PLL enabled */ - enable_pll(); + /* Make sure PLL is disabled */ + disable_pll(); return EC_SUCCESS; } diff --git a/common/main.c b/common/main.c index 79ad7bfac2..22906cb7be 100644 --- a/common/main.c +++ b/common/main.c @@ -52,7 +52,7 @@ int main(void) #ifdef CONFIG_FLASH /* - * Initialize flash and apply write protecte if necessary. Requires + * Initialize flash and apply write protect if necessary. Requires * the reset flags calculated by system initialization. */ flash_pre_init(); @@ -121,10 +121,6 @@ int main(void) */ hook_notify(HOOK_INIT, 0); -#ifdef BOARD_link - /* Reduce core clock now that init is done */ - clock_enable_pll(0); -#endif /* * Print the init time. Not completely accurate because it can't take * into account the time before timer_init(), but it'll at least catch diff --git a/include/clock.h b/include/clock.h index c28dbb1bf2..1d2506029d 100644 --- a/include/clock.h +++ b/include/clock.h @@ -3,24 +3,40 @@ * found in the LICENSE file. */ -/* Clocks and power management settings */ +/* Clocks and power management settings */ #ifndef __CROS_EC_CLOCK_H #define __CROS_EC_CLOCK_H #include "common.h" -/* Set the CPU clocks and PLLs. */ +/** + * Set the CPU clocks and PLLs. + */ int clock_init(void); -/* Return the current clock frequency in Hz. */ +/** + * Return the current clock frequency in Hz. + */ int clock_get_freq(void); -/* Enable or disable the PLL. */ -int clock_enable_pll(int enable); - -/* Wait <cycles> system clock cycles. Simple busy waiting for before - * clocks/timers are initialized. */ +/** + * Enable or disable the PLL. + * + * @param enable Enable PLL if non-zero; disable if zero. + * @param notify Notify other modules of the PLL change. This should + * be 1 unless you're briefly turning on the PLL to work + * around a chip errata at init time. + */ +int clock_enable_pll(int enable, int notify); + +/** + * Wait for a number of clock cycles. + * + * Simple busy waiting for use before clocks/timers are initialized. + * + * @param cycles Number of cycles to wait. + */ void clock_wait_cycles(uint32_t cycles); /* Low power modes for idle API */ |