Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Atheros AR71XX/AR724X/AR913X built-in hardware watchdog timer.
0004  *
0005  * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
0006  * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
0007  *
0008  * This driver was based on: drivers/watchdog/ixp4xx_wdt.c
0009  *  Author: Deepak Saxena <dsaxena@plexity.net>
0010  *  Copyright 2004 (c) MontaVista, Software, Inc.
0011  *
0012  * which again was based on sa1100 driver,
0013  *  Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
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  /* seconds */
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   /* no action */
0046 #define WDOG_CTRL_ACTION_GPI    1   /* general purpose interrupt */
0047 #define WDOG_CTRL_ACTION_NMI    2   /* NMI */
0048 #define WDOG_CTRL_ACTION_FCR    3   /* full chip reset */
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     /* flush write */
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      * Updating the TIMER register requires a few microseconds
0094      * on the AR934x SoCs at least. Use a small delay to ensure
0095      * that the TIMER register is updated within the hardware
0096      * before enabling the watchdog.
0097      */
0098     udelay(2);
0099 
0100     ath79_wdt_wr(WDOG_REG_CTRL, WDOG_CTRL_ACTION_FCR);
0101     /* flush write */
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     /* flush write */
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);