Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

watchdog: sp805_wdt: convert to watchdog core

This patch converts existing sp805 watchdog driver to use already in place
common infrastructure present in watchdog core. With this lot of code goes away.

Signed-off-by: Viresh Kumar <viresh.kumar@st.com>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>

authored by

Viresh Kumar and committed by
Wim Van Sebroeck
4a516539 2d8c7ff5

+85 -161
+1
drivers/watchdog/Kconfig
··· 99 99 config ARM_SP805_WATCHDOG 100 100 tristate "ARM SP805 Watchdog" 101 101 depends on ARM_AMBA 102 + select WATCHDOG_CORE 102 103 help 103 104 ARM Primecell SP805 Watchdog timer. This will reboot your system when 104 105 the timeout is reached.
+84 -161
drivers/watchdog/sp805_wdt.c
··· 16 16 #include <linux/amba/bus.h> 17 17 #include <linux/bitops.h> 18 18 #include <linux/clk.h> 19 - #include <linux/fs.h> 20 19 #include <linux/init.h> 21 20 #include <linux/io.h> 22 21 #include <linux/ioport.h> 23 22 #include <linux/kernel.h> 24 23 #include <linux/math64.h> 25 - #include <linux/miscdevice.h> 26 24 #include <linux/module.h> 27 25 #include <linux/moduleparam.h> 28 26 #include <linux/pm.h> 29 27 #include <linux/slab.h> 30 28 #include <linux/spinlock.h> 31 29 #include <linux/types.h> 32 - #include <linux/uaccess.h> 33 30 #include <linux/watchdog.h> 34 31 35 32 /* default timeout in seconds */ ··· 53 56 54 57 /** 55 58 * struct sp805_wdt: sp805 wdt device structure 59 + * @wdd: instance of struct watchdog_device 56 60 * @lock: spin lock protecting dev structure and io access 57 61 * @base: base address of wdt 58 62 * @clk: clock structure of wdt ··· 63 65 * @timeout: current programmed timeout 64 66 */ 65 67 struct sp805_wdt { 68 + struct watchdog_device wdd; 66 69 spinlock_t lock; 67 70 void __iomem *base; 68 71 struct clk *clk; 69 72 struct amba_device *adev; 70 - unsigned long status; 71 - #define WDT_BUSY 0 72 - #define WDT_CAN_BE_CLOSED 1 73 73 unsigned int load_val; 74 74 unsigned int timeout; 75 75 }; 76 76 77 - /* local variables */ 78 - static struct sp805_wdt *wdt; 79 77 static bool nowayout = WATCHDOG_NOWAYOUT; 78 + module_param(nowayout, bool, 0); 79 + MODULE_PARM_DESC(nowayout, 80 + "Set to 1 to keep watchdog running after device release"); 80 81 81 82 /* This routine finds load value that will reset system in required timout */ 82 - static void wdt_setload(unsigned int timeout) 83 + static int wdt_setload(struct watchdog_device *wdd, unsigned int timeout) 83 84 { 85 + struct sp805_wdt *wdt = watchdog_get_drvdata(wdd); 84 86 u64 load, rate; 85 87 86 88 rate = clk_get_rate(wdt->clk); ··· 101 103 /* roundup timeout to closest positive integer value */ 102 104 wdt->timeout = div_u64((load + 1) * 2 + (rate / 2), rate); 103 105 spin_unlock(&wdt->lock); 106 + 107 + return 0; 104 108 } 105 109 106 110 /* returns number of seconds left for reset to occur */ 107 - static u32 wdt_timeleft(void) 111 + static unsigned int wdt_timeleft(struct watchdog_device *wdd) 108 112 { 113 + struct sp805_wdt *wdt = watchdog_get_drvdata(wdd); 109 114 u64 load, rate; 110 115 111 116 rate = clk_get_rate(wdt->clk); ··· 124 123 return div_u64(load, rate); 125 124 } 126 125 127 - /* enables watchdog timers reset */ 128 - static void wdt_enable(void) 126 + static int wdt_config(struct watchdog_device *wdd, bool ping) 129 127 { 128 + struct sp805_wdt *wdt = watchdog_get_drvdata(wdd); 129 + int ret; 130 + 131 + if (!ping) { 132 + ret = clk_enable(wdt->clk); 133 + if (ret) { 134 + dev_err(&wdt->adev->dev, "clock enable fail"); 135 + return ret; 136 + } 137 + } 138 + 130 139 spin_lock(&wdt->lock); 131 140 132 141 writel_relaxed(UNLOCK, wdt->base + WDTLOCK); 133 142 writel_relaxed(wdt->load_val, wdt->base + WDTLOAD); 134 - writel_relaxed(INT_MASK, wdt->base + WDTINTCLR); 135 - writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL); 143 + 144 + if (!ping) { 145 + writel_relaxed(INT_MASK, wdt->base + WDTINTCLR); 146 + writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base + 147 + WDTCONTROL); 148 + } 149 + 136 150 writel_relaxed(LOCK, wdt->base + WDTLOCK); 137 151 138 152 /* Flush posted writes. */ 139 153 readl_relaxed(wdt->base + WDTLOCK); 140 154 spin_unlock(&wdt->lock); 155 + 156 + return 0; 157 + } 158 + 159 + static int wdt_ping(struct watchdog_device *wdd) 160 + { 161 + return wdt_config(wdd, true); 162 + } 163 + 164 + /* enables watchdog timers reset */ 165 + static int wdt_enable(struct watchdog_device *wdd) 166 + { 167 + return wdt_config(wdd, false); 141 168 } 142 169 143 170 /* disables watchdog timers reset */ 144 - static void wdt_disable(void) 171 + static int wdt_disable(struct watchdog_device *wdd) 145 172 { 173 + struct sp805_wdt *wdt = watchdog_get_drvdata(wdd); 174 + 146 175 spin_lock(&wdt->lock); 147 176 148 177 writel_relaxed(UNLOCK, wdt->base + WDTLOCK); ··· 182 151 /* Flush posted writes. */ 183 152 readl_relaxed(wdt->base + WDTLOCK); 184 153 spin_unlock(&wdt->lock); 185 - } 186 154 187 - static ssize_t sp805_wdt_write(struct file *file, const char *data, 188 - size_t len, loff_t *ppos) 189 - { 190 - if (len) { 191 - if (!nowayout) { 192 - size_t i; 193 - 194 - clear_bit(WDT_CAN_BE_CLOSED, &wdt->status); 195 - 196 - for (i = 0; i != len; i++) { 197 - char c; 198 - 199 - if (get_user(c, data + i)) 200 - return -EFAULT; 201 - /* Check for Magic Close character */ 202 - if (c == 'V') { 203 - set_bit(WDT_CAN_BE_CLOSED, 204 - &wdt->status); 205 - break; 206 - } 207 - } 208 - } 209 - wdt_enable(); 210 - } 211 - return len; 212 - } 213 - 214 - static const struct watchdog_info ident = { 215 - .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, 216 - .identity = MODULE_NAME, 217 - }; 218 - 219 - static long sp805_wdt_ioctl(struct file *file, unsigned int cmd, 220 - unsigned long arg) 221 - { 222 - int ret = -ENOTTY; 223 - unsigned int timeout; 224 - 225 - switch (cmd) { 226 - case WDIOC_GETSUPPORT: 227 - ret = copy_to_user((struct watchdog_info *)arg, &ident, 228 - sizeof(ident)) ? -EFAULT : 0; 229 - break; 230 - 231 - case WDIOC_GETSTATUS: 232 - ret = put_user(0, (int *)arg); 233 - break; 234 - 235 - case WDIOC_KEEPALIVE: 236 - wdt_enable(); 237 - ret = 0; 238 - break; 239 - 240 - case WDIOC_SETTIMEOUT: 241 - ret = get_user(timeout, (unsigned int *)arg); 242 - if (ret) 243 - break; 244 - 245 - wdt_setload(timeout); 246 - 247 - wdt_enable(); 248 - /* Fall through */ 249 - 250 - case WDIOC_GETTIMEOUT: 251 - ret = put_user(wdt->timeout, (unsigned int *)arg); 252 - break; 253 - case WDIOC_GETTIMELEFT: 254 - ret = put_user(wdt_timeleft(), (unsigned int *)arg); 255 - break; 256 - } 257 - return ret; 258 - } 259 - 260 - static int sp805_wdt_open(struct inode *inode, struct file *file) 261 - { 262 - int ret = 0; 263 - 264 - if (test_and_set_bit(WDT_BUSY, &wdt->status)) 265 - return -EBUSY; 266 - 267 - ret = clk_enable(wdt->clk); 268 - if (ret) { 269 - dev_err(&wdt->adev->dev, "clock enable fail"); 270 - goto err; 271 - } 272 - 273 - wdt_enable(); 274 - 275 - /* can not be closed, once enabled */ 276 - clear_bit(WDT_CAN_BE_CLOSED, &wdt->status); 277 - return nonseekable_open(inode, file); 278 - 279 - err: 280 - clear_bit(WDT_BUSY, &wdt->status); 281 - return ret; 282 - } 283 - 284 - static int sp805_wdt_release(struct inode *inode, struct file *file) 285 - { 286 - if (!test_bit(WDT_CAN_BE_CLOSED, &wdt->status)) { 287 - clear_bit(WDT_BUSY, &wdt->status); 288 - dev_warn(&wdt->adev->dev, "Device closed unexpectedly\n"); 289 - return 0; 290 - } 291 - 292 - wdt_disable(); 293 155 clk_disable(wdt->clk); 294 - clear_bit(WDT_BUSY, &wdt->status); 295 156 296 157 return 0; 297 158 } 298 159 299 - static const struct file_operations sp805_wdt_fops = { 300 - .owner = THIS_MODULE, 301 - .llseek = no_llseek, 302 - .write = sp805_wdt_write, 303 - .unlocked_ioctl = sp805_wdt_ioctl, 304 - .open = sp805_wdt_open, 305 - .release = sp805_wdt_release, 160 + static const struct watchdog_info wdt_info = { 161 + .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, 162 + .identity = MODULE_NAME, 306 163 }; 307 164 308 - static struct miscdevice sp805_wdt_miscdev = { 309 - .minor = WATCHDOG_MINOR, 310 - .name = "watchdog", 311 - .fops = &sp805_wdt_fops, 165 + static const struct watchdog_ops wdt_ops = { 166 + .owner = THIS_MODULE, 167 + .start = wdt_enable, 168 + .stop = wdt_disable, 169 + .ping = wdt_ping, 170 + .set_timeout = wdt_setload, 171 + .get_timeleft = wdt_timeleft, 312 172 }; 313 173 314 174 static int __devinit 315 175 sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id) 316 176 { 177 + struct sp805_wdt *wdt; 317 178 int ret = 0; 318 179 319 180 if (!devm_request_mem_region(&adev->dev, adev->res.start, ··· 238 315 } 239 316 240 317 wdt->adev = adev; 241 - spin_lock_init(&wdt->lock); 242 - wdt_setload(DEFAULT_TIMEOUT); 318 + wdt->wdd.info = &wdt_info; 319 + wdt->wdd.ops = &wdt_ops; 243 320 244 - ret = misc_register(&sp805_wdt_miscdev); 245 - if (ret < 0) { 246 - dev_warn(&adev->dev, "cannot register misc device\n"); 247 - goto err_misc_register; 321 + spin_lock_init(&wdt->lock); 322 + watchdog_set_nowayout(&wdt->wdd, nowayout); 323 + watchdog_set_drvdata(&wdt->wdd, wdt); 324 + wdt_setload(&wdt->wdd, DEFAULT_TIMEOUT); 325 + 326 + ret = watchdog_register_device(&wdt->wdd); 327 + if (ret) { 328 + dev_err(&adev->dev, "watchdog_register_device() failed: %d\n", 329 + ret); 330 + goto err_register; 248 331 } 332 + amba_set_drvdata(adev, wdt); 249 333 250 334 dev_info(&adev->dev, "registration successful\n"); 251 335 return 0; 252 336 253 - err_misc_register: 337 + err_register: 254 338 clk_put(wdt->clk); 255 339 err: 256 340 dev_err(&adev->dev, "Probe Failed!!!\n"); ··· 266 336 267 337 static int __devexit sp805_wdt_remove(struct amba_device *adev) 268 338 { 269 - misc_deregister(&sp805_wdt_miscdev); 339 + struct sp805_wdt *wdt = amba_get_drvdata(adev); 340 + 341 + watchdog_unregister_device(&wdt->wdd); 342 + amba_set_drvdata(adev, NULL); 343 + watchdog_set_drvdata(&wdt->wdd, NULL); 270 344 clk_put(wdt->clk); 271 345 272 346 return 0; ··· 279 345 #ifdef CONFIG_PM 280 346 static int sp805_wdt_suspend(struct device *dev) 281 347 { 282 - if (test_bit(WDT_BUSY, &wdt->status)) { 283 - wdt_disable(); 284 - clk_disable(wdt->clk); 285 - } 348 + struct sp805_wdt *wdt = dev_get_drvdata(dev); 349 + 350 + if (watchdog_active(&wdt->wdd)) 351 + return wdt_disable(&wdt->wdd); 286 352 287 353 return 0; 288 354 } 289 355 290 356 static int sp805_wdt_resume(struct device *dev) 291 357 { 292 - int ret = 0; 358 + struct sp805_wdt *wdt = dev_get_drvdata(dev); 293 359 294 - if (test_bit(WDT_BUSY, &wdt->status)) { 295 - ret = clk_enable(wdt->clk); 296 - if (ret) { 297 - dev_err(dev, "clock enable fail"); 298 - return ret; 299 - } 300 - wdt_enable(); 301 - } 360 + if (watchdog_active(&wdt->wdd)) 361 + return wdt_enable(&wdt->wdd); 302 362 303 - return ret; 363 + return 0; 304 364 } 305 365 #endif /* CONFIG_PM */ 306 366 ··· 323 395 324 396 module_amba_driver(sp805_wdt_driver); 325 397 326 - module_param(nowayout, bool, 0); 327 - MODULE_PARM_DESC(nowayout, 328 - "Set to 1 to keep watchdog running after device release"); 329 - 330 398 MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>"); 331 399 MODULE_DESCRIPTION("ARM SP805 Watchdog Driver"); 332 400 MODULE_LICENSE("GPL"); 333 - MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);