mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
watchdog: loongson1: Add Loongson-2k0300 watchdog support
According to the manual, the Loongson-2K0300 watchdog is similar to the Loongson-1, except for some register offsets and inconsistent register bit definitions. Separate definitions via driver_data suffice. Co-developed-by: Xiaochuang Mao <maoxiaochuan@loongson.cn> Signed-off-by: Xiaochuang Mao <maoxiaochuan@loongson.cn> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn> Reviewed-by: Huacai Chen <chenhuacai@loongson.cn> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
This commit is contained in:
committed by
Wim Van Sebroeck
parent
e4948e8011
commit
e0c50cddbd
@@ -1984,10 +1984,10 @@ config LANTIQ_WDT
|
||||
|
||||
config LOONGSON1_WDT
|
||||
tristate "Loongson1 SoC hardware watchdog"
|
||||
depends on MACH_LOONGSON32 || COMPILE_TEST
|
||||
depends on MACH_LOONGSON32 || MACH_LOONGSON64 || COMPILE_TEST
|
||||
select WATCHDOG_CORE
|
||||
help
|
||||
Hardware driver for the Loongson1 SoC Watchdog Timer.
|
||||
Hardware driver for the Loongson family Watchdog Timer.
|
||||
|
||||
config RALINK_WDT
|
||||
tristate "Ralink SoC watchdog"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2016 Yang Ling <gnaygnil@gmail.com>
|
||||
* Copyright (C) 2025 Binbin Zhou <zhoubinbin@loongson.cn>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
@@ -10,10 +11,8 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
/* Loongson 1 Watchdog Register Definitions */
|
||||
/* Loongson Watchdog Register Definitions */
|
||||
#define WDT_EN 0x0
|
||||
#define WDT_TIMER 0x4
|
||||
#define WDT_SET 0x8
|
||||
|
||||
#define DEFAULT_HEARTBEAT 30
|
||||
|
||||
@@ -27,18 +26,37 @@ module_param(heartbeat, uint, 0);
|
||||
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default="
|
||||
__MODULE_STRING(DEFAULT_HEARTBEAT) ")");
|
||||
|
||||
struct ls1x_wdt_pdata {
|
||||
u32 timer_offset;
|
||||
u32 set_offset;
|
||||
u32 wdt_en_bit;
|
||||
};
|
||||
|
||||
static const struct ls1x_wdt_pdata ls1b_wdt_pdata = {
|
||||
.timer_offset = 0x4,
|
||||
.set_offset = 0x8,
|
||||
.wdt_en_bit = BIT(0),
|
||||
};
|
||||
|
||||
static const struct ls1x_wdt_pdata ls2k0300_wdt_pdata = {
|
||||
.timer_offset = 0x8,
|
||||
.set_offset = 0x4,
|
||||
.wdt_en_bit = BIT(1),
|
||||
};
|
||||
|
||||
struct ls1x_wdt_drvdata {
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
unsigned long clk_rate;
|
||||
struct watchdog_device wdt;
|
||||
const struct ls1x_wdt_pdata *pdata;
|
||||
};
|
||||
|
||||
static int ls1x_wdt_ping(struct watchdog_device *wdt_dev)
|
||||
{
|
||||
struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
|
||||
|
||||
writel(0x1, drvdata->base + WDT_SET);
|
||||
writel(0x1, drvdata->base + drvdata->pdata->set_offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -53,7 +71,7 @@ static int ls1x_wdt_set_timeout(struct watchdog_device *wdt_dev,
|
||||
wdt_dev->timeout = timeout;
|
||||
|
||||
counts = drvdata->clk_rate * min(timeout, max_hw_heartbeat);
|
||||
writel(counts, drvdata->base + WDT_TIMER);
|
||||
writel(counts, drvdata->base + drvdata->pdata->timer_offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -62,7 +80,7 @@ static int ls1x_wdt_start(struct watchdog_device *wdt_dev)
|
||||
{
|
||||
struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
|
||||
|
||||
writel(0x1, drvdata->base + WDT_EN);
|
||||
writel(drvdata->pdata->wdt_en_bit, drvdata->base + WDT_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -70,8 +88,10 @@ static int ls1x_wdt_start(struct watchdog_device *wdt_dev)
|
||||
static int ls1x_wdt_stop(struct watchdog_device *wdt_dev)
|
||||
{
|
||||
struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
|
||||
u32 val = readl(drvdata->base + WDT_EN);
|
||||
|
||||
writel(0x0, drvdata->base + WDT_EN);
|
||||
val &= ~(drvdata->pdata->wdt_en_bit);
|
||||
writel(val, drvdata->base + WDT_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -81,9 +101,9 @@ static int ls1x_wdt_restart(struct watchdog_device *wdt_dev,
|
||||
{
|
||||
struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
|
||||
|
||||
writel(0x1, drvdata->base + WDT_EN);
|
||||
writel(0x1, drvdata->base + WDT_TIMER);
|
||||
writel(0x1, drvdata->base + WDT_SET);
|
||||
writel(drvdata->pdata->wdt_en_bit, drvdata->base + WDT_EN);
|
||||
writel(0x1, drvdata->base + drvdata->pdata->timer_offset);
|
||||
writel(0x1, drvdata->base + drvdata->pdata->set_offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -114,6 +134,8 @@ static int ls1x_wdt_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
platform_set_drvdata(pdev, drvdata);
|
||||
|
||||
drvdata->pdata = of_device_get_match_data(dev);
|
||||
|
||||
drvdata->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(drvdata->base))
|
||||
return PTR_ERR(drvdata->base);
|
||||
@@ -142,9 +164,32 @@ static int ls1x_wdt_probe(struct platform_device *pdev)
|
||||
return devm_watchdog_register_device(dev, &drvdata->wdt);
|
||||
}
|
||||
|
||||
static int ls1x_wdt_resume(struct device *dev)
|
||||
{
|
||||
struct ls1x_wdt_drvdata *data = dev_get_drvdata(dev);
|
||||
|
||||
if (watchdog_active(&data->wdt))
|
||||
ls1x_wdt_start(&data->wdt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ls1x_wdt_suspend(struct device *dev)
|
||||
{
|
||||
struct ls1x_wdt_drvdata *data = dev_get_drvdata(dev);
|
||||
|
||||
if (watchdog_active(&data->wdt))
|
||||
ls1x_wdt_stop(&data->wdt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(ls1x_wdt_pm_ops, ls1x_wdt_suspend, ls1x_wdt_resume);
|
||||
|
||||
static const struct of_device_id ls1x_wdt_dt_ids[] = {
|
||||
{ .compatible = "loongson,ls1b-wdt", },
|
||||
{ .compatible = "loongson,ls1c-wdt", },
|
||||
{ .compatible = "loongson,ls1b-wdt", .data = &ls1b_wdt_pdata },
|
||||
{ .compatible = "loongson,ls1c-wdt", .data = &ls1b_wdt_pdata },
|
||||
{ .compatible = "loongson,ls2k0300-wdt", .data = &ls2k0300_wdt_pdata },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ls1x_wdt_dt_ids);
|
||||
@@ -154,11 +199,13 @@ static struct platform_driver ls1x_wdt_driver = {
|
||||
.driver = {
|
||||
.name = "ls1x-wdt",
|
||||
.of_match_table = ls1x_wdt_dt_ids,
|
||||
.pm = pm_ptr(&ls1x_wdt_pm_ops),
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(ls1x_wdt_driver);
|
||||
|
||||
MODULE_AUTHOR("Yang Ling <gnaygnil@gmail.com>");
|
||||
MODULE_DESCRIPTION("Loongson1 Watchdog Driver");
|
||||
MODULE_AUTHOR("Binbin Zhou <zhoubinbin@loongson.cn>");
|
||||
MODULE_DESCRIPTION("Loongson Watchdog Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
Reference in New Issue
Block a user