diff options
-rw-r--r-- | drivers/watchdog/orion_wdt.c | 62 |
1 files changed, 43 insertions, 19 deletions
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index 9d3a5b97845b..b220e34285d1 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/clk.h> | 24 | #include <linux/clk.h> |
25 | #include <linux/err.h> | 25 | #include <linux/err.h> |
26 | #include <linux/of.h> | 26 | #include <linux/of.h> |
27 | #include <linux/of_device.h> | ||
27 | 28 | ||
28 | /* RSTOUT mask register physical address for Orion5x, Kirkwood and Dove */ | 29 | /* RSTOUT mask register physical address for Orion5x, Kirkwood and Dove */ |
29 | #define ORION_RSTOUT_MASK_OFFSET 0x20108 | 30 | #define ORION_RSTOUT_MASK_OFFSET 0x20108 |
@@ -35,29 +36,33 @@ | |||
35 | * Watchdog timer block registers. | 36 | * Watchdog timer block registers. |
36 | */ | 37 | */ |
37 | #define TIMER_CTRL 0x0000 | 38 | #define TIMER_CTRL 0x0000 |
38 | #define WDT_EN 0x0010 | ||
39 | #define WDT_VAL 0x0024 | ||
40 | 39 | ||
41 | #define WDT_MAX_CYCLE_COUNT 0xffffffff | 40 | #define WDT_MAX_CYCLE_COUNT 0xffffffff |
42 | 41 | ||
43 | #define WDT_RESET_OUT_EN BIT(1) | ||
44 | |||
45 | static bool nowayout = WATCHDOG_NOWAYOUT; | 42 | static bool nowayout = WATCHDOG_NOWAYOUT; |
46 | static int heartbeat = -1; /* module parameter (seconds) */ | 43 | static int heartbeat = -1; /* module parameter (seconds) */ |
47 | 44 | ||
45 | struct orion_watchdog_data { | ||
46 | int wdt_counter_offset; | ||
47 | int wdt_enable_bit; | ||
48 | int rstout_enable_bit; | ||
49 | }; | ||
50 | |||
48 | struct orion_watchdog { | 51 | struct orion_watchdog { |
49 | struct watchdog_device wdt; | 52 | struct watchdog_device wdt; |
50 | void __iomem *reg; | 53 | void __iomem *reg; |
51 | void __iomem *rstout; | 54 | void __iomem *rstout; |
52 | unsigned long clk_rate; | 55 | unsigned long clk_rate; |
53 | struct clk *clk; | 56 | struct clk *clk; |
57 | const struct orion_watchdog_data *data; | ||
54 | }; | 58 | }; |
55 | 59 | ||
56 | static int orion_wdt_ping(struct watchdog_device *wdt_dev) | 60 | static int orion_wdt_ping(struct watchdog_device *wdt_dev) |
57 | { | 61 | { |
58 | struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); | 62 | struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); |
59 | /* Reload watchdog duration */ | 63 | /* Reload watchdog duration */ |
60 | writel(dev->clk_rate * wdt_dev->timeout, dev->reg + WDT_VAL); | 64 | writel(dev->clk_rate * wdt_dev->timeout, |
65 | dev->reg + dev->data->wdt_counter_offset); | ||
61 | return 0; | 66 | return 0; |
62 | } | 67 | } |
63 | 68 | ||
@@ -66,13 +71,16 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev) | |||
66 | struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); | 71 | struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); |
67 | 72 | ||
68 | /* Set watchdog duration */ | 73 | /* Set watchdog duration */ |
69 | writel(dev->clk_rate * wdt_dev->timeout, dev->reg + WDT_VAL); | 74 | writel(dev->clk_rate * wdt_dev->timeout, |
75 | dev->reg + dev->data->wdt_counter_offset); | ||
70 | 76 | ||
71 | /* Enable watchdog timer */ | 77 | /* Enable watchdog timer */ |
72 | atomic_io_modify(dev->reg + TIMER_CTRL, WDT_EN, WDT_EN); | 78 | atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, |
79 | dev->data->wdt_enable_bit); | ||
73 | 80 | ||
74 | /* Enable reset on watchdog */ | 81 | /* Enable reset on watchdog */ |
75 | atomic_io_modify(dev->rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN); | 82 | atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit, |
83 | dev->data->rstout_enable_bit); | ||
76 | 84 | ||
77 | return 0; | 85 | return 0; |
78 | } | 86 | } |
@@ -82,10 +90,10 @@ static int orion_wdt_stop(struct watchdog_device *wdt_dev) | |||
82 | struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); | 90 | struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); |
83 | 91 | ||
84 | /* Disable reset on watchdog */ | 92 | /* Disable reset on watchdog */ |
85 | atomic_io_modify(dev->rstout, WDT_RESET_OUT_EN, 0); | 93 | atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit, 0); |
86 | 94 | ||
87 | /* Disable watchdog timer */ | 95 | /* Disable watchdog timer */ |
88 | atomic_io_modify(dev->reg + TIMER_CTRL, WDT_EN, 0); | 96 | atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, 0); |
89 | 97 | ||
90 | return 0; | 98 | return 0; |
91 | } | 99 | } |
@@ -94,8 +102,8 @@ static int orion_wdt_enabled(struct orion_watchdog *dev) | |||
94 | { | 102 | { |
95 | bool enabled, running; | 103 | bool enabled, running; |
96 | 104 | ||
97 | enabled = readl(dev->rstout) & WDT_RESET_OUT_EN; | 105 | enabled = readl(dev->rstout) & dev->data->rstout_enable_bit; |
98 | running = readl(dev->reg + TIMER_CTRL) & WDT_EN; | 106 | running = readl(dev->reg + TIMER_CTRL) & dev->data->wdt_enable_bit; |
99 | 107 | ||
100 | return enabled && running; | 108 | return enabled && running; |
101 | } | 109 | } |
@@ -103,7 +111,7 @@ static int orion_wdt_enabled(struct orion_watchdog *dev) | |||
103 | static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev) | 111 | static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev) |
104 | { | 112 | { |
105 | struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); | 113 | struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); |
106 | return readl(dev->reg + WDT_VAL) / dev->clk_rate; | 114 | return readl(dev->reg + dev->data->wdt_counter_offset) / dev->clk_rate; |
107 | } | 115 | } |
108 | 116 | ||
109 | static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev, | 117 | static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev, |
@@ -160,9 +168,25 @@ static void __iomem *orion_wdt_ioremap_rstout(struct platform_device *pdev, | |||
160 | return devm_ioremap(&pdev->dev, rstout, 0x4); | 168 | return devm_ioremap(&pdev->dev, rstout, 0x4); |
161 | } | 169 | } |
162 | 170 | ||
171 | static const struct orion_watchdog_data orion_data = { | ||
172 | .rstout_enable_bit = BIT(1), | ||
173 | .wdt_enable_bit = BIT(4), | ||
174 | .wdt_counter_offset = 0x24, | ||
175 | }; | ||
176 | |||
177 | static const struct of_device_id orion_wdt_of_match_table[] = { | ||
178 | { | ||
179 | .compatible = "marvell,orion-wdt", | ||
180 | .data = &orion_data, | ||
181 | }, | ||
182 | {}, | ||
183 | }; | ||
184 | MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table); | ||
185 | |||
163 | static int orion_wdt_probe(struct platform_device *pdev) | 186 | static int orion_wdt_probe(struct platform_device *pdev) |
164 | { | 187 | { |
165 | struct orion_watchdog *dev; | 188 | struct orion_watchdog *dev; |
189 | const struct of_device_id *match; | ||
166 | unsigned int wdt_max_duration; /* (seconds) */ | 190 | unsigned int wdt_max_duration; /* (seconds) */ |
167 | struct resource *res; | 191 | struct resource *res; |
168 | int ret, irq; | 192 | int ret, irq; |
@@ -172,9 +196,15 @@ static int orion_wdt_probe(struct platform_device *pdev) | |||
172 | if (!dev) | 196 | if (!dev) |
173 | return -ENOMEM; | 197 | return -ENOMEM; |
174 | 198 | ||
199 | match = of_match_device(orion_wdt_of_match_table, &pdev->dev); | ||
200 | if (!match) | ||
201 | /* Default legacy match */ | ||
202 | match = &orion_wdt_of_match_table[0]; | ||
203 | |||
175 | dev->wdt.info = &orion_wdt_info; | 204 | dev->wdt.info = &orion_wdt_info; |
176 | dev->wdt.ops = &orion_wdt_ops; | 205 | dev->wdt.ops = &orion_wdt_ops; |
177 | dev->wdt.min_timeout = 1; | 206 | dev->wdt.min_timeout = 1; |
207 | dev->data = match->data; | ||
178 | 208 | ||
179 | dev->clk = devm_clk_get(&pdev->dev, NULL); | 209 | dev->clk = devm_clk_get(&pdev->dev, NULL); |
180 | if (IS_ERR(dev->clk)) { | 210 | if (IS_ERR(dev->clk)) { |
@@ -269,12 +299,6 @@ static void orion_wdt_shutdown(struct platform_device *pdev) | |||
269 | orion_wdt_stop(wdt_dev); | 299 | orion_wdt_stop(wdt_dev); |
270 | } | 300 | } |
271 | 301 | ||
272 | static const struct of_device_id orion_wdt_of_match_table[] = { | ||
273 | { .compatible = "marvell,orion-wdt", }, | ||
274 | {}, | ||
275 | }; | ||
276 | MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table); | ||
277 | |||
278 | static struct platform_driver orion_wdt_driver = { | 302 | static struct platform_driver orion_wdt_driver = { |
279 | .probe = orion_wdt_probe, | 303 | .probe = orion_wdt_probe, |
280 | .remove = orion_wdt_remove, | 304 | .remove = orion_wdt_remove, |