1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) STMicroelectronics 2018
3 // Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
5 #include <linux/kernel.h>
6 #include <linux/mfd/stpmic1.h>
7 #include <linux/module.h>
8 #include <linux/platform_device.h>
10 #include <linux/regmap.h>
11 #include <linux/slab.h>
12 #include <linux/watchdog.h>
14 /* WATCHDOG CONTROL REGISTER bit */
15 #define WDT_START BIT(0)
16 #define WDT_PING BIT(1)
17 #define WDT_START_MASK BIT(0)
18 #define WDT_PING_MASK BIT(1)
21 #define PMIC_WDT_MIN_TIMEOUT 1
22 #define PMIC_WDT_MAX_TIMEOUT 256
23 #define PMIC_WDT_DEFAULT_TIMEOUT 30
25 static bool nowayout
= WATCHDOG_NOWAYOUT
;
26 module_param(nowayout
, bool, 0);
27 MODULE_PARM_DESC(nowayout
, "Watchdog cannot be stopped once started (default="
28 __MODULE_STRING(WATCHDOG_NOWAYOUT
) ")");
32 struct watchdog_device wdtdev
;
35 static int pmic_wdt_start(struct watchdog_device
*wdd
)
37 struct stpmic1_wdt
*wdt
= watchdog_get_drvdata(wdd
);
39 return regmap_update_bits(wdt
->pmic
->regmap
,
40 WCHDG_CR
, WDT_START_MASK
, WDT_START
);
43 static int pmic_wdt_stop(struct watchdog_device
*wdd
)
45 struct stpmic1_wdt
*wdt
= watchdog_get_drvdata(wdd
);
47 return regmap_update_bits(wdt
->pmic
->regmap
,
48 WCHDG_CR
, WDT_START_MASK
, WDT_STOP
);
51 static int pmic_wdt_ping(struct watchdog_device
*wdd
)
53 struct stpmic1_wdt
*wdt
= watchdog_get_drvdata(wdd
);
55 return regmap_update_bits(wdt
->pmic
->regmap
,
56 WCHDG_CR
, WDT_PING_MASK
, WDT_PING
);
59 static int pmic_wdt_set_timeout(struct watchdog_device
*wdd
,
62 struct stpmic1_wdt
*wdt
= watchdog_get_drvdata(wdd
);
64 wdd
->timeout
= timeout
;
65 /* timeout is equal to register value + 1 */
66 return regmap_write(wdt
->pmic
->regmap
, WCHDG_TIMER_CR
, timeout
- 1);
69 static const struct watchdog_info pmic_watchdog_info
= {
70 .options
= WDIOF_SETTIMEOUT
| WDIOF_KEEPALIVEPING
| WDIOF_MAGICCLOSE
,
71 .identity
= "STPMIC1 PMIC Watchdog",
74 static const struct watchdog_ops pmic_watchdog_ops
= {
76 .start
= pmic_wdt_start
,
77 .stop
= pmic_wdt_stop
,
78 .ping
= pmic_wdt_ping
,
79 .set_timeout
= pmic_wdt_set_timeout
,
82 static int pmic_wdt_probe(struct platform_device
*pdev
)
84 struct device
*dev
= &pdev
->dev
;
87 struct stpmic1_wdt
*wdt
;
92 pmic
= dev_get_drvdata(dev
->parent
);
96 wdt
= devm_kzalloc(dev
, sizeof(struct stpmic1_wdt
), GFP_KERNEL
);
102 wdt
->wdtdev
.info
= &pmic_watchdog_info
;
103 wdt
->wdtdev
.ops
= &pmic_watchdog_ops
;
104 wdt
->wdtdev
.min_timeout
= PMIC_WDT_MIN_TIMEOUT
;
105 wdt
->wdtdev
.max_timeout
= PMIC_WDT_MAX_TIMEOUT
;
106 wdt
->wdtdev
.parent
= dev
;
108 wdt
->wdtdev
.timeout
= PMIC_WDT_DEFAULT_TIMEOUT
;
109 watchdog_init_timeout(&wdt
->wdtdev
, 0, dev
);
111 watchdog_set_nowayout(&wdt
->wdtdev
, nowayout
);
112 watchdog_set_drvdata(&wdt
->wdtdev
, wdt
);
114 ret
= devm_watchdog_register_device(dev
, &wdt
->wdtdev
);
118 dev_dbg(wdt
->pmic
->dev
, "PMIC Watchdog driver probed\n");
122 static const struct of_device_id of_pmic_wdt_match
[] = {
123 { .compatible
= "st,stpmic1-wdt" },
127 MODULE_DEVICE_TABLE(of
, of_pmic_wdt_match
);
129 static struct platform_driver stpmic1_wdt_driver
= {
130 .probe
= pmic_wdt_probe
,
132 .name
= "stpmic1-wdt",
133 .of_match_table
= of_pmic_wdt_match
,
136 module_platform_driver(stpmic1_wdt_driver
);
138 MODULE_DESCRIPTION("Watchdog driver for STPMIC1 device");
139 MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>");
140 MODULE_LICENSE("GPL v2");