aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@st.com>2012-03-12 00:22:16 -0400
committerWim Van Sebroeck <wim@iguana.be>2012-05-30 01:56:41 -0400
commit4a516539faba13deca2399cff8faaa84d251a4ea (patch)
tree7397aae38c373ef22aa7a7edabdd1b3e0cc66ccf /drivers/watchdog
parent2d8c7ff52c2459a25034ac8ddc230e67cc0e2b67 (diff)
watchdog: sp805_wdt: convert to watchdog core
This patch converts existing sp805 watchdog driver to use already in place common infrastructure present in watchdog core. With this lot of code goes away. Signed-off-by: Viresh Kumar <viresh.kumar@st.com> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/Kconfig1
-rw-r--r--drivers/watchdog/sp805_wdt.c241
2 files changed, 83 insertions, 159 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 004e26152460..fe819b76de56 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -99,6 +99,7 @@ config WM8350_WATCHDOG
99config ARM_SP805_WATCHDOG 99config ARM_SP805_WATCHDOG
100 tristate "ARM SP805 Watchdog" 100 tristate "ARM SP805 Watchdog"
101 depends on ARM_AMBA 101 depends on ARM_AMBA
102 select WATCHDOG_CORE
102 help 103 help
103 ARM Primecell SP805 Watchdog timer. This will reboot your system when 104 ARM Primecell SP805 Watchdog timer. This will reboot your system when
104 the timeout is reached. 105 the timeout is reached.
diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
index bbb170e50055..18d4bcfd1bfc 100644
--- a/drivers/watchdog/sp805_wdt.c
+++ b/drivers/watchdog/sp805_wdt.c
@@ -16,20 +16,17 @@
16#include <linux/amba/bus.h> 16#include <linux/amba/bus.h>
17#include <linux/bitops.h> 17#include <linux/bitops.h>
18#include <linux/clk.h> 18#include <linux/clk.h>
19#include <linux/fs.h>
20#include <linux/init.h> 19#include <linux/init.h>
21#include <linux/io.h> 20#include <linux/io.h>
22#include <linux/ioport.h> 21#include <linux/ioport.h>
23#include <linux/kernel.h> 22#include <linux/kernel.h>
24#include <linux/math64.h> 23#include <linux/math64.h>
25#include <linux/miscdevice.h>
26#include <linux/module.h> 24#include <linux/module.h>
27#include <linux/moduleparam.h> 25#include <linux/moduleparam.h>
28#include <linux/pm.h> 26#include <linux/pm.h>
29#include <linux/slab.h> 27#include <linux/slab.h>
30#include <linux/spinlock.h> 28#include <linux/spinlock.h>
31#include <linux/types.h> 29#include <linux/types.h>
32#include <linux/uaccess.h>
33#include <linux/watchdog.h> 30#include <linux/watchdog.h>
34 31
35/* default timeout in seconds */ 32/* default timeout in seconds */
@@ -56,6 +53,7 @@
56 53
57/** 54/**
58 * struct sp805_wdt: sp805 wdt device structure 55 * struct sp805_wdt: sp805 wdt device structure
56 * @wdd: instance of struct watchdog_device
59 * @lock: spin lock protecting dev structure and io access 57 * @lock: spin lock protecting dev structure and io access
60 * @base: base address of wdt 58 * @base: base address of wdt
61 * @clk: clock structure of wdt 59 * @clk: clock structure of wdt
@@ -65,24 +63,24 @@
65 * @timeout: current programmed timeout 63 * @timeout: current programmed timeout
66 */ 64 */
67struct sp805_wdt { 65struct sp805_wdt {
66 struct watchdog_device wdd;
68 spinlock_t lock; 67 spinlock_t lock;
69 void __iomem *base; 68 void __iomem *base;
70 struct clk *clk; 69 struct clk *clk;
71 struct amba_device *adev; 70 struct amba_device *adev;
72 unsigned long status;
73 #define WDT_BUSY 0
74 #define WDT_CAN_BE_CLOSED 1
75 unsigned int load_val; 71 unsigned int load_val;
76 unsigned int timeout; 72 unsigned int timeout;
77}; 73};
78 74
79/* local variables */
80static struct sp805_wdt *wdt;
81static bool nowayout = WATCHDOG_NOWAYOUT; 75static bool nowayout = WATCHDOG_NOWAYOUT;
76module_param(nowayout, bool, 0);
77MODULE_PARM_DESC(nowayout,
78 "Set to 1 to keep watchdog running after device release");
82 79
83/* This routine finds load value that will reset system in required timout */ 80/* This routine finds load value that will reset system in required timout */
84static void wdt_setload(unsigned int timeout) 81static int wdt_setload(struct watchdog_device *wdd, unsigned int timeout)
85{ 82{
83 struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
86 u64 load, rate; 84 u64 load, rate;
87 85
88 rate = clk_get_rate(wdt->clk); 86 rate = clk_get_rate(wdt->clk);
@@ -103,11 +101,14 @@ static void wdt_setload(unsigned int timeout)
103 /* roundup timeout to closest positive integer value */ 101 /* roundup timeout to closest positive integer value */
104 wdt->timeout = div_u64((load + 1) * 2 + (rate / 2), rate); 102 wdt->timeout = div_u64((load + 1) * 2 + (rate / 2), rate);
105 spin_unlock(&wdt->lock); 103 spin_unlock(&wdt->lock);
104
105 return 0;
106} 106}
107 107
108/* returns number of seconds left for reset to occur */ 108/* returns number of seconds left for reset to occur */
109static u32 wdt_timeleft(void) 109static unsigned int wdt_timeleft(struct watchdog_device *wdd)
110{ 110{
111 struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
111 u64 load, rate; 112 u64 load, rate;
112 113
113 rate = clk_get_rate(wdt->clk); 114 rate = clk_get_rate(wdt->clk);
@@ -123,166 +124,88 @@ static u32 wdt_timeleft(void)
123 return div_u64(load, rate); 124 return div_u64(load, rate);
124} 125}
125 126
126/* enables watchdog timers reset */ 127static int wdt_config(struct watchdog_device *wdd, bool ping)
127static void wdt_enable(void)
128{ 128{
129 struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
130 int ret;
131
132 if (!ping) {
133 ret = clk_enable(wdt->clk);
134 if (ret) {
135 dev_err(&wdt->adev->dev, "clock enable fail");
136 return ret;
137 }
138 }
139
129 spin_lock(&wdt->lock); 140 spin_lock(&wdt->lock);
130 141
131 writel_relaxed(UNLOCK, wdt->base + WDTLOCK); 142 writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
132 writel_relaxed(wdt->load_val, wdt->base + WDTLOAD); 143 writel_relaxed(wdt->load_val, wdt->base + WDTLOAD);
133 writel_relaxed(INT_MASK, wdt->base + WDTINTCLR);
134 writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL);
135 writel_relaxed(LOCK, wdt->base + WDTLOCK);
136
137 /* Flush posted writes. */
138 readl_relaxed(wdt->base + WDTLOCK);
139 spin_unlock(&wdt->lock);
140}
141 144
142/* disables watchdog timers reset */ 145 if (!ping) {
143static void wdt_disable(void) 146 writel_relaxed(INT_MASK, wdt->base + WDTINTCLR);
144{ 147 writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base +
145 spin_lock(&wdt->lock); 148 WDTCONTROL);
149 }
146 150
147 writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
148 writel_relaxed(0, wdt->base + WDTCONTROL);
149 writel_relaxed(LOCK, wdt->base + WDTLOCK); 151 writel_relaxed(LOCK, wdt->base + WDTLOCK);
150 152
151 /* Flush posted writes. */ 153 /* Flush posted writes. */
152 readl_relaxed(wdt->base + WDTLOCK); 154 readl_relaxed(wdt->base + WDTLOCK);
153 spin_unlock(&wdt->lock); 155 spin_unlock(&wdt->lock);
156
157 return 0;
154} 158}
155 159
156static ssize_t sp805_wdt_write(struct file *file, const char *data, 160static int wdt_ping(struct watchdog_device *wdd)
157 size_t len, loff_t *ppos)
158{ 161{
159 if (len) { 162 return wdt_config(wdd, true);
160 if (!nowayout) {
161 size_t i;
162
163 clear_bit(WDT_CAN_BE_CLOSED, &wdt->status);
164
165 for (i = 0; i != len; i++) {
166 char c;
167
168 if (get_user(c, data + i))
169 return -EFAULT;
170 /* Check for Magic Close character */
171 if (c == 'V') {
172 set_bit(WDT_CAN_BE_CLOSED,
173 &wdt->status);
174 break;
175 }
176 }
177 }
178 wdt_enable();
179 }
180 return len;
181} 163}
182 164
183static const struct watchdog_info ident = { 165/* enables watchdog timers reset */
184 .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, 166static int wdt_enable(struct watchdog_device *wdd)
185 .identity = MODULE_NAME,
186};
187
188static long sp805_wdt_ioctl(struct file *file, unsigned int cmd,
189 unsigned long arg)
190{ 167{
191 int ret = -ENOTTY; 168 return wdt_config(wdd, false);
192 unsigned int timeout;
193
194 switch (cmd) {
195 case WDIOC_GETSUPPORT:
196 ret = copy_to_user((struct watchdog_info *)arg, &ident,
197 sizeof(ident)) ? -EFAULT : 0;
198 break;
199
200 case WDIOC_GETSTATUS:
201 ret = put_user(0, (int *)arg);
202 break;
203
204 case WDIOC_KEEPALIVE:
205 wdt_enable();
206 ret = 0;
207 break;
208
209 case WDIOC_SETTIMEOUT:
210 ret = get_user(timeout, (unsigned int *)arg);
211 if (ret)
212 break;
213
214 wdt_setload(timeout);
215
216 wdt_enable();
217 /* Fall through */
218
219 case WDIOC_GETTIMEOUT:
220 ret = put_user(wdt->timeout, (unsigned int *)arg);
221 break;
222 case WDIOC_GETTIMELEFT:
223 ret = put_user(wdt_timeleft(), (unsigned int *)arg);
224 break;
225 }
226 return ret;
227} 169}
228 170
229static int sp805_wdt_open(struct inode *inode, struct file *file) 171/* disables watchdog timers reset */
172static int wdt_disable(struct watchdog_device *wdd)
230{ 173{
231 int ret = 0; 174 struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
232 175
233 if (test_and_set_bit(WDT_BUSY, &wdt->status)) 176 spin_lock(&wdt->lock);
234 return -EBUSY;
235
236 ret = clk_enable(wdt->clk);
237 if (ret) {
238 dev_err(&wdt->adev->dev, "clock enable fail");
239 goto err;
240 }
241
242 wdt_enable();
243
244 /* can not be closed, once enabled */
245 clear_bit(WDT_CAN_BE_CLOSED, &wdt->status);
246 return nonseekable_open(inode, file);
247 177
248err: 178 writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
249 clear_bit(WDT_BUSY, &wdt->status); 179 writel_relaxed(0, wdt->base + WDTCONTROL);
250 return ret; 180 writel_relaxed(LOCK, wdt->base + WDTLOCK);
251}
252 181
253static int sp805_wdt_release(struct inode *inode, struct file *file) 182 /* Flush posted writes. */
254{ 183 readl_relaxed(wdt->base + WDTLOCK);
255 if (!test_bit(WDT_CAN_BE_CLOSED, &wdt->status)) { 184 spin_unlock(&wdt->lock);
256 clear_bit(WDT_BUSY, &wdt->status);
257 dev_warn(&wdt->adev->dev, "Device closed unexpectedly\n");
258 return 0;
259 }
260 185
261 wdt_disable();
262 clk_disable(wdt->clk); 186 clk_disable(wdt->clk);
263 clear_bit(WDT_BUSY, &wdt->status);
264 187
265 return 0; 188 return 0;
266} 189}
267 190
268static const struct file_operations sp805_wdt_fops = { 191static const struct watchdog_info wdt_info = {
269 .owner = THIS_MODULE, 192 .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
270 .llseek = no_llseek, 193 .identity = MODULE_NAME,
271 .write = sp805_wdt_write,
272 .unlocked_ioctl = sp805_wdt_ioctl,
273 .open = sp805_wdt_open,
274 .release = sp805_wdt_release,
275}; 194};
276 195
277static struct miscdevice sp805_wdt_miscdev = { 196static const struct watchdog_ops wdt_ops = {
278 .minor = WATCHDOG_MINOR, 197 .owner = THIS_MODULE,
279 .name = "watchdog", 198 .start = wdt_enable,
280 .fops = &sp805_wdt_fops, 199 .stop = wdt_disable,
200 .ping = wdt_ping,
201 .set_timeout = wdt_setload,
202 .get_timeleft = wdt_timeleft,
281}; 203};
282 204
283static int __devinit 205static int __devinit
284sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id) 206sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
285{ 207{
208 struct sp805_wdt *wdt;
286 int ret = 0; 209 int ret = 0;
287 210
288 if (!devm_request_mem_region(&adev->dev, adev->res.start, 211 if (!devm_request_mem_region(&adev->dev, adev->res.start,
@@ -315,19 +238,26 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
315 } 238 }
316 239
317 wdt->adev = adev; 240 wdt->adev = adev;
241 wdt->wdd.info = &wdt_info;
242 wdt->wdd.ops = &wdt_ops;
243
318 spin_lock_init(&wdt->lock); 244 spin_lock_init(&wdt->lock);
319 wdt_setload(DEFAULT_TIMEOUT); 245 watchdog_set_nowayout(&wdt->wdd, nowayout);
246 watchdog_set_drvdata(&wdt->wdd, wdt);
247 wdt_setload(&wdt->wdd, DEFAULT_TIMEOUT);
320 248
321 ret = misc_register(&sp805_wdt_miscdev); 249 ret = watchdog_register_device(&wdt->wdd);
322 if (ret < 0) { 250 if (ret) {
323 dev_warn(&adev->dev, "cannot register misc device\n"); 251 dev_err(&adev->dev, "watchdog_register_device() failed: %d\n",
324 goto err_misc_register; 252 ret);
253 goto err_register;
325 } 254 }
255 amba_set_drvdata(adev, wdt);
326 256
327 dev_info(&adev->dev, "registration successful\n"); 257 dev_info(&adev->dev, "registration successful\n");
328 return 0; 258 return 0;
329 259
330err_misc_register: 260err_register:
331 clk_put(wdt->clk); 261 clk_put(wdt->clk);
332err: 262err:
333 dev_err(&adev->dev, "Probe Failed!!!\n"); 263 dev_err(&adev->dev, "Probe Failed!!!\n");
@@ -336,7 +266,11 @@ err:
336 266
337static int __devexit sp805_wdt_remove(struct amba_device *adev) 267static int __devexit sp805_wdt_remove(struct amba_device *adev)
338{ 268{
339 misc_deregister(&sp805_wdt_miscdev); 269 struct sp805_wdt *wdt = amba_get_drvdata(adev);
270
271 watchdog_unregister_device(&wdt->wdd);
272 amba_set_drvdata(adev, NULL);
273 watchdog_set_drvdata(&wdt->wdd, NULL);
340 clk_put(wdt->clk); 274 clk_put(wdt->clk);
341 275
342 return 0; 276 return 0;
@@ -345,28 +279,22 @@ static int __devexit sp805_wdt_remove(struct amba_device *adev)
345#ifdef CONFIG_PM 279#ifdef CONFIG_PM
346static int sp805_wdt_suspend(struct device *dev) 280static int sp805_wdt_suspend(struct device *dev)
347{ 281{
348 if (test_bit(WDT_BUSY, &wdt->status)) { 282 struct sp805_wdt *wdt = dev_get_drvdata(dev);
349 wdt_disable(); 283
350 clk_disable(wdt->clk); 284 if (watchdog_active(&wdt->wdd))
351 } 285 return wdt_disable(&wdt->wdd);
352 286
353 return 0; 287 return 0;
354} 288}
355 289
356static int sp805_wdt_resume(struct device *dev) 290static int sp805_wdt_resume(struct device *dev)
357{ 291{
358 int ret = 0; 292 struct sp805_wdt *wdt = dev_get_drvdata(dev);
359 293
360 if (test_bit(WDT_BUSY, &wdt->status)) { 294 if (watchdog_active(&wdt->wdd))
361 ret = clk_enable(wdt->clk); 295 return wdt_enable(&wdt->wdd);
362 if (ret) {
363 dev_err(dev, "clock enable fail");
364 return ret;
365 }
366 wdt_enable();
367 }
368 296
369 return ret; 297 return 0;
370} 298}
371#endif /* CONFIG_PM */ 299#endif /* CONFIG_PM */
372 300
@@ -395,11 +323,6 @@ static struct amba_driver sp805_wdt_driver = {
395 323
396module_amba_driver(sp805_wdt_driver); 324module_amba_driver(sp805_wdt_driver);
397 325
398module_param(nowayout, bool, 0);
399MODULE_PARM_DESC(nowayout,
400 "Set to 1 to keep watchdog running after device release");
401
402MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>"); 326MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
403MODULE_DESCRIPTION("ARM SP805 Watchdog Driver"); 327MODULE_DESCRIPTION("ARM SP805 Watchdog Driver");
404MODULE_LICENSE("GPL"); 328MODULE_LICENSE("GPL");
405MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);