1 // SPDX-License-Identifier: GPL-2.0-only
3 * Maxim MAX77620 Watchdog Driver
5 * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
7 * Author: Laxman Dewangan <ldewangan@nvidia.com>
10 #include <linux/err.h>
11 #include <linux/init.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/mod_devicetable.h>
15 #include <linux/mfd/max77620.h>
16 #include <linux/platform_device.h>
17 #include <linux/regmap.h>
18 #include <linux/slab.h>
19 #include <linux/watchdog.h>
21 static bool nowayout
= WATCHDOG_NOWAYOUT
;
26 struct watchdog_device wdt_dev
;
29 static int max77620_wdt_start(struct watchdog_device
*wdt_dev
)
31 struct max77620_wdt
*wdt
= watchdog_get_drvdata(wdt_dev
);
33 return regmap_update_bits(wdt
->rmap
, MAX77620_REG_CNFGGLBL2
,
34 MAX77620_WDTEN
, MAX77620_WDTEN
);
37 static int max77620_wdt_stop(struct watchdog_device
*wdt_dev
)
39 struct max77620_wdt
*wdt
= watchdog_get_drvdata(wdt_dev
);
41 return regmap_update_bits(wdt
->rmap
, MAX77620_REG_CNFGGLBL2
,
45 static int max77620_wdt_ping(struct watchdog_device
*wdt_dev
)
47 struct max77620_wdt
*wdt
= watchdog_get_drvdata(wdt_dev
);
49 return regmap_update_bits(wdt
->rmap
, MAX77620_REG_CNFGGLBL3
,
50 MAX77620_WDTC_MASK
, 0x1);
53 static int max77620_wdt_set_timeout(struct watchdog_device
*wdt_dev
,
56 struct max77620_wdt
*wdt
= watchdog_get_drvdata(wdt_dev
);
57 unsigned int wdt_timeout
;
63 regval
= MAX77620_TWD_2s
;
68 regval
= MAX77620_TWD_16s
;
73 regval
= MAX77620_TWD_64s
;
78 regval
= MAX77620_TWD_128s
;
83 ret
= regmap_update_bits(wdt
->rmap
, MAX77620_REG_CNFGGLBL3
,
84 MAX77620_WDTC_MASK
, 0x1);
88 ret
= regmap_update_bits(wdt
->rmap
, MAX77620_REG_CNFGGLBL2
,
89 MAX77620_TWD_MASK
, regval
);
93 wdt_dev
->timeout
= wdt_timeout
;
98 static const struct watchdog_info max77620_wdt_info
= {
99 .identity
= "max77620-watchdog",
100 .options
= WDIOF_SETTIMEOUT
| WDIOF_KEEPALIVEPING
| WDIOF_MAGICCLOSE
,
103 static const struct watchdog_ops max77620_wdt_ops
= {
104 .start
= max77620_wdt_start
,
105 .stop
= max77620_wdt_stop
,
106 .ping
= max77620_wdt_ping
,
107 .set_timeout
= max77620_wdt_set_timeout
,
110 static int max77620_wdt_probe(struct platform_device
*pdev
)
112 struct device
*dev
= &pdev
->dev
;
113 struct max77620_wdt
*wdt
;
114 struct watchdog_device
*wdt_dev
;
118 wdt
= devm_kzalloc(dev
, sizeof(*wdt
), GFP_KERNEL
);
123 wdt
->rmap
= dev_get_regmap(dev
->parent
, NULL
);
125 dev_err(wdt
->dev
, "Failed to get parent regmap\n");
129 wdt_dev
= &wdt
->wdt_dev
;
130 wdt_dev
->info
= &max77620_wdt_info
;
131 wdt_dev
->ops
= &max77620_wdt_ops
;
132 wdt_dev
->min_timeout
= 2;
133 wdt_dev
->max_timeout
= 128;
134 wdt_dev
->max_hw_heartbeat_ms
= 128 * 1000;
136 platform_set_drvdata(pdev
, wdt
);
138 /* Enable WD_RST_WK - WDT expire results in a restart */
139 ret
= regmap_update_bits(wdt
->rmap
, MAX77620_REG_ONOFFCNFG2
,
140 MAX77620_ONOFFCNFG2_WD_RST_WK
,
141 MAX77620_ONOFFCNFG2_WD_RST_WK
);
143 dev_err(wdt
->dev
, "Failed to set WD_RST_WK: %d\n", ret
);
147 /* Set WDT clear in OFF and sleep mode */
148 ret
= regmap_update_bits(wdt
->rmap
, MAX77620_REG_CNFGGLBL2
,
149 MAX77620_WDTOFFC
| MAX77620_WDTSLPC
,
150 MAX77620_WDTOFFC
| MAX77620_WDTSLPC
);
152 dev_err(wdt
->dev
, "Failed to set WDT OFF mode: %d\n", ret
);
156 /* Check if WDT running and if yes then set flags properly */
157 ret
= regmap_read(wdt
->rmap
, MAX77620_REG_CNFGGLBL2
, ®val
);
159 dev_err(wdt
->dev
, "Failed to read WDT CFG register: %d\n", ret
);
163 switch (regval
& MAX77620_TWD_MASK
) {
164 case MAX77620_TWD_2s
:
165 wdt_dev
->timeout
= 2;
167 case MAX77620_TWD_16s
:
168 wdt_dev
->timeout
= 16;
170 case MAX77620_TWD_64s
:
171 wdt_dev
->timeout
= 64;
174 wdt_dev
->timeout
= 128;
178 if (regval
& MAX77620_WDTEN
)
179 set_bit(WDOG_HW_RUNNING
, &wdt_dev
->status
);
181 watchdog_set_nowayout(wdt_dev
, nowayout
);
182 watchdog_set_drvdata(wdt_dev
, wdt
);
184 watchdog_stop_on_unregister(wdt_dev
);
185 return devm_watchdog_register_device(dev
, wdt_dev
);
188 static const struct platform_device_id max77620_wdt_devtype
[] = {
189 { .name
= "max77620-watchdog", },
192 MODULE_DEVICE_TABLE(platform
, max77620_wdt_devtype
);
194 static struct platform_driver max77620_wdt_driver
= {
196 .name
= "max77620-watchdog",
198 .probe
= max77620_wdt_probe
,
199 .id_table
= max77620_wdt_devtype
,
202 module_platform_driver(max77620_wdt_driver
);
204 MODULE_DESCRIPTION("Max77620 watchdog timer driver");
206 module_param(nowayout
, bool, 0);
207 MODULE_PARM_DESC(nowayout
, "Watchdog cannot be stopped once started "
208 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT
) ")");
210 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
211 MODULE_LICENSE("GPL v2");