0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/clk.h>
0011 #include <linux/io.h>
0012 #include <linux/mod_devicetable.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/watchdog.h>
0016
0017 #define REG_WDT_CLR 0x0
0018 #define REG_WDT_MAX_PRD_L 0x10
0019 #define REG_WDT_MAX_PRD_H 0x14
0020
0021 #define MSC313E_WDT_MIN_TIMEOUT 1
0022 #define MSC313E_WDT_DEFAULT_TIMEOUT 30
0023
0024 static unsigned int timeout;
0025
0026 module_param(timeout, int, 0);
0027 MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
0028
0029 struct msc313e_wdt_priv {
0030 void __iomem *base;
0031 struct watchdog_device wdev;
0032 struct clk *clk;
0033 };
0034
0035 static int msc313e_wdt_start(struct watchdog_device *wdev)
0036 {
0037 struct msc313e_wdt_priv *priv = watchdog_get_drvdata(wdev);
0038 u32 timeout;
0039 int err;
0040
0041 err = clk_prepare_enable(priv->clk);
0042 if (err)
0043 return err;
0044
0045 timeout = wdev->timeout * clk_get_rate(priv->clk);
0046 writew(timeout & 0xffff, priv->base + REG_WDT_MAX_PRD_L);
0047 writew((timeout >> 16) & 0xffff, priv->base + REG_WDT_MAX_PRD_H);
0048 writew(1, priv->base + REG_WDT_CLR);
0049 return 0;
0050 }
0051
0052 static int msc313e_wdt_ping(struct watchdog_device *wdev)
0053 {
0054 struct msc313e_wdt_priv *priv = watchdog_get_drvdata(wdev);
0055
0056 writew(1, priv->base + REG_WDT_CLR);
0057 return 0;
0058 }
0059
0060 static int msc313e_wdt_stop(struct watchdog_device *wdev)
0061 {
0062 struct msc313e_wdt_priv *priv = watchdog_get_drvdata(wdev);
0063
0064 writew(0, priv->base + REG_WDT_MAX_PRD_L);
0065 writew(0, priv->base + REG_WDT_MAX_PRD_H);
0066 writew(0, priv->base + REG_WDT_CLR);
0067 clk_disable_unprepare(priv->clk);
0068 return 0;
0069 }
0070
0071 static int msc313e_wdt_settimeout(struct watchdog_device *wdev, unsigned int new_time)
0072 {
0073 wdev->timeout = new_time;
0074
0075 return msc313e_wdt_start(wdev);
0076 }
0077
0078 static const struct watchdog_info msc313e_wdt_ident = {
0079 .identity = "MSC313e watchdog",
0080 .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
0081 };
0082
0083 static const struct watchdog_ops msc313e_wdt_ops = {
0084 .owner = THIS_MODULE,
0085 .start = msc313e_wdt_start,
0086 .stop = msc313e_wdt_stop,
0087 .ping = msc313e_wdt_ping,
0088 .set_timeout = msc313e_wdt_settimeout,
0089 };
0090
0091 static const struct of_device_id msc313e_wdt_of_match[] = {
0092 { .compatible = "mstar,msc313e-wdt", },
0093 { }
0094 };
0095 MODULE_DEVICE_TABLE(of, msc313e_wdt_of_match);
0096
0097 static int msc313e_wdt_probe(struct platform_device *pdev)
0098 {
0099 struct device *dev = &pdev->dev;
0100 struct msc313e_wdt_priv *priv;
0101
0102 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0103 if (!priv)
0104 return -ENOMEM;
0105
0106 priv->base = devm_platform_ioremap_resource(pdev, 0);
0107 if (IS_ERR(priv->base))
0108 return PTR_ERR(priv->base);
0109
0110 priv->clk = devm_clk_get(dev, NULL);
0111 if (IS_ERR(priv->clk)) {
0112 dev_err(dev, "No input clock\n");
0113 return PTR_ERR(priv->clk);
0114 }
0115
0116 priv->wdev.info = &msc313e_wdt_ident,
0117 priv->wdev.ops = &msc313e_wdt_ops,
0118 priv->wdev.parent = dev;
0119 priv->wdev.min_timeout = MSC313E_WDT_MIN_TIMEOUT;
0120 priv->wdev.max_timeout = U32_MAX / clk_get_rate(priv->clk);
0121 priv->wdev.timeout = MSC313E_WDT_DEFAULT_TIMEOUT;
0122
0123
0124 if (readw(priv->base + REG_WDT_MAX_PRD_L) | (readw(priv->base + REG_WDT_MAX_PRD_H) << 16))
0125 set_bit(WDOG_HW_RUNNING, &priv->wdev.status);
0126
0127 watchdog_set_drvdata(&priv->wdev, priv);
0128
0129 watchdog_init_timeout(&priv->wdev, timeout, dev);
0130 watchdog_stop_on_reboot(&priv->wdev);
0131 watchdog_stop_on_unregister(&priv->wdev);
0132
0133 return devm_watchdog_register_device(dev, &priv->wdev);
0134 }
0135
0136 static int __maybe_unused msc313e_wdt_suspend(struct device *dev)
0137 {
0138 struct msc313e_wdt_priv *priv = dev_get_drvdata(dev);
0139
0140 if (watchdog_active(&priv->wdev))
0141 msc313e_wdt_stop(&priv->wdev);
0142
0143 return 0;
0144 }
0145
0146 static int __maybe_unused msc313e_wdt_resume(struct device *dev)
0147 {
0148 struct msc313e_wdt_priv *priv = dev_get_drvdata(dev);
0149
0150 if (watchdog_active(&priv->wdev))
0151 msc313e_wdt_start(&priv->wdev);
0152
0153 return 0;
0154 }
0155
0156 static SIMPLE_DEV_PM_OPS(msc313e_wdt_pm_ops, msc313e_wdt_suspend, msc313e_wdt_resume);
0157
0158 static struct platform_driver msc313e_wdt_driver = {
0159 .driver = {
0160 .name = "msc313e-wdt",
0161 .of_match_table = msc313e_wdt_of_match,
0162 .pm = &msc313e_wdt_pm_ops,
0163 },
0164 .probe = msc313e_wdt_probe,
0165 };
0166 module_platform_driver(msc313e_wdt_driver);
0167
0168 MODULE_AUTHOR("Daniel Palmer <daniel@thingy.jp>");
0169 MODULE_DESCRIPTION("Watchdog driver for MStar MSC313e");
0170 MODULE_LICENSE("GPL v2");