/** * @file sdrv_acmp.c * @brief semidrive acmp driver * * @copyright Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. */ #include #include #include #include #include #include #include #include "sdrv_acmp.h" /* Define the register offsets of acmp component */ #define ACMP_MAX_CSEL_NUM 4 #define ACMP_MAX_INDEX_NUM 32 #define ACMP_INIT_POLLs 200000 #define ACMP_SOFT (0x00) #define ACMP_SOFT_RST (0) #define ACMP_SOFT_RC_TMR_RST (1) #define ACMP_MODE (0x04) #define ACMP_IT_MODE_CFG (0x08) #define ACMP_IT_MODE_CFG_TG_START (0) #define ACMP_IT_MODE_CFG_QSTART (8) #define ACMP_IT_MODE_CFG_QEND (16) #define ACMP_IT_MODE_CFG_CUR_ENTRY_PT (24) #define ACMP_TIMER (0x0C) #define ACMP_TIMER_COMPARE_VAL (0) #define ACMP_TIMER_TERMINAL_VAL (16) #define ACMP_CFG_INDEX(n) (0x10 + n * 4) #define ACMP_CFG_INDEX_AMSEL (0) #define ACMP_CFG_INDEX_CSEL (12) #define ACMP_CFG_INDEX_IE (16) #define ACMP_CFG_INDEX_UIE (17) #define ACMP_ANA_CFG(n) (0x90 + n * 4) #define ACMP_ANA_CFG_REFSEL (0) #define ACMP_ANA_CFG_SDSEL (1) #define ACMP_ANA_CFG_HCFG (4) #define ACMP_ANA_CFG_DAIN (8) #define ACMP_CTRL_CFG(n) (0xA0 + n * 4) #define ACMP_CTRL_CFG_AMUX_SETUP (0) #define ACMP_CTRL_CFG_PROP_DLY (8) #define ACMP_CTRL_CFG_RBW (16) #define ACMP_CTRL_CFG_FBW (20) #define ACMP_CTRL_CFG_SAMPLE_EN (24) #define ACMP_CTRL_CFG_MASK_EN (25) #define ACMP_CTRL_CFG_POL_ADJ (26) #define ACMP_CTRL_CFG_SYNC_EN (27) #define ACMP_IRQ (0xB0) #define ACMP_IRQ_UNCOR (0xB4) #define ANA_EXT_MUX_ERR (0xB8) #define ANA_EXT_MUX_ERR_STATUS (0) #define ANA_EXT_MUX_ERR_SIG_EN (16) #define ACMP_PD_CTRL (0xBC) #define ACMP_PD_CTRL_CMP (0) #define ACMP_PD_CTRL_DAC (1) #define ACMP_PD_CTRL_Q_CH_CMP (8) #define ACMP_PD_CTRL_Q_CH_DAC (9) #define ACMP_INIT (0xC0) #define ACMP_INIT_CNT_THRD (0) #define ACMP_INIT_DONE (16) #define ACMP_LOW_POWER (0xC4) #define ACMP_SCH (0xC8) #define ACMP_SCH_ACMP_EN (0) #define ACMP_SCH_ANA_INSEL_ON (1) #define REG_PARITY_ERR_INT_STAT (0xD0) #define REG_PARITY_ERR_INT_STAT_EN (0xD4) #define REG_PARITY_ERR_INT_SIG_EN (0xD8) #define FUSA_COR_ERR_INT_STAT (0xE0) #define FUSA_COR_ERR_INT_STAT_EN (0xE4) #define FUSA_COR_ERR_INT_SIG_EN (0xE8) #define FUSA_UNCOR_ERR_INT_STAT (0xF0) #define FUSA_UNCOR_ERR_INT_STAT_PWDATA_UNCOR_ERR (0) #define FUSA_UNCOR_ERR_INT_STAT_PWDATA_DATAL_ERR (1) #define FUSA_UNCOR_ERR_INT_STAT_PADDR_UNCOR_ERR (2) #define FUSA_UNCOR_ERR_INT_STAT_PCTL_UNCOR_ERR (3) #define FUSA_UNCOR_ERR_INT_STAT_INPUT_ERR (4) #define FUSA_UNCOR_ERR_INT_STAT_EN (0xF4) #define FUSA_UNCOR_ERR_INT_STAT_EN_PWDATA_UNCOR_ERR (0) #define FUSA_UNCOR_ERR_INT_STAT_EN_PWDATA_DATAL_ERR (1) #define FUSA_UNCOR_ERR_INT_STAT_EN_PADDR_UNCOR_ERR (2) #define FUSA_UNCOR_ERR_INT_STAT_EN_PCTL_UNCOR_ERR (3) #define FUSA_UNCOR_ERR_INT_STAT_EN_INPUT_ERR (4) #define FUSA_UNCOR_ERR_INT_SIG_EN (0xF8) #define FUSA_UNCOR_ERR_INT_SIG_EN_PWDATA_UNCOR_ERR (0) #define FUSA_UNCOR_ERR_INT_SIG_EN_PWDATA_DATAL_ERR (1) #define FUSA_UNCOR_ERR_INT_SIG_EN_PADDR_UNCOR_ERR (2) #define FUSA_UNCOR_ERR_INT_SIG_EN_PCTL_UNCOR_ERR (3) #define FUSA_UNCOR_ERR_INT_SIG_EN_INPUT_ERR (4) #define PWDATA_INJ (0x100) #define PWECC_INJ (0x104) #define SELFTEST_MODE (0x108) #define PRDATAINJ (0x10C) #define INT_ERR_INJ (0x110) #define INT_ERR_INJ_IE_ERR (0) #define INT_ERR_INJ_COR_ERR (1) #define INT_ERR_INJ_UNC_ERR (2) /** * @brief sdrv acmp soft reset * * @param[in] base sdrv acmp address */ static void sdrv_acmp_soft_reset(paddr_t base) { RMWREG32(base + ACMP_SOFT, ACMP_SOFT_RST, 1, 1); RMWREG32(base + ACMP_SOFT, ACMP_SOFT_RST, 1, 0); } /** * @brief sdrv acmp config mode. * * @param[in] base sdrv acmp address * @param[in] mode sdrv acmp mode */ static void sdrv_acmp_config_mode(paddr_t base, sdrv_acmp_mode_t mode) { writel(mode, base + ACMP_MODE); } /** * @brief sdrv acmp get mode. * * @param[in] base sdrv acmp address * @param[in] mode sdrv acmp mode */ static sdrv_acmp_mode_t sdrv_acmp_get_mode(paddr_t base) { return (sdrv_acmp_mode_t)(readl(base + ACMP_MODE) & 0x1U); } /** * @brief sdrv acmp config it mode. * * @param[in] base sdrv acmp address * @param[in] qstart sdrv acmp trigger start id number for loop * @param[in] qend sdrv acmp trigger end id number for loop * @param[in] cur_entry_pt sdrv acmp trigger first access id number * @return SDRV_STATUS_OK represents success or other error code */ static status_t sdrv_acmp_config_it_mode(paddr_t base, uint8_t qstart, uint8_t qend, uint8_t cur_entry_pt) { if ((qstart <= cur_entry_pt) && (cur_entry_pt <= qend)) { RMWREG32(base + ACMP_IT_MODE_CFG, ACMP_IT_MODE_CFG_QSTART, 5, qstart & 0x1F); RMWREG32(base + ACMP_IT_MODE_CFG, ACMP_IT_MODE_CFG_QEND, 5, qend & 0x1F); RMWREG32(base + ACMP_IT_MODE_CFG, ACMP_IT_MODE_CFG_CUR_ENTRY_PT, 5, cur_entry_pt & 0x1F); return SDRV_STATUS_OK; } else { return SDRV_ACMP_STATUS_INVALID_PARAM; } } /** * @brief sdrv acmp get it mode config. * * @param[in] base sdrv acmp address * @param[in] qstart sdrv acmp trigger start id number for loop * @param[in] qend sdrv acmp trigger end id number for loop * @param[in] cur_entry_pt sdrv acmp trigger first access id number */ static void sdrv_acmp_get_it_mode_config(paddr_t base, uint8_t *qstart, uint8_t *qend, uint8_t *cur_entry_pt) { uint32_t it_cfg = readl(base + ACMP_IT_MODE_CFG); *qstart = (it_cfg >> ACMP_IT_MODE_CFG_QSTART) & 0x1F; *qend = (it_cfg >> ACMP_IT_MODE_CFG_QEND) & 0x1F; *cur_entry_pt = (it_cfg >> ACMP_IT_MODE_CFG_CUR_ENTRY_PT) & 0x1F; } /** * @brief sdrv acmp config timer. * * @param[in] base sdrv acmp address * @param[in] compare_val acmp timer compare value * @param[in] terminal_val acmp timer terminal value * @return SDRV_STATUS_OK represents success or other error code */ static status_t sdrv_acmp_config_timer(paddr_t base, uint16_t compare_val, uint16_t terminal_val) { RMWREG32(base + ACMP_TIMER, ACMP_TIMER_COMPARE_VAL, 16, compare_val & 0xFFFF); if (terminal_val > compare_val) { RMWREG32(base + ACMP_TIMER, ACMP_TIMER_TERMINAL_VAL, 16, terminal_val & 0xFFFF); } else { return SDRV_ACMP_STATUS_INVALID_PARAM; } return SDRV_STATUS_OK; } /** * @brief sdrv acmp start it generate. * * @param[in] base sdrv acmp address * @param[in] trigger_start acmp it generate start */ static void sdrv_acmp_it_gen_start(paddr_t base, bool trigger_start) { RMWREG32(base + ACMP_IT_MODE_CFG, ACMP_IT_MODE_CFG_TG_START, 1, trigger_start); } /** * @brief sdrv acmp config csel * * @param[in] base sdrv acmp address * @param[in] csel_cfg sdrv acmp csel cfg */ static void sdrv_acmp_config_csel(paddr_t base, sdrv_acmp_csel_cfg_t *csel_cfg) { uint32_t val = 0; /* acmp ctrl cfg*/ val = (csel_cfg->sync_en << ACMP_CTRL_CFG_SYNC_EN) | (csel_cfg->pol_adj << ACMP_CTRL_CFG_POL_ADJ) | (csel_cfg->mask_en << ACMP_CTRL_CFG_MASK_EN) | (csel_cfg->sample_en << ACMP_CTRL_CFG_SAMPLE_EN) | (csel_cfg->fbw << ACMP_CTRL_CFG_FBW) | (csel_cfg->rbw << ACMP_CTRL_CFG_RBW) | (csel_cfg->prop_delay << ACMP_CTRL_CFG_PROP_DLY) | (csel_cfg->amux_setup << ACMP_CTRL_CFG_AMUX_SETUP); writel(val, base + ACMP_CTRL_CFG(csel_cfg->csel_idx)); /* acmp ana cfg*/ val = (csel_cfg->dain << ACMP_ANA_CFG_DAIN) | (csel_cfg->hcfg << ACMP_ANA_CFG_HCFG) | (csel_cfg->sdsel << ACMP_ANA_CFG_SDSEL) | (csel_cfg->refsel << ACMP_ANA_CFG_REFSEL); writel(val, base + ACMP_ANA_CFG(csel_cfg->csel_idx)); } /** * @brief sdrv acmp config index * * @param[in] base sdrv acmp address * @param[in] index_cfg sdrv acmp index cfg */ static void sdrv_acmp_config_index(paddr_t base, sdrv_acmp_index_cfg_t *index_cfg) { uint32_t val = 0; val = (index_cfg->uie << ACMP_CFG_INDEX_UIE) | (index_cfg->ie << ACMP_CFG_INDEX_IE) | (index_cfg->csel << ACMP_CFG_INDEX_CSEL) | (index_cfg->amsel << ACMP_CFG_INDEX_AMSEL); writel(val, base + ACMP_CFG_INDEX(index_cfg->idx)); } /** * @brief sdrv acmp get irq state. * * @param[in] base sdrv acmp address * @return irq status */ static uint32_t sdrv_acmp_get_irq_state(paddr_t base) { return readl(base + ACMP_IRQ); } /** * @brief sdrv acmp clear irq. * * @param[in] base sdrv acmp address * @param[in] state irq state */ static void sdrv_acmp_clear_irq(paddr_t base, uint32_t state) { writel(state, base + ACMP_IRQ); } /** * @brief sdrv acmp get irq status. * * @param[in] base sdrv acmp address * @return init done */ static bool sdrv_acmp_lld_get_init_done(paddr_t base) { return ((readl(base + ACMP_INIT) >> ACMP_INIT_DONE) & 0x1); } /** * @brief sdrv acmp set low power req_n delay num. * * @param[in] base sdrv acmp address * @param[in] req_n_dly req_n delay number */ static void sdrv_acmp_set_low_power(paddr_t base, uint8_t req_n_dly) { writel(req_n_dly & 0xFFFF, base + ACMP_LOW_POWER); } /** * @brief sdrv acmp dac recieve q channel low power requset. * * @param[in] base sdrv acmp address * @param[in] enable cmp recieve q channel low power requset */ static void sdrv_acmp_rcv_qch_cmp(paddr_t base, bool enable) { RMWREG32(base + ACMP_PD_CTRL, ACMP_PD_CTRL_CMP, 1, enable); } /** * @brief sdrv acmp comperitor recieve q channel low power requset. * * @param[in] base sdrv acmp address * @param[in] enable dac recieve q channel low power requset */ static void sdrv_acmp_rcv_qch_dac(paddr_t base, bool enable) { RMWREG32(base + ACMP_PD_CTRL, ACMP_PD_CTRL_DAC, 1, enable); } /** * @brief sdrv acmp irq handler * * @param[in] irq irq number * @param[in] arg irq arg * return irq handler result */ static int sdrv_acmp_irq_handler(uint32_t irq, void *arg) { sdrv_acmp_t *dev = arg; uint32_t irq_state; int ret = 0; ASSERT(dev); irq_state = sdrv_acmp_get_irq_state(dev->base); if (irq_state) { if (dev->callback) { ret = dev->callback(dev, irq_state); } sdrv_acmp_clear_irq(dev->base, irq_state); } return ret; } /** * @brief sdrv acmp init * * This function initializes acmp device and attach callback function. * * @param[in] dev sdrv acmp device * @param[in] cfg sdrv acmp configuration parameters * @param[in] callback sdrv acmp callback function * @return SDRV_STATUS_OK represents success or other error code */ status_t sdrv_acmp_init(sdrv_acmp_t *dev, sdrv_acmp_config_t *cfg, sdrv_acmp_callback callback) { status_t ret; uint32_t i = 0; uint32_t tms = 0; if (cfg->base == 0) { return SDRV_ACMP_STATUS_INVALID_PARAM; } dev->base = cfg->base; dev->irq = cfg->irq; dev->callback = callback; #if (CONFIG_E3 || CONFIG_D3) if (IS_P0) { /* close ADC self-test to avoid disturbing the ACMP reference voltage */ #if APB_ADC1_BASE writel(0xFFFF, APB_ADC1_BASE + 0x244); #endif #if APB_ADC2_BASE writel(0xFFFF, APB_ADC2_BASE + 0x244); #endif #if APB_ADC3_BASE writel(0xFFFF, APB_ADC3_BASE + 0x244); #endif } #endif /* soft reset */ sdrv_acmp_soft_reset(dev->base); /* wait init done */ while (!sdrv_acmp_lld_get_init_done(dev->base)) { if (tms++ > ACMP_INIT_POLLs) { return SDRV_STATUS_TIMEOUT; } } /* config mode */ sdrv_acmp_config_mode(dev->base, cfg->mode); if (cfg->mode == ACMP_IT_MODE) { ret = sdrv_acmp_config_it_mode(dev->base, cfg->qstart, cfg->qend, cfg->cur_entry_pt); if (ret != SDRV_STATUS_OK) { return ret; } ret = sdrv_acmp_config_timer(dev->base, cfg->timer_compare_val, cfg->timer_terminal_val); if (ret != SDRV_STATUS_OK) { return ret; } } /* config csel */ if ((cfg->csel_num > 0) && (cfg->csel_num <= ACMP_MAX_CSEL_NUM)) { for (i = 0; i < cfg->csel_num; i++) { sdrv_acmp_config_csel(dev->base, &cfg->csel_cfg[i]); } } else { return SDRV_ACMP_STATUS_INVALID_PARAM; } /* config index */ if ((cfg->index_num > 0) && (cfg->index_num <= ACMP_MAX_INDEX_NUM)) { for (i = 0; i < cfg->index_num; i++) { sdrv_acmp_config_index(dev->base, &cfg->index_cfg[i]); } } else { return SDRV_ACMP_STATUS_INVALID_PARAM; } /* set low power req_n delay */ if (cfg->req_n_dly > 0) { sdrv_acmp_set_low_power(dev->base, cfg->req_n_dly); } /* competitor recv q channel low power request */ sdrv_acmp_rcv_qch_cmp(dev->base, cfg->qch_cmp_en); /* dac recv q channel low power request */ sdrv_acmp_rcv_qch_dac(dev->base, cfg->qch_dac_en); /* start it generate */ if (cfg->mode == ACMP_IT_MODE) { sdrv_acmp_it_gen_start(dev->base, true); } else { sdrv_acmp_it_gen_start(dev->base, false); } if (dev->irq > 0) { irq_attach(dev->irq, sdrv_acmp_irq_handler, dev); irq_enable(dev->irq); } else { return SDRV_ACMP_STATUS_INVALID_PARAM; } return SDRV_STATUS_OK; } /** * @brief sdrv acmp start * * This function is used to start or stop acmp comparation. * All the parameters are remained when acmp stop, and the previous comparation will restart when acmp start. * * @param[in] dev sdrv acmp dev * @param[in] start sdrv acmp start * @return SDRV_STATUS_OK represents success */ status_t sdrv_acmp_start(sdrv_acmp_t *dev, bool start) { if (dev->base == 0) { return SDRV_ACMP_STATUS_INVALID_PARAM; } RMWREG32(dev->base + ACMP_SCH, ACMP_SCH_ANA_INSEL_ON, 1, 0); RMWREG32(dev->base + ACMP_SCH, ACMP_SCH_ACMP_EN, 1, start); return SDRV_STATUS_OK; } /** * @brief sdrv acmp IT mode trigger start * * This function is used to stop or restart trigger with differnet id numbers in IT mode. * The new comparation will use the same comparation parameters with the former comparation. * If the parameters need to be modified, acmp should be stopped and reinitialized. * * @param[in] dev sdrv acmp device * @param[in] qstart sdrv acmp trigger start id number for loop * @param[in] qend sdrv acmp trigger end id number for loop * @param[in] cur_entry_pt sdrv acmp trigger first access id number * @param[in] trigger_start acmp IT mode trigger start * @return SDRV_STATUS_OK represents success */ status_t sdrv_acmp_it_trigger_start(sdrv_acmp_t *dev, uint8_t qstart, uint8_t qend, uint8_t cur_entry_pt, bool trigger_start) { if (dev->base == 0) { return SDRV_ACMP_STATUS_INVALID_PARAM; } /* check ACMP_IT_MODE */ if (sdrv_acmp_get_mode(dev->base) == ACMP_HT_MODE) { return SDRV_ACMP_STATUS_WRONG_MODE; } /* trigger stop */ sdrv_acmp_it_gen_start(dev->base, false); /* trigger restart */ if (trigger_start) { sdrv_acmp_config_it_mode(dev->base, qstart, qend, cur_entry_pt); sdrv_acmp_it_gen_start(dev->base, trigger_start); } return SDRV_STATUS_OK; } /** * @brief sdrv acmp IT mode update valid irq state * * This function is used to workaround for multiple trigger if interrupt is required in IT mode. * Occurrence scenario: * Only appers in multiple triggers of IT mode using interrupt, but this is not a problem * if not changing the configuration(index and analog config) at next trigger. * At the end of each trigger, if acmp voltage comparision result is pulled up one clock cycle * before next trigger, the interrupt generated by this trigger will update to the register ID * of the next trigger. Other functions of ACMP are not affected. * * How to use this function: * Call the function at beginning of acmp callback function. * * @param[in] dev sdrv acmp device * @param[in] state sdrv acmp irq state * @param[in] wait_time check irq valid wait time (unit: μs), * the period should be a little longer than terminal time. * @return SDRV_STATUS_OK represents success */ status_t sdrv_acmp_it_update_valid_irq(sdrv_acmp_t *dev, uint32_t *state, uint32_t wait_time) { uint8_t save_qstart = 0; uint8_t save_qend = 0; uint8_t save_cur_entry_pt = 0; uint8_t irq_bit = 0; if (dev->base == 0) { return SDRV_ACMP_STATUS_INVALID_PARAM; } /* check ACMP_IT_MODE */ if (sdrv_acmp_get_mode(dev->base) == ACMP_HT_MODE) { return SDRV_ACMP_STATUS_WRONG_MODE; } /* save IT mode qstart/qend/cur_entry_pt */ sdrv_acmp_get_it_mode_config(dev->base, &save_qstart, &save_qend, &save_cur_entry_pt); /* check state, and clear invalid bits */ while (*state >> irq_bit) { /* check irq_bit */ if (BIT(*state, irq_bit)) { /* clear irq_bit */ sdrv_acmp_clear_irq(dev->base, 1 << irq_bit); /* stop tg_start */ sdrv_acmp_it_gen_start(dev->base, false); /* only trigger irq_bit */ sdrv_acmp_config_it_mode(dev->base, irq_bit, irq_bit, irq_bit); /* restart tg_start */ sdrv_acmp_it_gen_start(dev->base, true);// /* wait more than terminal time */ udelay(wait_time); } /* check next bit */ irq_bit ++; if (irq_bit > 31) { break; } } /* update irq state */ *state = sdrv_acmp_get_irq_state(dev->base); /* restore IT mode qstart/qend/cur_entry_pt */ if (save_cur_entry_pt >= save_qend) { save_cur_entry_pt = save_qstart; } else { save_cur_entry_pt = save_cur_entry_pt + 1; } return sdrv_acmp_config_it_mode(dev->base, save_qstart, save_qend, save_cur_entry_pt); } /** * @brief sdrv acmp power ctrl * * This function sets the sdrv acmp power mode. * The status is default power on after acmp initilization. * If the acmp comparation is finished, the power mode can be set to power down to reduce power consumption. * * @param[in] dev sdrv acmp device * @param[in] down 0 power on (default), 1 power down * @return SDRV_STATUS_OK represents success */ status_t sdrv_acmp_power_ctrl(sdrv_acmp_t *dev, bool down) { if (dev->base == 0) { return SDRV_ACMP_STATUS_INVALID_PARAM; } /* power down analog competitor */ RMWREG32(dev->base + ACMP_PD_CTRL, ACMP_PD_CTRL_CMP, 1, down); /* power down analog dac */ RMWREG32(dev->base + ACMP_PD_CTRL, ACMP_PD_CTRL_DAC, 1, down); return SDRV_STATUS_OK; } /** * @brief sdrv acmp allows analog competitor and dac enter lowpower mode * * This function allows competitor and dac recv q channel low power request. * And than if the lowpower request is received, the competitor and dac will enter * low power mode after req_n_dly clock cycle. * * @param[in] dev sdrv acmp device * @param[in] cmp_en competitor enable or disable * @param[in] dac_en dac enable or disable * @param[in] req_n_dly enter lowpower mode delay number * @return SDRV_STATUS_OK represents success */ status_t sdrv_acmp_enable_low_power(sdrv_acmp_t *dev, bool cmp_en, bool dac_en, uint8_t req_n_dly) { if (dev->base == 0) { return SDRV_ACMP_STATUS_INVALID_PARAM; } /* set low power req_n delay */ sdrv_acmp_set_low_power(dev->base, req_n_dly); /* competitor recv q channel low power request */ sdrv_acmp_rcv_qch_cmp(dev->base, cmp_en); /* dac recv q channel low power request */ sdrv_acmp_rcv_qch_dac(dev->base, dac_en); return SDRV_STATUS_OK; } /** * @brief sdrv acmp set callback * * This function is used to set the sdrv acmp callback function separately, after acmp initilization. * * @param[in] dev sdrv acmp device * @param[in] callback acmp callback function * @return SDRV_STATUS_OK represents success */ status_t sdrv_acmp_set_callback(sdrv_acmp_t *dev, sdrv_acmp_callback callback) { dev->callback = callback; return SDRV_STATUS_OK; } /** * @brief sdrv acmp deinit * * This function stops acmp and deletes acmp initilization. * Acmp must be de-initiated before entering lowpower mode. * * @param[in] dev sdrv acmp device * @return SDRV_STATUS_OK represents success */ status_t sdrv_acmp_deinit(sdrv_acmp_t *dev) { status_t ret; if (dev->irq > 0) { irq_disable(dev->irq); irq_detach(dev->irq); } /* stop acmp */ ret = sdrv_acmp_start(dev, false); /* clear ACMP IT mode */ sdrv_acmp_config_mode(dev->base, ACMP_HT_MODE); /* soft reset */ sdrv_acmp_soft_reset(dev->base); /* clear the acmp controller. */ (void)memset(dev, 0, sizeof(sdrv_acmp_t)); return ret; }