From 5f5fb7d7925be3b40b4a963b11fb8b4cfedf03a1 Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Wed, 5 May 2021 16:23:51 +0800 Subject: [PATCH] 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 --- drivers/adc/adc_ite_it8xxx2.c | 206 ++++++++++----------- soc/riscv/riscv-ite/common/chip_chipregs.h | 80 ++++---- 2 files changed, 126 insertions(+), 160 deletions(-) diff --git a/drivers/adc/adc_ite_it8xxx2.c b/drivers/adc/adc_ite_it8xxx2.c index a505410e415c60..41b635a5205ab6 100644 --- a/drivers/adc/adc_ite_it8xxx2.c +++ b/drivers/adc/adc_ite_it8xxx2.c @@ -11,6 +11,7 @@ LOG_MODULE_REGISTER(adc_ite_it8xxx2); #include +#include #include #include #include @@ -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; + + 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; } @@ -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); diff --git a/soc/riscv/riscv-ite/common/chip_chipregs.h b/soc/riscv/riscv-ite/common/chip_chipregs.h index 54ca512c864c30..fdb9211e489d5b 100644 --- a/soc/riscv/riscv-ite/common/chip_chipregs.h +++ b/soc/riscv/riscv-ite/common/chip_chipregs.h @@ -1625,55 +1625,39 @@ #define IT8XXX2_GPIO_GRC21 ECREG(IT8XXX2_GPIO_BASE + 0xE6) /* Analog to Digital Converter (ADC) */ -#define IT83XX_ADC_BASE 0x00f01900 - -#define IT83XX_ADC_ADCSTS ECREG(IT83XX_ADC_BASE + 0x00) -#define IT83XX_ADC_ADCCTS1 BIT(7) -#define IT83XX_ADC_AINITB BIT(3) -#define IT83XX_ADC_ADCCFG ECREG(IT83XX_ADC_BASE + 0x01) -#define IT83XX_ADC_ADCCTS0 BIT(5) -#define IT83XX_ADC_ADCEN BIT(0) -#define IT83XX_ADC_ADCCTL ECREG(IT83XX_ADC_BASE + 0x02) -#define IT83XX_ADC_ADCGCR ECREG(IT83XX_ADC_BASE + 0x03) -#define IT83XX_ADC_VCH0CTL ECREG(IT83XX_ADC_BASE + 0x04) + +#ifndef __ASSEMBLER__ +struct adc_it8xxx2_regs { + volatile uint8_t ADCSTS; + volatile uint8_t ADCCFG; + volatile uint8_t ADCCTL; + volatile uint8_t ADCGCR; + volatile uint8_t VCH0CTL; + volatile uint8_t KDCTL; + volatile uint8_t reserved1[18]; + volatile uint8_t VCH0DATL; + volatile uint8_t VCH0DATM; + volatile uint8_t reserved2[42]; + volatile uint8_t ADCDVSTS; +}; +#endif /* !__ASSEMBLER__ */ + +/* ADC conversion time select 1 */ +#define IT8XXX2_ADC_ADCCTS1 BIT(7) +/* Analog accuracy initialization */ +#define IT8XXX2_ADC_AINITB BIT(3) +/* ADC conversion time select 0 */ +#define IT8XXX2_ADC_ADCCTS0 BIT(5) +/* ADC module enable */ +#define IT8XXX2_ADC_ADCEN BIT(0) +/* ADC data buffer keep enable */ +#define IT8XXX2_ADC_DBKEN BIT(7) /* W/C data valid flag */ -#define IT83XX_ADC_DATVAL BIT(7) -/* Data valid interrupt of adc. */ -#define IT83XX_ADC_INTDVEN BIT(5) -#define IT83XX_ADC_KDCTL ECREG(IT83XX_ADC_BASE + 0x05) -#define IT83XX_ADC_AHCE BIT(7) -#define IT83XX_ADC_VCH1CTL ECREG(IT83XX_ADC_BASE + 0x06) -#define IT83XX_ADC_VCH1DATL ECREG(IT83XX_ADC_BASE + 0x07) -#define IT83XX_ADC_VCH1DATM ECREG(IT83XX_ADC_BASE + 0x08) -#define IT83XX_ADC_VCH2CTL ECREG(IT83XX_ADC_BASE + 0x09) -#define IT83XX_ADC_VCH2DATL ECREG(IT83XX_ADC_BASE + 0x0A) -#define IT83XX_ADC_VCH2DATM ECREG(IT83XX_ADC_BASE + 0x0B) -#define IT83XX_ADC_VCH3CTL ECREG(IT83XX_ADC_BASE + 0x0C) -#define IT83XX_ADC_VCH3DATL ECREG(IT83XX_ADC_BASE + 0x0D) -#define IT83XX_ADC_VCH3DATM ECREG(IT83XX_ADC_BASE + 0x0E) -#define IT83XX_ADC_VHSCDBL ECREG(IT83XX_ADC_BASE + 0x14) -#define IT83XX_ADC_VHSCDBM ECREG(IT83XX_ADC_BASE + 0x15) -#define IT83XX_ADC_VCH0DATL ECREG(IT83XX_ADC_BASE + 0x18) -#define IT83XX_ADC_VCH0DATM ECREG(IT83XX_ADC_BASE + 0x19) -#define IT83XX_ADC_VHSGCDBL ECREG(IT83XX_ADC_BASE + 0x1C) -#define IT83XX_ADC_VHSGCDBM ECREG(IT83XX_ADC_BASE + 0x1D) -#define IT83XX_ADC_ADCSAR ECREG(IT83XX_ADC_BASE + 0x32) -#define IT83XX_ADC_VCMPSCP ECREG(IT83XX_ADC_BASE + 0x37) -#define IT83XX_ADC_VCH4CTL ECREG(IT83XX_ADC_BASE + 0x38) -/* Voltage channel enable (ch4~ch7) */ -#define IT83XX_ADC_VCHEN BIT(4) -#define IT83XX_ADC_VCH4DATM ECREG(IT83XX_ADC_BASE + 0x39) -#define IT83XX_ADC_VCH4DATL ECREG(IT83XX_ADC_BASE + 0x3A) -#define IT83XX_ADC_VCH5CTL ECREG(IT83XX_ADC_BASE + 0x3B) -#define IT83XX_ADC_VCH5DATM ECREG(IT83XX_ADC_BASE + 0x3C) -#define IT83XX_ADC_VCH5DATL ECREG(IT83XX_ADC_BASE + 0x3D) -#define IT83XX_ADC_VCH6CTL ECREG(IT83XX_ADC_BASE + 0x3E) -#define IT83XX_ADC_VCH6DATM ECREG(IT83XX_ADC_BASE + 0x3F) -#define IT83XX_ADC_VCH6DATL ECREG(IT83XX_ADC_BASE + 0x40) -#define IT83XX_ADC_VCH7CTL ECREG(IT83XX_ADC_BASE + 0x41) -#define IT83XX_ADC_VCH7DATM ECREG(IT83XX_ADC_BASE + 0x42) -#define IT83XX_ADC_VCH7DATL ECREG(IT83XX_ADC_BASE + 0x43) -#define IT83XX_ADC_ADCDVSTS ECREG(IT83XX_ADC_BASE + 0x44) +#define IT8XXX2_ADC_DATVAL BIT(7) +/* Data valid interrupt of adc */ +#define IT8XXX2_ADC_INTDVEN BIT(5) +/* Automatic hardware calibration enable */ +#define IT8XXX2_ADC_AHCE BIT(7) /* * Clock and Power Management (ECPM)