1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Maxim MAX77620 Watchdog Driver
4  *
5  * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
6  * Copyright (C) 2022 Luca Ceresoli
7  *
8  * Author: Laxman Dewangan <[email protected]>
9  * Author: Luca Ceresoli <[email protected]>
10  */
11 
12 #include <linux/err.h>
13 #include <linux/init.h>
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/mod_devicetable.h>
17 #include <linux/mfd/max77620.h>
18 #include <linux/mfd/max77714.h>
19 #include <linux/platform_device.h>
20 #include <linux/regmap.h>
21 #include <linux/slab.h>
22 #include <linux/watchdog.h>
23 
24 static bool nowayout = WATCHDOG_NOWAYOUT;
25 
26 /**
27  * struct max77620_variant - Data specific to a chip variant
28  * @reg_onoff_cnfg2:     ONOFF_CNFG2 register offset
29  * @reg_cnfg_glbl2:      CNFG_GLBL2 register offset
30  * @reg_cnfg_glbl3:      CNFG_GLBL3 register offset
31  * @wdtc_mask:           WDTC bit mask in CNFG_GLBL3 (=bits to update to ping the watchdog)
32  * @bit_wd_rst_wk:       WD_RST_WK bit offset within ONOFF_CNFG2
33  * @cnfg_glbl2_cfg_bits: configuration bits to enable in CNFG_GLBL2 register
34  */
35 struct max77620_variant {
36 	u8 reg_onoff_cnfg2;
37 	u8 reg_cnfg_glbl2;
38 	u8 reg_cnfg_glbl3;
39 	u8 wdtc_mask;
40 	u8 bit_wd_rst_wk;
41 	u8 cnfg_glbl2_cfg_bits;
42 };
43 
44 struct max77620_wdt {
45 	struct device			*dev;
46 	struct regmap			*rmap;
47 	const struct max77620_variant	*drv_data;
48 	struct watchdog_device		wdt_dev;
49 };
50 
51 static const struct max77620_variant max77620_wdt_data = {
52 	.reg_onoff_cnfg2     = MAX77620_REG_ONOFFCNFG2,
53 	.reg_cnfg_glbl2      = MAX77620_REG_CNFGGLBL2,
54 	.reg_cnfg_glbl3      = MAX77620_REG_CNFGGLBL3,
55 	.wdtc_mask           = MAX77620_WDTC_MASK,
56 	.bit_wd_rst_wk       = MAX77620_ONOFFCNFG2_WD_RST_WK,
57 	/* Set WDT clear in OFF and sleep mode */
58 	.cnfg_glbl2_cfg_bits = MAX77620_WDTSLPC | MAX77620_WDTOFFC,
59 };
60 
61 static const struct max77620_variant max77714_wdt_data = {
62 	.reg_onoff_cnfg2     = MAX77714_CNFG2_ONOFF,
63 	.reg_cnfg_glbl2      = MAX77714_CNFG_GLBL2,
64 	.reg_cnfg_glbl3      = MAX77714_CNFG_GLBL3,
65 	.wdtc_mask           = MAX77714_WDTC,
66 	.bit_wd_rst_wk       = MAX77714_WD_RST_WK,
67 	/* Set WDT clear in sleep mode (there is no WDTOFFC on MAX77714) */
68 	.cnfg_glbl2_cfg_bits = MAX77714_WDTSLPC,
69 };
70 
max77620_wdt_start(struct watchdog_device * wdt_dev)71 static int max77620_wdt_start(struct watchdog_device *wdt_dev)
72 {
73 	struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);
74 
75 	return regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,
76 				  MAX77620_WDTEN, MAX77620_WDTEN);
77 }
78 
max77620_wdt_stop(struct watchdog_device * wdt_dev)79 static int max77620_wdt_stop(struct watchdog_device *wdt_dev)
80 {
81 	struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);
82 
83 	return regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,
84 				  MAX77620_WDTEN, 0);
85 }
86 
max77620_wdt_ping(struct watchdog_device * wdt_dev)87 static int max77620_wdt_ping(struct watchdog_device *wdt_dev)
88 {
89 	struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);
90 
91 	return regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl3,
92 				  wdt->drv_data->wdtc_mask, 0x1);
93 }
94 
max77620_wdt_set_timeout(struct watchdog_device * wdt_dev,unsigned int timeout)95 static int max77620_wdt_set_timeout(struct watchdog_device *wdt_dev,
96 				    unsigned int timeout)
97 {
98 	struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);
99 	unsigned int wdt_timeout;
100 	u8 regval;
101 	int ret;
102 
103 	switch (timeout) {
104 	case 0 ... 2:
105 		regval = MAX77620_TWD_2s;
106 		wdt_timeout = 2;
107 		break;
108 
109 	case 3 ... 16:
110 		regval = MAX77620_TWD_16s;
111 		wdt_timeout = 16;
112 		break;
113 
114 	case 17 ... 64:
115 		regval = MAX77620_TWD_64s;
116 		wdt_timeout = 64;
117 		break;
118 
119 	default:
120 		regval = MAX77620_TWD_128s;
121 		wdt_timeout = 128;
122 		break;
123 	}
124 
125 	/*
126 	 * "If the value of TWD needs to be changed, clear the system
127 	 * watchdog timer first [...], then change the value of TWD."
128 	 * (MAX77714 datasheet but applies to MAX77620 too)
129 	 */
130 	ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl3,
131 				 wdt->drv_data->wdtc_mask, 0x1);
132 	if (ret < 0)
133 		return ret;
134 
135 	ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,
136 				 MAX77620_TWD_MASK, regval);
137 	if (ret < 0)
138 		return ret;
139 
140 	wdt_dev->timeout = wdt_timeout;
141 
142 	return 0;
143 }
144 
145 static const struct watchdog_info max77620_wdt_info = {
146 	.identity = "max77620-watchdog",
147 	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
148 };
149 
150 static const struct watchdog_ops max77620_wdt_ops = {
151 	.start		= max77620_wdt_start,
152 	.stop		= max77620_wdt_stop,
153 	.ping		= max77620_wdt_ping,
154 	.set_timeout	= max77620_wdt_set_timeout,
155 };
156 
max77620_wdt_probe(struct platform_device * pdev)157 static int max77620_wdt_probe(struct platform_device *pdev)
158 {
159 	const struct platform_device_id *id = platform_get_device_id(pdev);
160 	struct device *dev = &pdev->dev;
161 	struct max77620_wdt *wdt;
162 	struct watchdog_device *wdt_dev;
163 	unsigned int regval;
164 	int ret;
165 
166 	wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
167 	if (!wdt)
168 		return -ENOMEM;
169 
170 	wdt->dev = dev;
171 	wdt->drv_data = (const struct max77620_variant *) id->driver_data;
172 
173 	wdt->rmap = dev_get_regmap(dev->parent, NULL);
174 	if (!wdt->rmap) {
175 		dev_err(wdt->dev, "Failed to get parent regmap\n");
176 		return -ENODEV;
177 	}
178 
179 	wdt_dev = &wdt->wdt_dev;
180 	wdt_dev->info = &max77620_wdt_info;
181 	wdt_dev->ops = &max77620_wdt_ops;
182 	wdt_dev->min_timeout = 2;
183 	wdt_dev->max_timeout = 128;
184 	wdt_dev->max_hw_heartbeat_ms = 128 * 1000;
185 
186 	platform_set_drvdata(pdev, wdt);
187 
188 	/* Enable WD_RST_WK - WDT expire results in a restart */
189 	ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_onoff_cnfg2,
190 				 wdt->drv_data->bit_wd_rst_wk,
191 				 wdt->drv_data->bit_wd_rst_wk);
192 	if (ret < 0) {
193 		dev_err(wdt->dev, "Failed to set WD_RST_WK: %d\n", ret);
194 		return ret;
195 	}
196 
197 	/* Set the "auto WDT clear" bits available on the chip */
198 	ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,
199 				 wdt->drv_data->cnfg_glbl2_cfg_bits,
200 				 wdt->drv_data->cnfg_glbl2_cfg_bits);
201 	if (ret < 0) {
202 		dev_err(wdt->dev, "Failed to set WDT OFF mode: %d\n", ret);
203 		return ret;
204 	}
205 
206 	/* Check if WDT running and if yes then set flags properly */
207 	ret = regmap_read(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2, &regval);
208 	if (ret < 0) {
209 		dev_err(wdt->dev, "Failed to read WDT CFG register: %d\n", ret);
210 		return ret;
211 	}
212 
213 	switch (regval & MAX77620_TWD_MASK) {
214 	case MAX77620_TWD_2s:
215 		wdt_dev->timeout = 2;
216 		break;
217 	case MAX77620_TWD_16s:
218 		wdt_dev->timeout = 16;
219 		break;
220 	case MAX77620_TWD_64s:
221 		wdt_dev->timeout = 64;
222 		break;
223 	default:
224 		wdt_dev->timeout = 128;
225 		break;
226 	}
227 
228 	if (regval & MAX77620_WDTEN)
229 		set_bit(WDOG_HW_RUNNING, &wdt_dev->status);
230 
231 	watchdog_set_nowayout(wdt_dev, nowayout);
232 	watchdog_set_drvdata(wdt_dev, wdt);
233 
234 	watchdog_stop_on_unregister(wdt_dev);
235 	return devm_watchdog_register_device(dev, wdt_dev);
236 }
237 
238 static const struct platform_device_id max77620_wdt_devtype[] = {
239 	{ "max77620-watchdog", (kernel_ulong_t)&max77620_wdt_data },
240 	{ "max77714-watchdog", (kernel_ulong_t)&max77714_wdt_data },
241 	{ },
242 };
243 MODULE_DEVICE_TABLE(platform, max77620_wdt_devtype);
244 
245 static struct platform_driver max77620_wdt_driver = {
246 	.driver	= {
247 		.name	= "max77620-watchdog",
248 	},
249 	.probe	= max77620_wdt_probe,
250 	.id_table = max77620_wdt_devtype,
251 };
252 
253 module_platform_driver(max77620_wdt_driver);
254 
255 MODULE_DESCRIPTION("Max77620 watchdog timer driver");
256 
257 module_param(nowayout, bool, 0);
258 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
259 	"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
260 
261 MODULE_AUTHOR("Laxman Dewangan <[email protected]>");
262 MODULE_AUTHOR("Luca Ceresoli <[email protected]>");
263 MODULE_LICENSE("GPL v2");
264