aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/watchdog/marvel.txt3
-rw-r--r--drivers/watchdog/orion_wdt.c106
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 @@
3Required Properties: 3Required 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
42static bool nowayout = WATCHDOG_NOWAYOUT; 50static bool nowayout = WATCHDOG_NOWAYOUT;
43static int heartbeat = -1; /* module parameter (seconds) */ 51static 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
91static 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
114static 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
146static 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
90static int orion_start(struct watchdog_device *wdt_dev) 166static 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
284static 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
292static 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
208static const struct of_device_id orion_wdt_of_match_table[] = { 300static 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};
215MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table); 315MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table);
@@ -301,6 +401,7 @@ static int orion_wdt_probe(struct platform_device *pdev)
301 401
302disable_clk: 402disable_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