adc: overhaul adc_dw and rename it to adc_intel_quark_se_c1000_ss

Since commit 0906a51dac, the driver
fails the test: tests/drivers/adc/adc_api. Some of the workflow
turns out to be incorrect (e.g. not doing dummy conversion after
getting out of deep power down, and not clearing interrupt status
bits). So take some time to overhaul the driver. Also rename
the driver to adc_intel_quark_se_c1000_ss because the inner
working of this driver is tied to Quark SE C1000 SoC.

Fixes: #12632

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
Daniel Leung 2019-03-14 10:23:44 -07:00 committed by Andrew Boie
commit 71b4137d30
8 changed files with 780 additions and 651 deletions

View file

@ -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)

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -1,521 +0,0 @@
/* adc_dw.c - Designware ADC driver */
/*
* Copyright (c) 2015 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <init.h>
#include <kernel.h>
#include <string.h>
#include <stdlib.h>
#include <soc.h>
#include <adc.h>
#include <arch/cpu.h>
#define ADC_CONTEXT_USES_KERNEL_TIMER
#include "adc_context.h"
#include "adc_dw.h"
#define LOG_LEVEL CONFIG_ADC_LOG_LEVEL
#include <logging/log.h>
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);
}

View file

@ -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 <errno.h>
#include <init.h>
#include <kernel.h>
#include <string.h>
#include <stdlib.h>
#include <soc.h>
#include <adc.h>
#include <arch/cpu.h>
#include <misc/util.h>
#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 <logging/log.h>
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);
}

View file

@ -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 <zephyr/types.h>
#include <adc.h>
@ -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_ */

View file

@ -123,7 +123,7 @@ endif
endif # I2C
if ADC
config ADC_DW
config ADC_INTEL_QUARK_SE_C1000_SS
default y
endif