Skip to content

Commit

Permalink
ite: drivers/adc: it8xxx2: fix adc driver flow
Browse files Browse the repository at this point in the history
This commit fixes the ADC driver flow. And add internal
reference voltage to ADC driver API. And correct the
data buffer that only need to store raw data.

Signed-off-by: Tim Lin <[email protected]>
  • Loading branch information
GTLin08 authored and nashif committed May 13, 2021
1 parent bb40d93 commit 5f5fb7d
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 160 deletions.
206 changes: 94 additions & 112 deletions drivers/adc/adc_ite_it8xxx2.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
LOG_MODULE_REGISTER(adc_ite_it8xxx2);

#include <drivers/adc.h>
#include <drivers/pinmux.h>
#include <soc.h>
#include <errno.h>
#include <assert.h>
Expand All @@ -20,27 +21,10 @@ LOG_MODULE_REGISTER(adc_ite_it8xxx2);

#define DEV_DATA(dev) ((struct adc_it8xxx2_data * const)(dev)->data)

/* Data structure to define ADC channel control registers. */
struct adc_ctrl_t {
/* The voltage channel control register. */
volatile uint8_t *adc_ctrl;
/* The voltage channel data buffer MSB. */
volatile uint8_t *adc_datm;
/* The voltage channel data buffer LSB. */
volatile uint8_t *adc_datl;
};

/* Data structure of ADC channel control registers. */
static const struct adc_ctrl_t adc_ctrl_regs[] = {
{&IT83XX_ADC_VCH0CTL, &IT83XX_ADC_VCH0DATM, &IT83XX_ADC_VCH0DATL},
{&IT83XX_ADC_VCH1CTL, &IT83XX_ADC_VCH1DATM, &IT83XX_ADC_VCH1DATL},
{&IT83XX_ADC_VCH2CTL, &IT83XX_ADC_VCH2DATM, &IT83XX_ADC_VCH2DATL},
{&IT83XX_ADC_VCH3CTL, &IT83XX_ADC_VCH3DATM, &IT83XX_ADC_VCH3DATL},
{&IT83XX_ADC_VCH4CTL, &IT83XX_ADC_VCH4DATM, &IT83XX_ADC_VCH4DATL},
{&IT83XX_ADC_VCH5CTL, &IT83XX_ADC_VCH5DATM, &IT83XX_ADC_VCH5DATL},
{&IT83XX_ADC_VCH6CTL, &IT83XX_ADC_VCH6DATM, &IT83XX_ADC_VCH6DATL},
{&IT83XX_ADC_VCH7CTL, &IT83XX_ADC_VCH7DATM, &IT83XX_ADC_VCH7DATL},
};
/* ADC internal reference voltage (Unit:mV) */
#define IT8XXX2_ADC_VREF_VOL 3000
/* ADC channels disabled */
#define IT8XXX2_ADC_CHANNEL_DISABLED 0x1F

