11// SPDX-License-Identifier: GPL-2.0-or-later
22/*
33 * Copyright (c) 2016 Yang Ling <gnaygnil@gmail.com>
4+ * Copyright (C) 2025 Binbin Zhou <zhoubinbin@loongson.cn>
45 */
56
67#include <linux/clk.h>
1011#include <linux/platform_device.h>
1112#include <linux/watchdog.h>
1213
13- /* Loongson 1 Watchdog Register Definitions */
14+ /* Loongson Watchdog Register Definitions */
1415#define WDT_EN 0x0
15- #define WDT_TIMER 0x4
16- #define WDT_SET 0x8
1716
1817#define DEFAULT_HEARTBEAT 30
1918
@@ -27,18 +26,37 @@ module_param(heartbeat, uint, 0);
2726MODULE_PARM_DESC (heartbeat , "Watchdog heartbeat in seconds. (default="
2827 __MODULE_STRING (DEFAULT_HEARTBEAT ) ")" );
2928
29+ struct ls1x_wdt_pdata {
30+ u32 timer_offset ;
31+ u32 set_offset ;
32+ u32 wdt_en_bit ;
33+ };
34+
35+ static const struct ls1x_wdt_pdata ls1b_wdt_pdata = {
36+ .timer_offset = 0x4 ,
37+ .set_offset = 0x8 ,
38+ .wdt_en_bit = BIT (0 ),
39+ };
40+
41+ static const struct ls1x_wdt_pdata ls2k0300_wdt_pdata = {
42+ .timer_offset = 0x8 ,
43+ .set_offset = 0x4 ,
44+ .wdt_en_bit = BIT (1 ),
45+ };
46+
3047struct ls1x_wdt_drvdata {
3148 void __iomem * base ;
3249 struct clk * clk ;
3350 unsigned long clk_rate ;
3451 struct watchdog_device wdt ;
52+ const struct ls1x_wdt_pdata * pdata ;
3553};
3654
3755static int ls1x_wdt_ping (struct watchdog_device * wdt_dev )
3856{
3957 struct ls1x_wdt_drvdata * drvdata = watchdog_get_drvdata (wdt_dev );
4058
41- writel (0x1 , drvdata -> base + WDT_SET );
59+ writel (0x1 , drvdata -> base + drvdata -> pdata -> set_offset );
4260
4361 return 0 ;
4462}
@@ -53,7 +71,7 @@ static int ls1x_wdt_set_timeout(struct watchdog_device *wdt_dev,
5371 wdt_dev -> timeout = timeout ;
5472
5573 counts = drvdata -> clk_rate * min (timeout , max_hw_heartbeat );
56- writel (counts , drvdata -> base + WDT_TIMER );
74+ writel (counts , drvdata -> base + drvdata -> pdata -> timer_offset );
5775
5876 return 0 ;
5977}
@@ -62,16 +80,18 @@ static int ls1x_wdt_start(struct watchdog_device *wdt_dev)
6280{
6381 struct ls1x_wdt_drvdata * drvdata = watchdog_get_drvdata (wdt_dev );
6482
65- writel (0x1 , drvdata -> base + WDT_EN );
83+ writel (drvdata -> pdata -> wdt_en_bit , drvdata -> base + WDT_EN );
6684
6785 return 0 ;
6886}
6987
7088static int ls1x_wdt_stop (struct watchdog_device * wdt_dev )
7189{
7290 struct ls1x_wdt_drvdata * drvdata = watchdog_get_drvdata (wdt_dev );
91+ u32 val = readl (drvdata -> base + WDT_EN );
7392
74- writel (0x0 , drvdata -> base + WDT_EN );
93+ val &= ~(drvdata -> pdata -> wdt_en_bit );
94+ writel (val , drvdata -> base + WDT_EN );
7595
7696 return 0 ;
7797}
@@ -81,9 +101,9 @@ static int ls1x_wdt_restart(struct watchdog_device *wdt_dev,
81101{
82102 struct ls1x_wdt_drvdata * drvdata = watchdog_get_drvdata (wdt_dev );
83103
84- writel (0x1 , drvdata -> base + WDT_EN );
85- writel (0x1 , drvdata -> base + WDT_TIMER );
86- writel (0x1 , drvdata -> base + WDT_SET );
104+ writel (drvdata -> pdata -> wdt_en_bit , drvdata -> base + WDT_EN );
105+ writel (0x1 , drvdata -> base + drvdata -> pdata -> timer_offset );
106+ writel (0x1 , drvdata -> base + drvdata -> pdata -> set_offset );
87107
88108 return 0 ;
89109}
@@ -114,6 +134,8 @@ static int ls1x_wdt_probe(struct platform_device *pdev)
114134 return - ENOMEM ;
115135 platform_set_drvdata (pdev , drvdata );
116136
137+ drvdata -> pdata = of_device_get_match_data (dev );
138+
117139 drvdata -> base = devm_platform_ioremap_resource (pdev , 0 );
118140 if (IS_ERR (drvdata -> base ))
119141 return PTR_ERR (drvdata -> base );
@@ -142,9 +164,32 @@ static int ls1x_wdt_probe(struct platform_device *pdev)
142164 return devm_watchdog_register_device (dev , & drvdata -> wdt );
143165}
144166
167+ static int ls1x_wdt_resume (struct device * dev )
168+ {
169+ struct ls1x_wdt_drvdata * data = dev_get_drvdata (dev );
170+
171+ if (watchdog_active (& data -> wdt ))
172+ ls1x_wdt_start (& data -> wdt );
173+
174+ return 0 ;
175+ }
176+
177+ static int ls1x_wdt_suspend (struct device * dev )
178+ {
179+ struct ls1x_wdt_drvdata * data = dev_get_drvdata (dev );
180+
181+ if (watchdog_active (& data -> wdt ))
182+ ls1x_wdt_stop (& data -> wdt );
183+
184+ return 0 ;
185+ }
186+
187+ static DEFINE_SIMPLE_DEV_PM_OPS (ls1x_wdt_pm_ops , ls1x_wdt_suspend , ls1x_wdt_resume ) ;
188+
145189static const struct of_device_id ls1x_wdt_dt_ids [] = {
146- { .compatible = "loongson,ls1b-wdt" , },
147- { .compatible = "loongson,ls1c-wdt" , },
190+ { .compatible = "loongson,ls1b-wdt" , .data = & ls1b_wdt_pdata },
191+ { .compatible = "loongson,ls1c-wdt" , .data = & ls1b_wdt_pdata },
192+ { .compatible = "loongson,ls2k0300-wdt" , .data = & ls2k0300_wdt_pdata },
148193 { /* sentinel */ }
149194};
150195MODULE_DEVICE_TABLE (of , ls1x_wdt_dt_ids );
@@ -154,11 +199,13 @@ static struct platform_driver ls1x_wdt_driver = {
154199 .driver = {
155200 .name = "ls1x-wdt" ,
156201 .of_match_table = ls1x_wdt_dt_ids ,
202+ .pm = pm_ptr (& ls1x_wdt_pm_ops ),
157203 },
158204};
159205
160206module_platform_driver (ls1x_wdt_driver );
161207
162208MODULE_AUTHOR ("Yang Ling <gnaygnil@gmail.com>" );
163- MODULE_DESCRIPTION ("Loongson1 Watchdog Driver" );
209+ MODULE_AUTHOR ("Binbin Zhou <zhoubinbin@loongson.cn>" );
210+ MODULE_DESCRIPTION ("Loongson Watchdog Driver" );
164211MODULE_LICENSE ("GPL" );
0 commit comments