aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/bcm47xx_wdt.c
diff options
context:
space:
mode:
authorHauke Mehrtens <hauke@hauke-m.de>2013-01-24 12:13:34 -0500
committerWim Van Sebroeck <wim@iguana.be>2013-03-01 06:47:16 -0500
commitf82dedf812ecdf0c19c6c240e85a4a487ab62016 (patch)
tree656ae38bd44696b7c7b4ea4d46d5d323cb418fcb /drivers/watchdog/bcm47xx_wdt.c
parent5434a04db905bb0af281cdb758d1357fbecd0fe8 (diff)
watchdog: bcm47xx_wdt.c: use platform device
Instead of accessing the function to set the watchdog timer directly, register a platform driver the platform could register to use this watchdog driver. Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog/bcm47xx_wdt.c')
-rw-r--r--drivers/watchdog/bcm47xx_wdt.c156
1 files changed, 78 insertions, 78 deletions
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index 4c520d68397e..97ccfce0dabb 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright (C) 2008 Aleksandar Radovanovic <biblbroks@sezampro.rs> 4 * Copyright (C) 2008 Aleksandar Radovanovic <biblbroks@sezampro.rs>
5 * Copyright (C) 2009 Matthieu CASTET <castet.matthieu@free.fr> 5 * Copyright (C) 2009 Matthieu CASTET <castet.matthieu@free.fr>
6 * Copyright (C) 2012-2013 Hauke Mehrtens <hauke@hauke-m.de>
6 * 7 *
7 * This program is free software; you can redistribute it and/or 8 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 9 * modify it under the terms of the GNU General Public License
@@ -12,19 +13,19 @@
12 13
13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14 15
16#include <linux/bcm47xx_wdt.h>
15#include <linux/bitops.h> 17#include <linux/bitops.h>
16#include <linux/errno.h> 18#include <linux/errno.h>
17#include <linux/init.h> 19#include <linux/init.h>
18#include <linux/kernel.h> 20#include <linux/kernel.h>
19#include <linux/module.h> 21#include <linux/module.h>
20#include <linux/moduleparam.h> 22#include <linux/moduleparam.h>
23#include <linux/platform_device.h>
21#include <linux/reboot.h> 24#include <linux/reboot.h>
22#include <linux/types.h> 25#include <linux/types.h>
23#include <linux/watchdog.h> 26#include <linux/watchdog.h>
24#include <linux/timer.h> 27#include <linux/timer.h>
25#include <linux/jiffies.h> 28#include <linux/jiffies.h>
26#include <linux/ssb/ssb_embedded.h>
27#include <asm/mach-bcm47xx/bcm47xx.h>
28 29
29#define DRV_NAME "bcm47xx_wdt" 30#define DRV_NAME "bcm47xx_wdt"
30 31
@@ -43,48 +44,19 @@ MODULE_PARM_DESC(nowayout,
43 "Watchdog cannot be stopped once started (default=" 44 "Watchdog cannot be stopped once started (default="
44 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 45 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
45 46
46static struct timer_list wdt_timer; 47static inline struct bcm47xx_wdt *bcm47xx_wdt_get(struct watchdog_device *wdd)
47static atomic_t ticks;
48
49static inline void bcm47xx_wdt_hw_start(void)
50{ 48{
51 /* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */ 49 return container_of(wdd, struct bcm47xx_wdt, wdd);
52 switch (bcm47xx_bus_type) {
53#ifdef CONFIG_BCM47XX_SSB
54 case BCM47XX_BUS_TYPE_SSB:
55 ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
56 break;
57#endif
58#ifdef CONFIG_BCM47XX_BCMA
59 case BCM47XX_BUS_TYPE_BCMA:
60 bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc,
61 0xfffffff);
62 break;
63#endif
64 }
65} 50}
66 51
67static inline int bcm47xx_wdt_hw_stop(void) 52static void bcm47xx_timer_tick(unsigned long data)
68{ 53{
69 switch (bcm47xx_bus_type) { 54 struct bcm47xx_wdt *wdt = (struct bcm47xx_wdt *)data;
70#ifdef CONFIG_BCM47XX_SSB 55 u32 next_tick = min(wdt->wdd.timeout * 1000, wdt->max_timer_ms);
71 case BCM47XX_BUS_TYPE_SSB:
72 return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
73#endif
74#ifdef CONFIG_BCM47XX_BCMA
75 case BCM47XX_BUS_TYPE_BCMA:
76 bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
77 return 0;
78#endif
79 }
80 return -EINVAL;
81}
82 56
83static void bcm47xx_timer_tick(unsigned long unused) 57 if (!atomic_dec_and_test(&wdt->soft_ticks)) {
84{ 58 wdt->timer_set_ms(wdt, next_tick);
85 if (!atomic_dec_and_test(&ticks)) { 59 mod_timer(&wdt->soft_timer, jiffies + HZ);
86 bcm47xx_wdt_hw_start();
87 mod_timer(&wdt_timer, jiffies + HZ);
88 } else { 60 } else {
89 pr_crit("Watchdog will fire soon!!!\n"); 61 pr_crit("Watchdog will fire soon!!!\n");
90 } 62 }
@@ -92,23 +64,29 @@ static void bcm47xx_timer_tick(unsigned long unused)
92 64
93static int bcm47xx_wdt_keepalive(struct watchdog_device *wdd) 65static int bcm47xx_wdt_keepalive(struct watchdog_device *wdd)
94{ 66{
95 atomic_set(&ticks, wdt_time); 67 struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
68
69 atomic_set(&wdt->soft_ticks, wdd->timeout);
96 70
97 return 0; 71 return 0;
98} 72}
99 73
100static int bcm47xx_wdt_start(struct watchdog_device *wdd) 74static int bcm47xx_wdt_start(struct watchdog_device *wdd)
101{ 75{
102 bcm47xx_wdt_pet(); 76 struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
103 bcm47xx_timer_tick(0); 77
78 bcm47xx_wdt_keepalive(wdd);
79 bcm47xx_timer_tick((unsigned long)wdt);
104 80
105 return 0; 81 return 0;
106} 82}
107 83
108static int bcm47xx_wdt_stop(struct watchdog_device *wdd) 84static int bcm47xx_wdt_stop(struct watchdog_device *wdd)
109{ 85{
110 del_timer_sync(&wdt_timer); 86 struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
111 bcm47xx_wdt_hw_stop(); 87
88 del_timer_sync(&wdt->soft_timer);
89 wdt->timer_set(wdt, 0);
112 90
113 return 0; 91 return 0;
114} 92}
@@ -116,10 +94,13 @@ static int bcm47xx_wdt_stop(struct watchdog_device *wdd)
116static int bcm47xx_wdt_set_timeout(struct watchdog_device *wdd, 94static int bcm47xx_wdt_set_timeout(struct watchdog_device *wdd,
117 unsigned int new_time) 95 unsigned int new_time)
118{ 96{
119 if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) 97 if (new_time < 1 || new_time > WDT_MAX_TIME) {
98 pr_warn("timeout value must be 1<=x<=%d, using %d\n",
99 WDT_MAX_TIME, new_time);
120 return -EINVAL; 100 return -EINVAL;
101 }
121 102
122 wdt_time = new_time; 103 wdd->timeout = new_time;
123 return 0; 104 return 0;
124} 105}
125 106
@@ -133,8 +114,11 @@ static const struct watchdog_info bcm47xx_wdt_info = {
133static int bcm47xx_wdt_notify_sys(struct notifier_block *this, 114static int bcm47xx_wdt_notify_sys(struct notifier_block *this,
134 unsigned long code, void *unused) 115 unsigned long code, void *unused)
135{ 116{
117 struct bcm47xx_wdt *wdt;
118
119 wdt = container_of(this, struct bcm47xx_wdt, notifier);
136 if (code == SYS_DOWN || code == SYS_HALT) 120 if (code == SYS_DOWN || code == SYS_HALT)
137 bcm47xx_wdt_stop(); 121 wdt->wdd.ops->stop(&wdt->wdd);
138 return NOTIFY_DONE; 122 return NOTIFY_DONE;
139} 123}
140 124
@@ -146,56 +130,72 @@ static struct watchdog_ops bcm47xx_wdt_ops = {
146 .set_timeout = bcm47xx_wdt_set_timeout, 130 .set_timeout = bcm47xx_wdt_set_timeout,
147}; 131};
148 132
149static struct watchdog_device bcm47xx_wdt_wdd = { 133static int bcm47xx_wdt_probe(struct platform_device *pdev)
150 .info = &bcm47xx_wdt_info,
151 .ops = &bcm47xx_wdt_ops,
152};
153
154static struct notifier_block bcm47xx_wdt_notifier = {
155 .notifier_call = bcm47xx_wdt_notify_sys,
156};
157
158static int __init bcm47xx_wdt_init(void)
159{ 134{
160 int ret; 135 int ret;
136 struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev);
161 137
162 if (bcm47xx_wdt_hw_stop() < 0) 138 if (!wdt)
163 return -ENODEV; 139 return -ENXIO;
164 140
165 setup_timer(&wdt_timer, bcm47xx_timer_tick, 0L); 141 setup_timer(&wdt->soft_timer, bcm47xx_timer_tick,
142 (long unsigned int)wdt);
166 143
167 if (bcm47xx_wdt_settimeout(wdt_time)) { 144 wdt->wdd.ops = &bcm47xx_wdt_ops;
168 bcm47xx_wdt_settimeout(WDT_DEFAULT_TIME); 145 wdt->wdd.info = &bcm47xx_wdt_info;
169 pr_info("wdt_time value must be 0 < wdt_time < %d, using %d\n", 146 wdt->wdd.timeout = WDT_DEFAULT_TIME;
170 (WDT_MAX_TIME + 1), wdt_time); 147 ret = wdt->wdd.ops->set_timeout(&wdt->wdd, timeout);
171 } 148 if (ret)
172 watchdog_set_nowayout(&bcm47xx_wdt_wdd, nowayout); 149 goto err_timer;
150 watchdog_set_nowayout(&wdt->wdd, nowayout);
151
152 wdt->notifier.notifier_call = &bcm47xx_wdt_notify_sys;
173 153
174 ret = register_reboot_notifier(&bcm47xx_wdt_notifier); 154 ret = register_reboot_notifier(&wdt->notifier);
175 if (ret) 155 if (ret)
176 return ret; 156 goto err_timer;
177 157
178 ret = watchdog_register_device(&bcm47xx_wdt_wdd); 158 ret = watchdog_register_device(&wdt->wdd);
179 if (ret) { 159 if (ret)
180 unregister_reboot_notifier(&bcm47xx_wdt_notifier); 160 goto err_notifier;
181 return ret;
182 }
183 161
184 pr_info("BCM47xx Watchdog Timer enabled (%d seconds%s)\n", 162 pr_info("BCM47xx Watchdog Timer enabled (%d seconds%s)\n",
185 wdt_time, nowayout ? ", nowayout" : ""); 163 wdt_time, nowayout ? ", nowayout" : "");
186 return 0; 164 return 0;
165
166err_notifier:
167 unregister_reboot_notifier(&wdt->notifier);
168err_timer:
169 del_timer_sync(&wdt->soft_timer);
170
171 return ret;
187} 172}
188 173
189static void __exit bcm47xx_wdt_exit(void) 174static int bcm47xx_wdt_remove(struct platform_device *pdev)
190{ 175{
191 watchdog_unregister_device(&bcm47xx_wdt_wdd); 176 struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev);
177
178 if (!wdt)
179 return -ENXIO;
180
181 watchdog_unregister_device(&wdt->wdd);
182 unregister_reboot_notifier(&wdt->notifier);
192 183
193 unregister_reboot_notifier(&bcm47xx_wdt_notifier); 184 return 0;
194} 185}
195 186
196module_init(bcm47xx_wdt_init); 187static struct platform_driver bcm47xx_wdt_driver = {
197module_exit(bcm47xx_wdt_exit); 188 .driver = {
189 .owner = THIS_MODULE,
190 .name = "bcm47xx-wdt",
191 },
192 .probe = bcm47xx_wdt_probe,
193 .remove = bcm47xx_wdt_remove,
194};
195
196module_platform_driver(bcm47xx_wdt_driver);
198 197
199MODULE_AUTHOR("Aleksandar Radovanovic"); 198MODULE_AUTHOR("Aleksandar Radovanovic");
199MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
200MODULE_DESCRIPTION("Watchdog driver for Broadcom BCM47xx"); 200MODULE_DESCRIPTION("Watchdog driver for Broadcom BCM47xx");
201MODULE_LICENSE("GPL"); 201MODULE_LICENSE("GPL");