mirror of
https://github.com/torvalds/linux.git
synced 2025-11-30 23:16:01 +07:00
Merge tag 'linux-watchdog-6.18-rc1' of git://www.linux-watchdog.org/linux-watchdog
Pull watchdog updates from Wim Van Sebroeck: - renesas,wdt: Add support for RZ/T2H and RZ/N2H - Add SMARC-sAM67 support - Several small fixes and improvements * tag 'linux-watchdog-6.18-rc1' of git://www.linux-watchdog.org/linux-watchdog: watchdog/hpwdt New maintianer dt-bindings: watchdog: add SMARC-sAM67 support watchdog: mpc8xxx_wdt: Reload the watchdog timer when enabling the watchdog watchdog: visconti: don't print superfluous errors watchdog: rzv2h_wdt: don't print superfluous errors watchdog: rzg2l_wdt: don't print superfluous errors watchdog: s3c2410_wdt: exynosautov9: Enable supported features watchdog: s3c2410_wdt: exynosautov920: Enable QUIRK_HAS_32BIT_CNT watchdog: s3c2410_wdt: Increase max timeout value of watchdog watchdog: s3c2410_wdt: Fix max_timeout being calculated larger watchdog: s3c2410_wdt: Replace hardcoded values with macro definitions watchdog: rzv2h: Improve error strings and add newlines watchdog: rzv2h: Add support for RZ/T2H watchdog: rzv2h: Add support for configurable count clock source watchdog: rzv2h: Make "oscclk" and reset controller optional watchdog: rzv2h: Obtain clock-divider and timeout values from OF match data dt-bindings: watchdog: renesas,wdt: Add support for RZ/T2H and RZ/N2H watchdog: intel_oc_wdt: Do not try to write into const memory
This commit is contained in:
@@ -81,10 +81,17 @@ properties:
|
||||
- renesas,r9a09g056-wdt # RZ/V2N
|
||||
- const: renesas,r9a09g057-wdt # RZ/V2H(P)
|
||||
|
||||
- const: renesas,r9a09g057-wdt # RZ/V2H(P)
|
||||
- enum:
|
||||
- renesas,r9a09g057-wdt # RZ/V2H(P)
|
||||
- renesas,r9a09g077-wdt # RZ/T2H
|
||||
|
||||
- items:
|
||||
- const: renesas,r9a09g087-wdt # RZ/N2H
|
||||
- const: renesas,r9a09g077-wdt # RZ/T2H
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
@@ -132,6 +139,7 @@ allOf:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,r9a09g077-wdt
|
||||
- renesas,rza-wdt
|
||||
- renesas,rzn1-wdt
|
||||
then:
|
||||
@@ -183,7 +191,9 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,r9a09g057-wdt
|
||||
enum:
|
||||
- renesas,r9a09g057-wdt
|
||||
- renesas,r9a09g077-wdt
|
||||
then:
|
||||
properties:
|
||||
interrupts: false
|
||||
@@ -192,6 +202,26 @@ allOf:
|
||||
required:
|
||||
- interrupts
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,r9a09g077-wdt
|
||||
then:
|
||||
properties:
|
||||
resets: false
|
||||
clock-names:
|
||||
maxItems: 1
|
||||
reg:
|
||||
minItems: 2
|
||||
required:
|
||||
- clock-names
|
||||
- power-domains
|
||||
else:
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
||||
@@ -10961,7 +10961,7 @@ S: Supported
|
||||
F: drivers/misc/hpilo.[ch]
|
||||
|
||||
HEWLETT PACKARD ENTERPRISE ILO NMI WATCHDOG DRIVER
|
||||
M: Jerry Hoemann <jerry.hoemann@hpe.com>
|
||||
M: Craig Lamparter <craig.lamparter@hpe.com>
|
||||
S: Supported
|
||||
F: Documentation/watchdog/hpwdt.rst
|
||||
F: drivers/watchdog/hpwdt.c
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
struct intel_oc_wdt {
|
||||
struct watchdog_device wdd;
|
||||
struct resource *ctrl_res;
|
||||
struct watchdog_info info;
|
||||
bool locked;
|
||||
};
|
||||
|
||||
@@ -115,7 +116,6 @@ static const struct watchdog_ops intel_oc_wdt_ops = {
|
||||
|
||||
static int intel_oc_wdt_setup(struct intel_oc_wdt *oc_wdt)
|
||||
{
|
||||
struct watchdog_info *info;
|
||||
unsigned long val;
|
||||
|
||||
val = inl(INTEL_OC_WDT_CTRL_REG(oc_wdt));
|
||||
@@ -134,7 +134,6 @@ static int intel_oc_wdt_setup(struct intel_oc_wdt *oc_wdt)
|
||||
set_bit(WDOG_HW_RUNNING, &oc_wdt->wdd.status);
|
||||
|
||||
if (oc_wdt->locked) {
|
||||
info = (struct watchdog_info *)&intel_oc_wdt_info;
|
||||
/*
|
||||
* Set nowayout unconditionally as we cannot stop
|
||||
* the watchdog.
|
||||
@@ -145,7 +144,7 @@ static int intel_oc_wdt_setup(struct intel_oc_wdt *oc_wdt)
|
||||
* and inform the core we can't change it.
|
||||
*/
|
||||
oc_wdt->wdd.timeout = (val & INTEL_OC_WDT_TOV) + 1;
|
||||
info->options &= ~WDIOF_SETTIMEOUT;
|
||||
oc_wdt->info.options &= ~WDIOF_SETTIMEOUT;
|
||||
|
||||
dev_info(oc_wdt->wdd.parent,
|
||||
"Register access locked, heartbeat fixed at: %u s\n",
|
||||
@@ -193,7 +192,8 @@ static int intel_oc_wdt_probe(struct platform_device *pdev)
|
||||
wdd->min_timeout = INTEL_OC_WDT_MIN_TOV;
|
||||
wdd->max_timeout = INTEL_OC_WDT_MAX_TOV;
|
||||
wdd->timeout = INTEL_OC_WDT_DEF_TOV;
|
||||
wdd->info = &intel_oc_wdt_info;
|
||||
oc_wdt->info = intel_oc_wdt_info;
|
||||
wdd->info = &oc_wdt->info;
|
||||
wdd->ops = &intel_oc_wdt_ops;
|
||||
wdd->parent = dev;
|
||||
|
||||
|
||||
@@ -100,6 +100,8 @@ static int mpc8xxx_wdt_start(struct watchdog_device *w)
|
||||
ddata->swtc = tmp >> 16;
|
||||
set_bit(WDOG_HW_RUNNING, &ddata->wdd.status);
|
||||
|
||||
mpc8xxx_wdt_keepalive(ddata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -310,9 +310,7 @@ static int rzg2l_wdt_probe(struct platform_device *pdev)
|
||||
watchdog_set_nowayout(&priv->wdev, nowayout);
|
||||
watchdog_stop_on_unregister(&priv->wdev);
|
||||
|
||||
ret = watchdog_init_timeout(&priv->wdev, 0, dev);
|
||||
if (ret)
|
||||
dev_warn(dev, "Specified timeout invalid, using default");
|
||||
watchdog_init_timeout(&priv->wdev, 0, dev);
|
||||
|
||||
return devm_watchdog_register_device(&pdev->dev, &priv->wdev);
|
||||
}
|
||||
|
||||
@@ -21,11 +21,17 @@
|
||||
#define WDTSR 0x04 /* WDT Status Register RW, 16 */
|
||||
#define WDTRCR 0x06 /* WDT Reset Control Register RW, 8 */
|
||||
|
||||
/* This register is only available on RZ/T2H and RZ/N2H SoCs */
|
||||
#define WDTDCR 0x00 /* WDT Debug Control Register RW, 32 */
|
||||
|
||||
#define WDTCR_TOPS_1024 0x00
|
||||
#define WDTCR_TOPS_4096 0x01
|
||||
#define WDTCR_TOPS_16384 0x03
|
||||
|
||||
#define WDTCR_CKS_CLK_1 0x00
|
||||
#define WDTCR_CKS_CLK_4 0x10
|
||||
#define WDTCR_CKS_CLK_256 0x50
|
||||
#define WDTCR_CKS_CLK_8192 0x80
|
||||
|
||||
#define WDTCR_RPES_0 0x300
|
||||
#define WDTCR_RPES_75 0x000
|
||||
@@ -35,8 +41,7 @@
|
||||
|
||||
#define WDTRCR_RSTIRQS BIT(7)
|
||||
|
||||
#define MAX_TIMEOUT_CYCLES 16384
|
||||
#define CLOCK_DIV_BY_256 256
|
||||
#define WDTDCR_WDTSTOPCTRL BIT(0)
|
||||
|
||||
#define WDT_DEFAULT_TIMEOUT 60U
|
||||
|
||||
@@ -45,12 +50,29 @@ module_param(nowayout, bool, 0);
|
||||
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
|
||||
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
|
||||
|
||||
enum rzv2h_wdt_count_source {
|
||||
COUNT_SOURCE_LOCO,
|
||||
COUNT_SOURCE_PCLK,
|
||||
};
|
||||
|
||||
struct rzv2h_of_data {
|
||||
u8 cks_min;
|
||||
u8 cks_max;
|
||||
u16 cks_div;
|
||||
u8 tops;
|
||||
u16 timeout_cycles;
|
||||
enum rzv2h_wdt_count_source count_source;
|
||||
bool wdtdcr;
|
||||
};
|
||||
|
||||
struct rzv2h_wdt_priv {
|
||||
void __iomem *base;
|
||||
void __iomem *wdtdcr;
|
||||
struct clk *pclk;
|
||||
struct clk *oscclk;
|
||||
struct reset_control *rstc;
|
||||
struct watchdog_device wdev;
|
||||
const struct rzv2h_of_data *of_data;
|
||||
};
|
||||
|
||||
static int rzv2h_wdt_ping(struct watchdog_device *wdev)
|
||||
@@ -67,6 +89,20 @@ static int rzv2h_wdt_ping(struct watchdog_device *wdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rzt2h_wdt_wdtdcr_count_stop(struct rzv2h_wdt_priv *priv)
|
||||
{
|
||||
u32 reg = readl(priv->wdtdcr + WDTDCR);
|
||||
|
||||
writel(reg | WDTDCR_WDTSTOPCTRL, priv->wdtdcr + WDTDCR);
|
||||
}
|
||||
|
||||
static void rzt2h_wdt_wdtdcr_count_start(struct rzv2h_wdt_priv *priv)
|
||||
{
|
||||
u32 reg = readl(priv->wdtdcr + WDTDCR);
|
||||
|
||||
writel(reg & ~WDTDCR_WDTSTOPCTRL, priv->wdtdcr + WDTDCR);
|
||||
}
|
||||
|
||||
static void rzv2h_wdt_setup(struct watchdog_device *wdev, u16 wdtcr)
|
||||
{
|
||||
struct rzv2h_wdt_priv *priv = watchdog_get_drvdata(wdev);
|
||||
@@ -84,6 +120,7 @@ static void rzv2h_wdt_setup(struct watchdog_device *wdev, u16 wdtcr)
|
||||
static int rzv2h_wdt_start(struct watchdog_device *wdev)
|
||||
{
|
||||
struct rzv2h_wdt_priv *priv = watchdog_get_drvdata(wdev);
|
||||
const struct rzv2h_of_data *of_data = priv->of_data;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(wdev->parent);
|
||||
@@ -101,13 +138,20 @@ static int rzv2h_wdt_start(struct watchdog_device *wdev)
|
||||
|
||||
/*
|
||||
* WDTCR
|
||||
* - CKS[7:4] - Clock Division Ratio Select - 0101b: oscclk/256
|
||||
* - CKS[7:4] - Clock Division Ratio Select
|
||||
* - 0101b: oscclk/256 for RZ/V2H(P)
|
||||
* - 1000b: pclkl/8192 for RZ/T2H
|
||||
* - RPSS[13:12] - Window Start Position Select - 11b: 100%
|
||||
* - RPES[9:8] - Window End Position Select - 11b: 0%
|
||||
* - TOPS[1:0] - Timeout Period Select - 11b: 16384 cycles (3FFFh)
|
||||
* - TOPS[1:0] - Timeout Period Select
|
||||
* - 11b: 16384 cycles (3FFFh) for RZ/V2H(P)
|
||||
* - 01b: 4096 cycles (0FFFh) for RZ/T2H
|
||||
*/
|
||||
rzv2h_wdt_setup(wdev, WDTCR_CKS_CLK_256 | WDTCR_RPSS_100 |
|
||||
WDTCR_RPES_0 | WDTCR_TOPS_16384);
|
||||
rzv2h_wdt_setup(wdev, of_data->cks_max | WDTCR_RPSS_100 |
|
||||
WDTCR_RPES_0 | of_data->tops);
|
||||
|
||||
if (priv->of_data->wdtdcr)
|
||||
rzt2h_wdt_wdtdcr_count_start(priv);
|
||||
|
||||
/*
|
||||
* Down counting starts after writing the sequence 00h -> FFh to the
|
||||
@@ -127,6 +171,9 @@ static int rzv2h_wdt_stop(struct watchdog_device *wdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (priv->of_data->wdtdcr)
|
||||
rzt2h_wdt_wdtdcr_count_stop(priv);
|
||||
|
||||
ret = pm_runtime_put(wdev->parent);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -179,14 +226,19 @@ static int rzv2h_wdt_restart(struct watchdog_device *wdev,
|
||||
|
||||
/*
|
||||
* WDTCR
|
||||
* - CKS[7:4] - Clock Division Ratio Select - 0000b: oscclk/1
|
||||
* - CKS[7:4] - Clock Division Ratio Select
|
||||
* - 0000b: oscclk/1 for RZ/V2H(P)
|
||||
* - 0100b: pclkl/4 for RZ/T2H
|
||||
* - RPSS[13:12] - Window Start Position Select - 00b: 25%
|
||||
* - RPES[9:8] - Window End Position Select - 00b: 75%
|
||||
* - TOPS[1:0] - Timeout Period Select - 00b: 1024 cycles (03FFh)
|
||||
*/
|
||||
rzv2h_wdt_setup(wdev, WDTCR_CKS_CLK_1 | WDTCR_RPSS_25 |
|
||||
rzv2h_wdt_setup(wdev, priv->of_data->cks_min | WDTCR_RPSS_25 |
|
||||
WDTCR_RPES_75 | WDTCR_TOPS_1024);
|
||||
|
||||
if (priv->of_data->wdtdcr)
|
||||
rzt2h_wdt_wdtdcr_count_start(priv);
|
||||
|
||||
rzv2h_wdt_ping(wdev);
|
||||
|
||||
/* wait for underflow to trigger... */
|
||||
@@ -203,41 +255,83 @@ static const struct watchdog_ops rzv2h_wdt_ops = {
|
||||
.restart = rzv2h_wdt_restart,
|
||||
};
|
||||
|
||||
static int rzt2h_wdt_wdtdcr_init(struct platform_device *pdev,
|
||||
struct rzv2h_wdt_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
priv->wdtdcr = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (IS_ERR(priv->wdtdcr))
|
||||
return PTR_ERR(priv->wdtdcr);
|
||||
|
||||
ret = pm_runtime_resume_and_get(&pdev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rzt2h_wdt_wdtdcr_count_stop(priv);
|
||||
|
||||
ret = pm_runtime_put(&pdev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rzv2h_wdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rzv2h_wdt_priv *priv;
|
||||
struct clk *count_clk;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->of_data = of_device_get_match_data(dev);
|
||||
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
|
||||
priv->pclk = devm_clk_get_prepared(dev, "pclk");
|
||||
if (IS_ERR(priv->pclk))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->pclk), "no pclk");
|
||||
return dev_err_probe(dev, PTR_ERR(priv->pclk), "Failed to get pclk\n");
|
||||
|
||||
priv->oscclk = devm_clk_get_prepared(dev, "oscclk");
|
||||
priv->oscclk = devm_clk_get_optional_prepared(dev, "oscclk");
|
||||
if (IS_ERR(priv->oscclk))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->oscclk), "no oscclk");
|
||||
return dev_err_probe(dev, PTR_ERR(priv->oscclk), "Failed to get oscclk\n");
|
||||
|
||||
priv->rstc = devm_reset_control_get_exclusive(dev, NULL);
|
||||
priv->rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
|
||||
if (IS_ERR(priv->rstc))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->rstc),
|
||||
"failed to get cpg reset");
|
||||
"Failed to get cpg reset\n");
|
||||
|
||||
priv->wdev.max_hw_heartbeat_ms = (MILLI * MAX_TIMEOUT_CYCLES * CLOCK_DIV_BY_256) /
|
||||
clk_get_rate(priv->oscclk);
|
||||
switch (priv->of_data->count_source) {
|
||||
case COUNT_SOURCE_LOCO:
|
||||
count_clk = priv->oscclk;
|
||||
break;
|
||||
case COUNT_SOURCE_PCLK:
|
||||
count_clk = priv->pclk;
|
||||
break;
|
||||
default:
|
||||
return dev_err_probe(dev, -EINVAL, "Invalid count source\n");
|
||||
}
|
||||
|
||||
priv->wdev.max_hw_heartbeat_ms = (MILLI * priv->of_data->timeout_cycles *
|
||||
priv->of_data->cks_div) / clk_get_rate(count_clk);
|
||||
dev_dbg(dev, "max hw timeout of %dms\n", priv->wdev.max_hw_heartbeat_ms);
|
||||
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (priv->of_data->wdtdcr) {
|
||||
ret = rzt2h_wdt_wdtdcr_init(pdev, priv);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "WDTDCR init failed\n");
|
||||
}
|
||||
|
||||
priv->wdev.min_timeout = 1;
|
||||
priv->wdev.timeout = WDT_DEFAULT_TIMEOUT;
|
||||
priv->wdev.info = &rzv2h_wdt_ident;
|
||||
@@ -247,15 +341,33 @@ static int rzv2h_wdt_probe(struct platform_device *pdev)
|
||||
watchdog_set_nowayout(&priv->wdev, nowayout);
|
||||
watchdog_stop_on_unregister(&priv->wdev);
|
||||
|
||||
ret = watchdog_init_timeout(&priv->wdev, 0, dev);
|
||||
if (ret)
|
||||
dev_warn(dev, "Specified timeout invalid, using default");
|
||||
watchdog_init_timeout(&priv->wdev, 0, dev);
|
||||
|
||||
return devm_watchdog_register_device(dev, &priv->wdev);
|
||||
}
|
||||
|
||||
static const struct rzv2h_of_data rzt2h_wdt_of_data = {
|
||||
.cks_min = WDTCR_CKS_CLK_4,
|
||||
.cks_max = WDTCR_CKS_CLK_8192,
|
||||
.cks_div = 8192,
|
||||
.tops = WDTCR_TOPS_4096,
|
||||
.timeout_cycles = 4096,
|
||||
.count_source = COUNT_SOURCE_PCLK,
|
||||
.wdtdcr = true,
|
||||
};
|
||||
|
||||
static const struct rzv2h_of_data rzv2h_wdt_of_data = {
|
||||
.cks_min = WDTCR_CKS_CLK_1,
|
||||
.cks_max = WDTCR_CKS_CLK_256,
|
||||
.cks_div = 256,
|
||||
.tops = WDTCR_TOPS_16384,
|
||||
.timeout_cycles = 16384,
|
||||
.count_source = COUNT_SOURCE_LOCO,
|
||||
};
|
||||
|
||||
static const struct of_device_id rzv2h_wdt_ids[] = {
|
||||
{ .compatible = "renesas,r9a09g057-wdt", },
|
||||
{ .compatible = "renesas,r9a09g057-wdt", .data = &rzv2h_wdt_of_data },
|
||||
{ .compatible = "renesas,r9a09g077-wdt", .data = &rzt2h_wdt_of_data },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rzv2h_wdt_ids);
|
||||
|
||||
@@ -27,13 +27,15 @@
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/math64.h>
|
||||
|
||||
#define S3C2410_WTCON 0x00
|
||||
#define S3C2410_WTDAT 0x04
|
||||
#define S3C2410_WTCNT 0x08
|
||||
#define S3C2410_WTCLRINT 0x0c
|
||||
|
||||
#define S3C2410_WTCNT_MAXCNT 0xffff
|
||||
#define S3C2410_WTCNT_MAXCNT_16 0xffff
|
||||
#define S3C2410_WTCNT_MAXCNT_32 0xffffffff
|
||||
|
||||
#define S3C2410_WTCON_RSTEN BIT(0)
|
||||
#define S3C2410_WTCON_INTEN BIT(2)
|
||||
@@ -123,6 +125,10 @@
|
||||
* %QUIRK_HAS_DBGACK_BIT: WTCON register has DBGACK_MASK bit. Setting the
|
||||
* DBGACK_MASK bit disables the watchdog outputs when the SoC is in debug mode.
|
||||
* Debug mode is determined by the DBGACK CPU signal.
|
||||
*
|
||||
* %QUIRK_HAS_32BIT_CNT: WTDAT and WTCNT are 32-bit registers. With these
|
||||
* 32-bit registers, larger values will be set, which means that larger timeouts
|
||||
* value can be set.
|
||||
*/
|
||||
#define QUIRK_HAS_WTCLRINT_REG BIT(0)
|
||||
#define QUIRK_HAS_PMU_MASK_RESET BIT(1)
|
||||
@@ -130,6 +136,7 @@
|
||||
#define QUIRK_HAS_PMU_AUTO_DISABLE BIT(3)
|
||||
#define QUIRK_HAS_PMU_CNT_EN BIT(4)
|
||||
#define QUIRK_HAS_DBGACK_BIT BIT(5)
|
||||
#define QUIRK_HAS_32BIT_CNT BIT(6)
|
||||
|
||||
/* These quirks require that we have a PMU register map */
|
||||
#define QUIRKS_HAVE_PMUREG \
|
||||
@@ -198,6 +205,7 @@ struct s3c2410_wdt {
|
||||
struct notifier_block freq_transition;
|
||||
const struct s3c2410_wdt_variant *drv_data;
|
||||
struct regmap *pmureg;
|
||||
u32 max_cnt;
|
||||
};
|
||||
|
||||
static const struct s3c2410_wdt_variant drv_data_s3c2410 = {
|
||||
@@ -298,7 +306,8 @@ static const struct s3c2410_wdt_variant drv_data_exynosautov9_cl0 = {
|
||||
.cnt_en_reg = EXYNOS850_CLUSTER0_NONCPU_OUT,
|
||||
.cnt_en_bit = 7,
|
||||
.quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET |
|
||||
QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN,
|
||||
QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN |
|
||||
QUIRK_HAS_DBGACK_BIT | QUIRK_HAS_32BIT_CNT,
|
||||
};
|
||||
|
||||
static const struct s3c2410_wdt_variant drv_data_exynosautov9_cl1 = {
|
||||
@@ -310,7 +319,8 @@ static const struct s3c2410_wdt_variant drv_data_exynosautov9_cl1 = {
|
||||
.cnt_en_reg = EXYNOSAUTOV9_CLUSTER1_NONCPU_OUT,
|
||||
.cnt_en_bit = 7,
|
||||
.quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET |
|
||||
QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN,
|
||||
QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN |
|
||||
QUIRK_HAS_DBGACK_BIT | QUIRK_HAS_32BIT_CNT,
|
||||
};
|
||||
|
||||
static const struct s3c2410_wdt_variant drv_data_gs101_cl0 = {
|
||||
@@ -349,7 +359,7 @@ static const struct s3c2410_wdt_variant drv_data_exynosautov920_cl0 = {
|
||||
.cnt_en_bit = 8,
|
||||
.quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET |
|
||||
QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN |
|
||||
QUIRK_HAS_DBGACK_BIT,
|
||||
QUIRK_HAS_DBGACK_BIT | QUIRK_HAS_32BIT_CNT,
|
||||
};
|
||||
|
||||
static const struct s3c2410_wdt_variant drv_data_exynosautov920_cl1 = {
|
||||
@@ -362,7 +372,7 @@ static const struct s3c2410_wdt_variant drv_data_exynosautov920_cl1 = {
|
||||
.cnt_en_bit = 8,
|
||||
.quirks = QUIRK_HAS_WTCLRINT_REG | QUIRK_HAS_PMU_MASK_RESET |
|
||||
QUIRK_HAS_PMU_RST_STAT | QUIRK_HAS_PMU_CNT_EN |
|
||||
QUIRK_HAS_DBGACK_BIT,
|
||||
QUIRK_HAS_DBGACK_BIT | QUIRK_HAS_32BIT_CNT,
|
||||
};
|
||||
|
||||
static const struct of_device_id s3c2410_wdt_match[] = {
|
||||
@@ -410,9 +420,14 @@ static inline unsigned long s3c2410wdt_get_freq(struct s3c2410_wdt *wdt)
|
||||
static inline unsigned int s3c2410wdt_max_timeout(struct s3c2410_wdt *wdt)
|
||||
{
|
||||
const unsigned long freq = s3c2410wdt_get_freq(wdt);
|
||||
const u64 n_max = (u64)(S3C2410_WTCON_PRESCALE_MAX + 1) *
|
||||
S3C2410_WTCON_MAXDIV * wdt->max_cnt;
|
||||
u64 t_max = div64_ul(n_max, freq);
|
||||
|
||||
return S3C2410_WTCNT_MAXCNT / (freq / (S3C2410_WTCON_PRESCALE_MAX + 1)
|
||||
/ S3C2410_WTCON_MAXDIV);
|
||||
if (t_max > UINT_MAX)
|
||||
t_max = UINT_MAX;
|
||||
|
||||
return t_max;
|
||||
}
|
||||
|
||||
static int s3c2410wdt_disable_wdt_reset(struct s3c2410_wdt *wdt, bool mask)
|
||||
@@ -566,7 +581,7 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd,
|
||||
{
|
||||
struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
|
||||
unsigned long freq = s3c2410wdt_get_freq(wdt);
|
||||
unsigned int count;
|
||||
unsigned long count;
|
||||
unsigned int divisor = 1;
|
||||
unsigned long wtcon;
|
||||
|
||||
@@ -576,7 +591,7 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd,
|
||||
freq = DIV_ROUND_UP(freq, 128);
|
||||
count = timeout * freq;
|
||||
|
||||
dev_dbg(wdt->dev, "Heartbeat: count=%d, timeout=%d, freq=%lu\n",
|
||||
dev_dbg(wdt->dev, "Heartbeat: count=%lu, timeout=%d, freq=%lu\n",
|
||||
count, timeout, freq);
|
||||
|
||||
/* if the count is bigger than the watchdog register,
|
||||
@@ -584,16 +599,16 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd,
|
||||
actually make this value
|
||||
*/
|
||||
|
||||
if (count >= 0x10000) {
|
||||
divisor = DIV_ROUND_UP(count, 0xffff);
|
||||
if (count > wdt->max_cnt) {
|
||||
divisor = DIV_ROUND_UP(count, wdt->max_cnt);
|
||||
|
||||
if (divisor > 0x100) {
|
||||
if (divisor > S3C2410_WTCON_PRESCALE_MAX + 1) {
|
||||
dev_err(wdt->dev, "timeout %d too big\n", timeout);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(wdt->dev, "Heartbeat: timeout=%d, divisor=%d, count=%d (%08x)\n",
|
||||
dev_dbg(wdt->dev, "Heartbeat: timeout=%d, divisor=%d, count=%lu (%08lx)\n",
|
||||
timeout, divisor, count, DIV_ROUND_UP(count, divisor));
|
||||
|
||||
count = DIV_ROUND_UP(count, divisor);
|
||||
@@ -801,6 +816,11 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(wdt->src_clk))
|
||||
return dev_err_probe(dev, PTR_ERR(wdt->src_clk), "failed to get source clock\n");
|
||||
|
||||
if (wdt->drv_data->quirks & QUIRK_HAS_32BIT_CNT)
|
||||
wdt->max_cnt = S3C2410_WTCNT_MAXCNT_32;
|
||||
else
|
||||
wdt->max_cnt = S3C2410_WTCNT_MAXCNT_16;
|
||||
|
||||
wdt->wdt_device.min_timeout = 1;
|
||||
wdt->wdt_device.max_timeout = s3c2410wdt_max_timeout(wdt);
|
||||
|
||||
|
||||
@@ -118,7 +118,6 @@ static int visconti_wdt_probe(struct platform_device *pdev)
|
||||
struct visconti_wdt_priv *priv;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
unsigned long clk_freq;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
@@ -153,9 +152,7 @@ static int visconti_wdt_probe(struct platform_device *pdev)
|
||||
watchdog_stop_on_unregister(wdev);
|
||||
|
||||
/* This overrides the default timeout only if DT configuration was found */
|
||||
ret = watchdog_init_timeout(wdev, 0, dev);
|
||||
if (ret)
|
||||
dev_warn(dev, "Specified timeout value invalid, using default\n");
|
||||
watchdog_init_timeout(wdev, 0, dev);
|
||||
|
||||
return devm_watchdog_register_device(dev, wdev);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user