linux/drivers/watchdog/riowd.c
<<
>>
Prefs
   1/* riowd.c - driver for hw watchdog inside Super I/O of RIO
   2 *
   3 * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
   4 */
   5
   6#include <linux/kernel.h>
   7#include <linux/module.h>
   8#include <linux/types.h>
   9#include <linux/fs.h>
  10#include <linux/errno.h>
  11#include <linux/init.h>
  12#include <linux/miscdevice.h>
  13#include <linux/smp_lock.h>
  14#include <linux/watchdog.h>
  15#include <linux/of.h>
  16#include <linux/of_device.h>
  17
  18#include <asm/io.h>
  19#include <asm/uaccess.h>
  20
  21
  22/* RIO uses the NatSemi Super I/O power management logical device
  23 * as its' watchdog.
  24 *
  25 * When the watchdog triggers, it asserts a line to the BBC (Boot Bus
  26 * Controller) of the machine.  The BBC can only be configured to
  27 * trigger a power-on reset when the signal is asserted.  The BBC
  28 * can be configured to ignore the signal entirely as well.
  29 *
  30 * The only Super I/O device register we care about is at index
  31 * 0x05 (WDTO_INDEX) which is the watchdog time-out in minutes (1-255).
  32 * If set to zero, this disables the watchdog.  When set, the system
  33 * must periodically (before watchdog expires) clear (set to zero) and
  34 * re-set the watchdog else it will trigger.
  35 *
  36 * There are two other indexed watchdog registers inside this Super I/O
  37 * logical device, but they are unused.  The first, at index 0x06 is
  38 * the watchdog control and can be used to make the watchdog timer re-set
  39 * when the PS/2 mouse or serial lines show activity.  The second, at
  40 * index 0x07 is merely a sampling of the line from the watchdog to the
  41 * BBC.
  42 *
  43 * The watchdog device generates no interrupts.
  44 */
  45
  46MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
  47MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO");
  48MODULE_SUPPORTED_DEVICE("watchdog");
  49MODULE_LICENSE("GPL");
  50
  51#define DRIVER_NAME     "riowd"
  52#define PFX             DRIVER_NAME ": "
  53
  54struct riowd {
  55        void __iomem            *regs;
  56        spinlock_t              lock;
  57};
  58
  59static struct riowd *riowd_device;
  60
  61#define WDTO_INDEX      0x05
  62
  63static int riowd_timeout = 1;           /* in minutes */
  64module_param(riowd_timeout, int, 0);
  65MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes");
  66
  67static void riowd_writereg(struct riowd *p, u8 val, int index)
  68{
  69        unsigned long flags;
  70
  71        spin_lock_irqsave(&p->lock, flags);
  72        writeb(index, p->regs + 0);
  73        writeb(val, p->regs + 1);
  74        spin_unlock_irqrestore(&p->lock, flags);
  75}
  76
  77static int riowd_open(struct inode *inode, struct file *filp)
  78{
  79        cycle_kernel_lock();
  80        nonseekable_open(inode, filp);
  81        return 0;
  82}
  83
  84static int riowd_release(struct inode *inode, struct file *filp)
  85{
  86        return 0;
  87}
  88
  89static int riowd_ioctl(struct inode *inode, struct file *filp,
  90                       unsigned int cmd, unsigned long arg)
  91{
  92        static struct watchdog_info info = {
  93                .options                = WDIOF_SETTIMEOUT,
  94                .firmware_version       = 1,
  95                .identity               = DRIVER_NAME,
  96        };
  97        void __user *argp = (void __user *)arg;
  98        struct riowd *p = riowd_device;
  99        unsigned int options;
 100        int new_margin;
 101
 102        switch (cmd) {
 103        case WDIOC_GETSUPPORT:
 104                if (copy_to_user(argp, &info, sizeof(info)))
 105                        return -EFAULT;
 106                break;
 107
 108        case WDIOC_GETSTATUS:
 109        case WDIOC_GETBOOTSTATUS:
 110                if (put_user(0, (int __user *)argp))
 111                        return -EFAULT;
 112                break;
 113
 114        case WDIOC_KEEPALIVE:
 115                riowd_writereg(p, riowd_timeout, WDTO_INDEX);
 116                break;
 117
 118        case WDIOC_SETOPTIONS:
 119                if (copy_from_user(&options, argp, sizeof(options)))
 120                        return -EFAULT;
 121
 122                if (options & WDIOS_DISABLECARD)
 123                        riowd_writereg(p, 0, WDTO_INDEX);
 124                else if (options & WDIOS_ENABLECARD)
 125                        riowd_writereg(p, riowd_timeout, WDTO_INDEX);
 126                else
 127                        return -EINVAL;
 128
 129                break;
 130
 131        case WDIOC_SETTIMEOUT:
 132                if (get_user(new_margin, (int __user *)argp))
 133                        return -EFAULT;
 134                if ((new_margin < 60) || (new_margin > (255 * 60)))
 135                        return -EINVAL;
 136                riowd_timeout = (new_margin + 59) / 60;
 137                riowd_writereg(p, riowd_timeout, WDTO_INDEX);
 138                /* Fall */
 139
 140        case WDIOC_GETTIMEOUT:
 141                return put_user(riowd_timeout * 60, (int __user *)argp);
 142
 143        default:
 144                return -EINVAL;
 145        };
 146
 147        return 0;
 148}
 149
 150static ssize_t riowd_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
 151{
 152        struct riowd *p = riowd_device;
 153
 154        if (count) {
 155                riowd_writereg(p, riowd_timeout, WDTO_INDEX);
 156                return 1;
 157        }
 158
 159        return 0;
 160}
 161
 162static const struct file_operations riowd_fops = {
 163        .owner =        THIS_MODULE,
 164        .llseek =       no_llseek,
 165        .ioctl =        riowd_ioctl,
 166        .open =         riowd_open,
 167        .write =        riowd_write,
 168        .release =      riowd_release,
 169};
 170
 171static struct miscdevice riowd_miscdev = {
 172        .minor  = WATCHDOG_MINOR,
 173        .name   = "watchdog",
 174        .fops   = &riowd_fops
 175};
 176
 177static int __devinit riowd_probe(struct of_device *op,
 178                                 const struct of_device_id *match)
 179{
 180        struct riowd *p;
 181        int err = -EINVAL;
 182
 183        if (riowd_device)
 184                goto out;
 185
 186        err = -ENOMEM;
 187        p = kzalloc(sizeof(*p), GFP_KERNEL);
 188        if (!p)
 189                goto out;
 190
 191        spin_lock_init(&p->lock);
 192
 193        p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME);
 194        if (!p->regs) {
 195                printk(KERN_ERR PFX "Cannot map registers.\n");
 196                goto out_free;
 197        }
 198
 199        err = misc_register(&riowd_miscdev);
 200        if (err) {
 201                printk(KERN_ERR PFX "Cannot register watchdog misc device.\n");
 202                goto out_iounmap;
 203        }
 204
 205        printk(KERN_INFO PFX "Hardware watchdog [%i minutes], "
 206               "regs at %p\n", riowd_timeout, p->regs);
 207
 208        dev_set_drvdata(&op->dev, p);
 209        riowd_device = p;
 210        err = 0;
 211
 212out_iounmap:
 213        of_iounmap(&op->resource[0], p->regs, 2);
 214
 215out_free:
 216        kfree(p);
 217
 218out:
 219        return err;
 220}
 221
 222static int __devexit riowd_remove(struct of_device *op)
 223{
 224        struct riowd *p = dev_get_drvdata(&op->dev);
 225
 226        misc_deregister(&riowd_miscdev);
 227        of_iounmap(&op->resource[0], p->regs, 2);
 228        kfree(p);
 229
 230        return 0;
 231}
 232
 233static const struct of_device_id riowd_match[] = {
 234        {
 235                .name = "pmc",
 236        },
 237        {},
 238};
 239MODULE_DEVICE_TABLE(of, riowd_match);
 240
 241static struct of_platform_driver riowd_driver = {
 242        .name           = DRIVER_NAME,
 243        .match_table    = riowd_match,
 244        .probe          = riowd_probe,
 245        .remove         = __devexit_p(riowd_remove),
 246};
 247
 248static int __init riowd_init(void)
 249{
 250        return of_register_driver(&riowd_driver, &of_bus_type);
 251}
 252
 253static void __exit riowd_exit(void)
 254{
 255        of_unregister_driver(&riowd_driver);
 256}
 257
 258module_init(riowd_init);
 259module_exit(riowd_exit);
 260