1 // SPDX-License-Identifier: GPL-2.0
3 * Renesas RZ/N1 Watchdog timer.
4 * This is a 12-bit timer driver from a (62.5/16384) MHz clock. It can't even
7 * Copyright 2018 Renesas Electronics Europe Ltd.
9 * Derived from Ralink RT288x watchdog timer.
12 #include <linux/clk.h>
13 #include <linux/interrupt.h>
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/of_address.h>
17 #include <linux/of_irq.h>
18 #include <linux/platform_device.h>
19 #include <linux/reboot.h>
20 #include <linux/watchdog.h>
22 #define DEFAULT_TIMEOUT 60
24 #define RZN1_WDT_RETRIGGER 0x0
25 #define RZN1_WDT_RETRIGGER_RELOAD_VAL 0
26 #define RZN1_WDT_RETRIGGER_RELOAD_VAL_MASK 0xfff
27 #define RZN1_WDT_RETRIGGER_PRESCALE BIT(12)
28 #define RZN1_WDT_RETRIGGER_ENABLE BIT(13)
29 #define RZN1_WDT_RETRIGGER_WDSI (0x2 << 14)
31 #define RZN1_WDT_PRESCALER 16384
32 #define RZN1_WDT_MAX 4095
34 struct rzn1_watchdog
{
35 struct watchdog_device wdtdev
;
37 unsigned long clk_rate_khz
;
40 static inline uint32_t max_heart_beat_ms(unsigned long clk_rate_khz
)
42 return (RZN1_WDT_MAX
* RZN1_WDT_PRESCALER
) / clk_rate_khz
;
45 static inline uint32_t compute_reload_value(uint32_t tick_ms
,
46 unsigned long clk_rate_khz
)
48 return (tick_ms
* clk_rate_khz
) / RZN1_WDT_PRESCALER
;
51 static int rzn1_wdt_ping(struct watchdog_device
*w
)
53 struct rzn1_watchdog
*wdt
= watchdog_get_drvdata(w
);
55 /* Any value retrigggers the watchdog */
56 writel(0, wdt
->base
+ RZN1_WDT_RETRIGGER
);
61 static int rzn1_wdt_start(struct watchdog_device
*w
)
63 struct rzn1_watchdog
*wdt
= watchdog_get_drvdata(w
);
67 * The hardware allows you to write to this reg only once.
68 * Since this includes the reload value, there is no way to change the
69 * timeout once started. Also note that the WDT clock is half the bus
70 * fabric clock rate, so if the bus fabric clock rate is changed after
71 * the WDT is started, the WDT interval will be wrong.
73 val
= RZN1_WDT_RETRIGGER_WDSI
;
74 val
|= RZN1_WDT_RETRIGGER_ENABLE
;
75 val
|= RZN1_WDT_RETRIGGER_PRESCALE
;
76 val
|= compute_reload_value(w
->max_hw_heartbeat_ms
, wdt
->clk_rate_khz
);
77 writel(val
, wdt
->base
+ RZN1_WDT_RETRIGGER
);
82 static irqreturn_t
rzn1_wdt_irq(int irq
, void *_wdt
)
84 pr_crit("RZN1 Watchdog. Initiating system reboot\n");
90 static struct watchdog_info rzn1_wdt_info
= {
91 .identity
= "RZ/N1 Watchdog",
92 .options
= WDIOF_MAGICCLOSE
| WDIOF_SETTIMEOUT
| WDIOF_KEEPALIVEPING
,
95 static const struct watchdog_ops rzn1_wdt_ops
= {
97 .start
= rzn1_wdt_start
,
98 .ping
= rzn1_wdt_ping
,
101 static int rzn1_wdt_probe(struct platform_device
*pdev
)
103 struct device
*dev
= &pdev
->dev
;
104 struct rzn1_watchdog
*wdt
;
105 struct device_node
*np
= dev
->of_node
;
107 unsigned long clk_rate
;
111 wdt
= devm_kzalloc(dev
, sizeof(*wdt
), GFP_KERNEL
);
115 wdt
->base
= devm_platform_ioremap_resource(pdev
, 0);
116 if (IS_ERR(wdt
->base
))
117 return PTR_ERR(wdt
->base
);
119 irq
= platform_get_irq(pdev
, 0);
123 ret
= devm_request_irq(dev
, irq
, rzn1_wdt_irq
, 0,
126 dev_err(dev
, "failed to request irq %d\n", irq
);
130 clk
= devm_clk_get_enabled(dev
, NULL
);
132 dev_err(dev
, "failed to get the clock\n");
136 clk_rate
= clk_get_rate(clk
);
138 dev_err(dev
, "failed to get the clock rate\n");
142 wdt
->clk_rate_khz
= clk_rate
/ 1000;
143 wdt
->wdtdev
.info
= &rzn1_wdt_info
;
144 wdt
->wdtdev
.ops
= &rzn1_wdt_ops
;
145 wdt
->wdtdev
.status
= WATCHDOG_NOWAYOUT_INIT_STATUS
;
146 wdt
->wdtdev
.parent
= dev
;
148 * The period of the watchdog cannot be changed once set
149 * and is limited to a very short period.
150 * Configure it for a 1s period once and for all, and
151 * rely on the heart-beat provided by the watchdog core
152 * to make this usable by the user-space.
154 wdt
->wdtdev
.max_hw_heartbeat_ms
= max_heart_beat_ms(wdt
->clk_rate_khz
);
155 if (wdt
->wdtdev
.max_hw_heartbeat_ms
> 1000)
156 wdt
->wdtdev
.max_hw_heartbeat_ms
= 1000;
158 wdt
->wdtdev
.timeout
= DEFAULT_TIMEOUT
;
159 ret
= watchdog_init_timeout(&wdt
->wdtdev
, 0, dev
);
163 watchdog_set_drvdata(&wdt
->wdtdev
, wdt
);
165 return devm_watchdog_register_device(dev
, &wdt
->wdtdev
);
169 static const struct of_device_id rzn1_wdt_match
[] = {
170 { .compatible
= "renesas,rzn1-wdt" },
173 MODULE_DEVICE_TABLE(of
, rzn1_wdt_match
);
175 static struct platform_driver rzn1_wdt_driver
= {
176 .probe
= rzn1_wdt_probe
,
178 .name
= KBUILD_MODNAME
,
179 .of_match_table
= rzn1_wdt_match
,
183 module_platform_driver(rzn1_wdt_driver
);
185 MODULE_DESCRIPTION("Renesas RZ/N1 hardware watchdog");
186 MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
187 MODULE_LICENSE("GPL");