diff options
Diffstat (limited to 'chip/npcx/adc.c')
-rw-r--r-- | chip/npcx/adc.c | 390 |
1 files changed, 0 insertions, 390 deletions
diff --git a/chip/npcx/adc.c b/chip/npcx/adc.c deleted file mode 100644 index ea16589d9b..0000000000 --- a/chip/npcx/adc.c +++ /dev/null @@ -1,390 +0,0 @@ -/* Copyright 2014 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. - */ - -/* NPCX-specific ADC module for Chrome EC */ - -#include "adc.h" -#include "atomic.h" -#include "clock.h" -#include "clock_chip.h" -#include "console.h" -#include "common.h" -#include "gpio.h" -#include "hooks.h" -#include "registers.h" -#include "system.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args) - -/* Maximum time we allow for an ADC conversion */ -#define ADC_TIMEOUT_US SECOND -#define ADC_CLK 2000000 -#define ADC_REGULAR_DLY 0x11 -#define ADC_REGULAR_ADCCNF2 0x8B07 -#define ADC_REGULAR_GENDLY 0x0100 -#define ADC_REGULAR_MEAST 0x0001 - -/* ADC conversion mode */ -enum npcx_adc_conversion_mode { - ADC_CHN_CONVERSION_MODE = 0, - ADC_SCAN_CONVERSION_MODE = 1 -}; - -/* Global variables */ -static volatile task_id_t task_waiting; - -struct mutex adc_lock; - -/** - * Preset ADC operation clock. - * - * @param none - * @return none - * @notes changed when initial or HOOK_FREQ_CHANGE command - */ -void adc_freq_changed(void) -{ - uint8_t prescaler_divider = 0; - - /* Set clock prescaler divider to ADC module*/ - prescaler_divider = (uint8_t)(clock_get_apb1_freq() / ADC_CLK); - if (prescaler_divider >= 1) - prescaler_divider = prescaler_divider - 1; - if (prescaler_divider > 0x3F) - prescaler_divider = 0x3F; - - /* Set Core Clock Division Factor in order to obtain the ADC clock */ - SET_FIELD(NPCX_ATCTL, NPCX_ATCTL_SCLKDIV_FIELD, prescaler_divider); -} -DECLARE_HOOK(HOOK_FREQ_CHANGE, adc_freq_changed, HOOK_PRIO_DEFAULT); - -/** - * Flush an ADC sequencer and initiate a read. - * - * @param input_ch operation channel - * @param timeout preset timeout - * @return TRUE/FALSE success/fail - * @notes set SW-triggered interrupt conversion and one-shot mode in npcx chip - */ -static int start_single_and_wait(enum npcx_adc_input_channel input_ch - , int timeout) -{ - int event; - - task_waiting = task_get_current(); - - /* Stop ADC conversion first */ - SET_BIT(NPCX_ADCCNF, NPCX_ADCCNF_STOP); - - /* Set ADC conversion code to SW conversion mode */ - SET_FIELD(NPCX_ADCCNF, NPCX_ADCCNF_ADCMD_FIELD, - ADC_CHN_CONVERSION_MODE); - - /* Set conversion type to one-shot type */ - CLEAR_BIT(NPCX_ADCCNF, NPCX_ADCCNF_ADCRPTC); - - /* Update number of channel to be converted */ - SET_FIELD(NPCX_ASCADD, NPCX_ASCADD_SADDR_FIELD, input_ch); - - /* Clear End-of-Conversion Event status */ - SET_BIT(NPCX_ADCSTS, NPCX_ADCSTS_EOCEV); - - /* Enable ADC End-of-Conversion Interrupt if applicable */ - SET_BIT(NPCX_ADCCNF, NPCX_ADCCNF_INTECEN); - - /* Start conversion */ - SET_BIT(NPCX_ADCCNF, NPCX_ADCCNF_START); - - /* Wait for interrupt */ - event = task_wait_event_mask(TASK_EVENT_ADC_DONE, timeout); - - task_waiting = TASK_ID_INVALID; - - return (event == TASK_EVENT_ADC_DONE); - -} - -static uint16_t repetitive_enabled; -void npcx_set_adc_repetitive(enum npcx_adc_input_channel input_ch, int enable) -{ - mutex_lock(&adc_lock); - - /* Stop ADC conversion */ - SET_BIT(NPCX_ADCCNF, NPCX_ADCCNF_STOP); - - if (enable) { - /* Forbid EC enter deep sleep during conversion. */ - disable_sleep(SLEEP_MASK_ADC); - /* Turn on ADC */ - SET_BIT(NPCX_ADCCNF, NPCX_ADCCNF_ADCEN); - /* Set ADC conversion code to SW conversion mode */ - SET_FIELD(NPCX_ADCCNF, NPCX_ADCCNF_ADCMD_FIELD, - ADC_SCAN_CONVERSION_MODE); - /* Update number of channel to be converted */ - SET_BIT(NPCX_ADCCS, input_ch); - /* Set conversion type to repetitive (runs continuously) */ - SET_BIT(NPCX_ADCCNF, NPCX_ADCCNF_ADCRPTC); - repetitive_enabled |= BIT(input_ch); - - /* Start conversion */ - SET_BIT(NPCX_ADCCNF, NPCX_ADCCNF_START); - } else { - CLEAR_BIT(NPCX_ADCCS, input_ch); - repetitive_enabled &= ~BIT(input_ch); - - if (!repetitive_enabled) { - /* Turn off ADC */ - CLEAR_BIT(NPCX_ADCCNF, NPCX_ADCCNF_ADCEN); - /* Set ADC to one-shot mode */ - CLEAR_BIT(NPCX_ADCCNF, NPCX_ADCCNF_ADCRPTC); - /* Allow ec enter deep sleep */ - enable_sleep(SLEEP_MASK_ADC); - } else { - /* Start conversion again */ - SET_BIT(NPCX_ADCCNF, NPCX_ADCCNF_START); - } - } - - mutex_unlock(&adc_lock); -} - -/** - * Return the ADC value from CHNDAT register directly. - * - * @param input_ch channel number - * @return ADC data - */ -int adc_read_data(enum npcx_adc_input_channel input_ch) -{ - const struct adc_t *adc = adc_channels + input_ch; - int value; - uint16_t chn_data; - - chn_data = NPCX_CHNDAT(adc->input_ch); - value = GET_FIELD(chn_data, NPCX_CHNDAT_CHDAT_FIELD) * - adc->factor_mul / adc->factor_div + adc->shift; - return value; -} - -/** - * Start a single conversion and return the result - * - * @param ch operation channel - * @return ADC converted voltage or error message - */ -int adc_read_channel(enum adc_channel ch) -{ - const struct adc_t *adc = adc_channels + ch; - int value; - uint16_t chn_data; - - mutex_lock(&adc_lock); - - /* Forbid ec enter deep sleep during ADC conversion is proceeding. */ - disable_sleep(SLEEP_MASK_ADC); - - /* Turn on ADC */ - SET_BIT(NPCX_ADCCNF, NPCX_ADCCNF_ADCEN); - - if (start_single_and_wait(adc->input_ch, ADC_TIMEOUT_US)) { - chn_data = NPCX_CHNDAT(adc->input_ch); - if ((adc->input_ch == - GET_FIELD(NPCX_ASCADD, NPCX_ASCADD_SADDR_FIELD)) - && (IS_BIT_SET(chn_data, - NPCX_CHNDAT_NEW))) { - value = GET_FIELD(chn_data, NPCX_CHNDAT_CHDAT_FIELD) * - adc->factor_mul / adc->factor_div + adc->shift; - } else { - value = ADC_READ_ERROR; - } - } else { - value = ADC_READ_ERROR; - } - - if (!repetitive_enabled) { - /* Turn off ADC */ - CLEAR_BIT(NPCX_ADCCNF, NPCX_ADCCNF_ADCEN); - /* Allow ec enter deep sleep */ - enable_sleep(SLEEP_MASK_ADC); - } else { - /* Set ADC conversion code to SW conversion mode */ - SET_FIELD(NPCX_ADCCNF, NPCX_ADCCNF_ADCMD_FIELD, - ADC_SCAN_CONVERSION_MODE); - /* Set conversion type to repetitive (runs continuously) */ - SET_BIT(NPCX_ADCCNF, NPCX_ADCCNF_ADCRPTC); - /* Start conversion */ - SET_BIT(NPCX_ADCCNF, NPCX_ADCCNF_START); - } - - mutex_unlock(&adc_lock); - - return value; -} - -/* Board should register these callbacks with npcx_adc_cfg_thresh_int(). */ -static void (*adc_thresh_irqs[NPCX_ADC_THRESH_CNT])(void); - -void npcx_adc_thresh_int_enable(int threshold_idx, int enable) -{ - uint16_t thrcts; - - enable = !!enable; - - if ((threshold_idx < 1) || (threshold_idx > NPCX_ADC_THRESH_CNT)) { - CPRINTS("Invalid ADC thresh index! (%d)", - threshold_idx); - return; - } - threshold_idx--; /* convert to 0-based */ - - /* avoid clearing other threshold status */ - thrcts = NPCX_THRCTS & ~GENMASK(NPCX_ADC_THRESH_CNT - 1, 0); - - if (enable) { - /* clear threshold status */ - SET_BIT(thrcts, threshold_idx); - /* set enable threshold status */ - SET_BIT(thrcts, NPCX_THRCTS_THR1_IEN + threshold_idx); - } else { - CLEAR_BIT(thrcts, NPCX_THRCTS_THR1_IEN + threshold_idx); - } - NPCX_THRCTS = thrcts; -} - -void npcx_adc_register_thresh_irq(int threshold_idx, - const struct npcx_adc_thresh_t *thresh_cfg) -{ - int npcx_adc_ch; - int raw_val; - int mul; - int div; - int shift; - - if ((threshold_idx < 1) || (threshold_idx > NPCX_ADC_THRESH_CNT)) { - CPRINTS("Invalid ADC thresh index! (%d)", - threshold_idx); - return; - } - npcx_adc_ch = adc_channels[thresh_cfg->adc_ch].input_ch; - - if (!thresh_cfg->adc_thresh_cb) { - CPRINTS("No callback for ADC Threshold %d!", - threshold_idx); - return; - } - - /* Fill in the table */ - adc_thresh_irqs[threshold_idx-1] = thresh_cfg->adc_thresh_cb; - - /* Select the channel */ - SET_FIELD(NPCX_THRCTL(threshold_idx), NPCX_THRCTL_CHNSEL, - npcx_adc_ch); - - if (thresh_cfg->lower_or_higher) - SET_BIT(NPCX_THRCTL(threshold_idx), NPCX_THRCTL_L_H); - else - CLEAR_BIT(NPCX_THRCTL(threshold_idx), NPCX_THRCTL_L_H); - - /* Set the threshold value. */ - mul = adc_channels[thresh_cfg->adc_ch].factor_mul; - div = adc_channels[thresh_cfg->adc_ch].factor_div; - shift = adc_channels[thresh_cfg->adc_ch].shift; - - raw_val = (thresh_cfg->thresh_assert - shift) * div / mul; - CPRINTS("ADC THR%d: Setting THRVAL = %d, L_H: %d", threshold_idx, - raw_val, thresh_cfg->lower_or_higher); - SET_FIELD(NPCX_THRCTL(threshold_idx), NPCX_THRCTL_THRVAL, - raw_val); - -#if NPCX_FAMILY_VERSION <= NPCX_FAMILY_NPCX7 - /* Disable deassertion threshold function */ - CLEAR_BIT(NPCX_THR_DCTL(threshold_idx), NPCX_THR_DCTL_THRD_EN); -#endif - - /* Enable threshold detection */ - SET_BIT(NPCX_THRCTL(threshold_idx), NPCX_THRCTL_THEN); -} - -/** - * ADC interrupt handler - * - * @param none - * @return none - * @notes Only handle SW-triggered conversion in npcx chip - */ -void adc_interrupt(void) -{ - int i; - uint16_t thrcts; - - if (IS_BIT_SET(NPCX_ADCCNF, NPCX_ADCCNF_INTECEN) && - IS_BIT_SET(NPCX_ADCSTS, NPCX_ADCSTS_EOCEV)) { - /* Disable End-of-Conversion Interrupt */ - CLEAR_BIT(NPCX_ADCCNF, NPCX_ADCCNF_INTECEN); - - /* Stop conversion for single-shot mode */ - if (!repetitive_enabled) - SET_BIT(NPCX_ADCCNF, NPCX_ADCCNF_STOP); - - /* Clear End-of-Conversion Event status */ - SET_BIT(NPCX_ADCSTS, NPCX_ADCSTS_EOCEV); - - /* Wake up the task which was waiting for the interrupt */ - if (task_waiting != TASK_ID_INVALID) - task_set_event(task_waiting, TASK_EVENT_ADC_DONE); - } - - for (i = NPCX_THRCTS_THR1_STS; i < NPCX_ADC_THRESH_CNT; i++) { - if (IS_BIT_SET(NPCX_THRCTS, NPCX_THRCTS_THR1_IEN + i) && - IS_BIT_SET(NPCX_THRCTS, i)) { - /* avoid clearing other threshold status */ - thrcts = NPCX_THRCTS & - ~GENMASK(NPCX_ADC_THRESH_CNT - 1, 0); - /* Clear threshold status */ - SET_BIT(thrcts, i); - NPCX_THRCTS = thrcts; - if (adc_thresh_irqs[i]) - adc_thresh_irqs[i](); - } - } -} -DECLARE_IRQ(NPCX_IRQ_ADC, adc_interrupt, 4); - -/** - * ADC initial. - * - * @param none - * @return none - */ -static void adc_init(void) -{ - /* Configure pins from GPIOs to ADCs */ - gpio_config_module(MODULE_ADC, 1); - - /* Enable ADC clock (bit4 mask = 0x10) */ - clock_enable_peripheral(CGC_OFFSET_ADC, CGC_ADC_MASK, - CGC_MODE_RUN | CGC_MODE_SLEEP); - - /* Set Core Clock Division Factor in order to obtain the ADC clock */ - adc_freq_changed(); - - /* Set regular speed */ - SET_FIELD(NPCX_ATCTL, NPCX_ATCTL_DLY_FIELD, (ADC_REGULAR_DLY - 1)); - - /* Set the other ADC settings */ - NPCX_ADCCNF2 = ADC_REGULAR_ADCCNF2; - NPCX_GENDLY = ADC_REGULAR_GENDLY; - NPCX_MEAST = ADC_REGULAR_MEAST; - - task_waiting = TASK_ID_INVALID; - - /* Enable IRQs */ - task_enable_irq(NPCX_IRQ_ADC); -} -DECLARE_HOOK(HOOK_INIT, adc_init, HOOK_PRIO_INIT_ADC); |