| 1 | --- /dev/null |
| 2 | +++ b/drivers/watchdog/ar2315-wtd.c |
| 3 | @@ -0,0 +1,200 @@ |
| 4 | +/* |
| 5 | + * This program is free software; you can redistribute it and/or modify |
| 6 | + * it under the terms of the GNU General Public License as published by |
| 7 | + * the Free Software Foundation; either version 2 of the License, or |
| 8 | + * (at your option) any later version. |
| 9 | + * |
| 10 | + * This program is distributed in the hope that it will be useful, |
| 11 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | + * GNU General Public License for more details. |
| 14 | + * |
| 15 | + * You should have received a copy of the GNU General Public License |
| 16 | + * along with this program; if not, write to the Free Software |
| 17 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 18 | + * |
| 19 | + * Copyright (C) 2008 John Crispin <blogic@openwrt.org> |
| 20 | + * Based on EP93xx and ifxmips wdt driver |
| 21 | + */ |
| 22 | + |
| 23 | +#include <linux/interrupt.h> |
| 24 | +#include <linux/module.h> |
| 25 | +#include <linux/moduleparam.h> |
| 26 | +#include <linux/types.h> |
| 27 | +#include <linux/miscdevice.h> |
| 28 | +#include <linux/watchdog.h> |
| 29 | +#include <linux/fs.h> |
| 30 | +#include <linux/ioport.h> |
| 31 | +#include <linux/notifier.h> |
| 32 | +#include <linux/reboot.h> |
| 33 | +#include <linux/init.h> |
| 34 | +#include <linux/platform_device.h> |
| 35 | + |
| 36 | +#include <asm/io.h> |
| 37 | +#include <asm/uaccess.h> |
| 38 | +#include <asm/system.h> |
| 39 | +#include <asm/addrspace.h> |
| 40 | +#include <ar231x_platform.h> |
| 41 | +#include <ar2315_regs.h> |
| 42 | +#include <ar231x.h> |
| 43 | + |
| 44 | +#define CLOCK_RATE 40000000 |
| 45 | +#define HEARTBEAT(x) (x < 1 || x > 90)?(20):(x) |
| 46 | + |
| 47 | +static int wdt_timeout = 20; |
| 48 | +static int started = 0; |
| 49 | +static int in_use = 0; |
| 50 | + |
| 51 | +static void |
| 52 | +ar2315_wdt_enable(void) |
| 53 | +{ |
| 54 | + ar231x_write_reg(AR2315_WD, wdt_timeout * CLOCK_RATE); |
| 55 | + ar231x_write_reg(AR2315_ISR, 0x80); |
| 56 | +} |
| 57 | + |
| 58 | +static ssize_t |
| 59 | +ar2315_wdt_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) |
| 60 | +{ |
| 61 | + if(len) |
| 62 | + ar2315_wdt_enable(); |
| 63 | + return len; |
| 64 | +} |
| 65 | + |
| 66 | +static int |
| 67 | +ar2315_wdt_open(struct inode *inode, struct file *file) |
| 68 | +{ |
| 69 | + if(in_use) |
| 70 | + return -EBUSY; |
| 71 | + ar2315_wdt_enable(); |
| 72 | + in_use = started = 1; |
| 73 | + return nonseekable_open(inode, file); |
| 74 | +} |
| 75 | + |
| 76 | +static int |
| 77 | +ar2315_wdt_release(struct inode *inode, struct file *file) |
| 78 | +{ |
| 79 | + in_use = 0; |
| 80 | + return 0; |
| 81 | +} |
| 82 | + |
| 83 | +static irqreturn_t |
| 84 | +ar2315_wdt_interrupt(int irq, void *dev_id) |
| 85 | +{ |
| 86 | + if(started) |
| 87 | + { |
| 88 | + printk(KERN_CRIT "watchdog expired, rebooting system\n"); |
| 89 | + emergency_restart(); |
| 90 | + } else { |
| 91 | + ar231x_write_reg(AR2315_WDC, 0); |
| 92 | + ar231x_write_reg(AR2315_WD, 0); |
| 93 | + ar231x_write_reg(AR2315_ISR, 0x80); |
| 94 | + } |
| 95 | + return IRQ_HANDLED; |
| 96 | +} |
| 97 | + |
| 98 | +static struct watchdog_info ident = { |
| 99 | + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, |
| 100 | + .identity = "ar2315 Watchdog", |
| 101 | +}; |
| 102 | + |
| 103 | +static int |
| 104 | +ar2315_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) |
| 105 | +{ |
| 106 | + int new_wdt_timeout; |
| 107 | + int ret = -ENOIOCTLCMD; |
| 108 | + |
| 109 | + switch(cmd) |
| 110 | + { |
| 111 | + case WDIOC_GETSUPPORT: |
| 112 | + ret = copy_to_user((struct watchdog_info __user *)arg, &ident, sizeof(ident)) ? -EFAULT : 0; |
| 113 | + break; |
| 114 | + |
| 115 | + case WDIOC_KEEPALIVE: |
| 116 | + ar2315_wdt_enable(); |
| 117 | + ret = 0; |
| 118 | + break; |
| 119 | + |
| 120 | + case WDIOC_SETTIMEOUT: |
| 121 | + if((ret = get_user(new_wdt_timeout, (int __user *)arg))) |
| 122 | + break; |
| 123 | + wdt_timeout = HEARTBEAT(new_wdt_timeout); |
| 124 | + ar2315_wdt_enable(); |
| 125 | + break; |
| 126 | + |
| 127 | + case WDIOC_GETTIMEOUT: |
| 128 | + ret = put_user(wdt_timeout, (int __user *)arg); |
| 129 | + break; |
| 130 | + } |
| 131 | + return ret; |
| 132 | +} |
| 133 | + |
| 134 | +static struct file_operations ar2315_wdt_fops = { |
| 135 | + .owner = THIS_MODULE, |
| 136 | + .llseek = no_llseek, |
| 137 | + .write = ar2315_wdt_write, |
| 138 | + .ioctl = ar2315_wdt_ioctl, |
| 139 | + .open = ar2315_wdt_open, |
| 140 | + .release = ar2315_wdt_release, |
| 141 | +}; |
| 142 | + |
| 143 | +static struct miscdevice ar2315_wdt_miscdev = { |
| 144 | + .minor = WATCHDOG_MINOR, |
| 145 | + .name = "watchdog", |
| 146 | + .fops = &ar2315_wdt_fops, |
| 147 | +}; |
| 148 | + |
| 149 | +static int |
| 150 | +ar2315_wdt_probe(struct platform_device *dev) |
| 151 | +{ |
| 152 | + int ret = 0; |
| 153 | + |
| 154 | + ar2315_wdt_enable(); |
| 155 | + ret = request_irq(AR531X_MISC_IRQ_WATCHDOG, ar2315_wdt_interrupt, IRQF_DISABLED, "ar2315_wdt", NULL); |
| 156 | + if(ret) |
| 157 | + { |
| 158 | + printk(KERN_ERR "ar2315wdt: failed to register inetrrupt\n"); |
| 159 | + goto out; |
| 160 | + } |
| 161 | + |
| 162 | + ret = misc_register(&ar2315_wdt_miscdev); |
| 163 | + if(ret) |
| 164 | + printk(KERN_ERR "ar2315wdt: failed to register miscdev\n"); |
| 165 | + |
| 166 | +out: |
| 167 | + return ret; |
| 168 | +} |
| 169 | + |
| 170 | +static int |
| 171 | +ar2315_wdt_remove(struct platform_device *dev) |
| 172 | +{ |
| 173 | + misc_deregister(&ar2315_wdt_miscdev); |
| 174 | + free_irq(AR531X_MISC_IRQ_WATCHDOG, NULL); |
| 175 | + return 0; |
| 176 | +} |
| 177 | + |
| 178 | +static struct platform_driver ar2315_wdt_driver = { |
| 179 | + .probe = ar2315_wdt_probe, |
| 180 | + .remove = ar2315_wdt_remove, |
| 181 | + .driver = { |
| 182 | + .name = "ar2315_wdt", |
| 183 | + .owner = THIS_MODULE, |
| 184 | + }, |
| 185 | +}; |
| 186 | + |
| 187 | +static int __init |
| 188 | +init_ar2315_wdt(void) |
| 189 | +{ |
| 190 | + int ret = platform_driver_register(&ar2315_wdt_driver); |
| 191 | + if(ret) |
| 192 | + printk(KERN_INFO "ar2315_wdt: error registering platfom driver!"); |
| 193 | + return ret; |
| 194 | +} |
| 195 | + |
| 196 | +static void __exit |
| 197 | +exit_ar2315_wdt(void) |
| 198 | +{ |
| 199 | + platform_driver_unregister(&ar2315_wdt_driver); |
| 200 | +} |
| 201 | + |
| 202 | +module_init(init_ar2315_wdt); |
| 203 | +module_exit(exit_ar2315_wdt); |
| 204 | --- a/drivers/watchdog/Kconfig |
| 205 | +++ b/drivers/watchdog/Kconfig |
| 206 | @@ -930,6 +930,12 @@ config BCM63XX_WDT |
| 207 | To compile this driver as a loadable module, choose M here. |
| 208 | The module will be called bcm63xx_wdt. |
| 209 | |
| 210 | +config ATHEROS_WDT |
| 211 | + tristate "Atheros wisoc Watchdog Timer" |
| 212 | + depends on ATHEROS_AR231X |
| 213 | + help |
| 214 | + Hardware driver for the Atheros wisoc Watchdog Timer. |
| 215 | + |
| 216 | # PARISC Architecture |
| 217 | |
| 218 | # POWERPC Architecture |
| 219 | --- a/drivers/watchdog/Makefile |
| 220 | +++ b/drivers/watchdog/Makefile |
| 221 | @@ -116,6 +116,7 @@ obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o |
| 222 | obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o |
| 223 | obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o |
| 224 | obj-$(CONFIG_AR7_WDT) += ar7_wdt.o |
| 225 | +obj-$(CONFIG_ATHEROS_WDT) += ar2315-wtd.o |
| 226 | obj-$(CONFIG_TXX9_WDT) += txx9wdt.o |
| 227 | obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o |
| 228 | octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o |
| 229 | |