drivers/power/reset/ltc2952-poweroff.c

Source file repositories/reference/linux-study-clean/drivers/power/reset/ltc2952-poweroff.c

File Facts

System
Linux kernel
Corpus path
drivers/power/reset/ltc2952-poweroff.c
Extension
.c
Size
9062 bytes
Lines
319
Domain
Driver Families
Bucket
drivers/power
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 ltc2952_poweroff {
	struct hrtimer timer_trigger;
	struct hrtimer timer_wde;

	ktime_t trigger_delay;
	ktime_t wde_interval;

	struct device *dev;

	struct gpio_desc *gpio_trigger;
	struct gpio_desc *gpio_watchdog;
	struct gpio_desc *gpio_kill;

	bool kernel_panic;
	struct notifier_block panic_notifier;
};

#define to_ltc2952(p, m) container_of(p, struct ltc2952_poweroff, m)

/*
 * This global variable is only needed for pm_power_off. We should
 * remove it entirely once we don't need the global state anymore.
 */
static struct ltc2952_poweroff *ltc2952_data;

/**
 * ltc2952_poweroff_timer_wde - Timer callback
 * Toggles the watchdog reset signal each wde_interval
 *
 * @timer: corresponding timer
 *
 * Returns HRTIMER_RESTART for an infinite loop which will only stop when the
 * machine actually shuts down
 */
static enum hrtimer_restart ltc2952_poweroff_timer_wde(struct hrtimer *timer)
{
	int state;
	struct ltc2952_poweroff *data = to_ltc2952(timer, timer_wde);

	if (data->kernel_panic)
		return HRTIMER_NORESTART;

	state = gpiod_get_value(data->gpio_watchdog);
	gpiod_set_value(data->gpio_watchdog, !state);

	hrtimer_forward_now(timer, data->wde_interval);

	return HRTIMER_RESTART;
}

static void ltc2952_poweroff_start_wde(struct ltc2952_poweroff *data)
{
	hrtimer_start(&data->timer_wde, data->wde_interval, HRTIMER_MODE_REL);
}

static enum hrtimer_restart
ltc2952_poweroff_timer_trigger(struct hrtimer *timer)
{
	struct ltc2952_poweroff *data = to_ltc2952(timer, timer_trigger);

	ltc2952_poweroff_start_wde(data);
	dev_info(data->dev, "executing shutdown\n");
	orderly_poweroff(true);

	return HRTIMER_NORESTART;
}

/**
 * ltc2952_poweroff_handler - Interrupt handler
 * Triggered each time the trigger signal changes state and (de)activates a
 * time-out (timer_trigger). Once the time-out is actually reached the shut
 * down is executed.
 *
 * @irq: IRQ number
 * @dev_id: pointer to the main data structure
 */
static irqreturn_t ltc2952_poweroff_handler(int irq, void *dev_id)
{
	struct ltc2952_poweroff *data = dev_id;

	if (data->kernel_panic || hrtimer_active(&data->timer_wde)) {
		/* shutdown is already triggered, nothing to do any more */
		return IRQ_HANDLED;
	}

	if (gpiod_get_value(data->gpio_trigger)) {
		hrtimer_start(&data->timer_trigger, data->trigger_delay,
			      HRTIMER_MODE_REL);
	} else {
		hrtimer_cancel(&data->timer_trigger);

Annotation

Implementation Notes