static int at91_wdt_settimeout(unsigned int timeout) { unsigned int reg; unsigned int mr; /* */ mr = wdt_read(AT91_WDT_MR); if (mr & AT91_WDT_WDDIS) { pr_err("sorry, watchdog is disabled\n"); return -EIO; } /* */ reg = AT91_WDT_WDRSTEN /* */ /* */ | AT91_WDT_WDDBGHLT /* */ | AT91_WDT_WDD /* */ | (timeout & AT91_WDT_WDV); /* */ wdt_write(AT91_WDT_MR, reg); return 0; }
/* * Set the watchdog time interval in 1/256Hz (write-once) * Counter is 12 bit. */ static int at91_wdt_settimeout(unsigned int timeout) { unsigned int reg; unsigned int mr; /* Check if disabled */ mr = wdt_read(AT91_WDT_MR); if (mr & AT91_WDT_WDDIS) { pr_err("sorry, watchdog is disabled\n"); return -EIO; } /* * All counting occurs at SLOW_CLOCK / 128 = 256 Hz * * Since WDV is a 12-bit counter, the maximum period is * 4096 / 256 = 16 seconds. */ reg = AT91_WDT_WDRSTEN /* causes watchdog reset */ /* | AT91_WDT_WDRPROC causes processor reset only */ | AT91_WDT_WDDBGHLT /* disabled in debug mode */ | AT91_WDT_WDD /* restart at any time */ | (timeout & AT91_WDT_WDV); /* timer value */ wdt_write(AT91_WDT_MR, reg); return 0; }
static int at91wdt_enable(struct watchdog_device *wddev, unsigned int timeout) { struct at91wdt_drvdata *driver_data = watchdog_get_drvdata(wddev); unsigned int reg; /* Check if the watchdog is disabled, * if disabled, the reason is the bootstrap or the bootloader has * written the Watchdog Timer Mode Register to disable the * watchdog timer */ reg = wdt_read(driver_data, AT91_WDT_MR); if (reg & AT91_WDT_WDDIS) { driver_data->is_enable = false; pr_info("sorry, watchdog is disabled\n"); return -1; } /* * All counting occurs at SLOW_CLOCK / 128 = 256 Hz * * Since WDV is a 12-bit counter, the maximum period is * 4096 / 256 = 16 seconds. */ reg = AT91_WDT_WDRSTEN /* causes watchdog reset */ /* | AT91_WDT_WDRPROC causes processor reset only */ | AT91_WDT_WDDBGHLT /* disabled in debug mode */ | AT91_WDT_WDD /* restart at any time */ | (timeout & AT91_WDT_WDV); /* timer value */ wdt_write(driver_data, AT91_WDT_MR, reg); driver_data->is_enable = true; return 0; }
unsigned int at91_wdt_set_counter(unsigned int count) { unsigned int reg; reg = wdt_read(WDTC_MR); if (reg & AT91C_WDTC_WDDIS) { dbg_info("at91_wdt: watchdog is disabled\n"); return -1; } reg = AT91C_WDTC_WDRSTEN | AT91C_WDTC_WDDBGHLT | AT91C_WDTC_WDD | (count & AT91C_WDTC_WDV); wdt_write(WDTC_MR, reg); return 0; }
/* * Reload the watchdog timer. (ie, pat the watchdog) */ static inline void at91_wdt_reset(void) { wdt_write(AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT); }
static int at91_wdt_init(struct platform_device *pdev, struct at91wdt *wdt) { u32 tmp; u32 delta; u32 value; int err; u32 mask = wdt->mr_mask; unsigned long min_heartbeat = 1; unsigned long max_heartbeat; struct device *dev = &pdev->dev; tmp = wdt_read(wdt, AT91_WDT_MR); if ((tmp & mask) != (wdt->mr & mask)) { if (tmp == WDT_MR_RESET) { wdt_write(wdt, AT91_WDT_MR, wdt->mr); tmp = wdt_read(wdt, AT91_WDT_MR); } } if (tmp & AT91_WDT_WDDIS) { if (wdt->mr & AT91_WDT_WDDIS) return 0; dev_err(dev, "watchdog is disabled\n"); return -EINVAL; } value = tmp & AT91_WDT_WDV; delta = (tmp & AT91_WDT_WDD) >> 16; if (delta < value) min_heartbeat = ticks_to_hz_roundup(value - delta); max_heartbeat = ticks_to_hz_rounddown(value); if (!max_heartbeat) { dev_err(dev, "heartbeat is too small for the system to handle it correctly\n"); return -EINVAL; } /* * Try to reset the watchdog counter 4 or 2 times more often than * actually requested, to avoid spurious watchdog reset. * If this is not possible because of the min_heartbeat value, reset * it at the min_heartbeat period. */ if ((max_heartbeat / 4) >= min_heartbeat) wdt->heartbeat = max_heartbeat / 4; else if ((max_heartbeat / 2) >= min_heartbeat) wdt->heartbeat = max_heartbeat / 2; else wdt->heartbeat = min_heartbeat; if (max_heartbeat < min_heartbeat + 4) dev_warn(dev, "min heartbeat and max heartbeat might be too close for the system to handle it correctly\n"); if ((tmp & AT91_WDT_WDFIEN) && wdt->irq) { err = request_irq(wdt->irq, wdt_interrupt, IRQF_SHARED | IRQF_IRQPOLL | IRQF_NO_SUSPEND, pdev->name, wdt); if (err) return err; } if ((tmp & wdt->mr_mask) != (wdt->mr & wdt->mr_mask)) dev_warn(dev, "watchdog already configured differently (mr = %x expecting %x)\n", tmp & wdt->mr_mask, wdt->mr & wdt->mr_mask); timer_setup(&wdt->timer, at91_ping, 0); /* * Use min_heartbeat the first time to avoid spurious watchdog reset: * we don't know for how long the watchdog counter is running, and * - resetting it right now might trigger a watchdog fault reset * - waiting for heartbeat time might lead to a watchdog timeout * reset */ mod_timer(&wdt->timer, jiffies + min_heartbeat); /* Try to set timeout from device tree first */ if (watchdog_init_timeout(&wdt->wdd, 0, dev)) watchdog_init_timeout(&wdt->wdd, heartbeat, dev); watchdog_set_nowayout(&wdt->wdd, wdt->nowayout); err = watchdog_register_device(&wdt->wdd); if (err) goto out_stop_timer; wdt->next_heartbeat = jiffies + wdt->wdd.timeout * HZ; return 0; out_stop_timer: del_timer(&wdt->timer); return err; }
/* * Reload the watchdog timer. (ie, pat the watchdog) */ static inline void at91_wdt_reset(struct at91wdt *wdt) { wdt_write(wdt, AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT); }
unsigned int at91_wdt_reload_counter(void) { wdt_write(WDTC_CR, (AT91C_WDTC_WDRSTT | AT91C_WDTC_KEY)); return 0; }
void at91_disable_wdt(void) { wdt_write(WDTC_MR, AT91C_WDTC_WDDIS); }
/* * Reload the watchdog timer. (ie, pat the watchdog) */ static inline void at91_wdt_reset(struct at91wdt_drvdata *driver_data) { wdt_write(driver_data, AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT); }