Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * MOXA ART SoCs watchdog driver.
0003  *
0004  * Copyright (C) 2013 Jonas Jensen
0005  *
0006  * Jonas Jensen <jonas.jensen@gmail.com>
0007  *
0008  * This file is licensed under the terms of the GNU General Public
0009  * License version 2.  This program is licensed "as is" without any
0010  * warranty of any kind, whether express or implied.
0011  */
0012 
0013 #include <linux/clk.h>
0014 #include <linux/io.h>
0015 #include <linux/module.h>
0016 #include <linux/mod_devicetable.h>
0017 #include <linux/err.h>
0018 #include <linux/kernel.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/watchdog.h>
0021 #include <linux/moduleparam.h>
0022 
0023 #define REG_COUNT           0x4
0024 #define REG_MODE            0x8
0025 #define REG_ENABLE          0xC
0026 
0027 struct moxart_wdt_dev {
0028     struct watchdog_device dev;
0029     void __iomem *base;
0030     unsigned int clock_frequency;
0031 };
0032 
0033 static int heartbeat;
0034 
0035 static int moxart_wdt_restart(struct watchdog_device *wdt_dev,
0036                   unsigned long action, void *data)
0037 {
0038     struct moxart_wdt_dev *moxart_wdt = watchdog_get_drvdata(wdt_dev);
0039 
0040     writel(1, moxart_wdt->base + REG_COUNT);
0041     writel(0x5ab9, moxart_wdt->base + REG_MODE);
0042     writel(0x03, moxart_wdt->base + REG_ENABLE);
0043 
0044     return 0;
0045 }
0046 
0047 static int moxart_wdt_stop(struct watchdog_device *wdt_dev)
0048 {
0049     struct moxart_wdt_dev *moxart_wdt = watchdog_get_drvdata(wdt_dev);
0050 
0051     writel(0, moxart_wdt->base + REG_ENABLE);
0052 
0053     return 0;
0054 }
0055 
0056 static int moxart_wdt_start(struct watchdog_device *wdt_dev)
0057 {
0058     struct moxart_wdt_dev *moxart_wdt = watchdog_get_drvdata(wdt_dev);
0059 
0060     writel(moxart_wdt->clock_frequency * wdt_dev->timeout,
0061            moxart_wdt->base + REG_COUNT);
0062     writel(0x5ab9, moxart_wdt->base + REG_MODE);
0063     writel(0x03, moxart_wdt->base + REG_ENABLE);
0064 
0065     return 0;
0066 }
0067 
0068 static int moxart_wdt_set_timeout(struct watchdog_device *wdt_dev,
0069                   unsigned int timeout)
0070 {
0071     wdt_dev->timeout = timeout;
0072 
0073     return 0;
0074 }
0075 
0076 static const struct watchdog_info moxart_wdt_info = {
0077     .identity       = "moxart-wdt",
0078     .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
0079               WDIOF_MAGICCLOSE,
0080 };
0081 
0082 static const struct watchdog_ops moxart_wdt_ops = {
0083     .owner          = THIS_MODULE,
0084     .start          = moxart_wdt_start,
0085     .stop           = moxart_wdt_stop,
0086     .set_timeout    = moxart_wdt_set_timeout,
0087     .restart        = moxart_wdt_restart,
0088 };
0089 
0090 static int moxart_wdt_probe(struct platform_device *pdev)
0091 {
0092     struct moxart_wdt_dev *moxart_wdt;
0093     struct device *dev = &pdev->dev;
0094     struct clk *clk;
0095     int err;
0096     unsigned int max_timeout;
0097     bool nowayout = WATCHDOG_NOWAYOUT;
0098 
0099     moxart_wdt = devm_kzalloc(dev, sizeof(*moxart_wdt), GFP_KERNEL);
0100     if (!moxart_wdt)
0101         return -ENOMEM;
0102 
0103     platform_set_drvdata(pdev, moxart_wdt);
0104 
0105     moxart_wdt->base = devm_platform_ioremap_resource(pdev, 0);
0106     if (IS_ERR(moxart_wdt->base))
0107         return PTR_ERR(moxart_wdt->base);
0108 
0109     clk = devm_clk_get(dev, NULL);
0110     if (IS_ERR(clk)) {
0111         pr_err("%s: of_clk_get failed\n", __func__);
0112         return PTR_ERR(clk);
0113     }
0114 
0115     moxart_wdt->clock_frequency = clk_get_rate(clk);
0116     if (moxart_wdt->clock_frequency == 0) {
0117         pr_err("%s: incorrect clock frequency\n", __func__);
0118         return -EINVAL;
0119     }
0120 
0121     max_timeout = UINT_MAX / moxart_wdt->clock_frequency;
0122 
0123     moxart_wdt->dev.info = &moxart_wdt_info;
0124     moxart_wdt->dev.ops = &moxart_wdt_ops;
0125     moxart_wdt->dev.timeout = max_timeout;
0126     moxart_wdt->dev.min_timeout = 1;
0127     moxart_wdt->dev.max_timeout = max_timeout;
0128     moxart_wdt->dev.parent = dev;
0129 
0130     watchdog_init_timeout(&moxart_wdt->dev, heartbeat, dev);
0131     watchdog_set_nowayout(&moxart_wdt->dev, nowayout);
0132     watchdog_set_restart_priority(&moxart_wdt->dev, 128);
0133 
0134     watchdog_set_drvdata(&moxart_wdt->dev, moxart_wdt);
0135 
0136     watchdog_stop_on_unregister(&moxart_wdt->dev);
0137     err = devm_watchdog_register_device(dev, &moxart_wdt->dev);
0138     if (err)
0139         return err;
0140 
0141     dev_dbg(dev, "Watchdog enabled (heartbeat=%d sec, nowayout=%d)\n",
0142         moxart_wdt->dev.timeout, nowayout);
0143 
0144     return 0;
0145 }
0146 
0147 static const struct of_device_id moxart_watchdog_match[] = {
0148     { .compatible = "moxa,moxart-watchdog" },
0149     { },
0150 };
0151 MODULE_DEVICE_TABLE(of, moxart_watchdog_match);
0152 
0153 static struct platform_driver moxart_wdt_driver = {
0154     .probe      = moxart_wdt_probe,
0155     .driver     = {
0156         .name       = "moxart-watchdog",
0157         .of_match_table = moxart_watchdog_match,
0158     },
0159 };
0160 module_platform_driver(moxart_wdt_driver);
0161 
0162 module_param(heartbeat, int, 0);
0163 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds");
0164 
0165 MODULE_DESCRIPTION("MOXART watchdog driver");
0166 MODULE_LICENSE("GPL");
0167 MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>");