diff options
-rw-r--r-- | Documentation/devicetree/bindings/watchdog/marvel.txt | 3 | ||||
-rw-r--r-- | drivers/watchdog/orion_wdt.c | 106 |
2 files changed, 107 insertions, 2 deletions
diff --git a/Documentation/devicetree/bindings/watchdog/marvel.txt b/Documentation/devicetree/bindings/watchdog/marvel.txt index 1544fe991d24..de11eb4c121f 100644 --- a/Documentation/devicetree/bindings/watchdog/marvel.txt +++ b/Documentation/devicetree/bindings/watchdog/marvel.txt | |||
@@ -3,6 +3,9 @@ | |||
3 | Required Properties: | 3 | Required Properties: |
4 | 4 | ||
5 | - Compatibility : "marvell,orion-wdt" | 5 | - Compatibility : "marvell,orion-wdt" |
6 | "marvell,armada-370-wdt" | ||
7 | "marvell,armada-xp-wdt" | ||
8 | |||
6 | - reg : Should contain two entries: first one with the | 9 | - reg : Should contain two entries: first one with the |
7 | timer control address, second one with the | 10 | timer control address, second one with the |
8 | rstout enable address. | 11 | rstout enable address. |
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index 392529785b40..15321aa0bb94 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c | |||
@@ -36,9 +36,17 @@ | |||
36 | * Watchdog timer block registers. | 36 | * Watchdog timer block registers. |
37 | */ | 37 | */ |
38 | #define TIMER_CTRL 0x0000 | 38 | #define TIMER_CTRL 0x0000 |
39 | #define TIMER_A370_STATUS 0x04 | ||
39 | 40 | ||
40 | #define WDT_MAX_CYCLE_COUNT 0xffffffff | 41 | #define WDT_MAX_CYCLE_COUNT 0xffffffff |
41 | 42 | ||
43 | #define WDT_A370_RATIO_MASK(v) ((v) << 16) | ||
44 | #define WDT_A370_RATIO_SHIFT 5 | ||
45 | #define WDT_A370_RATIO (1 << WDT_A370_RATIO_SHIFT) | ||
46 | |||
47 | #define WDT_AXP_FIXED_ENABLE_BIT BIT(10) | ||
48 | #define WDT_A370_EXPIRED BIT(31) | ||
49 | |||
42 | static bool nowayout = WATCHDOG_NOWAYOUT; | 50 | static bool nowayout = WATCHDOG_NOWAYOUT; |
43 | static int heartbeat = -1; /* module parameter (seconds) */ | 51 | static int heartbeat = -1; /* module parameter (seconds) */ |
44 | 52 | ||
@@ -67,12 +75,60 @@ static int orion_wdt_clock_init(struct platform_device *pdev, | |||
67 | { | 75 | { |
68 | int ret; | 76 | int ret; |
69 | 77 | ||
70 | dev->clk = devm_clk_get(&pdev->dev, NULL); | 78 | dev->clk = clk_get(&pdev->dev, NULL); |
71 | if (IS_ERR(dev->clk)) | 79 | if (IS_ERR(dev->clk)) |
72 | return PTR_ERR(dev->clk); | 80 | return PTR_ERR(dev->clk); |
73 | ret = clk_prepare_enable(dev->clk); | 81 | ret = clk_prepare_enable(dev->clk); |
74 | if (ret) | 82 | if (ret) { |
83 | clk_put(dev->clk); | ||
75 | return ret; | 84 | return ret; |
85 | } | ||
86 | |||
87 | dev->clk_rate = clk_get_rate(dev->clk); | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static int armada370_wdt_clock_init(struct platform_device *pdev, | ||
92 | struct orion_watchdog *dev) | ||
93 | { | ||
94 | int ret; | ||
95 | |||
96 | dev->clk = clk_get(&pdev->dev, NULL); | ||
97 | if (IS_ERR(dev->clk)) | ||
98 | return PTR_ERR(dev->clk); | ||
99 | ret = clk_prepare_enable(dev->clk); | ||
100 | if (ret) { | ||
101 | clk_put(dev->clk); | ||
102 | return ret; | ||
103 | } | ||
104 | |||
105 | /* Setup watchdog input clock */ | ||
106 | atomic_io_modify(dev->reg + TIMER_CTRL, | ||
107 | WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT), | ||
108 | WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT)); | ||
109 | |||
110 | dev->clk_rate = clk_get_rate(dev->clk) / WDT_A370_RATIO; | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static int armadaxp_wdt_clock_init(struct platform_device *pdev, | ||
115 | struct orion_watchdog *dev) | ||
116 | { | ||
117 | int ret; | ||
118 | |||
119 | dev->clk = of_clk_get_by_name(pdev->dev.of_node, "fixed"); | ||
120 | if (IS_ERR(dev->clk)) | ||
121 | return PTR_ERR(dev->clk); | ||
122 | ret = clk_prepare_enable(dev->clk); | ||
123 | if (ret) { | ||
124 | clk_put(dev->clk); | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | /* Enable the fixed watchdog clock input */ | ||
129 | atomic_io_modify(dev->reg + TIMER_CTRL, | ||
130 | WDT_AXP_FIXED_ENABLE_BIT, | ||
131 | WDT_AXP_FIXED_ENABLE_BIT); | ||
76 | 132 | ||
77 | dev->clk_rate = clk_get_rate(dev->clk); | 133 | dev->clk_rate = clk_get_rate(dev->clk); |
78 | return 0; | 134 | return 0; |
@@ -87,6 +143,26 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev) | |||
87 | return 0; | 143 | return 0; |
88 | } | 144 | } |
89 | 145 | ||
146 | static int armada370_start(struct watchdog_device *wdt_dev) | ||
147 | { | ||
148 | struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); | ||
149 | |||
150 | /* Set watchdog duration */ | ||
151 | writel(dev->clk_rate * wdt_dev->timeout, | ||
152 | dev->reg + dev->data->wdt_counter_offset); | ||
153 | |||
154 | /* Clear the watchdog expiration bit */ | ||
155 | atomic_io_modify(dev->reg + TIMER_A370_STATUS, WDT_A370_EXPIRED, 0); | ||
156 | |||
157 | /* Enable watchdog timer */ | ||
158 | atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, | ||
159 | dev->data->wdt_enable_bit); | ||
160 | |||
161 | atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit, | ||
162 | dev->data->rstout_enable_bit); | ||
163 | return 0; | ||
164 | } | ||
165 | |||
90 | static int orion_start(struct watchdog_device *wdt_dev) | 166 | static int orion_start(struct watchdog_device *wdt_dev) |
91 | { | 167 | { |
92 | struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); | 168 | struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); |
@@ -205,11 +281,35 @@ static const struct orion_watchdog_data orion_data = { | |||
205 | .start = orion_start, | 281 | .start = orion_start, |
206 | }; | 282 | }; |
207 | 283 | ||
284 | static const struct orion_watchdog_data armada370_data = { | ||
285 | .rstout_enable_bit = BIT(8), | ||
286 | .wdt_enable_bit = BIT(8), | ||
287 | .wdt_counter_offset = 0x34, | ||
288 | .clock_init = armada370_wdt_clock_init, | ||
289 | .start = armada370_start, | ||
290 | }; | ||
291 | |||
292 | static const struct orion_watchdog_data armadaxp_data = { | ||
293 | .rstout_enable_bit = BIT(8), | ||
294 | .wdt_enable_bit = BIT(8), | ||
295 | .wdt_counter_offset = 0x34, | ||
296 | .clock_init = armadaxp_wdt_clock_init, | ||
297 | .start = armada370_start, | ||
298 | }; | ||
299 | |||
208 | static const struct of_device_id orion_wdt_of_match_table[] = { | 300 | static const struct of_device_id orion_wdt_of_match_table[] = { |
209 | { | 301 | { |
210 | .compatible = "marvell,orion-wdt", | 302 | .compatible = "marvell,orion-wdt", |
211 | .data = &orion_data, | 303 | .data = &orion_data, |
212 | }, | 304 | }, |
305 | { | ||
306 | .compatible = "marvell,armada-370-wdt", | ||
307 | .data = &armada370_data, | ||
308 | }, | ||
309 | { | ||
310 | .compatible = "marvell,armada-xp-wdt", | ||
311 | .data = &armadaxp_data, | ||
312 | }, | ||
213 | {}, | 313 | {}, |
214 | }; | 314 | }; |
215 | MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table); | 315 | MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table); |
@@ -301,6 +401,7 @@ static int orion_wdt_probe(struct platform_device *pdev) | |||
301 | 401 | ||
302 | disable_clk: | 402 | disable_clk: |
303 | clk_disable_unprepare(dev->clk); | 403 | clk_disable_unprepare(dev->clk); |
404 | clk_put(dev->clk); | ||
304 | return ret; | 405 | return ret; |
305 | } | 406 | } |
306 | 407 | ||
@@ -311,6 +412,7 @@ static int orion_wdt_remove(struct platform_device *pdev) | |||
311 | 412 | ||
312 | watchdog_unregister_device(wdt_dev); | 413 | watchdog_unregister_device(wdt_dev); |
313 | clk_disable_unprepare(dev->clk); | 414 | clk_disable_unprepare(dev->clk); |
415 | clk_put(dev->clk); | ||
314 | return 0; | 416 | return 0; |
315 | } | 417 | } |
316 | 418 | ||