Commit b2eed733 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'linux-watchdog-6.11-rc1' of git://www.linux-watchdog.org/linux-watchdog

Pull watchdog updates from Wim Van Sebroeck:

 - make watchdog_class const

 - rework of the rzg2l_wdt driver

 - other small fixes and improvements

* tag 'linux-watchdog-6.11-rc1' of git://www.linux-watchdog.org/linux-watchdog:
  dt-bindings: watchdog: dlg,da9062-watchdog: Drop blank space
  watchdog: rzn1: Convert comma to semicolon
  watchdog: lenovo_se10_wdt: Convert comma to semicolon
  dt-bindings: watchdog: renesas,wdt: Document RZ/G3S support
  watchdog: rzg2l_wdt: Add suspend/resume support
  watchdog: rzg2l_wdt: Rely on the reset driver for doing proper reset
  watchdog: rzg2l_wdt: Remove comparison with zero
  watchdog: rzg2l_wdt: Remove reset de-assert from probe
  watchdog: rzg2l_wdt: Check return status of pm_runtime_put()
  watchdog: rzg2l_wdt: Use pm_runtime_resume_and_get()
  watchdog: rzg2l_wdt: Make the driver depend on PM
  watchdog: rzg2l_wdt: Restrict the driver to ARCH_RZG2L and ARCH_R9A09G011
  watchdog: imx7ulp_wdt: keep already running watchdog enabled
  watchdog: starfive: Add missing clk_disable_unprepare()
  watchdog: Make watchdog_class const
