aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAxel Lin <axel.lin@gmail.com>2012-02-08 01:24:10 -0500
committerWim Van Sebroeck <wim@iguana.be>2012-03-27 14:06:59 -0400
commita0f3683365513c052d21991fe75eccd95aba9d34 (patch)
treec41a5e01375919c8f9d3595350bc0fbaea2bf3a9
parent6b1e83869d13a6b5ce9ceb4b8f79a7538d467dee (diff)
watchdog: Convert max63xx_wdt driver to watchdog framework
This patch converts max63xx_wdt driver to watchdog framework. Also use devm_* APIs to save a few error handling code. Signed-off-by: Axel Lin <axel.lin@gmail.com> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
-rw-r--r--drivers/watchdog/Kconfig1
-rw-r--r--drivers/watchdog/max63xx_wdt.c190
2 files changed, 32 insertions, 159 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index c83a83fe0398..8f5c31763286 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -330,6 +330,7 @@ config TS72XX_WATCHDOG
330config MAX63XX_WATCHDOG 330config MAX63XX_WATCHDOG
331 tristate "Max63xx watchdog" 331 tristate "Max63xx watchdog"
332 depends on ARM && HAS_IOMEM 332 depends on ARM && HAS_IOMEM
333 select WATCHDOG_CORE
333 help 334 help
334 Support for memory mapped max63{69,70,71,72,73,74} watchdog timer. 335 Support for memory mapped max63{69,70,71,72,73,74} watchdog timer.
335 336
diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c
index c9e9ff2a9c9d..8f4a74e91619 100644
--- a/drivers/watchdog/max63xx_wdt.c
+++ b/drivers/watchdog/max63xx_wdt.c
@@ -18,22 +18,19 @@
18#include <linux/moduleparam.h> 18#include <linux/moduleparam.h>
19#include <linux/types.h> 19#include <linux/types.h>
20#include <linux/kernel.h> 20#include <linux/kernel.h>
21#include <linux/fs.h>
22#include <linux/miscdevice.h> 21#include <linux/miscdevice.h>
23#include <linux/watchdog.h> 22#include <linux/watchdog.h>
24#include <linux/init.h> 23#include <linux/init.h>
25#include <linux/bitops.h> 24#include <linux/bitops.h>
26#include <linux/platform_device.h> 25#include <linux/platform_device.h>
27#include <linux/spinlock.h> 26#include <linux/spinlock.h>
28#include <linux/uaccess.h>
29#include <linux/io.h> 27#include <linux/io.h>
30#include <linux/device.h>
31#include <linux/slab.h> 28#include <linux/slab.h>
32 29
33#define DEFAULT_HEARTBEAT 60 30#define DEFAULT_HEARTBEAT 60
34#define MAX_HEARTBEAT 60 31#define MAX_HEARTBEAT 60
35 32
36static int heartbeat = DEFAULT_HEARTBEAT; 33static unsigned int heartbeat = DEFAULT_HEARTBEAT;
37static bool nowayout = WATCHDOG_NOWAYOUT; 34static bool nowayout = WATCHDOG_NOWAYOUT;
38 35
39/* 36/*
@@ -45,15 +42,8 @@ static bool nowayout = WATCHDOG_NOWAYOUT;
45 42
46static DEFINE_SPINLOCK(io_lock); 43static DEFINE_SPINLOCK(io_lock);
47 44
48static unsigned long wdt_status;
49#define WDT_IN_USE 0
50#define WDT_RUNNING 1
51#define WDT_OK_TO_CLOSE 2
52
53static int nodelay; 45static int nodelay;
54static struct resource *wdt_mem;
55static void __iomem *wdt_base; 46static void __iomem *wdt_base;
56static struct platform_device *max63xx_pdev;
57 47
58/* 48/*
59 * The timeout values used are actually the absolute minimum the chip 49 * The timeout values used are actually the absolute minimum the chip
@@ -117,7 +107,7 @@ max63xx_select_timeout(struct max63xx_timeout *table, int value)
117 return NULL; 107 return NULL;
118} 108}
119 109
120static void max63xx_wdt_ping(void) 110static int max63xx_wdt_ping(struct watchdog_device *wdd)
121{ 111{
122 u8 val; 112 u8 val;
123 113
@@ -129,15 +119,14 @@ static void max63xx_wdt_ping(void)
129 __raw_writeb(val & ~MAX6369_WDI, wdt_base); 119 __raw_writeb(val & ~MAX6369_WDI, wdt_base);
130 120
131 spin_unlock(&io_lock); 121 spin_unlock(&io_lock);
122 return 0;
132} 123}
133 124
134static void max63xx_wdt_enable(struct max63xx_timeout *entry) 125static int max63xx_wdt_start(struct watchdog_device *wdd)
135{ 126{
127 struct max63xx_timeout *entry = watchdog_get_drvdata(wdd);
136 u8 val; 128 u8 val;
137 129
138 if (test_and_set_bit(WDT_RUNNING, &wdt_status))
139 return;
140
141 spin_lock(&io_lock); 130 spin_lock(&io_lock);
142 131
143 val = __raw_readb(wdt_base); 132 val = __raw_readb(wdt_base);
@@ -149,10 +138,11 @@ static void max63xx_wdt_enable(struct max63xx_timeout *entry)
149 138
150 /* check for a edge triggered startup */ 139 /* check for a edge triggered startup */
151 if (entry->tdelay == 0) 140 if (entry->tdelay == 0)
152 max63xx_wdt_ping(); 141 max63xx_wdt_ping(wdd);
142 return 0;
153} 143}
154 144
155static void max63xx_wdt_disable(void) 145static int max63xx_wdt_stop(struct watchdog_device *wdd)
156{ 146{
157 u8 val; 147 u8 val;
158 148
@@ -164,113 +154,29 @@ static void max63xx_wdt_disable(void)
164 __raw_writeb(val, wdt_base); 154 __raw_writeb(val, wdt_base);
165 155
166 spin_unlock(&io_lock); 156 spin_unlock(&io_lock);
167 157 return 0;
168 clear_bit(WDT_RUNNING, &wdt_status);
169}
170
171static int max63xx_wdt_open(struct inode *inode, struct file *file)
172{
173 if (test_and_set_bit(WDT_IN_USE, &wdt_status))
174 return -EBUSY;
175
176 max63xx_wdt_enable(current_timeout);
177 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
178
179 return nonseekable_open(inode, file);
180}
181
182static ssize_t max63xx_wdt_write(struct file *file, const char *data,
183 size_t len, loff_t *ppos)
184{
185 if (len) {
186 if (!nowayout) {
187 size_t i;
188
189 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
190 for (i = 0; i != len; i++) {
191 char c;
192
193 if (get_user(c, data + i))
194 return -EFAULT;
195
196 if (c == 'V')
197 set_bit(WDT_OK_TO_CLOSE, &wdt_status);
198 }
199 }
200
201 max63xx_wdt_ping();
202 }
203
204 return len;
205} 158}
206 159
207static const struct watchdog_info ident = { 160static const struct watchdog_info max63xx_wdt_info = {
208 .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, 161 .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
209 .identity = "max63xx Watchdog", 162 .identity = "max63xx Watchdog",
210}; 163};
211 164
212static long max63xx_wdt_ioctl(struct file *file, unsigned int cmd, 165static const struct watchdog_ops max63xx_wdt_ops = {
213 unsigned long arg) 166 .owner = THIS_MODULE,
214{ 167 .start = max63xx_wdt_start,
215 int ret = -ENOTTY; 168 .stop = max63xx_wdt_stop,
216 169 .ping = max63xx_wdt_ping,
217 switch (cmd) {
218 case WDIOC_GETSUPPORT:
219 ret = copy_to_user((struct watchdog_info *)arg, &ident,
220 sizeof(ident)) ? -EFAULT : 0;
221 break;
222
223 case WDIOC_GETSTATUS:
224 case WDIOC_GETBOOTSTATUS:
225 ret = put_user(0, (int *)arg);
226 break;
227
228 case WDIOC_KEEPALIVE:
229 max63xx_wdt_ping();
230 ret = 0;
231 break;
232
233 case WDIOC_GETTIMEOUT:
234 ret = put_user(heartbeat, (int *)arg);
235 break;
236 }
237 return ret;
238}
239
240static int max63xx_wdt_release(struct inode *inode, struct file *file)
241{
242 if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
243 max63xx_wdt_disable();
244 else
245 dev_crit(&max63xx_pdev->dev,
246 "device closed unexpectedly - timer will not stop\n");
247
248 clear_bit(WDT_IN_USE, &wdt_status);
249 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
250
251 return 0;
252}
253
254static const struct file_operations max63xx_wdt_fops = {
255 .owner = THIS_MODULE,
256 .llseek = no_llseek,
257 .write = max63xx_wdt_write,
258 .unlocked_ioctl = max63xx_wdt_ioctl,
259 .open = max63xx_wdt_open,
260 .release = max63xx_wdt_release,
261}; 170};
262 171
263static struct miscdevice max63xx_wdt_miscdev = { 172static struct watchdog_device max63xx_wdt_dev = {
264 .minor = WATCHDOG_MINOR, 173 .info = &max63xx_wdt_info,
265 .name = "watchdog", 174 .ops = &max63xx_wdt_ops,
266 .fops = &max63xx_wdt_fops,
267}; 175};
268 176
269static int __devinit max63xx_wdt_probe(struct platform_device *pdev) 177static int __devinit max63xx_wdt_probe(struct platform_device *pdev)
270{ 178{
271 int ret = 0; 179 struct resource *wdt_mem;
272 int size;
273 struct device *dev = &pdev->dev;
274 struct max63xx_timeout *table; 180 struct max63xx_timeout *table;
275 181
276 table = (struct max63xx_timeout *)pdev->id_entry->driver_data; 182 table = (struct max63xx_timeout *)pdev->id_entry->driver_data;
@@ -278,68 +184,34 @@ static int __devinit max63xx_wdt_probe(struct platform_device *pdev)
278 if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT) 184 if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
279 heartbeat = DEFAULT_HEARTBEAT; 185 heartbeat = DEFAULT_HEARTBEAT;
280 186
281 dev_info(dev, "requesting %ds heartbeat\n", heartbeat); 187 dev_info(&pdev->dev, "requesting %ds heartbeat\n", heartbeat);
282 current_timeout = max63xx_select_timeout(table, heartbeat); 188 current_timeout = max63xx_select_timeout(table, heartbeat);
283 189
284 if (!current_timeout) { 190 if (!current_timeout) {
285 dev_err(dev, "unable to satisfy heartbeat request\n"); 191 dev_err(&pdev->dev, "unable to satisfy heartbeat request\n");
286 return -EINVAL; 192 return -EINVAL;
287 } 193 }
288 194
289 dev_info(dev, "using %ds heartbeat with %ds initial delay\n", 195 dev_info(&pdev->dev, "using %ds heartbeat with %ds initial delay\n",
290 current_timeout->twd, current_timeout->tdelay); 196 current_timeout->twd, current_timeout->tdelay);
291 197
292 heartbeat = current_timeout->twd; 198 heartbeat = current_timeout->twd;
293 199
294 max63xx_pdev = pdev;
295
296 wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 200 wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
297 if (wdt_mem == NULL) { 201 wdt_base = devm_request_and_ioremap(&pdev->dev, wdt_mem);
298 dev_err(dev, "failed to get memory region resource\n"); 202 if (!wdt_base)
299 return -ENOENT; 203 return -ENOMEM;
300 }
301 204
302 size = resource_size(wdt_mem); 205 max63xx_wdt_dev.timeout = heartbeat;
303 if (!request_mem_region(wdt_mem->start, size, pdev->name)) { 206 watchdog_set_nowayout(&max63xx_wdt_dev, nowayout);
304 dev_err(dev, "failed to get memory region\n"); 207 watchdog_set_drvdata(&max63xx_wdt_dev, current_timeout);
305 return -ENOENT;
306 }
307
308 wdt_base = ioremap(wdt_mem->start, size);
309 if (!wdt_base) {
310 dev_err(dev, "failed to map memory region\n");
311 ret = -ENOMEM;
312 goto out_request;
313 }
314 208
315 ret = misc_register(&max63xx_wdt_miscdev); 209 return watchdog_register_device(&max63xx_wdt_dev);
316 if (ret < 0) {
317 dev_err(dev, "cannot register misc device\n");
318 goto out_unmap;
319 }
320
321 return 0;
322
323out_unmap:
324 iounmap(wdt_base);
325out_request:
326 release_mem_region(wdt_mem->start, size);
327 wdt_mem = NULL;
328
329 return ret;
330} 210}
331 211
332static int __devexit max63xx_wdt_remove(struct platform_device *pdev) 212static int __devexit max63xx_wdt_remove(struct platform_device *pdev)
333{ 213{
334 misc_deregister(&max63xx_wdt_miscdev); 214 watchdog_unregister_device(&max63xx_wdt_dev);
335 if (wdt_mem) {
336 release_mem_region(wdt_mem->start, resource_size(wdt_mem));
337 wdt_mem = NULL;
338 }
339
340 if (wdt_base)
341 iounmap(wdt_base);
342
343 return 0; 215 return 0;
344} 216}
345 217