OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [watchdog/] [ks8695_wdt.c] - Blame information for rev 78

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * Watchdog driver for Kendin/Micrel KS8695.
3
 *
4
 * (C) 2007 Andrew Victor
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License version 2 as
8
 * published by the Free Software Foundation.
9
 */
10
 
11
#include <linux/bitops.h>
12
#include <linux/errno.h>
13
#include <linux/fs.h>
14
#include <linux/init.h>
15
#include <linux/kernel.h>
16
#include <linux/miscdevice.h>
17
#include <linux/module.h>
18
#include <linux/moduleparam.h>
19
#include <linux/platform_device.h>
20
#include <linux/types.h>
21
#include <linux/watchdog.h>
22
#include <asm/io.h>
23
#include <asm/uaccess.h>
24
#include <asm/arch/regs-timer.h>
25
 
26
 
27
#define WDT_DEFAULT_TIME        5       /* seconds */
28
#define WDT_MAX_TIME            171     /* seconds */
29
 
30
static int wdt_time = WDT_DEFAULT_TIME;
31
static int nowayout = WATCHDOG_NOWAYOUT;
32
 
33
module_param(wdt_time, int, 0);
34
MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")");
35
 
36
#ifdef CONFIG_WATCHDOG_NOWAYOUT
37
module_param(nowayout, int, 0);
38
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
39
#endif
40
 
41
 
42
static unsigned long ks8695wdt_busy;
43
 
44
/* ......................................................................... */
45
 
46
/*
47
 * Disable the watchdog.
48
 */
49
static void inline ks8695_wdt_stop(void)
50
{
51
        unsigned long tmcon;
52
 
53
        /* disable timer0 */
54
        tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
55
        __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
56
}
57
 
58
/*
59
 * Enable and reset the watchdog.
60
 */
61
static void inline ks8695_wdt_start(void)
62
{
63
        unsigned long tmcon;
64
        unsigned long tval = wdt_time * CLOCK_TICK_RATE;
65
 
66
        /* disable timer0 */
67
        tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
68
        __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
69
 
70
        /* program timer0 */
71
        __raw_writel(tval | T0TC_WATCHDOG, KS8695_TMR_VA + KS8695_T0TC);
72
 
73
        /* re-enable timer0 */
74
        tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
75
        __raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
76
}
77
 
78
/*
79
 * Reload the watchdog timer.  (ie, pat the watchdog)
80
 */
81
static void inline ks8695_wdt_reload(void)
82
{
83
        unsigned long tmcon;
84
 
85
        /* disable, then re-enable timer0 */
86
        tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
87
        __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
88
        __raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
89
}
90
 
91
/*
92
 * Change the watchdog time interval.
93
 */
94
static int ks8695_wdt_settimeout(int new_time)
95
{
96
        /*
97
         * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz
98
         *
99
         * Since WDV is a 16-bit counter, the maximum period is
100
         * 65536 / 0.256 = 256 seconds.
101
         */
102
        if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
103
                return -EINVAL;
104
 
105
        /* Set new watchdog time. It will be used when ks8695_wdt_start() is called. */
106
        wdt_time = new_time;
107
        return 0;
108
}
109
 
110
/* ......................................................................... */
111
 
112
/*
113
 * Watchdog device is opened, and watchdog starts running.
114
 */
115
static int ks8695_wdt_open(struct inode *inode, struct file *file)
116
{
117
        if (test_and_set_bit(0, &ks8695wdt_busy))
118
                return -EBUSY;
119
 
120
        ks8695_wdt_start();
121
        return nonseekable_open(inode, file);
122
}
123
 
124
/*
125
 * Close the watchdog device.
126
 * If CONFIG_WATCHDOG_NOWAYOUT is NOT defined then the watchdog is also
127
 *  disabled.
128
 */
129
static int ks8695_wdt_close(struct inode *inode, struct file *file)
130
{
131
        if (!nowayout)
132
                ks8695_wdt_stop();      /* Disable the watchdog when file is closed */
133
 
134
        clear_bit(0, &ks8695wdt_busy);
135
        return 0;
136
}
137
 
138
static struct watchdog_info ks8695_wdt_info = {
139
        .identity       = "ks8695 watchdog",
140
        .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
141
};
142
 
143
/*
144
 * Handle commands from user-space.
145
 */
146
static int ks8695_wdt_ioctl(struct inode *inode, struct file *file,
147
                unsigned int cmd, unsigned long arg)
