Blame view
drivers/watchdog/atlas7_wdt.c
5.38 KB
f50a7f3d9 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
b466ee895 watchdog: atlas7:... |
2 3 4 5 |
/* * Watchdog driver for CSR Atlas7 * * Copyright (c) 2015 Cambridge Silicon Radio Limited, a CSR plc group company. |
b466ee895 watchdog: atlas7:... |
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
*/ #include <linux/clk.h> #include <linux/io.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/watchdog.h> #define ATLAS7_TIMER_WDT_INDEX 5 #define ATLAS7_WDT_DEFAULT_TIMEOUT 20 #define ATLAS7_WDT_CNT_CTRL (0 + 4 * ATLAS7_TIMER_WDT_INDEX) #define ATLAS7_WDT_CNT_MATCH (0x18 + 4 * ATLAS7_TIMER_WDT_INDEX) #define ATLAS7_WDT_CNT (0x48 + 4 * ATLAS7_TIMER_WDT_INDEX) #define ATLAS7_WDT_CNT_EN (BIT(0) | BIT(1)) #define ATLAS7_WDT_EN 0x64 static unsigned int timeout = ATLAS7_WDT_DEFAULT_TIMEOUT; static bool nowayout = WATCHDOG_NOWAYOUT; module_param(timeout, uint, 0); module_param(nowayout, bool, 0); MODULE_PARM_DESC(timeout, "Default watchdog timeout (in seconds)"); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); struct atlas7_wdog { struct device *dev; void __iomem *base; unsigned long tick_rate; struct clk *clk; }; static unsigned int atlas7_wdt_gettimeleft(struct watchdog_device *wdd) { struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd); u32 counter, match, delta; counter = readl(wdt->base + ATLAS7_WDT_CNT); match = readl(wdt->base + ATLAS7_WDT_CNT_MATCH); delta = match - counter; return delta / wdt->tick_rate; } static int atlas7_wdt_ping(struct watchdog_device *wdd) { struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd); u32 counter, match, delta; counter = readl(wdt->base + ATLAS7_WDT_CNT); delta = wdd->timeout * wdt->tick_rate; match = counter + delta; writel(match, wdt->base + ATLAS7_WDT_CNT_MATCH); return 0; } static int atlas7_wdt_enable(struct watchdog_device *wdd) { struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd); atlas7_wdt_ping(wdd); writel(readl(wdt->base + ATLAS7_WDT_CNT_CTRL) | ATLAS7_WDT_CNT_EN, wdt->base + ATLAS7_WDT_CNT_CTRL); writel(1, wdt->base + ATLAS7_WDT_EN); return 0; } static int atlas7_wdt_disable(struct watchdog_device *wdd) { struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd); writel(0, wdt->base + ATLAS7_WDT_EN); writel(readl(wdt->base + ATLAS7_WDT_CNT_CTRL) & ~ATLAS7_WDT_CNT_EN, wdt->base + ATLAS7_WDT_CNT_CTRL); return 0; } static int atlas7_wdt_settimeout(struct watchdog_device *wdd, unsigned int to) { wdd->timeout = to; return 0; } #define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE) static const struct watchdog_info atlas7_wdt_ident = { .options = OPTIONS, .firmware_version = 0, .identity = "atlas7 Watchdog", }; |
b893e344b watchdog: constif... |
106 |
static const struct watchdog_ops atlas7_wdt_ops = { |
b466ee895 watchdog: atlas7:... |
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
.owner = THIS_MODULE, .start = atlas7_wdt_enable, .stop = atlas7_wdt_disable, .get_timeleft = atlas7_wdt_gettimeleft, .ping = atlas7_wdt_ping, .set_timeout = atlas7_wdt_settimeout, }; static struct watchdog_device atlas7_wdd = { .info = &atlas7_wdt_ident, .ops = &atlas7_wdt_ops, .timeout = ATLAS7_WDT_DEFAULT_TIMEOUT, }; static const struct of_device_id atlas7_wdt_ids[] = { { .compatible = "sirf,atlas7-tick"}, {} }; |
f332ce5d8 watchdog: atlas7_... |
125 126 127 128 |
static void atlas7_clk_disable_unprepare(void *data) { clk_disable_unprepare(data); } |
b466ee895 watchdog: atlas7:... |
129 130 |
static int atlas7_wdt_probe(struct platform_device *pdev) { |
f332ce5d8 watchdog: atlas7_... |
131 |
struct device *dev = &pdev->dev; |
b466ee895 watchdog: atlas7:... |
132 |
struct atlas7_wdog *wdt; |
b466ee895 watchdog: atlas7:... |
133 134 |
struct clk *clk; int ret; |
f332ce5d8 watchdog: atlas7_... |
135 |
wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); |
b466ee895 watchdog: atlas7:... |
136 137 |
if (!wdt) return -ENOMEM; |
0f0a6a285 watchdog: Convert... |
138 |
wdt->base = devm_platform_ioremap_resource(pdev, 0); |
b466ee895 watchdog: atlas7:... |
139 140 |
if (IS_ERR(wdt->base)) return PTR_ERR(wdt->base); |
f332ce5d8 watchdog: atlas7_... |
141 |
clk = devm_clk_get(dev, NULL); |
b466ee895 watchdog: atlas7:... |
142 143 144 145 |
if (IS_ERR(clk)) return PTR_ERR(clk); ret = clk_prepare_enable(clk); if (ret) { |
f332ce5d8 watchdog: atlas7_... |
146 147 148 |
dev_err(dev, "clk enable failed "); return ret; |
b466ee895 watchdog: atlas7:... |
149 |
} |
f332ce5d8 watchdog: atlas7_... |
150 151 152 |
ret = devm_add_action_or_reset(dev, atlas7_clk_disable_unprepare, clk); if (ret) return ret; |
b466ee895 watchdog: atlas7:... |
153 154 155 156 157 |
/* disable watchdog hardware */ writel(0, wdt->base + ATLAS7_WDT_CNT_CTRL); wdt->tick_rate = clk_get_rate(clk); |
f332ce5d8 watchdog: atlas7_... |
158 159 |
if (!wdt->tick_rate) return -EINVAL; |
ccc8208d0 watchdog: atlas7_... |
160 |
|
b466ee895 watchdog: atlas7:... |
161 162 163 |
wdt->clk = clk; atlas7_wdd.min_timeout = 1; atlas7_wdd.max_timeout = UINT_MAX / wdt->tick_rate; |
f332ce5d8 watchdog: atlas7_... |
164 |
watchdog_init_timeout(&atlas7_wdd, 0, dev); |
b466ee895 watchdog: atlas7:... |
165 166 167 168 |
watchdog_set_nowayout(&atlas7_wdd, nowayout); watchdog_set_drvdata(&atlas7_wdd, wdt); platform_set_drvdata(pdev, &atlas7_wdd); |
f332ce5d8 watchdog: atlas7_... |
169 170 171 |
watchdog_stop_on_reboot(&atlas7_wdd); watchdog_stop_on_unregister(&atlas7_wdd); return devm_watchdog_register_device(dev, &atlas7_wdd); |
b466ee895 watchdog: atlas7:... |
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
} static int __maybe_unused atlas7_wdt_suspend(struct device *dev) { /* * NOTE:timer controller registers settings are saved * and restored back by the timer-atlas7.c */ return 0; } static int __maybe_unused atlas7_wdt_resume(struct device *dev) { struct watchdog_device *wdd = dev_get_drvdata(dev); /* * NOTE: Since timer controller registers settings are saved * and restored back by the timer-atlas7.c, so we need not * update WD settings except refreshing timeout. */ atlas7_wdt_ping(wdd); return 0; } static SIMPLE_DEV_PM_OPS(atlas7_wdt_pm_ops, atlas7_wdt_suspend, atlas7_wdt_resume); MODULE_DEVICE_TABLE(of, atlas7_wdt_ids); static struct platform_driver atlas7_wdt_driver = { .driver = { .name = "atlas7-wdt", .pm = &atlas7_wdt_pm_ops, .of_match_table = atlas7_wdt_ids, }, .probe = atlas7_wdt_probe, |
b466ee895 watchdog: atlas7:... |
209 210 211 212 213 214 215 |
}; module_platform_driver(atlas7_wdt_driver); MODULE_DESCRIPTION("CSRatlas7 watchdog driver"); MODULE_AUTHOR("Guo Zeng <Guo.Zeng@csr.com>"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:atlas7-wdt"); |