]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
watchdog: sama5d4_wdt: Fix WDDIS detection on SAM9X60 and SAMA7G5
authorBalakrishnan Sambath <balakrishnan.s@microchip.com>
Mon, 2 Mar 2026 11:33:09 +0000 (17:03 +0530)
committerGuenter Roeck <linux@roeck-us.net>
Sun, 3 May 2026 15:50:12 +0000 (08:50 -0700)
The driver hardcoded AT91_WDT_WDDIS (bit 15) in wdt_enabled and the
probe initial state readout. SAM9X60 and SAMA7G5 use bit 12
(AT91_SAM9X60_WDDIS), causing incorrect WDDIS detection.

Introduce a per-device wddis_mask field to select the correct WDDIS
bit based on the compatible string.

Fixes: 266da53c35fc ("watchdog: sama5d4: readout initial state")
Co-developed-by: Andrei Simion <andrei.simion@microchip.com>
Signed-off-by: Andrei Simion <andrei.simion@microchip.com>
Signed-off-by: Balakrishnan Sambath <balakrishnan.s@microchip.com>
Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Link: https://lore.kernel.org/r/20260302113310.133989-2-balakrishnan.s@microchip.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
drivers/watchdog/sama5d4_wdt.c

index 13e72918338a20c1775d647036c78e6520390b72..704b786cc2ec63038e06ffa3274a339ccc7ef78f 100644 (file)
@@ -30,6 +30,7 @@ struct sama5d4_wdt {
        void __iomem            *reg_base;
        u32                     mr;
        u32                     ir;
+       u32                     wddis_mask;
        unsigned long           last_ping;
        bool                    need_irq;
        bool                    sam9x60_support;
@@ -48,7 +49,10 @@ MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
-#define wdt_enabled (!(wdt->mr & AT91_WDT_WDDIS))
+static inline bool wdt_enabled(struct sama5d4_wdt *wdt)
+{
+       return !(wdt->mr & wdt->wddis_mask);
+}
 
 #define wdt_read(wdt, field) \
        readl_relaxed((wdt)->reg_base + (field))
@@ -81,12 +85,9 @@ static int sama5d4_wdt_start(struct watchdog_device *wdd)
 {
        struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
 
-       if (wdt->sam9x60_support) {
+       if (wdt->sam9x60_support)
                writel_relaxed(wdt->ir, wdt->reg_base + AT91_SAM9X60_IER);
-               wdt->mr &= ~AT91_SAM9X60_WDDIS;
-       } else {
-               wdt->mr &= ~AT91_WDT_WDDIS;
-       }
+       wdt->mr &= ~wdt->wddis_mask;
        wdt_write(wdt, AT91_WDT_MR, wdt->mr);
 
        return 0;
@@ -96,12 +97,9 @@ static int sama5d4_wdt_stop(struct watchdog_device *wdd)
 {
        struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
 
-       if (wdt->sam9x60_support) {
+       if (wdt->sam9x60_support)
                writel_relaxed(wdt->ir, wdt->reg_base + AT91_SAM9X60_IDR);
-               wdt->mr |= AT91_SAM9X60_WDDIS;
-       } else {
-               wdt->mr |= AT91_WDT_WDDIS;
-       }
+       wdt->mr |= wdt->wddis_mask;
        wdt_write(wdt, AT91_WDT_MR, wdt->mr);
 
        return 0;
@@ -117,7 +115,7 @@ static int sama5d4_wdt_ping(struct watchdog_device *wdd)
 }
 
 static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd,
-                                unsigned int timeout)
+                                   unsigned int timeout)
 {
        struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
        u32 value = WDT_SEC2TICKS(timeout);
@@ -140,8 +138,8 @@ static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd,
         * 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);
+       if (wdt_enabled(wdt))
+               wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~wdt->wddis_mask);
 
        wdd->timeout = timeout;
 
@@ -184,10 +182,7 @@ static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt)
 {
        const char *tmp;
 
-       if (wdt->sam9x60_support)
-               wdt->mr = AT91_SAM9X60_WDDIS;
-       else
-               wdt->mr = AT91_WDT_WDDIS;
+       wdt->mr = wdt->wddis_mask;
 
        if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) &&
            !strcmp(tmp, "software"))
@@ -213,15 +208,11 @@ static int sama5d4_wdt_init(struct sama5d4_wdt *wdt)
         * If the watchdog is already running, we can safely update it.
         * Else, we have to disable it properly.
         */
-       if (!wdt_enabled) {
+       if (!wdt_enabled(wdt)) {
                reg = wdt_read(wdt, AT91_WDT_MR);
-               if (wdt->sam9x60_support && (!(reg & AT91_SAM9X60_WDDIS)))
-                       wdt_write_nosleep(wdt, AT91_WDT_MR,
-                                         reg | AT91_SAM9X60_WDDIS);
-               else if (!wdt->sam9x60_support &&
-                        (!(reg & AT91_WDT_WDDIS)))
+               if (!(reg & wdt->wddis_mask))
                        wdt_write_nosleep(wdt, AT91_WDT_MR,
-                                         reg | AT91_WDT_WDDIS);
+                                         reg | wdt->wddis_mask);
        }
 
        if (wdt->sam9x60_support) {
@@ -273,6 +264,9 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
            of_device_is_compatible(dev->of_node, "microchip,sama7g5-wdt"))
                wdt->sam9x60_support = true;
 
+       wdt->wddis_mask = wdt->sam9x60_support ? AT91_SAM9X60_WDDIS
+                                               : AT91_WDT_WDDIS;
+
        watchdog_set_drvdata(wdd, wdt);
 
        regs = devm_platform_ioremap_resource(pdev, 0);
@@ -306,8 +300,8 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
        watchdog_init_timeout(wdd, wdt_timeout, dev);
 
        reg = wdt_read(wdt, AT91_WDT_MR);
-       if (!(reg & AT91_WDT_WDDIS)) {
-               wdt->mr &= ~AT91_WDT_WDDIS;
+       if (!(reg & wdt->wddis_mask)) {
+               wdt->mr &= ~wdt->wddis_mask;
                set_bit(WDOG_HW_RUNNING, &wdd->status);
        }