1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2024 ROHM Semiconductors
5 * ROHM BD96801 watchdog driver
8 #include <linux/bitfield.h>
9 #include <linux/interrupt.h>
10 #include <linux/kernel.h>
11 #include <linux/mfd/rohm-bd96801.h>
12 #include <linux/mfd/rohm-generic.h>
13 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/reboot.h>
17 #include <linux/regmap.h>
18 #include <linux/watchdog.h>
21 module_param(nowayout
, bool, 0);
22 MODULE_PARM_DESC(nowayout
,
23 "Watchdog cannot be stopped once started (default=\"false\")");
25 #define BD96801_WD_TMO_SHORT_MASK 0x70
26 #define BD96801_WD_RATIO_MASK 0x3
27 #define BD96801_WD_TYPE_MASK 0x4
28 #define BD96801_WD_TYPE_SLOW 0x4
29 #define BD96801_WD_TYPE_WIN 0x0
31 #define BD96801_WD_EN_MASK 0x3
32 #define BD96801_WD_IF_EN 0x1
33 #define BD96801_WD_QA_EN 0x2
34 #define BD96801_WD_DISABLE 0x0
36 #define BD96801_WD_ASSERT_MASK 0x8
37 #define BD96801_WD_ASSERT_RST 0x8
38 #define BD96801_WD_ASSERT_IRQ 0x0
40 #define BD96801_WD_FEED_MASK 0x1
41 #define BD96801_WD_FEED 0x1
45 #define FASTNG_MAX_US (100 * FASTNG_MIN << 7)
46 #define SLOWNG_MAX_US (16 * FASTNG_MAX_US)
48 #define BD96801_WDT_DEFAULT_MARGIN_MS 1843
50 #define DEFAULT_TIMEOUT 30
53 * BD96801 WDG supports window mode so the TMO consists of SHORT and LONG
54 * timeout values. SHORT time is meaningful only in window mode where feeding
55 * period shorter than SHORT would be an error. LONG time is used to detect if
56 * feeding is not occurring within given time limit (SoC SW hangs). The LONG
57 * timeout time is a multiple of (2, 4, 8 or 16 times) the SHORT timeout.
62 struct regmap
*regmap
;
63 struct watchdog_device wdt
;
66 static int bd96801_wdt_ping(struct watchdog_device
*wdt
)
68 struct wdtbd96801
*w
= watchdog_get_drvdata(wdt
);
70 return regmap_update_bits(w
->regmap
, BD96801_REG_WD_FEED
,
71 BD96801_WD_FEED_MASK
, BD96801_WD_FEED
);
74 static int bd96801_wdt_start(struct watchdog_device
*wdt
)
76 struct wdtbd96801
*w
= watchdog_get_drvdata(wdt
);
78 return regmap_update_bits(w
->regmap
, BD96801_REG_WD_CONF
,
79 BD96801_WD_EN_MASK
, BD96801_WD_IF_EN
);
82 static int bd96801_wdt_stop(struct watchdog_device
*wdt
)
84 struct wdtbd96801
*w
= watchdog_get_drvdata(wdt
);
86 return regmap_update_bits(w
->regmap
, BD96801_REG_WD_CONF
,
87 BD96801_WD_EN_MASK
, BD96801_WD_DISABLE
);
90 static const struct watchdog_info bd96801_wdt_info
= {
91 .options
= WDIOF_MAGICCLOSE
| WDIOF_KEEPALIVEPING
|
93 .identity
= "BD96801 Watchdog",
96 static const struct watchdog_ops bd96801_wdt_ops
= {
97 .start
= bd96801_wdt_start
,
98 .stop
= bd96801_wdt_stop
,
99 .ping
= bd96801_wdt_ping
,
102 static int find_closest_fast(unsigned int target
, int *sel
, unsigned int *val
)
104 unsigned int window
= FASTNG_MIN
;
107 for (i
= 0; i
< 8 && window
< target
; i
++)
119 static int find_closest_slow_by_fast(unsigned int fast_val
, unsigned int *target
,
122 static const int multipliers
[] = {2, 4, 8, 16};
125 for (sel
= 0; sel
< ARRAY_SIZE(multipliers
) &&
126 multipliers
[sel
] * fast_val
< *target
; sel
++)
129 if (sel
== ARRAY_SIZE(multipliers
))
133 *target
= multipliers
[sel
] * fast_val
;
138 static int find_closest_slow(unsigned int *target
, int *slow_sel
, int *fast_sel
)
140 static const int multipliers
[] = {2, 4, 8, 16};
141 unsigned int window
= FASTNG_MIN
;
142 unsigned int val
= 0;
145 for (i
= 0; i
< 8; i
++) {
146 for (j
= 0; j
< ARRAY_SIZE(multipliers
); j
++) {
149 slow
= window
* multipliers
[j
];
150 if (slow
>= *target
&& (!val
|| slow
< val
)) {
166 static int bd96801_set_wdt_mode(struct wdtbd96801
*w
, unsigned int hw_margin
,
167 unsigned int hw_margin_min
)
169 int fastng
, slowng
, type
, ret
, reg
, mask
;
170 struct device
*dev
= w
->dev
;
173 if (hw_margin_min
* 1000 > FASTNG_MAX_US
) {
174 dev_err(dev
, "Unsupported fast timeout %u uS [max %u]\n",
175 hw_margin_min
* 1000, FASTNG_MAX_US
);
180 if (hw_margin
* 1000 > SLOWNG_MAX_US
) {
181 dev_err(dev
, "Unsupported slow timeout %u uS [max %u]\n",
182 hw_margin
* 1000, SLOWNG_MAX_US
);
188 * Convert to 100uS to guarantee reasonable timeouts fit in
189 * 32bit maintaining also a decent accuracy.
197 type
= BD96801_WD_TYPE_WIN
;
198 dev_dbg(dev
, "Setting type WINDOW 0x%x\n", type
);
199 ret
= find_closest_fast(hw_margin_min
, &fastng
, &min
);
203 ret
= find_closest_slow_by_fast(min
, &hw_margin
, &slowng
);
206 "can't support slow timeout %u uS using fast %u uS. [max slow %u uS]\n",
207 hw_margin
* 100, min
* 100, min
* 100 * 16);
211 w
->wdt
.min_hw_heartbeat_ms
= min
/ 10;
213 type
= BD96801_WD_TYPE_SLOW
;
214 dev_dbg(dev
, "Setting type SLOW 0x%x\n", type
);
215 ret
= find_closest_slow(&hw_margin
, &slowng
, &fastng
);
220 w
->wdt
.max_hw_heartbeat_ms
= hw_margin
/ 10;
222 fastng
= FIELD_PREP(BD96801_WD_TMO_SHORT_MASK
, fastng
);
224 reg
= slowng
| fastng
;
225 mask
= BD96801_WD_RATIO_MASK
| BD96801_WD_TMO_SHORT_MASK
;
226 ret
= regmap_update_bits(w
->regmap
, BD96801_REG_WD_TMO
,
231 ret
= regmap_update_bits(w
->regmap
, BD96801_REG_WD_CONF
,
232 BD96801_WD_TYPE_MASK
, type
);
237 static int bd96801_set_heartbeat_from_hw(struct wdtbd96801
*w
,
238 unsigned int conf_reg
)
241 unsigned int val
, sel
, fast
;
244 * The BD96801 supports a somewhat peculiar QA-mode, which we do not
245 * support in this driver. If the QA-mode is enabled then we just
248 if ((conf_reg
& BD96801_WD_EN_MASK
) != BD96801_WD_IF_EN
) {
249 dev_err(w
->dev
, "watchdog set to Q&A mode - exiting\n");
253 ret
= regmap_read(w
->regmap
, BD96801_REG_WD_TMO
, &val
);
257 sel
= FIELD_GET(BD96801_WD_TMO_SHORT_MASK
, val
);
258 fast
= FASTNG_MIN
<< sel
;
260 sel
= (val
& BD96801_WD_RATIO_MASK
) + 1;
261 w
->wdt
.max_hw_heartbeat_ms
= (fast
<< sel
) / USEC_PER_MSEC
;
263 if ((conf_reg
& BD96801_WD_TYPE_MASK
) == BD96801_WD_TYPE_WIN
)
264 w
->wdt
.min_hw_heartbeat_ms
= fast
/ USEC_PER_MSEC
;
269 static int init_wdg_hw(struct wdtbd96801
*w
)
273 u32 hw_margin_max
= BD96801_WDT_DEFAULT_MARGIN_MS
, hw_margin_min
= 0;
275 count
= device_property_count_u32(w
->dev
->parent
, "rohm,hw-timeout-ms");
276 if (count
< 0 && count
!= -EINVAL
)
280 if (count
> ARRAY_SIZE(hw_margin
))
283 ret
= device_property_read_u32_array(w
->dev
->parent
,
284 "rohm,hw-timeout-ms",
285 &hw_margin
[0], count
);
290 hw_margin_max
= hw_margin
[0];
293 if (hw_margin
[1] > hw_margin
[0]) {
294 hw_margin_max
= hw_margin
[1];
295 hw_margin_min
= hw_margin
[0];
297 hw_margin_max
= hw_margin
[0];
298 hw_margin_min
= hw_margin
[1];
303 ret
= bd96801_set_wdt_mode(w
, hw_margin_max
, hw_margin_min
);
307 ret
= device_property_match_string(w
->dev
->parent
, "rohm,wdg-action",
310 ret
= regmap_update_bits(w
->regmap
, BD96801_REG_WD_CONF
,
311 BD96801_WD_ASSERT_MASK
,
312 BD96801_WD_ASSERT_RST
);
316 ret
= device_property_match_string(w
->dev
->parent
, "rohm,wdg-action",
319 ret
= regmap_update_bits(w
->regmap
, BD96801_REG_WD_CONF
,
320 BD96801_WD_ASSERT_MASK
,
321 BD96801_WD_ASSERT_IRQ
);
328 static irqreturn_t
bd96801_irq_hnd(int irq
, void *data
)
335 static int bd96801_wdt_probe(struct platform_device
*pdev
)
337 struct wdtbd96801
*w
;
341 w
= devm_kzalloc(&pdev
->dev
, sizeof(*w
), GFP_KERNEL
);
345 w
->regmap
= dev_get_regmap(pdev
->dev
.parent
, NULL
);
348 w
->wdt
.info
= &bd96801_wdt_info
;
349 w
->wdt
.ops
= &bd96801_wdt_ops
;
350 w
->wdt
.parent
= pdev
->dev
.parent
;
351 w
->wdt
.timeout
= DEFAULT_TIMEOUT
;
352 watchdog_set_drvdata(&w
->wdt
, w
);
354 ret
= regmap_read(w
->regmap
, BD96801_REG_WD_CONF
, &val
);
356 return dev_err_probe(&pdev
->dev
, ret
,
357 "Failed to get the watchdog state\n");
360 * If the WDG is already enabled we assume it is configured by boot.
361 * In this case we just update the hw-timeout based on values set to
362 * the timeout / mode registers and leave the hardware configs
365 if ((val
& BD96801_WD_EN_MASK
) != BD96801_WD_DISABLE
) {
366 dev_dbg(&pdev
->dev
, "watchdog was running during probe\n");
367 ret
= bd96801_set_heartbeat_from_hw(w
, val
);
371 set_bit(WDOG_HW_RUNNING
, &w
->wdt
.status
);
373 /* If WDG is not running so we will initializate it */
374 ret
= init_wdg_hw(w
);
379 dev_dbg(w
->dev
, "heartbeat set to %u - %u\n",
380 w
->wdt
.min_hw_heartbeat_ms
, w
->wdt
.max_hw_heartbeat_ms
);
382 watchdog_init_timeout(&w
->wdt
, 0, pdev
->dev
.parent
);
383 watchdog_set_nowayout(&w
->wdt
, nowayout
);
384 watchdog_stop_on_reboot(&w
->wdt
);
386 irq
= platform_get_irq_byname(pdev
, "bd96801-wdg");
388 ret
= devm_request_threaded_irq(&pdev
->dev
, irq
, NULL
,
390 IRQF_ONESHOT
, "bd96801-wdg",
393 return dev_err_probe(&pdev
->dev
, ret
,
394 "Failed to register IRQ\n");
397 return devm_watchdog_register_device(&pdev
->dev
, &w
->wdt
);
400 static const struct platform_device_id bd96801_wdt_id
[] = {
404 MODULE_DEVICE_TABLE(platform
, bd96801_wdt_id
);
406 static struct platform_driver bd96801_wdt
= {
408 .name
= "bd96801-wdt"
410 .probe
= bd96801_wdt_probe
,
411 .id_table
= bd96801_wdt_id
,
413 module_platform_driver(bd96801_wdt
);
415 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
416 MODULE_DESCRIPTION("BD96801 watchdog driver");
417 MODULE_LICENSE("GPL");