ARM: LPC313X: Fix the coding style according to Linux specification
[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         spinlock_t lock;
71         void __iomem *base;
72         unsigned long status;
73         unsigned long boot_status;
74         struct device *dev;
75 } lpc313x_wdt;
76
77 static void lpc313x_wdt_stop(struct lpc313x_wdt *wdt)
78 {
79         void __iomem *base = wdt->base;
80
81         /* Disable watchdog clock */
82         cgu_clk_en_dis(CGU_SB_WDOG_PCLK_ID, 0);
83
84         /* Disable and reset counter */
85         writel(TCR_RST, base + LPC313x_WDT_TCR);
86
87         /* Clear interrupts */
88         writel(INTR_M0 | INTR_M1, base + LPC313x_WDT_TCR);
89         writel(0, base + LPC313x_WDT_MCR);
90         writel(0, base + LPC313x_WDT_PC);
91         writel(0, base + LPC313x_WDT_PR);
92
93         /* Bring counter out of reset */
94         writel(0, base + LPC313x_WDT_TCR);
95 }
96
97 static void lpc313x_wdt_start(struct lpc313x_wdt *wdt)
98 {
99         uint32_t freq;
100         void __iomem *base = wdt->base;
101
102         /* Enable WDOG_PCLK and get its frequency */
103         cgu_clk_en_dis(CGU_SB_WDOG_PCLK_ID, 1);
104         freq = cgu_get_clk_freq(CGU_SB_WDOG_PCLK_ID);
105         writel(freq - 1, base + LPC313x_WDT_PR);
106         writel(heartbeat, base + LPC313x_WDT_MR0);
107         writel(INTEN_MR0 | STOP_MR0, base + LPC313x_WDT_MCR);
108
109         /* Start WDT */
110         writel(TCR_EN, base + LPC313x_WDT_TCR);
111 }
112
113 static void lpc313x_wdt_keepalive(struct lpc313x_wdt *wdt)
114 {
115         void __iomem *base = wdt->base;
116         writel(0, base + LPC313x_WDT_PC);
117         writel(0, base + LPC313x_WDT_TC);
118 }
119
120 /**
121  *      wdt_open:
122  *      @inode: inode of device
123  *      @file: file handle to device
124  *
125  *      The watchdog device has been opened. The watchdog device is single
126  *      open and on opening we load the counters. Counter zero is a 100Hz
127  *      cascade, into counter 1 which downcounts to reboot. When the counter
128  *      triggers counter 2 downcounts the length of the reset pulse which
129  *      set set to be as long as possible.
130  */
131
132 static int lpc313x_wdt_open(struct inode *inode, struct file *file)
133 {
134         struct lpc313x_wdt *wdt = &lpc313x_wdt;
135         if (test_and_set_bit(WDT_IN_USE, &wdt->status))
136                 return -EBUSY;
137         clear_bit(WDT_OK_TO_CLOSE, &wdt->status);
138
139         /*
140          *      Activate
141          */
142         lpc313x_wdt_start(wdt);
143         return nonseekable_open(inode, file);
144 }
145
146 static ssize_t lpc313x_wdt_write(struct file *file, const char *data,
147                                  size_t len, loff_t * ppos)
148 {
149         struct lpc313x_wdt *wdt = &lpc313x_wdt;
150         if (len) {
151                 if (!nowayout) {
152                         size_t i;
153
154                         clear_bit(WDT_OK_TO_CLOSE, &wdt->status);
155
156                         for (i = 0; i != len; i++) {
157                                 char c;
158
159                                 if (get_user(c, data + i))
160                                         return -EFAULT;
161                                 if (c == 'V')
162                                         set_bit(WDT_OK_TO_CLOSE, &wdt->status);
163                         }
164                 }
165                 lpc313x_wdt_keepalive(wdt);
166         }
167
168         return len;
169 }
170
171 static const struct watchdog_info ident = {
172         .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
173             WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
174         .identity = "LPC313x Watchdog",
175 };
176
177 static long lpc313x_wdt_ioctl(struct file *file, unsigned int cmd,
178                               unsigned long arg)
179 {
180         int ret = -ENOTTY;
181         int time;
182         struct lpc313x_wdt *wdt = &lpc313x_wdt;
183
184         switch (cmd) {
185         case WDIOC_GETSUPPORT:
186                 ret = copy_to_user((struct watchdog_info *)arg, &ident,
187                                    sizeof(ident)) ? -EFAULT : 0;
188                 break;
189
190         case WDIOC_GETSTATUS:
191                 ret = put_user(0, (int *)arg);
192                 break;
193
194         case WDIOC_GETBOOTSTATUS:
195                 ret = put_user(wdt->boot_status, (int *)arg);
196                 break;
197
198         case WDIOC_KEEPALIVE:
199                 lpc313x_wdt_keepalive(wdt);
200                 dev_vdbg(wdt->dev, "Hearbeat received.\n");
201                 ret = 0;
202                 break;
203
204         case WDIOC_SETTIMEOUT:
205                 ret = get_user(time, (int *)arg);
206                 if (ret)
207                         break;
208
209                 if (time <= 0 || time > MAX_HEARTBEAT) {
210                         dev_err(wdt->dev, "Timeout value should be an "
211                                 "integer between 1 to %d\n", MAX_HEARTBEAT);
212                         ret = -EINVAL;
213                         break;
214                 }
215
216                 heartbeat = time;
217                 lpc313x_wdt_keepalive(wdt);
218                 dev_vdbg(wdt->dev, "Timeout set to: %d\n", time);
219                 /* Fall through */
220
221         case WDIOC_GETTIMEOUT:
222                 ret = put_user(heartbeat, (int *)arg);
223                 break;
224         }
225         return ret;
226 }
227
228 static int lpc313x_wdt_release(struct inode *inode, struct file *file)
229 {
230         struct lpc313x_wdt *wdt = &lpc313x_wdt;
231         if (!test_bit(WDT_OK_TO_CLOSE, &wdt->status))
232                 dev_warn(wdt->dev, "Watchdog timer closed unexpectedly\n");
233
234         lpc313x_wdt_stop(wdt);
235         clear_bit(WDT_IN_USE, &wdt->status);
236         clear_bit(WDT_OK_TO_CLOSE, &wdt->status);
237
238         return 0;
239 }
240
241 static const struct file_operations lpc313x_wdt_fops = {
242         .owner = THIS_MODULE,
243         .llseek = no_llseek,
244         .unlocked_ioctl = lpc313x_wdt_ioctl,
245         .open = lpc313x_wdt_open,
246         .write = lpc313x_wdt_write,
247         .release = lpc313x_wdt_release,
248 };
249
250 static struct miscdevice lpc313x_wdt_misc = {
251         .minor = WATCHDOG_MINOR,
252         .name = "watchdog",
253         .fops = &lpc313x_wdt_fops,
254 };
255
256 static int lpc313x_wdt_probe(struct platform_device *pdev)
257 {
258         int ret;
259         struct resource *res;
260         struct lpc313x_wdt *wdt = &lpc313x_wdt;
261         uint32_t size;
262
263         spin_lock_init(&wdt->lock);
264         wdt->dev = &pdev->dev;
265         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
266         if (res == NULL) {
267                 dev_err(&pdev->dev, "Unable to get resources.\n");
268                 return -ENXIO;
269         }
270
271         size = res->end - res->start + 1;
272         if (devm_request_mem_region(&pdev->dev,
273                                     res->start, size, pdev->name) == NULL) {
274                 dev_err(&pdev->dev, "Requested memory region unavailable\n");
275                 return -EBUSY;
276         }
277
278         wdt->base = devm_ioremap(&pdev->dev, res->start, size);
279         if (wdt->base == NULL) {
280                 dev_err(&pdev->dev, "Unable to remap memory region\n");
281                 return -ENOMEM;
282         }
283
284         ret = misc_register(&lpc313x_wdt_misc);
285         if (ret < 0) {
286                 dev_err(&pdev->dev, " lpc313x_wdt : failed to register\n");
287                 return ret;
288         }
289         platform_set_drvdata(pdev, wdt);
290
291         wdt->boot_status =
292             (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");