aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-12 11:45:53 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-12 11:45:53 -0400
commit24ba40588fe50adce2a99e026fc0026872ebeb85 (patch)
tree20f940860987d0e84588b9681bce6a2564764fea /drivers/watchdog
parentb9b42eeb88d36cc7400925302f1587aaaa348905 (diff)
parentbd5cc119ef6bbe8ad64a303542c436c7a82498b7 (diff)
Merge git://www.linux-watchdog.org/linux-watchdog
Pull watchdog updates from Wim Van Sebroeck: - New watchdog driver for Allwinner A10/A13 - some devm_ioremap_resource simplifications - a s3c2410_wdt change that removes the global variables * git://www.linux-watchdog.org/linux-watchdog: watchdog: s3c2410_wdt: simplify use of devm_ioremap_resource watchdog: simplify platform_get_resource_byname/devm_ioremap_resource watchdog: ts72xx_wdt: simplify use of devm_ioremap_resource watchdog: nuc900_wdt.c: simplify use of devm_ioremap_resource watchdog: sunxi: New watchdog driver for Allwinner A10/A13 watchdog: s3c2410_wdt: remove the global variables
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/Kconfig10
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/ar7_wdt.c5
-rw-r--r--drivers/watchdog/nuc900_wdt.c5
-rw-r--r--drivers/watchdog/s3c2410_wdt.c228
-rw-r--r--drivers/watchdog/sunxi_wdt.c237
-rw-r--r--drivers/watchdog/ts72xx_wdt.c10
7 files changed, 377 insertions, 119 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 362085d7ad8f..d1d53f301de7 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -290,6 +290,16 @@ config ORION_WATCHDOG
290 To compile this driver as a module, choose M here: the 290 To compile this driver as a module, choose M here: the
291 module will be called orion_wdt. 291 module will be called orion_wdt.
292 292
293config SUNXI_WATCHDOG
294 tristate "Allwinner SoCs watchdog support"
295 depends on ARCH_SUNXI
296 select WATCHDOG_CORE
297 help
298 Say Y here to include support for the watchdog timer
299 in Allwinner SoCs.
300 To compile this driver as a module, choose M here: the
301 module will be called sunxi_wdt.
302
293config COH901327_WATCHDOG 303config COH901327_WATCHDOG
294 bool "ST-Ericsson COH 901 327 watchdog" 304 bool "ST-Ericsson COH 901 327 watchdog"
295 depends on ARCH_U300 305 depends on ARCH_U300
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 2f26a0b47ddc..6c5bb274d3cd 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
46obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o 46obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
47obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o 47obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
48obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o 48obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o
49obj-$(CONFIG_SUNXI_WATCHDOG) += sunxi_wdt.o
49obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o 50obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
50obj-$(CONFIG_STMP3XXX_RTC_WATCHDOG) += stmp3xxx_rtc_wdt.o 51obj-$(CONFIG_STMP3XXX_RTC_WATCHDOG) += stmp3xxx_rtc_wdt.o
51obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o 52obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c
index 2f3cc8fb471a..b3709f9cf5be 100644
--- a/drivers/watchdog/ar7_wdt.c
+++ b/drivers/watchdog/ar7_wdt.c
@@ -280,11 +280,6 @@ static int ar7_wdt_probe(struct platform_device *pdev)
280 280
281 ar7_regs_wdt = 281 ar7_regs_wdt =
282 platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); 282 platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
283 if (!ar7_regs_wdt) {
284 pr_err("could not get registers resource\n");
285 return -ENODEV;
286 }
287
288 ar7_wdt = devm_ioremap_resource(&pdev->dev, ar7_regs_wdt); 283 ar7_wdt = devm_ioremap_resource(&pdev->dev, ar7_regs_wdt);
289 if (IS_ERR(ar7_wdt)) 284 if (IS_ERR(ar7_wdt))
290 return PTR_ERR(ar7_wdt); 285 return PTR_ERR(ar7_wdt);
diff --git a/drivers/watchdog/nuc900_wdt.c b/drivers/watchdog/nuc900_wdt.c
index e2b6d2cf5c9d..b15b6efd91a1 100644
--- a/drivers/watchdog/nuc900_wdt.c
+++ b/drivers/watchdog/nuc900_wdt.c
@@ -256,11 +256,6 @@ static int nuc900wdt_probe(struct platform_device *pdev)
256 spin_lock_init(&nuc900_wdt->wdt_lock); 256 spin_lock_init(&nuc900_wdt->wdt_lock);
257 257
258 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 258 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
259 if (res == NULL) {
260 dev_err(&pdev->dev, "no memory resource specified\n");
261 return -ENOENT;
262 }
263
264 nuc900_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res); 259 nuc900_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res);
265 if (IS_ERR(nuc900_wdt->wdt_base)) 260 if (IS_ERR(nuc900_wdt->wdt_base))
266 return PTR_ERR(nuc900_wdt->wdt_base); 261 return PTR_ERR(nuc900_wdt->wdt_base);
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index 6a22cf5d35bd..23aad7c6bf5d 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -84,13 +84,17 @@ MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, "
84 "0 to reboot (default 0)"); 84 "0 to reboot (default 0)");
85MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)"); 85MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)");
86 86
87static struct device *wdt_dev; /* platform device attached to */ 87struct s3c2410_wdt {
88static struct resource *wdt_mem; 88 struct device *dev;
89static struct resource *wdt_irq; 89 struct clk *clock;
90static struct clk *wdt_clock; 90 void __iomem *reg_base;
91static void __iomem *wdt_base; 91 unsigned int count;
92static unsigned int wdt_count; 92 spinlock_t lock;
93static DEFINE_SPINLOCK(wdt_lock); 93 unsigned long wtcon_save;
94 unsigned long wtdat_save;
95 struct watchdog_device wdt_device;
96 struct notifier_block freq_transition;
97};
94 98
95/* watchdog control routines */ 99/* watchdog control routines */
96 100
@@ -102,29 +106,38 @@ do { \
102 106
103/* functions */ 107/* functions */
104 108
109static inline struct s3c2410_wdt *freq_to_wdt(struct notifier_block *nb)
110{
111 return container_of(nb, struct s3c2410_wdt, freq_transition);
112}
113
105static int s3c2410wdt_keepalive(struct watchdog_device *wdd) 114static int s3c2410wdt_keepalive(struct watchdog_device *wdd)
106{ 115{
107 spin_lock(&wdt_lock); 116 struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
108 writel(wdt_count, wdt_base + S3C2410_WTCNT); 117
109 spin_unlock(&wdt_lock); 118 spin_lock(&wdt->lock);
119 writel(wdt->count, wdt->reg_base + S3C2410_WTCNT);
120 spin_unlock(&wdt->lock);
110 121
111 return 0; 122 return 0;
112} 123}
113 124
114static void __s3c2410wdt_stop(void) 125static void __s3c2410wdt_stop(struct s3c2410_wdt *wdt)
115{ 126{
116 unsigned long wtcon; 127 unsigned long wtcon;
117 128
118 wtcon = readl(wdt_base + S3C2410_WTCON); 129 wtcon = readl(wdt->reg_base + S3C2410_WTCON);
119 wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN); 130 wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN);
120 writel(wtcon, wdt_base + S3C2410_WTCON); 131 writel(wtcon, wdt->reg_base + S3C2410_WTCON);
121} 132}
122 133
123static int s3c2410wdt_stop(struct watchdog_device *wdd) 134static int s3c2410wdt_stop(struct watchdog_device *wdd)
124{ 135{
125 spin_lock(&wdt_lock); 136 struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
126 __s3c2410wdt_stop(); 137
127 spin_unlock(&wdt_lock); 138 spin_lock(&wdt->lock);
139 __s3c2410wdt_stop(wdt);
140 spin_unlock(&wdt->lock);
128 141
129 return 0; 142 return 0;
130} 143}
@@ -132,12 +145,13 @@ static int s3c2410wdt_stop(struct watchdog_device *wdd)
132static int s3c2410wdt_start(struct watchdog_device *wdd) 145static int s3c2410wdt_start(struct watchdog_device *wdd)
133{ 146{
134 unsigned long wtcon; 147 unsigned long wtcon;
148 struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
135 149
136 spin_lock(&wdt_lock); 150 spin_lock(&wdt->lock);
137 151
138 __s3c2410wdt_stop(); 152 __s3c2410wdt_stop(wdt);
139 153
140 wtcon = readl(wdt_base + S3C2410_WTCON); 154 wtcon = readl(wdt->reg_base + S3C2410_WTCON);
141 wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128; 155 wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128;
142 156
143 if (soft_noboot) { 157 if (soft_noboot) {
@@ -148,25 +162,26 @@ static int s3c2410wdt_start(struct watchdog_device *wdd)
148 wtcon |= S3C2410_WTCON_RSTEN; 162 wtcon |= S3C2410_WTCON_RSTEN;
149 } 163 }
150 164
151 DBG("%s: wdt_count=0x%08x, wtcon=%08lx\n", 165 DBG("%s: count=0x%08x, wtcon=%08lx\n",
152 __func__, wdt_count, wtcon); 166 __func__, wdt->count, wtcon);
153 167
154 writel(wdt_count, wdt_base + S3C2410_WTDAT); 168 writel(wdt->count, wdt->reg_base + S3C2410_WTDAT);
155 writel(wdt_count, wdt_base + S3C2410_WTCNT); 169 writel(wdt->count, wdt->reg_base + S3C2410_WTCNT);
156 writel(wtcon, wdt_base + S3C2410_WTCON); 170 writel(wtcon, wdt->reg_base + S3C2410_WTCON);
157 spin_unlock(&wdt_lock); 171 spin_unlock(&wdt->lock);
158 172
159 return 0; 173 return 0;
160} 174}
161 175
162static inline int s3c2410wdt_is_running(void) 176static inline int s3c2410wdt_is_running(struct s3c2410_wdt *wdt)
163{ 177{
164 return readl(wdt_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE; 178 return readl(wdt->reg_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE;
165} 179}
166 180
167static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeout) 181static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeout)
168{ 182{
169 unsigned long freq = clk_get_rate(wdt_clock); 183 struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
184 unsigned long freq = clk_get_rate(wdt->clock);
170 unsigned int count; 185 unsigned int count;
171 unsigned int divisor = 1; 186 unsigned int divisor = 1;
172 unsigned long wtcon; 187 unsigned long wtcon;
@@ -192,7 +207,7 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou
192 } 207 }
193 208
194 if ((count / divisor) >= 0x10000) { 209 if ((count / divisor) >= 0x10000) {
195 dev_err(wdt_dev, "timeout %d too big\n", timeout); 210 dev_err(wdt->dev, "timeout %d too big\n", timeout);
196 return -EINVAL; 211 return -EINVAL;
197 } 212 }
198 } 213 }
@@ -201,15 +216,15 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou
201 __func__, timeout, divisor, count, count/divisor); 216 __func__, timeout, divisor, count, count/divisor);
202 217
203 count /= divisor; 218 count /= divisor;
204 wdt_count = count; 219 wdt->count = count;
205 220
206 /* update the pre-scaler */ 221 /* update the pre-scaler */
207 wtcon = readl(wdt_base + S3C2410_WTCON); 222 wtcon = readl(wdt->reg_base + S3C2410_WTCON);
208 wtcon &= ~S3C2410_WTCON_PRESCALE_MASK; 223 wtcon &= ~S3C2410_WTCON_PRESCALE_MASK;
209 wtcon |= S3C2410_WTCON_PRESCALE(divisor-1); 224 wtcon |= S3C2410_WTCON_PRESCALE(divisor-1);
210 225
211 writel(count, wdt_base + S3C2410_WTDAT); 226 writel(count, wdt->reg_base + S3C2410_WTDAT);
212 writel(wtcon, wdt_base + S3C2410_WTCON); 227 writel(wtcon, wdt->reg_base + S3C2410_WTCON);
213 228
214 wdd->timeout = (count * divisor) / freq; 229 wdd->timeout = (count * divisor) / freq;
215 230
@@ -242,21 +257,23 @@ static struct watchdog_device s3c2410_wdd = {
242 257
243static irqreturn_t s3c2410wdt_irq(int irqno, void *param) 258static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
244{ 259{
245 dev_info(wdt_dev, "watchdog timer expired (irq)\n"); 260 struct s3c2410_wdt *wdt = platform_get_drvdata(param);
261
262 dev_info(wdt->dev, "watchdog timer expired (irq)\n");
246 263
247 s3c2410wdt_keepalive(&s3c2410_wdd); 264 s3c2410wdt_keepalive(&wdt->wdt_device);
248 return IRQ_HANDLED; 265 return IRQ_HANDLED;
249} 266}
250 267
251
252#ifdef CONFIG_CPU_FREQ 268#ifdef CONFIG_CPU_FREQ
253 269
254static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb, 270static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb,
255 unsigned long val, void *data) 271 unsigned long val, void *data)
256{ 272{
257 int ret; 273 int ret;
274 struct s3c2410_wdt *wdt = freq_to_wdt(nb);
258 275
259 if (!s3c2410wdt_is_running()) 276 if (!s3c2410wdt_is_running(wdt))
260 goto done; 277 goto done;
261 278
262 if (val == CPUFREQ_PRECHANGE) { 279 if (val == CPUFREQ_PRECHANGE) {
@@ -265,14 +282,15 @@ static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb,
265 * the watchdog is running. 282 * the watchdog is running.
266 */ 283 */
267 284
268 s3c2410wdt_keepalive(&s3c2410_wdd); 285 s3c2410wdt_keepalive(&wdt->wdt_device);
269 } else if (val == CPUFREQ_POSTCHANGE) { 286 } else if (val == CPUFREQ_POSTCHANGE) {
270 s3c2410wdt_stop(&s3c2410_wdd); 287 s3c2410wdt_stop(&wdt->wdt_device);
271 288
272 ret = s3c2410wdt_set_heartbeat(&s3c2410_wdd, s3c2410_wdd.timeout); 289 ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device,
290 wdt->wdt_device.timeout);
273 291
274 if (ret >= 0) 292 if (ret >= 0)
275 s3c2410wdt_start(&s3c2410_wdd); 293 s3c2410wdt_start(&wdt->wdt_device);
276 else 294 else
277 goto err; 295 goto err;
278 } 296 }
@@ -281,34 +299,35 @@ done:
281 return 0; 299 return 0;
282 300
283 err: 301 err:
284 dev_err(wdt_dev, "cannot set new value for timeout %d\n", 302 dev_err(wdt->dev, "cannot set new value for timeout %d\n",
285 s3c2410_wdd.timeout); 303 wdt->wdt_device.timeout);
286 return ret; 304 return ret;
287} 305}
288 306
289static struct notifier_block s3c2410wdt_cpufreq_transition_nb = { 307static inline int s3c2410wdt_cpufreq_register(struct s3c2410_wdt *wdt)
290 .notifier_call = s3c2410wdt_cpufreq_transition,
291};
292
293static inline int s3c2410wdt_cpufreq_register(void)
294{ 308{
295 return cpufreq_register_notifier(&s3c2410wdt_cpufreq_transition_nb, 309 wdt->freq_transition.notifier_call = s3c2410wdt_cpufreq_transition;
310
311 return cpufreq_register_notifier(&wdt->freq_transition,
296 CPUFREQ_TRANSITION_NOTIFIER); 312 CPUFREQ_TRANSITION_NOTIFIER);
297} 313}
298 314
299static inline void s3c2410wdt_cpufreq_deregister(void) 315static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt)
300{ 316{
301 cpufreq_unregister_notifier(&s3c2410wdt_cpufreq_transition_nb, 317 wdt->freq_transition.notifier_call = s3c2410wdt_cpufreq_transition;
318
319 cpufreq_unregister_notifier(&wdt->freq_transition,
302 CPUFREQ_TRANSITION_NOTIFIER); 320 CPUFREQ_TRANSITION_NOTIFIER);
303} 321}
304 322
305#else 323#else
306static inline int s3c2410wdt_cpufreq_register(void) 324
325static inline int s3c2410wdt_cpufreq_register(struct s3c2410_wdt *wdt)
307{ 326{
308 return 0; 327 return 0;
309} 328}
310 329
311static inline void s3c2410wdt_cpufreq_deregister(void) 330static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt)
312{ 331{
313} 332}
314#endif 333#endif
@@ -316,6 +335,9 @@ static inline void s3c2410wdt_cpufreq_deregister(void)
316static int s3c2410wdt_probe(struct platform_device *pdev) 335static int s3c2410wdt_probe(struct platform_device *pdev)
317{ 336{
318 struct device *dev; 337 struct device *dev;
338 struct s3c2410_wdt *wdt;
339 struct resource *wdt_mem;
340 struct resource *wdt_irq;
319 unsigned int wtcon; 341 unsigned int wtcon;
320 int started = 0; 342 int started = 0;
321 int ret; 343 int ret;
@@ -323,13 +345,14 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
323 DBG("%s: probe=%p\n", __func__, pdev); 345 DBG("%s: probe=%p\n", __func__, pdev);
324 346
325 dev = &pdev->dev; 347 dev = &pdev->dev;
326 wdt_dev = &pdev->dev;
327 348
328 wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 349 wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
329 if (wdt_mem == NULL) { 350 if (!wdt)
330 dev_err(dev, "no memory resource specified\n"); 351 return -ENOMEM;
331 return -ENOENT; 352
332 } 353 wdt->dev = &pdev->dev;
354 spin_lock_init(&wdt->lock);
355 wdt->wdt_device = s3c2410_wdd;
333 356
334 wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 357 wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
335 if (wdt_irq == NULL) { 358 if (wdt_irq == NULL) {
@@ -339,35 +362,40 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
339 } 362 }
340 363
341 /* get the memory region for the watchdog timer */ 364 /* get the memory region for the watchdog timer */
342 wdt_base = devm_ioremap_resource(dev, wdt_mem); 365 wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
343 if (IS_ERR(wdt_base)) { 366 wdt->reg_base = devm_ioremap_resource(dev, wdt_mem);
344 ret = PTR_ERR(wdt_base); 367 if (IS_ERR(wdt->reg_base)) {
368 ret = PTR_ERR(wdt->reg_base);
345 goto err; 369 goto err;
346 } 370 }
347 371
348 DBG("probe: mapped wdt_base=%p\n", wdt_base); 372 DBG("probe: mapped reg_base=%p\n", wdt->reg_base);
349 373
350 wdt_clock = devm_clk_get(dev, "watchdog"); 374 wdt->clock = devm_clk_get(dev, "watchdog");
351 if (IS_ERR(wdt_clock)) { 375 if (IS_ERR(wdt->clock)) {
352 dev_err(dev, "failed to find watchdog clock source\n"); 376 dev_err(dev, "failed to find watchdog clock source\n");
353 ret = PTR_ERR(wdt_clock); 377 ret = PTR_ERR(wdt->clock);
354 goto err; 378 goto err;
355 } 379 }
356 380
357 clk_prepare_enable(wdt_clock); 381 clk_prepare_enable(wdt->clock);
358 382
359 ret = s3c2410wdt_cpufreq_register(); 383 ret = s3c2410wdt_cpufreq_register(wdt);
360 if (ret < 0) { 384 if (ret < 0) {
361 dev_err(dev, "failed to register cpufreq\n"); 385 dev_err(dev, "failed to register cpufreq\n");
362 goto err_clk; 386 goto err_clk;
363 } 387 }
364 388
389 watchdog_set_drvdata(&wdt->wdt_device, wdt);
390
365 /* see if we can actually set the requested timer margin, and if 391 /* see if we can actually set the requested timer margin, and if
366 * not, try the default value */ 392 * not, try the default value */
367 393
368 watchdog_init_timeout(&s3c2410_wdd, tmr_margin, &pdev->dev); 394 watchdog_init_timeout(&wdt->wdt_device, tmr_margin, &pdev->dev);
369 if (s3c2410wdt_set_heartbeat(&s3c2410_wdd, s3c2410_wdd.timeout)) { 395 ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device,
370 started = s3c2410wdt_set_heartbeat(&s3c2410_wdd, 396 wdt->wdt_device.timeout);
397 if (ret) {
398 started = s3c2410wdt_set_heartbeat(&wdt->wdt_device,
371 CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); 399 CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
372 400
373 if (started == 0) 401 if (started == 0)
@@ -386,9 +414,9 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
386 goto err_cpufreq; 414 goto err_cpufreq;
387 } 415 }
388 416
389 watchdog_set_nowayout(&s3c2410_wdd, nowayout); 417 watchdog_set_nowayout(&wdt->wdt_device, nowayout);
390 418
391 ret = watchdog_register_device(&s3c2410_wdd); 419 ret = watchdog_register_device(&wdt->wdt_device);
392 if (ret) { 420 if (ret) {
393 dev_err(dev, "cannot register watchdog (%d)\n", ret); 421 dev_err(dev, "cannot register watchdog (%d)\n", ret);
394 goto err_cpufreq; 422 goto err_cpufreq;
@@ -396,18 +424,20 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
396 424
397 if (tmr_atboot && started == 0) { 425 if (tmr_atboot && started == 0) {
398 dev_info(dev, "starting watchdog timer\n"); 426 dev_info(dev, "starting watchdog timer\n");
399 s3c2410wdt_start(&s3c2410_wdd); 427 s3c2410wdt_start(&wdt->wdt_device);
400 } else if (!tmr_atboot) { 428 } else if (!tmr_atboot) {
401 /* if we're not enabling the watchdog, then ensure it is 429 /* if we're not enabling the watchdog, then ensure it is
402 * disabled if it has been left running from the bootloader 430 * disabled if it has been left running from the bootloader
403 * or other source */ 431 * or other source */
404 432
405 s3c2410wdt_stop(&s3c2410_wdd); 433 s3c2410wdt_stop(&wdt->wdt_device);
406 } 434 }
407 435
436 platform_set_drvdata(pdev, wdt);
437
408 /* print out a statement of readiness */ 438 /* print out a statement of readiness */
409 439
410 wtcon = readl(wdt_base + S3C2410_WTCON); 440 wtcon = readl(wdt->reg_base + S3C2410_WTCON);
411 441
412 dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n", 442 dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n",
413 (wtcon & S3C2410_WTCON_ENABLE) ? "" : "in", 443 (wtcon & S3C2410_WTCON_ENABLE) ? "" : "in",
@@ -417,64 +447,64 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
417 return 0; 447 return 0;
418 448
419 err_cpufreq: 449 err_cpufreq:
420 s3c2410wdt_cpufreq_deregister(); 450 s3c2410wdt_cpufreq_deregister(wdt);
421 451
422 err_clk: 452 err_clk:
423 clk_disable_unprepare(wdt_clock); 453 clk_disable_unprepare(wdt->clock);
424 wdt_clock = NULL; 454 wdt->clock = NULL;
425 455
426 err: 456 err:
427 wdt_irq = NULL;
428 wdt_mem = NULL;
429 return ret; 457 return ret;
430} 458}
431 459
432static int s3c2410wdt_remove(struct platform_device *dev) 460static int s3c2410wdt_remove(struct platform_device *dev)
433{ 461{
434 watchdog_unregister_device(&s3c2410_wdd); 462 struct s3c2410_wdt *wdt = platform_get_drvdata(dev);
435 463
436 s3c2410wdt_cpufreq_deregister(); 464 watchdog_unregister_device(&wdt->wdt_device);
437 465
438 clk_disable_unprepare(wdt_clock); 466 s3c2410wdt_cpufreq_deregister(wdt);
439 wdt_clock = NULL; 467
468 clk_disable_unprepare(wdt->clock);
469 wdt->clock = NULL;
440 470
441 wdt_irq = NULL;
442 wdt_mem = NULL;
443 return 0; 471 return 0;
444} 472}
445 473
446static void s3c2410wdt_shutdown(struct platform_device *dev) 474static void s3c2410wdt_shutdown(struct platform_device *dev)
447{ 475{
448 s3c2410wdt_stop(&s3c2410_wdd); 476 struct s3c2410_wdt *wdt = platform_get_drvdata(dev);
477
478 s3c2410wdt_stop(&wdt->wdt_device);
449} 479}
450 480
451#ifdef CONFIG_PM_SLEEP 481#ifdef CONFIG_PM_SLEEP
452 482
453static unsigned long wtcon_save;
454static unsigned long wtdat_save;
455
456static int s3c2410wdt_suspend(struct device *dev) 483static int s3c2410wdt_suspend(struct device *dev)
457{ 484{
485 struct s3c2410_wdt *wdt = dev_get_drvdata(dev);
486
458 /* Save watchdog state, and turn it off. */ 487 /* Save watchdog state, and turn it off. */
459 wtcon_save = readl(wdt_base + S3C2410_WTCON); 488 wdt->wtcon_save = readl(wdt->reg_base + S3C2410_WTCON);
460 wtdat_save = readl(wdt_base + S3C2410_WTDAT); 489 wdt->wtdat_save = readl(wdt->reg_base + S3C2410_WTDAT);
461 490
462 /* Note that WTCNT doesn't need to be saved. */ 491 /* Note that WTCNT doesn't need to be saved. */
463 s3c2410wdt_stop(&s3c2410_wdd); 492 s3c2410wdt_stop(&wdt->wdt_device);
464 493
465 return 0; 494 return 0;
466} 495}
467 496
468static int s3c2410wdt_resume(struct device *dev) 497static int s3c2410wdt_resume(struct device *dev)
469{ 498{
470 /* Restore watchdog state. */ 499 struct s3c2410_wdt *wdt = dev_get_drvdata(dev);
471 500
472 writel(wtdat_save, wdt_base + S3C2410_WTDAT); 501 /* Restore watchdog state. */
473 writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */ 502 writel(wdt->wtdat_save, wdt->reg_base + S3C2410_WTDAT);
474 writel(wtcon_save, wdt_base + S3C2410_WTCON); 503 writel(wdt->wtdat_save, wdt->reg_base + S3C2410_WTCNT);/* Reset count */
504 writel(wdt->wtcon_save, wdt->reg_base + S3C2410_WTCON);
475 505
476 dev_info(dev, "watchdog %sabled\n", 506 dev_info(dev, "watchdog %sabled\n",
477 (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis"); 507 (wdt->wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
478 508
479 return 0; 509 return 0;
480} 510}
diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c
new file mode 100644
index 000000000000..1f94b42764aa
--- /dev/null
+++ b/drivers/watchdog/sunxi_wdt.c
@@ -0,0 +1,237 @@
1/*
2 * sunxi Watchdog Driver
3 *
4 * Copyright (c) 2013 Carlo Caione
5 * 2012 Henrik Nordstrom
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * Based on xen_wdt.c
13 * (c) Copyright 2010 Novell, Inc.
14 */
15
16#include <linux/clk.h>
17#include <linux/err.h>
18#include <linux/init.h>
19#include <linux/io.h>
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/moduleparam.h>
23#include <linux/of.h>
24#include <linux/platform_device.h>
25#include <linux/types.h>
26#include <linux/watchdog.h>
27
28#define WDT_MAX_TIMEOUT 16
29#define WDT_MIN_TIMEOUT 1
30#define WDT_MODE_TIMEOUT(n) ((n) << 3)
31#define WDT_TIMEOUT_MASK WDT_MODE_TIMEOUT(0x0F)
32
33#define WDT_CTRL 0x00
34#define WDT_CTRL_RELOAD ((1 << 0) | (0x0a57 << 1))
35
36#define WDT_MODE 0x04
37#define WDT_MODE_EN (1 << 0)
38#define WDT_MODE_RST_EN (1 << 1)
39
40#define DRV_NAME "sunxi-wdt"
41#define DRV_VERSION "1.0"
42
43static bool nowayout = WATCHDOG_NOWAYOUT;
44static unsigned int timeout = WDT_MAX_TIMEOUT;
45
46struct sunxi_wdt_dev {
47 struct watchdog_device wdt_dev;
48 void __iomem *wdt_base;
49};
50
51/*
52 * wdt_timeout_map maps the watchdog timer interval value in seconds to
53 * the value of the register WDT_MODE bit 3:6
54 *
55 * [timeout seconds] = register value
56 *
57 */
58
59static const int wdt_timeout_map[] = {
60 [1] = 0b0001, /* 1s */
61 [2] = 0b0010, /* 2s */
62 [3] = 0b0011, /* 3s */
63 [4] = 0b0100, /* 4s */
64 [5] = 0b0101, /* 5s */
65 [6] = 0b0110, /* 6s */
66 [8] = 0b0111, /* 8s */
67 [10] = 0b1000, /* 10s */
68 [12] = 0b1001, /* 12s */
69 [14] = 0b1010, /* 14s */
70 [16] = 0b1011, /* 16s */
71};
72
73static int sunxi_wdt_ping(struct watchdog_device *wdt_dev)
74{
75 struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev);
76 void __iomem *wdt_base = sunxi_wdt->wdt_base;
77
78 iowrite32(WDT_CTRL_RELOAD, wdt_base + WDT_CTRL);
79
80 return 0;
81}
82
83static int sunxi_wdt_set_timeout(struct watchdog_device *wdt_dev,
84 unsigned int timeout)
85{
86 struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev);
87 void __iomem *wdt_base = sunxi_wdt->wdt_base;
88 u32 reg;
89
90 if (wdt_timeout_map[timeout] == 0)
91 timeout++;
92
93 sunxi_wdt->wdt_dev.timeout = timeout;
94
95 reg = ioread32(wdt_base + WDT_MODE);
96 reg &= ~WDT_TIMEOUT_MASK;
97 reg |= WDT_MODE_TIMEOUT(wdt_timeout_map[timeout]);
98 iowrite32(reg, wdt_base + WDT_MODE);
99
100 sunxi_wdt_ping(wdt_dev);
101
102 return 0;
103}
104
105static int sunxi_wdt_stop(struct watchdog_device *wdt_dev)
106{
107 struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev);
108 void __iomem *wdt_base = sunxi_wdt->wdt_base;
109
110 iowrite32(0, wdt_base + WDT_MODE);
111
112 return 0;
113}
114
115static int sunxi_wdt_start(struct watchdog_device *wdt_dev)
116{
117 u32 reg;
118 struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev);
119 void __iomem *wdt_base = sunxi_wdt->wdt_base;
120 int ret;
121
122 ret = sunxi_wdt_set_timeout(&sunxi_wdt->wdt_dev,
123 sunxi_wdt->wdt_dev.timeout);
124 if (ret < 0)
125 return ret;
126
127 reg = ioread32(wdt_base + WDT_MODE);
128 reg |= (WDT_MODE_RST_EN | WDT_MODE_EN);
129 iowrite32(reg, wdt_base + WDT_MODE);
130
131 return 0;
132}
133
134static const struct watchdog_info sunxi_wdt_info = {
135 .identity = DRV_NAME,
136 .options = WDIOF_SETTIMEOUT |
137 WDIOF_KEEPALIVEPING |
138 WDIOF_MAGICCLOSE,
139};
140
141static const struct watchdog_ops sunxi_wdt_ops = {
142 .owner = THIS_MODULE,
143 .start = sunxi_wdt_start,
144 .stop = sunxi_wdt_stop,
145 .ping = sunxi_wdt_ping,
146 .set_timeout = sunxi_wdt_set_timeout,
147};
148
149static int __init sunxi_wdt_probe(struct platform_device *pdev)
150{
151 struct sunxi_wdt_dev *sunxi_wdt;
152 struct resource *res;
153 int err;
154
155 sunxi_wdt = devm_kzalloc(&pdev->dev, sizeof(*sunxi_wdt), GFP_KERNEL);
156 if (!sunxi_wdt)
157 return -EINVAL;
158
159 platform_set_drvdata(pdev, sunxi_wdt);
160
161 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
162 sunxi_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res);
163 if (IS_ERR(sunxi_wdt->wdt_base))
164 return PTR_ERR(sunxi_wdt->wdt_base);
165
166 sunxi_wdt->wdt_dev.info = &sunxi_wdt_info;
167 sunxi_wdt->wdt_dev.ops = &sunxi_wdt_ops;
168 sunxi_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT;
169 sunxi_wdt->wdt_dev.max_timeout = WDT_MAX_TIMEOUT;
170 sunxi_wdt->wdt_dev.min_timeout = WDT_MIN_TIMEOUT;
171 sunxi_wdt->wdt_dev.parent = &pdev->dev;
172
173 watchdog_init_timeout(&sunxi_wdt->wdt_dev, timeout, &pdev->dev);
174 watchdog_set_nowayout(&sunxi_wdt->wdt_dev, nowayout);
175
176 watchdog_set_drvdata(&sunxi_wdt->wdt_dev, sunxi_wdt);
177
178 sunxi_wdt_stop(&sunxi_wdt->wdt_dev);
179
180 err = watchdog_register_device(&sunxi_wdt->wdt_dev);
181 if (unlikely(err))
182 return err;
183
184 dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)",
185 sunxi_wdt->wdt_dev.timeout, nowayout);
186
187 return 0;
188}
189
190static int __exit sunxi_wdt_remove(struct platform_device *pdev)
191{
192 struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev);
193
194 watchdog_unregister_device(&sunxi_wdt->wdt_dev);
195 watchdog_set_drvdata(&sunxi_wdt->wdt_dev, NULL);
196
197 return 0;
198}
199
200static void sunxi_wdt_shutdown(struct platform_device *pdev)
201{
202 struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev);
203
204 sunxi_wdt_stop(&sunxi_wdt->wdt_dev);
205}
206
207static const struct of_device_id sunxi_wdt_dt_ids[] = {
208 { .compatible = "allwinner,sun4i-wdt" },
209 { /* sentinel */ }
210};
211MODULE_DEVICE_TABLE(of, sunxi_wdt_dt_ids);
212
213static struct platform_driver sunxi_wdt_driver = {
214 .probe = sunxi_wdt_probe,
215 .remove = sunxi_wdt_remove,
216 .shutdown = sunxi_wdt_shutdown,
217 .driver = {
218 .owner = THIS_MODULE,
219 .name = DRV_NAME,
220 .of_match_table = of_match_ptr(sunxi_wdt_dt_ids)
221 },
222};
223
224module_platform_driver(sunxi_wdt_driver);
225
226module_param(timeout, uint, 0);
227MODULE_PARM_DESC(timeout, "Watchdog heartbeat in seconds");
228
229module_param(nowayout, bool, 0);
230MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
231 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
232
233MODULE_LICENSE("GPL");
234MODULE_AUTHOR("Carlo Caione <carlo.caione@gmail.com>");
235MODULE_AUTHOR("Henrik Nordstrom <henrik@henriknordstrom.net>");
236MODULE_DESCRIPTION("sunxi WatchDog Timer Driver");
237MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c
index 4da59b4d73f0..42913f131dc2 100644
--- a/drivers/watchdog/ts72xx_wdt.c
+++ b/drivers/watchdog/ts72xx_wdt.c
@@ -403,21 +403,11 @@ static int ts72xx_wdt_probe(struct platform_device *pdev)
403 } 403 }
404 404
405 r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); 405 r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
406 if (!r1) {
407 dev_err(&pdev->dev, "failed to get memory resource\n");
408 return -ENODEV;
409 }
410
411 wdt->control_reg = devm_ioremap_resource(&pdev->dev, r1); 406 wdt->control_reg = devm_ioremap_resource(&pdev->dev, r1);
412 if (IS_ERR(wdt->control_reg)) 407 if (IS_ERR(wdt->control_reg))
413 return PTR_ERR(wdt->control_reg); 408 return PTR_ERR(wdt->control_reg);
414 409
415 r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); 410 r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
416 if (!r2) {
417 dev_err(&pdev->dev, "failed to get memory resource\n");
418 return -ENODEV;
419 }
420
421 wdt->feed_reg = devm_ioremap_resource(&pdev->dev, r2); 411 wdt->feed_reg = devm_ioremap_resource(&pdev->dev, r2);
422 if (IS_ERR(wdt->feed_reg)) 412 if (IS_ERR(wdt->feed_reg))
423 return PTR_ERR(wdt->feed_reg); 413 return PTR_ERR(wdt->feed_reg);