aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorEzequiel Garcia <ezequiel.garcia@free-electrons.com>2014-02-10 18:00:31 -0500
committerJason Cooper <jason@lakedaemon.net>2014-02-21 22:44:19 -0500
commit463f96e0cdacce5be9bfdd4cc81e7225347cdc31 (patch)
tree31a4ddb92b5dfb79faa0bcf3041b4465a58f3773 /drivers/watchdog
parent490d8e3cbf60cc4ad874caa8c07e67e14c25a1af (diff)
watchdog: orion: Add support for Armada 370 and Armada XP SoC
Using the added infrastructure for handling SoC differences, this commit adds support for the watchdog controller available in Armada 370 and Armada XP SoCs. Also, and because the AXP clock initialization uses of_clk_get_by_name, this commit changes the orion clock initialization to use clk_get() and adds a proper clk_put() on the common exit/error paths. Reviewed-by: Guenter Roeck <linux@roeck-us.net> Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> Tested-by: Willy Tarreau <w@1wt.eu> Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> Acked-by: Wim Van Sebroeck <wim@iguana.be> Tested-By: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> Signed-off-by: Jason Cooper <jason@lakedaemon.net>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/orion_wdt.c106
1 files changed, 104 insertions, 2 deletions
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