1 /* 2 * Copyright 2010-2011 Picochip Ltd., Jamie Iles 3 * http://www.picochip.com 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License 7 * as published by the Free Software Foundation; either version 8 * 2 of the License, or (at your option) any later version. 9 * 10 * This file implements a driver for the Synopsys DesignWare watchdog device 11 * in the many subsystems. The watchdog has 16 different timeout periods 12 * and these are a function of the input clock frequency. 13 * 14 * The DesignWare watchdog cannot be stopped once it has been started so we 15 * do not implement a stop function. The watchdog core will continue to send 16 * heartbeat requests after the watchdog device has been closed. 17 */ 18 19 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 20 21 #include <linux/bitops.h> 22 #include <linux/clk.h> 23 #include <linux/delay.h> 24 #include <linux/err.h> 25 #include <linux/io.h> 26 #include <linux/kernel.h> 27 #include <linux/module.h> 28 #include <linux/moduleparam.h> 29 #include <linux/of.h> 30 #include <linux/pm.h> 31 #include <linux/platform_device.h> 32 #include <linux/reset.h> 33 #include <linux/watchdog.h> 34 35 #define WDOG_CONTROL_REG_OFFSET 0x00 36 #define WDOG_CONTROL_REG_WDT_EN_MASK 0x01 37 #define WDOG_CONTROL_REG_RESP_MODE_MASK 0x02 38 #define WDOG_TIMEOUT_RANGE_REG_OFFSET 0x04 39 #define WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT 4 40 #define WDOG_CURRENT_COUNT_REG_OFFSET 0x08 41 #define WDOG_COUNTER_RESTART_REG_OFFSET 0x0c 42 #define WDOG_COUNTER_RESTART_KICK_VALUE 0x76 43 44 /* The maximum TOP (timeout period) value that can be set in the watchdog. */ 45 #define DW_WDT_MAX_TOP 15 46 47 #define DW_WDT_DEFAULT_SECONDS 30 48 49 static bool nowayout = WATCHDOG_NOWAYOUT; 50 module_param(nowayout, bool, 0); 51 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " 52 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 53 54 struct dw_wdt { 55 void __iomem *regs; 56 struct clk *clk; 57 unsigned long rate; 58 struct watchdog_device wdd; 59 struct reset_control *rst; 60 /* Save/restore */ 61 u32 control; 62 u32 timeout; 63 }; 64 65 #define to_dw_wdt(wdd) container_of(wdd, struct dw_wdt, wdd) 66 67 static inline int dw_wdt_is_enabled(struct dw_wdt *dw_wdt) 68 { 69 return readl(dw_wdt->regs + WDOG_CONTROL_REG_OFFSET) & 70 WDOG_CONTROL_REG_WDT_EN_MASK; 71 } 72 73 static inline int dw_wdt_top_in_seconds(struct dw_wdt *dw_wdt, unsigned top) 74 { 75 /* 76 * There are 16 possible timeout values in 0..15 where the number of 77 * cycles is 2 ^ (16 + i) and the watchdog counts down. 78 */ 79 return (1U << (16 + top)) / dw_wdt->rate; 80 } 81 82 static int dw_wdt_get_top(struct dw_wdt *dw_wdt) 83 { 84 int top = readl(dw_wdt->regs + WDOG_TIMEOUT_RANGE_REG_OFFSET) & 0xF; 85 86 return dw_wdt_top_in_seconds(dw_wdt, top); 87 } 88 89 static int dw_wdt_ping(struct watchdog_device *wdd) 90 { 91 struct dw_wdt *dw_wdt = to_dw_wdt(wdd); 92 93 writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt->regs + 94 WDOG_COUNTER_RESTART_REG_OFFSET); 95 96 return 0; 97 } 98 99 static int dw_wdt_set_timeout(struct watchdog_device *wdd, unsigned int top_s) 100 { 101 struct dw_wdt *dw_wdt = to_dw_wdt(wdd); 102 int i, top_val = DW_WDT_MAX_TOP; 103 104 /* 105 * Iterate over the timeout values until we find the closest match. We 106 * always look for >=. 107 */ 108 for (i = 0; i <= DW_WDT_MAX_TOP; ++i) 109 if (dw_wdt_top_in_seconds(dw_wdt, i) >= top_s) { 110 top_val = i; 111 break; 112 } 113 114 /* 115 * Set the new value in the watchdog. Some versions of dw_wdt 116 * have have TOPINIT in the TIMEOUT_RANGE register (as per 117 * CP_WDT_DUAL_TOP in WDT_COMP_PARAMS_1). On those we 118 * effectively get a pat of the watchdog right here. 119 */ 120 writel(top_val | top_val << WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT, 121 dw_wdt->regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); 122 123 wdd->timeout = dw_wdt_top_in_seconds(dw_wdt, top_val); 124 125 return 0; 126 } 127 128 static void dw_wdt_arm_system_reset(struct dw_wdt *dw_wdt) 129 { 130 u32 val = readl(dw_wdt->regs + WDOG_CONTROL_REG_OFFSET); 131 132 /* Disable interrupt mode; always perform system reset. */ 133 val &= ~WDOG_CONTROL_REG_RESP_MODE_MASK; 134 /* Enable watchdog. */ 135 val |= WDOG_CONTROL_REG_WDT_EN_MASK; 136 writel(val, dw_wdt->regs + WDOG_CONTROL_REG_OFFSET); 137 } 138 139 static int dw_wdt_start(struct watchdog_device *wdd) 140 { 141 struct dw_wdt *dw_wdt = to_dw_wdt(wdd); 142 143 dw_wdt_set_timeout(wdd, wdd->timeout); 144 dw_wdt_arm_system_reset(dw_wdt); 145 146 return 0; 147 } 148 149 static int dw_wdt_stop(struct watchdog_device *wdd) 150 { 151 struct dw_wdt *dw_wdt = to_dw_wdt(wdd); 152 153 if (!dw_wdt->rst) { 154 set_bit(WDOG_HW_RUNNING, &wdd->status); 155 return 0; 156 } 157 158 reset_control_assert(dw_wdt->rst); 159 reset_control_deassert(dw_wdt->rst); 160 161 return 0; 162 } 163 164 static int dw_wdt_restart(struct watchdog_device *wdd, 165 unsigned long action, void *data) 166 { 167 struct dw_wdt *dw_wdt = to_dw_wdt(wdd); 168 169 writel(0, dw_wdt->regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); 170 if (dw_wdt_is_enabled(dw_wdt)) 171 writel(WDOG_COUNTER_RESTART_KICK_VALUE, 172 dw_wdt->regs + WDOG_COUNTER_RESTART_REG_OFFSET); 173 else 174 dw_wdt_arm_system_reset(dw_wdt); 175 176 /* wait for reset to assert... */ 177 mdelay(500); 178 179 return 0; 180 } 181 182 static unsigned int dw_wdt_get_timeleft(struct watchdog_device *wdd) 183 { 184 struct dw_wdt *dw_wdt = to_dw_wdt(wdd); 185 186 return readl(dw_wdt->regs + WDOG_CURRENT_COUNT_REG_OFFSET) / 187 dw_wdt->rate; 188 } 189 190 static const struct watchdog_info dw_wdt_ident = { 191 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | 192 WDIOF_MAGICCLOSE, 193 .identity = "Synopsys DesignWare Watchdog", 194 }; 195 196 static const struct watchdog_ops dw_wdt_ops = { 197 .owner = THIS_MODULE, 198 .start = dw_wdt_start, 199 .stop = dw_wdt_stop, 200 .ping = dw_wdt_ping, 201 .set_timeout = dw_wdt_set_timeout, 202 .get_timeleft = dw_wdt_get_timeleft, 203 .restart = dw_wdt_restart, 204 }; 205 206 #ifdef CONFIG_PM_SLEEP 207 static int dw_wdt_suspend(struct device *dev) 208 { 209 struct dw_wdt *dw_wdt = dev_get_drvdata(dev); 210 211 dw_wdt->control = readl(dw_wdt->regs + WDOG_CONTROL_REG_OFFSET); 212 dw_wdt->timeout = readl(dw_wdt->regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); 213 214 clk_disable_unprepare(dw_wdt->clk); 215 216 return 0; 217 } 218 219 static int dw_wdt_resume(struct device *dev) 220 { 221 struct dw_wdt *dw_wdt = dev_get_drvdata(dev); 222 int err = clk_prepare_enable(dw_wdt->clk); 223 224 if (err) 225 return err; 226 227 writel(dw_wdt->timeout, dw_wdt->regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); 228 writel(dw_wdt->control, dw_wdt->regs + WDOG_CONTROL_REG_OFFSET); 229 230 dw_wdt_ping(&dw_wdt->wdd); 231 232 return 0; 233 } 234 #endif /* CONFIG_PM_SLEEP */ 235 236 static SIMPLE_DEV_PM_OPS(dw_wdt_pm_ops, dw_wdt_suspend, dw_wdt_resume); 237 238 static int dw_wdt_drv_probe(struct platform_device *pdev) 239 { 240 struct device *dev = &pdev->dev; 241 struct watchdog_device *wdd; 242 struct dw_wdt *dw_wdt; 243 struct resource *mem; 244 int ret; 245 246 dw_wdt = devm_kzalloc(dev, sizeof(*dw_wdt), GFP_KERNEL); 247 if (!dw_wdt) 248 return -ENOMEM; 249 250 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 251 dw_wdt->regs = devm_ioremap_resource(dev, mem); 252 if (IS_ERR(dw_wdt->regs)) 253 return PTR_ERR(dw_wdt->regs); 254 255 dw_wdt->clk = devm_clk_get(dev, NULL); 256 if (IS_ERR(dw_wdt->clk)) 257 return PTR_ERR(dw_wdt->clk); 258 259 ret = clk_prepare_enable(dw_wdt->clk); 260 if (ret) 261 return ret; 262 263 dw_wdt->rate = clk_get_rate(dw_wdt->clk); 264 if (dw_wdt->rate == 0) { 265 ret = -EINVAL; 266 goto out_disable_clk; 267 } 268 269 dw_wdt->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); 270 if (IS_ERR(dw_wdt->rst)) { 271 ret = PTR_ERR(dw_wdt->rst); 272 goto out_disable_clk; 273 } 274 275 reset_control_deassert(dw_wdt->rst); 276 277 wdd = &dw_wdt->wdd; 278 wdd->info = &dw_wdt_ident; 279 wdd->ops = &dw_wdt_ops; 280 wdd->min_timeout = 1; 281 wdd->max_hw_heartbeat_ms = 282 dw_wdt_top_in_seconds(dw_wdt, DW_WDT_MAX_TOP) * 1000; 283 wdd->parent = dev; 284 285 watchdog_set_drvdata(wdd, dw_wdt); 286 watchdog_set_nowayout(wdd, nowayout); 287 watchdog_init_timeout(wdd, 0, dev); 288 289 /* 290 * If the watchdog is already running, use its already configured 291 * timeout. Otherwise use the default or the value provided through 292 * devicetree. 293 */ 294 if (dw_wdt_is_enabled(dw_wdt)) { 295 wdd->timeout = dw_wdt_get_top(dw_wdt); 296 set_bit(WDOG_HW_RUNNING, &wdd->status); 297 } else { 298 wdd->timeout = DW_WDT_DEFAULT_SECONDS; 299 watchdog_init_timeout(wdd, 0, dev); 300 } 301 302 platform_set_drvdata(pdev, dw_wdt); 303 304 watchdog_set_restart_priority(wdd, 128); 305 306 ret = watchdog_register_device(wdd); 307 if (ret) 308 goto out_disable_clk; 309 310 return 0; 311 312 out_disable_clk: 313 clk_disable_unprepare(dw_wdt->clk); 314 return ret; 315 } 316 317 static int dw_wdt_drv_remove(struct platform_device *pdev) 318 { 319 struct dw_wdt *dw_wdt = platform_get_drvdata(pdev); 320 321 watchdog_unregister_device(&dw_wdt->wdd); 322 reset_control_assert(dw_wdt->rst); 323 clk_disable_unprepare(dw_wdt->clk); 324 325 return 0; 326 } 327 328 #ifdef CONFIG_OF 329 static const struct of_device_id dw_wdt_of_match[] = { 330 { .compatible = "snps,dw-wdt", }, 331 { /* sentinel */ } 332 }; 333 MODULE_DEVICE_TABLE(of, dw_wdt_of_match); 334 #endif 335 336 static struct platform_driver dw_wdt_driver = { 337 .probe = dw_wdt_drv_probe, 338 .remove = dw_wdt_drv_remove, 339 .driver = { 340 .name = "dw_wdt", 341 .of_match_table = of_match_ptr(dw_wdt_of_match), 342 .pm = &dw_wdt_pm_ops, 343 }, 344 }; 345 346 module_platform_driver(dw_wdt_driver); 347 348 MODULE_AUTHOR("Jamie Iles"); 349 MODULE_DESCRIPTION("Synopsys DesignWare Watchdog Driver"); 350 MODULE_LICENSE("GPL"); 351