e8fcfdf5cc499a38f67f83120969e08716978fb6
[linux-2.6.33-lpc313x.git] / drivers / watchdog / wdt_lpc313x.c
1 /*
2  * LPC313x Watchdog timer driver
3  *
4  * drivers/watchdog/wdt_lpc313x.c
5  *
6  * Copyright (C) 2009 NXP Semiconductors
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include <linux/kernel.h>
24 #include <linux/module.h>
25 #include <linux/init.h>
26 #include <linux/miscdevice.h>
27 #include <linux/fs.h>
28 #include <linux/watchdog.h>
29 #include <linux/platform_device.h>
30 #include <linux/io.h>
31 #include <linux/uaccess.h>
32 #include <linux/interrupt.h>
33
34 #include <mach/hardware.h>
35 #include <mach/cgu.h>
36
37 #define MAX_HEARTBEAT 120
38 #define DEFAULT_HEARTBEAT 25
39 #define WDT_IN_USE        0
40 #define WDT_OK_TO_CLOSE   1
41
42 /* Offset of WDT registers */
43 #define LPC313x_WDT_IR       0x00
44 #define LPC313x_WDT_TCR      0x04
45 #define LPC313x_WDT_TC       0x08
46 #define LPC313x_WDT_PR       0x0C
47 #define LPC313x_WDT_PC       0x10
48 #define LPC313x_WDT_MCR      0x14
49 #define LPC313x_WDT_MR0      0x18
50 #define LPC313x_WDT_MR1      0x1C
51 #define LPC313x_WDT_EMR      0x3C
52
53 #define INTR_M0      0x01
54 #define INTR_M1      0x02
55
56 #define TCR_EN       0x01
57 #define TCR_RST      0x02
58
59 #define INTEN_MR0    (1 << 0)
60 #define RESET_MR0    (1 << 1)
61 #define STOP_MR0     (1 << 2)
62 #define INTEN_MR1    (1 << 3)
63 #define RESET_MR1    (1 << 4)
64 #define STOP_MR1     (1 << 5)
65
66 static int nowayout = WATCHDOG_NOWAYOUT;
67 static int heartbeat = DEFAULT_HEARTBEAT;
68
69 static struct lpc313x_wdt
70 {
71         spinlock_t lock;
72         void __iomem * base;
73         unsigned long status;
74         unsigned long boot_status;
75         struct device * dev;
76 }lpc313x_wdt;
77
78 static void lpc313x_wdt_stop(struct lpc313x_wdt * wdt)
79 {
80         void __iomem * base = wdt->base;
81
82         /* Disable watchdog clock */
83         cgu_clk_en_dis(CGU_SB_WDOG_PCLK_ID, 0);
84
85         /* Disable and reset counter */
86         writel(TCR_RST, base + LPC313x_WDT_TCR);
87
88         /* Clear interrupts */
89         writel(INTR_M0 | INTR_M1, base + LPC313x_WDT_TCR);
90         writel(0, base + LPC313x_WDT_MCR);
91         writel(0, base + LPC313x_WDT_PC);
92         writel(0, base + LPC313x_WDT_PR);
93
94         /* Bring counter out of reset */
95         writel(0, base + LPC313x_WDT_TCR);
96 }
97
98 static void lpc313x_wdt_start(struct lpc313x_wdt * wdt)
99 {
100         uint32_t freq;
101         void __iomem * base = wdt->base;
102
103         /* Enable WDOG_PCLK and get its frequency */
104         cgu_clk_en_dis(CGU_SB_WDOG_PCLK_ID, 1);
105         freq = cgu_get_clk_freq(CGU_SB_WDOG_PCLK_ID);
106         writel(freq-1, base + LPC313x_WDT_PR);
107         writel(heartbeat, base + LPC313x_WDT_MR0);
108         writel(INTEN_MR0 | STOP_MR0, base + LPC313x_WDT_MCR);
109
110         /* Start WDT */
111         writel(TCR_EN, base + LPC313x_WDT_TCR);
112 }
113
114 static void lpc313x_wdt_keepalive(struct lpc313x_wdt * wdt)
115 {
116         void __iomem * base = wdt->base;
117         writel(0, base + LPC313x_WDT_PC);
118         writel(0, base + LPC313x_WDT_TC);
119 }
120
121 /**
122  *      wdt_open:
123  *      @inode: inode of device
124  *      @file: file handle to device
125  *
126  *      The watchdog device has been opened. The watchdog device is single
127  *      open and on opening we load the counters. Counter zero is a 100Hz
128  *      cascade, into counter 1 which downcounts to reboot. When the counter
129  *      triggers counter 2 downcounts the length of the reset pulse which
130  *      set set to be as long as possible.
131  */
132
133 static int lpc313x_wdt_open(struct inode *inode, struct file *file)
134 {
135         struct lpc313x_wdt *wdt = &lpc313x_wdt;
136         if (test_and_set_bit(WDT_IN_USE, &wdt->status))
137                 return -EBUSY;
138         clear_bit(WDT_OK_TO_CLOSE, &wdt->status);
139
140         /*
141          *      Activate
142          */
143         lpc313x_wdt_start(wdt);
144         return nonseekable_open(inode, file);
145 }
146
147 static ssize_t lpc313x_wdt_write(struct file *file, const char *data,
148                                         size_t len, loff_t *ppos)
149 {
150         struct lpc313x_wdt *wdt = &lpc313x_wdt;
151         if (len) {
152                 if (!nowayout) {
153                         size_t i;
154
155                         clear_bit(WDT_OK_TO_CLOSE, &wdt->status);
156
157                         for (i = 0; i != len; i++) {
158                                 char c;
159
160                                 if (get_user(c, data + i))
161                                         return -EFAULT;
162                                 if (c == 'V')
163                                         set_bit(WDT_OK_TO_CLOSE, &wdt->status);
164                         }
165                 }
166                 lpc313x_wdt_keepalive(wdt);
167         }
168
169         return len;
170 }
171
172 static const struct watchdog_info ident = {
173         .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
174             WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
175         .identity = "LPC313x Watchdog",
176 };
177
178 static long lpc313x_wdt_ioctl(struct file *file, unsigned int cmd,
179                                 unsigned long arg)
180 {
181         int ret = -ENOTTY;
182         int time;
183         struct lpc313x_wdt * wdt = &lpc313x_wdt;
184
185         switch (cmd) {
186         case WDIOC_GETSUPPORT:
187                 ret = copy_to_user((struct watchdog_info *)arg, &ident,
188                                    sizeof(ident)) ? -EFAULT : 0;
189                 break;
190
191         case WDIOC_GETSTATUS:
192                 ret = put_user(0, (int *)arg);
193                 break;
194
195         case WDIOC_GETBOOTSTATUS:
196                 ret = put_user(wdt->boot_status, (int *)arg);
197                 break;
198
199         case WDIOC_KEEPALIVE:
200                 lpc313x_wdt_keepalive(wdt);
201                 dev_vdbg(wdt->dev, "Hearbeat received.\n");
202                 ret = 0;
203                 break;
204
205         case WDIOC_SETTIMEOUT:
206                 ret = get_user(time, (int *)arg);
207                 if (ret)
208                         break;
209
210                 if (time <= 0 || time > MAX_HEARTBEAT) {
211                         dev_err(wdt->dev, "Timeout value should be an "
212                                         "integer between 1 to %d\n", MAX_HEARTBEAT);
213                         ret = -EINVAL;
214                         break;
215                 }
216
217                 heartbeat = time;
218                 lpc313x_wdt_keepalive(wdt);
219                 dev_vdbg(wdt->dev, "Timeout set to: %d\n", time);
220                 /* Fall through */
221
222         case WDIOC_GETTIMEOUT:
223                 ret = put_user(heartbeat, (int *)arg);
224                 break;
225         }
226         return ret;
227 }
228
229 static int lpc313x_wdt_release(struct inode *inode, struct file *file)
230 {
231         struct lpc313x_wdt * wdt = &lpc313x_wdt;
232         if (!test_bit(WDT_OK_TO_CLOSE, &wdt->status))
233                 dev_warn(wdt->dev, "Watchdog timer closed unexpectedly\n");
234
235         lpc313x_wdt_stop(wdt);
236         clear_bit(WDT_IN_USE, &wdt->status);
237         clear_bit(WDT_OK_TO_CLOSE, &wdt->status);
238
239         return 0;
240 }
241
242 static const struct file_operations lpc313x_wdt_fops = {
243         .owner          = THIS_MODULE,
244         .llseek         = no_llseek,
245         .unlocked_ioctl = lpc313x_wdt_ioctl,
246         .open           = lpc313x_wdt_open,
247         .write          = lpc313x_wdt_write,
248         .release        = lpc313x_wdt_release,
249 };
250
251 static struct miscdevice lpc313x_wdt_misc = {
252         .minor  = WATCHDOG_MINOR,
253         .name   = "watchdog",
254         .fops   = &lpc313x_wdt_fops,
255 };
256
257 static int lpc313x_wdt_probe(struct platform_device *pdev)
258 {
259         int ret;
260         struct resource * res;
261         struct lpc313x_wdt * wdt = &lpc313x_wdt;
262         uint32_t size;
263
264         spin_lock_init(&wdt->lock);
265         wdt->dev = &pdev->dev;
266         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
267         if (res == NULL) {
268                 dev_err(&pdev->dev, "Unable to get resources.\n");
269                 return -ENXIO;
270         }
271
272         size = res->end - res->start + 1;
273         if(devm_request_mem_region(&pdev->dev, 
274                         res->start, size, pdev->name) == NULL) {
275                 dev_err (&pdev->dev, "Requested memory region unavailable\n");
276                 return -EBUSY;
277         }
278
279         wdt->base = devm_ioremap(&pdev->dev, res->start, size);
280         if (wdt->base == NULL) {
281                 dev_err (&pdev->dev, "Unable to remap memory region\n");
282                 return -ENOMEM;
283         }
284
285         ret = misc_register(&lpc313x_wdt_misc);
286         if (ret < 0) {
287                 dev_err(&pdev->dev, " lpc313x_wdt : failed to register\n");
288                 return ret;
289         }
290         platform_set_drvdata(pdev, wdt);
291
292         wdt->boot_status = (readl((void __iomem *) io_p2v(CGU_SB_PHYS)) & 0x1) ?
293                 WDIOF_CARDRESET : 0;
294         lpc313x_wdt_stop(wdt);
295         dev_info(&pdev->dev, "Watchdog device driver initialized.\n");
296         return 0;
297 }
298
299 static int lpc313x_wdt_remove(struct platform_device *pdev)
300 {
301         struct lpc313x_wdt * wdt = &lpc313x_wdt;
302
303         /* Stop the hardware */
304         lpc313x_wdt_stop(wdt);
305
306         misc_deregister(&lpc313x_wdt_misc);
307         /* All other resources are automatically de-allocated */
308         return 0;
309 }
310
311 static struct platform_driver lpc313x_wdt_driver = {
312         .probe = lpc313x_wdt_probe,
313         .remove = __devexit_p(lpc313x_wdt_remove),
314         .driver = {
315                 .owner = THIS_MODULE,
316                 .name = "lpc313x-wdt",
317         },
318 };
319
320 static int __init lpc313x_wdt_init(void)
321 {
322         return platform_driver_register(&lpc313x_wdt_driver);
323 }
324
325 static void __exit lpc313x_wdt_exit(void)
326 {
327         platform_driver_unregister(&lpc313x_wdt_driver);
328 }
329
330 module_init(lpc313x_wdt_init);
331 module_exit(lpc313x_wdt_exit);
332
333 MODULE_AUTHOR("NXP Semiconductors");
334 MODULE_DESCRIPTION("Driver for the LPC313x watchdog");
335 MODULE_LICENSE("GPL");
336 module_param(heartbeat, int, 0);
337 MODULE_PARM_DESC(heartbeat,
338                  "Watchdog heartbeat period in seconds from 1 to "
339                  __MODULE_STRING(MAX_HEARTBEAT) ", default "
340                  __MODULE_STRING(DEFAULT_HEARTBEAT));
341
342 module_param(nowayout, int, 0);
343 MODULE_PARM_DESC(nowayout,
344                  "Set to 1 to keep watchdog running after device release");
345 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
346 MODULE_ALIAS("platform:lpc313x-wdt");