drivers/watchdog/rti_wdt.c

Source file repositories/reference/linux-study-clean/drivers/watchdog/rti_wdt.c

File Facts

System
Linux kernel
Corpus path
drivers/watchdog/rti_wdt.c
Extension
.c
Size
10365 bytes
Lines
423
Domain
Driver Families
Bucket
drivers/watchdog
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct rti_wdt_data {
	bool nmi;
};

/*
 * struct to hold data for each WDT device
 * @base - base io address of WD device
 * @freq - source clock frequency of WDT
 * @wdd  - hold watchdog device as is in WDT core
 * @nmi - Set if this WDT instance supports generating NMI
 */
struct rti_wdt_device {
	void __iomem		*base;
	unsigned long		freq;
	struct watchdog_device	wdd;
	bool			nmi;
};

static int rti_wdt_start(struct watchdog_device *wdd)
{
	u32 timer_margin;
	struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd);
	u8 reaction;
	int ret;

	ret = pm_runtime_resume_and_get(wdd->parent);
	if (ret)
		return ret;

	/* set timeout period */
	timer_margin = (u64)wdd->timeout * wdt->freq;
	timer_margin >>= WDT_PRELOAD_SHIFT;
	if (timer_margin > WDT_PRELOAD_MAX)
		timer_margin = WDT_PRELOAD_MAX;
	writel_relaxed(timer_margin, wdt->base + RTIDWDPRLD);

	/*
	 * RTI only supports a windowed mode, where the watchdog can only
	 * be petted during the open window; not too early or not too late.
	 * The HW configuration options only allow for the open window size
	 * to be 50% or less than that; we obviouly want to configure the open
	 * window as large as possible so we select the 50% option.
	 */
	wdd->min_hw_heartbeat_ms = 520 * wdd->timeout + MAX_HW_ERROR;

	/* When WDT expires, generate NMI or reset if NMI not supported */
	if (wdt->nmi)
		reaction = RTIWWDRXN_NMI;
	else
		reaction = RTIWWDRXN_RST;

	writel_relaxed(reaction, wdt->base + RTIWWDRXCTRL);

	/* Open window size 50%; this is the largest window size available */
	writel_relaxed(RTIWWDSIZE_50P, wdt->base + RTIWWDSIZECTRL);

	readl_relaxed(wdt->base + RTIWWDSIZECTRL);

	/* enable watchdog */
	writel_relaxed(WDENABLE_KEY, wdt->base + RTIDWDCTRL);
	return 0;
}

static int rti_wdt_ping(struct watchdog_device *wdd)
{
	struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd);

	/* put watchdog in service state */
	writel_relaxed(WDKEY_SEQ0, wdt->base + RTIWDKEY);
	/* put watchdog in active state */
	writel_relaxed(WDKEY_SEQ1, wdt->base + RTIWDKEY);

	return 0;
}

static int rti_wdt_setup_hw_hb(struct watchdog_device *wdd, u32 wsize)
{
	/*
	 * RTI only supports a windowed mode, where the watchdog can only
	 * be petted during the open window; not too early or not too late.
	 * The HW configuration options only allow for the open window size
	 * to be 50% or less than that.
	 * To avoid any glitches, we accommodate 2% + max hardware error
	 * safety margin.
	 */
	switch (wsize) {
	case RTIWWDSIZE_50P:
		/* 50% open window => 52% min heartbeat */
		wdd->min_hw_heartbeat_ms = 520 * heartbeat + MAX_HW_ERROR;
		break;

Annotation

Implementation Notes