drivers/watchdog/imx_sc_wdt.c

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

File Facts

System
Linux kernel
Corpus path
drivers/watchdog/imx_sc_wdt.c
Extension
.c
Size
6546 bytes
Lines
259
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 imx_sc_wdt_device {
	struct watchdog_device wdd;
	struct notifier_block wdt_notifier;
};

static int imx_sc_wdt_ping(struct watchdog_device *wdog)
{
	struct arm_smccc_res res;

	arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_PING_WDOG,
		      0, 0, 0, 0, 0, 0, &res);

	return 0;
}

static bool imx_sc_wdt_is_running(void)
{
	struct arm_smccc_res res;

	arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_START_WDOG,
		      0, 0, 0, 0, 0, 0, &res);

	/* Already enabled (SC_TIMER_ERR_BUSY)? */
	if (res.a0 == SC_TIMER_ERR_BUSY)
		return true;

	/* Undo only if that was us who has (successfully) enabled the WDT */
	if (!res.a0)
		arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_STOP_WDOG,
			      0, 0, 0, 0, 0, 0, &res);

	return false;
}

static int imx_sc_wdt_start(struct watchdog_device *wdog)
{
	struct arm_smccc_res res;

	arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_START_WDOG,
		      0, 0, 0, 0, 0, 0, &res);

	/* Ignore if already enabled(SC_TIMER_ERR_BUSY) */
	if (res.a0 && res.a0 != SC_TIMER_ERR_BUSY)
		return -EACCES;

	arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_SET_WDOG_ACT,
		      SC_TIMER_WDOG_ACTION_PARTITION,
		      0, 0, 0, 0, 0, &res);
	return res.a0 ? -EACCES : 0;
}

static int imx_sc_wdt_stop(struct watchdog_device *wdog)
{
	struct arm_smccc_res res;

	arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_STOP_WDOG,
		      0, 0, 0, 0, 0, 0, &res);

	return res.a0 ? -EACCES : 0;
}

static int imx_sc_wdt_set_timeout(struct watchdog_device *wdog,
				unsigned int timeout)
{
	struct arm_smccc_res res;

	wdog->timeout = timeout;
	arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_SET_TIMEOUT_WDOG,
		      timeout * 1000, 0, 0, 0, 0, 0, &res);

	return res.a0 ? -EACCES : 0;
}

static int imx_sc_wdt_set_pretimeout(struct watchdog_device *wdog,
				     unsigned int pretimeout)
{
	struct arm_smccc_res res;

	/*
	 * SCU firmware calculates pretimeout based on current time
	 * stamp instead of watchdog timeout stamp, need to convert
	 * the pretimeout to SCU firmware's timeout value.
	 */
	arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_SET_PRETIME_WDOG,
		      (wdog->timeout - pretimeout) * 1000, 0, 0, 0,
		      0, 0, &res);
	if (res.a0)
		return -EACCES;

	wdog->pretimeout = pretimeout;

Annotation

Implementation Notes