aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEzequiel Garcia <ezequiel.garcia@free-electrons.com>2014-03-15 14:18:01 -0400
committerWim Van Sebroeck <wim@iguana.be>2014-06-10 15:44:41 -0400
commitb483642fc399c0c79a90aef25c956f37e29e6b27 (patch)
treed6f48f6379eee8201e432c8d6c50206addb32392
parent1b0ea574ac90c9c3da8e903f205848bd4724b1cf (diff)
watchdog: orion: Add Armada 375/380 SoC support
This commit adds support for the Armada 375 and Armada 380 SoCs. This SoC variant has a second RSTOUT register, in addition to the already existent, which is shared with the system-controller. To handle this RSTOUT, we introduce a new MMIO register 'rstout_mask' to be required on 'armada-{375,380}-watchdog' new compatible string. Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Acked-by: Jason Cooper <jason@lakedaemon.net> Tested-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
-rw-r--r--drivers/watchdog/orion_wdt.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index ba316db2b80c..00d0741228fc 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -55,6 +55,7 @@ struct orion_watchdog_data {
55 int wdt_counter_offset; 55 int wdt_counter_offset;
56 int wdt_enable_bit; 56 int wdt_enable_bit;
57 int rstout_enable_bit; 57 int rstout_enable_bit;
58 int rstout_mask_bit;
58 int (*clock_init)(struct platform_device *, 59 int (*clock_init)(struct platform_device *,
59 struct orion_watchdog *); 60 struct orion_watchdog *);
60 int (*enabled)(struct orion_watchdog *); 61 int (*enabled)(struct orion_watchdog *);
@@ -66,6 +67,7 @@ struct orion_watchdog {
66 struct watchdog_device wdt; 67 struct watchdog_device wdt;
67 void __iomem *reg; 68 void __iomem *reg;
68 void __iomem *rstout; 69 void __iomem *rstout;
70 void __iomem *rstout_mask;
69 unsigned long clk_rate; 71 unsigned long clk_rate;
70 struct clk *clk; 72 struct clk *clk;
71 const struct orion_watchdog_data *data; 73 const struct orion_watchdog_data *data;
@@ -144,6 +146,31 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev)
144 return 0; 146 return 0;
145} 147}
146 148
149static int armada375_start(struct watchdog_device *wdt_dev)
150{
151 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
152 u32 reg;
153
154 /* Set watchdog duration */
155 writel(dev->clk_rate * wdt_dev->timeout,
156 dev->reg + dev->data->wdt_counter_offset);
157
158 /* Clear the watchdog expiration bit */
159 atomic_io_modify(dev->reg + TIMER_A370_STATUS, WDT_A370_EXPIRED, 0);
160
161 /* Enable watchdog timer */
162 atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit,
163 dev->data->wdt_enable_bit);
164
165 /* Enable reset on watchdog */
166 reg = readl(dev->rstout);
167 reg |= dev->data->rstout_enable_bit;
168 writel(reg, dev->rstout);
169
170 atomic_io_modify(dev->rstout_mask, dev->data->rstout_mask_bit, 0);
171 return 0;
172}
173
147static int armada370_start(struct watchdog_device *wdt_dev) 174static int armada370_start(struct watchdog_device *wdt_dev)
148{ 175{
149 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); 176 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -207,6 +234,24 @@ static int orion_stop(struct watchdog_device *wdt_dev)
207 return 0; 234 return 0;
208} 235}
209 236
237static int armada375_stop(struct watchdog_device *wdt_dev)
238{
239 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
240 u32 reg;
241
242 /* Disable reset on watchdog */
243 atomic_io_modify(dev->rstout_mask, dev->data->rstout_mask_bit,
244 dev->data->rstout_mask_bit);
245 reg = readl(dev->rstout);
246 reg &= ~dev->data->rstout_enable_bit;
247 writel(reg, dev->rstout);
248
249 /* Disable watchdog timer */
250 atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, 0);
251
252 return 0;
253}
254
210static int armada370_stop(struct watchdog_device *wdt_dev) 255static int armada370_stop(struct watchdog_device *wdt_dev)
211{ 256{
212 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); 257 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -240,6 +285,17 @@ static int orion_enabled(struct orion_watchdog *dev)
240 return enabled && running; 285 return enabled && running;
241} 286}
242 287
288static int armada375_enabled(struct orion_watchdog *dev)
289{
290 bool masked, enabled, running;
291
292 masked = readl(dev->rstout_mask) & dev->data->rstout_mask_bit;
293 enabled = readl(dev->rstout) & dev->data->rstout_enable_bit;
294 running = readl(dev->reg + TIMER_CTRL) & dev->data->wdt_enable_bit;
295
296 return !masked && enabled && running;
297}
298
243static int orion_wdt_enabled(struct watchdog_device *wdt_dev) 299static int orion_wdt_enabled(struct watchdog_device *wdt_dev)
244{ 300{
245 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); 301 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -333,6 +389,28 @@ static const struct orion_watchdog_data armadaxp_data = {
333 .stop = armada370_stop, 389 .stop = armada370_stop,
334}; 390};
335 391
392static const struct orion_watchdog_data armada375_data = {
393 .rstout_enable_bit = BIT(8),
394 .rstout_mask_bit = BIT(10),
395 .wdt_enable_bit = BIT(8),
396 .wdt_counter_offset = 0x34,
397 .clock_init = armada370_wdt_clock_init,
398 .enabled = armada375_enabled,
399 .start = armada375_start,
400 .stop = armada375_stop,
401};
402
403static const struct orion_watchdog_data armada380_data = {
404 .rstout_enable_bit = BIT(8),
405 .rstout_mask_bit = BIT(10),
406 .wdt_enable_bit = BIT(8),
407 .wdt_counter_offset = 0x34,
408 .clock_init = armadaxp_wdt_clock_init,
409 .enabled = armada375_enabled,
410 .start = armada375_start,
411 .stop = armada375_stop,
412};
413
336static const struct of_device_id orion_wdt_of_match_table[] = { 414static const struct of_device_id orion_wdt_of_match_table[] = {
337 { 415 {
338 .compatible = "marvell,orion-wdt", 416 .compatible = "marvell,orion-wdt",
@@ -346,6 +424,14 @@ static const struct of_device_id orion_wdt_of_match_table[] = {
346 .compatible = "marvell,armada-xp-wdt", 424 .compatible = "marvell,armada-xp-wdt",
347 .data = &armadaxp_data, 425 .data = &armadaxp_data,
348 }, 426 },
427 {
428 .compatible = "marvell,armada-375-wdt",
429 .data = &armada375_data,
430 },
431 {
432 .compatible = "marvell,armada-380-wdt",
433 .data = &armada380_data,
434 },
349 {}, 435 {},
350}; 436};
351MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table); 437MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table);
@@ -381,6 +467,23 @@ static int orion_wdt_get_regs(struct platform_device *pdev,
381 if (IS_ERR(dev->rstout)) 467 if (IS_ERR(dev->rstout))
382 return PTR_ERR(dev->rstout); 468 return PTR_ERR(dev->rstout);
383 469
470 } else if (of_device_is_compatible(node, "marvell,armada-375-wdt") ||
471 of_device_is_compatible(node, "marvell,armada-380-wdt")) {
472
473 /* Dedicated RSTOUT register, can be requested. */
474 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
475 dev->rstout = devm_ioremap_resource(&pdev->dev, res);
476 if (IS_ERR(dev->rstout))
477 return PTR_ERR(dev->rstout);
478
479 res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
480 if (!res)
481 return -ENODEV;
482 dev->rstout_mask = devm_ioremap(&pdev->dev, res->start,
483 resource_size(res));
484 if (!dev->rstout_mask)
485 return -ENOMEM;
486
384 } else { 487 } else {
385 return -ENODEV; 488 return -ENODEV;
386 } 489 }