]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
watchdog: loongson1: Add Loongson-2k0300 watchdog support
authorBinbin Zhou <zhoubinbin@loongson.cn>
Fri, 7 Nov 2025 06:01:51 +0000 (14:01 +0800)
committerWim Van Sebroeck <wim@linux-watchdog.org>
Sat, 15 Nov 2025 14:28:10 +0000 (15:28 +0100)
According to the manual, the Loongson-2K0300 watchdog is similar to the
Loongson-1, except for some register offsets and inconsistent register
bit definitions. Separate definitions via driver_data suffice.

Co-developed-by: Xiaochuang Mao <maoxiaochuan@loongson.cn>
Signed-off-by: Xiaochuang Mao <maoxiaochuan@loongson.cn>
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
Reviewed-by: Huacai Chen <chenhuacai@loongson.cn>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
drivers/watchdog/Kconfig
drivers/watchdog/loongson1_wdt.c

index 792d0d831336dd0a59b137229dc112b9deafd26b..d3b9df7d466b0b7215ee87b3040811d44ee53d2a 100644 (file)
@@ -1984,10 +1984,10 @@ config LANTIQ_WDT
 
 config LOONGSON1_WDT
        tristate "Loongson1 SoC hardware watchdog"
-       depends on MACH_LOONGSON32 || COMPILE_TEST
+       depends on MACH_LOONGSON32 || MACH_LOONGSON64 || COMPILE_TEST
        select WATCHDOG_CORE
        help
-         Hardware driver for the Loongson1 SoC Watchdog Timer.
+         Hardware driver for the Loongson family Watchdog Timer.
 
 config RALINK_WDT
        tristate "Ralink SoC watchdog"
index 255198cbf5bf70c90fe76198f54c988de706e26c..2417519717cc487b0c330c4659cca4b6a6fbd07f 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Copyright (c) 2016 Yang Ling <gnaygnil@gmail.com>
+ * Copyright (C) 2025 Binbin Zhou <zhoubinbin@loongson.cn>
  */
 
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/watchdog.h>
 
-/* Loongson Watchdog Register Definitions */
+/* Loongson Watchdog Register Definitions */
 #define WDT_EN                 0x0
-#define WDT_TIMER              0x4
-#define WDT_SET                        0x8
 
 #define DEFAULT_HEARTBEAT      30
 
@@ -27,18 +26,37 @@ module_param(heartbeat, uint, 0);
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default="
                 __MODULE_STRING(DEFAULT_HEARTBEAT) ")");
 
+struct ls1x_wdt_pdata {
+       u32 timer_offset;
+       u32 set_offset;
+       u32 wdt_en_bit;
+};
+
+static const struct ls1x_wdt_pdata ls1b_wdt_pdata = {
+       .timer_offset = 0x4,
+       .set_offset = 0x8,
+       .wdt_en_bit = BIT(0),
+};
+
+static const struct ls1x_wdt_pdata ls2k0300_wdt_pdata = {
+       .timer_offset = 0x8,
+       .set_offset = 0x4,
+       .wdt_en_bit = BIT(1),
+};
+
 struct ls1x_wdt_drvdata {
        void __iomem *base;
        struct clk *clk;
        unsigned long clk_rate;
        struct watchdog_device wdt;
+       const struct ls1x_wdt_pdata *pdata;
 };
 
 static int ls1x_wdt_ping(struct watchdog_device *wdt_dev)
 {
        struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
 
-       writel(0x1, drvdata->base + WDT_SET);
+       writel(0x1, drvdata->base + drvdata->pdata->set_offset);
 
        return 0;
 }
@@ -53,7 +71,7 @@ static int ls1x_wdt_set_timeout(struct watchdog_device *wdt_dev,
        wdt_dev->timeout = timeout;
 
        counts = drvdata->clk_rate * min(timeout, max_hw_heartbeat);
-       writel(counts, drvdata->base + WDT_TIMER);
+       writel(counts, drvdata->base + drvdata->pdata->timer_offset);
 
        return 0;
 }
