drivers/watchdog: Add support for Microchip XEC device
Such watchdog timer is found on mec1501. It comes with a support of dbg stall feature and interrupt support. It does not support multistaging. Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com> Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
parent
e83f4fad29
commit
939fc26c2e
4 changed files with 200 additions and 0 deletions
|
@ -9,3 +9,4 @@ zephyr_sources_ifdef(CONFIG_WDT_SAM0 wdt_sam0.c)
|
|||
zephyr_sources_ifdef(CONFIG_WDT_NRFX wdt_nrfx.c)
|
||||
zephyr_sources_ifdef(CONFIG_WDT_MCUX_WDOG wdt_mcux_wdog.c)
|
||||
zephyr_sources_ifdef(CONFIG_WDT_MCUX_WDOG32 wdt_mcux_wdog32.c)
|
||||
zephyr_sources_ifdef(CONFIG_WDT_XEC wdt_mchp_xec.c)
|
||||
|
|
|
@ -57,4 +57,6 @@ source "drivers/watchdog/Kconfig.nrfx"
|
|||
|
||||
source "drivers/watchdog/Kconfig.mcux"
|
||||
|
||||
source "drivers/watchdog/Kconfig.xec"
|
||||
|
||||
endif
|
||||
|
|
14
drivers/watchdog/Kconfig.xec
Normal file
14
drivers/watchdog/Kconfig.xec
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Kconfig - Microchip XEC Watchdog Timer configuration
|
||||
#
|
||||
# Copyright (c) 2019 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
config WDT_XEC
|
||||
bool "Microchip XEC series Watchdog Timer (WDT) driver"
|
||||
depends on SOC_FAMILY_MEC
|
||||
select HAS_DTS_WDT
|
||||
default y
|
||||
help
|
||||
Enable WDT driver for Microchip XEC MCU series.
|
183
drivers/watchdog/wdt_mchp_xec.c
Normal file
183
drivers/watchdog/wdt_mchp_xec.c
Normal file
|
@ -0,0 +1,183 @@
|
|||
/* wdt_xec.c - Microchip XEC watchdog driver */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define LOG_LEVEL CONFIG_WDT_LOG_LEVEL
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(wdt_mchp_xec);
|
||||
|
||||
#include <drivers/watchdog.h>
|
||||
#include <soc.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define WDT_XEC_REG_BASE \
|
||||
((WDT_Type *)(DT_INST_0_MICROCHIP_XEC_WATCHDOG_BASE_ADDRESS))
|
||||
|
||||
struct wdt_xec_data {
|
||||
wdt_callback_t cb;
|
||||
bool timeout_installed;
|
||||
};
|
||||
|
||||
|
||||
DEVICE_DECLARE(wdt_xec);
|
||||
|
||||
static int wdt_xec_setup(struct device *dev, u8_t options)
|
||||
{
|
||||
WDT_Type *wdt_regs = WDT_XEC_REG_BASE;
|
||||
struct wdt_xec_data *data = dev->driver_data;
|
||||
|
||||
if (wdt_regs->CTRL & MCHP_WDT_CTRL_EN) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (!data->timeout_installed) {
|
||||
LOG_ERR("No valid WDT timeout installed");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (options & WDT_OPT_PAUSE_IN_SLEEP) {
|
||||
LOG_WRN("WDT_OPT_PAUSE_IN_SLEEP is not supported");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) {
|
||||
wdt_regs->CTRL |= MCHP_WDT_CTRL_JTAG_STALL_EN;
|
||||
} else {
|
||||
wdt_regs->CTRL &= ~MCHP_WDT_CTRL_JTAG_STALL_EN;
|
||||
}
|
||||
|
||||
wdt_regs->CTRL |= MCHP_WDT_CTRL_EN;
|
||||
|
||||
LOG_DBG("WDT Setup and enabled");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wdt_xec_disable(struct device *dev)
|
||||
{
|
||||
WDT_Type *wdt_regs = WDT_XEC_REG_BASE;
|
||||
struct wdt_xec_data *data = dev->driver_data;
|
||||
|
||||
if (!(wdt_regs->CTRL & MCHP_WDT_CTRL_EN)) {
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
wdt_regs->CTRL &= ~MCHP_WDT_CTRL_EN;
|
||||
data->timeout_installed = false;
|
||||
|
||||
LOG_DBG("WDT Disabled");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wdt_xec_install_timeout(struct device *dev,
|
||||
const struct wdt_timeout_cfg *config)
|
||||
{
|
||||
WDT_Type *wdt_regs = WDT_XEC_REG_BASE;
|
||||
struct wdt_xec_data *data = dev->driver_data;
|
||||
|
||||
if (wdt_regs->CTRL & MCHP_WDT_CTRL_EN) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (config->window.min > 0U) {
|
||||
data->timeout_installed = false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wdt_regs->LOAD = 0;
|
||||
|
||||
data->cb = config->callback;
|
||||
if (data->cb) {
|
||||
wdt_regs->CTRL |= MCHP_WDT_CTRL_MODE_IRQ;
|
||||
wdt_regs->IEN |= MCHP_WDT_IEN_EVENT_IRQ_EN;
|
||||
|
||||
LOG_DBG("WDT callback enabled");
|
||||
} else {
|
||||
/* Setting WDT_FLAG_RESET_SOC or not will have no effect:
|
||||
* even after the cb, if anything is done, SoC will reset
|
||||
*/
|
||||
wdt_regs->CTRL &= ~MCHP_WDT_CTRL_MODE_IRQ;
|
||||
wdt_regs->IEN &= ~MCHP_WDT_IEN_EVENT_IRQ_EN;
|
||||
|
||||
LOG_DBG("WDT Reset enabled");
|
||||
}
|
||||
|
||||
/* Since it almost takes 1ms to decrement the load register
|
||||
* (See datasheet 18.6.1.4: 33/32.768 KHz = 1.007ms)
|
||||
* Let's use the given window directly.
|
||||
*/
|
||||
wdt_regs->LOAD = config->window.max;
|
||||
|
||||
data->timeout_installed = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wdt_xec_feed(struct device *dev, int channel_id)
|
||||
{
|
||||
WDT_Type *wdt_regs = WDT_XEC_REG_BASE;
|
||||
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(channel_id);
|
||||
|
||||
if (!(wdt_regs->CTRL & MCHP_WDT_CTRL_EN)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LOG_DBG("WDT Kicking");
|
||||
|
||||
wdt_regs->KICK = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wdt_xec_isr(struct device *dev)
|
||||
{
|
||||
WDT_Type *wdt_regs = WDT_XEC_REG_BASE;
|
||||
struct wdt_xec_data *data = dev->driver_data;
|
||||
|
||||
LOG_DBG("WDT ISR");
|
||||
|
||||
if (data->cb) {
|
||||
data->cb(dev, 0);
|
||||
}
|
||||
|
||||
MCHP_GIRQ_SRC(MCHP_WDT_GIRQ) = MCHP_WDT_GIRQ_VAL;
|
||||
wdt_regs->IEN &= ~MCHP_WDT_IEN_EVENT_IRQ_EN;
|
||||
}
|
||||
|
||||
static const struct wdt_driver_api wdt_xec_api = {
|
||||
.setup = wdt_xec_setup,
|
||||
.disable = wdt_xec_disable,
|
||||
.install_timeout = wdt_xec_install_timeout,
|
||||
.feed = wdt_xec_feed,
|
||||
};
|
||||
|
||||
static int wdt_xec_init(struct device *dev)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_WDT_DISABLE_AT_BOOT)) {
|
||||
wdt_xec_disable(dev);
|
||||
}
|
||||
|
||||
MCHP_GIRQ_ENSET(MCHP_WDT_GIRQ) = MCHP_WDT_GIRQ_VAL;
|
||||
|
||||
IRQ_CONNECT(DT_INST_0_MICROCHIP_XEC_WATCHDOG_IRQ_0,
|
||||
DT_INST_0_MICROCHIP_XEC_WATCHDOG_IRQ_0_PRIORITY,
|
||||
wdt_xec_isr, DEVICE_GET(wdt_xec), 0);
|
||||
irq_enable(DT_INST_0_MICROCHIP_XEC_WATCHDOG_IRQ_0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct wdt_xec_data wdt_xec_dev_data;
|
||||
|
||||
DEVICE_AND_API_INIT(wdt_xec, DT_INST_0_MICROCHIP_XEC_WATCHDOG_LABEL,
|
||||
wdt_xec_init, &wdt_xec_dev_data, NULL,
|
||||
PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
|
||||
&wdt_xec_api);
|
Loading…
Add table
Add a link
Reference in a new issue