1 // SPDX-License-Identifier: GPL-2.0-only
3 * Watchdog driver for Ricoh RN5T618 PMIC
5 * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
8 #include <linux/device.h>
9 #include <linux/mfd/rn5t618.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/watchdog.h>
14 #define DRIVER_NAME "rn5t618-wdt"
16 static bool nowayout
= WATCHDOG_NOWAYOUT
;
17 static unsigned int timeout
;
19 module_param(timeout
, uint
, 0);
20 MODULE_PARM_DESC(timeout
, "Initial watchdog timeout in seconds");
22 module_param(nowayout
, bool, 0);
23 MODULE_PARM_DESC(nowayout
, "Watchdog cannot be stopped once started (default="
24 __MODULE_STRING(WATCHDOG_NOWAYOUT
) ")");
27 struct watchdog_device wdt_dev
;
28 struct rn5t618
*rn5t618
;
32 * This array encodes the values of WDOGTIM field for the supported
33 * watchdog expiration times. If the watchdog is not accessed before
34 * the timer expiration, the PMU generates an interrupt and if the CPU
35 * doesn't clear it within one second the system is restarted.
40 } rn5t618_wdt_map
[] = {
47 static int rn5t618_wdt_set_timeout(struct watchdog_device
*wdt_dev
,
50 struct rn5t618_wdt
*wdt
= watchdog_get_drvdata(wdt_dev
);
53 for (i
= 0; i
< ARRAY_SIZE(rn5t618_wdt_map
); i
++) {
54 if (rn5t618_wdt_map
[i
].time
+ 1 >= t
)
58 if (i
== ARRAY_SIZE(rn5t618_wdt_map
))
61 ret
= regmap_update_bits(wdt
->rn5t618
->regmap
, RN5T618_WATCHDOG
,
62 RN5T618_WATCHDOG_WDOGTIM_M
,
63 rn5t618_wdt_map
[i
].reg_val
);
65 wdt_dev
->timeout
= rn5t618_wdt_map
[i
].time
;
70 static int rn5t618_wdt_start(struct watchdog_device
*wdt_dev
)
72 struct rn5t618_wdt
*wdt
= watchdog_get_drvdata(wdt_dev
);
75 ret
= rn5t618_wdt_set_timeout(wdt_dev
, wdt_dev
->timeout
);
79 /* enable repower-on */
80 ret
= regmap_update_bits(wdt
->rn5t618
->regmap
, RN5T618_REPCNT
,
81 RN5T618_REPCNT_REPWRON
,
82 RN5T618_REPCNT_REPWRON
);
87 ret
= regmap_update_bits(wdt
->rn5t618
->regmap
, RN5T618_WATCHDOG
,
88 RN5T618_WATCHDOG_WDOGEN
,
89 RN5T618_WATCHDOG_WDOGEN
);
93 /* enable watchdog interrupt */
94 return regmap_update_bits(wdt
->rn5t618
->regmap
, RN5T618_PWRIREN
,
95 RN5T618_PWRIRQ_IR_WDOG
,
96 RN5T618_PWRIRQ_IR_WDOG
);
99 static int rn5t618_wdt_stop(struct watchdog_device
*wdt_dev
)
101 struct rn5t618_wdt
*wdt
= watchdog_get_drvdata(wdt_dev
);
103 return regmap_update_bits(wdt
->rn5t618
->regmap
, RN5T618_WATCHDOG
,
104 RN5T618_WATCHDOG_WDOGEN
, 0);
107 static int rn5t618_wdt_ping(struct watchdog_device
*wdt_dev
)
109 struct rn5t618_wdt
*wdt
= watchdog_get_drvdata(wdt_dev
);
113 /* The counter is restarted after a R/W access to watchdog register */
114 ret
= regmap_read(wdt
->rn5t618
->regmap
, RN5T618_WATCHDOG
, &val
);
118 ret
= regmap_write(wdt
->rn5t618
->regmap
, RN5T618_WATCHDOG
, val
);
122 /* Clear pending watchdog interrupt */
123 return regmap_update_bits(wdt
->rn5t618
->regmap
, RN5T618_PWRIRQ
,
124 RN5T618_PWRIRQ_IR_WDOG
, 0);
127 static const struct watchdog_info rn5t618_wdt_info
= {
128 .options
= WDIOF_SETTIMEOUT
| WDIOF_MAGICCLOSE
|
130 .identity
= DRIVER_NAME
,
133 static const struct watchdog_ops rn5t618_wdt_ops
= {
134 .owner
= THIS_MODULE
,
135 .start
= rn5t618_wdt_start
,
136 .stop
= rn5t618_wdt_stop
,
137 .ping
= rn5t618_wdt_ping
,
138 .set_timeout
= rn5t618_wdt_set_timeout
,
141 static int rn5t618_wdt_probe(struct platform_device
*pdev
)
143 struct device
*dev
= &pdev
->dev
;
144 struct rn5t618
*rn5t618
= dev_get_drvdata(dev
->parent
);
145 struct rn5t618_wdt
*wdt
;
146 int min_timeout
, max_timeout
;
150 wdt
= devm_kzalloc(dev
, sizeof(struct rn5t618_wdt
), GFP_KERNEL
);
154 min_timeout
= rn5t618_wdt_map
[0].time
;
155 max_timeout
= rn5t618_wdt_map
[ARRAY_SIZE(rn5t618_wdt_map
) - 1].time
;
157 wdt
->rn5t618
= rn5t618
;
158 wdt
->wdt_dev
.info
= &rn5t618_wdt_info
;
159 wdt
->wdt_dev
.ops
= &rn5t618_wdt_ops
;
160 wdt
->wdt_dev
.min_timeout
= min_timeout
;
161 wdt
->wdt_dev
.max_timeout
= max_timeout
;
162 wdt
->wdt_dev
.timeout
= max_timeout
;
163 wdt
->wdt_dev
.parent
= dev
;
165 /* Read out previous power-off factor */
166 ret
= regmap_read(wdt
->rn5t618
->regmap
, RN5T618_POFFHIS
, &val
);
170 if (val
& RN5T618_POFFHIS_VINDET
)
171 wdt
->wdt_dev
.bootstatus
= WDIOF_POWERUNDER
;
172 else if (val
& RN5T618_POFFHIS_WDG
)
173 wdt
->wdt_dev
.bootstatus
= WDIOF_CARDRESET
;
175 watchdog_set_drvdata(&wdt
->wdt_dev
, wdt
);
176 watchdog_init_timeout(&wdt
->wdt_dev
, timeout
, dev
);
177 watchdog_set_nowayout(&wdt
->wdt_dev
, nowayout
);
179 platform_set_drvdata(pdev
, wdt
);
181 return devm_watchdog_register_device(dev
, &wdt
->wdt_dev
);
184 static struct platform_driver rn5t618_wdt_driver
= {
185 .probe
= rn5t618_wdt_probe
,
191 module_platform_driver(rn5t618_wdt_driver
);
193 MODULE_ALIAS("platform:rn5t618-wdt");
194 MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
195 MODULE_DESCRIPTION("RN5T618 watchdog driver");
196 MODULE_LICENSE("GPL v2");