0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0018
0019 #include <linux/module.h>
0020 #include <linux/moduleparam.h>
0021 #include <linux/clk.h>
0022 #include <linux/types.h>
0023 #include <linux/kernel.h>
0024 #include <linux/fs.h>
0025 #include <linux/platform_device.h>
0026 #include <linux/miscdevice.h>
0027 #include <linux/watchdog.h>
0028 #include <linux/init.h>
0029 #include <linux/io.h>
0030 #include <linux/bitops.h>
0031 #include <linux/uaccess.h>
0032 #include <linux/timex.h>
0033
0034 #define REG_OSMR0 0x0000
0035 #define REG_OSMR1 0x0004
0036 #define REG_OSMR2 0x0008
0037 #define REG_OSMR3 0x000c
0038 #define REG_OSCR 0x0010
0039 #define REG_OSSR 0x0014
0040 #define REG_OWER 0x0018
0041 #define REG_OIER 0x001C
0042
0043 #define OSSR_M3 (1 << 3)
0044 #define OSSR_M2 (1 << 2)
0045 #define OSSR_M1 (1 << 1)
0046 #define OSSR_M0 (1 << 0)
0047
0048 #define OWER_WME (1 << 0)
0049
0050 #define OIER_E3 (1 << 3)
0051 #define OIER_E2 (1 << 2)
0052 #define OIER_E1 (1 << 1)
0053 #define OIER_E0 (1 << 0)
0054
0055 static unsigned long oscr_freq;
0056 static unsigned long sa1100wdt_users;
0057 static unsigned int pre_margin;
0058 static int boot_status;
0059 static void __iomem *reg_base;
0060
0061 static inline void sa1100_wr(u32 val, u32 offset)
0062 {
0063 writel_relaxed(val, reg_base + offset);
0064 }
0065
0066 static inline u32 sa1100_rd(u32 offset)
0067 {
0068 return readl_relaxed(reg_base + offset);
0069 }
0070
0071
0072
0073
0074 static int sa1100dog_open(struct inode *inode, struct file *file)
0075 {
0076 if (test_and_set_bit(1, &sa1100wdt_users))
0077 return -EBUSY;
0078
0079
0080 sa1100_wr(sa1100_rd(REG_OSCR) + pre_margin, REG_OSMR3);
0081 sa1100_wr(OSSR_M3, REG_OSSR);
0082 sa1100_wr(OWER_WME, REG_OWER);
0083 sa1100_wr(sa1100_rd(REG_OIER) | OIER_E3, REG_OIER);
0084 return stream_open(inode, file);
0085 }
0086
0087
0088
0089
0090
0091
0092
0093
0094 static int sa1100dog_release(struct inode *inode, struct file *file)
0095 {
0096 pr_crit("Device closed - timer will not stop\n");
0097 clear_bit(1, &sa1100wdt_users);
0098 return 0;
0099 }
0100
0101 static ssize_t sa1100dog_write(struct file *file, const char __user *data,
0102 size_t len, loff_t *ppos)
0103 {
0104 if (len)
0105
0106 sa1100_wr(sa1100_rd(REG_OSCR) + pre_margin, REG_OSMR3);
0107 return len;
0108 }
0109
0110 static const struct watchdog_info ident = {
0111 .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT
0112 | WDIOF_KEEPALIVEPING,
0113 .identity = "SA1100/PXA255 Watchdog",
0114 .firmware_version = 1,
0115 };
0116
0117 static long sa1100dog_ioctl(struct file *file, unsigned int cmd,
0118 unsigned long arg)
0119 {
0120 int ret = -ENOTTY;
0121 int time;
0122 void __user *argp = (void __user *)arg;
0123 int __user *p = argp;
0124
0125 switch (cmd) {
0126 case WDIOC_GETSUPPORT:
0127 ret = copy_to_user(argp, &ident,
0128 sizeof(ident)) ? -EFAULT : 0;
0129 break;
0130
0131 case WDIOC_GETSTATUS:
0132 ret = put_user(0, p);
0133 break;
0134
0135 case WDIOC_GETBOOTSTATUS:
0136 ret = put_user(boot_status, p);
0137 break;
0138
0139 case WDIOC_KEEPALIVE:
0140 sa1100_wr(sa1100_rd(REG_OSCR) + pre_margin, REG_OSMR3);
0141 ret = 0;
0142 break;
0143
0144 case WDIOC_SETTIMEOUT:
0145 ret = get_user(time, p);
0146 if (ret)
0147 break;
0148
0149 if (time <= 0 || (oscr_freq * (long long)time >= 0xffffffff)) {
0150 ret = -EINVAL;
0151 break;
0152 }
0153
0154 pre_margin = oscr_freq * time;
0155 sa1100_wr(sa1100_rd(REG_OSCR) + pre_margin, REG_OSMR3);
0156 fallthrough;
0157
0158 case WDIOC_GETTIMEOUT:
0159 ret = put_user(pre_margin / oscr_freq, p);
0160 break;
0161 }
0162 return ret;
0163 }
0164
0165 static const struct file_operations sa1100dog_fops = {
0166 .owner = THIS_MODULE,
0167 .llseek = no_llseek,
0168 .write = sa1100dog_write,
0169 .unlocked_ioctl = sa1100dog_ioctl,
0170 .compat_ioctl = compat_ptr_ioctl,
0171 .open = sa1100dog_open,
0172 .release = sa1100dog_release,
0173 };
0174
0175 static struct miscdevice sa1100dog_miscdev = {
0176 .minor = WATCHDOG_MINOR,
0177 .name = "watchdog",
0178 .fops = &sa1100dog_fops,
0179 };
0180
0181 static int margin = 60;
0182 static struct clk *clk;
0183
0184 static int sa1100dog_probe(struct platform_device *pdev)
0185 {
0186 int ret;
0187 int *platform_data;
0188 struct resource *res;
0189
0190 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0191 if (!res)
0192 return -ENXIO;
0193 reg_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
0194 ret = PTR_ERR_OR_ZERO(reg_base);
0195 if (ret)
0196 return ret;
0197
0198 clk = clk_get(NULL, "OSTIMER0");
0199 if (IS_ERR(clk)) {
0200 pr_err("SA1100/PXA2xx Watchdog Timer: clock not found: %d\n",
0201 (int) PTR_ERR(clk));
0202 return PTR_ERR(clk);
0203 }
0204
0205 ret = clk_prepare_enable(clk);
0206 if (ret) {
0207 pr_err("SA1100/PXA2xx Watchdog Timer: clock failed to prepare+enable: %d\n",
0208 ret);
0209 goto err;
0210 }
0211
0212 oscr_freq = clk_get_rate(clk);
0213
0214 platform_data = pdev->dev.platform_data;
0215 if (platform_data && *platform_data)
0216 boot_status = WDIOF_CARDRESET;
0217 pre_margin = oscr_freq * margin;
0218
0219 ret = misc_register(&sa1100dog_miscdev);
0220 if (ret == 0) {
0221 pr_info("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n",
0222 margin);
0223 return 0;
0224 }
0225
0226 clk_disable_unprepare(clk);
0227 err:
0228 clk_put(clk);
0229 return ret;
0230 }
0231
0232 static int sa1100dog_remove(struct platform_device *pdev)
0233 {
0234 misc_deregister(&sa1100dog_miscdev);
0235 clk_disable_unprepare(clk);
0236 clk_put(clk);
0237
0238 return 0;
0239 }
0240
0241 struct platform_driver sa1100dog_driver = {
0242 .driver.name = "sa1100_wdt",
0243 .probe = sa1100dog_probe,
0244 .remove = sa1100dog_remove,
0245 };
0246 module_platform_driver(sa1100dog_driver);
0247
0248 MODULE_AUTHOR("Oleg Drokin <green@crimea.edu>");
0249 MODULE_DESCRIPTION("SA1100/PXA2xx Watchdog");
0250
0251 module_param(margin, int, 0);
0252 MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)");
0253
0254 MODULE_LICENSE("GPL");