drivers/input/misc/twl4030-pwrbutton.c

Source file repositories/reference/linux-study-clean/drivers/input/misc/twl4030-pwrbutton.c

File Facts

System
Linux kernel
Corpus path
drivers/input/misc/twl4030-pwrbutton.c
Extension
.c
Size
4409 bytes
Lines
165
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 twl_pwrbutton_chipdata {
	u8 status_reg;
	bool need_manual_irq;
};

static const struct twl_pwrbutton_chipdata twl4030_chipdata = {
	.status_reg = 0xf,
	.need_manual_irq = false,
};

static const struct twl_pwrbutton_chipdata twl6030_chipdata = {
	.status_reg = 0x2,
	.need_manual_irq = true,
};

static irqreturn_t powerbutton_irq(int irq, void *_pwr)
{
	struct input_dev *pwr = _pwr;
	const struct twl_pwrbutton_chipdata *pdata = dev_get_drvdata(pwr->dev.parent);
	int err;
	u8 value;

	err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &value, pdata->status_reg);
	if (!err)  {
		pm_wakeup_event(pwr->dev.parent, 0);
		input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ);
		input_sync(pwr);
	} else {
		dev_err(pwr->dev.parent, "twl4030: i2c error %d while reading"
			" TWL4030 PM_MASTER STS_HW_CONDITIONS register\n", err);
	}

	return IRQ_HANDLED;
}

static int twl4030_pwrbutton_probe(struct platform_device *pdev)
{
	const struct twl_pwrbutton_chipdata *pdata;
	struct input_dev *pwr;
	int irq = platform_get_irq(pdev, 0);
	int err;

	pdata = device_get_match_data(&pdev->dev);
	if (!pdata)
		return -EINVAL;

	platform_set_drvdata(pdev, (void *)pdata);

	pwr = devm_input_allocate_device(&pdev->dev);
	if (!pwr) {
		dev_err(&pdev->dev, "Can't allocate power button\n");
		return -ENOMEM;
	}

	input_set_capability(pwr, EV_KEY, KEY_POWER);
	pwr->name = "twl4030_pwrbutton";
	pwr->phys = "twl4030_pwrbutton/input0";
	pwr->dev.parent = &pdev->dev;

	err = devm_request_threaded_irq(&pdev->dev, irq, NULL, powerbutton_irq,
			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
			IRQF_ONESHOT,
			"twl4030_pwrbutton", pwr);
	if (err < 0) {
		dev_err(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err);
		return err;
	}

	err = input_register_device(pwr);
	if (err) {
		dev_err(&pdev->dev, "Can't register power button: %d\n", err);
		return err;
	}

	if (pdata->need_manual_irq) {
		err = twl6030_interrupt_unmask(0x01, REG_INT_MSK_LINE_A);
		if (err)
			return err;

		err = twl6030_interrupt_unmask(0x01, REG_INT_MSK_STS_A);
		if (err)
			return err;
	}

	device_init_wakeup(&pdev->dev, true);

	return 0;
}

static void twl4030_pwrbutton_remove(struct platform_device *pdev)

Annotation

Implementation Notes