1 /* 2 * Watchdog driver for Atmel AT91SAM9x processors. 3 * 4 * Copyright (C) 2008 Renaud CERRATO r.cerrato@til-technologies.fr 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12 /* 13 * The Watchdog Timer Mode Register can be only written to once. If the 14 * timeout need to be set from Linux, be sure that the bootstrap or the 15 * bootloader doesn't write to this register. 16 */ 17 18 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 19 20 #include <linux/errno.h> 21 #include <linux/init.h> 22 #include <linux/io.h> 23 #include <linux/kernel.h> 24 #include <linux/module.h> 25 #include <linux/moduleparam.h> 26 #include <linux/platform_device.h> 27 #include <linux/types.h> 28 #include <linux/watchdog.h> 29 #include <linux/jiffies.h> 30 #include <linux/timer.h> 31 #include <linux/bitops.h> 32 #include <linux/uaccess.h> 33 #include <linux/of.h> 34 35 #include "at91sam9_wdt.h" 36 37 #define DRV_NAME "AT91SAM9 Watchdog" 38 39 #define wdt_read(field) \ 40 __raw_readl(at91wdt_private.base + field) 41 #define wdt_write(field, val) \ 42 __raw_writel((val), at91wdt_private.base + field) 43 44 /* AT91SAM9 watchdog runs a 12bit counter @ 256Hz, 45 * use this to convert a watchdog 46 * value from/to milliseconds. 47 */ 48 #define ms_to_ticks(t) (((t << 8) / 1000) - 1) 49 #define ticks_to_ms(t) (((t + 1) * 1000) >> 8) 50 51 /* Hardware timeout in seconds */ 52 #define WDT_HW_TIMEOUT 2 53 54 /* Timer heartbeat (500ms) */ 55 #define WDT_TIMEOUT (HZ/2) 56 57 /* User land timeout */ 58 #define WDT_HEARTBEAT 15 59 static int heartbeat; 60 module_param(heartbeat, int, 0); 61 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. " 62 "(default = " __MODULE_STRING(WDT_HEARTBEAT) ")"); 63 64 static bool nowayout = WATCHDOG_NOWAYOUT; 65 module_param(nowayout, bool, 0); 66 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " 67 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 68 69 static struct watchdog_device at91_wdt_dev; 70 static void at91_ping(unsigned long data); 71 72 static struct { 73 void __iomem *base; 74 unsigned long next_heartbeat; /* the next_heartbeat for the timer */ 75 struct timer_list timer; /* The timer that pings the watchdog */ 76 } at91wdt_private; 77 78 /* ......................................................................... */ 79 80 /* 81 * Reload the watchdog timer. (ie, pat the watchdog) 82 */ 83 static inline void at91_wdt_reset(void) 84 { 85 wdt_write(AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT); 86 } 87 88 /* 89 * Timer tick 90 */ 91 static void at91_ping(unsigned long data) 92 { 93 if (time_before(jiffies, at91wdt_private.next_heartbeat) || 94 (!watchdog_active(&at91_wdt_dev))) { 95 at91_wdt_reset(); 96 mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT); 97 } else 98 pr_crit("I will reset your machine !\n"); 99 } 100 101 static int at91_wdt_ping(struct watchdog_device *wdd) 102 { 103 /* calculate when the next userspace timeout will be */ 104 at91wdt_private.next_heartbeat = jiffies + wdd->timeout * HZ; 105 return 0; 106 } 107 108 static int at91_wdt_start(struct watchdog_device *wdd) 109 { 110 /* calculate the next userspace timeout and modify the timer */ 111 at91_wdt_ping(wdd); 112 mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT); 113 return 0; 114 } 115 116 static int at91_wdt_stop(struct watchdog_device *wdd) 117 { 118 /* The watchdog timer hardware can not be stopped... */ 119 return 0; 120 } 121 122 static int at91_wdt_set_timeout(struct watchdog_device *wdd, unsigned int new_timeout) 123 { 124 wdd->timeout = new_timeout; 125 return 0; 126 } 127 128 /* 129 * Set the watchdog time interval in 1/256Hz (write-once) 130 * Counter is 12 bit. 131 */ 132 static int at91_wdt_settimeout(unsigned int timeout) 133 { 134 unsigned int reg; 135 unsigned int mr; 136 137 /* Check if disabled */ 138 mr = wdt_read(AT91_WDT_MR); 139 if (mr & AT91_WDT_WDDIS) { 140 pr_err("sorry, watchdog is disabled\n"); 141 return -EIO; 142 } 143 144 /* 145 * All counting occurs at SLOW_CLOCK / 128 = 256 Hz 146 * 147 * Since WDV is a 12-bit counter, the maximum period is 148 * 4096 / 256 = 16 seconds. 149 */ 150 reg = AT91_WDT_WDRSTEN /* causes watchdog reset */ 151 /* | AT91_WDT_WDRPROC causes processor reset only */ 152 | AT91_WDT_WDDBGHLT /* disabled in debug mode */ 153 | AT91_WDT_WDD /* restart at any time */ 154 | (timeout & AT91_WDT_WDV); /* timer value */ 155 wdt_write(AT91_WDT_MR, reg); 156 157 return 0; 158 } 159 160 /* ......................................................................... */ 161 162 static const struct watchdog_info at91_wdt_info = { 163 .identity = DRV_NAME, 164 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | 165 WDIOF_MAGICCLOSE, 166 }; 167 168 static const struct watchdog_ops at91_wdt_ops = { 169 .owner = THIS_MODULE, 170 .start = at91_wdt_start, 171 .stop = at91_wdt_stop, 172 .ping = at91_wdt_ping, 173 .set_timeout = at91_wdt_set_timeout, 174 }; 175 176 static struct watchdog_device at91_wdt_dev = { 177 .info = &at91_wdt_info, 178 .ops = &at91_wdt_ops, 179 .timeout = WDT_HEARTBEAT, 180 .min_timeout = 1, 181 .max_timeout = 0xFFFF, 182 }; 183 184 static int __init at91wdt_probe(struct platform_device *pdev) 185 { 186 struct resource *r; 187 int res; 188 189 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 190 if (!r) 191 return -ENODEV; 192 at91wdt_private.base = ioremap(r->start, resource_size(r)); 193 if (!at91wdt_private.base) { 194 dev_err(&pdev->dev, "failed to map registers, aborting.\n"); 195 return -ENOMEM; 196 } 197 198 at91_wdt_dev.parent = &pdev->dev; 199 watchdog_init_timeout(&at91_wdt_dev, heartbeat, &pdev->dev); 200 watchdog_set_nowayout(&at91_wdt_dev, nowayout); 201 202 /* Set watchdog */ 203 res = at91_wdt_settimeout(ms_to_ticks(WDT_HW_TIMEOUT * 1000)); 204 if (res) 205 return res; 206 207 res = watchdog_register_device(&at91_wdt_dev); 208 if (res) 209 return res; 210 211 at91wdt_private.next_heartbeat = jiffies + at91_wdt_dev.timeout * HZ; 212 setup_timer(&at91wdt_private.timer, at91_ping, 0); 213 mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT); 214 215 pr_info("enabled (heartbeat=%d sec, nowayout=%d)\n", 216 at91_wdt_dev.timeout, nowayout); 217 218 return 0; 219 } 220 221 static int __exit at91wdt_remove(struct platform_device *pdev) 222 { 223 watchdog_unregister_device(&at91_wdt_dev); 224 225 pr_warn("I quit now, hardware will probably reboot!\n"); 226 del_timer(&at91wdt_private.timer); 227 228 return 0; 229 } 230 231 #if defined(CONFIG_OF) 232 static const struct of_device_id at91_wdt_dt_ids[] = { 233 { .compatible = "atmel,at91sam9260-wdt" }, 234 { /* sentinel */ } 235 }; 236 237 MODULE_DEVICE_TABLE(of, at91_wdt_dt_ids); 238 #endif 239 240 static struct platform_driver at91wdt_driver = { 241 .remove = __exit_p(at91wdt_remove), 242 .driver = { 243 .name = "at91_wdt", 244 .owner = THIS_MODULE, 245 .of_match_table = of_match_ptr(at91_wdt_dt_ids), 246 }, 247 }; 248 249 module_platform_driver_probe(at91wdt_driver, at91wdt_probe); 250 251 MODULE_AUTHOR("Renaud CERRATO <r.cerrato@til-technologies.fr>"); 252 MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors"); 253 MODULE_LICENSE("GPL"); 254