0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0017
0018 #include <linux/bitops.h>
0019 #include <linux/delay.h>
0020 #include <linux/errno.h>
0021 #include <linux/fs.h>
0022 #include <linux/io.h>
0023 #include <linux/kernel.h>
0024 #include <linux/miscdevice.h>
0025 #include <linux/module.h>
0026 #include <linux/moduleparam.h>
0027 #include <linux/platform_device.h>
0028 #include <linux/types.h>
0029 #include <linux/watchdog.h>
0030 #include <linux/clk.h>
0031 #include <linux/err.h>
0032 #include <linux/of.h>
0033 #include <linux/of_platform.h>
0034 #include <linux/uaccess.h>
0035
0036 #define DRIVER_NAME "ath79-wdt"
0037
0038 #define WDT_TIMEOUT 15
0039
0040 #define WDOG_REG_CTRL 0x00
0041 #define WDOG_REG_TIMER 0x04
0042
0043 #define WDOG_CTRL_LAST_RESET BIT(31)
0044 #define WDOG_CTRL_ACTION_MASK 3
0045 #define WDOG_CTRL_ACTION_NONE 0
0046 #define WDOG_CTRL_ACTION_GPI 1
0047 #define WDOG_CTRL_ACTION_NMI 2
0048 #define WDOG_CTRL_ACTION_FCR 3
0049
0050 static bool nowayout = WATCHDOG_NOWAYOUT;
0051 module_param(nowayout, bool, 0);
0052 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
0053 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0054
0055 static int timeout = WDT_TIMEOUT;
0056 module_param(timeout, int, 0);
0057 MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds "
0058 "(default=" __MODULE_STRING(WDT_TIMEOUT) "s)");
0059
0060 static unsigned long wdt_flags;
0061
0062 #define WDT_FLAGS_BUSY 0
0063 #define WDT_FLAGS_EXPECT_CLOSE 1
0064
0065 static struct clk *wdt_clk;
0066 static unsigned long wdt_freq;
0067 static int boot_status;
0068 static int max_timeout;
0069 static void __iomem *wdt_base;
0070
0071 static inline void ath79_wdt_wr(unsigned reg, u32 val)
0072 {
0073 iowrite32(val, wdt_base + reg);
0074 }
0075
0076 static inline u32 ath79_wdt_rr(unsigned reg)
0077 {
0078 return ioread32(wdt_base + reg);
0079 }
0080
0081 static inline void ath79_wdt_keepalive(void)
0082 {
0083 ath79_wdt_wr(WDOG_REG_TIMER, wdt_freq * timeout);
0084
0085 ath79_wdt_rr(WDOG_REG_TIMER);
0086 }
0087
0088 static inline void ath79_wdt_enable(void)
0089 {
0090 ath79_wdt_keepalive();
0091
0092
0093
0094
0095
0096
0097
0098 udelay(2);
0099
0100 ath79_wdt_wr(WDOG_REG_CTRL, WDOG_CTRL_ACTION_FCR);
0101
0102 ath79_wdt_rr(WDOG_REG_CTRL);
0103 }
0104
0105 static inline void ath79_wdt_disable(void)
0106 {
0107 ath79_wdt_wr(WDOG_REG_CTRL, WDOG_CTRL_ACTION_NONE);
0108
0109 ath79_wdt_rr(WDOG_REG_CTRL);
0110 }
0111
0112 static int ath79_wdt_set_timeout(int val)
0113 {
0114 if (val < 1 || val > max_timeout)
0115 return -EINVAL;
0116
0117 timeout = val;
0118 ath79_wdt_keepalive();
0119
0120 return 0;
0121 }
0122
0123 static int ath79_wdt_open(struct inode *inode, struct file *file)
0124 {
0125 if (test_and_set_bit(WDT_FLAGS_BUSY, &wdt_flags))
0126 return -EBUSY;
0127
0128 clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
0129 ath79_wdt_enable();
0130
0131 return stream_open(inode, file);
0132 }
0133
0134 static int ath79_wdt_release(struct inode *inode, struct file *file)
0135 {
0136 if (test_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags))
0137 ath79_wdt_disable();
0138 else {
0139 pr_crit("device closed unexpectedly, watchdog timer will not stop!\n");
0140 ath79_wdt_keepalive();
0141 }
0142
0143 clear_bit(WDT_FLAGS_BUSY, &wdt_flags);
0144 clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
0145
0146 return 0;
0147 }
0148
0149 static ssize_t ath79_wdt_write(struct file *file, const char *data,
0150 size_t len, loff_t *ppos)
0151 {
0152 if (len) {
0153 if (!nowayout) {
0154 size_t i;
0155
0156 clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
0157
0158 for (i = 0; i != len; i++) {
0159 char c;
0160
0161 if (get_user(c, data + i))
0162 return -EFAULT;
0163
0164 if (c == 'V')
0165 set_bit(WDT_FLAGS_EXPECT_CLOSE,
0166 &wdt_flags);
0167 }
0168 }
0169
0170 ath79_wdt_keepalive();
0171 }
0172
0173 return len;
0174 }
0175
0176 static const struct watchdog_info ath79_wdt_info = {
0177 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
0178 WDIOF_MAGICCLOSE | WDIOF_CARDRESET,
0179 .firmware_version = 0,
0180 .identity = "ATH79 watchdog",
0181 };
0182
0183 static long ath79_wdt_ioctl(struct file *file, unsigned int cmd,
0184 unsigned long arg)
0185 {
0186 void __user *argp = (void __user *)arg;
0187 int __user *p = argp;
0188 int err;
0189 int t;
0190
0191 switch (cmd) {
0192 case WDIOC_GETSUPPORT:
0193 err = copy_to_user(argp, &ath79_wdt_info,
0194 sizeof(ath79_wdt_info)) ? -EFAULT : 0;
0195 break;
0196
0197 case WDIOC_GETSTATUS:
0198 err = put_user(0, p);
0199 break;
0200
0201 case WDIOC_GETBOOTSTATUS:
0202 err = put_user(boot_status, p);
0203 break;
0204
0205 case WDIOC_KEEPALIVE:
0206 ath79_wdt_keepalive();
0207 err = 0;
0208 break;
0209
0210 case WDIOC_SETTIMEOUT:
0211 err = get_user(t, p);
0212 if (err)
0213 break;
0214
0215 err = ath79_wdt_set_timeout(t);
0216 if (err)
0217 break;
0218 fallthrough;
0219
0220 case WDIOC_GETTIMEOUT:
0221 err = put_user(timeout, p);
0222 break;
0223
0224 default:
0225 err = -ENOTTY;
0226 break;
0227 }
0228
0229 return err;
0230 }
0231
0232 static const struct file_operations ath79_wdt_fops = {
0233 .owner = THIS_MODULE,
0234 .llseek = no_llseek,
0235 .write = ath79_wdt_write,
0236 .unlocked_ioctl = ath79_wdt_ioctl,
0237 .compat_ioctl = compat_ptr_ioctl,
0238 .open = ath79_wdt_open,
0239 .release = ath79_wdt_release,
0240 };
0241
0242 static struct miscdevice ath79_wdt_miscdev = {
0243 .minor = WATCHDOG_MINOR,
0244 .name = "watchdog",
0245 .fops = &ath79_wdt_fops,
0246 };
0247
0248 static int ath79_wdt_probe(struct platform_device *pdev)
0249 {
0250 u32 ctrl;
0251 int err;
0252
0253 if (wdt_base)
0254 return -EBUSY;
0255
0256 wdt_base = devm_platform_ioremap_resource(pdev, 0);
0257 if (IS_ERR(wdt_base))
0258 return PTR_ERR(wdt_base);
0259
0260 wdt_clk = devm_clk_get(&pdev->dev, "wdt");
0261 if (IS_ERR(wdt_clk))
0262 return PTR_ERR(wdt_clk);
0263
0264 err = clk_prepare_enable(wdt_clk);
0265 if (err)
0266 return err;
0267
0268 wdt_freq = clk_get_rate(wdt_clk);
0269 if (!wdt_freq) {
0270 err = -EINVAL;
0271 goto err_clk_disable;
0272 }
0273
0274 max_timeout = (0xfffffffful / wdt_freq);
0275 if (timeout < 1 || timeout > max_timeout) {
0276 timeout = max_timeout;
0277 dev_info(&pdev->dev,
0278 "timeout value must be 0 < timeout < %d, using %d\n",
0279 max_timeout, timeout);
0280 }
0281
0282 ctrl = ath79_wdt_rr(WDOG_REG_CTRL);
0283 boot_status = (ctrl & WDOG_CTRL_LAST_RESET) ? WDIOF_CARDRESET : 0;
0284
0285 err = misc_register(&ath79_wdt_miscdev);
0286 if (err) {
0287 dev_err(&pdev->dev,
0288 "unable to register misc device, err=%d\n", err);
0289 goto err_clk_disable;
0290 }
0291
0292 return 0;
0293
0294 err_clk_disable:
0295 clk_disable_unprepare(wdt_clk);
0296 return err;
0297 }
0298
0299 static int ath79_wdt_remove(struct platform_device *pdev)
0300 {
0301 misc_deregister(&ath79_wdt_miscdev);
0302 clk_disable_unprepare(wdt_clk);
0303 return 0;
0304 }
0305
0306 static void ath79_wdt_shutdown(struct platform_device *pdev)
0307 {
0308 ath79_wdt_disable();
0309 }
0310
0311 #ifdef CONFIG_OF
0312 static const struct of_device_id ath79_wdt_match[] = {
0313 { .compatible = "qca,ar7130-wdt" },
0314 {},
0315 };
0316 MODULE_DEVICE_TABLE(of, ath79_wdt_match);
0317 #endif
0318
0319 static struct platform_driver ath79_wdt_driver = {
0320 .probe = ath79_wdt_probe,
0321 .remove = ath79_wdt_remove,
0322 .shutdown = ath79_wdt_shutdown,
0323 .driver = {
0324 .name = DRIVER_NAME,
0325 .of_match_table = of_match_ptr(ath79_wdt_match),
0326 },
0327 };
0328
0329 module_platform_driver(ath79_wdt_driver);
0330
0331 MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X hardware watchdog driver");
0332 MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org");
0333 MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org");
0334 MODULE_LICENSE("GPL v2");
0335 MODULE_ALIAS("platform:" DRIVER_NAME);