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