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
;
148 wdt
= devm_kzalloc(dev
, sizeof(struct rn5t618_wdt
), GFP_KERNEL
);
152 min_timeout
= rn5t618_wdt_map
[0].time
;
153 max_timeout
= rn5t618_wdt_map
[ARRAY_SIZE(rn5t618_wdt_map
) - 1].time
;
155 wdt
->rn5t618
= rn5t618
;
156 wdt
->wdt_dev
.info
= &rn5t618_wdt_info
;
157 wdt
->wdt_dev
.ops
= &rn5t618_wdt_ops
;
158 wdt
->wdt_dev
.min_timeout
= min_timeout
;
159 wdt
->wdt_dev
.max_timeout
= max_timeout
;
160 wdt
->wdt_dev
.timeout
= max_timeout
;
161 wdt
->wdt_dev
.parent
= dev
;
163 watchdog_set_drvdata(&wdt
->wdt_dev
, wdt
);
164 watchdog_init_timeout(&wdt
->wdt_dev
, timeout
, dev
);
165 watchdog_set_nowayout(&wdt
->wdt_dev
, nowayout
);
167 platform_set_drvdata(pdev
, wdt
);
169 return watchdog_register_device(&wdt
->wdt_dev
);
172 static int rn5t618_wdt_remove(struct platform_device
*pdev
)
174 struct rn5t618_wdt
*wdt
= platform_get_drvdata(pdev
);
176 watchdog_unregister_device(&wdt
->wdt_dev
);
181 static struct platform_driver rn5t618_wdt_driver
= {
182 .probe
= rn5t618_wdt_probe
,
183 .remove
= rn5t618_wdt_remove
,
189 module_platform_driver(rn5t618_wdt_driver
);
191 MODULE_ALIAS("platform:rn5t618-wdt");
192 MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
193 MODULE_DESCRIPTION("RN5T618 watchdog driver");
194 MODULE_LICENSE("GPL v2");