aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorHauke Mehrtens <hauke@hauke-m.de>2013-01-12 12:14:11 -0500
committerWim Van Sebroeck <wim@iguana.be>2013-03-01 06:47:31 -0500
commite3e83d0001a77cdb337be9170e58b55488835ba0 (patch)
tree2bad2d0197b00acaa6ce11970d6480d186b9f29d /drivers/watchdog
parent93aed1f02a7a67ce81e6bd2e37c3e1d994d33d5b (diff)
watchdog: bcm47xx_wdt.c: add hard timer
The more recent devices have a watchdog timer which could be configured for over 2 hours and not just 2 seconds like the first generation devices. For those devices do not use the extra software timer, but directly program the time into the register. This will automatically be used if the timer supports more than a minute. Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/bcm47xx_wdt.c69
1 files changed, 63 insertions, 6 deletions
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index e3bfe25a71ef..b4021a2b459b 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -31,6 +31,7 @@
31 31
32#define WDT_DEFAULT_TIME 30 /* seconds */ 32#define WDT_DEFAULT_TIME 30 /* seconds */
33#define WDT_SOFTTIMER_MAX 255 /* seconds */ 33#define WDT_SOFTTIMER_MAX 255 /* seconds */
34#define WDT_SOFTTIMER_THRESHOLD 60 /* seconds */
34 35
35static int timeout = WDT_DEFAULT_TIME; 36static int timeout = WDT_DEFAULT_TIME;
36static bool nowayout = WATCHDOG_NOWAYOUT; 37static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -49,6 +50,53 @@ static inline struct bcm47xx_wdt *bcm47xx_wdt_get(struct watchdog_device *wdd)
49 return container_of(wdd, struct bcm47xx_wdt, wdd); 50 return container_of(wdd, struct bcm47xx_wdt, wdd);
50} 51}
51 52
53static int bcm47xx_wdt_hard_keepalive(struct watchdog_device *wdd)
54{
55 struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
56
57 wdt->timer_set_ms(wdt, wdd->timeout * 1000);
58
59 return 0;
60}
61
62static int bcm47xx_wdt_hard_start(struct watchdog_device *wdd)
63{
64 return 0;
65}
66
67static int bcm47xx_wdt_hard_stop(struct watchdog_device *wdd)
68{
69 struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
70
71 wdt->timer_set(wdt, 0);
72
73 return 0;
74}
75
76static int bcm47xx_wdt_hard_set_timeout(struct watchdog_device *wdd,
77 unsigned int new_time)
78{
79 struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
80 u32 max_timer = wdt->max_timer_ms;
81
82 if (new_time < 1 || new_time > max_timer / 1000) {
83 pr_warn("timeout value must be 1<=x<=%d, using %d\n",
84 max_timer / 1000, new_time);
85 return -EINVAL;
86 }
87
88 wdd->timeout = new_time;
89 return 0;
90}
91
92static struct watchdog_ops bcm47xx_wdt_hard_ops = {
93 .owner = THIS_MODULE,
94 .start = bcm47xx_wdt_hard_start,
95 .stop = bcm47xx_wdt_hard_stop,
96 .ping = bcm47xx_wdt_hard_keepalive,
97 .set_timeout = bcm47xx_wdt_hard_set_timeout,
98};
99
52static void bcm47xx_wdt_soft_timer_tick(unsigned long data) 100static void bcm47xx_wdt_soft_timer_tick(unsigned long data)
53{ 101{
54 struct bcm47xx_wdt *wdt = (struct bcm47xx_wdt *)data; 102 struct bcm47xx_wdt *wdt = (struct bcm47xx_wdt *)data;
@@ -133,15 +181,22 @@ static struct watchdog_ops bcm47xx_wdt_soft_ops = {
133static int bcm47xx_wdt_probe(struct platform_device *pdev) 181static int bcm47xx_wdt_probe(struct platform_device *pdev)
134{ 182{
135 int ret; 183 int ret;
184 bool soft;
136 struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev); 185 struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev);
137 186
138 if (!wdt) 187 if (!wdt)
139 return -ENXIO; 188 return -ENXIO;
140 189
141 setup_timer(&wdt->soft_timer, bcm47xx_wdt_soft_timer_tick, 190 soft = wdt->max_timer_ms < WDT_SOFTTIMER_THRESHOLD * 1000;
142 (long unsigned int)wdt); 191
192 if (soft) {
193 wdt->wdd.ops = &bcm47xx_wdt_soft_ops;
194 setup_timer(&wdt->soft_timer, bcm47xx_wdt_soft_timer_tick,
195 (long unsigned int)wdt);
196 } else {
197 wdt->wdd.ops = &bcm47xx_wdt_hard_ops;
198 }
143 199
144 wdt->wdd.ops = &bcm47xx_wdt_soft_ops;
145 wdt->wdd.info = &bcm47xx_wdt_info; 200 wdt->wdd.info = &bcm47xx_wdt_info;
146 wdt->wdd.timeout = WDT_DEFAULT_TIME; 201 wdt->wdd.timeout = WDT_DEFAULT_TIME;
147 ret = wdt->wdd.ops->set_timeout(&wdt->wdd, timeout); 202 ret = wdt->wdd.ops->set_timeout(&wdt->wdd, timeout);
@@ -159,14 +214,16 @@ static int bcm47xx_wdt_probe(struct platform_device *pdev)
159 if (ret) 214 if (ret)
160 goto err_notifier; 215 goto err_notifier;
161 216
162 pr_info("BCM47xx Watchdog Timer enabled (%d seconds%s)\n", 217 dev_info(&pdev->dev, "BCM47xx Watchdog Timer enabled (%d seconds%s%s)\n",
163 timeout, nowayout ? ", nowayout" : ""); 218 timeout, nowayout ? ", nowayout" : "",
219 soft ? ", Software Timer" : "");
164 return 0; 220 return 0;
165 221
166err_notifier: 222err_notifier:
167 unregister_reboot_notifier(&wdt->notifier); 223 unregister_reboot_notifier(&wdt->notifier);
168err_timer: 224err_timer:
169 del_timer_sync(&wdt->soft_timer); 225 if (soft)
226 del_timer_sync(&wdt->soft_timer);
170 227
171 return ret; 228 return ret;
172} 229}