[coldfire]: 2.6.31 support (WiP)
[15.05/openwrt.git] / target / linux / coldfire / patches / 075-mcfv4e_watchdog.patch
1 From 3c6c80a04d6ca99c4f9fbb5e4f279bd644b2df48 Mon Sep 17 00:00:00 2001
2 From: Kurt Mahan <kmahan@freescale.com>
3 Date: Tue, 8 Jul 2008 14:10:46 -0600
4 Subject: [PATCH] Add Coldfire Watchdog support.
5
6 LTIBName: mcfv4e-watchdog
7 Signed-off-by: Kurt Mahan <kmahan@freescale.com>
8 ---
9  drivers/watchdog/Kconfig   |    9 ++
10  drivers/watchdog/Makefile  |    1 +
11  drivers/watchdog/mcf_wdt.c |  220 ++++++++++++++++++++++++++++++++++++++++++++
12  3 files changed, 230 insertions(+), 0 deletions(-)
13  create mode 100644 drivers/watchdog/mcf_wdt.c
14
15 --- a/drivers/watchdog/Kconfig
16 +++ b/drivers/watchdog/Kconfig
17 @@ -672,6 +672,15 @@ config TXX9_WDT
18  
19  # PARISC Architecture
20  
21 +# ColdFire Architecture
22 +
23 +config COLDFIRE_WATCHDOG
24 +       tristate "ColdFire watchdog support"
25 +       depends on WATCHDOG
26 +       help
27 +         To compile this driver as a module, choose M here: the
28 +         module will be called softdog.
29 +
30  # POWERPC Architecture
31  
32  config MPC5200_WDT
33 --- a/drivers/watchdog/Makefile
34 +++ b/drivers/watchdog/Makefile
35 @@ -86,6 +86,7 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc
36  # M32R Architecture
37  
38  # M68K Architecture
39 +obj-$(CONFIG_COLDFIRE_WATCHDOG) += mcf_wdt.o
40  
41  # M68KNOMMU Architecture
42  
43 --- /dev/null
44 +++ b/drivers/watchdog/mcf_wdt.c
45 @@ -0,0 +1,220 @@
46 +/*
47 + * drivers/watchdog/mcf_wdt.c
48 + *
49 + * Watchdog driver for ColdFire processors
50 + *
51 + * Adapted from the IXP4xx watchdog driver.
52 + * The original version carries these notices:
53 + *
54 + * Author: Deepak Saxena <dsaxena@plexity.net>
55 + *
56 + * Copyright 2004 (c) MontaVista, Software, Inc.
57 + * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
58 + *
59 + * This file is licensed under  the terms of the GNU General Public
60 + * License version 2. This program is licensed "as is" without any
61 + * warranty of any kind, whether express or implied.
62 + */
63 +
64 +#include <linux/module.h>
65 +#include <linux/moduleparam.h>
66 +#include <linux/types.h>
67 +#include <linux/kernel.h>
68 +#include <linux/fs.h>
69 +#include <linux/miscdevice.h>
70 +#include <linux/watchdog.h>
71 +#include <linux/init.h>
72 +#include <linux/bitops.h>
73 +
74 +#include <asm-m68k/uaccess.h>
75 +#include <asm-m68k/coldfire.h>
76 +#include <asm-m68k/m5485gpt.h>
77 +
78 +static int nowayout;
79 +static unsigned int heartbeat = 30;    /* (secs) Default is 0.5 minute */
80 +static unsigned long wdt_status;
81 +
82 +#define        WDT_IN_USE              0
83 +#define        WDT_OK_TO_CLOSE         1
84 +
85 +static unsigned long wdt_tick_rate;
86 +
87 +static void
88 +wdt_enable(void)
89 +{
90 +       MCF_GPT_GMS0 = 0;
91 +       MCF_GPT_GCIR0 =  MCF_GPT_GCIR_PRE(heartbeat*wdt_tick_rate) |
92 +                               MCF_GPT_GCIR_CNT(0xffff);
93 +       MCF_GPT_GMS0 = MCF_GPT_GMS_OCPW(0xA5) | MCF_GPT_GMS_WDEN |
94 +                               MCF_GPT_GMS_CE | MCF_GPT_GMS_TMS_GPIO;
95 +}
96 +
97 +static void
98 +wdt_disable(void)
99 +{
100 +       MCF_GPT_GMS0 = 0;
101 +}
102 +
103 +static void
104 +wdt_keepalive(void)
105 +{
106 +       MCF_GPT_GMS0 = MCF_GPT_GMS_OCPW(0xA5) | MCF_GPT_GMS0;
107 +}
108 +
109 +static int
110 +mcf_wdt_open(struct inode *inode, struct file *file)
111 +{
112 +       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
113 +               return -EBUSY;
114 +
115 +       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
116 +
117 +       wdt_enable();
118 +
119 +       return nonseekable_open(inode, file);
120 +}
121 +
122 +static ssize_t
123 +mcf_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
124 +{
125 +       if (len) {
126 +               if (!nowayout) {
127 +                       size_t i;
128 +
129 +                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
130 +
131 +                       for (i = 0; i != len; i++) {
132 +                               char c;
133 +
134 +                               if (get_user(c, data + i))
135 +                                       return -EFAULT;
136 +                               if (c == 'V')
137 +                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
138 +                       }
139 +               }
140 +               wdt_keepalive();
141 +       }
142 +
143 +       return len;
144 +}
145 +
146 +
147 +static struct watchdog_info ident = {
148 +       .options        = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
149 +                               WDIOF_KEEPALIVEPING,
150 +       .identity       = "Coldfire Watchdog",
151 +};
152 +
153 +static int
154 +mcf_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
155 +                       unsigned long arg)
156 +{
157 +       int ret = -ENOIOCTLCMD;
158 +       int time;
159 +
160 +       switch (cmd) {
161 +       case WDIOC_GETSUPPORT:
162 +               ret = copy_to_user((struct watchdog_info *)arg, &ident,
163 +                                  sizeof(ident)) ? -EFAULT : 0;
164 +               break;
165 +
166 +       case WDIOC_GETSTATUS:
167 +               ret = put_user(0, (int *)arg);
168 +               break;
169 +
170 +       case WDIOC_GETBOOTSTATUS:
171 +               ret = put_user(0, (int *)arg);
172 +               break;
173 +
174 +       case WDIOC_SETTIMEOUT:
175 +               ret = get_user(time, (int *)arg);
176 +               if (ret)
177 +                       break;
178 +
179 +               if (time <= 0 || time > 30) {
180 +                       ret = -EINVAL;
181 +                       break;
182 +               }
183 +
184 +               heartbeat = time;
185 +               wdt_enable();
186 +               /* Fall through */
187 +
188 +       case WDIOC_GETTIMEOUT:
189 +               ret = put_user(heartbeat, (int *)arg);
190 +               break;
191 +
192 +       case WDIOC_KEEPALIVE:
193 +               wdt_keepalive();
194 +               ret = 0;
195 +               break;
196 +       }
197 +
198 +       return ret;
199 +}
200 +
201 +static int
202 +mcf_wdt_release(struct inode *inode, struct file *file)
203 +{
204 +       if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
205 +               wdt_disable();
206 +       } else {
207 +               printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - "
208 +                                       "timer will not stop\n");
209 +       }
210 +
211 +       clear_bit(WDT_IN_USE, &wdt_status);
212 +       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
213 +
214 +       return 0;
215 +}
216 +
217 +
218 +static struct file_operations mcf_wdt_fops = {
219 +       .owner          = THIS_MODULE,
220 +       .llseek         = no_llseek,
221 +       .write          = mcf_wdt_write,
222 +       .ioctl          = mcf_wdt_ioctl,
223 +       .open           = mcf_wdt_open,
224 +       .release        = mcf_wdt_release,
225 +};
226 +
227 +static struct miscdevice mcf_wdt_miscdev = {
228 +       .minor          = WATCHDOG_MINOR,
229 +       .name           = "watchdog",
230 +       .fops           = &mcf_wdt_fops,
231 +};
232 +
233 +static int __init mcf_wdt_init(void)
234 +{
235 +       wdt_tick_rate = MCF_BUSCLK/0xffff;
236 +#ifdef CONFIG_WATCHDOG_NOWAYOUT
237 +       nowayout = 1;
238 +#else
239 +       nowayout = 0;
240 +#endif
241 +       printk("ColdFire watchdog driver is loaded.\n");
242 +
243 +       return misc_register(&mcf_wdt_miscdev);
244 +}
245 +
246 +static void __exit mcf_wdt_exit(void)
247 +{
248 +       misc_deregister(&mcf_wdt_miscdev);
249 +}
250 +
251 +module_init(mcf_wdt_init);
252 +module_exit(mcf_wdt_exit);
253 +
254 +MODULE_AUTHOR("Deepak Saxena");
255 +MODULE_DESCRIPTION("ColdFire Watchdog");
256 +
257 +module_param(heartbeat, int, 0);
258 +MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
259 +
260 +module_param(nowayout, int, 0);
261 +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
262 +
263 +MODULE_LICENSE("GPL");
264 +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
265 +