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 */
atcwdt_get_index(unsigned char index,enum timer_type timer_type)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 */
atcwdt_get_clock_period(long long tick,enum timer_type timer_type,unsigned char * index)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 */
atcwdt_get_timeout_params(struct atcwdt_drv * drv_data,unsigned int timeout,unsigned char * int_timer_params,unsigned char * rst_timer_params)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 -EBUSY.
264 *
265 * Returns: 0 on success or negative error code on failure.
266 */
atcwdt_get_int_timer_type(struct atcwdt_drv * drv_data)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 dev_err_probe(dev, -EBUSY,
278 "Watchdog is enabled, cannot detect timer type\n");
279 }
280
281 /*
282 * Configures the IntTime field with the maximum mask value
283 * (CTRL_INT_TIME_MSK), reads its value from the control register
284 * to identify the maximum writable bits.
285 */
286 regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC);
287 regmap_write(drv_data->regmap, REG_CTRL, CTRL_INT_TIME_MSK);
288 regmap_read(drv_data->regmap, REG_CTRL, &val);
289 spin_unlock(&drv_data->lock);
290
291 val = CTRL_INT_TIME_GET(val);
292 switch (val) {
293 case 7:
294 drv_data->int_timer_type = TMR_INT_16;
295 break;
296 case 15:
297 drv_data->int_timer_type = TMR_INT_32;
298 break;
299 default:
300 drv_data->int_timer_type = TMR_UNKNOWN;
301 ret = dev_err_probe(dev, -ENODEV,
302 "Failed to detect interrupt timer type\n");
303 }
304
305 return ret;
306 }
307
atcwdt_ping(struct watchdog_device * wdt_dev)308 static int atcwdt_ping(struct watchdog_device *wdt_dev)
309 {
310 struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev);
311
312 spin_lock(&drv_data->lock);
313 regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC);
314 regmap_write(drv_data->regmap, REG_RESTART, RESTART_MAGIC);
315 regmap_update_bits(drv_data->regmap, REG_STATUS, STATUS_INT_EXPIRED,
316 STATUS_INT_EXPIRED);
317 spin_unlock(&drv_data->lock);
318
319 return 0;
320 }
321
atcwdt_set_timeout(struct watchdog_device * wdt_dev,unsigned int timeout)322 static int atcwdt_set_timeout(struct watchdog_device *wdt_dev,
323 unsigned int timeout)
324 {
325 struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev);
326 unsigned int value;
327 unsigned char rst_val;
328 unsigned char int_val;
329
330 wdt_dev->timeout = timeout;
331 atcwdt_get_timeout_params(drv_data, timeout, &int_val, &rst_val);
332
333 spin_lock(&drv_data->lock);
334 regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC);
335
336 value = CTRL_RST_TIME_SET(rst_val) |
337 CTRL_INT_TIME_SET(int_val) |
338 CTRL_CLK_SEL_SET(drv_data->clk_src);
339 regmap_update_bits(drv_data->regmap,
340 REG_CTRL,
341 CTRL_RST_TIME_MSK |
342 CTRL_INT_TIME_MSK |
343 CTRL_CLK_SEL,
344 value);
345
346 spin_unlock(&drv_data->lock);
347 atcwdt_ping(wdt_dev);
348
349 return 0;
350 }
351
atcwdt_start(struct watchdog_device * wdt_dev)352 static int atcwdt_start(struct watchdog_device *wdt_dev)
353 {
354 struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev);
355
356 atcwdt_set_timeout(wdt_dev, wdt_dev->timeout);
357
358 spin_lock(&drv_data->lock);
359 regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC);
360 regmap_update_bits(drv_data->regmap,
361 REG_CTRL,
362 CTRL_RST_EN | CTRL_WDT_EN,
363 CTRL_RST_EN | CTRL_WDT_EN);
364
365 spin_unlock(&drv_data->lock);
366
367 return 0;
368 }
369
atcwdt_stop(struct watchdog_device * wdt_dev)370 static int atcwdt_stop(struct watchdog_device *wdt_dev)
371 {
372 struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev);
373
374 spin_lock(&drv_data->lock);
375 regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC);
376 regmap_update_bits(drv_data->regmap,
377 REG_CTRL,
378 CTRL_RST_EN | CTRL_WDT_EN,
379 0);
380 spin_unlock(&drv_data->lock);
381
382 return 0;
383 }
384
atcwdt_restart(struct watchdog_device * wdt_dev,unsigned long action,void * data)385 static int atcwdt_restart(struct watchdog_device *wdt_dev,
386 unsigned long action, void *data)
387 {
388 struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev);
389
390 atcwdt_set_timeout(wdt_dev, 0);
391
392 spin_lock(&drv_data->lock);
393 regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC);
394 regmap_update_bits(drv_data->regmap,
395 REG_CTRL,
396 CTRL_RST_EN | CTRL_WDT_EN,
397 CTRL_RST_EN | CTRL_WDT_EN);
398 spin_unlock(&drv_data->lock);
399
400 return 0;
401 }
402
403 static const struct watchdog_ops atcwdt_ops = {
404 .owner = THIS_MODULE,
405 .start = atcwdt_start,
406 .stop = atcwdt_stop,
407 .ping = atcwdt_ping,
408 .set_timeout = atcwdt_set_timeout,
409 .restart = atcwdt_restart,
410 };
411
atcwdt_init_resource(struct platform_device * pdev,struct atcwdt_drv * drv_data)412 static int atcwdt_init_resource(struct platform_device *pdev,
413 struct atcwdt_drv *drv_data)
414 {
415 struct device *dev = &pdev->dev;
416 void __iomem *base;
417 const struct regmap_config cfg = {
418 .name = "atcwdt",
419 .reg_bits = 32,
420 .val_bits = 32,
421 .cache_type = REGCACHE_NONE,
422 .reg_stride = 4,
423 .max_register = REG_STATUS,
424 };
425
426 base = devm_platform_ioremap_resource(pdev, 0);
427 if (IS_ERR(base))
428 return dev_err_probe(dev, PTR_ERR(base),
429 "Failed to ioremap I/O resource\n");
430
431 drv_data->regmap = devm_regmap_init_mmio(dev, base, &cfg);
432 if (IS_ERR(drv_data->regmap))
433 return dev_err_probe(dev, PTR_ERR(drv_data->regmap),
434 "Failed to create regmap\n");
435
436 return 0;
437 }
438
atcwdt_enable_clk(struct atcwdt_drv * drv_data)439 static int atcwdt_enable_clk(struct atcwdt_drv *drv_data)
440 {
441 struct device *dev = drv_data->wdt_dev.parent;
442 unsigned int val;
443 int clk_src;
444
445 drv_data->clk = devm_clk_get_enabled(dev, NULL);
446 if (IS_ERR(drv_data->clk))
447 return dev_err_probe(dev, PTR_ERR(drv_data->clk),
448 "Failed to get watchdog clock\n");
449
450 drv_data->clk_freq = clk_get_rate(drv_data->clk);
451 if (!drv_data->clk_freq)
452 return dev_err_probe(dev, -EINVAL,
453 "Failed to get clock rate\n");
454
455 clk_src = device_property_read_u32(dev, "andestech,clock-source", &val);
456 drv_data->clk_src = (!clk_src && val != 0) ? CTRL_CLK_SEL_PCLK : 0;
457
458 return 0;
459 }
460
atcwdt_init_wdt_device(struct device * dev,struct atcwdt_drv * drv_data)461 static int atcwdt_init_wdt_device(struct device *dev,
462 struct atcwdt_drv *drv_data)
463 {
464 struct watchdog_device *wdd = &drv_data->wdt_dev;
465
466 wdd->parent = dev;
467 wdd->info = &atcwdt_info;
468 wdd->ops = &atcwdt_ops;
469 wdd->timeout = ATCWDT_TIMEOUT;
470 wdd->min_timeout = 1;
471
472 watchdog_set_nowayout(wdd, nowayout);
473 watchdog_set_drvdata(wdd, drv_data);
474
475 return 0;
476 }
477
atcwdt_calc_max_timeout(struct atcwdt_drv * drv_data)478 static void atcwdt_calc_max_timeout(struct atcwdt_drv *drv_data)
479 {
480 unsigned char rst_idx = atcwdt_get_index(0xFF, TMR_RST);
481 unsigned char int_idx = atcwdt_get_index(0xFF,
482 drv_data->int_timer_type);
483
484 drv_data->wdt_dev.max_timeout =
485 ((1U << rst_idx) + (1U << int_idx)) / drv_data->clk_freq;
486 }
487
atcwdt_probe(struct platform_device * pdev)488 static int atcwdt_probe(struct platform_device *pdev)
489 {
490 struct device *dev = &pdev->dev;
491 struct atcwdt_drv *drv_data;
492 int ret;
493
494 drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
495 if (!drv_data)
496 return -ENOMEM;
497
498 platform_set_drvdata(pdev, drv_data);
499 spin_lock_init(&drv_data->lock);
500
501 ret = atcwdt_init_wdt_device(dev, drv_data);
502 if (ret)
503 return ret;
504
505 ret = atcwdt_init_resource(pdev, drv_data);
506 if (ret)
507 return ret;
508
509 ret = atcwdt_enable_clk(drv_data);
510 if (ret)
511 return ret;
512
513 ret = atcwdt_get_int_timer_type(drv_data);
514 if (ret)
515 return ret;
516
517 atcwdt_calc_max_timeout(drv_data);
518
519 ret = devm_watchdog_register_device(dev, &drv_data->wdt_dev);
520
521 return ret;
522 }
523
atcwdt_suspend(struct device * dev)524 static int atcwdt_suspend(struct device *dev)
525 {
526 struct atcwdt_drv *drv_data = dev_get_drvdata(dev);
527
528 if (watchdog_active(&drv_data->wdt_dev)) {
529 atcwdt_stop(&drv_data->wdt_dev);
530 clk_disable_unprepare(drv_data->clk);
531 }
532
533 return 0;
534 }
535
atcwdt_resume(struct device * dev)536 static int atcwdt_resume(struct device *dev)
537 {
538 struct atcwdt_drv *drv_data = dev_get_drvdata(dev);
539 int ret = 0;
540
541 if (watchdog_active(&drv_data->wdt_dev)) {
542 ret = clk_prepare_enable(drv_data->clk);
543 if (ret)
544 return ret;
545 atcwdt_start(&drv_data->wdt_dev);
546 atcwdt_ping(&drv_data->wdt_dev);
547 }
548
549 return ret;
550 }
551
552 static const struct of_device_id atcwdt_match[] = {
553 { .compatible = "andestech,ae350-wdt" },
554 { /* sentinel */ },
555 };
556 MODULE_DEVICE_TABLE(of, atcwdt_match);
557
558 static DEFINE_SIMPLE_DEV_PM_OPS(atcwdt_pm_ops, atcwdt_suspend, atcwdt_resume);
559
560 static struct platform_driver atcwdt_driver = {
561 .probe = atcwdt_probe,
562 .driver = {
563 .name = DRV_NAME,
564 .of_match_table = atcwdt_match,
565 .pm = pm_sleep_ptr(&atcwdt_pm_ops),
566 },
567 };
568
569 module_platform_driver(atcwdt_driver);
570
571 module_param(timeout, uint, 0);
572 MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default="
573 __MODULE_STRING(ATCWDT_TIMEOUT) ")");
574
575 module_param(nowayout, bool, 0);
576 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
577 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
578
579 MODULE_LICENSE("GPL");
580 MODULE_AUTHOR("CL Wang <cl634@andestech.com>");
581 MODULE_DESCRIPTION("Andes ATCWDT200 Watchdog timer driver");
582