xref: /linux/drivers/watchdog/atcwdt200_wdt.c (revision 9611c0ce215a66770ccbe5c126bf57ba8c31bcad)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Andes ATCWDT200 watchdog timer driver.
4  *
5  * Copyright (C) 2025 Andes Technology Corporation
6  */
7 
8 #include <linux/bitfield.h>
9 #include <linux/clk.h>
10 #include <linux/device.h>
11 #include <linux/dev_printk.h>
12 #include <linux/math64.h>
13 #include <linux/minmax.h>
14 #include <linux/moduleparam.h>
15 #include <linux/module.h>
16 #include <linux/of.h>
17 #include <linux/of_platform.h>
18 #include <linux/platform_device.h>
19 #include <linux/pm.h>
20 #include <linux/pm_runtime.h>
21 #include <linux/regmap.h>
22 #include <linux/watchdog.h>
23 
24 /* Register definitions */
25 #define REG_CTRL		0x10
26 #define REG_RESTART		0x14
27 #define REG_WRITE_EN		0x18
28 #define REG_STATUS		0x1C
29 
30 /* Control Register */
31 #define CTRL_RST_TIME_MSK	GENMASK(10, 8)
32 #define CTRL_RST_TIME_SET(x)	FIELD_PREP(CTRL_RST_TIME_MSK, x)
33 #define CTRL_INT_TIME_MSK	GENMASK(7, 4)
34 #define CTRL_INT_TIME_SET(x)	FIELD_PREP(CTRL_INT_TIME_MSK, x)
35 #define CTRL_INT_TIME_GET(x)	FIELD_GET(CTRL_INT_TIME_MSK, x)
36 #define CTRL_RST_EN		BIT(3)
37 #define CTRL_CLK_SEL		BIT(1)
38 #define CTRL_CLK_SEL_PCLK	1
39 #define CTRL_CLK_SEL_SET(x)	FIELD_PREP(CTRL_CLK_SEL, x)
40 #define CTRL_WDT_EN		BIT(0)
41 
42 /* Restart Register */
43 #define RESTART_MAGIC		0xCAFE
44 
45 /* Write Enable Register */
46 #define WRITE_EN_MAGIC		0x5AA5
47 
48 /* Status Register */
49 #define STATUS_INT_EXPIRED	BIT(1)
50 
51 /* The default timeout value in seconds */
52 #define ATCWDT_TIMEOUT		4
53 
54 /* Define the array size for each timer type */
55 #define TMR_SZ_RST		8
56 #define TMR_SZ_INT_16		8
57 #define TMR_SZ_INT_32		16
58 
59 #define DRV_NAME		"atcwdt200"
60 /**
61  * enum timer_type - Supported timer types for ATCWDT200 watchdog driver
62  * @TMR_RST:      Reset timer (non-interrupt).
63  * @TMR_INT_16:   16-bit interrupt timer supported by hardware.
64  * @TMR_INT_32:   32-bit interrupt timer supported by hardware.
65  * @TMR_UNKNOWN:  Timer type cannot be determined.
66  */
67 enum timer_type {
68 	TMR_RST,
69 	TMR_INT_16,
70 	TMR_INT_32,
71 	TMR_UNKNOWN
72 };
73 
74 static unsigned int timeout = ATCWDT_TIMEOUT;
75 static bool nowayout = WATCHDOG_NOWAYOUT;
76 
77 /**
78  * struct atcwdt_drv - ATCWDT200 watchdog driver private data
79  * @wdt_dev:        Watchdog device used by the watchdog framework.
80  * @regmap:         Register map for accessing hardware registers.
81  * @clk:            Hardware clock used by the watchdog timer.
82  * @lock:           Spinlock protecting register accesses and driver state.
83  * @clk_freq:       Input clock frequency of the ATCWDT200.
84  * @clk_src:        Selected clock source for the watchdog timer.
85  * @int_timer_type: Detected interrupt timer type (16-bit, 32-bit, or unknown).
86  */
87 struct atcwdt_drv {
88 	struct watchdog_device	wdt_dev;
89 	struct regmap		*regmap;
90 	struct clk		*clk;
91 	spinlock_t		lock;
92 	unsigned int		clk_freq;
93 	unsigned char		clk_src;
94 	unsigned char		int_timer_type;
95 };
96 
97 static const struct watchdog_info atcwdt_info = {
98 	.identity = DRV_NAME,
99 	.options = WDIOF_SETTIMEOUT |
100 		   WDIOF_KEEPALIVEPING |
101 		   WDIOF_MAGICCLOSE,
102 };
103 
104 /**
105  * atcwdt_get_index - Get the interval value for the specified timer type
106  * @index: The index of the interval in the array
107  * @timer_type: The type of timer, which can be TMR_RST, TMR_INT_16, or
108  *              TMR_INT_32.
109  *
110  * This function retrieves the interval value based on the timer type and
111  * ensures the index stays within the valid range for the given timer type.
112  * For TMR_RST:
113  *  - The maximum array size is 8 (index range: 0-7).
114  * For TMR_INT_16:
115  *  - The maximum array size is 8 (index range: 0-7).
116  * For TMR_INT_32:
117  *  - The maximum array size is 16 (index range: 0-15).
118  *
119  * If the index exceeds the maximum array size, the function will return
120  * the last element of the respective array.
121  */
122 static inline unsigned char atcwdt_get_index(unsigned char index,
123 					     enum timer_type timer_type)
124 {
125 	static const unsigned char rst_timer_interval[TMR_SZ_RST] = {
126 		7, 8, 9, 10, 11, 12, 13, 14};
127 	static const unsigned char int_timer_interval[TMR_SZ_INT_32] = {
128 		6, 8, 10, 11, 12, 13, 14, 15, 17, 19, 21, 23, 25, 27, 29, 31};
129 	unsigned char array_index;
130 
131 	if (timer_type == TMR_RST) {
132 		array_index = min(index, TMR_SZ_RST - 1);
133 		return rst_timer_interval[array_index];
134 	}
135 
136 	if (timer_type == TMR_INT_32)
137 		array_index = min(index, TMR_SZ_INT_32 - 1);
138 	else
139 		array_index = min(index, TMR_SZ_INT_16 - 1);
140 
141 	return int_timer_interval[array_index];
142 }
143 
144 /**
145  * atcwdt_get_clock_period - Calculate the closest clock period based on a
146  *                           given tick count
147  * @tick: The target tick count to match
148  * @timer_type: The type of timer, which can be TMR_RST, TMR_INT_16, or
149  *              TMR_INT_32.
150  * @index: Pointer to store the index of the selected parameter
151  *
152  * This function calculates the closest clock period to the given tick count
153  * by iterating through the timer parameters and selecting the one that
154  * minimizes the difference between the target tick count and the calculated
155  * clock period. The function determines the index of the closest parameter
156  * and returns the difference between the target tick count and the selected
157  * clock period.
158  *
159  * Return: The difference between the target tick count and the selected
160  * clock period.
161  */
162 static long long atcwdt_get_clock_period(long long tick,
163 					 enum timer_type timer_type,
164 					 unsigned char *index)
165 {
166 	long long result;
167 	unsigned char size;
168 	char i;
169 
170 	if (timer_type == TMR_RST)
171 		size = TMR_SZ_RST;
172 	else if (timer_type == TMR_INT_32)
173 		size = TMR_SZ_INT_32;
174 	else
175 		size = TMR_SZ_INT_16;
176 
177 	*index = size - 1;
178 	for (i = 0; i < size; i++) {
179 		result = tick - (1LL << atcwdt_get_index(i, timer_type));
180 
181 		if (result <= 1) {
182 			*index = i;
183 			break;
184 		}
185 	}
186 
187 	return result;
188 }
189 
190 /**
191  * atcwdt_get_timeout_params - Calculate optimal parameters for Watchdog Timer
192  * @drv_data: Pointer to the Watchdog driver data structure
193  * @timeout: Desired timeout value (in seconds)
194  * @int_timer_params: Pointer to store the calculated interrupt timer
195  *                    parameter index
196  * @rst_timer_params: Pointer to store the calculated reset timer parameter
197  *                    index
198  *
199  * This function calculates the optimal parameter combination for the
200  * interrupt timer and reset timer of the Watchdog Timer to achieve a
201  * timeout value closest to, but not less than the specified timeout.
202  *
203  * Algorithm:
204  * 1. The parameters for both the interrupt timer and reset timer are
205  *    predefined as a series of options represented as powers of 2.
206  * 2. The function first determines the interrupt timer's parameter index
207  *    that provides a time closest to and not exceeding the desired timeout.
208  * 3. Based on the selected interrupt timer, it calculates the required
209  *    reset timer parameter to ensure the total timeout matches the target.
210  *
211  * Return: The calculated parameter indices are stored in the provided
212  *         pointers.
213  */
214 static void atcwdt_get_timeout_params(struct atcwdt_drv *drv_data,
215 				      unsigned int timeout,
216 				      unsigned char *int_timer_params,
217 				      unsigned char *rst_timer_params)
218 {
219 	long long rest_time_ms;
220 	long long result;
221 	long long tick;
222 	unsigned char rst_index;
223 	unsigned char int_index;
224 	unsigned char above;
225 	unsigned char below;
226 
227 	tick = (long long)timeout * drv_data->clk_freq;
228 	result = atcwdt_get_clock_period(tick,
229 					 drv_data->int_timer_type,
230 					 &above);
231 	if (result == 0 || above == 0) {
232 		*int_timer_params = above;
233 		*rst_timer_params = 0;
234 		return;
235 	}
236 	below = above - 1;
237 
238 	int_index = atcwdt_get_index(below, drv_data->int_timer_type);
239 	rest_time_ms = timeout * 1000LL
240 		       - div64_s64(1000LL << int_index, drv_data->clk_freq);
241 
242 	result = atcwdt_get_clock_period(rest_time_ms * drv_data->clk_freq,
243 					 TMR_RST,
244 					 &rst_index);
245 
246 	if (result > 1) {
247 		*int_timer_params = above;
248 		*rst_timer_params = 0;
249 	} else {
250 		*int_timer_params = below;
251 		*rst_timer_params = rst_index;
252 	}
253 }
254 
255 /**
256  * atcwdt_get_int_timer_type - Get the supported interrupt timer type.
257  * @drv_data: Pointer to the watchdog driver data structure.
258  *
259  * This function tests the writable bits in the IntTime field of the control
260  * register to determine the interrupt timer type supported by the hardware.
261  *
262  * Note: This function must only be called when the ATCWDT200 watchdog is
263  * disabled. If the watchdog is enabled, this function returns TMR_UNKNOWN.
264  *
265  * Returns: The interrupt timer type supported by the hardware.
266  */
267 static int atcwdt_get_int_timer_type(struct atcwdt_drv *drv_data)
268 {
269 	struct device *dev = drv_data->wdt_dev.parent;
270 	unsigned int val;
271 	int ret  = 0;
272 
273 	spin_lock(&drv_data->lock);
274 	regmap_read(drv_data->regmap, REG_CTRL, &val);
275 	if (val & CTRL_WDT_EN) {
276 		spin_unlock(&drv_data->lock);
277 		return TMR_UNKNOWN;
278 	}
279 
280 	/*
281 	 * Configures the IntTime field with the maximum mask value
282 	 * (CTRL_INT_TIME_MSK), reads its value from the control register
283 	 * to identify the maximum writable bits.
284 	 */
285 	regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC);
286 	regmap_write(drv_data->regmap, REG_CTRL, CTRL_INT_TIME_MSK);
287 	regmap_read(drv_data->regmap, REG_CTRL, &val);
288 	spin_unlock(&drv_data->lock);
289 
290 	val = CTRL_INT_TIME_GET(val);
291 	switch (val) {
292 	case 7:
293 		drv_data->int_timer_type = TMR_INT_16;
294 		break;
295 	case 15:
296 		drv_data->int_timer_type = TMR_INT_32;
297 		break;
298 	default:
299 		drv_data->int_timer_type = TMR_UNKNOWN;
300 		ret = dev_err_probe(dev, -ENODEV,
301 				    "Failed to detect interrupt timer type\n");
302 	}
303 
304 	return ret;
305 }
306 
307 static int atcwdt_ping(struct watchdog_device *wdt_dev)
308 {
309 	struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev);
310 
311 	spin_lock(&drv_data->lock);
312 	regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC);
313 	regmap_write(drv_data->regmap, REG_RESTART, RESTART_MAGIC);
314 	regmap_update_bits(drv_data->regmap, REG_STATUS, STATUS_INT_EXPIRED,
315 			   STATUS_INT_EXPIRED);
316 	spin_unlock(&drv_data->lock);
317 
318 	return 0;
319 }
320 
321 static int atcwdt_set_timeout(struct watchdog_device *wdt_dev,
322 			      unsigned int timeout)
323 {
324 	struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev);
325 	unsigned int value;
326 	unsigned char  rst_val;
327 	unsigned char  int_val;
328 
329 	wdt_dev->timeout = timeout;
330 	atcwdt_get_timeout_params(drv_data, timeout, &int_val, &rst_val);
331 
332 	spin_lock(&drv_data->lock);
333 	regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC);
334 
335 	value = CTRL_RST_TIME_SET(rst_val) |
336 		CTRL_INT_TIME_SET(int_val) |
337 		CTRL_CLK_SEL_SET(drv_data->clk_src);
338 	regmap_update_bits(drv_data->regmap,
339 			   REG_CTRL,
340 			   CTRL_RST_TIME_MSK |
341 			   CTRL_INT_TIME_MSK |
342 			   CTRL_CLK_SEL,
343 			   value);
344 
345 	spin_unlock(&drv_data->lock);
346 	atcwdt_ping(wdt_dev);
347 
348 	return 0;
349 }
350 
351 static int atcwdt_start(struct watchdog_device *wdt_dev)
352 {
353 	struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev);
354 
355 	atcwdt_set_timeout(wdt_dev, wdt_dev->timeout);
356 
357 	spin_lock(&drv_data->lock);
358 	regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC);
359 	regmap_update_bits(drv_data->regmap,
360 			   REG_CTRL,
361 			   CTRL_RST_EN | CTRL_WDT_EN,
362 			   CTRL_RST_EN | CTRL_WDT_EN);
363 
364 	spin_unlock(&drv_data->lock);
365 
366 	return 0;
367 }
368 
369 static int atcwdt_stop(struct watchdog_device *wdt_dev)
370 {
371 	struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev);
372 
373 	spin_lock(&drv_data->lock);
374 	regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC);
375 	regmap_update_bits(drv_data->regmap,
376 			   REG_CTRL,
377 			   CTRL_RST_EN | CTRL_WDT_EN,
378 			   0);
379 	spin_unlock(&drv_data->lock);
380 
381 	return 0;
382 }
383 
384 static int atcwdt_restart(struct watchdog_device *wdt_dev,
385 			  unsigned long action, void *data)
386 {
387 	struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev);
388 
389 	atcwdt_set_timeout(wdt_dev, 0);
390 
391 	spin_lock(&drv_data->lock);
392 	regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC);
393 	regmap_update_bits(drv_data->regmap,
394 			   REG_CTRL,
395 			   CTRL_RST_EN | CTRL_WDT_EN,
396 			   CTRL_RST_EN | CTRL_WDT_EN);
397 	spin_unlock(&drv_data->lock);
398 
399 	return 0;
400 }
401 
402 static const struct watchdog_ops atcwdt_ops = {
403 	.owner = THIS_MODULE,
404 	.start = atcwdt_start,
405 	.stop = atcwdt_stop,
406 	.ping = atcwdt_ping,
407 	.set_timeout = atcwdt_set_timeout,
408 	.restart = atcwdt_restart,
409 };
410 
411 static int atcwdt_init_resource(struct platform_device *pdev,
412 				struct atcwdt_drv *drv_data)
413 {
414 	struct device *dev = &pdev->dev;
415 	void __iomem *base;
416 	const struct regmap_config cfg = {
417 		.name = "atcwdt",
418 		.reg_bits = 32,
419 		.val_bits = 32,
420 		.cache_type = REGCACHE_NONE,
421 		.reg_stride = 4,
422 		.max_register = REG_STATUS,
423 	};
424 
425 	base = devm_platform_ioremap_resource(pdev, 0);
426 	if (IS_ERR(base))
427 		return dev_err_probe(dev, PTR_ERR(base),
428 				     "Failed to ioremap I/O resource\n");
429 
430 	drv_data->regmap = devm_regmap_init_mmio(dev, base, &cfg);
431 	if (IS_ERR(drv_data->regmap))
432 		return dev_err_probe(dev, PTR_ERR(drv_data->regmap),
433 				     "Failed to create regmap\n");
434 
435 	return 0;
436 }
437 
438 static int atcwdt_enable_clk(struct atcwdt_drv *drv_data)
439 {
440 	struct device *dev = drv_data->wdt_dev.parent;
441 	unsigned int val;
442 	int clk_src;
443 
444 	drv_data->clk = devm_clk_get_enabled(dev, NULL);
445 	if (IS_ERR(drv_data->clk))
446 		return dev_err_probe(dev, PTR_ERR(drv_data->clk),
447 				     "Failed to get watchdog clock\n");
448 
449 	drv_data->clk_freq = clk_get_rate(drv_data->clk);
450 	if (!drv_data->clk_freq)
451 		return dev_err_probe(dev, -EINVAL,
452 				     "Failed to get clock rate\n");
453 
454 	clk_src = device_property_read_u32(dev, "andestech,clock-source", &val);
455 	drv_data->clk_src = (!clk_src && val != 0) ? CTRL_CLK_SEL_PCLK : 0;
456 
457 	return 0;
458 }
459 
460 static int atcwdt_init_wdt_device(struct device *dev,
461 				  struct atcwdt_drv *drv_data)
462 {
463 	struct watchdog_device *wdd = &drv_data->wdt_dev;
464 
465 	wdd->parent = dev;
466 	wdd->info = &atcwdt_info;
467 	wdd->ops = &atcwdt_ops;
468 	wdd->timeout = ATCWDT_TIMEOUT;
469 	wdd->min_timeout = 1;
470 
471 	watchdog_set_nowayout(wdd, nowayout);
472 	watchdog_set_drvdata(wdd, drv_data);
473 
474 	return 0;
475 }
476 
477 static void atcwdt_calc_max_timeout(struct atcwdt_drv *drv_data)
478 {
479 	unsigned char rst_idx = atcwdt_get_index(0xFF, TMR_RST);
480 	unsigned char int_idx = atcwdt_get_index(0xFF,
481 						 drv_data->int_timer_type);
482 
483 	drv_data->wdt_dev.max_timeout =
484 		((1U << rst_idx) + (1U << int_idx)) / drv_data->clk_freq;
485 }
486 
487 static int atcwdt_probe(struct platform_device *pdev)
488 {
489 	struct device *dev = &pdev->dev;
490 	struct atcwdt_drv *drv_data;
491 	int ret;
492 
493 	drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
494 	if (!drv_data)
495 		return -ENOMEM;
496 
497 	platform_set_drvdata(pdev, drv_data);
498 	spin_lock_init(&drv_data->lock);
499 
500 	ret = atcwdt_init_wdt_device(dev, drv_data);
501 	if (ret)
502 		return ret;
503 
504 	ret = atcwdt_init_resource(pdev, drv_data);
505 	if (ret)
506 		return ret;
507 
508 	ret = atcwdt_enable_clk(drv_data);
509 	if (ret)
510 		return ret;
511 
512 	ret = atcwdt_get_int_timer_type(drv_data);
513 	if (ret)
514 		return ret;
515 
516 	atcwdt_calc_max_timeout(drv_data);
517 
518 	ret = devm_watchdog_register_device(dev, &drv_data->wdt_dev);
519 
520 	return ret;
521 }
522 
523 static int atcwdt_suspend(struct device *dev)
524 {
525 	struct atcwdt_drv *drv_data = dev_get_drvdata(dev);
526 
527 	if (watchdog_active(&drv_data->wdt_dev)) {
528 		atcwdt_stop(&drv_data->wdt_dev);
529 		clk_disable_unprepare(drv_data->clk);
530 	}
531 
532 	return 0;
533 }
534 
535 static int atcwdt_resume(struct device *dev)
536 {
537 	struct atcwdt_drv *drv_data = dev_get_drvdata(dev);
538 	int ret = 0;
539 
540 	if (watchdog_active(&drv_data->wdt_dev)) {
541 		ret = clk_prepare_enable(drv_data->clk);
542 		if (ret)
543 			return ret;
544 		atcwdt_start(&drv_data->wdt_dev);
545 		atcwdt_ping(&drv_data->wdt_dev);
546 	}
547 
548 	return ret;
549 }
550 
551 static const struct of_device_id atcwdt_match[] = {
552 	{ .compatible = "andestech,ae350-wdt" },
553 	{ /* sentinel */ },
554 };
555 MODULE_DEVICE_TABLE(of, atcwdt_match);
556 
557 static DEFINE_SIMPLE_DEV_PM_OPS(atcwdt_pm_ops, atcwdt_suspend, atcwdt_resume);
558 
559 static struct platform_driver atcwdt_driver = {
560 	.probe = atcwdt_probe,
561 	.driver = {
562 		.name = DRV_NAME,
563 		.of_match_table = atcwdt_match,
564 		.pm = pm_sleep_ptr(&atcwdt_pm_ops),
565 	},
566 };
567 
568 module_platform_driver(atcwdt_driver);
569 
570 module_param(timeout, uint, 0);
571 MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default="
572 		 __MODULE_STRING(ATCWDT_TIMEOUT) ")");
573 
574 module_param(nowayout, bool, 0);
575 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
576 		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
577 
578 MODULE_LICENSE("GPL");
579 MODULE_AUTHOR("CL Wang <cl634@andestech.com>");
580 MODULE_DESCRIPTION("Andes ATCWDT200 Watchdog timer driver");
581