1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Watchdog driver for the SA11x0/PXA2xx 4 * 5 * (c) Copyright 2000 Oleg Drokin <green@crimea.edu> 6 * Based on SoftDog driver by Alan Cox <alan@lxorguk.ukuu.org.uk> 7 * 8 * Neither Oleg Drokin nor iXcelerator.com admit liability nor provide 9 * warranty for any of this software. This material is provided 10 * "AS-IS" and at no charge. 11 * 12 * (c) Copyright 2000 Oleg Drokin <green@crimea.edu> 13 * 14 * 27/11/2000 Initial release 15 */ 16 17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 18 19 #include <linux/module.h> 20 #include <linux/moduleparam.h> 21 #include <linux/clk.h> 22 #include <linux/types.h> 23 #include <linux/kernel.h> 24 #include <linux/fs.h> 25 #include <linux/miscdevice.h> 26 #include <linux/watchdog.h> 27 #include <linux/init.h> 28 #include <linux/io.h> 29 #include <linux/bitops.h> 30 #include <linux/uaccess.h> 31 #include <linux/timex.h> 32 33 #ifdef CONFIG_ARCH_PXA 34 #include <mach/regs-ost.h> 35 #endif 36 37 #include <mach/reset.h> 38 #include <mach/hardware.h> 39 40 static unsigned long oscr_freq; 41 static unsigned long sa1100wdt_users; 42 static unsigned int pre_margin; 43 static int boot_status; 44 45 /* 46 * Allow only one person to hold it open 47 */ 48 static int sa1100dog_open(struct inode *inode, struct file *file) 49 { 50 if (test_and_set_bit(1, &sa1100wdt_users)) 51 return -EBUSY; 52 53 /* Activate SA1100 Watchdog timer */ 54 writel_relaxed(readl_relaxed(OSCR) + pre_margin, OSMR3); 55 writel_relaxed(OSSR_M3, OSSR); 56 writel_relaxed(OWER_WME, OWER); 57 writel_relaxed(readl_relaxed(OIER) | OIER_E3, OIER); 58 return stream_open(inode, file); 59 } 60 61 /* 62 * The watchdog cannot be disabled. 63 * 64 * Previous comments suggested that turning off the interrupt by 65 * clearing OIER[E3] would prevent the watchdog timing out but this 66 * does not appear to be true (at least on the PXA255). 67 */ 68 static int sa1100dog_release(struct inode *inode, struct file *file) 69 { 70 pr_crit("Device closed - timer will not stop\n"); 71 clear_bit(1, &sa1100wdt_users); 72 return 0; 73 } 74 75 static ssize_t sa1100dog_write(struct file *file, const char __user *data, 76 size_t len, loff_t *ppos) 77 { 78 if (len) 79 /* Refresh OSMR3 timer. */ 80 writel_relaxed(readl_relaxed(OSCR) + pre_margin, OSMR3); 81 return len; 82 } 83 84 static const struct watchdog_info ident = { 85 .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT 86 | WDIOF_KEEPALIVEPING, 87 .identity = "SA1100/PXA255 Watchdog", 88 .firmware_version = 1, 89 }; 90 91 static long sa1100dog_ioctl(struct file *file, unsigned int cmd, 92 unsigned long arg) 93 { 94 int ret = -ENOTTY; 95 int time; 96 void __user *argp = (void __user *)arg; 97 int __user *p = argp; 98 99 switch (cmd) { 100 case WDIOC_GETSUPPORT: 101 ret = copy_to_user(argp, &ident, 102 sizeof(ident)) ? -EFAULT : 0; 103 break; 104 105 case WDIOC_GETSTATUS: 106 ret = put_user(0, p); 107 break; 108 109 case WDIOC_GETBOOTSTATUS: 110 ret = put_user(boot_status, p); 111 break; 112 113 case WDIOC_KEEPALIVE: 114 writel_relaxed(readl_relaxed(OSCR) + pre_margin, OSMR3); 115 ret = 0; 116 break; 117 118 case WDIOC_SETTIMEOUT: 119 ret = get_user(time, p); 120 if (ret) 121 break; 122 123 if (time <= 0 || (oscr_freq * (long long)time >= 0xffffffff)) { 124 ret = -EINVAL; 125 break; 126 } 127 128 pre_margin = oscr_freq * time; 129 writel_relaxed(readl_relaxed(OSCR) + pre_margin, OSMR3); 130 /*fall through*/ 131 132 case WDIOC_GETTIMEOUT: 133 ret = put_user(pre_margin / oscr_freq, p); 134 break; 135 } 136 return ret; 137 } 138 139 static const struct file_operations sa1100dog_fops = { 140 .owner = THIS_MODULE, 141 .llseek = no_llseek, 142 .write = sa1100dog_write, 143 .unlocked_ioctl = sa1100dog_ioctl, 144 .open = sa1100dog_open, 145 .release = sa1100dog_release, 146 }; 147 148 static struct miscdevice sa1100dog_miscdev = { 149 .minor = WATCHDOG_MINOR, 150 .name = "watchdog", 151 .fops = &sa1100dog_fops, 152 }; 153 154 static int margin __initdata = 60; /* (secs) Default is 1 minute */ 155 static struct clk *clk; 156 157 static int __init sa1100dog_init(void) 158 { 159 int ret; 160 161 clk = clk_get(NULL, "OSTIMER0"); 162 if (IS_ERR(clk)) { 163 pr_err("SA1100/PXA2xx Watchdog Timer: clock not found: %d\n", 164 (int) PTR_ERR(clk)); 165 return PTR_ERR(clk); 166 } 167 168 ret = clk_prepare_enable(clk); 169 if (ret) { 170 pr_err("SA1100/PXA2xx Watchdog Timer: clock failed to prepare+enable: %d\n", 171 ret); 172 goto err; 173 } 174 175 oscr_freq = clk_get_rate(clk); 176 177 /* 178 * Read the reset status, and save it for later. If 179 * we suspend, RCSR will be cleared, and the watchdog 180 * reset reason will be lost. 181 */ 182 boot_status = (reset_status & RESET_STATUS_WATCHDOG) ? 183 WDIOF_CARDRESET : 0; 184 pre_margin = oscr_freq * margin; 185 186 ret = misc_register(&sa1100dog_miscdev); 187 if (ret == 0) { 188 pr_info("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n", 189 margin); 190 return 0; 191 } 192 193 clk_disable_unprepare(clk); 194 err: 195 clk_put(clk); 196 return ret; 197 } 198 199 static void __exit sa1100dog_exit(void) 200 { 201 misc_deregister(&sa1100dog_miscdev); 202 clk_disable_unprepare(clk); 203 clk_put(clk); 204 } 205 206 module_init(sa1100dog_init); 207 module_exit(sa1100dog_exit); 208 209 MODULE_AUTHOR("Oleg Drokin <green@crimea.edu>"); 210 MODULE_DESCRIPTION("SA1100/PXA2xx Watchdog"); 211 212 module_param(margin, int, 0); 213 MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)"); 214 215 MODULE_LICENSE("GPL"); 216