Commit f82dedf812ecdf0c19c6c240e85a4a487ab62016

Authored by Hauke Mehrtens
Committed by Wim Van Sebroeck
1 parent 5434a04db9

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>

Showing 2 changed files with 87 additions and 78 deletions Side-by-side Diff

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