drivers/watchdog/realtek_otto_wdt.c

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

File Facts

System
Linux kernel
Corpus path
drivers/watchdog/realtek_otto_wdt.c
Extension
.c
Size
10337 bytes
Lines
367
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 otto_wdt_ctrl {
	struct watchdog_device wdev;
	struct device *dev;
	void __iomem *base;
	unsigned int clk_rate_khz;
	int irq_phase1;
};

static int otto_wdt_start(struct watchdog_device *wdev)
{
	struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
	u32 v;

	v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL);
	v |= OTTO_WDT_CTRL_ENABLE;
	iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);

	return 0;
}

static int otto_wdt_stop(struct watchdog_device *wdev)
{
	struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
	u32 v;

	v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL);
	v &= ~OTTO_WDT_CTRL_ENABLE;
	iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);

	return 0;
}

static int otto_wdt_ping(struct watchdog_device *wdev)
{
	struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);

	iowrite32(OTTO_WDT_CNTR_PING, ctrl->base + OTTO_WDT_REG_CNTR);

	return 0;
}

static int otto_wdt_tick_ms(struct otto_wdt_ctrl *ctrl, int prescale)
{
	return DIV_ROUND_CLOSEST(1 << (25 + prescale), ctrl->clk_rate_khz);
}

/*
 * The timer asserts the PHASE1/PHASE2 IRQs when the number of ticks exceeds
 * the value stored in those fields. This means each phase will run for at least
 * one tick, so small values need to be clamped to correctly reflect the timeout.
 */
static int otto_wdt_determine_timeouts(struct watchdog_device *wdev, unsigned int timeout,
		unsigned int pretimeout)
{
	struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
	unsigned int pretimeout_ms = pretimeout * 1000;
	unsigned int timeout_ms = timeout * 1000;
	unsigned int prescale_next = 0;
	unsigned int phase1_ticks;
	unsigned int phase2_ticks;
	unsigned int total_ticks;
	unsigned int prescale;
	unsigned int tick_ms;
	u32 v;

	do {
		prescale = prescale_next;
		if (prescale > OTTO_WDT_PRESCALE_MAX)
			return -EINVAL;

		tick_ms = otto_wdt_tick_ms(ctrl, prescale);
		total_ticks = max(2, DIV_ROUND_UP(timeout_ms, tick_ms));
		phase2_ticks = max(1, pretimeout_ms / tick_ms);
		phase1_ticks = total_ticks - phase2_ticks;

		prescale_next++;
	} while (phase1_ticks > OTTO_WDT_PHASE_TICKS_MAX
		|| phase2_ticks > OTTO_WDT_PHASE_TICKS_MAX);

	v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL);

	v &= ~(OTTO_WDT_CTRL_PRESCALE | OTTO_WDT_CTRL_PHASE1 | OTTO_WDT_CTRL_PHASE2);
	v |= FIELD_PREP(OTTO_WDT_CTRL_PHASE1, phase1_ticks - 1);
	v |= FIELD_PREP(OTTO_WDT_CTRL_PHASE2, phase2_ticks - 1);
	v |= FIELD_PREP(OTTO_WDT_CTRL_PRESCALE, prescale);

	iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);

	timeout_ms = total_ticks * tick_ms;
	ctrl->wdev.timeout = timeout_ms / 1000;

Annotation

Implementation Notes