drivers/watchdog/kempld_wdt.c

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

File Facts

System
Linux kernel
Corpus path
drivers/watchdog/kempld_wdt.c
Extension
.c
Size
13903 bytes
Lines
546
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 kempld_wdt_stage {
	unsigned int	id;
	u32		mask;
};

struct kempld_wdt_data {
	struct kempld_device_data	*pld;
	struct watchdog_device		wdd;
	unsigned int			pretimeout;
	struct kempld_wdt_stage		stage[KEMPLD_WDT_MAX_STAGES];
	u8				pm_status_store;
};

#define DEFAULT_TIMEOUT		30 /* seconds */
#define DEFAULT_PRETIMEOUT	0

static unsigned int timeout = DEFAULT_TIMEOUT;
module_param(timeout, uint, 0);
MODULE_PARM_DESC(timeout,
	"Watchdog timeout in seconds. (>=0, default="
	__MODULE_STRING(DEFAULT_TIMEOUT) ")");

static unsigned int pretimeout = DEFAULT_PRETIMEOUT;
module_param(pretimeout, uint, 0);
MODULE_PARM_DESC(pretimeout,
	"Watchdog pretimeout in seconds. (>=0, default="
	__MODULE_STRING(DEFAULT_PRETIMEOUT) ")");

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 int kempld_wdt_set_stage_action(struct kempld_wdt_data *wdt_data,
					struct kempld_wdt_stage *stage,
					u8 action)
{
	struct kempld_device_data *pld = wdt_data->pld;
	u8 stage_cfg;

	if (!stage || !stage->mask)
		return -EINVAL;

	kempld_get_mutex(pld);
	stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
	stage_cfg &= ~STAGE_CFG_ACTION_MASK;
	stage_cfg |= (action & STAGE_CFG_ACTION_MASK);

	if (action == ACTION_RESET)
		stage_cfg |= STAGE_CFG_ASSERT;
	else
		stage_cfg &= ~STAGE_CFG_ASSERT;

	kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg);
	kempld_release_mutex(pld);

	return 0;
}

static int kempld_wdt_set_stage_timeout(struct kempld_wdt_data *wdt_data,
					struct kempld_wdt_stage *stage,
					unsigned int timeout)
{
	struct kempld_device_data *pld = wdt_data->pld;
	u32 prescaler;
	u64 stage_timeout64;
	u32 stage_timeout;
	u32 remainder;
	u8 stage_cfg;

	prescaler = kempld_prescaler[PRESCALER_21];

	if (!stage)
		return -EINVAL;

	stage_timeout64 = (u64)timeout * pld->pld_clock;
	remainder = do_div(stage_timeout64, prescaler);
	if (remainder)
		stage_timeout64++;

	if (stage_timeout64 > stage->mask)
		return -EINVAL;

	stage_timeout = stage_timeout64 & stage->mask;

	kempld_get_mutex(pld);
	stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
	stage_cfg &= ~STAGE_CFG_PRESCALER_MASK;
	stage_cfg |= STAGE_CFG_SET_PRESCALER(PRESCALER_21);

Annotation

Implementation Notes