static void clock_module_disable(void) { /* bit0: FSPI interface tri-state */ IT83XX_SMFI_FLHCTRL3R |= (1 << 0); /* bit7: USB pad power-on disable */ IT83XX_GCTRL_PMER2 &= ~(1 << 7); clock_disable_peripheral((CGC_OFFSET_EGPC | CGC_OFFSET_CIR), 0, 0); clock_disable_peripheral((CGC_OFFSET_SMBA | CGC_OFFSET_SMBB | CGC_OFFSET_SMBC | CGC_OFFSET_SMBD | CGC_OFFSET_SMBE | CGC_OFFSET_SMBF), 0, 0); clock_disable_peripheral((CGC_OFFSET_SSPI | CGC_OFFSET_PECI | CGC_OFFSET_USB), 0, 0); }
static void adc_init(void) { int i; /* Configure GPIOs */ configure_gpio(); /* * 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 in run and sleep modes. */ clock_enable_peripheral(CGC_OFFSET_ADC, 0x1, CGC_MODE_RUN | CGC_MODE_SLEEP); /* * 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 IRQs */ 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); /* 2**6 = 64x oversampling */ LM4_ADC_ADCSAC = 6; /* Initialize ADC sequencer */ for (i = 0; i < ADC_CH_COUNT; ++i) adc_configure(adc_channels + i); /* Disable ADC0 module until it is needed to conserve power. */ clock_disable_peripheral(CGC_OFFSET_ADC, 0x1, CGC_MODE_RUN | CGC_MODE_SLEEP); }
int adc_read_channel(enum adc_channel ch) { const struct adc_t *adc = adc_channels + ch; static uint32_t ch_busy_mask; static struct mutex adc_clock; int rv; /* * TODO(crbug.com/314121): Generalize ADC reads such that any task can * trigger a read of any channel. */ /* * Enable ADC clock and set a bit in ch_busy_mask to signify that this * channel is busy. Note, this function may be called from multiple * tasks, but each channel may be read by only one task. If assert * fails, then it means multiple tasks are trying to read same channel. */ mutex_lock(&adc_clock); ASSERT(!(ch_busy_mask & (1UL << ch))); clock_enable_peripheral(CGC_OFFSET_ADC, 0x1, CGC_MODE_RUN | CGC_MODE_SLEEP); ch_busy_mask |= (1UL << ch); mutex_unlock(&adc_clock); rv = flush_and_read(adc->sequencer); /* * If no ADC channels are busy, then disable ADC clock to conserve * power. */ mutex_lock(&adc_clock); ch_busy_mask &= ~(1UL << ch); if (!ch_busy_mask) clock_disable_peripheral(CGC_OFFSET_ADC, 0x1, CGC_MODE_RUN | CGC_MODE_SLEEP); mutex_unlock(&adc_clock); if (rv == ADC_READ_ERROR) return ADC_READ_ERROR; return rv * adc->factor_mul / adc->factor_div + adc->shift; }