drivers: adc: support Nuvoton numaker m2l31x

Update m2l31x.dtsi for adc support and update adc_numaker.c
to support acquisition time in 0~255 ADC ticks.

Signed-off-by: cyliang tw <cyliang@nuvoton.com>
This commit is contained in:
cyliang tw 2024-04-09 19:21:56 +08:00 committed by Fabio Baltieri
commit 0190ed2713
2 changed files with 39 additions and 15 deletions

View file

@ -17,6 +17,7 @@
#include <NuMicro.h> #include <NuMicro.h>
#define ADC_CONTEXT_USES_KERNEL_TIMER #define ADC_CONTEXT_USES_KERNEL_TIMER
#define ADC_CONTEXT_ENABLE_ON_COMPLETE
#include "adc_context.h" #include "adc_context.h"
LOG_MODULE_REGISTER(adc_numaker, CONFIG_ADC_LOG_LEVEL); LOG_MODULE_REGISTER(adc_numaker, CONFIG_ADC_LOG_LEVEL);
@ -45,6 +46,7 @@ struct adc_numaker_data {
uint16_t *repeat_buffer; uint16_t *repeat_buffer;
bool is_differential; bool is_differential;
uint32_t channels; uint32_t channels;
uint32_t acq_time;
}; };
static int adc_numaker_channel_setup(const struct device *dev, static int adc_numaker_channel_setup(const struct device *dev,
@ -54,9 +56,13 @@ static int adc_numaker_channel_setup(const struct device *dev,
struct adc_numaker_data *data = dev->data; struct adc_numaker_data *data = dev->data;
if (chan_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { if (chan_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) {
LOG_ERR("Not support acquisition time"); if ((ADC_ACQ_TIME_UNIT(chan_cfg->acquisition_time) != ADC_ACQ_TIME_TICKS) ||
return -ENOTSUP; (ADC_ACQ_TIME_VALUE(chan_cfg->acquisition_time) > 255)) {
LOG_ERR("Selected ADC acquisition time is not in 0~255 ticks");
return -EINVAL;
}
} }
data->acq_time = ADC_ACQ_TIME_VALUE(chan_cfg->acquisition_time);
if (chan_cfg->gain != ADC_GAIN_1) { if (chan_cfg->gain != ADC_GAIN_1) {
LOG_ERR("Not support channel gain"); LOG_ERR("Not support channel gain");
@ -115,9 +121,6 @@ static void adc_numaker_isr(const struct device *dev)
uint16_t conv_data; uint16_t conv_data;
uint32_t pend_flag; uint32_t pend_flag;
/* Clear pending flag first */
pend_flag = eadc->PENDSTS;
eadc->PENDSTS = pend_flag;
LOG_DBG("ADC ISR pend flag: 0x%X\n", pend_flag); LOG_DBG("ADC ISR pend flag: 0x%X\n", pend_flag);
LOG_DBG("ADC ISR STATUS2[0x%x] STATUS3[0x%x]", eadc->STATUS2, eadc->STATUS3); LOG_DBG("ADC ISR STATUS2[0x%x] STATUS3[0x%x]", eadc->STATUS2, eadc->STATUS3);
/* Complete the conversion of channels. /* Complete the conversion of channels.
@ -151,9 +154,6 @@ static void adc_numaker_isr(const struct device *dev)
eadc->SCTL[module_id] = 0; eadc->SCTL[module_id] = 0;
} }
/* Disable ADC */
EADC_Close(eadc);
/* Inform sampling is done */ /* Inform sampling is done */
adc_context_on_sampling_done(&data->ctx, data->dev); adc_context_on_sampling_done(&data->ctx, data->dev);
} }
@ -179,6 +179,8 @@ static void m_adc_numaker_start_scan(const struct device *dev)
channel_mask &= ~BIT(channel_id); channel_mask &= ~BIT(channel_id);
EADC_ConfigSampleModule(eadc, module_id, EADC_ConfigSampleModule(eadc, module_id,
EADC_SOFTWARE_TRIGGER, channel_id); EADC_SOFTWARE_TRIGGER, channel_id);
/* Set sample module external sampling time to 0 */
EADC_SetExtendSampleTime(eadc, module_id, data->acq_time);
} }
/* Clear the A/D ADINT0 interrupt flag for safe */ /* Clear the A/D ADINT0 interrupt flag for safe */
@ -221,6 +223,19 @@ static void adc_context_update_buffer_pointer(struct adc_context *ctx,
} }
} }
static void adc_context_on_complete(struct adc_context *ctx, int status)
{
struct adc_numaker_data *data =
CONTAINER_OF(ctx, struct adc_numaker_data, ctx);
const struct adc_numaker_config *cfg = data->dev->config;
EADC_T *eadc = cfg->eadc_base;
ARG_UNUSED(status);
/* Disable ADC */
EADC_Close(eadc);
}
static int m_adc_numaker_start_read(const struct device *dev, static int m_adc_numaker_start_read(const struct device *dev,
const struct adc_sequence *sequence) const struct adc_sequence *sequence)
{ {
@ -243,14 +258,9 @@ static int m_adc_numaker_start_read(const struct device *dev,
/* Enable the A/D converter */ /* Enable the A/D converter */
if (data->is_differential) { if (data->is_differential) {
err = EADC_Open(eadc, EADC_CTL_DIFFEN_DIFFERENTIAL); EADC_Open(eadc, EADC_CTL_DIFFEN_DIFFERENTIAL);
} else { } else {
err = EADC_Open(eadc, EADC_CTL_DIFFEN_SINGLE_END); EADC_Open(eadc, EADC_CTL_DIFFEN_SINGLE_END);
}
if (err) {
LOG_ERR("ADC Open fail (%u)", err);
return -ENODEV;
} }
data->buffer = sequence->buffer; data->buffer = sequence->buffer;

View file

@ -11,6 +11,7 @@
#include <zephyr/dt-bindings/reset/numaker_m2l31x_reset.h> #include <zephyr/dt-bindings/reset/numaker_m2l31x_reset.h>
#include <zephyr/dt-bindings/gpio/gpio.h> #include <zephyr/dt-bindings/gpio/gpio.h>
#include <zephyr/dt-bindings/i2c/i2c.h> #include <zephyr/dt-bindings/i2c/i2c.h>
#include <zephyr/dt-bindings/adc/adc.h>
/ { / {
chosen { chosen {
@ -306,6 +307,19 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
}; };
eadc0: eadc@40043000 {
compatible = "nuvoton,numaker-adc";
reg = <0x40043000 0xffc>;
interrupts = <42 0>;
resets = <&rst NUMAKER_EADC0_RST>;
clocks = <&pcc NUMAKER_EADC0_MODULE
NUMAKER_CLK_CLKSEL0_EADC0SEL_HCLK
NUMAKER_CLK_CLKDIV0_EADC0(2)>;
channels = <31>;
status = "disabled";
#io-channel-cells = <1>;
};
}; };
}; };