The datasheet states: "When setting the WDDIS bit, and while it is set, the
fields WDV and WDD must not be modified."
Because the whole configuration is already cached inside .mr, wait for the
user to enable the watchdog to configure it so it is enabled and configured
at the same time (what the IP is actually expecting).
When the watchdog is already enabled, it is not an issue to reconfigure it.
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Acked-by: Wenyou.Yang <wenyou.yang@microchip.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+#define wdt_enabled (!(wdt->mr & AT91_WDT_WDDIS))
+
#define wdt_read(wdt, field) \
readl_relaxed((wdt)->reg_base + (field))
#define wdt_read(wdt, field) \
readl_relaxed((wdt)->reg_base + (field))
wdt->mr &= ~AT91_WDT_WDD;
wdt->mr |= AT91_WDT_SET_WDV(value);
wdt->mr |= AT91_WDT_SET_WDD(value);
wdt->mr &= ~AT91_WDT_WDD;
wdt->mr |= AT91_WDT_SET_WDV(value);
wdt->mr |= AT91_WDT_SET_WDD(value);
- wdt_write(wdt, AT91_WDT_MR, wdt->mr);
+
+ /*
+ * WDDIS has to be 0 when updating WDD/WDV. The datasheet states: When
+ * setting the WDDIS bit, and while it is set, the fields WDV and WDD
+ * must not be modified.
+ * If the watchdog is enabled, then the timeout can be updated. Else,
+ * wait that the user enables it.
+ */
+ if (wdt_enabled)
+ wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~AT91_WDT_WDDIS);
static int sama5d4_wdt_init(struct sama5d4_wdt *wdt)
{
static int sama5d4_wdt_init(struct sama5d4_wdt *wdt)
{
- struct watchdog_device *wdd = &wdt->wdd;
- u32 value = WDT_SEC2TICKS(wdd->timeout);
- * Because the fields WDV and WDD must not be modified when the WDDIS
- * bit is set, so clear the WDDIS bit before writing the WDT_MR.
+ * When booting and resuming, the bootloader may have changed the
+ * watchdog configuration.
+ * If the watchdog is already running, we can safely update it.
+ * Else, we have to disable it properly.
- reg = wdt_read(wdt, AT91_WDT_MR);
- reg &= ~AT91_WDT_WDDIS;
- wdt_write(wdt, AT91_WDT_MR, reg);
-
- wdt->mr |= AT91_WDT_SET_WDD(value);
- wdt->mr |= AT91_WDT_SET_WDV(value);
-
- wdt_write(wdt, AT91_WDT_MR, wdt->mr);
-
+ if (wdt_enabled) {
+ wdt_write(wdt, AT91_WDT_MR, wdt->mr);
+ } else {
+ reg = wdt_read(wdt, AT91_WDT_MR);
+ if (!(reg & AT91_WDT_WDDIS))
+ wdt_write(wdt, AT91_WDT_MR, reg | AT91_WDT_WDDIS);
+ }
struct resource *res;
void __iomem *regs;
u32 irq = 0;
struct resource *res;
void __iomem *regs;
u32 irq = 0;
int ret;
wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
int ret;
wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+ timeout = WDT_SEC2TICKS(wdd->timeout);
+
+ wdt->mr |= AT91_WDT_SET_WDD(timeout);
+ wdt->mr |= AT91_WDT_SET_WDV(timeout);
+
ret = sama5d4_wdt_init(wdt);
if (ret)
return ret;
ret = sama5d4_wdt_init(wdt);
if (ret)
return ret;
{
struct sama5d4_wdt *wdt = dev_get_drvdata(dev);
{
struct sama5d4_wdt *wdt = dev_get_drvdata(dev);
- wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~AT91_WDT_WDDIS);
- if (wdt->mr & AT91_WDT_WDDIS)
- wdt_write(wdt, AT91_WDT_MR, wdt->mr);