2.6.31 support (WiP)
[openwrt/staging/chunkeey.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 +