Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fc8cd2ac authored by Ezequiel Garcia's avatar Ezequiel Garcia Committed by Jason Cooper
Browse files

watchdog: orion: Use atomic access for shared registers



Since the timer control register is shared with the clocksource driver,
use the recently introduced atomic_io_clear_set() to access such register.
Given the watchdog core already provides serialization for all the
watchdog ops, this commit allows to remove the spinlock entirely.

Reviewed-by: default avatarGuenter Roeck <linux@roeck-us.net>
Tested-by: default avatarSebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Tested-by: default avatarWilly Tarreau <w@1wt.eu>
Signed-off-by: default avatarEzequiel Garcia <ezequiel.garcia@free-electrons.com>
Acked-by: default avatarWim Van Sebroeck <wim@iguana.be>
Tested-By: default avatarJason Gunthorpe <jgunthorpe@obsidianresearch.com>
Signed-off-by: default avatarJason Cooper <jason@lakedaemon.net>
parent bb02c662
Loading
Loading
Loading
Loading
+5 −37
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@
#include <linux/watchdog.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/of.h>
@@ -46,25 +45,16 @@ static unsigned int wdt_max_duration; /* (seconds) */
static struct clk *clk;
static unsigned int wdt_tclk;
static void __iomem *wdt_reg;
static DEFINE_SPINLOCK(wdt_lock);

static int orion_wdt_ping(struct watchdog_device *wdt_dev)
{
	spin_lock(&wdt_lock);

	/* Reload watchdog duration */
	writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);

	spin_unlock(&wdt_lock);
	return 0;
}

static int orion_wdt_start(struct watchdog_device *wdt_dev)
{
	u32 reg;

	spin_lock(&wdt_lock);

	/* Set watchdog duration */
	writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);

@@ -72,48 +62,26 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
	writel(~WDT_INT_REQ, BRIDGE_CAUSE);

	/* Enable watchdog timer */
	reg = readl(wdt_reg + TIMER_CTRL);
	reg |= WDT_EN;
	writel(reg, wdt_reg + TIMER_CTRL);
	atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN);

	/* Enable reset on watchdog */
	reg = readl(RSTOUTn_MASK);
	reg |= WDT_RESET_OUT_EN;
	writel(reg, RSTOUTn_MASK);

	spin_unlock(&wdt_lock);
	atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
	return 0;
}

static int orion_wdt_stop(struct watchdog_device *wdt_dev)
{
	u32 reg;

	spin_lock(&wdt_lock);

	/* Disable reset on watchdog */
	reg = readl(RSTOUTn_MASK);
	reg &= ~WDT_RESET_OUT_EN;
	writel(reg, RSTOUTn_MASK);
	atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, 0);

	/* Disable watchdog timer */
	reg = readl(wdt_reg + TIMER_CTRL);
	reg &= ~WDT_EN;
	writel(reg, wdt_reg + TIMER_CTRL);

	spin_unlock(&wdt_lock);
	atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, 0);
	return 0;
}

static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev)
{
	unsigned int time_left;

	spin_lock(&wdt_lock);
	time_left = readl(wdt_reg + WDT_VAL) / wdt_tclk;
	spin_unlock(&wdt_lock);

	return time_left;
	return readl(wdt_reg + WDT_VAL) / wdt_tclk;
}

static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev,