drivers: watchdog: Add Raspberry Pi Pico watchdog driver
This adds basic support for the watchdog timer on the RP2040 MCU and Raspberry Pi Pico development board Signed-off-by: Jamie McCrae <spam@helper3000.net>
This commit is contained in:
parent
927d6b620d
commit
a20eb66742
|
@ -443,6 +443,7 @@
|
|||
/drivers/watchdog/wdt_ite_it8xxx2.c @RuibinChang
|
||||
/drivers/watchdog/Kconfig.it8xxx2 @RuibinChang
|
||||
/drivers/watchdog/wdt_counter.c @nordic-krch
|
||||
/drivers/watchdog/*rpi_pico* @thedjnK
|
||||
/drivers/wifi/ @rlubos @tbursztyka @pfalcon
|
||||
/drivers/wifi/esp_at/ @mniestroj
|
||||
/drivers/wifi/eswifi/ @loicpoulain @nandojve
|
||||
|
|
|
@ -28,8 +28,15 @@
|
|||
};
|
||||
};
|
||||
|
||||
xtal_clk: xtal-clk {
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <12000000>;
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
aliases {
|
||||
led0 = &led0;
|
||||
watchdog0 = &wdt0;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -85,6 +92,10 @@
|
|||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
&wdt0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
zephyr_udc0: &usbd {
|
||||
status = "okay";
|
||||
};
|
||||
|
|
|
@ -17,6 +17,7 @@ zephyr_library_sources_ifdef(CONFIG_WDT_MCUX_WDOG32 wdt_mcux_wdog32.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_WDT_MCUX_WWDT wdt_mcux_wwdt.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_WDT_NPCX wdt_npcx.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_WDT_NRFX wdt_nrfx.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_WDT_RPI_PICO wdt_rpi_pico.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_WDT_SAM wdt_sam.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_WDT_SAM0 wdt_sam0.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_WDT_SIFIVE wdt_sifive.c)
|
||||
|
|
|
@ -82,4 +82,7 @@ source "drivers/watchdog/Kconfig.npcx"
|
|||
source "drivers/watchdog/Kconfig.cc32xx"
|
||||
|
||||
source "drivers/watchdog/Kconfig.it8xxx2"
|
||||
|
||||
source "drivers/watchdog/Kconfig.rpi_pico"
|
||||
|
||||
endif
|
||||
|
|
20
drivers/watchdog/Kconfig.rpi_pico
Normal file
20
drivers/watchdog/Kconfig.rpi_pico
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Copyright (c) 2022, Jamie McCrae
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
DT_COMPAT_RASPBERRYPI_PICO_WATCHDOG := raspberrypi,pico-watchdog
|
||||
|
||||
config WDT_RPI_PICO
|
||||
bool "Raspberry Pi Pico Watchdog driver"
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_RASPBERRYPI_PICO_WATCHDOG))
|
||||
depends on SOC_FAMILY_RPI_PICO
|
||||
|
||||
config WDT_RPI_PICO_INITIAL_TIMEOUT
|
||||
int "Default watchdog timeout in us"
|
||||
depends on WDT_RPI_PICO
|
||||
default 8388607
|
||||
range 1 8388607
|
||||
help
|
||||
Sets the default watchdog timeout at start-up, the feed function must
|
||||
be called every interval prior to this time elapsing to prevent a
|
||||
reboot of the module. The default is just over 8 seconds, which is the
|
||||
largest timeout possible.
|
171
drivers/watchdog/wdt_rpi_pico.c
Normal file
171
drivers/watchdog/wdt_rpi_pico.c
Normal file
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Jamie McCrae
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT raspberrypi_pico_watchdog
|
||||
|
||||
#include <hardware/watchdog.h>
|
||||
#include <hardware/structs/psm.h>
|
||||
#include <zephyr/drivers/watchdog.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(wdt_rpi_pico, CONFIG_WDT_LOG_LEVEL);
|
||||
|
||||
/* Maximum watchdog time is halved due to errata RP2040-E1 */
|
||||
#define RPI_PICO_MAX_WDT_TIME (0xffffff / 2)
|
||||
#define RPI_PICO_WDT_TIME_MULTIPLICATION_FACTOR 2
|
||||
|
||||
/* Watchdog requires a 1MHz clock source, divided from the crystal oscillator */
|
||||
#define RPI_PICO_XTAL_FREQ_WDT_TICK_DIVISOR 1000000
|
||||
|
||||
struct wdt_rpi_pico_data {
|
||||
uint8_t reset_type;
|
||||
uint32_t load;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
struct wdt_rpi_pico_config {
|
||||
uint32_t xtal_frequency;
|
||||
};
|
||||
|
||||
static int wdt_rpi_pico_setup(const struct device *dev, uint8_t options)
|
||||
{
|
||||
const struct wdt_rpi_pico_config *config = dev->config;
|
||||
struct wdt_rpi_pico_data *data = dev->data;
|
||||
|
||||
if ((options & WDT_OPT_PAUSE_IN_SLEEP) == 1) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
hw_clear_bits(&watchdog_hw->ctrl, WATCHDOG_CTRL_ENABLE_BITS);
|
||||
|
||||
psm_hw->wdsel = 0;
|
||||
|
||||
/* TODO: Handle individual core reset when SMP support for RP2040 is added */
|
||||
if (data->reset_type == WDT_FLAG_RESET_SOC) {
|
||||
hw_set_bits(&psm_hw->wdsel, PSM_WDSEL_BITS);
|
||||
} else if (data->reset_type == WDT_FLAG_RESET_CPU_CORE) {
|
||||
hw_set_bits(&psm_hw->wdsel, PSM_WDSEL_PROC0_BITS);
|
||||
}
|
||||
|
||||
if ((options & WDT_OPT_PAUSE_HALTED_BY_DBG) == 0) {
|
||||
hw_clear_bits(&watchdog_hw->ctrl,
|
||||
(WATCHDOG_CTRL_PAUSE_JTAG_BITS | WATCHDOG_CTRL_PAUSE_DBG0_BITS |
|
||||
WATCHDOG_CTRL_PAUSE_DBG1_BITS));
|
||||
} else {
|
||||
hw_set_bits(&watchdog_hw->ctrl,
|
||||
(WATCHDOG_CTRL_PAUSE_JTAG_BITS | WATCHDOG_CTRL_PAUSE_DBG0_BITS |
|
||||
WATCHDOG_CTRL_PAUSE_DBG1_BITS));
|
||||
}
|
||||
|
||||
watchdog_hw->load = data->load;
|
||||
|
||||
/* Zero out the scratch registers so that the module reboots at the
|
||||
* default program counter
|
||||
*/
|
||||
watchdog_hw->scratch[4] = 0;
|
||||
watchdog_hw->scratch[5] = 0;
|
||||
watchdog_hw->scratch[6] = 0;
|
||||
watchdog_hw->scratch[7] = 0;
|
||||
|
||||
hw_set_bits(&watchdog_hw->ctrl, WATCHDOG_CTRL_ENABLE_BITS);
|
||||
|
||||
data->enabled = true;
|
||||
|
||||
watchdog_hw->tick = (config->xtal_frequency / RPI_PICO_XTAL_FREQ_WDT_TICK_DIVISOR) |
|
||||
WATCHDOG_TICK_ENABLE_BITS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wdt_rpi_pico_disable(const struct device *dev)
|
||||
{
|
||||
struct wdt_rpi_pico_data *data = dev->data;
|
||||
|
||||
if (data->enabled == false) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
hw_clear_bits(&watchdog_hw->ctrl, WATCHDOG_CTRL_ENABLE_BITS);
|
||||
|
||||
data->enabled = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wdt_rpi_pico_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *cfg)
|
||||
{
|
||||
struct wdt_rpi_pico_data *data = dev->data;
|
||||
|
||||
if (cfg->window.min != 0U || cfg->window.max == 0U) {
|
||||
return -EINVAL;
|
||||
} else if (cfg->window.max > RPI_PICO_MAX_WDT_TIME) {
|
||||
return -EINVAL;
|
||||
} else if (cfg->callback != NULL) {
|
||||
return -ENOTSUP;
|
||||
} else if ((cfg->flags & WDT_FLAG_RESET_MASK) == WDT_FLAG_RESET_NONE) {
|
||||
/* The RP2040 does technically support this mode, but requires
|
||||
* a program counter and stack pointer value to be set,
|
||||
* therefore do not allow configuring in this mode
|
||||
*/
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data->load = (cfg->window.max * RPI_PICO_WDT_TIME_MULTIPLICATION_FACTOR);
|
||||
data->reset_type = (cfg->flags & WDT_FLAG_RESET_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wdt_rpi_pico_feed(const struct device *dev, int channel_id)
|
||||
{
|
||||
struct wdt_rpi_pico_data *data = dev->data;
|
||||
|
||||
if (channel_id != 0) {
|
||||
/* There is only one input to the watchdog */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (data->enabled == false) {
|
||||
/* Watchdog is not running so does not need to be fed */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
watchdog_hw->load = data->load;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wdt_rpi_pico_init(const struct device *dev)
|
||||
{
|
||||
#ifndef CONFIG_WDT_DISABLE_AT_BOOT
|
||||
return wdt_rpi_pico_setup(dev, WDT_OPT_PAUSE_HALTED_BY_DBG);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct wdt_driver_api wdt_rpi_pico_driver_api = {
|
||||
.setup = wdt_rpi_pico_setup,
|
||||
.disable = wdt_rpi_pico_disable,
|
||||
.install_timeout = wdt_rpi_pico_install_timeout,
|
||||
.feed = wdt_rpi_pico_feed,
|
||||
};
|
||||
|
||||
#define WDT_RPI_PICO_WDT_DEVICE(idx) \
|
||||
static const struct wdt_rpi_pico_config wdt_##idx##_config = { \
|
||||
.xtal_frequency = DT_INST_PROP_BY_PHANDLE(idx, clocks, clock_frequency) \
|
||||
}; \
|
||||
static struct wdt_rpi_pico_data wdt_##idx##_data = { \
|
||||
.reset_type = WDT_FLAG_RESET_SOC, \
|
||||
.load = (CONFIG_WDT_RPI_PICO_INITIAL_TIMEOUT * \
|
||||
RPI_PICO_WDT_TIME_MULTIPLICATION_FACTOR), \
|
||||
.enabled = false \
|
||||
}; \
|
||||
DEVICE_DT_DEFINE(DT_NODELABEL(wdt##idx), wdt_rpi_pico_init, NULL, &wdt_##idx##_data, \
|
||||
&wdt_##idx##_config, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
|
||||
&wdt_rpi_pico_driver_api)
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(WDT_RPI_PICO_WDT_DEVICE);
|
|
@ -125,6 +125,14 @@
|
|||
status = "disabled";
|
||||
};
|
||||
|
||||
wdt0: watchdog@40058000 {
|
||||
compatible = "raspberrypi,pico-watchdog";
|
||||
reg = <0x40058000 DT_SIZE_K(4)>;
|
||||
clocks = <&xtal_clk>;
|
||||
label = "WDT_0";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
usbd: usbd@50100000 {
|
||||
compatible = "raspberrypi,pico-usbd";
|
||||
reg = <0x50100000 0x10000>;
|
||||
|
|
19
dts/bindings/watchdog/raspberrypi,pico-watchdog.yaml
Normal file
19
dts/bindings/watchdog/raspberrypi,pico-watchdog.yaml
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Copyright (c) 2022, Jamie McCrae
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Raspberry Pi Pico Watchdog
|
||||
|
||||
compatible: "raspberrypi,pico-watchdog"
|
||||
|
||||
include: base.yaml
|
||||
|
||||
properties:
|
||||
reg:
|
||||
required: true
|
||||
|
||||
label:
|
||||
required: true
|
||||
|
||||
clocks:
|
||||
required: true
|
||||
description: Crystal oscillator source clock
|
Loading…
Reference in a new issue