2 * Maxim MAX77620 Watchdog Driver
4 * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
6 * Author: Laxman Dewangan <ldewangan@nvidia.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/err.h>
14 #include <linux/init.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/mfd/max77620.h>
18 #include <linux/platform_device.h>
19 #include <linux/regmap.h>
20 #include <linux/slab.h>
21 #include <linux/watchdog.h>
23 static bool nowayout
= WATCHDOG_NOWAYOUT
;
28 struct watchdog_device wdt_dev
;
31 static int max77620_wdt_start(struct watchdog_device
*wdt_dev
)
33 struct max77620_wdt
*wdt
= watchdog_get_drvdata(wdt_dev
);
35 return regmap_update_bits(wdt
->rmap
, MAX77620_REG_CNFGGLBL2
,
36 MAX77620_WDTEN
, MAX77620_WDTEN
);
39 static int max77620_wdt_stop(struct watchdog_device
*wdt_dev
)
41 struct max77620_wdt
*wdt
= watchdog_get_drvdata(wdt_dev
);
43 return regmap_update_bits(wdt
->rmap
, MAX77620_REG_CNFGGLBL2
,
47 static int max77620_wdt_ping(struct watchdog_device
*wdt_dev
)
49 struct max77620_wdt
*wdt
= watchdog_get_drvdata(wdt_dev
);
51 return regmap_update_bits(wdt
->rmap
, MAX77620_REG_CNFGGLBL3
,
52 MAX77620_WDTC_MASK
, 0x1);
55 static int max77620_wdt_set_timeout(struct watchdog_device
*wdt_dev
,
58 struct max77620_wdt
*wdt
= watchdog_get_drvdata(wdt_dev
);
59 unsigned int wdt_timeout
;
65 regval
= MAX77620_TWD_2s
;
70 regval
= MAX77620_TWD_16s
;
75 regval
= MAX77620_TWD_64s
;
80 regval
= MAX77620_TWD_128s
;
85 ret
= regmap_update_bits(wdt
->rmap
, MAX77620_REG_CNFGGLBL3
,
86 MAX77620_WDTC_MASK
, 0x1);
90 ret
= regmap_update_bits(wdt
->rmap
, MAX77620_REG_CNFGGLBL2
,
91 MAX77620_TWD_MASK
, regval
);
95 wdt_dev
->timeout
= wdt_timeout
;
100 static const struct watchdog_info max77620_wdt_info
= {
101 .identity
= "max77620-watchdog",
102 .options
= WDIOF_SETTIMEOUT
| WDIOF_KEEPALIVEPING
| WDIOF_MAGICCLOSE
,
105 static const struct watchdog_ops max77620_wdt_ops
= {
106 .start
= max77620_wdt_start
,
107 .stop
= max77620_wdt_stop
,
108 .ping
= max77620_wdt_ping
,
109 .set_timeout
= max77620_wdt_set_timeout
,
112 static int max77620_wdt_probe(struct platform_device
*pdev
)
114 struct max77620_wdt
*wdt
;
115 struct watchdog_device
*wdt_dev
;
119 wdt
= devm_kzalloc(&pdev
->dev
, sizeof(*wdt
), GFP_KERNEL
);
123 wdt
->dev
= &pdev
->dev
;
124 wdt
->rmap
= dev_get_regmap(pdev
->dev
.parent
, NULL
);
126 dev_err(wdt
->dev
, "Failed to get parent regmap\n");
130 wdt_dev
= &wdt
->wdt_dev
;
131 wdt_dev
->info
= &max77620_wdt_info
;
132 wdt_dev
->ops
= &max77620_wdt_ops
;
133 wdt_dev
->min_timeout
= 2;
134 wdt_dev
->max_timeout
= 128;
135 wdt_dev
->max_hw_heartbeat_ms
= 128 * 1000;
137 platform_set_drvdata(pdev
, wdt
);
139 /* Enable WD_RST_WK - WDT expire results in a restart */
140 ret
= regmap_update_bits(wdt
->rmap
, MAX77620_REG_ONOFFCNFG2
,
141 MAX77620_ONOFFCNFG2_WD_RST_WK
,
142 MAX77620_ONOFFCNFG2_WD_RST_WK
);
144 dev_err(wdt
->dev
, "Failed to set WD_RST_WK: %d\n", ret
);
148 /* Set WDT clear in OFF and sleep mode */
149 ret
= regmap_update_bits(wdt
->rmap
, MAX77620_REG_CNFGGLBL2
,
150 MAX77620_WDTOFFC
| MAX77620_WDTSLPC
,
151 MAX77620_WDTOFFC
| MAX77620_WDTSLPC
);
153 dev_err(wdt
->dev
, "Failed to set WDT OFF mode: %d\n", ret
);
157 /* Check if WDT running and if yes then set flags properly */
158 ret
= regmap_read(wdt
->rmap
, MAX77620_REG_CNFGGLBL2
, ®val
);
160 dev_err(wdt
->dev
, "Failed to read WDT CFG register: %d\n", ret
);
164 switch (regval
& MAX77620_TWD_MASK
) {
165 case MAX77620_TWD_2s
:
166 wdt_dev
->timeout
= 2;
168 case MAX77620_TWD_16s
:
169 wdt_dev
->timeout
= 16;
171 case MAX77620_TWD_64s
:
172 wdt_dev
->timeout
= 64;
175 wdt_dev
->timeout
= 128;
179 if (regval
& MAX77620_WDTEN
)
180 set_bit(WDOG_HW_RUNNING
, &wdt_dev
->status
);
182 watchdog_set_nowayout(wdt_dev
, nowayout
);
183 watchdog_set_drvdata(wdt_dev
, wdt
);
185 ret
= watchdog_register_device(wdt_dev
);
187 dev_err(&pdev
->dev
, "watchdog registration failed: %d\n", ret
);
194 static int max77620_wdt_remove(struct platform_device
*pdev
)
196 struct max77620_wdt
*wdt
= platform_get_drvdata(pdev
);
198 max77620_wdt_stop(&wdt
->wdt_dev
);
199 watchdog_unregister_device(&wdt
->wdt_dev
);
204 static const struct platform_device_id max77620_wdt_devtype
[] = {
205 { .name
= "max77620-watchdog", },
208 MODULE_DEVICE_TABLE(platform
, max77620_wdt_devtype
);
210 static struct platform_driver max77620_wdt_driver
= {
212 .name
= "max77620-watchdog",
214 .probe
= max77620_wdt_probe
,
215 .remove
= max77620_wdt_remove
,
216 .id_table
= max77620_wdt_devtype
,
219 module_platform_driver(max77620_wdt_driver
);
221 MODULE_DESCRIPTION("Max77620 watchdog timer driver");
223 module_param(nowayout
, bool, 0);
224 MODULE_PARM_DESC(nowayout
, "Watchdog cannot be stopped once started "
225 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT
) ")");
227 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
228 MODULE_LICENSE("GPL v2");