Blame view
drivers/watchdog/s3c2410_wdt.c
12.8 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 |
/* linux/drivers/char/watchdog/s3c2410_wdt.c * * Copyright (c) 2004 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * * S3C2410 Watchdog Timer Support * * Based on, softdog.c by Alan Cox, |
29fa0586d [PATCH] Switch al... |
9 |
* (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk> |
1da177e4c Linux-2.6.12-rc2 |
10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
1da177e4c Linux-2.6.12-rc2 |
24 25 26 27 |
*/ #include <linux/module.h> #include <linux/moduleparam.h> |
1da177e4c Linux-2.6.12-rc2 |
28 29 |
#include <linux/types.h> #include <linux/timer.h> |
25dc46e38 watchdog: s3c2410... |
30 |
#include <linux/miscdevice.h> /* for MODULE_ALIAS_MISCDEV */ |
1da177e4c Linux-2.6.12-rc2 |
31 |
#include <linux/watchdog.h> |
1da177e4c Linux-2.6.12-rc2 |
32 |
#include <linux/init.h> |
d052d1bef Create platform_d... |
33 |
#include <linux/platform_device.h> |
1da177e4c Linux-2.6.12-rc2 |
34 |
#include <linux/interrupt.h> |
f8ce25476 [ARM] Move asm/ha... |
35 |
#include <linux/clk.h> |
41dc8b72e s3c2410_wdt watch... |
36 37 |
#include <linux/uaccess.h> #include <linux/io.h> |
e02f838ee [WATCHDOG] CPUFRE... |
38 |
#include <linux/cpufreq.h> |
5a0e3ad6a include cleanup: ... |
39 |
#include <linux/slab.h> |
25dc46e38 watchdog: s3c2410... |
40 |
#include <linux/err.h> |
1da177e4c Linux-2.6.12-rc2 |
41 |
|
a09e64fbc [ARM] Move includ... |
42 |
#include <mach/map.h> |
1da177e4c Linux-2.6.12-rc2 |
43 |
|
b430708ad [WATCHDOG] s3c241... |
44 45 |
#undef S3C_VA_WATCHDOG #define S3C_VA_WATCHDOG (0) |
1da177e4c Linux-2.6.12-rc2 |
46 |
|
180ee700d [ARM] S3C: Move r... |
47 |
#include <plat/regs-watchdog.h> |
1da177e4c Linux-2.6.12-rc2 |
48 49 50 51 52 |
#define PFX "s3c2410-wdt: " #define CONFIG_S3C2410_WATCHDOG_ATBOOT (0) #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15) |
25ff3780d [WATCHDOG] s3c24X... |
53 |
static int nowayout = WATCHDOG_NOWAYOUT; |
1da177e4c Linux-2.6.12-rc2 |
54 55 |
static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME; static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT; |
41dc8b72e s3c2410_wdt watch... |
56 57 |
static int soft_noboot; static int debug; |
1da177e4c Linux-2.6.12-rc2 |
58 59 60 61 62 63 |
module_param(tmr_margin, int, 0); module_param(tmr_atboot, int, 0); module_param(nowayout, int, 0); module_param(soft_noboot, int, 0); module_param(debug, int, 0); |
76550d329 watchdog: fix sev... |
64 |
MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. (default=" |
41dc8b72e s3c2410_wdt watch... |
65 66 67 68 69 70 |
__MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")"); MODULE_PARM_DESC(tmr_atboot, "Watchdog is started at boot time if set to 1, default=" __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT)); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
a77dba7e4 [WATCHDOG] Some m... |
71 |
MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, " |
76550d329 watchdog: fix sev... |
72 73 |
"0 to reboot (default 0)"); MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)"); |
1da177e4c Linux-2.6.12-rc2 |
74 |
|
e8ef92b8d [WATCHDOG] change... |
75 |
static struct device *wdt_dev; /* platform device attached to */ |
1da177e4c Linux-2.6.12-rc2 |
76 77 78 79 80 |
static struct resource *wdt_mem; static struct resource *wdt_irq; static struct clk *wdt_clock; static void __iomem *wdt_base; static unsigned int wdt_count; |
41dc8b72e s3c2410_wdt watch... |
81 |
static DEFINE_SPINLOCK(wdt_lock); |
1da177e4c Linux-2.6.12-rc2 |
82 83 84 85 86 87 |
/* watchdog control routines */ #define DBG(msg...) do { \ if (debug) \ printk(KERN_INFO msg); \ |
41dc8b72e s3c2410_wdt watch... |
88 |
} while (0) |
1da177e4c Linux-2.6.12-rc2 |
89 90 |
/* functions */ |
25dc46e38 watchdog: s3c2410... |
91 |
static int s3c2410wdt_keepalive(struct watchdog_device *wdd) |
1da177e4c Linux-2.6.12-rc2 |
92 |
{ |
41dc8b72e s3c2410_wdt watch... |
93 |
spin_lock(&wdt_lock); |
1da177e4c Linux-2.6.12-rc2 |
94 |
writel(wdt_count, wdt_base + S3C2410_WTCNT); |
41dc8b72e s3c2410_wdt watch... |
95 |
spin_unlock(&wdt_lock); |
25dc46e38 watchdog: s3c2410... |
96 97 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
98 |
} |
41dc8b72e s3c2410_wdt watch... |
99 |
static void __s3c2410wdt_stop(void) |
1da177e4c Linux-2.6.12-rc2 |
100 101 |
{ unsigned long wtcon; |
41dc8b72e s3c2410_wdt watch... |
102 103 104 105 |
wtcon = readl(wdt_base + S3C2410_WTCON); wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN); writel(wtcon, wdt_base + S3C2410_WTCON); } |
25dc46e38 watchdog: s3c2410... |
106 |
static int s3c2410wdt_stop(struct watchdog_device *wdd) |
41dc8b72e s3c2410_wdt watch... |
107 108 109 110 |
{ spin_lock(&wdt_lock); __s3c2410wdt_stop(); spin_unlock(&wdt_lock); |
25dc46e38 watchdog: s3c2410... |
111 112 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
113 |
} |
25dc46e38 watchdog: s3c2410... |
114 |
static int s3c2410wdt_start(struct watchdog_device *wdd) |
1da177e4c Linux-2.6.12-rc2 |
115 116 |
{ unsigned long wtcon; |
41dc8b72e s3c2410_wdt watch... |
117 118 119 |
spin_lock(&wdt_lock); __s3c2410wdt_stop(); |
1da177e4c Linux-2.6.12-rc2 |
120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
wtcon = readl(wdt_base + S3C2410_WTCON); wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128; if (soft_noboot) { wtcon |= S3C2410_WTCON_INTEN; wtcon &= ~S3C2410_WTCON_RSTEN; } else { wtcon &= ~S3C2410_WTCON_INTEN; wtcon |= S3C2410_WTCON_RSTEN; } DBG("%s: wdt_count=0x%08x, wtcon=%08lx ", |
fa9363c5f [WATCHDOG] replac... |
134 |
__func__, wdt_count, wtcon); |
1da177e4c Linux-2.6.12-rc2 |
135 136 137 138 |
writel(wdt_count, wdt_base + S3C2410_WTDAT); writel(wdt_count, wdt_base + S3C2410_WTCNT); writel(wtcon, wdt_base + S3C2410_WTCON); |
41dc8b72e s3c2410_wdt watch... |
139 |
spin_unlock(&wdt_lock); |
25dc46e38 watchdog: s3c2410... |
140 141 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
142 |
} |
e02f838ee [WATCHDOG] CPUFRE... |
143 144 145 146 |
static inline int s3c2410wdt_is_running(void) { return readl(wdt_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE; } |
25dc46e38 watchdog: s3c2410... |
147 |
static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeout) |
1da177e4c Linux-2.6.12-rc2 |
148 |
{ |
e02f838ee [WATCHDOG] CPUFRE... |
149 |
unsigned long freq = clk_get_rate(wdt_clock); |
1da177e4c Linux-2.6.12-rc2 |
150 151 152 153 154 155 156 157 158 |
unsigned int count; unsigned int divisor = 1; unsigned long wtcon; if (timeout < 1) return -EINVAL; freq /= 128; count = timeout * freq; |
e02f838ee [WATCHDOG] CPUFRE... |
159 160 |
DBG("%s: count=%d, timeout=%d, freq=%lu ", |
fa9363c5f [WATCHDOG] replac... |
161 |
__func__, count, timeout, freq); |
1da177e4c Linux-2.6.12-rc2 |
162 163 164 165 166 167 168 169 170 171 172 173 174 |
/* if the count is bigger than the watchdog register, then work out what we need to do (and if) we can actually make this value */ if (count >= 0x10000) { for (divisor = 1; divisor <= 0x100; divisor++) { if ((count / divisor) < 0x10000) break; } if ((count / divisor) >= 0x10000) { |
e8ef92b8d [WATCHDOG] change... |
175 176 |
dev_err(wdt_dev, "timeout %d too big ", timeout); |
1da177e4c Linux-2.6.12-rc2 |
177 178 179 |
return -EINVAL; } } |
1da177e4c Linux-2.6.12-rc2 |
180 181 |
DBG("%s: timeout=%d, divisor=%d, count=%d (%08x) ", |
fa9363c5f [WATCHDOG] replac... |
182 |
__func__, timeout, divisor, count, count/divisor); |
1da177e4c Linux-2.6.12-rc2 |
183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
count /= divisor; wdt_count = count; /* update the pre-scaler */ wtcon = readl(wdt_base + S3C2410_WTCON); wtcon &= ~S3C2410_WTCON_PRESCALE_MASK; wtcon |= S3C2410_WTCON_PRESCALE(divisor-1); writel(count, wdt_base + S3C2410_WTDAT); writel(wtcon, wdt_base + S3C2410_WTCON); return 0; } |
a77dba7e4 [WATCHDOG] Some m... |
197 |
#define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE) |
1da177e4c Linux-2.6.12-rc2 |
198 |
|
41dc8b72e s3c2410_wdt watch... |
199 |
static const struct watchdog_info s3c2410_wdt_ident = { |
1da177e4c Linux-2.6.12-rc2 |
200 201 202 203 |
.options = OPTIONS, .firmware_version = 0, .identity = "S3C2410 Watchdog", }; |
25dc46e38 watchdog: s3c2410... |
204 205 206 207 208 209 |
static struct watchdog_ops s3c2410wdt_ops = { .owner = THIS_MODULE, .start = s3c2410wdt_start, .stop = s3c2410wdt_stop, .ping = s3c2410wdt_keepalive, .set_timeout = s3c2410wdt_set_heartbeat, |
1da177e4c Linux-2.6.12-rc2 |
210 |
}; |
25dc46e38 watchdog: s3c2410... |
211 212 213 |
static struct watchdog_device s3c2410_wdd = { .info = &s3c2410_wdt_ident, .ops = &s3c2410wdt_ops, |
1da177e4c Linux-2.6.12-rc2 |
214 |
}; |
1da177e4c Linux-2.6.12-rc2 |
215 |
/* interrupt handler code */ |
7d12e780e IRQ: Maintain reg... |
216 |
static irqreturn_t s3c2410wdt_irq(int irqno, void *param) |
1da177e4c Linux-2.6.12-rc2 |
217 |
{ |
e8ef92b8d [WATCHDOG] change... |
218 219 |
dev_info(wdt_dev, "watchdog timer expired (irq) "); |
1da177e4c Linux-2.6.12-rc2 |
220 |
|
25dc46e38 watchdog: s3c2410... |
221 |
s3c2410wdt_keepalive(&s3c2410_wdd); |
1da177e4c Linux-2.6.12-rc2 |
222 223 |
return IRQ_HANDLED; } |
e02f838ee [WATCHDOG] CPUFRE... |
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
#ifdef CONFIG_CPU_FREQ static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb, unsigned long val, void *data) { int ret; if (!s3c2410wdt_is_running()) goto done; if (val == CPUFREQ_PRECHANGE) { /* To ensure that over the change we don't cause the * watchdog to trigger, we perform an keep-alive if * the watchdog is running. */ |
25dc46e38 watchdog: s3c2410... |
241 |
s3c2410wdt_keepalive(&s3c2410_wdd); |
e02f838ee [WATCHDOG] CPUFRE... |
242 |
} else if (val == CPUFREQ_POSTCHANGE) { |
25dc46e38 watchdog: s3c2410... |
243 |
s3c2410wdt_stop(&s3c2410_wdd); |
e02f838ee [WATCHDOG] CPUFRE... |
244 |
|
25dc46e38 watchdog: s3c2410... |
245 |
ret = s3c2410wdt_set_heartbeat(&s3c2410_wdd, s3c2410_wdd.timeout); |
e02f838ee [WATCHDOG] CPUFRE... |
246 247 |
if (ret >= 0) |
25dc46e38 watchdog: s3c2410... |
248 |
s3c2410wdt_start(&s3c2410_wdd); |
e02f838ee [WATCHDOG] CPUFRE... |
249 250 251 252 253 254 255 256 |
else goto err; } done: return 0; err: |
25dc46e38 watchdog: s3c2410... |
257 258 259 |
dev_err(wdt_dev, "cannot set new value for timeout %d ", s3c2410_wdd.timeout); |
e02f838ee [WATCHDOG] CPUFRE... |
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
return ret; } static struct notifier_block s3c2410wdt_cpufreq_transition_nb = { .notifier_call = s3c2410wdt_cpufreq_transition, }; static inline int s3c2410wdt_cpufreq_register(void) { return cpufreq_register_notifier(&s3c2410wdt_cpufreq_transition_nb, CPUFREQ_TRANSITION_NOTIFIER); } static inline void s3c2410wdt_cpufreq_deregister(void) { cpufreq_unregister_notifier(&s3c2410wdt_cpufreq_transition_nb, CPUFREQ_TRANSITION_NOTIFIER); } #else static inline int s3c2410wdt_cpufreq_register(void) { return 0; } static inline void s3c2410wdt_cpufreq_deregister(void) { } #endif |
a77dba7e4 [WATCHDOG] Some m... |
289 |
static int __devinit s3c2410wdt_probe(struct platform_device *pdev) |
1da177e4c Linux-2.6.12-rc2 |
290 |
{ |
e8ef92b8d [WATCHDOG] change... |
291 |
struct device *dev; |
46b814d6e [WATCHDOG] s3c241... |
292 |
unsigned int wtcon; |
1da177e4c Linux-2.6.12-rc2 |
293 294 295 |
int started = 0; int ret; int size; |
fa9363c5f [WATCHDOG] replac... |
296 297 |
DBG("%s: probe=%p ", __func__, pdev); |
1da177e4c Linux-2.6.12-rc2 |
298 |
|
e8ef92b8d [WATCHDOG] change... |
299 300 |
dev = &pdev->dev; wdt_dev = &pdev->dev; |
1da177e4c Linux-2.6.12-rc2 |
301 |
/* get the memory region for the watchdog timer */ |
f72401e94 watchdog: s3c2410... |
302 303 |
wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (wdt_mem == NULL) { |
e8ef92b8d [WATCHDOG] change... |
304 305 |
dev_err(dev, "no memory resource specified "); |
1da177e4c Linux-2.6.12-rc2 |
306 307 |
return -ENOENT; } |
f72401e94 watchdog: s3c2410... |
308 309 |
size = resource_size(wdt_mem); if (!request_mem_region(wdt_mem->start, size, pdev->name)) { |
e8ef92b8d [WATCHDOG] change... |
310 311 |
dev_err(dev, "failed to get memory region "); |
100fb76f0 watchdog: s3c2410... |
312 |
return -EBUSY; |
1da177e4c Linux-2.6.12-rc2 |
313 |
} |
f72401e94 watchdog: s3c2410... |
314 |
wdt_base = ioremap(wdt_mem->start, size); |
b4253f8fc [WATCHDOG] Fix NU... |
315 |
if (wdt_base == NULL) { |
e8ef92b8d [WATCHDOG] change... |
316 317 |
dev_err(dev, "failed to ioremap() region "); |
0b6dd8a64 [WATCHDOG] s3c241... |
318 319 |
ret = -EINVAL; goto err_req; |
1da177e4c Linux-2.6.12-rc2 |
320 321 322 323 |
} DBG("probe: mapped wdt_base=%p ", wdt_base); |
62be07414 [WATCHDOG] s3c241... |
324 325 |
wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (wdt_irq == NULL) { |
e8ef92b8d [WATCHDOG] change... |
326 327 |
dev_err(dev, "no irq resource specified "); |
0b6dd8a64 [WATCHDOG] s3c241... |
328 329 |
ret = -ENOENT; goto err_map; |
1da177e4c Linux-2.6.12-rc2 |
330 |
} |
62be07414 [WATCHDOG] s3c241... |
331 |
ret = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev); |
1da177e4c Linux-2.6.12-rc2 |
332 |
if (ret != 0) { |
e8ef92b8d [WATCHDOG] change... |
333 334 |
dev_err(dev, "failed to install irq (%d) ", ret); |
0b6dd8a64 [WATCHDOG] s3c241... |
335 |
goto err_map; |
1da177e4c Linux-2.6.12-rc2 |
336 |
} |
3ae5eaec1 [DRIVER MODEL] Co... |
337 |
wdt_clock = clk_get(&pdev->dev, "watchdog"); |
9cd446198 [WATCHDOG] fix cl... |
338 |
if (IS_ERR(wdt_clock)) { |
e8ef92b8d [WATCHDOG] change... |
339 340 |
dev_err(dev, "failed to find watchdog clock source "); |
9cd446198 [WATCHDOG] fix cl... |
341 |
ret = PTR_ERR(wdt_clock); |
0b6dd8a64 [WATCHDOG] s3c241... |
342 |
goto err_irq; |
1da177e4c Linux-2.6.12-rc2 |
343 |
} |
1da177e4c Linux-2.6.12-rc2 |
344 |
clk_enable(wdt_clock); |
e02f838ee [WATCHDOG] CPUFRE... |
345 346 347 348 349 |
if (s3c2410wdt_cpufreq_register() < 0) { printk(KERN_ERR PFX "failed to register cpufreq "); goto err_clk; } |
1da177e4c Linux-2.6.12-rc2 |
350 351 |
/* see if we can actually set the requested timer margin, and if * not, try the default value */ |
25dc46e38 watchdog: s3c2410... |
352 353 |
if (s3c2410wdt_set_heartbeat(&s3c2410_wdd, tmr_margin)) { started = s3c2410wdt_set_heartbeat(&s3c2410_wdd, |
41dc8b72e s3c2410_wdt watch... |
354 |
CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); |
1da177e4c Linux-2.6.12-rc2 |
355 |
|
41dc8b72e s3c2410_wdt watch... |
356 357 358 359 |
if (started == 0) dev_info(dev, "tmr_margin value out of range, default %d used ", |
1da177e4c Linux-2.6.12-rc2 |
360 |
CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); |
41dc8b72e s3c2410_wdt watch... |
361 |
else |
a77dba7e4 [WATCHDOG] Some m... |
362 363 364 |
dev_info(dev, "default timer value is out of range, " "cannot start "); |
1da177e4c Linux-2.6.12-rc2 |
365 |
} |
ff0b3cd4a watchdog: add now... |
366 |
watchdog_set_nowayout(&s3c2410_wdd, nowayout); |
25dc46e38 watchdog: s3c2410... |
367 |
ret = watchdog_register_device(&s3c2410_wdd); |
1da177e4c Linux-2.6.12-rc2 |
368 |
if (ret) { |
25dc46e38 watchdog: s3c2410... |
369 370 |
dev_err(dev, "cannot register watchdog (%d) ", ret); |
e02f838ee [WATCHDOG] CPUFRE... |
371 |
goto err_cpufreq; |
1da177e4c Linux-2.6.12-rc2 |
372 373 374 |
} if (tmr_atboot && started == 0) { |
e8ef92b8d [WATCHDOG] change... |
375 376 |
dev_info(dev, "starting watchdog timer "); |
25dc46e38 watchdog: s3c2410... |
377 |
s3c2410wdt_start(&s3c2410_wdd); |
655516c80 [WATCHDOG] s3c241... |
378 379 380 381 |
} else if (!tmr_atboot) { /* if we're not enabling the watchdog, then ensure it is * disabled if it has been left running from the bootloader * or other source */ |
25dc46e38 watchdog: s3c2410... |
382 |
s3c2410wdt_stop(&s3c2410_wdd); |
1da177e4c Linux-2.6.12-rc2 |
383 |
} |
46b814d6e [WATCHDOG] s3c241... |
384 385 386 |
/* print out a statement of readiness */ wtcon = readl(wdt_base + S3C2410_WTCON); |
e8ef92b8d [WATCHDOG] change... |
387 388 |
dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled ", |
46b814d6e [WATCHDOG] s3c241... |
389 |
(wtcon & S3C2410_WTCON_ENABLE) ? "" : "in", |
20403e845 watchdog: fix ini... |
390 391 |
(wtcon & S3C2410_WTCON_RSTEN) ? "en" : "dis", (wtcon & S3C2410_WTCON_INTEN) ? "en" : "dis"); |
41dc8b72e s3c2410_wdt watch... |
392 |
|
1da177e4c Linux-2.6.12-rc2 |
393 |
return 0; |
0b6dd8a64 [WATCHDOG] s3c241... |
394 |
|
e02f838ee [WATCHDOG] CPUFRE... |
395 396 |
err_cpufreq: s3c2410wdt_cpufreq_deregister(); |
0b6dd8a64 [WATCHDOG] s3c241... |
397 398 399 400 401 402 403 404 405 406 407 |
err_clk: clk_disable(wdt_clock); clk_put(wdt_clock); err_irq: free_irq(wdt_irq->start, pdev); err_map: iounmap(wdt_base); err_req: |
f72401e94 watchdog: s3c2410... |
408 409 |
release_mem_region(wdt_mem->start, size); wdt_mem = NULL; |
0b6dd8a64 [WATCHDOG] s3c241... |
410 411 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
412 |
} |
a77dba7e4 [WATCHDOG] Some m... |
413 |
static int __devexit s3c2410wdt_remove(struct platform_device *dev) |
1da177e4c Linux-2.6.12-rc2 |
414 |
{ |
25dc46e38 watchdog: s3c2410... |
415 |
watchdog_unregister_device(&s3c2410_wdd); |
1da177e4c Linux-2.6.12-rc2 |
416 |
|
9a3725631 watchdog: s3c2410... |
417 |
s3c2410wdt_cpufreq_deregister(); |
1da177e4c Linux-2.6.12-rc2 |
418 |
|
0b6dd8a64 [WATCHDOG] s3c241... |
419 420 421 |
clk_disable(wdt_clock); clk_put(wdt_clock); wdt_clock = NULL; |
1da177e4c Linux-2.6.12-rc2 |
422 |
|
9a3725631 watchdog: s3c2410... |
423 424 |
free_irq(wdt_irq->start, dev); wdt_irq = NULL; |
e34477e99 [WATCHDOG] iorema... |
425 |
iounmap(wdt_base); |
9a3725631 watchdog: s3c2410... |
426 |
|
f72401e94 watchdog: s3c2410... |
427 |
release_mem_region(wdt_mem->start, resource_size(wdt_mem)); |
9a3725631 watchdog: s3c2410... |
428 |
wdt_mem = NULL; |
1da177e4c Linux-2.6.12-rc2 |
429 430 |
return 0; } |
3ae5eaec1 [DRIVER MODEL] Co... |
431 |
static void s3c2410wdt_shutdown(struct platform_device *dev) |
94f1e9f31 [WATCHDOG] s3c241... |
432 |
{ |
25dc46e38 watchdog: s3c2410... |
433 |
s3c2410wdt_stop(&s3c2410_wdd); |
94f1e9f31 [WATCHDOG] s3c241... |
434 |
} |
af4bb822b [WATCHDOG] s3c241... |
435 436 437 438 |
#ifdef CONFIG_PM static unsigned long wtcon_save; static unsigned long wtdat_save; |
3ae5eaec1 [DRIVER MODEL] Co... |
439 |
static int s3c2410wdt_suspend(struct platform_device *dev, pm_message_t state) |
af4bb822b [WATCHDOG] s3c241... |
440 |
{ |
9480e307c [PATCH] DRIVER MO... |
441 442 443 |
/* Save watchdog state, and turn it off. */ wtcon_save = readl(wdt_base + S3C2410_WTCON); wtdat_save = readl(wdt_base + S3C2410_WTDAT); |
af4bb822b [WATCHDOG] s3c241... |
444 |
|
9480e307c [PATCH] DRIVER MO... |
445 |
/* Note that WTCNT doesn't need to be saved. */ |
25dc46e38 watchdog: s3c2410... |
446 |
s3c2410wdt_stop(&s3c2410_wdd); |
af4bb822b [WATCHDOG] s3c241... |
447 448 449 |
return 0; } |
3ae5eaec1 [DRIVER MODEL] Co... |
450 |
static int s3c2410wdt_resume(struct platform_device *dev) |
af4bb822b [WATCHDOG] s3c241... |
451 |
{ |
9480e307c [PATCH] DRIVER MO... |
452 |
/* Restore watchdog state. */ |
af4bb822b [WATCHDOG] s3c241... |
453 |
|
9480e307c [PATCH] DRIVER MO... |
454 455 456 |
writel(wtdat_save, wdt_base + S3C2410_WTDAT); writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */ writel(wtcon_save, wdt_base + S3C2410_WTCON); |
af4bb822b [WATCHDOG] s3c241... |
457 |
|
9480e307c [PATCH] DRIVER MO... |
458 459 460 |
printk(KERN_INFO PFX "watchdog %sabled ", (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis"); |
af4bb822b [WATCHDOG] s3c241... |
461 462 463 464 465 466 467 468 |
return 0; } #else #define s3c2410wdt_suspend NULL #define s3c2410wdt_resume NULL #endif /* CONFIG_PM */ |
9487a9cc7 watchdog: s3c2410... |
469 470 471 472 473 474 475 476 477 |
#ifdef CONFIG_OF static const struct of_device_id s3c2410_wdt_match[] = { { .compatible = "samsung,s3c2410-wdt" }, {}, }; MODULE_DEVICE_TABLE(of, s3c2410_wdt_match); #else #define s3c2410_wdt_match NULL #endif |
af4bb822b [WATCHDOG] s3c241... |
478 |
|
3ae5eaec1 [DRIVER MODEL] Co... |
479 |
static struct platform_driver s3c2410wdt_driver = { |
1da177e4c Linux-2.6.12-rc2 |
480 |
.probe = s3c2410wdt_probe, |
a77dba7e4 [WATCHDOG] Some m... |
481 |
.remove = __devexit_p(s3c2410wdt_remove), |
94f1e9f31 [WATCHDOG] s3c241... |
482 |
.shutdown = s3c2410wdt_shutdown, |
af4bb822b [WATCHDOG] s3c241... |
483 484 |
.suspend = s3c2410wdt_suspend, .resume = s3c2410wdt_resume, |
3ae5eaec1 [DRIVER MODEL] Co... |
485 486 487 |
.driver = { .owner = THIS_MODULE, .name = "s3c2410-wdt", |
9487a9cc7 watchdog: s3c2410... |
488 |
.of_match_table = s3c2410_wdt_match, |
3ae5eaec1 [DRIVER MODEL] Co... |
489 |
}, |
1da177e4c Linux-2.6.12-rc2 |
490 |
}; |
41dc8b72e s3c2410_wdt watch... |
491 492 493 |
static char banner[] __initdata = KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics "; |
1da177e4c Linux-2.6.12-rc2 |
494 495 496 497 |
static int __init watchdog_init(void) { printk(banner); |
3ae5eaec1 [DRIVER MODEL] Co... |
498 |
return platform_driver_register(&s3c2410wdt_driver); |
1da177e4c Linux-2.6.12-rc2 |
499 500 501 502 |
} static void __exit watchdog_exit(void) { |
3ae5eaec1 [DRIVER MODEL] Co... |
503 |
platform_driver_unregister(&s3c2410wdt_driver); |
1da177e4c Linux-2.6.12-rc2 |
504 505 506 507 |
} module_init(watchdog_init); module_exit(watchdog_exit); |
af4bb822b [WATCHDOG] s3c241... |
508 509 |
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, " "Dimitry Andric <dimitry.andric@tomtom.com>"); |
1da177e4c Linux-2.6.12-rc2 |
510 511 512 |
MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
f37d193c7 watchdog: fix pla... |
513 |
MODULE_ALIAS("platform:s3c2410-wdt"); |