aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Looijmans <mike.looijmans@topic.nl>2015-01-14 01:28:29 -0500
committerWim Van Sebroeck <wim@iguana.be>2015-02-17 15:33:22 -0500
commitba804a9510df555c42c2be6c340960879afe39d2 (patch)
tree39ddf8b02b9004c5f9124c5ebd2eae23e149344c
parent396f163ceba3ac2829e3076764efcfb10797293c (diff)
watchdog: gpio_wdt: Add "always_running" feature to GPIO watchdog
On some chips, like the TPS386000, the trigger cannot be disabled and the CPU must keep toggling the line at all times. Add a switch "always_running" to keep toggling the GPIO line regardless of the state of the soft part of the watchdog. The "armed" member keeps track of whether a timeout must also cause a reset. Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
-rw-r--r--Documentation/devicetree/bindings/watchdog/gpio-wdt.txt5
-rw-r--r--drivers/watchdog/gpio_wdt.c37
2 files changed, 34 insertions, 8 deletions
diff --git a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
index 37afec194949..198794963786 100644
--- a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
@@ -13,6 +13,11 @@ Required Properties:
13 by the GPIO flags. 13 by the GPIO flags.
14- hw_margin_ms: Maximum time to reset watchdog circuit (milliseconds). 14- hw_margin_ms: Maximum time to reset watchdog circuit (milliseconds).
15 15
16Optional Properties:
17- always-running: If the watchdog timer cannot be disabled, add this flag to
18 have the driver keep toggling the signal without a client. It will only cease
19 to toggle the signal when the device is open and the timeout elapsed.
20
16Example: 21Example:
17 watchdog: watchdog { 22 watchdog: watchdog {
18 /* ADM706 */ 23 /* ADM706 */
diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c
index bbdb19b45332..cbc313d37c59 100644
--- a/drivers/watchdog/gpio_wdt.c
+++ b/drivers/watchdog/gpio_wdt.c
@@ -31,6 +31,8 @@ struct gpio_wdt_priv {
31 int gpio; 31 int gpio;
32 bool active_low; 32 bool active_low;
33 bool state; 33 bool state;
34 bool always_running;
35 bool armed;
34 unsigned int hw_algo; 36 unsigned int hw_algo;
35 unsigned int hw_margin; 37 unsigned int hw_margin;
36 unsigned long last_jiffies; 38 unsigned long last_jiffies;
@@ -48,14 +50,20 @@ static void gpio_wdt_disable(struct gpio_wdt_priv *priv)
48 gpio_direction_input(priv->gpio); 50 gpio_direction_input(priv->gpio);
49} 51}
50 52
51static int gpio_wdt_start(struct watchdog_device *wdd) 53static void gpio_wdt_start_impl(struct gpio_wdt_priv *priv)
52{ 54{
53 struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
54
55 priv->state = priv->active_low; 55 priv->state = priv->active_low;
56 gpio_direction_output(priv->gpio, priv->state); 56 gpio_direction_output(priv->gpio, priv->state);
57 priv->last_jiffies = jiffies; 57 priv->last_jiffies = jiffies;
58 mod_timer(&priv->timer, priv->last_jiffies + priv->hw_margin); 58 mod_timer(&priv->timer, priv->last_jiffies + priv->hw_margin);
59}
60
61static int gpio_wdt_start(struct watchdog_device *wdd)
62{
63 struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
64
65 gpio_wdt_start_impl(priv);
66 priv->armed = true;
59 67
60 return 0; 68 return 0;
61} 69}
@@ -64,8 +72,11 @@ static int gpio_wdt_stop(struct watchdog_device *wdd)
64{ 72{
65 struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); 73 struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
66 74
67 mod_timer(&priv->timer, 0); 75 priv->armed = false;
68 gpio_wdt_disable(priv); 76 if (!priv->always_running) {
77 mod_timer(&priv->timer, 0);
78 gpio_wdt_disable(priv);
79 }
69 80
70 return 0; 81 return 0;
71} 82}
@@ -91,8 +102,8 @@ static void gpio_wdt_hwping(unsigned long data)
91 struct watchdog_device *wdd = (struct watchdog_device *)data; 102 struct watchdog_device *wdd = (struct watchdog_device *)data;
92 struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); 103 struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
93 104
94 if (time_after(jiffies, priv->last_jiffies + 105 if (priv->armed && time_after(jiffies, priv->last_jiffies +
95 msecs_to_jiffies(wdd->timeout * 1000))) { 106 msecs_to_jiffies(wdd->timeout * 1000))) {
96 dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n"); 107 dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n");
97 return; 108 return;
98 } 109 }
@@ -197,6 +208,9 @@ static int gpio_wdt_probe(struct platform_device *pdev)
197 /* Use safe value (1/2 of real timeout) */ 208 /* Use safe value (1/2 of real timeout) */
198 priv->hw_margin = msecs_to_jiffies(hw_margin / 2); 209 priv->hw_margin = msecs_to_jiffies(hw_margin / 2);
199 210
211 priv->always_running = of_property_read_bool(pdev->dev.of_node,
212 "always-running");
213
200 watchdog_set_drvdata(&priv->wdd, priv); 214 watchdog_set_drvdata(&priv->wdd, priv);
201 215
202 priv->wdd.info = &gpio_wdt_ident; 216 priv->wdd.info = &gpio_wdt_ident;
@@ -216,8 +230,15 @@ static int gpio_wdt_probe(struct platform_device *pdev)
216 priv->notifier.notifier_call = gpio_wdt_notify_sys; 230 priv->notifier.notifier_call = gpio_wdt_notify_sys;
217 ret = register_reboot_notifier(&priv->notifier); 231 ret = register_reboot_notifier(&priv->notifier);
218 if (ret) 232 if (ret)
219 watchdog_unregister_device(&priv->wdd); 233 goto error_unregister;
220 234
235 if (priv->always_running)
236 gpio_wdt_start_impl(priv);
237
238 return 0;
239
240error_unregister:
241 watchdog_unregister_device(&priv->wdd);
221 return ret; 242 return ret;
222} 243}
223 244