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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [watchdog/] [mpc5200_wdt.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
#include <linux/init.h>
2
#include <linux/module.h>
3
#include <linux/miscdevice.h>
4
#include <linux/watchdog.h>
5
#include <linux/io.h>
6
#include <linux/spinlock.h>
7
#include <asm/of_platform.h>
8
#include <asm/uaccess.h>
9
#include <asm/mpc52xx.h>
10
 
11
 
12
#define GPT_MODE_WDT            (1<<15)
13
#define GPT_MODE_CE             (1<<12)
14
#define GPT_MODE_MS_TIMER       (0x4)
15
 
16
 
17
struct mpc5200_wdt {
18
        unsigned count; /* timer ticks before watchdog kicks in */
19
        long ipb_freq;
20
        struct miscdevice miscdev;
21
        struct resource mem;
22
        struct mpc52xx_gpt __iomem *regs;
23
        spinlock_t io_lock;
24
};
25
 
26
/* is_active stores wether or not the /dev/watchdog device is opened */
27
static unsigned long is_active;
28
 
29
/* misc devices don't provide a way, to get back to 'dev' or 'miscdev' from
30
 * file operations, which sucks. But there can be max 1 watchdog anyway, so...
31
 */
32
static struct mpc5200_wdt *wdt_global;
33
 
34
 
35
/* helper to calculate timeout in timer counts */
36
static void mpc5200_wdt_set_timeout(struct mpc5200_wdt *wdt, int timeout)
37
{
38
        /* use biggest prescaler of 64k */
39
        wdt->count = (wdt->ipb_freq + 0xffff) / 0x10000 * timeout;
40
 
41
        if (wdt->count > 0xffff)
42
                wdt->count = 0xffff;
43
}
44
/* return timeout in seconds (calculated from timer count) */
45
static int mpc5200_wdt_get_timeout(struct mpc5200_wdt *wdt)
46
{
47
        return wdt->count * 0x10000 / wdt->ipb_freq;
48
}
49
 
50
 
51
/* watchdog operations */
52
static int mpc5200_wdt_start(struct mpc5200_wdt *wdt)
53
{
54
        spin_lock(&wdt->io_lock);
55
        /* disable */
56
        out_be32(&wdt->regs->mode, 0);
57
        /* set timeout, with maximum prescaler */
58
        out_be32(&wdt->regs->count, 0x0 | wdt->count);
59
        /* enable watchdog */
60
        out_be32(&wdt->regs->mode, GPT_MODE_CE | GPT_MODE_WDT | GPT_MODE_MS_TIMER);
61
        spin_unlock(&wdt->io_lock);
62
 
63
        return 0;
64
}
65
static int mpc5200_wdt_ping(struct mpc5200_wdt *wdt)
66
{
67
        spin_lock(&wdt->io_lock);
68
        /* writing A5 to OCPW resets the watchdog */
69
        out_be32(&wdt->regs->mode, 0xA5000000 | (0xffffff & in_be32(&wdt->regs->mode)));
70
        spin_unlock(&wdt->io_lock);
71
        return 0;
72
}
73
static int mpc5200_wdt_stop(struct mpc5200_wdt *wdt)
74
{
75
        spin_lock(&wdt->io_lock);
76
        /* disable */
77
        out_be32(&wdt->regs->mode, 0);
78
        spin_unlock(&wdt->io_lock);
79
        return 0;
80
}
81
 
82
 
83
/* file operations */
84
static ssize_t mpc5200_wdt_write(struct file *file, const char __user *data,
85
                size_t len, loff_t *ppos)
86
{
87
        struct mpc5200_wdt *wdt = file->private_data;
88
        mpc5200_wdt_ping(wdt);
89
        return 0;
90
}
91
static struct watchdog_info mpc5200_wdt_info = {
92
        .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
93
        .identity       = "mpc5200 watchdog on GPT0",
94
};
95
static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file,
96
                unsigned int cmd, unsigned long arg)
97
{
98
        struct mpc5200_wdt *wdt = file->private_data;
99
        int __user *data = (int __user *)arg;
100
        int timeout;
101
        int ret = 0;
102
 
103
        switch (cmd) {
104
        case WDIOC_GETSUPPORT:
105
                ret = copy_to_user(data, &mpc5200_wdt_info,
106
                        sizeof(mpc5200_wdt_info));
107
                if (ret)
108
                        ret = -EFAULT;
109
                break;
110
 
111
        case WDIOC_GETSTATUS:
112
        case WDIOC_GETBOOTSTATUS:
113
                ret = put_user(0, data);
114
                break;
115
 
116
        case WDIOC_KEEPALIVE:
117
                mpc5200_wdt_ping(wdt);
118
                break;
119
 
120
        case WDIOC_SETTIMEOUT:
121
                ret = get_user(timeout, data);
122
                if (ret)
123
                        break;
124
                mpc5200_wdt_set_timeout(wdt, timeout);
125
                mpc5200_wdt_start(wdt);
126
                /* fall through and return the timeout */
127
 
128
        case WDIOC_GETTIMEOUT:
129
                timeout = mpc5200_wdt_get_timeout(wdt);
130
                ret = put_user(timeout, data);
131
                break;
132
 
133
        default:
134
                ret = -ENOTTY;
135
        }
136
        return ret;
137
}
138
static int mpc5200_wdt_open(struct inode *inode, struct file *file)
139
{
140
        /* /dev/watchdog can only be opened once */
141
        if (test_and_set_bit(0, &is_active))
142
                return -EBUSY;
143
 
144
        /* Set and activate the watchdog */
145
        mpc5200_wdt_set_timeout(wdt_global, 30);
146
        mpc5200_wdt_start(wdt_global);
147
        file->private_data = wdt_global;
148
        return nonseekable_open(inode, file);
149
}
150
static int mpc5200_wdt_release(struct inode *inode, struct file *file)
151
{
152
#if WATCHDOG_NOWAYOUT == 0
153
        struct mpc5200_wdt *wdt = file->private_data;
154
        mpc5200_wdt_stop(wdt);
155
        wdt->count = 0;          /* == disabled */
156
#endif
157
        clear_bit(0, &is_active);
158
        return 0;
159
}
160
 
