diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index 9ecca0b0afe..b33f726e2f1 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -1,8 +1,8 @@ zephyr_library() -zephyr_library_sources_ifdef(CONFIG_ADC_DW adc_dw.c) zephyr_library_sources_ifdef(CONFIG_ADC_MCUX_ADC16 adc_mcux_adc16.c) zephyr_library_sources_ifdef(CONFIG_ADC_SAM_AFEC adc_sam_afec.c) zephyr_library_sources_ifdef(CONFIG_ADC_NRFX_ADC adc_nrfx_adc.c) zephyr_library_sources_ifdef(CONFIG_ADC_NRFX_SAADC adc_nrfx_saadc.c) +zephyr_library_sources_ifdef(CONFIG_ADC_INTEL_QUARK_SE_C1000_SS adc_intel_quark_se_c1000_ss.c) zephyr_library_sources_ifdef(CONFIG_ADC_INTEL_QUARK_D2000 adc_intel_quark_d2000.c) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 71ac55ab411..04ae5f0bf2b 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -47,8 +47,6 @@ config ADC_0 config ADC_1 bool "Enable ADC 1" -source "drivers/adc/Kconfig.dw" - source "drivers/adc/Kconfig.mcux" source "drivers/adc/Kconfig.nrfx" diff --git a/drivers/adc/Kconfig.dw b/drivers/adc/Kconfig.dw deleted file mode 100644 index 1c235d91f3f..00000000000 --- a/drivers/adc/Kconfig.dw +++ /dev/null @@ -1,71 +0,0 @@ -# Kconfig - ADC configuration options - -# -# Copyright (c) 2015 Intel Corporation -# -# SPDX-License-Identifier: Apache-2.0 -# - -menuconfig ADC_DW - bool "ARC Designware Driver" - depends on ARC - select ADC_0 - help - Enable the driver implementation of the Designware ADC IP. - -if ADC_DW - - -config ADC_DW_CALIBRATION - bool "Enable Calibration" - default y - help - Enables ADC to run with a calibrated output at the - expense of execution speed when exiting low power states. - If disabled, the ADC will require the application/system-integrator - to provide a calibration method. - -choice - prompt "Output Mode" - default ADC_DW_SERIAL - help - ADC output mode: parallel or serial. - -config ADC_DW_SERIAL - bool "Serial" - -config ADC_DW_PARALLEL - bool "Parallel" - -endchoice - -choice - prompt "Capture Mode" - default ADC_DW_RISING_EDGE - help - ADC controller capture mode: - by rising or falling edge of adc_clk - -config ADC_DW_RISING_EDGE - bool "Rising Edge" - -config ADC_DW_FALLING_EDGE - bool "Falling Edge" - -endchoice - -config ADC_DW_SERIAL_DELAY - int "Serial Delay" - default 1 - help - Number of ADC clock ticks that the first bit of - the serial output is delayed after the conversion - has started. - -config ADC_DW_CLOCK_RATIO - int "Clock Ratio" - default 1024 - help - ADC Clock Ratio - -endif # ADC_DW diff --git a/drivers/adc/Kconfig.intel_quark b/drivers/adc/Kconfig.intel_quark index 49097a476d1..b102977582a 100644 --- a/drivers/adc/Kconfig.intel_quark +++ b/drivers/adc/Kconfig.intel_quark @@ -1,11 +1,75 @@ # Kconfig - ADC configuration options # -# Copyright (c) 2018 Intel Corporation +# Copyright (c) 2018-2019 Intel Corporation # # SPDX-License-Identifier: Apache-2.0 # +menuconfig ADC_INTEL_QUARK_SE_C1000_SS + bool "ADC Driver for Intel Quark SE C1000 Sensor Subsystem" + depends on SOC_QUARK_SE_C1000_SS + select ADC_0 + help + Enable the ADC driver implementation of the Intel Quark SE C1000 + Sensor Subsystem. + +if ADC_INTEL_QUARK_SE_C1000_SS + +config ADC_INTEL_QUARK_SE_C1000_SS_CALIBRATION + bool "Enable Calibration" + default y + help + Enables ADC to run with a calibrated output at the + expense of execution speed when exiting low power states. + If disabled, the ADC will require the application/system-integrator + to provide a calibration method. + +choice + prompt "Output Mode" + default ADC_INTEL_QUARK_SE_C1000_SS_SERIAL + help + ADC output mode: parallel or serial. + +config ADC_INTEL_QUARK_SE_C1000_SS_SERIAL + bool "Serial" + +config ADC_INTEL_QUARK_SE_C1000_SS_PARALLEL + bool "Parallel" + +endchoice + +choice + prompt "Capture Mode" + default ADC_INTEL_QUARK_SE_C1000_SS_RISING_EDGE + help + ADC controller capture mode: + by rising or falling edge of adc_clk + +config ADC_INTEL_QUARK_SE_C1000_SS_RISING_EDGE + bool "Rising Edge" + +config ADC_INTEL_QUARK_SE_C1000_SS_FALLING_EDGE + bool "Falling Edge" + +endchoice + +config ADC_INTEL_QUARK_SE_C1000_SS_SERIAL_DELAY + int "Serial Delay" + default 1 + help + Number of ADC clock ticks that the first bit of + the serial output is delayed after the conversion + has started. + +config ADC_INTEL_QUARK_SE_C1000_SS_CLOCK_RATIO + int "Clock Ratio" + default 1024 + help + ADC Clock Ratio + +endif # ADC_INTEL_QUARK_SE_C1000_SS + menuconfig ADC_INTEL_QUARK_D2000 bool "ADC Driver for Intel Quark D2000" depends on SOC_QUARK_D2000 diff --git a/drivers/adc/adc_dw.c b/drivers/adc/adc_dw.c deleted file mode 100644 index 119a9a8f227..00000000000 --- a/drivers/adc/adc_dw.c +++ /dev/null @@ -1,521 +0,0 @@ -/* adc_dw.c - Designware ADC driver */ - -/* - * Copyright (c) 2015 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#define ADC_CONTEXT_USES_KERNEL_TIMER -#include "adc_context.h" -#include "adc_dw.h" - -#define LOG_LEVEL CONFIG_ADC_LOG_LEVEL -#include -LOG_MODULE_REGISTER(adc_dw); - -#define ADC_CLOCK_GATE (1 << 31) -#define ADC_DEEP_POWER_DOWN 0x01 -#define ADC_POWER_DOWN 0x01 -#define ADC_STANDBY 0x02 -#define ADC_NORMAL_WITH_CALIB 0x03 -#define ADC_NORMAL_WO_CALIB 0x04 -#define ADC_MODE_MASK 0x07 - -#define ONE_BIT_SET 0x1 -#define THREE_BITS_SET 0x7 -#define FIVE_BITS_SET 0x1f -#define SIX_BITS_SET 0x3f -#define SEVEN_BITS_SET 0xef -#define ELEVEN_BITS_SET 0x7ff - -#define INPUT_MODE_POS 5 -#define CAPTURE_MODE_POS 6 -#define OUTPUT_MODE_POS 7 -#define SERIAL_DELAY_POS 8 -#define SEQUENCE_MODE_POS 13 -#define SEQ_ENTRIES_POS 16 -#define THRESHOLD_POS 24 - -#define SEQ_DELAY_EVEN_POS 5 -#define SEQ_MUX_ODD_POS 16 -#define SEQ_DELAY_ODD_POS 21 - -#ifdef CONFIG_SOC_QUARK_SE_C1000_SS -#define int_unmask(__mask) \ - sys_write32(sys_read32((__mask)) & ENABLE_SSS_INTERRUPTS, (__mask)) -#else -#define int_unmask(...) { ; } -#endif -static void adc_config_irq(void); - - -struct adc_info adc_info_dev = { - ADC_CONTEXT_INIT_TIMER(adc_info_dev, ctx), - ADC_CONTEXT_INIT_LOCK(adc_info_dev, ctx), - ADC_CONTEXT_INIT_SYNC(adc_info_dev, ctx), - .state = ADC_STATE_IDLE, -#ifdef CONFIG_ADC_DW_CALIBRATION - .calibration_value = ADC_NONE_CALIBRATION, -#endif -}; - -#ifdef CONFIG_ADC_DW_CALIBRATION -static void calibration_command(u8_t command) -{ - u32_t state; - u32_t reg_value; - - state = irq_lock(); - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_MST0); - reg_value |= (command & THREE_BITS_SET) << 17; - reg_value |= 0x10000; - sys_out32(reg_value, PERIPH_ADDR_BASE_CREG_MST0); - irq_unlock(state); - /*Poll waiting for command*/ - do { - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); - } while ((reg_value & BIT(4)) == 0); - - /*Clear Calibration Request*/ - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_MST0); - reg_value &= ~(0x10000); - sys_out32(reg_value, PERIPH_ADDR_BASE_CREG_MST0); -} - -static void adc_goto_normal_mode(struct device *dev) -{ - struct adc_info *info = dev->driver_data; - u8_t calibration_value; - u32_t reg_value; - u32_t state; - - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); - - if ((reg_value & ADC_MODE_MASK) != ADC_NORMAL_WITH_CALIB) { - - state = irq_lock(); - /*Request Normal With Calibration Mode*/ - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_MST0); - reg_value &= ~(ADC_MODE_MASK); - reg_value |= ADC_NORMAL_WITH_CALIB; - sys_out32(reg_value, PERIPH_ADDR_BASE_CREG_MST0); - irq_unlock(state); - - /*Poll waiting for normal mode*/ - do { - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); - } while ((reg_value & BIT(3)) == 0); - - if (info->calibration_value == ADC_NONE_CALIBRATION) { - /*Reset Calibration*/ - calibration_command(ADC_CMD_RESET_CALIBRATION); - /*Request Calibration*/ - calibration_command(ADC_CMD_START_CALIBRATION); - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); - calibration_value = (reg_value >> 5) & SEVEN_BITS_SET; - info->calibration_value = calibration_value; - } - - /*Load Calibration*/ - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_MST0); - reg_value |= (info->calibration_value << 20); - sys_out32(reg_value, PERIPH_ADDR_BASE_CREG_MST0); - calibration_command(ADC_CMD_LOAD_CALIBRATION); - } -} - -#else -static void adc_goto_normal_mode(struct device *dev) -{ - u32_t reg_value; - u32_t state; - - ARG_UNUSED(dev); - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); - - if ((reg_value & ADC_MODE_MASK) == ADC_NORMAL_WO_CALIB) { - state = irq_lock(); - /*Request Power Down*/ - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_MST0); - - reg_value &= ~(ADC_MODE_MASK); - reg_value |= ADC_POWER_DOWN; - - sys_out32(reg_value, PERIPH_ADDR_BASE_CREG_MST0); - irq_unlock(state); - - do { - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); - } while ((reg_value & BIT(3)) == 0); - } - - /*Request Normal With Calibration Mode*/ - state = irq_lock(); - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_MST0); - reg_value &= ~(ADC_MODE_MASK); - reg_value |= ADC_NORMAL_WO_CALIB; - sys_out32(reg_value, PERIPH_ADDR_BASE_CREG_MST0); - irq_unlock(state); - - /*Poll waiting for normal mode*/ - do { - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); - } while ((reg_value & BIT(3)) == 0); -} -#endif - -static int set_resolution(struct device *dev, - const struct adc_sequence *sequence) -{ - u32_t tmp_val; - const struct adc_config *config = dev->config->config_info; - u32_t adc_base = config->reg_base; - - tmp_val = sys_in32(adc_base + ADC_SET); - tmp_val &= ~FIVE_BITS_SET; - - switch (sequence->resolution) { - case 6: - break; - case 8: - tmp_val |= 1 & FIVE_BITS_SET; - break; - case 10: - tmp_val |= 2 & FIVE_BITS_SET; - break; - case 12: - tmp_val |= 3 & FIVE_BITS_SET; - break; - default: - return -EINVAL; - } - - sys_out32(tmp_val, adc_base + ADC_SET); - - return 0; -} - -static void adc_dw_enable(struct device *dev) -{ - u32_t reg_value; - struct adc_info *info = dev->driver_data; - const struct adc_config *config = dev->config->config_info; - u32_t adc_base = config->reg_base; - - /*Go to Normal Mode*/ - sys_out32(ADC_INT_DSB|ENABLE_ADC, adc_base + ADC_CTRL); - adc_goto_normal_mode(dev); - - /*Clock Gate*/ - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_MST0); - reg_value &= ~(ADC_CLOCK_GATE); - sys_out32(reg_value, PERIPH_ADDR_BASE_CREG_MST0); - sys_out32(ENABLE_ADC, adc_base + ADC_CTRL); - - info->state = ADC_STATE_IDLE; -} - -/* Implementation of the ADC driver API function: adc_channel_setup. */ -static int adc_dw_channel_setup(struct device *dev, - const struct adc_channel_cfg *channel_cfg) -{ - u8_t channel_id = channel_cfg->channel_id; - struct adc_info *info = dev->driver_data; - - if (channel_id >= DW_CHANNEL_COUNT) { - LOG_ERR("Invalid channel id"); - return -EINVAL; - } - - if (channel_cfg->gain != ADC_GAIN_1) { - LOG_ERR("Invalid channel gain"); - return -EINVAL; - } - - if (channel_cfg->reference != ADC_REF_INTERNAL) { - LOG_ERR("Invalid channel reference"); - return -EINVAL; - } - - if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { - LOG_ERR("Invalid channel acquisition time"); - return -EINVAL; - } - - if (info->state != ADC_STATE_IDLE) { - LOG_ERR("ADC is busy or in error state"); - return -EAGAIN; - } - - info->active_channels |= 1 << channel_id; - return 0; -} - -static int adc_dw_read_request(struct device *dev, - const struct adc_sequence *seq_tbl) -{ - struct adc_info *info = dev->driver_data; - int error = 0; - u32_t saved; - - /*hardware requires minimum 10 us delay between consecutive samples*/ - if (seq_tbl->options && - seq_tbl->options->extra_samplings && - seq_tbl->options->interval_us < 10) { - return -EINVAL; - } - - info->channels = seq_tbl->channels & info->active_channels; - - if (seq_tbl->channels != info->channels) { - return -EINVAL; - } - - error = set_resolution(dev, seq_tbl); - if (error) { - return error; - } - - saved = irq_lock(); - info->entries = seq_tbl; - info->buffer = (u16_t *)seq_tbl->buffer; - - if (seq_tbl->options) { - info->seq_size = seq_tbl->options->extra_samplings + 1; - } else { - info->seq_size = 1U; - } - - info->state = ADC_STATE_SAMPLING; - irq_unlock(saved); - - adc_context_start_read(&info->ctx, seq_tbl); - error = adc_context_wait_for_completion(&info->ctx); - - if (info->state == ADC_STATE_ERROR) { - info->state = ADC_STATE_IDLE; - return -EIO; - } - - return error; -} - -static int adc_dw_read(struct device *dev, const struct adc_sequence *seq_tbl) -{ - struct adc_info *info = dev->driver_data; - int ret; - - adc_context_lock(&info->ctx, false, NULL); - ret = adc_dw_read_request(dev, seq_tbl); - adc_context_release(&info->ctx, ret); - - return ret; -} - -#ifdef CONFIG_ADC_ASYNC -/* Implementation of the ADC driver API function: adc_read_async. */ -static int adc_dw_read_async(struct device *dev, - const struct adc_sequence *sequence, - struct k_poll_signal *async) -{ - struct adc_info *info = dev->driver_data; - int ret; - - adc_context_lock(&info->ctx, true, async); - ret = adc_dw_read_request(dev, sequence); - adc_context_release(&info->ctx, ret); - - return ret; -} -#endif - -static void adc_dw_start_conversion(struct device *dev) -{ - struct adc_info *info = dev->driver_data; - const struct adc_config *config = info->dev->config->config_info; - const struct adc_sequence *entry = info->ctx.sequence; - u32_t adc_base = config->reg_base; - u32_t ctrl, tmp_val, interval_us = 0U; - - info->channel_id = find_lsb_set(info->channels) - 1; - - ctrl = sys_in32(adc_base + ADC_CTRL); - ctrl |= ADC_SEQ_PTR_RST; - sys_out32(ctrl, adc_base + ADC_CTRL); - - tmp_val = sys_in32(adc_base + ADC_SET); - tmp_val &= ADC_SEQ_SIZE_SET_MASK; - sys_out32(tmp_val, adc_base + ADC_SET); - - if (entry->options) { - interval_us = entry->options->interval_us; - } - tmp_val = ((interval_us & ELEVEN_BITS_SET) - << SEQ_DELAY_EVEN_POS); - tmp_val |= (info->channel_id & FIVE_BITS_SET); - - sys_out32(tmp_val, adc_base + ADC_SEQ); - sys_out32(ctrl | ADC_SEQ_PTR_RST, adc_base + ADC_CTRL); - - sys_out32(START_ADC_SEQ, adc_base + ADC_CTRL); -} - -static void adc_context_start_sampling(struct adc_context *ctx) -{ - struct adc_info *info = CONTAINER_OF(ctx, struct adc_info, ctx); - - info->channels = ctx->sequence->channels; - - adc_dw_start_conversion(info->dev); -} - -static void adc_context_update_buffer_pointer(struct adc_context *ctx, - bool repeat) -{ - struct adc_info *info = CONTAINER_OF(ctx, struct adc_info, ctx); - const struct adc_sequence *entry = ctx->sequence; - - if (repeat) { - info->buffer = (u16_t *)entry->buffer; - } -} - -int adc_dw_init(struct device *dev) -{ - u32_t tmp_val; - u32_t val; - const struct adc_config *config = dev->config->config_info; - u32_t adc_base = config->reg_base; - struct adc_info *info = dev->driver_data; - - sys_out32(ADC_INT_DSB | ADC_CLK_ENABLE, adc_base + ADC_CTRL); - - tmp_val = sys_in32(adc_base + ADC_SET); - tmp_val &= ADC_CONFIG_SET_MASK; - val = ((config->capture_mode & ONE_BIT_SET) << CAPTURE_MODE_POS); - val |= ((config->out_mode & ONE_BIT_SET) << OUTPUT_MODE_POS); - val |= ((config->serial_dly & FIVE_BITS_SET) << SERIAL_DELAY_POS); - val |= ((config->seq_mode & ONE_BIT_SET) << SEQUENCE_MODE_POS); - val &= ~(1 << INPUT_MODE_POS); - sys_out32(tmp_val|val, adc_base + ADC_SET); - - sys_out32(config->clock_ratio & ADC_CLK_RATIO_MASK, - adc_base + ADC_DIVSEQSTAT); - - sys_out32(ADC_INT_ENABLE & ~(ADC_CLK_ENABLE), - adc_base + ADC_CTRL); - - config->config_func(); - - int_unmask(config->reg_irq_mask); - int_unmask(config->reg_err_mask); - - info->dev = dev; - - adc_dw_enable(dev); - adc_context_unlock_unconditionally(&info->ctx); - return 0; -} - -static void adc_dw_rx_isr(void *arg) -{ - struct device *dev = (struct device *)arg; - struct adc_info *info = dev->driver_data; - const struct adc_config *config = dev->config->config_info; - u32_t adc_base = config->reg_base; - u32_t reg_val; - - reg_val = sys_in32(adc_base + ADC_SET); - sys_out32(reg_val|ADC_POP_SAMPLE, adc_base + ADC_SET); - *info->buffer++ = sys_in32(adc_base + ADC_SAMPLE); - - /*Resume ADC state to continue new conversions*/ - sys_out32(RESUME_ADC_CAPTURE, adc_base + ADC_CTRL); - reg_val = sys_in32(adc_base + ADC_SET); - sys_out32(reg_val | ADC_FLUSH_RX, adc_base + ADC_SET); - - /*Clear data A register*/ - reg_val = sys_in32(adc_base + ADC_CTRL); - sys_out32(reg_val | ADC_CLR_DATA_A, adc_base + ADC_CTRL); - - info->state = ADC_STATE_IDLE; - info->channels &= ~BIT(info->channel_id); - - if (info->channels) { - adc_dw_start_conversion(dev); - } else { - adc_context_on_sampling_done(&info->ctx, dev); - } -} - -static void adc_dw_err_isr(void *arg) -{ - struct device *dev = (struct device *) arg; - const struct adc_config *config = dev->config->config_info; - struct adc_info *info = dev->driver_data; - u32_t adc_base = config->reg_base; - u32_t reg_val = sys_in32(adc_base + ADC_SET); - - sys_out32(RESUME_ADC_CAPTURE, adc_base + ADC_CTRL); - sys_out32(reg_val | ADC_FLUSH_RX, adc_base + ADC_CTRL); - sys_out32(FLUSH_ADC_ERRORS, adc_base + ADC_CTRL); - - info->state = ADC_STATE_ERROR; - adc_context_on_sampling_done(&info->ctx, dev); -} - -static const struct adc_driver_api api_funcs = { - .channel_setup = adc_dw_channel_setup, - .read = adc_dw_read, -#ifdef CONFIG_ADC_ASYNC - .read_async = adc_dw_read_async, -#endif -}; - -const static struct adc_config adc_config_dev = { - .reg_base = DT_ADC_0_BASE_ADDRESS, - .reg_irq_mask = SCSS_REGISTER_BASE + INT_SS_ADC_IRQ_MASK, - .reg_err_mask = SCSS_REGISTER_BASE + INT_SS_ADC_ERR_MASK, -#ifdef CONFIG_ADC_DW_SERIAL - .out_mode = 0, -#elif CONFIG_ADC_DW_PARALLEL - .out_mode = 1, -#endif - .seq_mode = 0, - -#ifdef CONFIG_ADC_DW_RISING_EDGE - .capture_mode = 0, -#elif CONFIG_ADC_DW_FALLING_EDGE - .capture_mode = 1, -#endif - .clock_ratio = CONFIG_ADC_DW_CLOCK_RATIO, - .serial_dly = CONFIG_ADC_DW_SERIAL_DELAY, - .config_func = adc_config_irq, -}; - -DEVICE_AND_API_INIT(adc_dw, DT_ADC_0_NAME, &adc_dw_init, - &adc_info_dev, &adc_config_dev, - POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, - &api_funcs); - -static void adc_config_irq(void) -{ - IRQ_CONNECT(DT_ADC_0_IRQ, DT_ADC_0_IRQ_PRI, adc_dw_rx_isr, - DEVICE_GET(adc_dw), 0); - irq_enable(DT_ADC_0_IRQ); - - IRQ_CONNECT(DT_ADC_IRQ_ERR, DT_ADC_0_IRQ_PRI, - adc_dw_err_isr, DEVICE_GET(adc_dw), 0); - irq_enable(DT_ADC_IRQ_ERR); -} diff --git a/drivers/adc/adc_intel_quark_se_c1000_ss.c b/drivers/adc/adc_intel_quark_se_c1000_ss.c new file mode 100644 index 00000000000..4adf5fea55d --- /dev/null +++ b/drivers/adc/adc_intel_quark_se_c1000_ss.c @@ -0,0 +1,663 @@ +/* + * Copyright (c) 2015-2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Intel Quark SE C1000 Sensor Subsystem ADC Driver + * + * This is the driver for the ADC block in the Intel Quark SE C1000 + * Sensor Subsystem. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" +#include "adc_intel_quark_se_c1000_ss.h" + +#define LOG_LEVEL CONFIG_ADC_LOG_LEVEL +#include +LOG_MODULE_REGISTER(adc_intel_quark_se_c1000_ss); + +/* MST */ +#define ADC_CLOCK_GATE BIT(31) +#define ADC_CAL_REQ BIT(16) +#define ADC_DEEP_POWER_DOWN 0x01 +#define ADC_POWER_DOWN 0x01 +#define ADC_STANDBY 0x02 +#define ADC_NORMAL_WITH_CALIB 0x03 +#define ADC_NORMAL_WO_CALIB 0x04 +#define ADC_MODE_MASK 0x07 +#define ADC_DELAY_MASK (0xFFF8) +#define ADC_DELAY_POS 3 +#define ADC_DELAY_32MHZ (160 << ADC_DELAY_POS) + +/* SLV0 */ +#define ADC_CAL_ACK BIT(4) +#define ADC_PWR_MODE_STS BIT(3) + +#define ONE_BIT_SET 0x1 +#define THREE_BITS_SET 0x7 +#define FIVE_BITS_SET 0x1f +#define SIX_BITS_SET 0x3f +#define SEVEN_BITS_SET 0xef +#define ELEVEN_BITS_SET 0x7ff + +#define CAPTURE_MODE_POS 6 +#define OUTPUT_MODE_POS 7 +#define SERIAL_DELAY_POS 8 +#define SEQUENCE_MODE_POS 13 +#define SEQ_ENTRIES_POS 16 +#define THRESHOLD_POS 24 + +#define SEQ_MUX_EVEN_POS 0 +#define SEQ_DELAY_EVEN_POS 5 +#define SEQ_MUX_ODD_POS 16 +#define SEQ_DELAY_ODD_POS 21 + +#define ADC_NONE_CALIBRATION (0x80) + +#ifdef CONFIG_SOC_QUARK_SE_C1000_SS +#define int_unmask(__mask) \ + sys_write32(sys_read32((__mask)) & ENABLE_SSS_INTERRUPTS, (__mask)) +#else +#define int_unmask(...) { ; } +#endif +static void adc_config_irq(void); + + +struct adc_info adc_info_dev = { + ADC_CONTEXT_INIT_TIMER(adc_info_dev, ctx), + ADC_CONTEXT_INIT_LOCK(adc_info_dev, ctx), + ADC_CONTEXT_INIT_SYNC(adc_info_dev, ctx), + .state = ADC_STATE_IDLE, +#ifdef CONFIG_ADC_INTEL_QUARK_SE_C1000_SS_CALIBRATION + .calibration_value = ADC_NONE_CALIBRATION, +#endif +}; + +static inline void wait_slv0_bit_set(u32_t bit_mask) +{ + u32_t reg_value; + + do { + reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); + } while ((reg_value & bit_mask) == 0); +} + +static void set_power_mode_inner(u32_t mode) +{ + u32_t reg_value; + u32_t state; + + state = irq_lock(); + + /* Request Power Down first before transitioning */ + reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_MST0); + + reg_value &= ~(ADC_MODE_MASK); + reg_value |= mode; + + sys_out32(reg_value, PERIPH_ADDR_BASE_CREG_MST0); + + irq_unlock(state); + + /* Wait for power mode to be set */ + wait_slv0_bit_set(ADC_PWR_MODE_STS); +} + +static void set_power_mode(u32_t mode) +{ + u32_t reg_value; + + reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); + + /* no need to set if power mode is the same as requested */ + if ((reg_value & ADC_MODE_MASK) == mode) { + return; + } + + /* Request Power Down first before transitioning */ + set_power_mode_inner(ADC_POWER_DOWN); + + /* Then set to the desired mode */ + set_power_mode_inner(mode); +} + +/* + * A dummy conversion is needed after coming out of deep + * power down, or else the first conversion would not be + * correct. + */ +static void dummy_conversion(struct device *dev) +{ + const struct adc_config *config = dev->config->config_info; + u32_t adc_base = config->reg_base; + u32_t reg_value; + + /* Flush FIFO */ + reg_value = sys_in32(adc_base + ADC_SET); + reg_value |= ADC_SET_FLUSH_RX; + sys_out32(reg_value, adc_base + ADC_SET); + + /* Reset sequence table */ + reg_value = sys_in32(adc_base + ADC_CTRL); + reg_value |= ADC_CTRL_SEQ_TABLE_RST; + sys_out32(reg_value, adc_base + ADC_CTRL); + + /* Setup sequence table for dummy */ + sys_out32((10 << 5), adc_base + ADC_SEQ); + + /* + * Set number of entries in sequencer (n-1) + * and threshold to generate interrupt. + */ + reg_value = sys_in32(adc_base + ADC_SET); + reg_value &= ~(ADC_SET_SEQ_ENTRIES_MASK | ADC_SET_THRESHOLD_MASK); + sys_out32(reg_value, adc_base + ADC_SET); + + /* + * Reset sequence pointer, + * Clear and mask interrupts, + * Enable ADC and start sequencer. + */ + reg_value = sys_in32(adc_base + ADC_CTRL); + reg_value |= ADC_CTRL_SEQ_PTR_RST | ADC_CTRL_INT_CLR_ALL | + ADC_CTRL_INT_MASK_ALL | ADC_CTRL_ENABLE | + ADC_CTRL_SEQ_START; + sys_out32(reg_value, adc_base + ADC_CTRL); + + /* Wait for data available */ + do { + reg_value = sys_in32(adc_base + ADC_INTSTAT); + } while ((reg_value & ADC_INTSTAT_DATA_A) == 0); + + /* Flush FIFO */ + reg_value = sys_in32(adc_base + ADC_SET); + reg_value |= ADC_SET_FLUSH_RX; + sys_out32(reg_value, adc_base + ADC_SET); + + /* Clear data available interrupt and disable ADC */ + reg_value = sys_in32(adc_base + ADC_CTRL); + reg_value |= ADC_CTRL_CLR_DATA_A; + reg_value &= ~ADC_CTRL_ENABLE; + sys_out32(reg_value, adc_base + ADC_CTRL); +} + +#ifdef CONFIG_ADC_INTEL_QUARK_SE_C1000_SS_CALIBRATION +static void calibration_command(u8_t command) +{ + u32_t state; + u32_t reg_value; + + /* Set Calibration Request */ + state = irq_lock(); + reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_MST0); + reg_value |= (command & THREE_BITS_SET) << 17; + reg_value |= ADC_CAL_REQ; + sys_out32(reg_value, PERIPH_ADDR_BASE_CREG_MST0); + irq_unlock(state); + + /* Waiting for calibration ack */ + wait_slv0_bit_set(ADC_CAL_ACK); + + /* Clear Calibration Request once done */ + reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_MST0); + reg_value &= ~ADC_CAL_REQ; + sys_out32(reg_value, PERIPH_ADDR_BASE_CREG_MST0); +} + +static void adc_goto_normal_mode(struct device *dev) +{ + struct adc_info *info = dev->driver_data; + u8_t calibration_value; + u32_t reg_value; + + reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); + + if ((reg_value & ADC_MODE_MASK) != ADC_NORMAL_WITH_CALIB) { + + /* Request Normal With Calibration Mode */ + set_power_mode(ADC_NORMAL_WITH_CALIB); + + /* Poll waiting for normal mode with calibration */ + wait_slv0_bit_set(ADC_PWR_MODE_STS); + + if (info->calibration_value == ADC_NONE_CALIBRATION) { + /* Reset Calibration */ + calibration_command(ADC_CMD_RESET_CALIBRATION); + /* Request Calibration */ + calibration_command(ADC_CMD_START_CALIBRATION); + reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); + calibration_value = (reg_value >> 5) & SEVEN_BITS_SET; + info->calibration_value = calibration_value; + } + + /* Load Calibration */ + reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_MST0); + reg_value |= (info->calibration_value << 20); + sys_out32(reg_value, PERIPH_ADDR_BASE_CREG_MST0); + calibration_command(ADC_CMD_LOAD_CALIBRATION); + } + + dummy_conversion(dev); +} + +#else +static void adc_goto_normal_mode(struct device *dev) +{ + ARG_UNUSED(dev); + + /* Request Normal Without Calibration Mode */ + set_power_mode(ADC_NORMAL_WO_CALIB); + + dummy_conversion(dev); +} +#endif + +static int set_resolution(struct device *dev, + const struct adc_sequence *sequence) +{ + u32_t tmp_val; + const struct adc_config *config = dev->config->config_info; + u32_t adc_base = config->reg_base; + + tmp_val = sys_in32(adc_base + ADC_SET); + tmp_val &= ~FIVE_BITS_SET; + + switch (sequence->resolution) { + case 6: + break; + case 8: + tmp_val |= 1 & FIVE_BITS_SET; + break; + case 10: + tmp_val |= 2 & FIVE_BITS_SET; + break; + case 12: + tmp_val |= 3 & FIVE_BITS_SET; + break; + default: + return -EINVAL; + } + + sys_out32(tmp_val, adc_base + ADC_SET); + + return 0; +} + +/* Implementation of the ADC driver API function: adc_channel_setup. */ +static int adc_quark_se_ss_channel_setup( + struct device *dev, + const struct adc_channel_cfg *channel_cfg + ) +{ + u8_t channel_id = channel_cfg->channel_id; + struct adc_info *info = dev->driver_data; + + if (channel_id >= DW_CHANNEL_COUNT) { + LOG_ERR("Invalid channel id"); + return -EINVAL; + } + + if (channel_cfg->gain != ADC_GAIN_1) { + LOG_ERR("Invalid channel gain"); + return -EINVAL; + } + + if (channel_cfg->reference != ADC_REF_INTERNAL) { + LOG_ERR("Invalid channel reference"); + return -EINVAL; + } + + if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { + LOG_ERR("Invalid channel acquisition time"); + return -EINVAL; + } + + if (info->state != ADC_STATE_IDLE) { + LOG_ERR("ADC is busy or in error state"); + return -EAGAIN; + } + + info->active_channels |= 1 << channel_id; + return 0; +} + +static int adc_quark_se_ss_read_request(struct device *dev, + const struct adc_sequence *seq_tbl) +{ + struct adc_info *info = dev->driver_data; + int error = 0; + u32_t utmp, num_channels, interval = 0U; + + info->channels = seq_tbl->channels & info->active_channels; + + if (seq_tbl->channels != info->channels) { + return -EINVAL; + } + + error = set_resolution(dev, seq_tbl); + if (error) { + return error; + } + + /* + * Make sure the requested interval is longer than the time + * needed to do one conversion. + */ + if (seq_tbl->options && + (seq_tbl->options->interval_us > 0)) { + /* + * System clock is 32MHz, which means 1us == 32 cycles + * if divider is 1. + */ + interval = seq_tbl->options->interval_us * 32 / + CONFIG_ADC_INTEL_QUARK_SE_C1000_SS_CLOCK_RATIO; + + if (interval < (seq_tbl->resolution + 2)) { + return -EINVAL; + } + } + + info->entries = seq_tbl; + info->buffer = (u16_t *)seq_tbl->buffer; + + /* check if buffer has enough size */ + utmp = info->channels; + num_channels = 0U; + while (utmp) { + if (utmp & BIT(0)) { + num_channels++; + } + utmp >>= 1; + } + utmp = num_channels * sizeof(u16_t); + + if (seq_tbl->options) { + utmp *= (1 + seq_tbl->options->extra_samplings); + } + + if (utmp > seq_tbl->buffer_size) { + return -ENOMEM; + } + + info->state = ADC_STATE_SAMPLING; + + adc_context_start_read(&info->ctx, seq_tbl); + error = adc_context_wait_for_completion(&info->ctx); + + if (info->state == ADC_STATE_ERROR) { + info->state = ADC_STATE_IDLE; + return -EIO; + } + + return error; +} + +static int adc_quark_se_ss_read(struct device *dev, + const struct adc_sequence *seq_tbl) +{ + struct adc_info *info = dev->driver_data; + int ret; + + adc_context_lock(&info->ctx, false, NULL); + ret = adc_quark_se_ss_read_request(dev, seq_tbl); + adc_context_release(&info->ctx, ret); + + return ret; +} + +#ifdef CONFIG_ADC_ASYNC +/* Implementation of the ADC driver API function: adc_read_async. */ +static int adc_quark_se_ss_read_async(struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + struct adc_info *info = dev->driver_data; + int ret; + + adc_context_lock(&info->ctx, true, async); + ret = adc_quark_se_ss_read_request(dev, sequence); + adc_context_release(&info->ctx, ret); + + return ret; +} +#endif + +static void adc_quark_se_ss_start_conversion(struct device *dev) +{ + struct adc_info *info = dev->driver_data; + const struct adc_config *config = info->dev->config->config_info; + const struct adc_sequence *entry = info->ctx.sequence; + u32_t adc_base = config->reg_base; + u32_t ctrl, tmp_val, sample_window; + + info->channel_id = find_lsb_set(info->channels) - 1; + + /* Flush FIFO */ + tmp_val = sys_in32(adc_base + ADC_SET); + tmp_val |= ADC_SET_FLUSH_RX; + sys_out32(tmp_val, adc_base + ADC_SET); + + /* Reset sequence table */ + ctrl = sys_in32(adc_base + ADC_CTRL); + ctrl |= ADC_CTRL_SEQ_TABLE_RST; + sys_out32(ctrl, adc_base + ADC_CTRL); + + /* + * Hardware requires min (resolution + 2) cycles, + * or will emit SEQERROR. + */ + sample_window = entry->resolution + 2; + tmp_val = (sample_window & ELEVEN_BITS_SET) << SEQ_DELAY_EVEN_POS; + tmp_val |= (info->channel_id & FIVE_BITS_SET); + + sys_out32(tmp_val, adc_base + ADC_SEQ); + + /* + * Clear number of entries in sequencer and threshold to generate + * interrupt, since only 1 conversion is needed and fields are + * zero-based. + */ + tmp_val = sys_in32(adc_base + ADC_SET); + tmp_val &= ~(ADC_SET_SEQ_ENTRIES_MASK | ADC_SET_THRESHOLD_MASK); + sys_out32(tmp_val, adc_base + ADC_SET); + + /* + * Reset sequence pointer, + * Clear and unmask interrupts, + * Enable ADC and start sequencer. + */ + ctrl = sys_in32(adc_base + ADC_CTRL); + ctrl &= ~ADC_CTRL_INT_MASK_ALL; + ctrl |= ADC_CTRL_SEQ_PTR_RST | ADC_CTRL_INT_CLR_ALL | + ADC_CTRL_ENABLE | ADC_CTRL_SEQ_START; + sys_out32(ctrl, adc_base + ADC_CTRL); +} + +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct adc_info *info = CONTAINER_OF(ctx, struct adc_info, ctx); + + info->channels = ctx->sequence->channels; + + adc_quark_se_ss_start_conversion(info->dev); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, + bool repeat) +{ + struct adc_info *info = CONTAINER_OF(ctx, struct adc_info, ctx); + const struct adc_sequence *entry = ctx->sequence; + + if (repeat) { + info->buffer = (u16_t *)entry->buffer; + } +} + +int adc_quark_se_ss_init(struct device *dev) +{ + u32_t val; + const struct adc_config *config = dev->config->config_info; + u32_t adc_base = config->reg_base; + struct adc_info *info = dev->driver_data; + + /* Disable clock gating */ + val = sys_in32(PERIPH_ADDR_BASE_CREG_MST0); + val &= ~(ADC_CLOCK_GATE); + sys_out32(val, PERIPH_ADDR_BASE_CREG_MST0); + + /* Mask all interrupts and enable clock */ + val = ADC_CTRL_INT_MASK_ALL | ADC_CTRL_CLK_ENABLE; + sys_out32(val, adc_base + ADC_CTRL); + + /* Configure common properties */ + val = ((config->capture_mode & ONE_BIT_SET) << CAPTURE_MODE_POS); + val |= ((config->out_mode & ONE_BIT_SET) << OUTPUT_MODE_POS); + val |= ((config->serial_dly & FIVE_BITS_SET) << SERIAL_DELAY_POS); + val |= ((config->seq_mode & ONE_BIT_SET) << SEQUENCE_MODE_POS); + val &= ~(ADC_SET_INPUT_MODE_MASK); + sys_out32(val, adc_base + ADC_SET); + + /* Set the clock ratio */ + sys_out32(config->clock_ratio & ADC_DIVSEQSTAT_CLK_RATIO_MASK, + adc_base + ADC_DIVSEQSTAT); + + config->config_func(); + + int_unmask(config->reg_irq_mask); + int_unmask(config->reg_err_mask); + + info->dev = dev; + + adc_goto_normal_mode(dev); + + info->state = ADC_STATE_IDLE; + + adc_context_unlock_unconditionally(&info->ctx); + return 0; +} + +static void adc_quark_se_ss_rx_isr(void *arg) +{ + struct device *dev = (struct device *)arg; + struct adc_info *info = dev->driver_data; + const struct adc_config *config = dev->config->config_info; + const struct adc_sequence *seq = info->ctx.sequence; + u32_t adc_base = config->reg_base; + u32_t reg_val; + + /* Pop data from FIFO and put it into buffer */ + reg_val = sys_in32(adc_base + ADC_SET); + reg_val |= ADC_SET_POP_RX; + sys_out32(reg_val, adc_base + ADC_SET); + + /* Sample is always 12-bit, so need to shift */ + *info->buffer++ = sys_in32(adc_base + ADC_SAMPLE) >> + (12 - seq->resolution); + + /* Clear data available register */ + reg_val = sys_in32(adc_base + ADC_CTRL); + reg_val |= ADC_CTRL_CLR_DATA_A; + sys_out32(reg_val, adc_base + ADC_CTRL); + + /* Stop sequencer and mask all interrupts */ + reg_val = sys_in32(adc_base + ADC_CTRL); + reg_val &= ~ADC_CTRL_SEQ_START; + reg_val |= ADC_CTRL_INT_MASK_ALL; + sys_out32(reg_val, adc_base + ADC_CTRL); + + /* Disable ADC */ + reg_val = sys_in32(adc_base + ADC_CTRL); + reg_val &= ~ADC_CTRL_ENABLE; + sys_out32(reg_val, adc_base + ADC_CTRL); + + info->state = ADC_STATE_IDLE; + info->channels &= ~BIT(info->channel_id); + + if (info->channels) { + adc_quark_se_ss_start_conversion(dev); + } else { + adc_context_on_sampling_done(&info->ctx, dev); + } +} + +static void adc_quark_se_ss_err_isr(void *arg) +{ + struct device *dev = (struct device *) arg; + const struct adc_config *config = dev->config->config_info; + struct adc_info *info = dev->driver_data; + u32_t adc_base = config->reg_base; + u32_t reg_val = sys_in32(adc_base + ADC_SET); + + /* + * Stop sequencer, mask/clear all interrupts, + * and disable ADC. + */ + reg_val = sys_in32(adc_base + ADC_CTRL); + reg_val &= ~(ADC_CTRL_SEQ_START | ADC_CTRL_ENABLE); + reg_val |= ADC_CTRL_INT_MASK_ALL; + reg_val |= ADC_CTRL_INT_CLR_ALL; + sys_out32(reg_val, adc_base + ADC_CTRL); + + info->state = ADC_STATE_ERROR; + adc_context_on_sampling_done(&info->ctx, dev); +} + +static const struct adc_driver_api api_funcs = { + .channel_setup = adc_quark_se_ss_channel_setup, + .read = adc_quark_se_ss_read, +#ifdef CONFIG_ADC_ASYNC + .read_async = adc_quark_se_ss_read_async, +#endif +}; + +const static struct adc_config adc_config_dev = { + .reg_base = DT_ADC_0_BASE_ADDRESS, + .reg_irq_mask = SCSS_REGISTER_BASE + INT_SS_ADC_IRQ_MASK, + .reg_err_mask = SCSS_REGISTER_BASE + INT_SS_ADC_ERR_MASK, +#ifdef CONFIG_ADC_INTEL_QUARK_SE_C1000_SS_SERIAL + .out_mode = 0, +#elif CONFIG_ADC_INTEL_QUARK_SE_C1000_SS_PARALLEL + .out_mode = 1, +#endif + .seq_mode = 0, + +#ifdef CONFIG_ADC_INTEL_QUARK_SE_C1000_SS_RISING_EDGE + .capture_mode = 0, +#elif CONFIG_ADC_INTEL_QUARK_SE_C1000_SS_FALLING_EDGE + .capture_mode = 1, +#endif + .clock_ratio = CONFIG_ADC_INTEL_QUARK_SE_C1000_SS_CLOCK_RATIO, + .serial_dly = CONFIG_ADC_INTEL_QUARK_SE_C1000_SS_SERIAL_DELAY, + .config_func = adc_config_irq, +}; + +DEVICE_AND_API_INIT(adc_quark_se_ss, DT_ADC_0_NAME, &adc_quark_se_ss_init, + &adc_info_dev, &adc_config_dev, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, + &api_funcs); + +static void adc_config_irq(void) +{ + IRQ_CONNECT(DT_ADC_0_IRQ, DT_ADC_0_IRQ_PRI, adc_quark_se_ss_rx_isr, + DEVICE_GET(adc_quark_se_ss), 0); + irq_enable(DT_ADC_0_IRQ); + + IRQ_CONNECT(DT_ADC_IRQ_ERR, DT_ADC_0_IRQ_PRI, + adc_quark_se_ss_err_isr, DEVICE_GET(adc_quark_se_ss), 0); + irq_enable(DT_ADC_IRQ_ERR); +} diff --git a/drivers/adc/adc_dw.h b/drivers/adc/adc_intel_quark_se_c1000_ss.h similarity index 69% rename from drivers/adc/adc_dw.h rename to drivers/adc/adc_intel_quark_se_c1000_ss.h index 264a7937535..1e32b1f430c 100644 --- a/drivers/adc/adc_dw.h +++ b/drivers/adc/adc_intel_quark_se_c1000_ss.h @@ -33,8 +33,8 @@ * @brief Designware ADC header file */ -#ifndef ZEPHYR_DRIVERS_ADC_ADC_DW_H_ -#define ZEPHYR_DRIVERS_ADC_ADC_DW_H_ +#ifndef ZEPHYR_DRIVERS_ADC_ADC_INTEL_QUARK_SE_C1000_SS_H_ +#define ZEPHYR_DRIVERS_ADC_ADC_INTEL_QUARK_SE_C1000_SS_H_ #include #include @@ -70,33 +70,36 @@ extern "C" { #define INT_SS_ADC_ERR_MASK (0x400) #define INT_SS_ADC_IRQ_MASK (0x404) -/* ADC Specific macros */ -#define ADC_POP_SAMPLE (0x80000000) -#define ADC_FLUSH_RX (0x40000000) -#define ADC_FTL_SET_MASK (0x00ffffff) -#define ADC_SEQ_SIZE_SET_MASK (0x3fc0ffff) -#define ADC_SEQ_MODE_SET_MASK (0x3fffdfff) -#define ADC_CONFIG_SET_MASK (0x3fffe000) -#define ADC_CLK_RATIO_MASK (0x1fffff) -#define ADC_CLR_UNDRFLOW (1 << 18) -#define ADC_CLR_OVERFLOW (1 << 17) -#define ADC_CLR_DATA_A (1 << 16) -#define ADC_SEQ_TABLE_RST (0x0040) -#define ADC_SEQ_PTR_RST (0x0020) -#define ADC_SEQ_START (0x0010) -#define ADC_SEQ_STOP_MASK (0x078ec) -#define ADC_INT_ENA_MASK (0x001e) -#define ADC_INT_DSB (0x0F00) -#define ADC_INT_ENABLE (0x0000) -#define ADC_CLK_ENABLE (0x0004) -#define ADC_ENABLE (0x0002) -#define ADC_DISABLE (0x0) -#define ADC_RESET (0x1) -#define ADC_INT_DATA_A (0x1) -#define ADC_INT_ERR (0x6) -#define ADC_NONE_CALIBRATION (0x80) -#define ADC_NONE_DUMMY (0x00) -#define ADC_DONE_DUMMY (0x01) +/* ADC_DIVSEQSTAT register */ +#define ADC_DIVSEQSTAT_CLK_RATIO_MASK (0x1fffff) + +/* ADC_SET register */ +#define ADC_SET_POP_RX BIT(31) +#define ADC_SET_FLUSH_RX BIT(30) +#define ADC_SET_SEQ_MODE_MASK BIT(13) +#define ADC_SET_INPUT_MODE_MASK BIT(5) +#define ADC_SET_THRESHOLD_MASK (0x3F000000) +#define ADC_SET_THRESHOLD_POS 24 +#define ADC_SET_SEQ_ENTRIES_MASK (0x003F0000) +#define ADC_SET_SEQ_ENTRIES_POS 16 + +/* ADC_CTRL register */ +#define ADC_CTRL_CLR_DATA_A BIT(16) +#define ADC_CTRL_SEQ_TABLE_RST BIT(6) +#define ADC_CTRL_SEQ_PTR_RST BIT(5) +#define ADC_CTRL_SEQ_START BIT(4) +#define ADC_CTRL_CLK_ENABLE BIT(2) +#define ADC_CTRL_INT_CLR_ALL (0x000F0000) +#define ADC_CTRL_INT_MASK_ALL (0x00000F00) + +#define ADC_CTRL_ENABLE BIT(1) +#define ADC_CTRL_DISABLE (0x0) + +/* ADC_INTSTAT register */ +#define ADC_INTSTAT_SEQERROR BIT(3) +#define ADC_INTSTAT_UNDERFLOW BIT(2) +#define ADC_INTSTAT_OVERFLOW BIT(1) +#define ADC_INTSTAT_DATA_A BIT(0) #define ADC_STATE_CLOSED 0 #define ADC_STATE_DISABLED 1 @@ -108,10 +111,6 @@ extern "C" { #define ADC_CMD_START_CALIBRATION 3 #define ADC_CMD_LOAD_CALIBRATION 4 -/* ADC control commands */ -#define IO_ADC0_FS (32) -#define IO_ADC0_SE (32) - #define IO_ADC_SET_CLK_DIVIDER (0x20) #define IO_ADC_SET_CONFIG (0x21) #define IO_ADC_SET_SEQ_TABLE (0x22) @@ -130,10 +129,20 @@ extern "C" { #define IO_ADC_SEQ_MODE_REPETITIVE 1 #define ENABLE_SSS_INTERRUPTS ~(0x01 << 8) -#define ENABLE_ADC (ADC_INT_ENABLE | ADC_CLK_ENABLE | ADC_SEQ_TABLE_RST) -#define START_ADC_SEQ (ADC_SEQ_START | ADC_ENABLE | ADC_CLK_ENABLE) -#define RESUME_ADC_CAPTURE (ADC_INT_DSB|ADC_CLK_ENABLE|ADC_SEQ_PTR_RST) -#define FLUSH_ADC_ERRORS (ADC_INT_DSB|ADC_CLK_ENABLE|ADC_CLR_OVERFLOW|ADC_CLR_UNDRFLOW) + +#define ENABLE_ADC \ + ( \ + ADC_CTRL_CLK_ENABLE \ + | ADC_CTRL_SEQ_TABLE_RST \ + | ADC_CTRL_SEQ_PTR_RST \ + ) + +#define START_ADC_SEQ \ + ( \ + ADC_CTRL_SEQ_START \ + | ADC_CTRL_ENABLE \ + | ADC_CTRL_CLK_ENABLE \ + ) #define DW_CHANNEL_COUNT 19 @@ -155,7 +164,7 @@ extern "C" { #define ss_adc_data_to_mv(_data_, _resolution_) \ ((_data_ * ADC_VREF) / (1 << _resolution_)) -typedef void (*adc_dw_config_t)(void); +typedef void (*adc_intel_quark_se_c1000_ss_config_t)(void); /** @brief ADC configuration * This structure defines the ADC configuration values * that define the ADC hardware instance and configuration. @@ -181,7 +190,7 @@ struct adc_config { /**Clock ratio*/ u32_t clock_ratio; /**Config handler*/ - adc_dw_config_t config_func; + adc_intel_quark_se_c1000_ss_config_t config_func; }; /**@brief ADC information and data. @@ -203,28 +212,15 @@ struct adc_info { u8_t state; /**Sequence size*/ u8_t seq_size; -#ifdef CONFIG_ADC_DW_CALIBRATION +#ifdef CONFIG_ADC_INTEL_QUARK_SE_C1000_SS_CALIBRATION /**Calibration value*/ u8_t calibration_value; #endif }; -/** - * - * @brief ADC Initialization function. - * - * Inits device model for the ADC IP from Dataware. - * - * @param dev Pointer to the device structure descriptor that - * will be initialized. - * - * @return Integer: 0 for success, error otherwise. - */ -int adc_dw_init(struct device *dev); - #ifdef __cplusplus } #endif -#endif /* ZEPHYR_DRIVERS_ADC_ADC_DW_H_ */ +#endif /* ZEPHYR_DRIVERS_ADC_ADC_INTEL_QUARK_SE_C1000_SS_H_ */ diff --git a/soc/arc/quark_se_c1000_ss/Kconfig.defconfig b/soc/arc/quark_se_c1000_ss/Kconfig.defconfig index d1884089012..faa862b282b 100644 --- a/soc/arc/quark_se_c1000_ss/Kconfig.defconfig +++ b/soc/arc/quark_se_c1000_ss/Kconfig.defconfig @@ -123,7 +123,7 @@ endif endif # I2C if ADC -config ADC_DW +config ADC_INTEL_QUARK_SE_C1000_SS default y endif