Commit b2eed733 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ properties:
              - renesas,r9a07g043-wdt    # RZ/G2UL and RZ/Five
              - renesas,r9a07g044-wdt    # RZ/G2{L,LC}
              - renesas,r9a07g054-wdt    # RZ/V2L
              - renesas,r9a08g045-wdt    # RZ/G3S
          - const: renesas,rzg2l-wdt

      - items:
+2 −1
Original line number Diff line number Diff line
@@ -946,7 +946,8 @@ config RENESAS_RZN1WDT

config RENESAS_RZG2LWDT
	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
	help
	  This driver adds watchdog support for the integrated watchdogs in the
+5 −0
Original line number Diff line number Diff line
@@ -290,6 +290,11 @@ static int imx7ulp_wdt_init(struct imx7ulp_wdt_device *wdt, unsigned int timeout
	if (wdt->ext_reset)
		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 {
		ret = _imx7ulp_wdt_init(wdt, timeout, val);
		toval = readl(wdt->base + WDOG_TOVAL);
+2 −2
Original line number Diff line number Diff line
@@ -196,8 +196,8 @@ static int se10_wdt_probe(struct platform_device *pdev)
	watchdog_set_drvdata(&priv->wdd, priv);

	priv->wdd.parent = dev;
	priv->wdd.info = &wdt_info,
	priv->wdd.ops = &se10_wdt_ops,
	priv->wdd.info = &wdt_info;
	priv->wdd.ops = &se10_wdt_ops;
	priv->wdd.timeout = WATCHDOG_TIMEOUT; /* Set default timeout */
	priv->wdd.min_timeout = MIN_TIMEOUT;
	priv->wdd.max_timeout = MAX_TIMEOUT;
+63 −50
Original line number Diff line number Diff line
@@ -8,7 +8,6 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -54,35 +53,11 @@ struct rzg2l_wdt_priv {
	struct reset_control *rstc;
	unsigned long osc_clk_rate;
	unsigned long delay;
	unsigned long minimum_assertion_period;
	struct clk *pclk;
	struct clk *osc_clk;
	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)
{
	/* delay timer when change the setting register */
@@ -123,8 +98,17 @@ static void rzg2l_wdt_init_timeout(struct watchdog_device *wdev)
static int rzg2l_wdt_start(struct watchdog_device *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 */
	rzg2l_wdt_init_timeout(wdev);
@@ -141,15 +125,23 @@ static int rzg2l_wdt_start(struct watchdog_device *wdev)
static int rzg2l_wdt_stop(struct watchdog_device *wdev)
{
	struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);
	int ret;

	rzg2l_wdt_reset(priv);
	pm_runtime_put(wdev->parent);
	ret = reset_control_assert(priv->rstc);
	if (ret)
		return ret;

	ret = pm_runtime_put(wdev->parent);
	if (ret < 0)
		return ret;

	return 0;
}

static int rzg2l_wdt_set_timeout(struct watchdog_device *wdev, unsigned int timeout)
{
	int ret = 0;

	wdev->timeout = timeout;

	/*
@@ -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.
	 */
	if (watchdog_active(wdev)) {
		rzg2l_wdt_stop(wdev);
		rzg2l_wdt_start(wdev);
		ret = rzg2l_wdt_stop(wdev);
		if (ret)
			return ret;

		ret = rzg2l_wdt_start(wdev);
	}

	return 0;
	return ret;
}

static int rzg2l_wdt_restart(struct watchdog_device *wdev,
			     unsigned long action, void *data)
{
	struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);
	int ret;

	clk_prepare_enable(priv->pclk);
	clk_prepare_enable(priv->osc_clk);

	if (priv->devtype == WDT_RZG2L) {
		ret = reset_control_deassert(priv->rstc);
		if (ret)
			return ret;

		/* Generate Reset (WDTRSTB) Signal on parity error */
		rzg2l_wdt_write(priv, 0, PECR);

@@ -181,7 +181,9 @@ static int rzg2l_wdt_restart(struct watchdog_device *wdev,
		rzg2l_wdt_write(priv, PEEN_FORCE, PEEN);
	} else {
		/* 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;

@@ -224,13 +226,11 @@ static const struct watchdog_ops rzg2l_wdt_ops = {
	.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 rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);

	pm_runtime_disable(wdev->parent);
	reset_control_assert(priv->rstc);
}

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),
				     "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);

	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);

	priv->wdev.info = &rzg2l_wdt_ident;
@@ -297,10 +286,9 @@ static int rzg2l_wdt_probe(struct platform_device *pdev)
	priv->wdev.timeout = WDT_DEFAULT_TIMEOUT;

	watchdog_set_drvdata(&priv->wdev, priv);
	ret = devm_add_action_or_reset(&pdev->dev,
				       rzg2l_wdt_reset_assert_pm_disable,
				       &priv->wdev);
	if (ret < 0)
	dev_set_drvdata(dev, priv);
	ret = devm_add_action_or_reset(&pdev->dev, rzg2l_wdt_pm_disable, &priv->wdev);
	if (ret)
		return ret;

	watchdog_set_nowayout(&priv->wdev, nowayout);
@@ -320,10 +308,35 @@ static const struct of_device_id 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 = {
	.driver = {
		.name = "rzg2l_wdt",
		.of_match_table = rzg2l_wdt_ids,
		.pm = &rzg2l_wdt_pm_ops,
	},
	.probe = rzg2l_wdt_probe,
};
Loading