1 // SPDX-License-Identifier: GPL-2.0+
3 * Realtek RTD129x watchdog
5 * Copyright (c) 2017 Andreas Färber
9 #include <linux/bitops.h>
10 #include <linux/clk.h>
13 #include <linux/of_address.h>
14 #include <linux/platform_device.h>
15 #include <linux/watchdog.h>
17 #define RTD119X_TCWCR 0x0
18 #define RTD119X_TCWTR 0x4
19 #define RTD119X_TCWOV 0xc
21 #define RTD119X_TCWCR_WDEN_DISABLED 0xa5
22 #define RTD119X_TCWCR_WDEN_ENABLED 0xff
23 #define RTD119X_TCWCR_WDEN_MASK 0xff
25 #define RTD119X_TCWTR_WDCLR BIT(0)
27 struct rtd119x_watchdog_device
{
28 struct watchdog_device wdt_dev
;
33 static int rtd119x_wdt_start(struct watchdog_device
*wdev
)
35 struct rtd119x_watchdog_device
*data
= watchdog_get_drvdata(wdev
);
38 val
= readl_relaxed(data
->base
+ RTD119X_TCWCR
);
39 val
&= ~RTD119X_TCWCR_WDEN_MASK
;
40 val
|= RTD119X_TCWCR_WDEN_ENABLED
;
41 writel(val
, data
->base
+ RTD119X_TCWCR
);
46 static int rtd119x_wdt_stop(struct watchdog_device
*wdev
)
48 struct rtd119x_watchdog_device
*data
= watchdog_get_drvdata(wdev
);
51 val
= readl_relaxed(data
->base
+ RTD119X_TCWCR
);
52 val
&= ~RTD119X_TCWCR_WDEN_MASK
;
53 val
|= RTD119X_TCWCR_WDEN_DISABLED
;
54 writel(val
, data
->base
+ RTD119X_TCWCR
);
59 static int rtd119x_wdt_ping(struct watchdog_device
*wdev
)
61 struct rtd119x_watchdog_device
*data
= watchdog_get_drvdata(wdev
);
63 writel_relaxed(RTD119X_TCWTR_WDCLR
, data
->base
+ RTD119X_TCWTR
);
65 return rtd119x_wdt_start(wdev
);
68 static int rtd119x_wdt_set_timeout(struct watchdog_device
*wdev
, unsigned int val
)
70 struct rtd119x_watchdog_device
*data
= watchdog_get_drvdata(wdev
);
72 writel(val
* clk_get_rate(data
->clk
), data
->base
+ RTD119X_TCWOV
);
74 data
->wdt_dev
.timeout
= val
;
79 static const struct watchdog_ops rtd119x_wdt_ops
= {
81 .start
= rtd119x_wdt_start
,
82 .stop
= rtd119x_wdt_stop
,
83 .ping
= rtd119x_wdt_ping
,
84 .set_timeout
= rtd119x_wdt_set_timeout
,
87 static const struct watchdog_info rtd119x_wdt_info
= {
88 .identity
= "rtd119x-wdt",
92 static const struct of_device_id rtd119x_wdt_dt_ids
[] = {
93 { .compatible
= "realtek,rtd1295-watchdog" },
97 static int rtd119x_wdt_probe(struct platform_device
*pdev
)
99 struct device
*dev
= &pdev
->dev
;
100 struct rtd119x_watchdog_device
*data
;
102 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
106 data
->base
= devm_platform_ioremap_resource(pdev
, 0);
107 if (IS_ERR(data
->base
))
108 return PTR_ERR(data
->base
);
110 data
->clk
= devm_clk_get_enabled(dev
, NULL
);
111 if (IS_ERR(data
->clk
))
112 return PTR_ERR(data
->clk
);
114 data
->wdt_dev
.info
= &rtd119x_wdt_info
;
115 data
->wdt_dev
.ops
= &rtd119x_wdt_ops
;
116 data
->wdt_dev
.timeout
= 120;
117 data
->wdt_dev
.max_timeout
= 0xffffffff / clk_get_rate(data
->clk
);
118 data
->wdt_dev
.min_timeout
= 1;
119 data
->wdt_dev
.parent
= dev
;
121 watchdog_stop_on_reboot(&data
->wdt_dev
);
122 watchdog_set_drvdata(&data
->wdt_dev
, data
);
123 platform_set_drvdata(pdev
, data
);
125 writel_relaxed(RTD119X_TCWTR_WDCLR
, data
->base
+ RTD119X_TCWTR
);
126 rtd119x_wdt_set_timeout(&data
->wdt_dev
, data
->wdt_dev
.timeout
);
127 rtd119x_wdt_stop(&data
->wdt_dev
);
129 return devm_watchdog_register_device(dev
, &data
->wdt_dev
);
132 static struct platform_driver rtd119x_wdt_driver
= {
133 .probe
= rtd119x_wdt_probe
,
135 .name
= "rtd1295-watchdog",
136 .of_match_table
= rtd119x_wdt_dt_ids
,
139 builtin_platform_driver(rtd119x_wdt_driver
);