From 962d8dfd18338469df8ffa3d1c0e9a7398cb2156 Mon Sep 17 00:00:00 2001 From: Ruibin Chang Date: Wed, 28 May 2025 16:01:33 +0800 Subject: [PATCH] drivers/counter/it8xxx2: fix loss timer interrupt potential risk 1.correct timer register control flow 2.select timer interrupt rising edge trigger, instead of default level trigger Stress test: top timer fires interrupt every 300ms for 18 hours. The result is that we don't lose any interrupts. Signed-off-by: Ruibin Chang --- drivers/counter/counter_ite_it8xxx2.c | 46 ++++++++++++++++++++------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/drivers/counter/counter_ite_it8xxx2.c b/drivers/counter/counter_ite_it8xxx2.c index cbd34a605ff..aaa871f9a8c 100644 --- a/drivers/counter/counter_ite_it8xxx2.c +++ b/drivers/counter/counter_ite_it8xxx2.c @@ -24,6 +24,7 @@ LOG_MODULE_REGISTER(counter_it8xxx2, CONFIG_COUNTER_LOG_LEVEL); /* ETnCTLR bit definitions (for n = 7 ~ 8) */ #define ET_COMB BIT(3) /* only defined in ET7CTRL */ #define ET_TC BIT(2) +#define ET_RST_EN (ET_RST | ET_EN) #define ET_RST BIT(1) #define ET_EN BIT(0) @@ -35,8 +36,10 @@ struct counter_it8xxx2_config { mm_reg_t base; /* alarm timer irq */ int alarm_irq; + int alarm_flag; /* top timer irq */ int top_irq; + int top_flag; void (*irq_config_func)(const struct device *dev); }; @@ -89,7 +92,7 @@ static int counter_it8xxx2_start(const struct device *dev) { LOG_DBG("starting top timer"); - counter_it8xxx2_write8(dev, ET_EN | ET_RST, ET8CTRL); + counter_it8xxx2_write8(dev, ET_RST_EN, ET8CTRL); return 0; } @@ -141,17 +144,17 @@ static int counter_it8xxx2_set_alarm(const struct device *dev, uint8_t chan_id, irq_disable(config->alarm_irq); + counter_it8xxx2_write8(dev, counter_it8xxx2_read8(dev, ET7CTRL) & ~ET_EN, ET7CTRL); + counter_it8xxx2_write32(dev, alarm_cfg->ticks, ET7CNTLLR); data->alarm_callback = alarm_cfg->callback; data->alarm_user_data = alarm_cfg->user_data; - LOG_DBG("%p Counter alarm set to %u ticks", dev, alarm_cfg->ticks); - - counter_it8xxx2_write8(dev, counter_it8xxx2_read8(dev, ET7CTRL) | ET_EN | ET_RST, ET7CTRL); - ite_intc_isr_clear(config->alarm_irq); + counter_it8xxx2_write8(dev, counter_it8xxx2_read8(dev, ET7CTRL) | ET_RST_EN, ET7CTRL); + irq_enable(config->alarm_irq); return 0; @@ -212,14 +215,17 @@ static int counter_it8xxx2_set_top_value(const struct device *dev, irq_disable(config->top_irq); + /* disable top timer */ + counter_it8xxx2_write8(dev, counter_it8xxx2_read8(dev, ET8CTRL) & ~ET_EN, ET8CTRL); + /* set new top value */ counter_it8xxx2_write32(dev, top_cfg->ticks, ET8CNTLLR); - /* re-enable and reset timer */ - counter_it8xxx2_write8(dev, counter_it8xxx2_read8(dev, ET8CTRL) | ET_EN | ET_RST, ET8CTRL); - ite_intc_isr_clear(config->top_irq); + /* re-enable and reset timer */ + counter_it8xxx2_write8(dev, counter_it8xxx2_read8(dev, ET8CTRL) | ET_RST_EN, ET8CTRL); + irq_enable(config->top_irq); return 0; @@ -273,18 +279,34 @@ static void counter_it8xxx2_top_isr(const struct device *dev) static int counter_it8xxx2_init(const struct device *dev) { const struct counter_it8xxx2_config *config = dev->config; + uint8_t et7_ctrl = counter_it8xxx2_read8(dev, ET7CTRL); + uint8_t et8_ctrl = counter_it8xxx2_read8(dev, ET8CTRL); LOG_DBG("max top value = 0x%08x", config->info.max_top_value); LOG_DBG("frequency = %d", config->info.freq); LOG_DBG("channels = %d", config->info.channels); - /* set the top value of top timer */ - counter_it8xxx2_write32(dev, config->info.max_top_value, ET8CNTLLR); + /* First time enable: enable and re-start timer -> disable timer */ + counter_it8xxx2_write8(dev, et7_ctrl | ET_RST_EN, ET7CTRL); + counter_it8xxx2_write8(dev, et7_ctrl & ~ET_EN, ET7CTRL); + counter_it8xxx2_write8(dev, et8_ctrl | ET_RST_EN, ET8CTRL); + counter_it8xxx2_write8(dev, et8_ctrl & ~ET_EN, ET8CTRL); - /* set the frequencies of alarm timer and top timer */ + /* Set rising edge trigger of alarm timer and top timer */ + ite_intc_irq_polarity_set(config->alarm_irq, config->alarm_flag); + ite_intc_irq_polarity_set(config->top_irq, config->top_flag); + + /* Clear interrupt status of alarm timer and top timer */ + ite_intc_isr_clear(config->alarm_irq); + ite_intc_isr_clear(config->top_irq); + + /* Select clock source of alarm timer and top timer */ counter_it8xxx2_write8(dev, ETnPSR_32768HZ, ET7PSR); counter_it8xxx2_write8(dev, ETnPSR_32768HZ, ET8PSR); + /* Set top value ticks to top timer */ + counter_it8xxx2_write32(dev, config->info.max_top_value, ET8CNTLLR); + config->irq_config_func(dev); return 0; @@ -319,7 +341,9 @@ static DEVICE_API(counter, counter_it8xxx2_driver_api) = { }, \ .base = DT_INST_REG_ADDR(n), \ .alarm_irq = DT_INST_IRQN_BY_IDX(n, 0), \ + .alarm_flag = DT_INST_IRQ_BY_IDX(n, 0, flags), \ .top_irq = DT_INST_IRQN_BY_IDX(n, 1), \ + .top_flag = DT_INST_IRQ_BY_IDX(n, 1, flags), \ .irq_config_func = counter_it8xxx2_cfg_func_##n, \ }; \ \