-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
1 parent
927d6b6
commit a20eb66
Showing
8 changed files
with
234 additions
and
0 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |