diff options
author | Ezequiel Garcia <ezequiel.garcia@free-electrons.com> | 2014-03-15 14:18:01 -0400 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2014-06-10 15:44:41 -0400 |
commit | b483642fc399c0c79a90aef25c956f37e29e6b27 (patch) | |
tree | d6f48f6379eee8201e432c8d6c50206addb32392 | |
parent | 1b0ea574ac90c9c3da8e903f205848bd4724b1cf (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.c | 103 |
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 | ||
149 | static 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 | |||
147 | static int armada370_start(struct watchdog_device *wdt_dev) | 174 | static 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 | ||
237 | static 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 | |||
210 | static int armada370_stop(struct watchdog_device *wdt_dev) | 255 | static 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 | ||
288 | static 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 | |||
243 | static int orion_wdt_enabled(struct watchdog_device *wdt_dev) | 299 | static 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 | ||
392 | static 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 | |||
403 | static 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 | |||
336 | static const struct of_device_id orion_wdt_of_match_table[] = { | 414 | static 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 | }; |
351 | MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table); | 437 | MODULE_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 | } |