watchdog: sama5d4_wdt: Fix WDDIS detection on SAM9X60 and SAMA7G5

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: 266da53c35 ("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>
This commit is contained in:
Balakrishnan Sambath 2026-03-02 17:03:09 +05:30 committed by Guenter Roeck
parent ca316e145c
commit e8bc610b14

View 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)))
if (!(reg & wdt->wddis_mask))
wdt_write_nosleep(wdt, AT91_WDT_MR,
reg | AT91_SAM9X60_WDDIS);
else if (!wdt->sam9x60_support &&
(!(reg & AT91_WDT_WDDIS)))
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);
}