148
{
149
        void __user *argp = (void __user *)arg;
150
        int __user *p = argp;
151
        int new_value;
152
 
153
        switch(cmd) {
154
                case WDIOC_KEEPALIVE:
155
                        ks8695_wdt_reload();    /* pat the watchdog */
156
                        return 0;
157
 
158
                case WDIOC_GETSUPPORT:
159
                        return copy_to_user(argp, &ks8695_wdt_info, sizeof(ks8695_wdt_info)) ? -EFAULT : 0;
160
 
161
                case WDIOC_SETTIMEOUT:
162
                        if (get_user(new_value, p))
163
                                return -EFAULT;
164
 
165
                        if (ks8695_wdt_settimeout(new_value))
166
                                return -EINVAL;
167
 
168
                        /* Enable new time value */
169
                        ks8695_wdt_start();
170
 
171
                        /* Return current value */
172
                        return put_user(wdt_time, p);
173
 
174
                case WDIOC_GETTIMEOUT:
175
                        return put_user(wdt_time, p);
176
 
177
                case WDIOC_GETSTATUS:
178
                case WDIOC_GETBOOTSTATUS:
179
                        return put_user(0, p);
180
 
181
                case WDIOC_SETOPTIONS:
182
                        if (get_user(new_value, p))
183
                                return -EFAULT;
184
 
185
                        if (new_value & WDIOS_DISABLECARD)
186
                                ks8695_wdt_stop();
187
                        if (new_value & WDIOS_ENABLECARD)
188
                                ks8695_wdt_start();
189
                        return 0;
190
 
191
                default:
192
                        return -ENOTTY;
193
        }
194
}
195
 
196
/*
197
 * Pat the watchdog whenever device is written to.
198
 */
199
static ssize_t ks8695_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
200
{
201
        ks8695_wdt_reload();            /* pat the watchdog */
202
        return len;
203
}
204
 
205
/* ......................................................................... */
206
 
207
static const struct file_operations ks8695wdt_fops = {
208
        .owner          = THIS_MODULE,
209
        .llseek         = no_llseek,
210
        .ioctl          = ks8695_wdt_ioctl,
211
        .open           = ks8695_wdt_open,
212
        .release        = ks8695_wdt_close,
213
        .write          = ks8695_wdt_write,
214
};
215
 
216
static struct miscdevice ks8695wdt_miscdev = {
217
        .minor          = WATCHDOG_MINOR,
218
        .name           = "watchdog",
219
        .fops           = &ks8695wdt_fops,
220
};
221
 
222
static int __init ks8695wdt_probe(struct platform_device *pdev)
223
{
224
        int res;
225
 
226
        if (ks8695wdt_miscdev.parent)
227
                return -EBUSY;
228
        ks8695wdt_miscdev.parent = &pdev->dev;
229
 
230
        res = misc_register(&ks8695wdt_miscdev);
231
        if (res)
232
                return res;
233
 
234
        printk("KS8695 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : "");
235
        return 0;
236
}
237
 
238
static int __exit ks8695wdt_remove(struct platform_device *pdev)
239
{
240
        int res;
241
 
242
        res = misc_deregister(&ks8695wdt_miscdev);
243
        if (!res)
244
                ks8695wdt_miscdev.parent = NULL;
245
 
246
        return res;
247
}
248
 
249
static void ks8695wdt_shutdown(struct platform_device *pdev)
250
{
251
        ks8695_wdt_stop();
252
}
253
 
254
#ifdef CONFIG_PM
255
 
256
static int ks8695wdt_suspend(struct platform_device *pdev, pm_message_t message)
257
{
258
        ks8695_wdt_stop();
259
        return 0;
260
}
261
 
262
static int ks8695wdt_resume(struct platform_device *pdev)
263
{
264
        if (ks8695wdt_busy)
265
                ks8695_wdt_start();
266
        return 0;
267
}
268
 
269
#else
270
#define ks8695wdt_suspend NULL
271
#define ks8695wdt_resume        NULL
272
#endif
273
 
274
static struct platform_driver ks8695wdt_driver = {
275
        .probe          = ks8695wdt_probe,
276
        .remove         = __exit_p(ks8695wdt_remove),
277
        .shutdown       = ks8695wdt_shutdown,
278
        .suspend        = ks8695wdt_suspend,
279
        .resume         = ks8695wdt_resume,
280
        .driver         = {
281
                .name   = "ks8695_wdt",
282
                .owner  = THIS_MODULE,
283
        },
284
};
285
 
286
static int __init ks8695_wdt_init(void)
287
{
288
        /* Check that the heartbeat value is within range; if not reset to the default */
289
        if (ks8695_wdt_settimeout(wdt_time)) {
290
                ks8695_wdt_settimeout(WDT_DEFAULT_TIME);
291
                pr_info("ks8695_wdt: wdt_time value must be 1 <= wdt_time <= %i, using %d\n", wdt_time, WDT_MAX_TIME);
292
        }
293
 
294
        return platform_driver_register(&ks8695wdt_driver);
295
}
296
 
297
static void __exit ks8695_wdt_exit(void)
298
{
299
        platform_driver_unregister(&ks8695wdt_driver);
300
}
301
 
302
module_init(ks8695_wdt_init);
303
module_exit(ks8695_wdt_exit);
304
 
305
MODULE_AUTHOR("Andrew Victor");
306
MODULE_DESCRIPTION("Watchdog driver for KS8695");
307
MODULE_LICENSE("GPL");
308
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.