blob: a908dc00fd9c23dee9f42111a3e3cfae8d7f9e1b [file] [log] [blame]
/****************************************************************************
* arch/risc-v/src/esp32c3-legacy/esp32c3_wdt.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <stdbool.h>
#include <assert.h>
#include <debug.h>
#include "riscv_internal.h"
#include "hardware/esp32c3_rtccntl.h"
#include "hardware/esp32c3_tim.h"
#include "hardware/esp32c3_efuse.h"
#include "esp32c3_irq.h"
#include "esp32c3_rtc.h"
#include "esp32c3_rtc_gpio.h"
#include "esp32c3_wdt.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Helpers for converting from Q13.19 fixed-point format to float */
#define N 19
#define Q_TO_FLOAT(x) ((float)x/(float)(1<<N))
/* Check whether the provided device is a RTC Watchdog Timer */
#define IS_RWDT(dev) ((struct esp32c3_wdt_priv_s *)dev)->base == \
RTC_CNTL_OPTIONS0_REG
/****************************************************************************
* Private Types
****************************************************************************/
struct esp32c3_wdt_priv_s
{
struct esp32c3_wdt_ops_s *ops;
uint32_t base; /* WDT register base address */
uint8_t periph; /* Peripheral ID */
uint8_t irq; /* Interrupt ID */
int32_t cpuint; /* CPU interrupt assigned to this WDT */
bool inuse; /* Flag indicating if this WDT is in use */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* WDT registers access *****************************************************/
static void esp32c3_wdt_putreg(struct esp32c3_wdt_dev_s *dev,
uint32_t offset,
uint32_t value);
static void esp32c3_wdt_modifyreg32(struct esp32c3_wdt_dev_s *dev,
uint32_t offset,
uint32_t clearbits,
uint32_t setbits);
static uint32_t esp32c3_wdt_getreg(struct esp32c3_wdt_dev_s *dev,
uint32_t offset);
/* WDT operations ***********************************************************/
static void esp32c3_wdt_start(struct esp32c3_wdt_dev_s *dev);
static void esp32c3_wdt_stop(struct esp32c3_wdt_dev_s *dev);
static void esp32c3_wdt_enablewp(struct esp32c3_wdt_dev_s *dev);
static void esp32c3_wdt_disablewp(struct esp32c3_wdt_dev_s *dev);
static void esp32c3_wdt_pre(struct esp32c3_wdt_dev_s *dev,
uint16_t value);
static int32_t esp32c3_wdt_settimeout(struct esp32c3_wdt_dev_s *dev,
uint32_t value,
enum esp32c3_wdt_stage_e stage);
static void esp32c3_wdt_feed(struct esp32c3_wdt_dev_s *dev);
static int32_t esp32c3_wdt_config_stage(struct esp32c3_wdt_dev_s *dev,
enum esp32c3_wdt_stage_e stage,
enum esp32c3_wdt_stage_action_e cfg);
static void esp32c3_wdt_update_conf(struct esp32c3_wdt_dev_s *dev);
static uint16_t esp32c3_wdt_rtc_clk(struct esp32c3_wdt_dev_s *dev);
static int32_t esp32c3_wdt_setisr(struct esp32c3_wdt_dev_s *dev,
xcpt_t handler, void *arg);
static void esp32c3_wdt_enableint(struct esp32c3_wdt_dev_s *dev);
static void esp32c3_wdt_disableint(struct esp32c3_wdt_dev_s *dev);
static void esp32c3_wdt_ackint(struct esp32c3_wdt_dev_s *dev);
/****************************************************************************
* Private Data
****************************************************************************/
/* ESP32-C3 WDT ops */
struct esp32c3_wdt_ops_s esp32c3_mwdt_ops =
{
.start = esp32c3_wdt_start,
.stop = esp32c3_wdt_stop,
.enablewp = esp32c3_wdt_enablewp,
.disablewp = esp32c3_wdt_disablewp,
.pre = esp32c3_wdt_pre,
.settimeout = esp32c3_wdt_settimeout,
.feed = esp32c3_wdt_feed,
.stg_conf = esp32c3_wdt_config_stage,
.upd_conf = esp32c3_wdt_update_conf,
.rtc_clk = NULL,
.setisr = esp32c3_wdt_setisr,
.enableint = esp32c3_wdt_enableint,
.disableint = esp32c3_wdt_disableint,
.ackint = esp32c3_wdt_ackint,
};
struct esp32c3_wdt_ops_s esp32c3_rwdt_ops =
{
.start = esp32c3_wdt_start,
.stop = esp32c3_wdt_stop,
.enablewp = esp32c3_wdt_enablewp,
.disablewp = esp32c3_wdt_disablewp,
.pre = NULL,
.settimeout = esp32c3_wdt_settimeout,
.feed = esp32c3_wdt_feed,
.stg_conf = esp32c3_wdt_config_stage,
.upd_conf = NULL,
.rtc_clk = esp32c3_wdt_rtc_clk,
.setisr = esp32c3_wdt_setisr,
.enableint = esp32c3_wdt_enableint,
.disableint = esp32c3_wdt_disableint,
.ackint = esp32c3_wdt_ackint,
};
#ifdef CONFIG_ESP32C3_MWDT0
struct esp32c3_wdt_priv_s g_esp32c3_mwdt0_priv =
{
.ops = &esp32c3_mwdt_ops,
.base = TIMG_T0CONFIG_REG(0),
.periph = ESP32C3_PERIPH_TG0_WDT,
.irq = ESP32C3_IRQ_TG0_WDT,
.cpuint = -ENOMEM,
.inuse = false,
};
#endif
#ifdef CONFIG_ESP32C3_MWDT1
struct esp32c3_wdt_priv_s g_esp32c3_mwdt1_priv =
{
.ops = &esp32c3_mwdt_ops,
.base = TIMG_T0CONFIG_REG(1),
.periph = ESP32C3_PERIPH_TG1_WDT,
.irq = ESP32C3_IRQ_TG1_WDT,
.cpuint = -ENOMEM,
.inuse = false,
};
#endif
#ifdef CONFIG_ESP32C3_RWDT
struct esp32c3_wdt_priv_s g_esp32c3_rwdt_priv =
{
.ops = &esp32c3_rwdt_ops,
.base = RTC_CNTL_OPTIONS0_REG,
.periph = ESP32C3_PERIPH_RTC_CORE,
.irq = ESP32C3_IRQ_RTC_WDT,
.cpuint = -ENOMEM,
.inuse = false,
};
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: esp32c3_wdt_putreg
*
* Description:
* Write a 32-bit register value by offset.
*
* Parameters:
* dev - Pointer to the driver state structure.
* offset - Offset value to the base address of the WDT device.
* value - Value to written to the specified memory region.
*
****************************************************************************/
static void esp32c3_wdt_putreg(struct esp32c3_wdt_dev_s *dev,
uint32_t offset,
uint32_t value)
{
DEBUGASSERT(dev);
putreg32(value, ((struct esp32c3_wdt_priv_s *)dev)->base + offset);
}
/****************************************************************************
* Name: esp32c3_wdt_modifyreg32
*
* Description:
* Atomically modify a 32-bit register value by offset.
*
* Parameters:
* dev - Pointer to the driver state structure.
* offset - Offset value to the base address of the WDT device.
* clearbits - Bits to be cleared on the specified memory region.
* setbits - Bits to be set on the specified memory region.
*
****************************************************************************/
static void esp32c3_wdt_modifyreg32(struct esp32c3_wdt_dev_s *dev,
uint32_t offset,
uint32_t clearbits,
uint32_t setbits)
{
DEBUGASSERT(dev);
modifyreg32(((struct esp32c3_wdt_priv_s *)dev)->base + offset,
clearbits, setbits);
}
/****************************************************************************
* Name: esp32c3_wdt_getreg
*
* Description:
* Read a 32-bit register value by offset.
*
* Parameters:
* dev - Pointer to the driver state structure.
* offset - Offset value to the base address of the WDT device.
*
* Returned Values:
* A 32-bit value from the provided memory region of the WDT device.
*
****************************************************************************/
static uint32_t esp32c3_wdt_getreg(struct esp32c3_wdt_dev_s *dev,
uint32_t offset)
{
DEBUGASSERT(dev);
return getreg32(((struct esp32c3_wdt_priv_s *)dev)->base + offset);
}
/****************************************************************************
* Name: esp32c3_wdt_start
*
* Description:
* Release the counter.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_start(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
esp32c3_wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET, 0, RTC_CNTL_WDT_EN);
}
else
{
esp32c3_wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, 0, TIMG_WDT_EN);
}
}
/****************************************************************************
* Name: esp32c3_wdt_config_stage
*
* Description:
* Configure the action to be triggered by a stage on expiration.
*
* Parameters:
* dev - Pointer to the driver state structure.
* stage - WDT stage to be configured.
* cfg - Action to be executed on stage expiration.
*
* Returned Values:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
static int32_t esp32c3_wdt_config_stage(struct esp32c3_wdt_dev_s *dev,
enum esp32c3_wdt_stage_e stage,
enum esp32c3_wdt_stage_action_e cfg)
{
uint32_t mask;
DEBUGASSERT(dev);
switch (stage)
{
case ESP32C3_WDT_STAGE0:
{
if (IS_RWDT(dev))
{
mask = (uint32_t)cfg << RTC_CNTL_WDT_STG0_S;
esp32c3_wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET,
RTC_CNTL_WDT_STG0_M, mask);
}
else
{
mask = (uint32_t)cfg << TIMG_WDT_STG0_S;
esp32c3_wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET,
TIMG_WDT_STG0_M, mask);
}
break;
}
case ESP32C3_WDT_STAGE1:
{
if (IS_RWDT(dev))
{
mask = (uint32_t)cfg << RTC_CNTL_WDT_STG1_S;
esp32c3_wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET,
RTC_CNTL_WDT_STG1_M, mask);
}
else
{
mask = (uint32_t)cfg << TIMG_WDT_STG1_S;
esp32c3_wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET,
TIMG_WDT_STG1_M, mask);
}
break;
}
case ESP32C3_WDT_STAGE2:
{
if (IS_RWDT(dev))
{
mask = (uint32_t)cfg << RTC_CNTL_WDT_STG2_S;
esp32c3_wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET,
RTC_CNTL_WDT_STG2_M, mask);
}
else
{
mask = (uint32_t)cfg << TIMG_WDT_STG2_S;
esp32c3_wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET,
TIMG_WDT_STG2_M, mask);
}
break;
}
case ESP32C3_WDT_STAGE3:
{
if (IS_RWDT(dev))
{
mask = (uint32_t)cfg << RTC_CNTL_WDT_STG3_S;
esp32c3_wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET,
RTC_CNTL_WDT_STG3_M, mask);
}
else
{
mask = (uint32_t)cfg << TIMG_WDT_STG3_S;
esp32c3_wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET,
TIMG_WDT_STG3_M, mask);
}
break;
}
default:
{
wderr("ERROR: unsupported stage %d\n", stage);
return -EINVAL;
}
}
return OK;
}
/****************************************************************************
* Name: esp32c3_wdt_update_conf
*
* Description:
* Update the Watchdog Timer configuration registers.
* Configuration registers for the MWDT are updated asynchronously.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_update_conf(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
esp32c3_wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, 0,
TIMG_WDT_CONF_UPDATE_EN);
}
/****************************************************************************
* Name: esp32c3_wdt_stop
*
* Description:
* Disable the watchdog.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_stop(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
esp32c3_wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET, RTC_CNTL_WDT_EN, 0);
}
else
{
esp32c3_wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, TIMG_WDT_EN, 0);
}
}
/****************************************************************************
* Name: esp32c3_wdt_enablewp
*
* Description:
* Enable write protection (WP) on registers against accidental writing.
* TRM recommends to change any WDT register through this sequence:
* - Disable WP
* - Do the op
* - Re-enable WP
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_enablewp(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
esp32c3_wdt_putreg(dev, RWDT_WP_REG, 0);
}
else
{
esp32c3_wdt_putreg(dev, MWDT_WP_REG, 0);
}
}
/****************************************************************************
* Name: esp32c3_wdt_disablewp
*
* Description:
* Disable write protection (WP) on registers against accidental writing.
* TRM recommends to change any WDT register through this sequence:
* - Disable WP
* - Do the op
* - Re-enable WP
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_disablewp(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
esp32c3_wdt_putreg(dev, RWDT_WP_REG, RTC_CNTL_WDT_WKEY_VALUE);
}
else
{
esp32c3_wdt_putreg(dev, MWDT_WP_REG, TIMG_WDT_WKEY_VALUE);
}
}
/****************************************************************************
* Name: esp32c3_wdt_pre
*
* Description:
* Set a prescale value.
* The MWDT clock period is 12.5 ns * value (pre).
* NOTE: There's no prescaler register for RWDT and its source clock is
* clocked from the RTC slow clock.
*
* Parameters:
* dev - Pointer to the driver state structure.
* pre - Prescaler value to be configured.
*
****************************************************************************/
static void esp32c3_wdt_pre(struct esp32c3_wdt_dev_s *dev,
uint16_t pre)
{
uint32_t mask = (uint32_t)pre << TIMG_WDT_CLK_PRESCALE_S;
DEBUGASSERT(dev);
esp32c3_wdt_modifyreg32(dev, MWDT_CLK_PRESCALE_OFFSET,
TIMG_WDT_CLK_PRESCALE_M, mask);
}
/****************************************************************************
* Name: esp32c3_wdt_settimeout
*
* Description:
* Set the WDT timeout.
*
* Parameters:
* dev - Pointer to the driver state structure.
* value - Timeout value in number of WDT cycles.
* stage - Stage whose timeout value needs to be configured.
*
* Returned Values:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
static int32_t esp32c3_wdt_settimeout(struct esp32c3_wdt_dev_s *dev,
uint32_t value,
enum esp32c3_wdt_stage_e stage)
{
int32_t ret = OK;
DEBUGASSERT(dev);
switch (stage)
{
case ESP32C3_WDT_STAGE0:
{
if (IS_RWDT(dev))
{
/* The timeout of only stage 0 happens at:
* Thold0 = RTC_CNTL_WDT_STG0_HOLD << (EFUSE_WDT_DELAY_SEL + 1)
*/
uint32_t delay;
delay = REG_GET_FIELD(EFUSE_RD_REPEAT_DATA1_REG,
EFUSE_WDT_DELAY_SEL);
value = value >> (delay + 1);
esp32c3_wdt_putreg(dev, RWDT_STAGE0_TIMEOUT_OFFSET, value);
}
else
{
esp32c3_wdt_putreg(dev, MWDT_STAGE0_TIMEOUT_OFFSET, value);
}
break;
}
case ESP32C3_WDT_STAGE1:
{
if (IS_RWDT(dev))
{
esp32c3_wdt_putreg(dev, RWDT_STAGE1_TIMEOUT_OFFSET, value);
}
else
{
esp32c3_wdt_putreg(dev, MWDT_STAGE1_TIMEOUT_OFFSET, value);
}
break;
}
case ESP32C3_WDT_STAGE2:
{
if (IS_RWDT(dev))
{
esp32c3_wdt_putreg(dev, RWDT_STAGE2_TIMEOUT_OFFSET, value);
}
else
{
esp32c3_wdt_putreg(dev, MWDT_STAGE2_TIMEOUT_OFFSET, value);
}
break;
}
case ESP32C3_WDT_STAGE3:
{
if (IS_RWDT(dev))
{
esp32c3_wdt_putreg(dev, RWDT_STAGE3_TIMEOUT_OFFSET, value);
}
else
{
esp32c3_wdt_putreg(dev, MWDT_STAGE3_TIMEOUT_OFFSET, value);
}
break;
}
default:
{
wderr("ERROR: unsupported stage %d\n", stage);
ret = -EINVAL;
}
}
return ret;
}
/****************************************************************************
* Name: esp32c3_wdt_feed
*
* Description:
* Feed the watchdog.
* The watchdog timer returns to stage 0 and its counter restarts from 0.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_feed(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
esp32c3_wdt_modifyreg32(dev, RWDT_FEED_OFFSET, 0, RTC_CNTL_WDT_FEED);
}
else
{
esp32c3_wdt_putreg(dev, MWDT_FEED_OFFSET, TIMG_WDT_FEED);
}
}
/****************************************************************************
* Name: esp32c3_wdt_rtc_clk
*
* Description:
* Calculate the necessary cycles of RTC SLOW_CLK to complete
* 1 ms.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
* Returned Values:
* Return the number of cycles that completes 1 ms.
*
****************************************************************************/
static uint16_t esp32c3_wdt_rtc_clk(struct esp32c3_wdt_dev_s *dev)
{
enum esp32c3_rtc_slow_freq_e slow_clk_rtc;
uint32_t period_13q19;
float period;
float cycles_ms;
uint16_t cycles_ms_int;
/* Calibration map: Maps each RTC SLOW_CLK source to the number
* used to calibrate this source.
*/
static const enum esp32c3_rtc_cal_sel_e cal_map[] =
{
RTC_CAL_RTC_MUX,
RTC_CAL_32K_XTAL,
RTC_CAL_8MD256
};
DEBUGASSERT(dev);
/* Check which clock is sourcing the slow_clk_rtc */
slow_clk_rtc = esp32c3_rtc_clk_slow_freq_get();
/* Get the slow_clk_rtc period in us in Q13.19 fixed point format */
period_13q19 = esp32c3_rtc_clk_cal(cal_map[slow_clk_rtc],
SLOW_CLK_CAL_CYCLES);
/* Assert no error happened during the calibration */
DEBUGASSERT(period_13q19 != 0);
/* Convert from Q13.19 format to float */
period = Q_TO_FLOAT(period_13q19);
wdinfo("PERIOD: %f %" PRIu32"\n", period, period_13q19);
/* Get the number of cycles necessary to count 1 ms */
cycles_ms = 1000.0f / period;
/* Get the integer number of cycles */
cycles_ms_int = (uint16_t)cycles_ms;
return cycles_ms_int;
}
/****************************************************************************
* Name: esp32c3_wdt_setisr
*
* Description:
* Allocate a Level CPU Interrupt, connect the peripheral source to this
* Interrupt, register the callback and enable the interrupt.
* In case a NULL handler is provided, deallocate the interrupt and
* unregister the previously provided handler.
*
* Parameters:
* dev - Pointer to the driver state structure.
* handler - Callback to be invoked on watchdog timer interrupt.
* arg - Argument to be passed to the handler callback.
*
* Returned Values:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
static int32_t esp32c3_wdt_setisr(struct esp32c3_wdt_dev_s *dev,
xcpt_t handler,
void *arg)
{
struct esp32c3_wdt_priv_s *wdt = NULL;
int32_t ret = OK;
DEBUGASSERT(dev);
wdt = (struct esp32c3_wdt_priv_s *)dev;
/* Disable interrupt when callback is removed. */
if (handler == NULL)
{
#ifdef CONFIG_ESP32C3_RWDT
if (wdt->irq == ESP32C3_IRQ_RTC_WDT)
{
esp32c3_rtcioirqdisable(wdt->irq);
irq_detach(wdt->irq);
}
else
#endif
if (wdt->cpuint != -ENOMEM)
{
{
/* If a CPU Interrupt was previously allocated,
* then deallocate it.
*/
up_disable_irq(wdt->irq);
irq_detach(wdt->irq);
esp32c3_teardown_irq(wdt->periph, wdt->cpuint);
wdt->cpuint = -ENOMEM;
}
}
}
/* Otherwise set callback and enable interrupt. */
else
{
#ifdef CONFIG_ESP32C3_RWDT
if (wdt->irq == ESP32C3_IRQ_RTC_WDT)
{
ret = irq_attach(wdt->irq, handler, arg);
if (ret != OK)
{
esp32c3_rtcioirqdisable(wdt->irq);
tmrerr("ERROR: Failed to associate an IRQ Number");
}
esp32c3_rtcioirqenable(wdt->irq);
}
else
#endif
{
if (wdt->cpuint != -ENOMEM)
{
/* Disable the provided CPU interrupt to configure it. */
up_disable_irq(wdt->irq);
/* Free CPU interrupt that is attached to this peripheral
* because we will get another from esp32c3_setup_irq()
*/
esp32c3_teardown_irq(wdt->periph, wdt->cpuint);
}
wdt->cpuint = esp32c3_setup_irq(wdt->periph,
ESP32C3_INT_PRIO_DEF,
ESP32C3_INT_LEVEL);
if (wdt->cpuint < 0)
{
return wdt->cpuint;
}
/* Attach and enable the IRQ. */
ret = irq_attach(wdt->irq, handler, arg);
if (ret != OK)
{
/* Failed to attach IRQ, so CPU interrupt must be freed. */
esp32c3_teardown_irq(wdt->periph, wdt->cpuint);
wdt->cpuint = -ENOMEM;
return ret;
}
/* Enable the CPU interrupt that is linked to the WDT. */
up_enable_irq(wdt->irq);
}
}
return ret;
}
/****************************************************************************
* Name: esp32c3_wdt_enableint
*
* Description:
* Enable a Level Interrupt at timeout.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_enableint(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
esp32c3_wdt_modifyreg32(dev, RWDT_INT_ENA_REG_OFFSET, 0,
RTC_CNTL_WDT_INT_ENA);
}
else
{
esp32c3_wdt_modifyreg32(dev, MWDT_INT_ENA_REG_OFFSET, 0,
TIMG_WDT_INT_ENA);
}
}
/****************************************************************************
* Name: esp32c3_wdt_disableint
*
* Description:
* Disable a Level Interrupt at timeout.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_disableint(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
esp32c3_wdt_modifyreg32(dev, RWDT_INT_ENA_REG_OFFSET,
RTC_CNTL_WDT_INT_ENA, 0);
}
else
{
esp32c3_wdt_modifyreg32(dev, MWDT_INT_ENA_REG_OFFSET,
TIMG_WDT_INT_ENA, 0);
}
}
/****************************************************************************
* Name: esp32c3_wdt_ackint
*
* Description:
* Acknowledge an interrupt.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void esp32c3_wdt_ackint(struct esp32c3_wdt_dev_s *dev)
{
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
esp32c3_wdt_putreg(dev, RWDT_INT_CLR_REG_OFFSET, RTC_CNTL_WDT_INT_CLR);
}
else
{
esp32c3_wdt_putreg(dev, MWDT_INT_CLR_REG_OFFSET, TIMG_WDT_INT_CLR);
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: esp32c3_wdt_init
*
* Description:
* Initialize WDT device.
*
* Parameters:
* wdt_id - A Watchdog Timer instance to be initialized.
*
* Return Values:
* Pointer to the driver state structure.
*
****************************************************************************/
struct esp32c3_wdt_dev_s *esp32c3_wdt_init(enum esp32c3_wdt_inst_e wdt_id)
{
struct esp32c3_wdt_priv_s *wdt = NULL;
/* Get WDT instance */
switch (wdt_id)
{
#ifdef CONFIG_ESP32C3_MWDT0
case ESP32C3_WDT_MWDT0:
{
wdt = &g_esp32c3_mwdt0_priv;
break;
}
#endif
#ifdef CONFIG_ESP32C3_MWDT1
case ESP32C3_WDT_MWDT1:
{
wdt = &g_esp32c3_mwdt1_priv;
break;
}
#endif
#ifdef CONFIG_ESP32C3_RWDT
case ESP32C3_WDT_RWDT:
{
wdt = &g_esp32c3_rwdt_priv;
/* If RTC was not initialized in a previous
* stage by the PM or by clock_initialize()
* Then, init the RTC clock configuration here.
*/
#if !defined(CONFIG_PM) && !defined(CONFIG_RTC)
/* Initialize RTC controller parameters */
esp32c3_rtc_init();
esp32c3_rtc_clk_set();
#endif
break;
}
#endif
default:
{
wderr("ERROR: unsupported WDT %d\n", wdt_id);
return NULL;
}
}
/* If some code is using it then sends an error message,
* Otherwise, inform it has been used.
*/
if (wdt->inuse == true)
{
wderr("ERROR: WDT %d is already in use\n", wdt_id);
return NULL;
}
else
{
wdt->inuse = true;
}
return (struct esp32c3_wdt_dev_s *)wdt;
}
/****************************************************************************
* Name: esp32c3_wdt_early_deinit
*
* Description:
* Disable the WDT(s) that was/were enabled by the bootloader.
*
****************************************************************************/
void esp32c3_wdt_early_deinit(void)
{
uint32_t regval;
putreg32(RTC_CNTL_WDT_WKEY_VALUE, RTC_CNTL_WDTWPROTECT_REG);
regval = getreg32(RTC_CNTL_WDTCONFIG0_REG);
regval &= ~RTC_CNTL_WDT_EN;
putreg32(regval, RTC_CNTL_WDTCONFIG0_REG);
putreg32(0, RTC_CNTL_WDTWPROTECT_REG);
}
/****************************************************************************
* Name: esp32c3_wdt_deinit
*
* Description:
* Deinitialize a WDT device.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
void esp32c3_wdt_deinit(struct esp32c3_wdt_dev_s *dev)
{
struct esp32c3_wdt_priv_s *wdt = NULL;
DEBUGASSERT(dev);
wdt = (struct esp32c3_wdt_priv_s *)dev;
wdt->inuse = false;
}
/****************************************************************************
* Name: esp32c3_wdt_is_running
*
* Description:
* Check whether the WDT is already started.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
* Returned Values:
* true if the Watchdog Timer is already started, false otherwise.
*
****************************************************************************/
bool esp32c3_wdt_is_running(struct esp32c3_wdt_dev_s *dev)
{
uint32_t status = 0;
DEBUGASSERT(dev);
if (IS_RWDT(dev))
{
status = esp32c3_wdt_getreg(dev, RWDT_CONFIG0_OFFSET);
if (status & RTC_CNTL_WDT_EN)
{
return true;
}
}
else
{
status = esp32c3_wdt_getreg(dev, MWDT_CONFIG0_OFFSET);
if (status & TIMG_WDT_EN)
{
return true;
}
}
return false;
}