* [PATCH 0/3] watchdog: Add support for Andes ATCWDT200
@ 2026-01-07 14:50 CL Wang
2026-01-07 14:50 ` [PATCH 1/3] dt-bindings: " CL Wang
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: CL Wang @ 2026-01-07 14:50 UTC (permalink / raw)
To: cl634, wim, linux, robh, krzk+dt, conor+dt
Cc: devicetree, linux-kernel, linux-watchdog, tim609
This series adds support for the Andes ATCWDT200 watchdog timer.
The driver integrates with the Linux watchdog framework and supports:
- Basic watchdog operations (start, stop, ping, set_timeout).
- Programmable reset and interrupt intervals.
- Automatic detection of the supported interrupt timer bit-width.
- System reset via the watchdog restart handler.
CL Wang (3):
dt-bindings: watchdog: Add support for Andes ATCWDT200
watchdog: atcwdt200: Add driver for Andes ATCWDT200
MAINTAINERS: Add entry for Andes ATCWDT200
.../watchdog/andestech,ae350-wdt.yaml | 48 ++
MAINTAINERS | 6 +
drivers/watchdog/Kconfig | 9 +
drivers/watchdog/Makefile | 1 +
drivers/watchdog/atcwdt200_wdt.c | 596 ++++++++++++++++++
5 files changed, 660 insertions(+)
create mode 100644 Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml
create mode 100644 drivers/watchdog/atcwdt200_wdt.c
--
2.34.1
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 1/3] dt-bindings: watchdog: Add support for Andes ATCWDT200 2026-01-07 14:50 [PATCH 0/3] watchdog: Add support for Andes ATCWDT200 CL Wang @ 2026-01-07 14:50 ` CL Wang 2026-01-07 15:44 ` Krzysztof Kozlowski 2026-01-07 16:23 ` Rob Herring (Arm) 2026-01-07 14:50 ` [PATCH 2/3] watchdog: atcwdt200: Add driver " CL Wang 2026-01-07 14:50 ` [PATCH 3/3] MAINTAINERS: Add entry " CL Wang 2 siblings, 2 replies; 11+ messages in thread From: CL Wang @ 2026-01-07 14:50 UTC (permalink / raw) To: cl634, wim, linux, robh, krzk+dt, conor+dt Cc: devicetree, linux-kernel, linux-watchdog, tim609 Add the devicetree binding documentation for the Andes ATCWDT200 watchdog timer, including supported properties and usage examples. Signed-off-by: CL Wang <cl634@andestech.com> --- .../watchdog/andestech,ae350-wdt.yaml | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml diff --git a/Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml b/Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml new file mode 100644 index 000000000000..4726bd6734d8 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/andestech,ae350-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Andes ATCWDT200 Watchdog Timer + +maintainers: + - CL Wang <cl634@andestech.com> + +allOf: + - $ref: watchdog.yaml# + +properties: + compatible: + oneOf: + - items: + - enum: + - andestech,qilai-wdt + - const: andestech,ae350-wdt + - const: andestech,ae350-wdt + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + andestech,clock-source: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - andestech,clock-source + +unevaluatedProperties: false + +examples: + - | + watchdog@f0500000 { + compatible = "andestech,ae350-wdt"; + reg = <0xf0500000 0x20>; + clocks = <&clk_wdt>; + andestech,clock-source = <0>; + }; -- 2.34.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 1/3] dt-bindings: watchdog: Add support for Andes ATCWDT200 2026-01-07 14:50 ` [PATCH 1/3] dt-bindings: " CL Wang @ 2026-01-07 15:44 ` Krzysztof Kozlowski 2026-01-09 9:35 ` CL Wang 2026-01-07 16:23 ` Rob Herring (Arm) 1 sibling, 1 reply; 11+ messages in thread From: Krzysztof Kozlowski @ 2026-01-07 15:44 UTC (permalink / raw) To: CL Wang, wim, linux, robh, krzk+dt, conor+dt Cc: devicetree, linux-kernel, linux-watchdog, tim609 On 07/01/2026 15:50, CL Wang wrote: > Add the devicetree binding documentation for the Andes ATCWDT200 > watchdog timer, including supported properties and usage examples. Last part is redundant. Can you add a binding without supported properties and without usage examples? > > Signed-off-by: CL Wang <cl634@andestech.com> > --- > .../watchdog/andestech,ae350-wdt.yaml | 48 +++++++++++++++++++ > 1 file changed, 48 insertions(+) > create mode 100644 Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml > > diff --git a/Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml b/Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml > new file mode 100644 > index 000000000000..4726bd6734d8 > --- /dev/null > +++ b/Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml > @@ -0,0 +1,48 @@ > +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause > +%YAML 1.2 > +--- > +$id: http://devicetree.org/schemas/watchdog/andestech,ae350-wdt.yaml# > +$schema: http://devicetree.org/meta-schemas/core.yaml# > + > +title: Andes ATCWDT200 Watchdog Timer > + > +maintainers: > + - CL Wang <cl634@andestech.com> > + > +allOf: > + - $ref: watchdog.yaml# > + > +properties: > + compatible: > + oneOf: > + - items: > + - enum: > + - andestech,qilai-wdt > + - const: andestech,ae350-wdt > + - const: andestech,ae350-wdt Subject says WDT200, this code sais 350 and qilai. What is what? You have entire commit msg to explain that > + > + reg: > + maxItems: 1 > + > + clocks: > + maxItems: 1 > + > + andestech,clock-source: No clue what's this, but for sure does not pass tests without description and type. > + maxItems: 1 > + > +required: > + - compatible > + - reg > + - clocks > + - andestech,clock-source > + > +unevaluatedProperties: false > + > +examples: > + - | > + watchdog@f0500000 { > + compatible = "andestech,ae350-wdt"; > + reg = <0xf0500000 0x20>; > + clocks = <&clk_wdt>; > + andestech,clock-source = <0>; > + }; Best regards, Krzysztof ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/3] dt-bindings: watchdog: Add support for Andes ATCWDT200 2026-01-07 15:44 ` Krzysztof Kozlowski @ 2026-01-09 9:35 ` CL Wang 0 siblings, 0 replies; 11+ messages in thread From: CL Wang @ 2026-01-09 9:35 UTC (permalink / raw) To: Krzysztof Kozlowski Cc: wim, linux, robh, krzk+dt, conor+dt, devicetree, linux-kernel, linux-watchdog, tim609, ben717 Hi Krzysztof, Thanks for your review. On 07/01/2026 15:50, Krzysztof Kozlowski wrote: > Last part is redundant. Can you add a binding without supported properties and without usage examples? Agreed. I will remove the redundant part "including supported properties and usage examples" in the commit message in the next version. > Subject says WDT200, this code sais 350 and qilai. What is what? You have entire commit msg to explain that I will clarify in the commit message that ATCWDT200 is the IP name, which is embedded in AndesCore-based platforms or SoCs such as AE350 and Qilai. > No clue what's this, but for sure does not pass tests without description and type. You are right, I missed the type definition. I will add the description and set the type to uint32 (enum [0, 1]) for `andestech,clock-source`. Best regards, CL Wang ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/3] dt-bindings: watchdog: Add support for Andes ATCWDT200 2026-01-07 14:50 ` [PATCH 1/3] dt-bindings: " CL Wang 2026-01-07 15:44 ` Krzysztof Kozlowski @ 2026-01-07 16:23 ` Rob Herring (Arm) 2026-01-12 6:59 ` CL Wang 1 sibling, 1 reply; 11+ messages in thread From: Rob Herring (Arm) @ 2026-01-07 16:23 UTC (permalink / raw) To: CL Wang Cc: krzk+dt, linux-watchdog, tim609, linux-kernel, wim, linux, conor+dt, devicetree On Wed, 07 Jan 2026 22:50:55 +0800, CL Wang wrote: > Add the devicetree binding documentation for the Andes ATCWDT200 > watchdog timer, including supported properties and usage examples. > > Signed-off-by: CL Wang <cl634@andestech.com> > --- > .../watchdog/andestech,ae350-wdt.yaml | 48 +++++++++++++++++++ > 1 file changed, 48 insertions(+) > create mode 100644 Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml > My bot found errors running 'make dt_binding_check' on your patch: yamllint warnings/errors: dtschema/dtc warnings/errors: /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml: andestech,clock-source: missing type definition doc reference errors (make refcheckdocs): See https://patchwork.kernel.org/project/devicetree/patch/20260107145058.213334-2-cl634@andestech.com The base for the series is generally the latest rc1. A different dependency should be noted in *this* patch. If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date: pip3 install dtschema --upgrade Please check and re-submit after running the above command yourself. Note that DT_SCHEMA_FILES can be set to your schema file to speed up checking your schema. However, it must be unset to test all examples with your schema. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/3] dt-bindings: watchdog: Add support for Andes ATCWDT200 2026-01-07 16:23 ` Rob Herring (Arm) @ 2026-01-12 6:59 ` CL Wang 0 siblings, 0 replies; 11+ messages in thread From: CL Wang @ 2026-01-12 6:59 UTC (permalink / raw) To: Rob Herring (Arm) Cc: krzk+dt, linux-watchdog, tim609, linux-kernel, wim, linux, conor+dt, devicetree Hi Rob, Thanks for the report. You are right, the andestech,clock-source property is missing a type definition. I will fix the schema, re-run make dt_binding_check with an up-to-date dt-schema, and resend the patch. Best regards, CL Wang ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 2/3] watchdog: atcwdt200: Add driver for Andes ATCWDT200 2026-01-07 14:50 [PATCH 0/3] watchdog: Add support for Andes ATCWDT200 CL Wang 2026-01-07 14:50 ` [PATCH 1/3] dt-bindings: " CL Wang @ 2026-01-07 14:50 ` CL Wang 2026-01-07 15:46 ` Krzysztof Kozlowski 2026-01-07 14:50 ` [PATCH 3/3] MAINTAINERS: Add entry " CL Wang 2 siblings, 1 reply; 11+ messages in thread From: CL Wang @ 2026-01-07 14:50 UTC (permalink / raw) To: cl634, wim, linux, robh, krzk+dt, conor+dt Cc: devicetree, linux-kernel, linux-watchdog, tim609 Add support for the Andes ATCWDT200 watchdog timer. The driver implements programmable reset and interrupt timers, and includes automatic detection of the supported IntTime bit-width. Integrated with the Linux watchdog framework, it supports basic operations including start, stop, ping, timeout configuration, and system reset via the restart handler. Signed-off-by: CL Wang <cl634@andestech.com> --- drivers/watchdog/Kconfig | 9 + drivers/watchdog/Makefile | 1 + drivers/watchdog/atcwdt200_wdt.c | 596 +++++++++++++++++++++++++++++++ 3 files changed, 606 insertions(+) create mode 100644 drivers/watchdog/atcwdt200_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index d3b9df7d466b..f5d3c1227385 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -2140,6 +2140,15 @@ config WATCHDOG_RTAS # RISC-V Architecture +config ATCWDT200_WATCHDOG + tristate "Andes ATCWDT200 Watchdog support" + depends on ARCH_ANDES || COMPILE_TEST + help + Driver for the Andes ATCWDT200 watchdog timer. It provides access to + programmable reset and interrupt counters with clock-source dependent + timing. The driver automatically detects the supported IntTime bit-width + and is fully integrated with the Linux Watchdog Framework. + config STARFIVE_WATCHDOG tristate "StarFive Watchdog support" depends on ARCH_STARFIVE || COMPILE_TEST diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index ba52099b1253..aaecf7899380 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -201,6 +201,7 @@ obj-$(CONFIG_PSERIES_WDT) += pseries-wdt.o obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o # RISC-V Architecture +obj-$(CONFIG_ATCWDT200_WATCHDOG) += atcwdt200_wdt.o obj-$(CONFIG_STARFIVE_WATCHDOG) += starfive-wdt.o # S390 Architecture diff --git a/drivers/watchdog/atcwdt200_wdt.c b/drivers/watchdog/atcwdt200_wdt.c new file mode 100644 index 000000000000..d5aa56d165cf --- /dev/null +++ b/drivers/watchdog/atcwdt200_wdt.c @@ -0,0 +1,596 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Andes ATCWDT200 watchdog timer driver. + * + * Copyright (C) 2025 Andes Technology Corporation + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/dev_printk.h> +#include <linux/math64.h> +#include <linux/minmax.h> +#include <linux/moduleparam.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/watchdog.h> + +/* Register definitions */ +#define REG_CTRL 0x10 +#define REG_RESTART 0x14 +#define REG_WRITE_EN 0x18 +#define REG_STATUS 0x1C + +/* Control Register */ +#define CTRL_RST_TIME_MSK GENMASK(10, 8) +#define CTRL_RST_TIME_SET(x) FIELD_PREP(CTRL_RST_TIME_MSK, x) +#define CTRL_INT_TIME_MSK GENMASK(7, 4) +#define CTRL_INT_TIME_SET(x) FIELD_PREP(CTRL_INT_TIME_MSK, x) +#define CTRL_INT_TIME_GET(x) FIELD_GET(CTRL_INT_TIME_MSK, x) +#define CTRL_RST_EN BIT(3) +#define CTRL_CLK_SEL BIT(1) +#define CTRL_CLK_SEL_PCLK 1 +#define CTRL_CLK_SEL_SET(x) FIELD_PREP(CTRL_CLK_SEL, x) +#define CTRL_WDT_EN BIT(0) + +/* Restart Register */ +#define RESTART_MAGIC 0xCAFE + +/* Write Enable Register */ +#define WRITE_EN_MAGIC 0x5AA5 + +/* Status Register */ +#define STATUS_INT_EXPIRED BIT(1) + +/* The default timeout value in seconds */ +#define ATCWDT_TIMEOUT 4 + +/* Define the array size for each timer type */ +#define TMR_SZ_RST 8 +#define TMR_SZ_INT_16 8 +#define TMR_SZ_INT_32 16 + +#define DRV_NAME "atcwdt200" +/** + * enum timer_type - Supported timer types for ATCWDT200 watchdog driver + * @TMR_RST: Reset timer (non-interrupt). + * @TMR_INT_16: 16-bit interrupt timer supported by hardware. + * @TMR_INT_32: 32-bit interrupt timer supported by hardware. + * @TMR_UNKNOWN: Timer type cannot be determined. + */ +enum timer_type { + TMR_RST, + TMR_INT_16, + TMR_INT_32, + TMR_UNKNOWN +}; + +static unsigned int timeout = ATCWDT_TIMEOUT; +static bool nowayout = WATCHDOG_NOWAYOUT; + +/** + * struct atcwdt_drv - ATCWDT200 watchdog driver private data + * @wdt_dev: Watchdog device used by the watchdog framework. + * @regmap: Register map for accessing hardware registers. + * @clk: Hardware clock used by the watchdog timer. + * @lock: Spinlock protecting register accesses and driver state. + * @clk_freq: Input clock frequency of the ATCWDT200. + * @clk_src: Selected clock source for the watchdog timer. + * @int_timer_type: Detected interrupt timer type (16-bit, 32-bit, or unknown). + */ +struct atcwdt_drv { + struct watchdog_device wdt_dev; + struct regmap *regmap; + struct clk *clk; + spinlock_t lock; + unsigned int clk_freq; + unsigned char clk_src; + unsigned char int_timer_type; +}; + +static const struct watchdog_info atcwdt_info = { + .identity = DRV_NAME, + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, +}; + +/** + * atcwdt_get_index - Get the interval value for the specified timer type + * @index: The index of the interval in the array + * @timer_type: The type of timer, which can be TMR_RST, TMR_INT_16, or + * TMR_INT_32. + * + * This function retrieves the interval value based on the timer type and + * ensures the index stays within the valid range for the given timer type. + * For TMR_RST: + * - The maximum array size is 8 (index range: 0-7). + * For TMR_INT_16: + * - The maximum array size is 8 (index range: 0-7). + * For TMR_INT_32: + * - The maximum array size is 16 (index range: 0-15). + * + * If the index exceeds the maximum array size, the function will return + * the last element of the respective array. + */ +static inline unsigned char atcwdt_get_index(unsigned char index, + enum timer_type timer_type) +{ + static const unsigned char rst_timer_interval[TMR_SZ_RST] = { + 7, 8, 9, 10, 11, 12, 13, 14}; + static const unsigned char int_timer_interval[TMR_SZ_INT_32] = { + 6, 8, 10, 11, 12, 13, 14, 15, 17, 19, 21, 23, 25, 27, 29, 31}; + unsigned char array_index; + + if (timer_type == TMR_RST) { + array_index = min(index, TMR_SZ_RST - 1); + return rst_timer_interval[array_index]; + } + + if (timer_type == TMR_INT_32) + array_index = min(index, TMR_SZ_INT_32 - 1); + else + array_index = min(index, TMR_SZ_INT_16 - 1); + + return int_timer_interval[array_index]; +} + +/** + * atcwdt_get_clock_period - Calculate the closest clock period based on a + * given tick count + * @tick: The target tick count to match + * @timer_type: The type of timer, which can be TMR_RST, TMR_INT_16, or + * TMR_INT_32. + * @index: Pointer to store the index of the selected parameter + * + * This function calculates the closest clock period to the given tick count + * by iterating through the timer parameters and selecting the one that + * minimizes the difference between the target tick count and the calculated + * clock period. The function determines the index of the closest parameter + * and returns the difference between the target tick count and the selected + * clock period. + * + * Return: The difference between the target tick count and the selected + * clock period. + */ +static long long atcwdt_get_clock_period(long long tick, + enum timer_type timer_type, + unsigned char *index) +{ + long long result; + unsigned char size; + char i; + + if (timer_type == TMR_RST) + size = TMR_SZ_RST; + else if (timer_type == TMR_INT_32) + size = TMR_SZ_INT_32; + else + size = TMR_SZ_INT_16; + + *index = size - 1; + for (i = 0; i < size; i++) { + result = tick - (1LL << atcwdt_get_index(i, timer_type)); + + if (result <= 1) { + *index = i; + break; + } + } + + return result; +} + +/** + * atcwdt_get_timeout_params - Calculate optimal parameters for Watchdog Timer + * @drv_data: Pointer to the Watchdog driver data structure + * @timeout: Desired timeout value (in seconds) + * @int_timer_params: Pointer to store the calculated interrupt timer + * parameter index + * @rst_timer_params: Pointer to store the calculated reset timer parameter + * index + * + * This function calculates the optimal parameter combination for the + * interrupt timer and reset timer of the Watchdog Timer to achieve a + * timeout value closest to, but not less than the specified timeout. + * + * Algorithm: + * 1. The parameters for both the interrupt timer and reset timer are + * predefined as a series of options represented as powers of 2. + * 2. The function first determines the interrupt timer's parameter index + * that provides a time closest to and not exceeding the desired timeout. + * 3. Based on the selected interrupt timer, it calculates the required + * reset timer parameter to ensure the total timeout matches the target. + * + * Return: The calculated parameter indices are stored in the provided + * pointers. + */ +static void atcwdt_get_timeout_params(struct atcwdt_drv *drv_data, + unsigned int timeout, + unsigned char *int_timer_params, + unsigned char *rst_timer_params) +{ + long long rest_time_ms; + long long result; + long long tick; + unsigned char rst_index; + unsigned char int_index; + unsigned char above; + unsigned char below; + + tick = (long long)timeout * drv_data->clk_freq; + result = atcwdt_get_clock_period(tick, + drv_data->int_timer_type, + &above); + if (result == 0 || above == 0) { + *int_timer_params = above; + *rst_timer_params = 0; + return; + } + below = above - 1; + + int_index = atcwdt_get_index(below, drv_data->int_timer_type); + rest_time_ms = timeout * 1000LL + - div64_s64(1000LL << int_index, drv_data->clk_freq); + + result = atcwdt_get_clock_period(rest_time_ms * drv_data->clk_freq, + TMR_RST, + &rst_index); + + if (result > 1) { + *int_timer_params = above; + *rst_timer_params = 0; + } else { + *int_timer_params = below; + *rst_timer_params = rst_index; + } +} + +/** + * atcwdt_get_int_timer_type - Get the supported interrupt timer type. + * @drv_data: Pointer to the watchdog driver data structure. + * + * This function tests the writable bits in the IntTime field of the control + * register to determine the interrupt timer type supported by the hardware. + * + * Note: This function must only be called when the ATCWDT200 watchdog is + * disabled. If the watchdog is enabled, this function returns TMR_UNKNOWN. + * + * Returns: The interrupt timer type supported by the hardware. + */ +static int atcwdt_get_int_timer_type(struct atcwdt_drv *drv_data) +{ + struct device *dev = drv_data->wdt_dev.parent; + unsigned int val; + int ret = 0; + + spin_lock(&drv_data->lock); + regmap_read(drv_data->regmap, REG_CTRL, &val); + if (val & CTRL_WDT_EN) { + spin_unlock(&drv_data->lock); + return TMR_UNKNOWN; + } + + /* + * Configures the IntTime field with the maximum mask value + * (CTRL_INT_TIME_MSK), reads its value from the control register + * to identify the maximum writable bits. + */ + regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); + regmap_write(drv_data->regmap, REG_CTRL, CTRL_INT_TIME_MSK); + regmap_read(drv_data->regmap, REG_CTRL, &val); + spin_unlock(&drv_data->lock); + + val = CTRL_INT_TIME_GET(val); + switch (val) { + case 7: + drv_data->int_timer_type = TMR_INT_16; + break; + case 15: + drv_data->int_timer_type = TMR_INT_32; + break; + default: + drv_data->int_timer_type = TMR_UNKNOWN; + ret = dev_err_probe(dev, -ENODEV, + "Failed to detect interrupt timer type\n"); + } + + return ret; +} + +static int atcwdt_ping(struct watchdog_device *wdt_dev) +{ + struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev); + + spin_lock(&drv_data->lock); + regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); + regmap_write(drv_data->regmap, REG_RESTART, RESTART_MAGIC); + regmap_update_bits(drv_data->regmap, REG_STATUS, STATUS_INT_EXPIRED, + STATUS_INT_EXPIRED); + spin_unlock(&drv_data->lock); + + return 0; +} + +static int atcwdt_set_timeout(struct watchdog_device *wdt_dev, + unsigned int timeout) +{ + struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev); + unsigned int value; + unsigned char rst_val; + unsigned char int_val; + + wdt_dev->timeout = timeout; + atcwdt_get_timeout_params(drv_data, timeout, &int_val, &rst_val); + + spin_lock(&drv_data->lock); + regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); + + value = CTRL_RST_TIME_SET(rst_val) | + CTRL_INT_TIME_SET(int_val) | + CTRL_CLK_SEL_SET(drv_data->clk_src); + regmap_update_bits(drv_data->regmap, + REG_CTRL, + CTRL_RST_TIME_MSK | + CTRL_INT_TIME_MSK | + CTRL_CLK_SEL, + value); + + spin_unlock(&drv_data->lock); + atcwdt_ping(wdt_dev); + + return 0; +} + +static int atcwdt_start(struct watchdog_device *wdt_dev) +{ + struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev); + + atcwdt_set_timeout(wdt_dev, wdt_dev->timeout); + + spin_lock(&drv_data->lock); + regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); + regmap_update_bits(drv_data->regmap, + REG_CTRL, + CTRL_RST_EN | CTRL_WDT_EN, + CTRL_RST_EN | CTRL_WDT_EN); + + spin_unlock(&drv_data->lock); + + return 0; +} + +static int atcwdt_stop(struct watchdog_device *wdt_dev) +{ + struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev); + + spin_lock(&drv_data->lock); + regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); + regmap_update_bits(drv_data->regmap, + REG_CTRL, + CTRL_RST_EN | CTRL_WDT_EN, + 0); + spin_unlock(&drv_data->lock); + + return 0; +} + +static int atcwdt_restart(struct watchdog_device *wdt_dev, + unsigned long action, void *data) +{ + struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev); + + atcwdt_set_timeout(wdt_dev, 0); + + spin_lock(&drv_data->lock); + regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); + regmap_update_bits(drv_data->regmap, + REG_CTRL, + CTRL_RST_EN | CTRL_WDT_EN, + CTRL_RST_EN | CTRL_WDT_EN); + spin_unlock(&drv_data->lock); + + return 0; +} + +static const struct watchdog_ops atcwdt_ops = { + .owner = THIS_MODULE, + .start = atcwdt_start, + .stop = atcwdt_stop, + .ping = atcwdt_ping, + .set_timeout = atcwdt_set_timeout, + .restart = atcwdt_restart, +}; + +static int atcwdt_init_resource(struct platform_device *pdev, + struct atcwdt_drv *drv_data) +{ + struct device *dev = &pdev->dev; + void __iomem *base; + const struct regmap_config cfg = { + .name = "atcwdt", + .reg_bits = 32, + .val_bits = 32, + .cache_type = REGCACHE_NONE, + .reg_stride = 4, + .max_register = REG_STATUS, + }; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return dev_err_probe(dev, PTR_ERR(base), + "Failed to ioremap I/O resource\n"); + + drv_data->regmap = devm_regmap_init_mmio(dev, base, &cfg); + if (IS_ERR(drv_data->regmap)) + return dev_err_probe(dev, PTR_ERR(drv_data->regmap), + "Failed to create regmap\n"); + + return 0; +} + +static int atcwdt_enable_clk(struct atcwdt_drv *drv_data) +{ + struct device *dev = drv_data->wdt_dev.parent; + unsigned int val; + int ret; + + drv_data->clk = devm_clk_get(dev, NULL); + if (IS_ERR(drv_data->clk)) + return dev_err_probe(dev, PTR_ERR(drv_data->clk), + "Failed to get watchdog clock\n"); + + ret = clk_prepare_enable(drv_data->clk); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable clock\n"); + + drv_data->clk_freq = clk_get_rate(drv_data->clk); + if (!drv_data->clk_freq) + return dev_err_probe(dev, -EINVAL, + "Failed to get clock rate\n"); + + ret = device_property_read_u32(dev, "andestech,clock-source", &val); + drv_data->clk_src = (!ret && val != 0) ? CTRL_CLK_SEL_PCLK : 0; + + return 0; +} + +static int atcwdt_init_wdt_device(struct device *dev, + struct atcwdt_drv *drv_data) +{ + struct watchdog_device *wdd = &drv_data->wdt_dev; + + wdd->parent = dev; + wdd->info = &atcwdt_info; + wdd->ops = &atcwdt_ops; + wdd->timeout = ATCWDT_TIMEOUT; + wdd->min_timeout = 1; + + watchdog_set_nowayout(wdd, nowayout); + watchdog_set_drvdata(wdd, drv_data); + + return 0; +} + +static void atcwdt_calc_max_timeout(struct atcwdt_drv *drv_data) +{ + unsigned char rst_idx = atcwdt_get_index(0xFF, TMR_RST); + unsigned char int_idx = atcwdt_get_index(0xFF, + drv_data->int_timer_type); + + drv_data->wdt_dev.max_timeout = + ((1U << rst_idx) + (1U << int_idx)) / drv_data->clk_freq; +} + +static int atcwdt_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct atcwdt_drv *drv_data; + int ret; + + drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); + if (!drv_data) + return -ENOMEM; + + platform_set_drvdata(pdev, drv_data); + spin_lock_init(&drv_data->lock); + + ret = atcwdt_init_wdt_device(dev, drv_data); + if (ret) + return ret; + + ret = atcwdt_init_resource(pdev, drv_data); + if (ret) + return ret; + + ret = atcwdt_enable_clk(drv_data); + if (ret) + return ret; + + ret = atcwdt_get_int_timer_type(drv_data); + if (ret) + goto disable_clk; + + atcwdt_calc_max_timeout(drv_data); + + ret = devm_watchdog_register_device(dev, &drv_data->wdt_dev); + if (ret) + goto disable_clk; + + return 0; + +disable_clk: + clk_disable_unprepare(drv_data->clk); + + return ret; +} + +static int atcwdt_suspend(struct device *dev) +{ + struct atcwdt_drv *drv_data = dev_get_drvdata(dev); + + if (watchdog_active(&drv_data->wdt_dev)) { + atcwdt_stop(&drv_data->wdt_dev); + clk_disable_unprepare(drv_data->clk); + } + + return 0; +} + +static int atcwdt_resume(struct device *dev) +{ + struct atcwdt_drv *drv_data = dev_get_drvdata(dev); + int ret = 0; + + if (watchdog_active(&drv_data->wdt_dev)) { + ret = clk_prepare_enable(drv_data->clk); + if (ret) + goto clk_prepare_err; + + atcwdt_start(&drv_data->wdt_dev); + atcwdt_ping(&drv_data->wdt_dev); + } + +clk_prepare_err: + return ret; +} + +static const struct of_device_id atcwdt_match[] = { + { .compatible = "andestech,qilai-wdt" }, + { .compatible = "andestech,ae350-wdt" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, atcwdt_match); + +static DEFINE_SIMPLE_DEV_PM_OPS(atcwdt_pm_ops, atcwdt_suspend, atcwdt_resume); + +static struct platform_driver atcwdt_driver = { + .probe = atcwdt_probe, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = atcwdt_match, + .pm = pm_sleep_ptr(&atcwdt_pm_ops), + }, +}; + +module_platform_driver(atcwdt_driver); + +module_param(timeout, uint, 0); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=" + __MODULE_STRING(ATCWDT_TIMEOUT) ")"); + +module_param(nowayout, bool, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("CL Wang <cl634@andestech.com>"); +MODULE_DESCRIPTION("Andes ATCWDT200 Watchdog timer driver"); -- 2.34.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 2/3] watchdog: atcwdt200: Add driver for Andes ATCWDT200 2026-01-07 14:50 ` [PATCH 2/3] watchdog: atcwdt200: Add driver " CL Wang @ 2026-01-07 15:46 ` Krzysztof Kozlowski 2026-01-12 7:05 ` CL Wang 0 siblings, 1 reply; 11+ messages in thread From: Krzysztof Kozlowski @ 2026-01-07 15:46 UTC (permalink / raw) To: CL Wang, wim, linux, robh, krzk+dt, conor+dt Cc: devicetree, linux-kernel, linux-watchdog, tim609 On 07/01/2026 15:50, CL Wang wrote: > + > +static int atcwdt_enable_clk(struct atcwdt_drv *drv_data) > +{ > + struct device *dev = drv_data->wdt_dev.parent; > + unsigned int val; > + int ret; > + > + drv_data->clk = devm_clk_get(dev, NULL); Just use API for getting enabled clock. > + if (IS_ERR(drv_data->clk)) > + return dev_err_probe(dev, PTR_ERR(drv_data->clk), > + "Failed to get watchdog clock\n"); > + > + ret = clk_prepare_enable(drv_data->clk); > + if (ret) > + return dev_err_probe(dev, ret, > + "Failed to enable clock\n"); > + > + drv_data->clk_freq = clk_get_rate(drv_data->clk); > + if (!drv_data->clk_freq) > + return dev_err_probe(dev, -EINVAL, > + "Failed to get clock rate\n"); > + > + ret = device_property_read_u32(dev, "andestech,clock-source", &val); No, read your binding. You said it is a list... list of phandles? > + drv_data->clk_src = (!ret && val != 0) ? CTRL_CLK_SEL_PCLK : 0; > + > + return 0; > +} > + > +static int atcwdt_init_wdt_device(struct device *dev, > + struct atcwdt_drv *drv_data) > +{ > + struct watchdog_device *wdd = &drv_data->wdt_dev; > + > + wdd->parent = dev; > + wdd->info = &atcwdt_info; > + wdd->ops = &atcwdt_ops; > + wdd->timeout = ATCWDT_TIMEOUT; > + wdd->min_timeout = 1; > + > + watchdog_set_nowayout(wdd, nowayout); > + watchdog_set_drvdata(wdd, drv_data); > + > + return 0; > +} > + > +static void atcwdt_calc_max_timeout(struct atcwdt_drv *drv_data) > +{ > + unsigned char rst_idx = atcwdt_get_index(0xFF, TMR_RST); > + unsigned char int_idx = atcwdt_get_index(0xFF, > + drv_data->int_timer_type); > + > + drv_data->wdt_dev.max_timeout = > + ((1U << rst_idx) + (1U << int_idx)) / drv_data->clk_freq; > +} > + > +static int atcwdt_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct atcwdt_drv *drv_data; > + int ret; > + > + drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); > + if (!drv_data) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, drv_data); > + spin_lock_init(&drv_data->lock); > + > + ret = atcwdt_init_wdt_device(dev, drv_data); > + if (ret) > + return ret; > + > + ret = atcwdt_init_resource(pdev, drv_data); > + if (ret) > + return ret; > + > + ret = atcwdt_enable_clk(drv_data); > + if (ret) > + return ret; > + > + ret = atcwdt_get_int_timer_type(drv_data); > + if (ret) > + goto disable_clk; > + > + atcwdt_calc_max_timeout(drv_data); > + > + ret = devm_watchdog_register_device(dev, &drv_data->wdt_dev); > + if (ret) > + goto disable_clk; > + > + return 0; > + > +disable_clk: > + clk_disable_unprepare(drv_data->clk); > + > + return ret; > +} > + > +static int atcwdt_suspend(struct device *dev) > +{ > + struct atcwdt_drv *drv_data = dev_get_drvdata(dev); > + > + if (watchdog_active(&drv_data->wdt_dev)) { > + atcwdt_stop(&drv_data->wdt_dev); > + clk_disable_unprepare(drv_data->clk); > + } > + > + return 0; > +} > + > +static int atcwdt_resume(struct device *dev) > +{ > + struct atcwdt_drv *drv_data = dev_get_drvdata(dev); > + int ret = 0; > + > + if (watchdog_active(&drv_data->wdt_dev)) { > + ret = clk_prepare_enable(drv_data->clk); > + if (ret) > + goto clk_prepare_err; Just return. > + > + atcwdt_start(&drv_data->wdt_dev); > + atcwdt_ping(&drv_data->wdt_dev); > + } > + > +clk_prepare_err: > + return ret; > +} > + > +static const struct of_device_id atcwdt_match[] = { > + { .compatible = "andestech,qilai-wdt" }, Drop, not needed. > + { .compatible = "andestech,ae350-wdt" }, > + { /* sentinel */ }, > +}; > +MODULE_DEVICE_TABLE(of, atcwdt_match); > + > +static DEFINE_SIMPLE_DEV_PM_OPS(atcwdt_pm_ops, atcwdt_suspend, atcwdt_resume); > + > +static struct platform_driver atcwdt_driver = { > + .probe = atcwdt_probe, > + .driver = { > + .name = DRV_NAME, > + .owner = THIS_MODULE, From where did you get this? > + .of_match_table = atcwdt_match, > + .pm = pm_sleep_ptr(&atcwdt_pm_ops), > + }, > +}; > + > +module_platform_driver(atcwdt_driver); > + > +module_param(timeout, uint, 0); > +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=" > + __MODULE_STRING(ATCWDT_TIMEOUT) ")"); > + > +module_param(nowayout, bool, 0); > +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" > + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); > + > +MODULE_LICENSE("GPL"); > +MODULE_AUTHOR("CL Wang <cl634@andestech.com>"); > +MODULE_DESCRIPTION("Andes ATCWDT200 Watchdog timer driver"); Best regards, Krzysztof ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/3] watchdog: atcwdt200: Add driver for Andes ATCWDT200 2026-01-07 15:46 ` Krzysztof Kozlowski @ 2026-01-12 7:05 ` CL Wang 0 siblings, 0 replies; 11+ messages in thread From: CL Wang @ 2026-01-12 7:05 UTC (permalink / raw) To: Krzysztof Kozlowski Cc: wim, linux, robh, krzk+dt, conor+dt, devicetree, linux-kernel, linux-watchdog, tim609, cl634, ben717 Hi Krzysztof, Thanks for your review. On 07/01/2026 15:50, Krzysztof Kozlowski wrote: > Just use API for getting enabled clock. Agreed. I will switch to using `devm_clk_get_enabled()` to simplify the clock handling and error paths. > No, read your binding. You said it is a list... list of phandles? You are right. The property is intended to be a single uint32 configuration value. I will update the binding schema to clearly define it as such and make it consistent with the driver. > Just return. Agreed. I will simplify the resume path and return directly on error. > Drop, not needed. Understood. I will drop the `"andestech,qilai-wdt"` compatible and keep only the generic one. > From where did you get this? You're right, this is unnecessary. I will remove `.owner = THIS_MODULE`. I will address all of the above in the next revision. Best regards, CL Wang ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 3/3] MAINTAINERS: Add entry for Andes ATCWDT200 2026-01-07 14:50 [PATCH 0/3] watchdog: Add support for Andes ATCWDT200 CL Wang 2026-01-07 14:50 ` [PATCH 1/3] dt-bindings: " CL Wang 2026-01-07 14:50 ` [PATCH 2/3] watchdog: atcwdt200: Add driver " CL Wang @ 2026-01-07 14:50 ` CL Wang 2 siblings, 0 replies; 11+ messages in thread From: CL Wang @ 2026-01-07 14:50 UTC (permalink / raw) To: cl634, wim, linux, robh, krzk+dt, conor+dt Cc: devicetree, linux-kernel, linux-watchdog, tim609 Add a MAINTAINERS entry for the Andes ATCWDT200 watchdog driver and its associated Device Tree bindings. Signed-off-by: CL Wang <cl634@andestech.com> --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 12f49de7fe03..1a1c2b68252a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1817,6 +1817,12 @@ S: Supported F: drivers/clk/analogbits/* F: include/linux/clk/analogbits* +ANDES ATCWDT200 WATCHDOG DRIVER +M: CL Wang <cl634@andestech.com> +S: Supported +F: Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml +F: drivers/watchdog/atcwdt200_wdt.c + ANDROID DRIVERS M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> M: Arve Hjønnevåg <arve@android.com> -- 2.34.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 1/3] dt-bindings: watchdog: Add support for Andes ATCWDT200
@ 2026-01-12 18:04 kernel test robot
0 siblings, 0 replies; 11+ messages in thread
From: kernel test robot @ 2026-01-12 18:04 UTC (permalink / raw)
To: oe-kbuild; +Cc: lkp
::::::
:::::: Manual check reason: "dtcheck: binding changes may go via different trees"
::::::
BCC: lkp@intel.com
CC: oe-kbuild-all@lists.linux.dev
In-Reply-To: <20260107145058.213334-2-cl634@andestech.com>
References: <20260107145058.213334-2-cl634@andestech.com>
TO: CL Wang <cl634@andestech.com>
TO: cl634@andestech.com
TO: wim@linux-watchdog.org
TO: linux@roeck-us.net
TO: robh@kernel.org
TO: krzk+dt@kernel.org
TO: conor+dt@kernel.org
CC: devicetree@vger.kernel.org
CC: linux-kernel@vger.kernel.org
CC: linux-watchdog@vger.kernel.org
CC: tim609@andestech.com
Hi CL,
kernel test robot noticed the following build warnings:
[auto build test WARNING on robh/for-next]
[also build test WARNING on groeck-staging/hwmon-next linus/master v6.16-rc1 next-20260109]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/CL-Wang/dt-bindings-watchdog-Add-support-for-Andes-ATCWDT200/20260107-233010
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link: https://lore.kernel.org/r/20260107145058.213334-2-cl634%40andestech.com
patch subject: [PATCH 1/3] dt-bindings: watchdog: Add support for Andes ATCWDT200
:::::: branch date: 5 days ago
:::::: commit date: 5 days ago
config: openrisc-randconfig-2052-20260112 (https://download.01.org/0day-ci/archive/20260112/202601121920.S7fOeWjT-lkp@intel.com/config)
compiler: or1k-linux-gcc (GCC) 15.1.0
dtschema version: 2025.12
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260112/202601121920.S7fOeWjT-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/r/202601121920.S7fOeWjT-lkp@intel.com/
dtcheck warnings: (new ones prefixed by >>)
>> Documentation/devicetree/bindings/watchdog/andestech,ae350-wdt.yaml: andestech,clock-source: missing type definition
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 11+ messages in threadend of thread, other threads:[~2026-01-12 18:04 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-01-07 14:50 [PATCH 0/3] watchdog: Add support for Andes ATCWDT200 CL Wang 2026-01-07 14:50 ` [PATCH 1/3] dt-bindings: " CL Wang 2026-01-07 15:44 ` Krzysztof Kozlowski 2026-01-09 9:35 ` CL Wang 2026-01-07 16:23 ` Rob Herring (Arm) 2026-01-12 6:59 ` CL Wang 2026-01-07 14:50 ` [PATCH 2/3] watchdog: atcwdt200: Add driver " CL Wang 2026-01-07 15:46 ` Krzysztof Kozlowski 2026-01-12 7:05 ` CL Wang 2026-01-07 14:50 ` [PATCH 3/3] MAINTAINERS: Add entry " CL Wang -- strict thread matches above, loose matches on Subject: below -- 2026-01-12 18:04 [PATCH 1/3] dt-bindings: watchdog: Add support " kernel test robot
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.