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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [alim1535d_wdt.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      Watchdog for the 7101 PMU version found in the ALi1535 chipsets
3
 *
4
 *      This program is free software; you can redistribute it and/or
5
 *      modify it under the terms of the GNU General Public License
6
 *      as published by the Free Software Foundation; either version
7
 *      2 of the License, or (at your option) any later version.
8
 */
9
 
10
#include <linux/module.h>
11
#include <linux/types.h>
12
#include <linux/kernel.h>
13
#include <linux/fs.h>
14
#include <linux/mm.h>
15
#include <linux/miscdevice.h>
16
#include <linux/watchdog.h>
17
#include <linux/reboot.h>
18
#include <linux/init.h>
19
#include <linux/pci.h>
20
#include <linux/ioport.h>
21
#include <asm/uaccess.h>
22
#include <asm/io.h>
23
 
24
static spinlock_t ali_lock;     /* Guards the hardware */
25
 
26
#ifdef CONFIG_WATCHDOG_NOWAYOUT
27
static int nowayout = 1;
28
#else
29
static int nowayout = 0;
30
#endif
31
 
32
MODULE_PARM(nowayout,"i");
33
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
34
 
35
static unsigned long timer_alive;
36
static char ali_expect_close;
37
static u32 ali_timeout = 60;                    /* 60 seconds */
38
static u32 ali_timeout_bits = 1 | (1<<7);       /* 1 count in minutes */
39
 
40
static struct pci_dev *ali_pci;
41
 
42
/**
43
 *      ali_timer_start         -       start watchdog countdown
44
 *      @dev: PCI device of the PMU
45
 *
46
 *      Starts the timer running providing the timer has a counter
47
 *      configuration set.
48
 */
49
 
50
static void ali_timer_start(struct pci_dev *pdev)
51
{
52
        u32 val;
53
 
54
        spin_lock(&ali_lock);
55
 
56
        pci_read_config_dword(pdev, 0xCC, &val);
57
        val &= ~0x3F;   /* Mask count */
58
        val |= (1<<25) | ali_timeout_bits;
59
        pci_write_config_dword(pdev, 0xCC, val);
60
        spin_unlock(&ali_lock);
61
}
62
 
63
/**
64
 *      ali_timer_stop  -       stop the timer countdown
65
 *      @pdev: PCI device of the PMU
66
 *
67
 *      Stop the ALi watchdog countdown
68
 */
69
 
70
static void ali_timer_stop (struct pci_dev *pdev)
71
{
72
        u32 val;
73
 
74
        spin_lock(&ali_lock);
75
        pci_read_config_dword(pdev, 0xCC, &val);
76
        val &= ~0x3F;   /* Mask count to zero (disabled) */
77
        val &= ~(1<<25);/* and for safety mask the reset enable */
78
        pci_write_config_dword(pdev, 0xCC, val);
79
        spin_unlock(&ali_lock);
80
}
81
 
82
/**
83
 *      ali_timer_settimer      -       compute the timer reload value
84
 *      @pdev: PCI device of the PMU
85
 *      @t: time in seconds
86
 *
87
 *      Computes the timeout values needed and then restarts the timer
88
 *      running with the new timeout values
89
 */
90
 
91
static int ali_timer_settimer(struct pci_dev *pdev, unsigned long t)
92
{
93
        if(t < 60)
94
                ali_timeout_bits = t|(1<<6);
95
        else if(t < 3600)
96
                ali_timeout_bits = (t/60)|(1<<7);
97
        else if(t < 18000)
98
                ali_timeout_bits = (t/300)|(1<<6)|(1<<7);
99
        else return -EINVAL;
100
 
101
        ali_timeout = t;
102
        ali_timer_start(pdev);
103
        return 0;
104
}
105
 
106
/**
107
 *      ali_open        -       handle open of ali watchdog
108
 *      @inode: inode from VFS
109
 *      @file: file from VFS
110
 *
111
 *      Open the ALi watchdog device. Ensure only one person opens it
112
 *      at a time. Also start the watchdog running.
113
 */
114
 
115
static int ali_open(struct inode *inode, struct file *file)
116
{
117
        if (test_and_set_bit(0, &timer_alive))
118
                return -EBUSY;
119
        ali_timer_start (ali_pci);
120
        return 0;
121
}
122
 
123
/**
124
 *      ali_release     -       close an ALi watchdog
125
 *      @inode: inode from VFS
126
 *      @file: file from VFS
127
 *
128
 *      Close the ALi watchdog device. Actual shutdown of the timer
129
 *      only occurs if the magic sequence has been set or nowayout is
130
 *      disabled
131
 */
132
 
133
static int ali_release (struct inode *inode, struct file *file)
134
{
135
        /*
136
         *      Shut off the timer.
137
         */
138
        if (ali_expect_close == 42 && !nowayout) {
139
                ali_timer_stop(ali_pci);
140
        } else {
141
                ali_timer_start(ali_pci);
142
                printk(KERN_CRIT  "ali1535_wdt: Unexpected close, not stopping watchdog!\n");
143
        }
144
        clear_bit(0, &timer_alive);
145
        ali_expect_close = 0;
146
        return 0;
147
}
148
 
149
/**
150
 *      ali_write       -       writes to ALi watchdog
151
 *      @file: file from VFS
152
 *      @data: user address of data
153
 *      @len: length of data
154
 *      @ppos: pointer to the file offset
155
 *
156
 *      Handle a write to the ALi watchdog. Writing to the file pings
157
 *      the watchdog and resets it. Writing the magic 'V' sequence allows
158
 *      the next close to turn off the watchdog.
159
 */
160
 
161
static ssize_t ali_write (struct file *file, const char *data,
162
                              size_t len, loff_t * ppos)
163
{
164
        /*  Can't seek (pwrite) on this device  */
165
        if (ppos != &file->f_pos)
166
                return -ESPIPE;
167
 
168
        /* See if we got the magic character 'V' and reload the timer */
169
        if (len) {
170
                size_t i;
171
 
172
                ali_expect_close = 0;
173
 
174
                /* scan to see wether or not we got the magic character */
175
                for (i = 0; i != len; i++) {
176
                        u8 c;
177
                        if(get_user(c, data+i))
178
                                return -EFAULT;
179
                        if (c == 'V')
180
                                ali_expect_close = 42;
181
                }
182
 
183
                /* someone wrote to us, we should reload the timer */
184
                ali_timer_start(ali_pci);
185
                return 1;
186
        }
187
        return 0;
188
}
189
 
190
/**
191
 *      ali_ioctl       -       handle watchdog ioctls
192
 *      @inode: VFS inode
193
 *      @file: VFS file pointer
194
 *      @cmd: ioctl number
195
 *      @arg: arguments to the ioctl
196
 *
197
 *      Handle the watchdog ioctls supported by the ALi driver. Really
198
 *      we want an extension to enable irq ack monitoring and the like
199
 */
200
 
201
static int ali_ioctl (struct inode *inode, struct file *file,
202
                          unsigned int cmd, unsigned long arg)
203
{
204
        int options, retval = -EINVAL;
205
        u32 t;
206
        static struct watchdog_info ident = {
207
                options:                WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
208
                firmware_version:       0,
209
                identity:               "ALi 1535D+ TCO timer",
210
        };
211
        switch (cmd) {
212
                default:
213
                        return -ENOTTY;
214
                case WDIOC_GETSUPPORT:
215
                        if (copy_to_user((struct watchdog_info *) arg, &ident, sizeof (ident)))
216
                                return -EFAULT;
217
                        return 0;
218
                case WDIOC_GETSTATUS:
219
                case WDIOC_GETBOOTSTATUS:
220
                        return put_user(0, (int *) arg);
221
                case WDIOC_SETOPTIONS:
222
                        if (get_user (options, (int *) arg))
223
                                return -EFAULT;
224
                        if (options & WDIOS_DISABLECARD) {
225
                                ali_timer_stop(ali_pci);
226
                                retval = 0;
227
                        }
228
                        if (options & WDIOS_ENABLECARD) {
229
                                ali_timer_start(ali_pci);
230
                                retval = 0;
231
                        }
232
                        return retval;
233
                case WDIOC_KEEPALIVE:
234
                        ali_timer_start(ali_pci);
235
                        return 0;
236
                case WDIOC_SETTIMEOUT:
237
                        if (get_user(t, (int *) arg))
238
                                return -EFAULT;
239
                        if (ali_timer_settimer(ali_pci, t))
240
                            return -EINVAL;
241
                        ali_timer_start(ali_pci);
242
                        /* Fall */
243
                case WDIOC_GETTIMEOUT:
244
                        return put_user(ali_timeout, (int *)arg);
245
        }
246
}
247
 
248
/*
249
 * Data for PCI driver interface
250
 *
251
 * This data only exists for exporting the supported
252
 * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
253
 * register a pci_driver, because someone else might one day
254
 * want to register another driver on the same PCI id.
255
 */
256
 
257
static struct pci_device_id ali_pci_tbl[] __initdata = {
258
        { PCI_VENDOR_ID_AL, 1535, PCI_ANY_ID, PCI_ANY_ID,},
259
        { 0, },
260
};
261
MODULE_DEVICE_TABLE (pci, ali_pci_tbl);
262
 
263
 
264
/**
265
 *      ali_find_watchdog       -       find a 1535 and 7101
266
 *
267
 *      Scans the PCI hardware for a 1535 series bridge and matching 7101
268
 *      watchdog device. This may be overtight but it is better to be safe
269
 */
270
 
271
static int __init ali_find_watchdog(void)
272
{
273
        struct pci_dev *pdev;
274
        u32 wdog;
275
 
276
        /* Check for a 1535 series bridge */
277
        pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x1535, NULL);
278
        if(pdev == NULL)
279
                return -ENODEV;
280
 
281
        /* Check for the a 7101 PMU */
282
        pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x7101, NULL);