/* List of ADC channels. */
enum chip_adc_channel {
Expand All @@ -57,6 +41,8 @@ enum chip_adc_channel {

struct adc_it8xxx2_data {
struct adc_context ctx;
/* Channel ID */
uint32_t ch;
/* Save ADC result to the buffer. */
uint16_t *buffer;
/*
Expand All @@ -66,10 +52,14 @@ struct adc_it8xxx2_data {
uint16_t *repeat_buffer;
};

#define ADC_IT8XXX2_REG_BASE \
((struct adc_it8xxx2_regs *)(DT_INST_REG_ADDR(0)))

static int adc_it8xxx2_channel_setup(const struct device *dev,
const struct adc_channel_cfg *channel_cfg)
const struct adc_channel_cfg *channel_cfg)
{
ARG_UNUSED(dev);
const struct device *porti = DEVICE_DT_GET(DT_NODELABEL(pinmuxi));

if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) {
LOG_ERR("Selected ADC acquisition time is not valid");
Expand All @@ -91,36 +81,41 @@ static int adc_it8xxx2_channel_setup(const struct device *dev,
return -EINVAL;
}

if (channel_cfg->channel_id < CHIP_ADC_CH4) {
/* For channel 0 ~ 3 control register. */
*adc_ctrl_regs[channel_cfg->channel_id].adc_ctrl =
(IT83XX_ADC_DATVAL | IT83XX_ADC_INTDVEN) +
channel_cfg->channel_id;
} else {
/* For channel 4 ~ 7 control register. */
*adc_ctrl_regs[channel_cfg->channel_id].adc_ctrl =
IT83XX_ADC_DATVAL | IT83XX_ADC_INTDVEN | IT83XX_ADC_VCHEN;
}
/* The channel is set to ADC alternate function */
pinmux_pin_set(porti, channel_cfg->channel_id, IT8XXX2_PINMUX_FUNC_1);
LOG_DBG("Channel setup succeeded!");

return 0;
}

static uint8_t count_channels(uint8_t ch)
static void adc_enable_measurement(uint32_t ch)
{
uint8_t count = 0;
uint8_t bit;
struct adc_it8xxx2_regs *const adc_regs = ADC_IT8XXX2_REG_BASE;

bit = find_lsb_set(ch);
while (bit != 0) {
uint8_t idx = bit - 1;
/* Select and enable a voltage channel input for measurement */
adc_regs->VCH0CTL = (IT8XXX2_ADC_DATVAL | IT8XXX2_ADC_INTDVEN) + ch;

ch &= ~BIT(idx);
bit = find_lsb_set(ch);
count++;
}
/* Enable adc interrupt */
irq_enable(DT_INST_IRQN(0));

return count;
/* ADC module enable */
adc_regs->ADCCFG |= IT8XXX2_ADC_ADCEN;
}

static void adc_disable_measurement(void)
{
struct adc_it8xxx2_regs *const adc_regs = ADC_IT8XXX2_REG_BASE;

/*
* Disable measurement.
* bit(4:0) = 0x1f : channel disable
*/
adc_regs->VCH0CTL = IT8XXX2_ADC_DATVAL | IT8XXX2_ADC_CHANNEL_DISABLED;

/* ADC module disable */
adc_regs->ADCCFG &= ~IT8XXX2_ADC_ADCEN;

/* disable adc interrupt */
irq_disable(DT_INST_IRQN(0));
}

static int check_buffer_size(const struct adc_sequence *sequence,
Expand All @@ -143,14 +138,12 @@ static int check_buffer_size(const struct adc_sequence *sequence,
}

static int adc_it8xxx2_start_read(const struct device *dev,
const struct adc_sequence *sequence)
const struct adc_sequence *sequence)
{
struct adc_it8xxx2_data *data = DEV_DATA(dev);
uint8_t channels = sequence->channels;
uint8_t channel_count;
int err;
uint32_t channel_mask = sequence->channels;

if (!channels || channels & ~BIT_MASK(CHIP_ADC_COUNT)) {
if (!channel_mask || channel_mask & ~BIT_MASK(CHIP_ADC_COUNT)) {
LOG_ERR("Invalid selection of channels");
return -EINVAL;
}
Expand All @@ -161,13 +154,6 @@ static int adc_it8xxx2_start_read(const struct device *dev,
}
LOG_DBG("Configure resolution=%d", sequence->resolution);

channel_count = count_channels(channels);
err = check_buffer_size(sequence, channel_count);
if (err) {
return err;
}

data->buffer = sequence->buffer;
adc_context_start_read(&data->ctx, sequence);

return adc_context_wait_for_completion(&data->ctx);
Expand All @@ -180,22 +166,34 @@ static void adc_context_start_sampling(struct adc_context *ctx)

data->repeat_buffer = data->buffer;

/* enable adc interrupt */
irq_enable(DT_INST_IRQN(0));

/* ADC module enable */
IT83XX_ADC_ADCCFG |= IT83XX_ADC_ADCEN;
adc_enable_measurement(data->ch);
}

static int adc_it8xxx2_read(const struct device *dev,
const struct adc_sequence *sequence)
const struct adc_sequence *sequence)
{
struct adc_it8xxx2_data *data = DEV_DATA(dev);
int err;
uint32_t channel_mask = sequence->channels;
uint8_t channel_count = 0;
int err = 0;

data->buffer = sequence->buffer;

adc_context_lock(&data->ctx, false, NULL);
err = adc_it8xxx2_start_read(dev, sequence);
adc_context_release(&data->ctx, err);
while (channel_mask) {
adc_context_lock(&data->ctx, false, NULL);
data->ch = find_lsb_set(channel_mask) - 1;

err = adc_it8xxx2_start_read(dev, sequence);
if (err) {
return err;
}

channel_mask &= ~BIT(data->ch);
channel_count++;
adc_context_release(&data->ctx, err);
}

err = check_buffer_size(sequence, channel_count);

return err;
}
Expand All @@ -211,49 +209,26 @@ static void adc_context_update_buffer_pointer(struct adc_context *ctx,
}
}

static int adc_data_valid(enum chip_adc_channel adc_ch)
{
return IT83XX_ADC_ADCDVSTS & BIT(adc_ch);
}

