2 * Watchdog driver for Renesas WDT watchdog
4 * Copyright (C) 2015-16 Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
5 * Copyright (C) 2015-16 Renesas Electronics Corporation
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
11 #include <linux/bitops.h>
12 #include <linux/clk.h>
14 #include <linux/kernel.h>
15 #include <linux/module.h>
17 #include <linux/platform_device.h>
18 #include <linux/pm_runtime.h>
19 #include <linux/watchdog.h>
23 #define RWTCSRA_WOVF BIT(4)
24 #define RWTCSRA_WRFLG BIT(5)
25 #define RWTCSRA_TME BIT(7)
27 #define RWDT_DEFAULT_TIMEOUT 60U
29 static const unsigned int clk_divs
[] = { 1, 4, 16, 32, 64, 128, 1024 };
31 static bool nowayout
= WATCHDOG_NOWAYOUT
;
32 module_param(nowayout
, bool, 0);
33 MODULE_PARM_DESC(nowayout
, "Watchdog cannot be stopped once started (default="
34 __MODULE_STRING(WATCHDOG_NOWAYOUT
) ")");
38 struct watchdog_device wdev
;
40 unsigned int clks_per_sec
;
44 static void rwdt_write(struct rwdt_priv
*priv
, u32 val
, unsigned int reg
)
51 writel_relaxed(val
, priv
->base
+ reg
);
54 static int rwdt_init_timeout(struct watchdog_device
*wdev
)
56 struct rwdt_priv
*priv
= watchdog_get_drvdata(wdev
);
58 rwdt_write(priv
, 65536 - wdev
->timeout
* priv
->clks_per_sec
, RWTCNT
);
63 static int rwdt_start(struct watchdog_device
*wdev
)
65 struct rwdt_priv
*priv
= watchdog_get_drvdata(wdev
);
67 clk_prepare_enable(priv
->clk
);
69 rwdt_write(priv
, priv
->cks
, RWTCSRA
);
70 rwdt_init_timeout(wdev
);
72 while (readb_relaxed(priv
->base
+ RWTCSRA
) & RWTCSRA_WRFLG
)
75 rwdt_write(priv
, priv
->cks
| RWTCSRA_TME
, RWTCSRA
);
80 static int rwdt_stop(struct watchdog_device
*wdev
)
82 struct rwdt_priv
*priv
= watchdog_get_drvdata(wdev
);
84 rwdt_write(priv
, priv
->cks
, RWTCSRA
);
85 clk_disable_unprepare(priv
->clk
);
90 static unsigned int rwdt_get_timeleft(struct watchdog_device
*wdev
)
92 struct rwdt_priv
*priv
= watchdog_get_drvdata(wdev
);
93 u16 val
= readw_relaxed(priv
->base
+ RWTCNT
);
95 return DIV_ROUND_CLOSEST(65536 - val
, priv
->clks_per_sec
);
98 static const struct watchdog_info rwdt_ident
= {
99 .options
= WDIOF_MAGICCLOSE
| WDIOF_KEEPALIVEPING
| WDIOF_SETTIMEOUT
,
100 .identity
= "Renesas WDT Watchdog",
103 static const struct watchdog_ops rwdt_ops
= {
104 .owner
= THIS_MODULE
,
107 .ping
= rwdt_init_timeout
,
108 .get_timeleft
= rwdt_get_timeleft
,
111 static int rwdt_probe(struct platform_device
*pdev
)
113 struct rwdt_priv
*priv
;
114 struct resource
*res
;
116 unsigned int clks_per_sec
;
119 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
123 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
124 priv
->base
= devm_ioremap_resource(&pdev
->dev
, res
);
125 if (IS_ERR(priv
->base
))
126 return PTR_ERR(priv
->base
);
128 priv
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
129 if (IS_ERR(priv
->clk
))
130 return PTR_ERR(priv
->clk
);
132 rate
= clk_get_rate(priv
->clk
);
136 for (i
= ARRAY_SIZE(clk_divs
) - 1; i
>= 0; i
--) {
137 clks_per_sec
= DIV_ROUND_UP(rate
, clk_divs
[i
]);
139 priv
->clks_per_sec
= clks_per_sec
;
146 dev_err(&pdev
->dev
, "Can't find suitable clock divider\n");
150 pm_runtime_enable(&pdev
->dev
);
151 pm_runtime_get_sync(&pdev
->dev
);
153 priv
->wdev
.info
= &rwdt_ident
,
154 priv
->wdev
.ops
= &rwdt_ops
,
155 priv
->wdev
.parent
= &pdev
->dev
;
156 priv
->wdev
.min_timeout
= 1;
157 priv
->wdev
.max_timeout
= 65536 / clks_per_sec
;
158 priv
->wdev
.timeout
= min(priv
->wdev
.max_timeout
, RWDT_DEFAULT_TIMEOUT
);
160 platform_set_drvdata(pdev
, priv
);
161 watchdog_set_drvdata(&priv
->wdev
, priv
);
162 watchdog_set_nowayout(&priv
->wdev
, nowayout
);
164 /* This overrides the default timeout only if DT configuration was found */
165 ret
= watchdog_init_timeout(&priv
->wdev
, 0, &pdev
->dev
);
167 dev_warn(&pdev
->dev
, "Specified timeout value invalid, using default\n");
169 ret
= watchdog_register_device(&priv
->wdev
);
171 pm_runtime_put(&pdev
->dev
);
172 pm_runtime_disable(&pdev
->dev
);
179 static int rwdt_remove(struct platform_device
*pdev
)
181 struct rwdt_priv
*priv
= platform_get_drvdata(pdev
);
183 watchdog_unregister_device(&priv
->wdev
);
184 pm_runtime_put(&pdev
->dev
);
185 pm_runtime_disable(&pdev
->dev
);
191 * This driver does also fit for R-Car Gen2 (r8a779[0-4]) WDT. However, for SMP
192 * to work there, one also needs a RESET (RST) driver which does not exist yet
193 * due to HW issues. This needs to be solved before adding compatibles here.
195 static const struct of_device_id rwdt_ids
[] = {
196 { .compatible
= "renesas,rcar-gen3-wdt", },
199 MODULE_DEVICE_TABLE(of
, rwdt_ids
);
201 static struct platform_driver rwdt_driver
= {
203 .name
= "renesas_wdt",
204 .of_match_table
= rwdt_ids
,
207 .remove
= rwdt_remove
,
209 module_platform_driver(rwdt_driver
);
211 MODULE_DESCRIPTION("Renesas WDT Watchdog Driver");
212 MODULE_LICENSE("GPL v2");
213 MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");