wdt: dw: Extraction of common functions from the wdt_dw driver

Functions that can be used by other wdt_dw based drivers have been moved to
wdt_dw_common.

Signed-off-by: Adrian Warecki <adrian.warecki@intel.com>
This commit is contained in:
Adrian Warecki 2023-01-10 09:28:08 +01:00 committed by Anas Nashif
parent 884e6b98f4
commit 1d964d8fba
4 changed files with 188 additions and 70 deletions

View file

@ -33,6 +33,6 @@ zephyr_library_sources_ifdef(CONFIG_WDT_NXP_S32 wdt_nxp_s32.c)
zephyr_library_sources_ifdef(CONFIG_WDT_SMARTBOND wdt_smartbond.c)
zephyr_library_sources_ifdef(CONFIG_WDT_TI_TPS382X wdt_ti_tps382x.c)
zephyr_library_sources_ifdef(CONFIG_WDT_DW wdt_dw.c)
zephyr_library_sources_ifdef(CONFIG_WDT_DW wdt_dw.c wdt_dw_common.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE wdt_handlers.c)

View file

@ -13,11 +13,10 @@
#include <zephyr/math/ilog2.h>
#include "wdt_dw.h"
#include "wdt_dw_common.h"
LOG_MODULE_REGISTER(wdt_dw, CONFIG_WDT_LOG_LEVEL);
#define WDT_DW_FLAG_CONFIGURED 0x80000000
#define WDT_IS_INST_IRQ_EN(inst) DT_NODE_HAS_PROP(DT_DRV_INST(inst), interrupts)
#define WDT_CHECK_INTERRUPT_USED(inst) WDT_IS_INST_IRQ_EN(inst) ||
#define WDT_DW_INTERRUPT_SUPPORT DT_INST_FOREACH_STATUS_OKAY(WDT_CHECK_INTERRUPT_USED) 0
@ -44,55 +43,21 @@ static int dw_wdt_setup(const struct device *dev, uint8_t options)
{
const struct dw_wdt_dev_cfg *const dev_config = dev->config;
struct dw_wdt_dev_data *const dev_data = dev->data;
uint32_t period;
if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) {
LOG_ERR("Pausing watchdog by debugger is not supported.");
return -ENOTSUP;
}
if (options & WDT_OPT_PAUSE_IN_SLEEP) {
LOG_ERR("Pausing watchdog in sleep is not supported.");
return -ENOTSUP;
}
if (!(dev_data->config & WDT_DW_FLAG_CONFIGURED)) {
LOG_ERR("Timeout not installed.");
return -ENOTSUP;
}
/* Configure timeout */
period = dev_data->config & ~WDT_DW_FLAG_CONFIGURED;
if (dw_wdt_dual_timeout_period_get(dev_config->base)) {
dw_wdt_timeout_period_init_set(dev_config->base, period);
}
dw_wdt_timeout_period_set(dev_config->base, period);
dw_wdt_check_options(options);
#if WDT_DW_INTERRUPT_SUPPORT
/* Configure response mode */
dw_wdt_response_mode_set(dev_config->base, !!dev_data->callback);
#endif
/* Enable watchdog */
dw_wdt_enable(dev_config->base);
dw_wdt_counter_restart(dev_config->base);
return 0;
}
static int dw_wdt_disable(const struct device *dev)
{
return -ENOTSUP;
return dw_wdt_configure(dev_config->base, dev_data->config);
}
static int dw_wdt_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *config)
{
const struct dw_wdt_dev_cfg *const dev_config = dev->config;
struct dw_wdt_dev_data *const dev_data = dev->data;
uint64_t period64;
uint32_t period;
#if WDT_DW_INTERRUPT_SUPPORT
if (config->callback && !dev_config->irq_config) {
@ -103,36 +68,17 @@ static int dw_wdt_install_timeout(const struct device *dev, const struct wdt_tim
return -ENOTSUP;
}
/* Window timeout is not supported by this driver */
if (config->window.min) {
LOG_ERR("Window timeout is not supported.");
return -ENOTSUP;
}
if (config->flags) {
LOG_ERR("Watchdog behavior is not configurable.");
return -ENOTSUP;
}
period64 = (uint64_t)dev_config->clk_freq * config->window.max;
period64 /= 1000;
if (!period64 || (period64 >> 31)) {
LOG_ERR("Window max is out of range.");
return -EINVAL;
}
period = period64 - 1;
period = ilog2(period);
if (period >= dw_wdt_cnt_width_get(dev_config->base)) {
LOG_ERR("Watchdog timeout too long.");
return -EINVAL;
}
/* The minimum counter value is 64k, maximum 2G */
dev_data->config = WDT_DW_FLAG_CONFIGURED | (period >= 15 ? period - 15 : 0);
#ifdef WDT_DW_INTERRUPT_SUPPORT
dev_data->callback = config->callback;
return 0;
#endif
return dw_wdt_calc_period(dev_config->base, dev_config->clk_freq, config,
&dev_data->config);
}
static int dw_wdt_feed(const struct device *dev, int channel_id)
@ -159,14 +105,11 @@ static const struct wdt_driver_api dw_wdt_api = {
static int dw_wdt_init(const struct device *dev)
{
const struct dw_wdt_dev_cfg *const dev_config = dev->config;
int ret;
/* Check component type */
if (dw_wdt_comp_type_get(dev_config->base) != WDT_COMP_TYPE_VALUE) {
LOG_ERR("Invalid component type %x", dw_wdt_comp_type_get(dev_config->base));
return -ENODEV;
}
dw_wdt_reset_pulse_length_set(dev_config->base, dev_config->reset_pulse_length);
ret = dw_wdt_probe(dev_config->base, dev_config->reset_pulse_length);
if (ret)
return ret;
#if WDT_DW_INTERRUPT_SUPPORT
if (dev_config->irq_config) {

View file

@ -0,0 +1,110 @@
/* SPDX-License-Identifier: Apache-2.0 */
/*
* Copyright (c) 2023 Intel Corporation
*
* Author: Adrian Warecki <adrian.warecki@intel.com>
*/
#include <zephyr/drivers/watchdog.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys_clock.h>
#include <zephyr/math/ilog2.h>
#include "wdt_dw_common.h"
#include "wdt_dw.h"
LOG_MODULE_REGISTER(wdt_dw_common, CONFIG_WDT_LOG_LEVEL);
#define WDT_DW_FLAG_CONFIGURED 0x80000000
int dw_wdt_check_options(const uint8_t options)
{
if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) {
LOG_ERR("Pausing watchdog by debugger is not supported.");
return -ENOTSUP;
}
if (options & WDT_OPT_PAUSE_IN_SLEEP) {
LOG_ERR("Pausing watchdog in sleep is not supported.");
return -ENOTSUP;
}
return 0;
}
int dw_wdt_configure(const uint32_t base, const uint32_t config)
{
uint32_t period;
if (!(config & WDT_DW_FLAG_CONFIGURED)) {
LOG_ERR("Timeout not installed.");
return -ENOTSUP;
}
/* Configure timeout */
period = config & ~WDT_DW_FLAG_CONFIGURED;
if (dw_wdt_dual_timeout_period_get(base)) {
dw_wdt_timeout_period_init_set(base, period);
}
dw_wdt_timeout_period_set(base, period);
/* Enable watchdog */
dw_wdt_enable(base);
dw_wdt_counter_restart(base);
return 0;
}
int dw_wdt_calc_period(const uint32_t base, const uint32_t clk_freq,
const struct wdt_timeout_cfg *config, uint32_t *period_out)
{
uint64_t period64;
uint32_t period;
/* Window timeout is not supported by this driver */
if (config->window.min) {
LOG_ERR("Window timeout is not supported.");
return -ENOTSUP;
}
period64 = (uint64_t)clk_freq * config->window.max;
period64 /= 1000;
if (!period64 || (period64 >> 31)) {
LOG_ERR("Window max is out of range.");
return -EINVAL;
}
period = period64 - 1;
period = ilog2(period);
if (period >= dw_wdt_cnt_width_get(base)) {
LOG_ERR("Watchdog timeout too long.");
return -EINVAL;
}
/* The minimum counter value is 64k, maximum 2G */
*period_out = WDT_DW_FLAG_CONFIGURED | (period >= 15 ? period - 15 : 0);
return 0;
}
int dw_wdt_probe(const uint32_t base, const uint32_t reset_pulse_length)
{
/* Check component type */
const uint32_t type = dw_wdt_comp_type_get(base);
if (type != WDT_COMP_TYPE_VALUE) {
LOG_ERR("Invalid component type %x", type);
return -ENODEV;
}
dw_wdt_reset_pulse_length_set(base, reset_pulse_length);
return 0;
}
int dw_wdt_disable(const struct device *dev)
{
return -ENOTSUP;
}

View file

@ -0,0 +1,65 @@
/* SPDX-License-Identifier: Apache-2.0 */
/*
* Copyright (c) 2023 Intel Corporation
*
* Author: Adrian Warecki <adrian.warecki@intel.com>
*/
#ifndef ZEPHYR_DRIVERS_WATCHDOG_WDT_DW_COMMON_H_
#define ZEPHYR_DRIVERS_WATCHDOG_WDT_DW_COMMON_H_
#include <stdint.h>
/**
* @brief Check watchdog configuration options
*
* Check options value passed to a watchdog setup function. Returns error if unsupported option
* is used.
*
* @param options options value passed to a watchdog setup function.
* @return Error code, 0 on success.
*/
int dw_wdt_check_options(const uint8_t options);
/**
* @brief Configure watchdog device
*
* @param base Device base address.
* @param config device configuration word
* @return Error code, 0 on success.
*/
int dw_wdt_configure(const uint32_t base, const uint32_t config);
/**
* @brief Calculate period
*
* @param [in]base Device base address.
* @param [in]clk_freq frequency of a clock used by watchdog device
* @param [in]config pointer to a watchdog configuration structure
* @param [out]period_out pointer to a variable in which the period configuration word will be
* placed
* @return Error code, 0 on success.
*/
int dw_wdt_calc_period(const uint32_t base, const uint32_t clk_freq,
const struct wdt_timeout_cfg *config, uint32_t *period_out);
/**
* @brief Watchdog probe
*
* Checks device id register and configure a reset pulse length.
*
* @param base Device base address.
* @param reset_pulse_length Length of a reset pulse produced by watchdog
* @return Error code, 0 on success.
*/
int dw_wdt_probe(const uint32_t base, const uint32_t reset_pulse_length);
/**
* @brief Watchdog disable function
*
* @param dev Device structure.
* @return -ENOTSUP. The hardware does not support disabling.
*/
int dw_wdt_disable(const struct device *dev);
#endif /* ZEPHYR_DRIVERS_WATCHDOG_WDT_DW_COMMON_H_ */