drivers/watchdog/s32g_wdt.c

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

File Facts

System
Linux kernel
Corpus path
drivers/watchdog/s32g_wdt.c
Extension
.c
Size
8454 bytes
Lines
316
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 s32g_wdt_device {
	int rate;
	void __iomem *base;
	struct watchdog_device wdog;
};

static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");

static unsigned int timeout_param = S32G_WDT_DEFAULT_TIMEOUT;
module_param(timeout_param, uint, 0);
MODULE_PARM_DESC(timeout_param, "Watchdog timeout in seconds (default="
		 __MODULE_STRING(S32G_WDT_DEFAULT_TIMEOUT) ")");

static bool early_enable;
module_param(early_enable, bool, 0);
MODULE_PARM_DESC(early_enable,
		 "Watchdog is started on module insertion (default=false)");

static const struct watchdog_info s32g_wdt_info = {
	.identity = "s32g watchdog",
	.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE |
	WDIOC_GETTIMEOUT | WDIOC_GETTIMELEFT,
};

static struct s32g_wdt_device *wdd_to_s32g_wdt(struct watchdog_device *wdd)
{
	return container_of(wdd, struct s32g_wdt_device, wdog);
}

static unsigned int wdog_sec_to_count(struct s32g_wdt_device *wdev, unsigned int timeout)
{
	return wdev->rate * timeout;
}

static int s32g_wdt_ping(struct watchdog_device *wdog)
{
	struct s32g_wdt_device *wdev = wdd_to_s32g_wdt(wdog);

	writel(S32G_WDT_SEQ1, S32G_SWT_SR(wdev->base));
	writel(S32G_WDT_SEQ2, S32G_SWT_SR(wdev->base));

	return 0;
}

static int s32g_wdt_start(struct watchdog_device *wdog)
{
	struct s32g_wdt_device *wdev = wdd_to_s32g_wdt(wdog);
	unsigned long val;

	val = readl(S32G_SWT_CR(wdev->base));

	val |= S32G_SWT_CR_WEN;

	writel(val, S32G_SWT_CR(wdev->base));

	return 0;
}

static int s32g_wdt_stop(struct watchdog_device *wdog)
{
	struct s32g_wdt_device *wdev = wdd_to_s32g_wdt(wdog);
	unsigned long val;

	val = readl(S32G_SWT_CR(wdev->base));

	val &= ~S32G_SWT_CR_WEN;

	writel(val, S32G_SWT_CR(wdev->base));

	return 0;
}

static int s32g_wdt_set_timeout(struct watchdog_device *wdog, unsigned int timeout)
{
	struct s32g_wdt_device *wdev = wdd_to_s32g_wdt(wdog);

	writel(wdog_sec_to_count(wdev, timeout), S32G_SWT_TO(wdev->base));

	wdog->timeout = timeout;

	/*
	 * Conforming to the documentation, the timeout counter is
	 * loaded when servicing is operated (aka ping) or when the
	 * counter is enabled. In case the watchdog is already started
	 * it must be stopped and started again to update the timeout
	 * register or a ping can be sent to refresh the counter. Here
	 * we choose to send a ping to the watchdog which is harmless

Annotation

Implementation Notes