drivers/watchdog/sprd_wdt.c

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

File Facts

System
Linux kernel
Corpus path
drivers/watchdog/sprd_wdt.c
Extension
.c
Size
9237 bytes
Lines
381
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 sprd_wdt {
	void __iomem *base;
	struct watchdog_device wdd;
	struct clk *enable;
	struct clk *rtc_enable;
	int irq;
};

static inline struct sprd_wdt *to_sprd_wdt(struct watchdog_device *wdd)
{
	return container_of(wdd, struct sprd_wdt, wdd);
}

static inline void sprd_wdt_lock(void __iomem *addr)
{
	writel_relaxed(0x0, addr + SPRD_WDT_LOCK);
}

static inline void sprd_wdt_unlock(void __iomem *addr)
{
	writel_relaxed(SPRD_WDT_UNLOCK_KEY, addr + SPRD_WDT_LOCK);
}

static irqreturn_t sprd_wdt_isr(int irq, void *dev_id)
{
	struct sprd_wdt *wdt = (struct sprd_wdt *)dev_id;

	sprd_wdt_unlock(wdt->base);
	writel_relaxed(SPRD_WDT_INT_CLEAR_BIT, wdt->base + SPRD_WDT_INT_CLR);
	sprd_wdt_lock(wdt->base);
	watchdog_notify_pretimeout(&wdt->wdd);
	return IRQ_HANDLED;
}

static u32 sprd_wdt_get_cnt_value(struct sprd_wdt *wdt)
{
	u32 val;

	val = readl_relaxed(wdt->base + SPRD_WDT_CNT_HIGH) <<
		SPRD_WDT_CNT_HIGH_SHIFT;
	val |= readl_relaxed(wdt->base + SPRD_WDT_CNT_LOW) &
		SPRD_WDT_LOW_VALUE_MASK;

	return val;
}

static int sprd_wdt_load_value(struct sprd_wdt *wdt, u32 timeout,
			       u32 pretimeout)
{
	u32 val, delay_cnt = 0;
	u32 tmr_step = timeout * SPRD_WDT_CNT_STEP;
	u32 prtmr_step = pretimeout * SPRD_WDT_CNT_STEP;

	/*
	 * Checking busy bit to make sure the previous loading operation is
	 * done. According to the specification, the busy bit would be set
	 * after a new loading operation and last 2 or 3 RTC clock
	 * cycles (about 60us~92us).
	 */
	do {
		val = readl_relaxed(wdt->base + SPRD_WDT_INT_RAW);
		if (!(val & SPRD_WDT_LD_BUSY_BIT))
			break;

		usleep_range(10, 100);
	} while (delay_cnt++ < SPRD_WDT_LOAD_TIMEOUT);

	if (delay_cnt >= SPRD_WDT_LOAD_TIMEOUT)
		return -EBUSY;

	sprd_wdt_unlock(wdt->base);
	writel_relaxed((tmr_step >> SPRD_WDT_CNT_HIGH_SHIFT) &
		      SPRD_WDT_LOW_VALUE_MASK, wdt->base + SPRD_WDT_LOAD_HIGH);
	writel_relaxed((tmr_step & SPRD_WDT_LOW_VALUE_MASK),
		       wdt->base + SPRD_WDT_LOAD_LOW);
	writel_relaxed((prtmr_step >> SPRD_WDT_CNT_HIGH_SHIFT) &
			SPRD_WDT_LOW_VALUE_MASK,
		       wdt->base + SPRD_WDT_IRQ_LOAD_HIGH);
	writel_relaxed(prtmr_step & SPRD_WDT_LOW_VALUE_MASK,
		       wdt->base + SPRD_WDT_IRQ_LOAD_LOW);
	sprd_wdt_lock(wdt->base);

	return 0;
}

static int sprd_wdt_enable(struct sprd_wdt *wdt)
{
	u32 val;
	int ret;

Annotation

Implementation Notes