161
static struct file_operations mpc5200_wdt_fops = {
162
        .owner  = THIS_MODULE,
163
        .write  = mpc5200_wdt_write,
164
        .ioctl  = mpc5200_wdt_ioctl,
165
        .open   = mpc5200_wdt_open,
166
        .release = mpc5200_wdt_release,
167
};
168
 
169
/* module operations */
170
static int mpc5200_wdt_probe(struct of_device *op, const struct of_device_id *match)
171
{
172
        struct mpc5200_wdt *wdt;
173
        int err;
174
        const void *has_wdt;
175
        int size;
176
 
177
        has_wdt = of_get_property(op->node, "has-wdt", NULL);
178
        if (!has_wdt)
179
                has_wdt = of_get_property(op->node, "fsl,has-wdt", NULL);
180
        if (!has_wdt)
181
                return -ENODEV;
182
 
183
        wdt = kzalloc(sizeof(*wdt), GFP_KERNEL);
184
        if (!wdt)
185
                return -ENOMEM;
186
 
187
        wdt->ipb_freq = mpc52xx_find_ipb_freq(op->node);
188
 
189
        err = of_address_to_resource(op->node, 0, &wdt->mem);
190
        if (err)
191
                goto out_free;
192
        size = wdt->mem.end - wdt->mem.start + 1;
193
        if (!request_mem_region(wdt->mem.start, size, "mpc5200_wdt")) {
194
                err = -ENODEV;
195
                goto out_free;
196
        }
197
        wdt->regs = ioremap(wdt->mem.start, size);
198
        if (!wdt->regs) {
199
                err = -ENODEV;
200
                goto out_release;
201
        }
202
 
203
        dev_set_drvdata(&op->dev, wdt);
204
        spin_lock_init(&wdt->io_lock);
205
 
206
        wdt->miscdev = (struct miscdevice) {
207
                .minor  = WATCHDOG_MINOR,
208
                .name   = "watchdog",
209
                .fops   = &mpc5200_wdt_fops,
210
                .parent = &op->dev,
211
        };
212
        wdt_global = wdt;
213
        err = misc_register(&wdt->miscdev);
214
        if (!err)
215
                return 0;
216
 
217
        iounmap(wdt->regs);
218
 out_release:
219
        release_mem_region(wdt->mem.start, size);
220
 out_free:
221
        kfree(wdt);
222
        return err;
223
}
224
 
225
static int mpc5200_wdt_remove(struct of_device *op)
226
{
227
        struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
228
 
229
        mpc5200_wdt_stop(wdt);
230
        misc_deregister(&wdt->miscdev);
231
        iounmap(wdt->regs);
232
        release_mem_region(wdt->mem.start, wdt->mem.end - wdt->mem.start + 1);
233
        kfree(wdt);
234
 
235
        return 0;
236
}
237
static int mpc5200_wdt_suspend(struct of_device *op, pm_message_t state)
238
{
239
        struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
240
        mpc5200_wdt_stop(wdt);
241
        return 0;
242
}
243
static int mpc5200_wdt_resume(struct of_device *op)
244
{
245
        struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
246
        if (wdt->count)
247
                mpc5200_wdt_start(wdt);
248
        return 0;
249
}
250
static int mpc5200_wdt_shutdown(struct of_device *op)
251
{
252
        struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
253
        mpc5200_wdt_stop(wdt);
254
        return 0;
255
}
256
 
257
static struct of_device_id mpc5200_wdt_match[] = {
258
        { .compatible = "mpc5200-gpt", },
259
        { .compatible = "fsl,mpc5200-gpt", },
260
        {},
261
};
262
static struct of_platform_driver mpc5200_wdt_driver = {
263
        .owner          = THIS_MODULE,
264
        .name           = "mpc5200-gpt-wdt",
265
        .match_table    = mpc5200_wdt_match,
266
        .probe          = mpc5200_wdt_probe,
267
        .remove         = mpc5200_wdt_remove,
268
        .suspend        = mpc5200_wdt_suspend,
269
        .resume         = mpc5200_wdt_resume,
270
        .shutdown       = mpc5200_wdt_shutdown,
271
};
272
 
273
 
274
static int __init mpc5200_wdt_init(void)
275
{
276
        return of_register_platform_driver(&mpc5200_wdt_driver);
277
}
278
 
279
static void __exit mpc5200_wdt_exit(void)
280
{
281
        of_unregister_platform_driver(&mpc5200_wdt_driver);
282
}
283
 
284
module_init(mpc5200_wdt_init);
285
module_exit(mpc5200_wdt_exit);
286
 
287
MODULE_AUTHOR("Domen Puncer <domen.puncer@telargo.com>");
288
MODULE_LICENSE("Dual BSD/GPL");
289
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.