drivers/watchdog/imx7ulp_wdt.c

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

File Facts

System
Linux kernel
Corpus path
drivers/watchdog/imx7ulp_wdt.c
Extension
.c
Size
10591 bytes
Lines
440
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_wdt_hw_feature {
	bool prescaler_enable;
	bool post_rcs_wait;
	bool cpu_lpm_auto_cg;
	u32 wdog_clock_rate;
};

struct imx7ulp_wdt_device {
	struct watchdog_device wdd;
	void __iomem *base;
	struct clk *clk;
	bool ext_reset;
	const struct imx_wdt_hw_feature *hw;
};

static int imx7ulp_wdt_wait_ulk(void __iomem *base)
{
	u32 val = readl(base + WDOG_CS);

	if (!(val & WDOG_CS_ULK) &&
	    readl_poll_timeout_atomic(base + WDOG_CS, val,
				      val & WDOG_CS_ULK, 0,
				      WDOG_ULK_WAIT_TIMEOUT))
		return -ETIMEDOUT;

	return 0;
}

static int imx7ulp_wdt_wait_rcs(struct imx7ulp_wdt_device *wdt)
{
	int ret = 0;
	u32 val = readl(wdt->base + WDOG_CS);
	u64 timeout = (val & WDOG_CS_PRES) ?
		WDOG_RCS_WAIT_TIMEOUT * 256 : WDOG_RCS_WAIT_TIMEOUT;
	unsigned long wait_min = (val & WDOG_CS_PRES) ?
		WDOG_RCS_POST_WAIT * 256 : WDOG_RCS_POST_WAIT;

	if (!(val & WDOG_CS_RCS) &&
	    readl_poll_timeout(wdt->base + WDOG_CS, val, val & WDOG_CS_RCS, 100,
			       timeout))
		ret = -ETIMEDOUT;

	/* Wait 2.5 clocks after RCS done */
	if (wdt->hw->post_rcs_wait)
		usleep_range(wait_min, wait_min + 2000);

	return ret;
}

static int _imx7ulp_wdt_enable(struct imx7ulp_wdt_device *wdt, bool enable)
{
	u32 val = readl(wdt->base + WDOG_CS);
	int ret;

	local_irq_disable();
	writel(UNLOCK, wdt->base + WDOG_CNT);
	ret = imx7ulp_wdt_wait_ulk(wdt->base);
	if (ret)
		goto enable_out;
	if (enable)
		writel(val | WDOG_CS_EN, wdt->base + WDOG_CS);
	else
		writel(val & ~WDOG_CS_EN, wdt->base + WDOG_CS);

	local_irq_enable();
	ret = imx7ulp_wdt_wait_rcs(wdt);

	return ret;

enable_out:
	local_irq_enable();
	return ret;
}

static int imx7ulp_wdt_enable(struct watchdog_device *wdog, bool enable)
{
	struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog);
	int ret;
	u32 val;
	u32 loop = RETRY_MAX;

	do {
		ret = _imx7ulp_wdt_enable(wdt, enable);
		val = readl(wdt->base + WDOG_CS);
	} while (--loop > 0 && ((!!(val & WDOG_CS_EN)) != enable || ret));

	if (loop == 0)
		return -EBUSY;

	return ret;

Annotation

Implementation Notes