/* Get result for each ADC selected channel. */
static void adc_it8xxx2_get_sample(const struct device *dev)
{
struct adc_it8xxx2_data *data = DEV_DATA(dev);
uint8_t channels = data->ctx.sequence.channels;
uint8_t bit;
struct adc_it8xxx2_regs *const adc_regs = ADC_IT8XXX2_REG_BASE;
bool valid = false;

bit = find_lsb_set(channels);
while (bit != 0) {
uint8_t idx = bit - 1;
if (adc_regs->VCH0CTL & IT8XXX2_ADC_DATVAL) {
/* Read adc raw data of msb and lsb */
*data->buffer++ = adc_regs->VCH0DATM << 8 | adc_regs->VCH0DATL;

if (adc_data_valid(idx)) {
/* Read adc raw data of msb and lsb */
uint16_t val = (*adc_ctrl_regs[idx].adc_datm << 8) |
*adc_ctrl_regs[idx].adc_datl;
/* Raw data multiply resolution. */
*data->buffer++ = val * data->ctx.sequence.resolution;

/* W/C data valid flag */
IT83XX_ADC_ADCDVSTS = BIT(idx);
valid = 1;
}

if (!valid) {
LOG_WRN("ADC failed to read (regs=%x, ch=%d)",
IT83XX_ADC_ADCDVSTS, idx);
}

channels &= ~BIT(idx);
bit = find_lsb_set(channels);
valid = 1;
}

/* ADC module disable */
IT83XX_ADC_ADCCFG &= ~IT83XX_ADC_ADCEN;
/* disable adc interrupt */
irq_disable(DT_INST_IRQN(0));
if (!valid) {
LOG_WRN("ADC failed to read (regs=%x, ch=%d)",
adc_regs->ADCDVSTS, data->ch);
}

adc_disable_measurement();
}

static void adc_it8xxx2_isr(const void *arg)
Expand All @@ -271,6 +246,7 @@ static void adc_it8xxx2_isr(const void *arg)
static const struct adc_driver_api api_it8xxx2_driver_api = {
.channel_setup = adc_it8xxx2_channel_setup,
.read = adc_it8xxx2_read,
.ref_internal = IT8XXX2_ADC_VREF_VOL,
};

/*
Expand All @@ -283,19 +259,20 @@ static const struct adc_driver_api api_it8xxx2_driver_api = {
*/
static void adc_accuracy_initialization(void)
{
struct adc_it8xxx2_regs *const adc_regs = ADC_IT8XXX2_REG_BASE;

/* Start adc accuracy initialization */
IT83XX_ADC_ADCSTS |= IT83XX_ADC_AINITB;
adc_regs->ADCSTS |= IT8XXX2_ADC_AINITB;
/* Enable automatic HW calibration. */
IT83XX_ADC_KDCTL |= IT83XX_ADC_AHCE;
/* short delay for adc accuracy initialization */
IT83XX_GCTRL_WNCKR = 0;
adc_regs->KDCTL |= IT8XXX2_ADC_AHCE;
/* Stop adc accuracy initialization */
IT83XX_ADC_ADCSTS &= ~IT83XX_ADC_AINITB;
adc_regs->ADCSTS &= ~IT8XXX2_ADC_AINITB;
}

static int adc_it8xxx2_init(const struct device *dev)
{
struct adc_it8xxx2_data *data = DEV_DATA(dev);
struct adc_it8xxx2_regs *const adc_regs = ADC_IT8XXX2_REG_BASE;

/* ADC analog accuracy initialization */
adc_accuracy_initialization();
Expand All @@ -307,13 +284,18 @@ static int adc_it8xxx2_init(const struct device *dev)
* NOTE: A sample time delay (60us) also need to be included in
* conversion time, so the final result is ~= 121.6us.
*/
IT83XX_ADC_ADCSTS &= ~IT83XX_ADC_ADCCTS1;
IT83XX_ADC_ADCCFG &= ~IT83XX_ADC_ADCCTS0;
adc_regs->ADCSTS &= ~IT8XXX2_ADC_ADCCTS1;
adc_regs->ADCCFG &= ~IT8XXX2_ADC_ADCCTS0;
/*
* bit[5-0]@ADCCTL : SCLKDIV
* SCLKDIV has to be equal to or greater than 1h;
*/
IT83XX_ADC_ADCCTL = 1;
adc_regs->ADCCTL = 1;
/*
* Enable this bit, and data of VCHxDATL/VCHxDATM will be
* kept until data valid is cleared.
*/
adc_regs->ADCGCR |= IT8XXX2_ADC_DBKEN;

IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),
adc_it8xxx2_isr, DEVICE_DT_INST_GET(0), 0);
Expand All @@ -329,8 +311,8 @@ static struct adc_it8xxx2_data adc_it8xxx2_data_0 = {
ADC_CONTEXT_INIT_SYNC(adc_it8xxx2_data_0, ctx),
};
DEVICE_DT_INST_DEFINE(0, adc_it8xxx2_init,
NULL,
&adc_it8xxx2_data_0,
NULL, POST_KERNEL,
CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&api_it8xxx2_driver_api);
NULL,
&adc_it8xxx2_data_0,
NULL, PRE_KERNEL_1,
CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&api_it8xxx2_driver_api);
Loading

0 comments on commit 5f5fb7d

Please sign in to comment.