drivers/watchdog/stm32_iwdg.c
Source file repositories/reference/linux-study-clean/drivers/watchdog/stm32_iwdg.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/watchdog/stm32_iwdg.c- Extension
.c- Size
- 10097 bytes
- Lines
- 394
- 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/clk.hlinux/delay.hlinux/interrupt.hlinux/io.hlinux/iopoll.hlinux/kernel.hlinux/module.hlinux/of.hlinux/platform_device.hlinux/pm_wakeirq.hlinux/watchdog.h
Detected Declarations
struct stm32_iwdg_datastruct stm32_iwdgfunction reg_readfunction reg_writefunction stm32_iwdg_startfunction stm32_iwdg_pingfunction stm32_iwdg_set_timeoutfunction stm32_iwdg_set_pretimeoutfunction stm32_iwdg_isrfunction stm32_clk_disable_unpreparefunction stm32_iwdg_clk_initfunction stm32_iwdg_irq_initfunction stm32_iwdg_probe
Annotated Snippet
struct stm32_iwdg_data {
bool has_pclk;
bool has_early_wakeup;
u32 max_prescaler;
};
static const struct stm32_iwdg_data stm32_iwdg_data = {
.has_pclk = false,
.has_early_wakeup = false,
.max_prescaler = 256,
};
static const struct stm32_iwdg_data stm32mp1_iwdg_data = {
.has_pclk = true,
.has_early_wakeup = true,
.max_prescaler = 1024,
};
struct stm32_iwdg {
struct watchdog_device wdd;
const struct stm32_iwdg_data *data;
void __iomem *regs;
struct clk *clk_lsi;
struct clk *clk_pclk;
unsigned int rate;
};
static inline u32 reg_read(void __iomem *base, u32 reg)
{
return readl_relaxed(base + reg);
}
static inline void reg_write(void __iomem *base, u32 reg, u32 val)
{
writel_relaxed(val, base + reg);
}
static int stm32_iwdg_start(struct watchdog_device *wdd)
{
struct stm32_iwdg *wdt = watchdog_get_drvdata(wdd);
u32 tout, ptot, presc, iwdg_rlr, iwdg_ewcr, iwdg_pr, iwdg_sr;
int ret;
dev_dbg(wdd->parent, "%s\n", __func__);
if (!wdd->pretimeout)
wdd->pretimeout = 3 * wdd->timeout / 4;
tout = clamp_t(unsigned int, wdd->timeout,
wdd->min_timeout, wdd->max_hw_heartbeat_ms / 1000);
ptot = clamp_t(unsigned int, tout - wdd->pretimeout,
wdd->min_timeout, tout);
presc = DIV_ROUND_UP(tout * wdt->rate, RLR_MAX + 1);
/* The prescaler is align on power of 2 and start at 2 ^ PR_SHIFT. */
presc = roundup_pow_of_two(presc);
iwdg_pr = presc <= 1 << PR_SHIFT ? 0 : ilog2(presc) - PR_SHIFT;
iwdg_rlr = ((tout * wdt->rate) / presc) - 1;
iwdg_ewcr = ((ptot * wdt->rate) / presc) - 1;
/* enable write access */
reg_write(wdt->regs, IWDG_KR, KR_KEY_EWA);
/* set prescaler & reload registers */
reg_write(wdt->regs, IWDG_PR, iwdg_pr);
reg_write(wdt->regs, IWDG_RLR, iwdg_rlr);
if (wdt->data->has_early_wakeup)
reg_write(wdt->regs, IWDG_EWCR, iwdg_ewcr | EWCR_EWIE);
reg_write(wdt->regs, IWDG_KR, KR_KEY_ENABLE);
/* wait for the registers to be updated (max 100ms) */
ret = readl_relaxed_poll_timeout(wdt->regs + IWDG_SR, iwdg_sr,
!(iwdg_sr & (SR_PVU | SR_RVU)),
SLEEP_US, TIMEOUT_US);
if (ret) {
dev_err(wdd->parent, "Fail to set prescaler, reload regs\n");
return ret;
}
/* reload watchdog */
reg_write(wdt->regs, IWDG_KR, KR_KEY_RELOAD);
return 0;
}
static int stm32_iwdg_ping(struct watchdog_device *wdd)
{
struct stm32_iwdg *wdt = watchdog_get_drvdata(wdd);
Annotation
- Immediate include surface: `linux/clk.h`, `linux/delay.h`, `linux/interrupt.h`, `linux/io.h`, `linux/iopoll.h`, `linux/kernel.h`, `linux/module.h`, `linux/of.h`.
- Detected declarations: `struct stm32_iwdg_data`, `struct stm32_iwdg`, `function reg_read`, `function reg_write`, `function stm32_iwdg_start`, `function stm32_iwdg_ping`, `function stm32_iwdg_set_timeout`, `function stm32_iwdg_set_pretimeout`, `function stm32_iwdg_isr`, `function stm32_clk_disable_unprepare`.
- 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.