drivers/watchdog/ixp4xx_wdt.c

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

File Facts

System
Linux kernel
Corpus path
drivers/watchdog/ixp4xx_wdt.c
Extension
.c
Size
5366 bytes
Lines
198
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 ixp4xx_wdt {
	struct watchdog_device wdd;
	void __iomem *base;
	unsigned long rate;
};

/* Fallback if we do not have a clock for this */
#define IXP4XX_TIMER_FREQ	66666000

/* Registers after the timer registers */
#define IXP4XX_OSWT_OFFSET	0x14  /* Watchdog Timer */
#define IXP4XX_OSWE_OFFSET	0x18  /* Watchdog Enable */
#define IXP4XX_OSWK_OFFSET	0x1C  /* Watchdog Key */
#define IXP4XX_OSST_OFFSET	0x20  /* Timer Status */

#define IXP4XX_OSST_TIMER_WDOG_PEND	0x00000008
#define IXP4XX_OSST_TIMER_WARM_RESET	0x00000010
#define IXP4XX_WDT_KEY			0x0000482E
#define IXP4XX_WDT_RESET_ENABLE		0x00000001
#define IXP4XX_WDT_IRQ_ENABLE		0x00000002
#define IXP4XX_WDT_COUNT_ENABLE		0x00000004

static inline
struct ixp4xx_wdt *to_ixp4xx_wdt(struct watchdog_device *wdd)
{
	return container_of(wdd, struct ixp4xx_wdt, wdd);
}

static int ixp4xx_wdt_start(struct watchdog_device *wdd)
{
	struct ixp4xx_wdt *iwdt = to_ixp4xx_wdt(wdd);

	__raw_writel(IXP4XX_WDT_KEY, iwdt->base + IXP4XX_OSWK_OFFSET);
	__raw_writel(0, iwdt->base + IXP4XX_OSWE_OFFSET);
	__raw_writel(wdd->timeout * iwdt->rate,
		     iwdt->base + IXP4XX_OSWT_OFFSET);
	__raw_writel(IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE,
		     iwdt->base + IXP4XX_OSWE_OFFSET);
	__raw_writel(0, iwdt->base + IXP4XX_OSWK_OFFSET);

	return 0;
}

static int ixp4xx_wdt_stop(struct watchdog_device *wdd)
{
	struct ixp4xx_wdt *iwdt = to_ixp4xx_wdt(wdd);

	__raw_writel(IXP4XX_WDT_KEY, iwdt->base + IXP4XX_OSWK_OFFSET);
	__raw_writel(0, iwdt->base + IXP4XX_OSWE_OFFSET);
	__raw_writel(0, iwdt->base + IXP4XX_OSWK_OFFSET);

	return 0;
}

static int ixp4xx_wdt_set_timeout(struct watchdog_device *wdd,
				  unsigned int timeout)
{
	wdd->timeout = timeout;
	if (watchdog_active(wdd))
		ixp4xx_wdt_start(wdd);

	return 0;
}

static int ixp4xx_wdt_restart(struct watchdog_device *wdd,
                              unsigned long action, void *data)
{
	struct ixp4xx_wdt *iwdt = to_ixp4xx_wdt(wdd);

	__raw_writel(IXP4XX_WDT_KEY, iwdt->base + IXP4XX_OSWK_OFFSET);
	__raw_writel(0, iwdt->base + IXP4XX_OSWT_OFFSET);
	__raw_writel(IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE,
		     iwdt->base + IXP4XX_OSWE_OFFSET);

	return 0;
}

static const struct watchdog_ops ixp4xx_wdt_ops = {
	.start = ixp4xx_wdt_start,
	.stop = ixp4xx_wdt_stop,
	.set_timeout = ixp4xx_wdt_set_timeout,
	.restart = ixp4xx_wdt_restart,
	.owner = THIS_MODULE,
};

/*
 * The A0 version of the IXP422 had a bug in the watchdog making
 * is useless, but we still need to use it to restart the system
 * as it is the only way, so in this special case we register a
 * "dummy" watchdog that doesn't really work, but will support

Annotation

Implementation Notes