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.
- 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.
- Touches IRQ or DMA behavior; this matters for the representative real-device path.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/bits.hlinux/bitfield.hlinux/clk.hlinux/delay.hlinux/interrupt.hlinux/io.hlinux/math.hlinux/minmax.hlinux/module.hlinux/mod_devicetable.hlinux/platform_device.hlinux/property.hlinux/reboot.hlinux/watchdog.h
Detected Declarations
struct otto_wdt_ctrlfunction otto_wdt_startfunction otto_wdt_stopfunction otto_wdt_pingfunction otto_wdt_tick_msfunction otto_wdt_determine_timeoutsfunction otto_wdt_set_timeoutfunction otto_wdt_set_pretimeoutfunction otto_wdt_restartfunction otto_wdt_phase1_isrfunction otto_wdt_probe_clkfunction otto_wdt_probe_reset_modefunction otto_wdt_probe
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
- Immediate include surface: `linux/bits.h`, `linux/bitfield.h`, `linux/clk.h`, `linux/delay.h`, `linux/interrupt.h`, `linux/io.h`, `linux/math.h`, `linux/minmax.h`.
- Detected declarations: `struct otto_wdt_ctrl`, `function otto_wdt_start`, `function otto_wdt_stop`, `function otto_wdt_ping`, `function otto_wdt_tick_ms`, `function otto_wdt_determine_timeouts`, `function otto_wdt_set_timeout`, `function otto_wdt_set_pretimeout`, `function otto_wdt_restart`, `function otto_wdt_phase1_isr`.
- Atlas domain: Driver Families / drivers/watchdog.
- Implementation status: source implementation candidate.
- IRQ or DMA behavior appears here, which is relevant to the selected PCIe/NVMe device path.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.