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
...@@ -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