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