ite: drivers/adc: it8xxx2: fix adc driver flow
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 <tim2.lin@ite.corp-partner.google.com>
This commit is contained in:
parent
bb40d93f27
commit
5f5fb7d792
2 changed files with 125 additions and 159 deletions
|
@ -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>
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
/*
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
adc_context_lock(&data->ctx, false, NULL);
|
||||
err = adc_it8xxx2_start_read(dev, sequence);
|
||||
adc_context_release(&data->ctx, err);
|
||||
data->buffer = sequence->buffer;
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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…
Add table
Add a link
Reference in a new issue