1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2024 ROHM Semiconductors 4 * 5 * ROHM BD96801 watchdog driver 6 */ 7 8 #include <linux/interrupt.h> 9 #include <linux/kernel.h> 10 #include <linux/mfd/rohm-bd96801.h> 11 #include <linux/mfd/rohm-generic.h> 12 #include <linux/module.h> 13 #include <linux/of.h> 14 #include <linux/platform_device.h> 15 #include <linux/reboot.h> 16 #include <linux/regmap.h> 17 #include <linux/watchdog.h> 18 19 static bool nowayout; 20 module_param(nowayout, bool, 0); 21 MODULE_PARM_DESC(nowayout, 22 "Watchdog cannot be stopped once started (default=\"false\")"); 23 24 #define BD96801_WD_TMO_SHORT_MASK 0x70 25 #define BD96801_WD_RATIO_MASK 0x3 26 #define BD96801_WD_TYPE_MASK 0x4 27 #define BD96801_WD_TYPE_SLOW 0x4 28 #define BD96801_WD_TYPE_WIN 0x0 29 30 #define BD96801_WD_EN_MASK 0x3 31 #define BD96801_WD_IF_EN 0x1 32 #define BD96801_WD_QA_EN 0x2 33 #define BD96801_WD_DISABLE 0x0 34 35 #define BD96801_WD_ASSERT_MASK 0x8 36 #define BD96801_WD_ASSERT_RST 0x8 37 #define BD96801_WD_ASSERT_IRQ 0x0 38 39 #define BD96801_WD_FEED_MASK 0x1 40 #define BD96801_WD_FEED 0x1 41 42 /* 1.1 mS */ 43 #define FASTNG_MIN 11 44 #define FASTNG_MAX_US (100 * FASTNG_MIN << 7) 45 #define SLOWNG_MAX_US (16 * FASTNG_MAX_US) 46 47 #define BD96801_WDT_DEFAULT_MARGIN_MS 1843 48 /* Unit is seconds */ 49 #define DEFAULT_TIMEOUT 30 50 51 /* 52 * BD96801 WDG supports window mode so the TMO consists of SHORT and LONG 53 * timeout values. SHORT time is meaningful only in window mode where feeding 54 * period shorter than SHORT would be an error. LONG time is used to detect if 55 * feeding is not occurring within given time limit (SoC SW hangs). The LONG 56 * timeout time is a multiple of (2, 4, 8 or 16 times) the SHORT timeout. 57 */ 58 59 struct wdtbd96801 { 60 struct device *dev; 61 struct regmap *regmap; 62 struct watchdog_device wdt; 63 }; 64 65 static int bd96801_wdt_ping(struct watchdog_device *wdt) 66 { 67 struct wdtbd96801 *w = watchdog_get_drvdata(wdt); 68 69 return regmap_update_bits(w->regmap, BD96801_REG_WD_FEED, 70 BD96801_WD_FEED_MASK, BD96801_WD_FEED); 71 } 72 73 static int bd96801_wdt_start(struct watchdog_device *wdt) 74 { 75 struct wdtbd96801 *w = watchdog_get_drvdata(wdt); 76 77 return regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, 78 BD96801_WD_EN_MASK, BD96801_WD_IF_EN); 79 } 80 81 static int bd96801_wdt_stop(struct watchdog_device *wdt) 82 { 83 struct wdtbd96801 *w = watchdog_get_drvdata(wdt); 84 85 return regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, 86 BD96801_WD_EN_MASK, BD96801_WD_DISABLE); 87 } 88 89 static const struct watchdog_info bd96801_wdt_info = { 90 .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | 91 WDIOF_SETTIMEOUT, 92 .identity = "BD96801 Watchdog", 93 }; 94 95 static const struct watchdog_ops bd96801_wdt_ops = { 96 .start = bd96801_wdt_start, 97 .stop = bd96801_wdt_stop, 98 .ping = bd96801_wdt_ping, 99 }; 100 101 static int find_closest_fast(unsigned int target, int *sel, unsigned int *val) 102 { 103 unsigned int window = FASTNG_MIN; 104 int i; 105 106 for (i = 0; i < 8 && window < target; i++) 107 window <<= 1; 108 109 if (i == 8) 110 return -EINVAL; 111 112 *val = window; 113 *sel = i; 114 115 return 0; 116 } 117 118 static int find_closest_slow_by_fast(unsigned int fast_val, unsigned int *target, 119 int *slowsel) 120 { 121 static const int multipliers[] = {2, 4, 8, 16}; 122 int sel; 123 124 for (sel = 0; sel < ARRAY_SIZE(multipliers) && 125 multipliers[sel] * fast_val < *target; sel++) 126 ; 127 128 if (sel == ARRAY_SIZE(multipliers)) 129 return -EINVAL; 130 131 *slowsel = sel; 132 *target = multipliers[sel] * fast_val; 133 134 return 0; 135 } 136 137 static int find_closest_slow(unsigned int *target, int *slow_sel, int *fast_sel) 138 { 139 static const int multipliers[] = {2, 4, 8, 16}; 140 unsigned int window = FASTNG_MIN; 141 unsigned int val = 0; 142 int i, j; 143 144 for (i = 0; i < 8; i++) { 145 for (j = 0; j < ARRAY_SIZE(multipliers); j++) { 146 unsigned int slow; 147 148 slow = window * multipliers[j]; 149 if (slow >= *target && (!val || slow < val)) { 150 val = slow; 151 *fast_sel = i; 152 *slow_sel = j; 153 } 154 } 155 window <<= 1; 156 } 157 if (!val) 158 return -EINVAL; 159 160 *target = val; 161 162 return 0; 163 } 164 165 static int bd96801_set_wdt_mode(struct wdtbd96801 *w, unsigned int hw_margin, 166 unsigned int hw_margin_min) 167 { 168 int fastng, slowng, type, ret, reg, mask; 169 struct device *dev = w->dev; 170 171 172 if (hw_margin_min * 1000 > FASTNG_MAX_US) { 173 dev_err(dev, "Unsupported fast timeout %u uS [max %u]\n", 174 hw_margin_min * 1000, FASTNG_MAX_US); 175 176 return -EINVAL; 177 } 178 179 if (hw_margin * 1000 > SLOWNG_MAX_US) { 180 dev_err(dev, "Unsupported slow timeout %u uS [max %u]\n", 181 hw_margin * 1000, SLOWNG_MAX_US); 182 183 return -EINVAL; 184 } 185 186 /* 187 * Convert to 100uS to guarantee reasonable timeouts fit in 188 * 32bit maintaining also a decent accuracy. 189 */ 190 hw_margin *= 10; 191 hw_margin_min *= 10; 192 193 if (hw_margin_min) { 194 unsigned int min; 195 196 type = BD96801_WD_TYPE_WIN; 197 dev_dbg(dev, "Setting type WINDOW 0x%x\n", type); 198 ret = find_closest_fast(hw_margin_min, &fastng, &min); 199 if (ret) 200 return ret; 201 202 ret = find_closest_slow_by_fast(min, &hw_margin, &slowng); 203 if (ret) { 204 dev_err(dev, 205 "can't support slow timeout %u uS using fast %u uS. [max slow %u uS]\n", 206 hw_margin * 100, min * 100, min * 100 * 16); 207 208 return ret; 209 } 210 w->wdt.min_hw_heartbeat_ms = min / 10; 211 } else { 212 type = BD96801_WD_TYPE_SLOW; 213 dev_dbg(dev, "Setting type SLOW 0x%x\n", type); 214 ret = find_closest_slow(&hw_margin, &slowng, &fastng); 215 if (ret) 216 return ret; 217 } 218 219 w->wdt.max_hw_heartbeat_ms = hw_margin / 10; 220 221 fastng = FIELD_PREP(BD96801_WD_TMO_SHORT_MASK, fastng); 222 223 reg = slowng | fastng; 224 mask = BD96801_WD_RATIO_MASK | BD96801_WD_TMO_SHORT_MASK; 225 ret = regmap_update_bits(w->regmap, BD96801_REG_WD_TMO, 226 mask, reg); 227 if (ret) 228 return ret; 229 230 ret = regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, 231 BD96801_WD_TYPE_MASK, type); 232 233 return ret; 234 } 235 236 static int bd96801_set_heartbeat_from_hw(struct wdtbd96801 *w, 237 unsigned int conf_reg) 238 { 239 int ret; 240 unsigned int val, sel, fast; 241 242 /* 243 * The BD96801 supports a somewhat peculiar QA-mode, which we do not 244 * support in this driver. If the QA-mode is enabled then we just 245 * warn and bail-out. 246 */ 247 if ((conf_reg & BD96801_WD_EN_MASK) != BD96801_WD_IF_EN) { 248 dev_err(w->dev, "watchdog set to Q&A mode - exiting\n"); 249 return -EINVAL; 250 } 251 252 ret = regmap_read(w->regmap, BD96801_REG_WD_TMO, &val); 253 if (ret) 254 return ret; 255 256 sel = FIELD_GET(BD96801_WD_TMO_SHORT_MASK, val); 257 fast = FASTNG_MIN << sel; 258 259 sel = (val & BD96801_WD_RATIO_MASK) + 1; 260 w->wdt.max_hw_heartbeat_ms = (fast << sel) / USEC_PER_MSEC; 261 262 if ((conf_reg & BD96801_WD_TYPE_MASK) == BD96801_WD_TYPE_WIN) 263 w->wdt.min_hw_heartbeat_ms = fast / USEC_PER_MSEC; 264 265 return 0; 266 } 267 268 static int init_wdg_hw(struct wdtbd96801 *w) 269 { 270 u32 hw_margin[2]; 271 int count, ret; 272 u32 hw_margin_max = BD96801_WDT_DEFAULT_MARGIN_MS, hw_margin_min = 0; 273 274 count = device_property_count_u32(w->dev->parent, "rohm,hw-timeout-ms"); 275 if (count < 0 && count != -EINVAL) 276 return count; 277 278 if (count > 0) { 279 if (count > ARRAY_SIZE(hw_margin)) 280 return -EINVAL; 281 282 ret = device_property_read_u32_array(w->dev->parent, 283 "rohm,hw-timeout-ms", 284 &hw_margin[0], count); 285 if (ret < 0) 286 return ret; 287 288 if (count == 1) 289 hw_margin_max = hw_margin[0]; 290 291 if (count == 2) { 292 if (hw_margin[1] > hw_margin[0]) { 293 hw_margin_max = hw_margin[1]; 294 hw_margin_min = hw_margin[0]; 295 } else { 296 hw_margin_max = hw_margin[0]; 297 hw_margin_min = hw_margin[1]; 298 } 299 } 300 } 301 302 ret = bd96801_set_wdt_mode(w, hw_margin_max, hw_margin_min); 303 if (ret) 304 return ret; 305 306 ret = device_property_match_string(w->dev->parent, "rohm,wdg-action", 307 "prstb"); 308 if (ret >= 0) { 309 ret = regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, 310 BD96801_WD_ASSERT_MASK, 311 BD96801_WD_ASSERT_RST); 312 return ret; 313 } 314 315 ret = device_property_match_string(w->dev->parent, "rohm,wdg-action", 316 "intb-only"); 317 if (ret >= 0) { 318 ret = regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, 319 BD96801_WD_ASSERT_MASK, 320 BD96801_WD_ASSERT_IRQ); 321 return ret; 322 } 323 324 return 0; 325 } 326 327 static irqreturn_t bd96801_irq_hnd(int irq, void *data) 328 { 329 emergency_restart(); 330 331 return IRQ_NONE; 332 } 333 334 static int bd96801_wdt_probe(struct platform_device *pdev) 335 { 336 struct wdtbd96801 *w; 337 int ret, irq; 338 unsigned int val; 339 340 w = devm_kzalloc(&pdev->dev, sizeof(*w), GFP_KERNEL); 341 if (!w) 342 return -ENOMEM; 343 344 w->regmap = dev_get_regmap(pdev->dev.parent, NULL); 345 w->dev = &pdev->dev; 346 347 w->wdt.info = &bd96801_wdt_info; 348 w->wdt.ops = &bd96801_wdt_ops; 349 w->wdt.parent = pdev->dev.parent; 350 w->wdt.timeout = DEFAULT_TIMEOUT; 351 watchdog_set_drvdata(&w->wdt, w); 352 353 ret = regmap_read(w->regmap, BD96801_REG_WD_CONF, &val); 354 if (ret) 355 return dev_err_probe(&pdev->dev, ret, 356 "Failed to get the watchdog state\n"); 357 358 /* 359 * If the WDG is already enabled we assume it is configured by boot. 360 * In this case we just update the hw-timeout based on values set to 361 * the timeout / mode registers and leave the hardware configs 362 * untouched. 363 */ 364 if ((val & BD96801_WD_EN_MASK) != BD96801_WD_DISABLE) { 365 dev_dbg(&pdev->dev, "watchdog was running during probe\n"); 366 ret = bd96801_set_heartbeat_from_hw(w, val); 367 if (ret) 368 return ret; 369 370 set_bit(WDOG_HW_RUNNING, &w->wdt.status); 371 } else { 372 /* If WDG is not running so we will initializate it */ 373 ret = init_wdg_hw(w); 374 if (ret) 375 return ret; 376 } 377 378 dev_dbg(w->dev, "heartbeat set to %u - %u\n", 379 w->wdt.min_hw_heartbeat_ms, w->wdt.max_hw_heartbeat_ms); 380 381 watchdog_init_timeout(&w->wdt, 0, pdev->dev.parent); 382 watchdog_set_nowayout(&w->wdt, nowayout); 383 watchdog_stop_on_reboot(&w->wdt); 384 385 irq = platform_get_irq_byname(pdev, "bd96801-wdg"); 386 if (irq > 0) { 387 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 388 bd96801_irq_hnd, 389 IRQF_ONESHOT, "bd96801-wdg", 390 NULL); 391 if (ret) 392 return dev_err_probe(&pdev->dev, ret, 393 "Failed to register IRQ\n"); 394 } 395 396 return devm_watchdog_register_device(&pdev->dev, &w->wdt); 397 } 398 399 static const struct platform_device_id bd96801_wdt_id[] = { 400 { "bd96801-wdt", }, 401 { } 402 }; 403 MODULE_DEVICE_TABLE(platform, bd96801_wdt_id); 404 405 static struct platform_driver bd96801_wdt = { 406 .driver = { 407 .name = "bd96801-wdt" 408 }, 409 .probe = bd96801_wdt_probe, 410 .id_table = bd96801_wdt_id, 411 }; 412 module_platform_driver(bd96801_wdt); 413 414 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 415 MODULE_DESCRIPTION("BD96801 watchdog driver"); 416 MODULE_LICENSE("GPL"); 417