drivers/input/misc/nxp-bbnsm-pwrkey.c

Source file repositories/reference/linux-study-clean/drivers/input/misc/nxp-bbnsm-pwrkey.c

File Facts

System
Linux kernel
Corpus path
drivers/input/misc/nxp-bbnsm-pwrkey.c
Extension
.c
Size
6077 bytes
Lines
240
Domain
Driver Families
Bucket
drivers/input
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 bbnsm_pwrkey {
	struct regmap *regmap;
	int irq;
	int keycode;
	int keystate;  /* 1:pressed */
	bool suspended;
	struct timer_list check_timer;
	struct input_dev *input;
};

static void bbnsm_pwrkey_check_for_events(struct timer_list *t)
{
	struct bbnsm_pwrkey *bbnsm = timer_container_of(bbnsm, t, check_timer);
	struct input_dev *input = bbnsm->input;
	u32 state;

	regmap_read(bbnsm->regmap, BBNSM_EVENTS, &state);

	state = state & BBNSM_BTN_PRESSED ? 1 : 0;

	/* only report new event if status changed */
	if (state ^ bbnsm->keystate) {
		bbnsm->keystate = state;
		input_event(input, EV_KEY, bbnsm->keycode, state);
		input_sync(input);
		pm_relax(bbnsm->input->dev.parent);
	}

	/* repeat check if pressed long */
	if (state)
		mod_timer(&bbnsm->check_timer,
			  jiffies + msecs_to_jiffies(REPEAT_INTERVAL));
}

static irqreturn_t bbnsm_pwrkey_interrupt(int irq, void *dev_id)
{
	struct platform_device *pdev = dev_id;
	struct bbnsm_pwrkey *bbnsm = platform_get_drvdata(pdev);
	struct input_dev *input = bbnsm->input;
	u32 event;

	regmap_read(bbnsm->regmap, BBNSM_EVENTS, &event);
	if (!(event & BBNSM_BTN_OFF))
		return IRQ_NONE;

	pm_wakeup_event(bbnsm->input->dev.parent, 0);

	/*
	 * Directly report key event after resume to make sure key press
	 * event is never missed.
	 */
	if (bbnsm->suspended) {
		bbnsm->keystate = 1;
		input_event(input, EV_KEY, bbnsm->keycode, 1);
		input_sync(input);
		/* Fire at most once per suspend/resume cycle */
		bbnsm->suspended = false;
	}

	mod_timer(&bbnsm->check_timer,
		   jiffies + msecs_to_jiffies(DEBOUNCE_TIME));

	/* clear PWR OFF */
	regmap_write(bbnsm->regmap, BBNSM_EVENTS, BBNSM_BTN_OFF);

	return IRQ_HANDLED;
}

static void bbnsm_pwrkey_act(void *pdata)
{
	struct bbnsm_pwrkey *bbnsm = pdata;

	timer_shutdown_sync(&bbnsm->check_timer);
}

static int bbnsm_pwrkey_probe(struct platform_device *pdev)
{
	struct bbnsm_pwrkey *bbnsm;
	struct input_dev *input;
	struct device_node *np = pdev->dev.of_node;
	int error;

	bbnsm = devm_kzalloc(&pdev->dev, sizeof(*bbnsm), GFP_KERNEL);
	if (!bbnsm)
		return -ENOMEM;

	bbnsm->regmap = syscon_node_to_regmap(np->parent);
	if (IS_ERR(bbnsm->regmap)) {
		dev_err(&pdev->dev, "bbnsm pwerkey get regmap failed\n");
		return PTR_ERR(bbnsm->regmap);

Annotation

Implementation Notes