drivers/watchdog/sp805_wdt.c
Source file repositories/reference/linux-study-clean/drivers/watchdog/sp805_wdt.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/watchdog/sp805_wdt.c- Extension
.c- Size
- 9336 bytes
- Lines
- 376
- 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.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- 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/device.hlinux/resource.hlinux/amba/bus.hlinux/bitops.hlinux/clk.hlinux/io.hlinux/ioport.hlinux/kernel.hlinux/math64.hlinux/module.hlinux/moduleparam.hlinux/pm.hlinux/property.hlinux/reset.hlinux/slab.hlinux/spinlock.hlinux/types.hlinux/watchdog.h
Detected Declarations
struct sp805_wdtfunction wdt_is_runningfunction wdt_setloadfunction wdt_timeleftfunction wdt_restartfunction wdt_configfunction wdt_pingfunction wdt_enablefunction wdt_disablefunction sp805_wdt_probefunction sp805_wdt_removefunction sp805_wdt_suspendfunction sp805_wdt_resume
Annotated Snippet
struct sp805_wdt {
struct watchdog_device wdd;
spinlock_t lock;
void __iomem *base;
struct clk *clk;
u64 rate;
struct amba_device *adev;
unsigned int load_val;
};
static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Set to 1 to keep watchdog running after device release");
/* returns true if wdt is running; otherwise returns false */
static bool wdt_is_running(struct watchdog_device *wdd)
{
struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
u32 wdtcontrol = readl_relaxed(wdt->base + WDTCONTROL);
return (wdtcontrol & ENABLE_MASK) == ENABLE_MASK;
}
/* This routine finds load value that will reset system in required timeout */
static int wdt_setload(struct watchdog_device *wdd, unsigned int timeout)
{
struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
u64 load, rate;
rate = wdt->rate;
/*
* sp805 runs counter with given value twice, after the end of first
* counter it gives an interrupt and then starts counter again. If
* interrupt already occurred then it resets the system. This is why
* load is half of what should be required.
*/
load = div_u64(rate, 2) * timeout - 1;
load = (load > LOAD_MAX) ? LOAD_MAX : load;
load = (load < LOAD_MIN) ? LOAD_MIN : load;
spin_lock(&wdt->lock);
wdt->load_val = load;
/* roundup timeout to closest positive integer value */
wdd->timeout = div_u64((load + 1) * 2 + (rate / 2), rate);
spin_unlock(&wdt->lock);
return 0;
}
/* returns number of seconds left for reset to occur */
static unsigned int wdt_timeleft(struct watchdog_device *wdd)
{
struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
u64 load;
spin_lock(&wdt->lock);
load = readl_relaxed(wdt->base + WDTVALUE);
/*If the interrupt is inactive then time left is WDTValue + WDTLoad. */
if (!(readl_relaxed(wdt->base + WDTRIS) & INT_MASK))
load += (u64)wdt->load_val + 1;
spin_unlock(&wdt->lock);
return div_u64(load, wdt->rate);
}
static int
wdt_restart(struct watchdog_device *wdd, unsigned long mode, void *cmd)
{
struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
writel_relaxed(0, wdt->base + WDTCONTROL);
writel_relaxed(0, wdt->base + WDTLOAD);
writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL);
/* Flush posted writes. */
readl_relaxed(wdt->base + WDTLOCK);
return 0;
}
static int wdt_config(struct watchdog_device *wdd, bool ping)
{
struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
int ret;
Annotation
- Immediate include surface: `linux/device.h`, `linux/resource.h`, `linux/amba/bus.h`, `linux/bitops.h`, `linux/clk.h`, `linux/io.h`, `linux/ioport.h`, `linux/kernel.h`.
- Detected declarations: `struct sp805_wdt`, `function wdt_is_running`, `function wdt_setload`, `function wdt_timeleft`, `function wdt_restart`, `function wdt_config`, `function wdt_ping`, `function wdt_enable`, `function wdt_disable`, `function sp805_wdt_probe`.
- Atlas domain: Driver Families / drivers/watchdog.
- Implementation status: source implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
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.