283
        if(pdev == NULL)
284
                return -ENODEV;
285
 
286
        if(pci_enable_device(pdev))
287
                return -EIO;
288
 
289
        ali_pci = pdev;
290
 
291
        /*
292
         *      Initialize the timer bits
293
         */
294
 
295
        pci_read_config_dword(pdev, 0xCC, &wdog);
296
 
297
        wdog &= ~0x3F;          /* Timer bits */
298
        wdog &= ~((1<<27)|(1<<26)|(1<<25)|(1<<24));     /* Issued events */
299
        wdog &= ~((1<<16)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9));      /* No monitor bits */
300
 
301
        pci_write_config_dword(pdev, 0xCC, wdog);
302
        return 0;
303
}
304
 
305
static struct file_operations ali_fops = {
306
        owner:          THIS_MODULE,
307
        write:          ali_write,
308
        ioctl:          ali_ioctl,
309
        open:           ali_open,
310
        release:        ali_release,
311
};
312
 
313
static struct miscdevice ali_miscdev = {
314
        minor:          WATCHDOG_MINOR,
315
        name:           "watchdog",
316
        fops:           &ali_fops,
317
};
318
 
319
/**
320
 *      watchdog_init   -       module initialiser
321
 *
322
 *      Scan for a suitable watchdog and if so initialize it. Return an error
323
 *      if we cannot, the error causes the module to unload
324
 */
325
 
326
static int __init watchdog_init (void)
327
{
328
        spin_lock_init(&ali_lock);
329
        if (!ali_find_watchdog())
330
                return -ENODEV;
331
        if (misc_register (&ali_miscdev) != 0) {
332
                printk (KERN_ERR "alim1535d: cannot register watchdog device node.\n");
333
                return -EIO;
334
        }
335
        return 0;
336
}
337
 
338
/**
339
 *      watchdog_cleanup        -       unload watchdog
340
 *
341
 *      Called on the unload of a successfully installed watchdog module.
342
 */
343
 
344
static void __exit watchdog_cleanup (void)
345
{
346
        ali_timer_stop(ali_pci);
347
        misc_deregister (&ali_miscdev);
348
}
349
 
350
module_init(watchdog_init);
351
module_exit(watchdog_cleanup);
352
 
353
MODULE_AUTHOR("Alan Cox");
354
MODULE_DESCRIPTION("Watchdog driver for the ALi 1535+ PMU");
355
MODULE_LICENSE("GPL");
356
EXPORT_NO_SYMBOLS;

powered by: WebSVN 2.1.0

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