@@ -62,7 +80,7 @@ static int ls1x_wdt_start(struct watchdog_device *wdt_dev)
 {
        struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
 
-       writel(0x1, drvdata->base + WDT_EN);
+       writel(drvdata->pdata->wdt_en_bit, drvdata->base + WDT_EN);
 
        return 0;
 }
@@ -70,8 +88,10 @@ static int ls1x_wdt_start(struct watchdog_device *wdt_dev)
 static int ls1x_wdt_stop(struct watchdog_device *wdt_dev)
 {
        struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
+       u32 val = readl(drvdata->base + WDT_EN);
 
-       writel(0x0, drvdata->base + WDT_EN);
+       val &= ~(drvdata->pdata->wdt_en_bit);
+       writel(val, drvdata->base + WDT_EN);
 
        return 0;
 }
@@ -81,9 +101,9 @@ static int ls1x_wdt_restart(struct watchdog_device *wdt_dev,
 {
        struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
 
-       writel(0x1, drvdata->base + WDT_EN);
-       writel(0x1, drvdata->base + WDT_TIMER);
-       writel(0x1, drvdata->base + WDT_SET);
+       writel(drvdata->pdata->wdt_en_bit, drvdata->base + WDT_EN);
+       writel(0x1, drvdata->base + drvdata->pdata->timer_offset);
+       writel(0x1, drvdata->base + drvdata->pdata->set_offset);
 
        return 0;
 }
@@ -114,6 +134,8 @@ static int ls1x_wdt_probe(struct platform_device *pdev)
                return -ENOMEM;
        platform_set_drvdata(pdev, drvdata);
 
+       drvdata->pdata = of_device_get_match_data(dev);
+
        drvdata->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(drvdata->base))
                return PTR_ERR(drvdata->base);
@@ -142,9 +164,32 @@ static int ls1x_wdt_probe(struct platform_device *pdev)
        return devm_watchdog_register_device(dev, &drvdata->wdt);
 }
 
+static int ls1x_wdt_resume(struct device *dev)
+{
+       struct ls1x_wdt_drvdata *data = dev_get_drvdata(dev);
+
+       if (watchdog_active(&data->wdt))
+               ls1x_wdt_start(&data->wdt);
+
+       return 0;
+}
+
+static int ls1x_wdt_suspend(struct device *dev)
+{
+       struct ls1x_wdt_drvdata *data = dev_get_drvdata(dev);
+
+       if (watchdog_active(&data->wdt))
+               ls1x_wdt_stop(&data->wdt);
+
+       return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(ls1x_wdt_pm_ops, ls1x_wdt_suspend, ls1x_wdt_resume);
+
 static const struct of_device_id ls1x_wdt_dt_ids[] = {
-       { .compatible = "loongson,ls1b-wdt", },
-       { .compatible = "loongson,ls1c-wdt", },
+       { .compatible = "loongson,ls1b-wdt", .data = &ls1b_wdt_pdata },
+       { .compatible = "loongson,ls1c-wdt", .data = &ls1b_wdt_pdata },
+       { .compatible = "loongson,ls2k0300-wdt", .data = &ls2k0300_wdt_pdata },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, ls1x_wdt_dt_ids);
@@ -154,11 +199,13 @@ static struct platform_driver ls1x_wdt_driver = {
        .driver = {
                .name = "ls1x-wdt",
                .of_match_table = ls1x_wdt_dt_ids,
+               .pm = pm_ptr(&ls1x_wdt_pm_ops),
        },
 };
 
 module_platform_driver(ls1x_wdt_driver);
 
 MODULE_AUTHOR("Yang Ling <gnaygnil@gmail.com>");
-MODULE_DESCRIPTION("Loongson1 Watchdog Driver");
+MODULE_AUTHOR("Binbin Zhou <zhoubinbin@loongson.cn>");
+MODULE_DESCRIPTION("Loongson Watchdog Driver");
 MODULE_LICENSE("GPL");