0001
0002
0003
0004
0005
0006 #include <linux/kernel.h>
0007 #include <linux/module.h>
0008 #include <linux/interrupt.h>
0009 #include <linux/io.h>
0010 #include <linux/of.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/watchdog.h>
0013
0014
0015 #define MIN_WDT_TIMEOUT 1
0016 #define MAX_WDT_TIMEOUT 255
0017
0018
0019
0020
0021
0022
0023
0024 #define WDT_BASE 0x100
0025 #define WDT_ID 0
0026
0027
0028
0029
0030
0031
0032
0033
0034 #define WDT_TIMER_BASE 0x60
0035 #define WDT_TIMER_ID 5
0036
0037
0038 #define WDT_CFG 0x0
0039 #define WDT_CFG_PERIOD_SHIFT 4
0040 #define WDT_CFG_PERIOD_MASK 0xff
0041 #define WDT_CFG_INT_EN (1 << 12)
0042 #define WDT_CFG_PMC2CAR_RST_EN (1 << 15)
0043 #define WDT_STS 0x4
0044 #define WDT_STS_COUNT_SHIFT 4
0045 #define WDT_STS_COUNT_MASK 0xff
0046 #define WDT_STS_EXP_SHIFT 12
0047 #define WDT_STS_EXP_MASK 0x3
0048 #define WDT_CMD 0x8
0049 #define WDT_CMD_START_COUNTER (1 << 0)
0050 #define WDT_CMD_DISABLE_COUNTER (1 << 1)
0051 #define WDT_UNLOCK (0xc)
0052 #define WDT_UNLOCK_PATTERN (0xc45a << 0)
0053
0054
0055 #define TIMER_PTV 0x0
0056 #define TIMER_EN (1 << 31)
0057 #define TIMER_PERIODIC (1 << 30)
0058
0059 struct tegra_wdt {
0060 struct watchdog_device wdd;
0061 void __iomem *wdt_regs;
0062 void __iomem *tmr_regs;
0063 };
0064
0065 #define WDT_HEARTBEAT 120
0066 static int heartbeat = WDT_HEARTBEAT;
0067 module_param(heartbeat, int, 0);
0068 MODULE_PARM_DESC(heartbeat,
0069 "Watchdog heartbeats in seconds. (default = "
0070 __MODULE_STRING(WDT_HEARTBEAT) ")");
0071
0072 static bool nowayout = WATCHDOG_NOWAYOUT;
0073 module_param(nowayout, bool, 0);
0074 MODULE_PARM_DESC(nowayout,
0075 "Watchdog cannot be stopped once started (default="
0076 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0077
0078 static int tegra_wdt_start(struct watchdog_device *wdd)
0079 {
0080 struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
0081 u32 val;
0082
0083
0084
0085
0086
0087
0088
0089 val = 1000000ul / 4;
0090 val |= (TIMER_EN | TIMER_PERIODIC);
0091 writel(val, wdt->tmr_regs + TIMER_PTV);
0092
0093
0094
0095
0096
0097
0098
0099
0100 val = WDT_TIMER_ID |
0101 (wdd->timeout << WDT_CFG_PERIOD_SHIFT) |
0102 WDT_CFG_PMC2CAR_RST_EN;
0103 writel(val, wdt->wdt_regs + WDT_CFG);
0104
0105 writel(WDT_CMD_START_COUNTER, wdt->wdt_regs + WDT_CMD);
0106
0107 return 0;
0108 }
0109
0110 static int tegra_wdt_stop(struct watchdog_device *wdd)
0111 {
0112 struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
0113
0114 writel(WDT_UNLOCK_PATTERN, wdt->wdt_regs + WDT_UNLOCK);
0115 writel(WDT_CMD_DISABLE_COUNTER, wdt->wdt_regs + WDT_CMD);
0116 writel(0, wdt->tmr_regs + TIMER_PTV);
0117
0118 return 0;
0119 }
0120
0121 static int tegra_wdt_ping(struct watchdog_device *wdd)
0122 {
0123 struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
0124
0125 writel(WDT_CMD_START_COUNTER, wdt->wdt_regs + WDT_CMD);
0126
0127 return 0;
0128 }
0129
0130 static int tegra_wdt_set_timeout(struct watchdog_device *wdd,
0131 unsigned int timeout)
0132 {
0133 wdd->timeout = timeout;
0134
0135 if (watchdog_active(wdd)) {
0136 tegra_wdt_stop(wdd);
0137 return tegra_wdt_start(wdd);
0138 }
0139
0140 return 0;
0141 }
0142
0143 static unsigned int tegra_wdt_get_timeleft(struct watchdog_device *wdd)
0144 {
0145 struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
0146 u32 val;
0147 int count;
0148 int exp;
0149
0150 val = readl(wdt->wdt_regs + WDT_STS);
0151
0152
0153 count = (val >> WDT_STS_COUNT_SHIFT) & WDT_STS_COUNT_MASK;
0154
0155
0156 exp = (val >> WDT_STS_EXP_SHIFT) & WDT_STS_EXP_MASK;
0157
0158
0159
0160
0161
0162 return (((3 - exp) * wdd->timeout) + count) / 4;
0163 }
0164
0165 static const struct watchdog_info tegra_wdt_info = {
0166 .options = WDIOF_SETTIMEOUT |
0167 WDIOF_MAGICCLOSE |
0168 WDIOF_KEEPALIVEPING,
0169 .firmware_version = 0,
0170 .identity = "Tegra Watchdog",
0171 };
0172
0173 static const struct watchdog_ops tegra_wdt_ops = {
0174 .owner = THIS_MODULE,
0175 .start = tegra_wdt_start,
0176 .stop = tegra_wdt_stop,
0177 .ping = tegra_wdt_ping,
0178 .set_timeout = tegra_wdt_set_timeout,
0179 .get_timeleft = tegra_wdt_get_timeleft,
0180 };
0181
0182 static int tegra_wdt_probe(struct platform_device *pdev)
0183 {
0184 struct device *dev = &pdev->dev;
0185 struct watchdog_device *wdd;
0186 struct tegra_wdt *wdt;
0187 void __iomem *regs;
0188 int ret;
0189
0190
0191 regs = devm_platform_ioremap_resource(pdev, 0);
0192 if (IS_ERR(regs))
0193 return PTR_ERR(regs);
0194
0195
0196
0197
0198
0199 wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
0200 if (!wdt)
0201 return -ENOMEM;
0202
0203
0204 wdt->wdt_regs = regs + WDT_BASE;
0205 wdt->tmr_regs = regs + WDT_TIMER_BASE;
0206
0207
0208 wdd = &wdt->wdd;
0209 wdd->timeout = heartbeat;
0210 wdd->info = &tegra_wdt_info;
0211 wdd->ops = &tegra_wdt_ops;
0212 wdd->min_timeout = MIN_WDT_TIMEOUT;
0213 wdd->max_timeout = MAX_WDT_TIMEOUT;
0214 wdd->parent = dev;
0215
0216 watchdog_set_drvdata(wdd, wdt);
0217
0218 watchdog_set_nowayout(wdd, nowayout);
0219
0220 watchdog_stop_on_unregister(wdd);
0221 ret = devm_watchdog_register_device(dev, wdd);
0222 if (ret)
0223 return ret;
0224
0225 platform_set_drvdata(pdev, wdt);
0226
0227 dev_info(dev, "initialized (heartbeat = %d sec, nowayout = %d)\n",
0228 heartbeat, nowayout);
0229
0230 return 0;
0231 }
0232
0233 static int tegra_wdt_suspend(struct device *dev)
0234 {
0235 struct tegra_wdt *wdt = dev_get_drvdata(dev);
0236
0237 if (watchdog_active(&wdt->wdd))
0238 tegra_wdt_stop(&wdt->wdd);
0239
0240 return 0;
0241 }
0242
0243 static int tegra_wdt_resume(struct device *dev)
0244 {
0245 struct tegra_wdt *wdt = dev_get_drvdata(dev);
0246
0247 if (watchdog_active(&wdt->wdd))
0248 tegra_wdt_start(&wdt->wdd);
0249
0250 return 0;
0251 }
0252
0253 static const struct of_device_id tegra_wdt_of_match[] = {
0254 { .compatible = "nvidia,tegra30-timer", },
0255 { },
0256 };
0257 MODULE_DEVICE_TABLE(of, tegra_wdt_of_match);
0258
0259 static DEFINE_SIMPLE_DEV_PM_OPS(tegra_wdt_pm_ops,
0260 tegra_wdt_suspend, tegra_wdt_resume);
0261
0262 static struct platform_driver tegra_wdt_driver = {
0263 .probe = tegra_wdt_probe,
0264 .driver = {
0265 .name = "tegra-wdt",
0266 .pm = pm_sleep_ptr(&tegra_wdt_pm_ops),
0267 .of_match_table = tegra_wdt_of_match,
0268 },
0269 };
0270 module_platform_driver(tegra_wdt_driver);
0271
0272 MODULE_AUTHOR("NVIDIA Corporation");
0273 MODULE_DESCRIPTION("Tegra Watchdog Driver");
0274 MODULE_LICENSE("GPL v2");