parents 9cf601e8 63d097d4
...@@ -28,7 +28,7 @@ properties: ...@@ -28,7 +28,7 @@ properties:
Add this property to disable the watchdog during suspend. Add this property to disable the watchdog during suspend.
Only use this option if you can't use the watchdog automatic suspend Only use this option if you can't use the watchdog automatic suspend
function during a suspend (see register CONTROL_B). function during a suspend (see register CONTROL_B).
dlg,wdt-sd: dlg,wdt-sd:
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1] enum: [0, 1]
......
...@@ -29,6 +29,7 @@ properties: ...@@ -29,6 +29,7 @@ properties:
- renesas,r9a07g043-wdt # RZ/G2UL and RZ/Five - renesas,r9a07g043-wdt # RZ/G2UL and RZ/Five
- renesas,r9a07g044-wdt # RZ/G2{L,LC} - renesas,r9a07g044-wdt # RZ/G2{L,LC}
- renesas,r9a07g054-wdt # RZ/V2L - renesas,r9a07g054-wdt # RZ/V2L
- renesas,r9a08g045-wdt # RZ/G3S
- const: renesas,rzg2l-wdt - const: renesas,rzg2l-wdt
- items: - items:
......
...@@ -946,7 +946,8 @@ config RENESAS_RZN1WDT ...@@ -946,7 +946,8 @@ config RENESAS_RZN1WDT
config RENESAS_RZG2LWDT config RENESAS_RZG2LWDT
tristate "Renesas RZ/G2L WDT Watchdog" tristate "Renesas RZ/G2L WDT Watchdog"
depends on ARCH_RENESAS || COMPILE_TEST depends on ARCH_RZG2L || ARCH_R9A09G011 || COMPILE_TEST
depends on PM || COMPILE_TEST
select WATCHDOG_CORE select WATCHDOG_CORE
help help
This driver adds watchdog support for the integrated watchdogs in the This driver adds watchdog support for the integrated watchdogs in the
......
...@@ -290,6 +290,11 @@ static int imx7ulp_wdt_init(struct imx7ulp_wdt_device *wdt, unsigned int timeout ...@@ -290,6 +290,11 @@ static int imx7ulp_wdt_init(struct imx7ulp_wdt_device *wdt, unsigned int timeout
if (wdt->ext_reset) if (wdt->ext_reset)
val |= WDOG_CS_INT_EN; val |= WDOG_CS_INT_EN;
if (readl(wdt->base + WDOG_CS) & WDOG_CS_EN) {
set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
val |= WDOG_CS_EN;
}
do { do {
ret = _imx7ulp_wdt_init(wdt, timeout, val); ret = _imx7ulp_wdt_init(wdt, timeout, val);
toval = readl(wdt->base + WDOG_TOVAL); toval = readl(wdt->base + WDOG_TOVAL);
......
...@@ -196,8 +196,8 @@ static int se10_wdt_probe(struct platform_device *pdev) ...@@ -196,8 +196,8 @@ static int se10_wdt_probe(struct platform_device *pdev)
watchdog_set_drvdata(&priv->wdd, priv); watchdog_set_drvdata(&priv->wdd, priv);
priv->wdd.parent = dev; priv->wdd.parent = dev;
priv->wdd.info = &wdt_info, priv->wdd.info = &wdt_info;
priv->wdd.ops = &se10_wdt_ops, priv->wdd.ops = &se10_wdt_ops;
priv->wdd.timeout = WATCHDOG_TIMEOUT; /* Set default timeout */ priv->wdd.timeout = WATCHDOG_TIMEOUT; /* Set default timeout */
priv->wdd.min_timeout = MIN_TIMEOUT; priv->wdd.min_timeout = MIN_TIMEOUT;
priv->wdd.max_timeout = MAX_TIMEOUT; priv->wdd.max_timeout = MAX_TIMEOUT;
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -54,35 +53,11 @@ struct rzg2l_wdt_priv { ...@@ -54,35 +53,11 @@ struct rzg2l_wdt_priv {
struct reset_control *rstc; struct reset_control *rstc;
unsigned long osc_clk_rate; unsigned long osc_clk_rate;
unsigned long delay; unsigned long delay;
unsigned long minimum_assertion_period;
struct clk *pclk; struct clk *pclk;
struct clk *osc_clk; struct clk *osc_clk;
enum rz_wdt_type devtype; enum rz_wdt_type devtype;
}; };
static int rzg2l_wdt_reset(struct rzg2l_wdt_priv *priv)
{
int err, status;
if (priv->devtype == WDT_RZV2M) {
/* WDT needs TYPE-B reset control */
err = reset_control_assert(priv->rstc);
if (err)
return err;
ndelay(priv->minimum_assertion_period);
err = reset_control_deassert(priv->rstc);
if (err)
return err;
err = read_poll_timeout(reset_control_status, status,
status != 1, 0, 1000, false,
priv->rstc);
} else {
err = reset_control_reset(priv->rstc);
}
return err;
}
static void rzg2l_wdt_wait_delay(struct rzg2l_wdt_priv *priv) static void rzg2l_wdt_wait_delay(struct rzg2l_wdt_priv *priv)
{ {
/* delay timer when change the setting register */ /* delay timer when change the setting register */
...@@ -123,8 +98,17 @@ static void rzg2l_wdt_init_timeout(struct watchdog_device *wdev) ...@@ -123,8 +98,17 @@ static void rzg2l_wdt_init_timeout(struct watchdog_device *wdev)
static int rzg2l_wdt_start(struct watchdog_device *wdev) static int rzg2l_wdt_start(struct watchdog_device *wdev)
{ {
struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev); struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);
int ret;
pm_runtime_get_sync(wdev->parent); ret = pm_runtime_resume_and_get(wdev->parent);
if (ret)
return ret;
ret = reset_control_deassert(priv->rstc);
if (ret) {
pm_runtime_put(wdev->parent);
return ret;
}
/* Initialize time out */ /* Initialize time out */
rzg2l_wdt_init_timeout(wdev); rzg2l_wdt_init_timeout(wdev);
...@@ -141,15 +125,23 @@ static int rzg2l_wdt_start(struct watchdog_device *wdev) ...@@ -141,15 +125,23 @@ static int rzg2l_wdt_start(struct watchdog_device *wdev)
static int rzg2l_wdt_stop(struct watchdog_device *wdev) static int rzg2l_wdt_stop(struct watchdog_device *wdev)
{ {
struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev); struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);
int ret;
rzg2l_wdt_reset(priv); ret = reset_control_assert(priv->rstc);
pm_runtime_put(wdev->parent); if (ret)
return ret;
ret = pm_runtime_put(wdev->parent);
if (ret < 0)
return ret;
return 0; return 0;
} }
static int rzg2l_wdt_set_timeout(struct watchdog_device *wdev, unsigned int timeout) static int rzg2l_wdt_set_timeout(struct watchdog_device *wdev, unsigned int timeout)
{ {
int ret = 0;
wdev->timeout = timeout; wdev->timeout = timeout;
/* /*
...@@ -158,22 +150,30 @@ static int rzg2l_wdt_set_timeout(struct watchdog_device *wdev, unsigned int time ...@@ -158,22 +150,30 @@ static int rzg2l_wdt_set_timeout(struct watchdog_device *wdev, unsigned int time
* to reset the module) so that it is updated with new timeout values. * to reset the module) so that it is updated with new timeout values.
*/ */
if (watchdog_active(wdev)) { if (watchdog_active(wdev)) {
rzg2l_wdt_stop(wdev); ret = rzg2l_wdt_stop(wdev);
rzg2l_wdt_start(wdev); if (ret)
return ret;
ret = rzg2l_wdt_start(wdev);
} }
return 0; return ret;
} }
static int rzg2l_wdt_restart(struct watchdog_device *wdev, static int rzg2l_wdt_restart(struct watchdog_device *wdev,
unsigned long action, void *data) unsigned long action, void *data)
{ {
struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev); struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);
int ret;
clk_prepare_enable(priv->pclk); clk_prepare_enable(priv->pclk);
clk_prepare_enable(priv->osc_clk); clk_prepare_enable(priv->osc_clk);
if (priv->devtype == WDT_RZG2L) { if (priv->devtype == WDT_RZG2L) {
ret = reset_control_deassert(priv->rstc);
if (ret)
return ret;
/* Generate Reset (WDTRSTB) Signal on parity error */ /* Generate Reset (WDTRSTB) Signal on parity error */
rzg2l_wdt_write(priv, 0, PECR); rzg2l_wdt_write(priv, 0, PECR);
...@@ -181,7 +181,9 @@ static int rzg2l_wdt_restart(struct watchdog_device *wdev, ...@@ -181,7 +181,9 @@ static int rzg2l_wdt_restart(struct watchdog_device *wdev,
rzg2l_wdt_write(priv, PEEN_FORCE, PEEN); rzg2l_wdt_write(priv, PEEN_FORCE, PEEN);
} else { } else {
/* RZ/V2M doesn't have parity error registers */ /* RZ/V2M doesn't have parity error registers */
rzg2l_wdt_reset(priv); ret = reset_control_reset(priv->rstc);
if (ret)
return ret;
wdev->timeout = 0; wdev->timeout = 0;
...@@ -224,13 +226,11 @@ static const struct watchdog_ops rzg2l_wdt_ops = { ...@@ -224,13 +226,11 @@ static const struct watchdog_ops rzg2l_wdt_ops = {
.restart = rzg2l_wdt_restart, .restart = rzg2l_wdt_restart,
}; };
static void rzg2l_wdt_reset_assert_pm_disable(void *data) static void rzg2l_wdt_pm_disable(void *data)
{ {
struct watchdog_device *wdev = data; struct watchdog_device *wdev = data;
struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);
pm_runtime_disable(wdev->parent); pm_runtime_disable(wdev->parent);
reset_control_assert(priv->rstc);
} }
static int rzg2l_wdt_probe(struct platform_device *pdev) static int rzg2l_wdt_probe(struct platform_device *pdev)
...@@ -273,19 +273,8 @@ static int rzg2l_wdt_probe(struct platform_device *pdev) ...@@ -273,19 +273,8 @@ static int rzg2l_wdt_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, PTR_ERR(priv->rstc), return dev_err_probe(&pdev->dev, PTR_ERR(priv->rstc),
"failed to get cpg reset"); "failed to get cpg reset");
ret = reset_control_deassert(priv->rstc);
if (ret)
return dev_err_probe(dev, ret, "failed to deassert");
priv->devtype = (uintptr_t)of_device_get_match_data(dev); priv->devtype = (uintptr_t)of_device_get_match_data(dev);
if (priv->devtype == WDT_RZV2M) {
priv->minimum_assertion_period = RZV2M_A_NSEC +
3 * F2CYCLE_NSEC(pclk_rate) + 5 *
max(F2CYCLE_NSEC(priv->osc_clk_rate),
F2CYCLE_NSEC(pclk_rate));
}
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
priv->wdev.info = &rzg2l_wdt_ident; priv->wdev.info = &rzg2l_wdt_ident;
...@@ -297,10 +286,9 @@ static int rzg2l_wdt_probe(struct platform_device *pdev) ...@@ -297,10 +286,9 @@ static int rzg2l_wdt_probe(struct platform_device *pdev)
priv->wdev.timeout = WDT_DEFAULT_TIMEOUT; priv->wdev.timeout = WDT_DEFAULT_TIMEOUT;
watchdog_set_drvdata(&priv->wdev, priv); watchdog_set_drvdata(&priv->wdev, priv);
ret = devm_add_action_or_reset(&pdev->dev, dev_set_drvdata(dev, priv);
rzg2l_wdt_reset_assert_pm_disable, ret = devm_add_action_or_reset(&pdev->dev, rzg2l_wdt_pm_disable, &priv->wdev);
&priv->wdev); if (ret)
if (ret < 0)
return ret; return ret;
watchdog_set_nowayout(&priv->wdev, nowayout); watchdog_set_nowayout(&priv->wdev, nowayout);
...@@ -320,10 +308,35 @@ static const struct of_device_id rzg2l_wdt_ids[] = { ...@@ -320,10 +308,35 @@ static const struct of_device_id rzg2l_wdt_ids[] = {
}; };
MODULE_DEVICE_TABLE(of, rzg2l_wdt_ids); MODULE_DEVICE_TABLE(of, rzg2l_wdt_ids);
static int rzg2l_wdt_suspend_late(struct device *dev)
{
struct rzg2l_wdt_priv *priv = dev_get_drvdata(dev);
if (!watchdog_active(&priv->wdev))
return 0;
return rzg2l_wdt_stop(&priv->wdev);
}
static int rzg2l_wdt_resume_early(struct device *dev)
{
struct rzg2l_wdt_priv *priv = dev_get_drvdata(dev);
if (!watchdog_active(&priv->wdev))
return 0;
return rzg2l_wdt_start(&priv->wdev);
}
static const struct dev_pm_ops rzg2l_wdt_pm_ops = {
LATE_SYSTEM_SLEEP_PM_OPS(rzg2l_wdt_suspend_late, rzg2l_wdt_resume_early)
};
static struct platform_driver rzg2l_wdt_driver = { static struct platform_driver rzg2l_wdt_driver = {
.driver = { .driver = {
.name = "rzg2l_wdt", .name = "rzg2l_wdt",
.of_match_table = rzg2l_wdt_ids, .of_match_table = rzg2l_wdt_ids,
.pm = &rzg2l_wdt_pm_ops,
}, },
.probe = rzg2l_wdt_probe, .probe = rzg2l_wdt_probe,
}; };
......
...@@ -140,9 +140,9 @@ static int rzn1_wdt_probe(struct platform_device *pdev) ...@@ -140,9 +140,9 @@ static int rzn1_wdt_probe(struct platform_device *pdev)
} }
wdt->clk_rate_khz = clk_rate / 1000; wdt->clk_rate_khz = clk_rate / 1000;
wdt->wdtdev.info = &rzn1_wdt_info, wdt->wdtdev.info = &rzn1_wdt_info;
wdt->wdtdev.ops = &rzn1_wdt_ops, wdt->wdtdev.ops = &rzn1_wdt_ops;
wdt->wdtdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS, wdt->wdtdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS;
wdt->wdtdev.parent = dev; wdt->wdtdev.parent = dev;
/* /*
* The period of the watchdog cannot be changed once set * The period of the watchdog cannot be changed once set
......
...@@ -152,8 +152,10 @@ static int starfive_wdt_enable_clock(struct starfive_wdt *wdt) ...@@ -152,8 +152,10 @@ static int starfive_wdt_enable_clock(struct starfive_wdt *wdt)
return dev_err_probe(wdt->wdd.parent, ret, "failed to enable apb clock\n"); return dev_err_probe(wdt->wdd.parent, ret, "failed to enable apb clock\n");
ret = clk_prepare_enable(wdt->core_clk); ret = clk_prepare_enable(wdt->core_clk);
if (ret) if (ret) {
clk_disable_unprepare(wdt->apb_clk);
return dev_err_probe(wdt->wdd.parent, ret, "failed to enable core clock\n"); return dev_err_probe(wdt->wdd.parent, ret, "failed to enable core clock\n");
}
return 0; return 0;
} }
......
...@@ -1004,7 +1004,7 @@ static struct miscdevice watchdog_miscdev = { ...@@ -1004,7 +1004,7 @@ static struct miscdevice watchdog_miscdev = {
.fops = &watchdog_fops, .fops = &watchdog_fops,
}; };
static struct class watchdog_class = { static const struct class watchdog_class = {
.name = "watchdog", .name = "watchdog",
.dev_groups = wdt_groups, .dev_groups = wdt_groups,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment