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>
This commit is contained in:
Ezequiel Garcia 2014-02-10 20:00:31 -03:00 committed by Jason Cooper
parent 490d8e3cbf
commit 463f96e0cd
2 changed files with 107 additions and 2 deletions

View File

@ -3,6 +3,9 @@
Required Properties: Required Properties:
- Compatibility : "marvell,orion-wdt" - Compatibility : "marvell,orion-wdt"
"marvell,armada-370-wdt"
"marvell,armada-xp-wdt"
- reg : Should contain two entries: first one with the - reg : Should contain two entries: first one with the
timer control address, second one with the timer control address, second one with the
rstout enable address. rstout enable address.

View File

@ -36,9 +36,17 @@
* Watchdog timer block registers. * Watchdog timer block registers.
*/ */
#define TIMER_CTRL 0x0000 #define TIMER_CTRL 0x0000
#define TIMER_A370_STATUS 0x04
#define WDT_MAX_CYCLE_COUNT 0xffffffff #define WDT_MAX_CYCLE_COUNT 0xffffffff
#define WDT_A370_RATIO_MASK(v) ((v) << 16)
#define WDT_A370_RATIO_SHIFT 5
#define WDT_A370_RATIO (1 << WDT_A370_RATIO_SHIFT)
#define WDT_AXP_FIXED_ENABLE_BIT BIT(10)
#define WDT_A370_EXPIRED BIT(31)
static bool nowayout = WATCHDOG_NOWAYOUT; static bool nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = -1; /* module parameter (seconds) */ static int heartbeat = -1; /* module parameter (seconds) */
@ -67,12 +75,60 @@ static int orion_wdt_clock_init(struct platform_device *pdev,
{ {
int ret; int ret;
dev->clk = devm_clk_get(&pdev->dev, NULL); dev->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk)) if (IS_ERR(dev->clk))
return PTR_ERR(dev->clk); return PTR_ERR(dev->clk);
ret = clk_prepare_enable(dev->clk); ret = clk_prepare_enable(dev->clk);
if (ret) if (ret) {
clk_put(dev->clk);
return ret; return ret;
}
dev->clk_rate = clk_get_rate(dev->clk);
return 0;
}
static int armada370_wdt_clock_init(struct platform_device *pdev,
struct orion_watchdog *dev)
{
int ret;
dev->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk))
return PTR_ERR(dev->clk);
ret = clk_prepare_enable(dev->clk);
if (ret) {
clk_put(dev->clk);
return ret;
}
/* Setup watchdog input clock */
atomic_io_modify(dev->reg + TIMER_CTRL,
WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT),
WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT));
dev->clk_rate = clk_get_rate(dev->clk) / WDT_A370_RATIO;
return 0;
}
static int armadaxp_wdt_clock_init(struct platform_device *pdev,
struct orion_watchdog *dev)
{
int ret;
dev->clk = of_clk_get_by_name(pdev->dev.of_node, "fixed");
if (IS_ERR(dev->clk))
return PTR_ERR(dev->clk);
ret = clk_prepare_enable(dev->clk);
if (ret) {
clk_put(dev->clk);
return ret;
}
/* Enable the fixed watchdog clock input */
atomic_io_modify(dev->reg + TIMER_CTRL,
WDT_AXP_FIXED_ENABLE_BIT,
WDT_AXP_FIXED_ENABLE_BIT);
dev->clk_rate = clk_get_rate(dev->clk); dev->clk_rate = clk_get_rate(dev->clk);
return 0; return 0;
@ -87,6 +143,26 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev)
return 0; return 0;
} }
static int armada370_start(struct watchdog_device *wdt_dev)
{
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
/* Set watchdog duration */
writel(dev->clk_rate * wdt_dev->timeout,
dev->reg + dev->data->wdt_counter_offset);
/* Clear the watchdog expiration bit */
atomic_io_modify(dev->reg + TIMER_A370_STATUS, WDT_A370_EXPIRED, 0);
/* Enable watchdog timer */
atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit,
dev->data->wdt_enable_bit);
atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit,
dev->data->rstout_enable_bit);
return 0;
}
static int orion_start(struct watchdog_device *wdt_dev) static int orion_start(struct watchdog_device *wdt_dev)
{ {
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@ -205,11 +281,35 @@ static const struct orion_watchdog_data orion_data = {
.start = orion_start, .start = orion_start,
}; };
static const struct orion_watchdog_data armada370_data = {
.rstout_enable_bit = BIT(8),
.wdt_enable_bit = BIT(8),
.wdt_counter_offset = 0x34,
.clock_init = armada370_wdt_clock_init,
.start = armada370_start,
};
static const struct orion_watchdog_data armadaxp_data = {
.rstout_enable_bit = BIT(8),
.wdt_enable_bit = BIT(8),
.wdt_counter_offset = 0x34,
.clock_init = armadaxp_wdt_clock_init,
.start = armada370_start,
};
static const struct of_device_id orion_wdt_of_match_table[] = { static const struct of_device_id orion_wdt_of_match_table[] = {
{ {
.compatible = "marvell,orion-wdt", .compatible = "marvell,orion-wdt",
.data = &orion_data, .data = &orion_data,
}, },
{
.compatible = "marvell,armada-370-wdt",
.data = &armada370_data,
},
{
.compatible = "marvell,armada-xp-wdt",
.data = &armadaxp_data,
},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table); MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table);
@ -301,6 +401,7 @@ static int orion_wdt_probe(struct platform_device *pdev)
disable_clk: disable_clk:
clk_disable_unprepare(dev->clk); clk_disable_unprepare(dev->clk);
clk_put(dev->clk);
return ret; return ret;
} }
@ -311,6 +412,7 @@ static int orion_wdt_remove(struct platform_device *pdev)
watchdog_unregister_device(wdt_dev); watchdog_unregister_device(wdt_dev);
clk_disable_unprepare(dev->clk); clk_disable_unprepare(dev->clk);
clk_put(dev->clk);
return 0; return 0;
} }