From: Binbin Zhou Date: Fri, 7 Nov 2025 06:01:51 +0000 (+0800) Subject: watchdog: loongson1: Add Loongson-2k0300 watchdog support X-Git-Tag: v6.19-rc1~80^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e0c50cddbd942338cbd6029ddbbcef4268a30718;p=thirdparty%2Fkernel%2Flinux.git watchdog: loongson1: Add Loongson-2k0300 watchdog support 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 Signed-off-by: Xiaochuang Mao Signed-off-by: Binbin Zhou Reviewed-by: Huacai Chen Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 792d0d831336d..d3b9df7d466b0 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -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" diff --git a/drivers/watchdog/loongson1_wdt.c b/drivers/watchdog/loongson1_wdt.c index 255198cbf5bf7..2417519717cc4 100644 --- a/drivers/watchdog/loongson1_wdt.c +++ b/drivers/watchdog/loongson1_wdt.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2016 Yang Ling + * Copyright (C) 2025 Binbin Zhou */ #include @@ -10,10 +11,8 @@ #include #include -/* Loongson 1 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 "); -MODULE_DESCRIPTION("Loongson1 Watchdog Driver"); +MODULE_AUTHOR("Binbin Zhou "); +MODULE_DESCRIPTION("Loongson Watchdog Driver"); MODULE_LICENSE("GPL");