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 fallthrough; 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 .compat_ioctl = compat_ptr_ioctl, 145 .open = sa1100dog_open, 146 .release = sa1100dog_release, 147 }; 148 149 static struct miscdevice sa1100dog_miscdev = { 150 .minor = WATCHDOG_MINOR, 151 .name = "watchdog", 152 .fops = &sa1100dog_fops, 153 }; 154 155 static int margin __initdata = 60; /* (secs) Default is 1 minute */ 156 static struct clk *clk; 157 158 static int __init sa1100dog_init(void) 159 { 160 int ret; 161 162 clk = clk_get(NULL, "OSTIMER0"); 163 if (IS_ERR(clk)) { 164 pr_err("SA1100/PXA2xx Watchdog Timer: clock not found: %d\n", 165 (int) PTR_ERR(clk)); 166 return PTR_ERR(clk); 167 } 168 169 ret = clk_prepare_enable(clk); 170 if (ret) { 171 pr_err("SA1100/PXA2xx Watchdog Timer: clock failed to prepare+enable: %d\n", 172 ret); 173 goto err; 174 } 175 176 oscr_freq = clk_get_rate(clk); 177 178 /* 179 * Read the reset status, and save it for later. If 180 * we suspend, RCSR will be cleared, and the watchdog 181 * reset reason will be lost. 182 */ 183 boot_status = (reset_status & RESET_STATUS_WATCHDOG) ? 184 WDIOF_CARDRESET : 0; 185 pre_margin = oscr_freq * margin; 186 187 ret = misc_register(&sa1100dog_miscdev); 188 if (ret == 0) { 189 pr_info("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n", 190 margin); 191 return 0; 192 } 193 194 clk_disable_unprepare(clk); 195 err: 196 clk_put(clk); 197 return ret; 198 } 199 200 static void __exit sa1100dog_exit(void) 201 { 202 misc_deregister(&sa1100dog_miscdev); 203 clk_disable_unprepare(clk); 204 clk_put(clk); 205 } 206 207 module_init(sa1100dog_init); 208 module_exit(sa1100dog_exit); 209 210 MODULE_AUTHOR("Oleg Drokin <green@crimea.edu>"); 211 MODULE_DESCRIPTION("SA1100/PXA2xx Watchdog"); 212 213 module_param(margin, int, 0); 214 MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)"); 215 216 MODULE_LICENSE("GPL"); 217