Commit 170031ff authored by Job Sava's avatar Job Sava Committed by Lee Jones
Browse files

input: tps6594-pwrbutton: Add power button functionality



TPS6594 defines two interrupts for the power button one for push and
one for release.

This driver is very simple in that it maps the push interrupt to a key
input and the release interrupt to a key release.

Signed-off-by: default avatarJob Sava <jsava@criticallink.com>
Signed-off-by: default avatarMichael Walle <mwalle@kernel.org>
Acked-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
Link: https://lore.kernel.org/r/20250826134631.1499936-2-mwalle@kernel.org


Signed-off-by: default avatarLee Jones <lee@kernel.org>
parent 8f5ae30d
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -506,6 +506,16 @@ config INPUT_TPS65219_PWRBUTTON
	  To compile this driver as a module, choose M here. The module will
	  be called tps65219-pwrbutton.

config INPUT_TPS6594_PWRBUTTON
	tristate "TPS6594 Power button driver"
	depends on MFD_TPS6594
	help
	  Say Y here if you want to enable power button reporting for
	  TPS6594 Power Management IC devices.

	  To compile this driver as a module, choose M here. The module will
	  be called tps6594-pwrbutton.

config INPUT_AXP20X_PEK
	tristate "X-Powers AXP20X power button driver"
	depends on MFD_AXP20X
+1 −0
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
obj-$(CONFIG_INPUT_STPMIC1_ONKEY)  	+= stpmic1_onkey.o
obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON)	+= tps65218-pwrbutton.o
obj-$(CONFIG_INPUT_TPS65219_PWRBUTTON)	+= tps65219-pwrbutton.o
obj-$(CONFIG_INPUT_TPS6594_PWRBUTTON)	+= tps6594-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON)	+= twl4030-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_VIBRA)	+= twl4030-vibra.o
obj-$(CONFIG_INPUT_TWL6040_VIBRA)	+= twl6040-vibra.o
+126 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * power button driver for TI TPS6594 PMICs
 *
 * Copyright (C) 2025 Critical Link LLC - https://www.criticallink.com/
 */
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/tps6594.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>

struct tps6594_pwrbutton {
	struct device *dev;
	struct input_dev *idev;
	char phys[32];
};

static irqreturn_t tps6594_pb_push_irq(int irq, void *_pwr)
{
	struct tps6594_pwrbutton *pwr = _pwr;

	input_report_key(pwr->idev, KEY_POWER, 1);
	pm_wakeup_event(pwr->dev, 0);
	input_sync(pwr->idev);

	return IRQ_HANDLED;
}

static irqreturn_t tps6594_pb_release_irq(int irq, void *_pwr)
{
	struct tps6594_pwrbutton *pwr = _pwr;

	input_report_key(pwr->idev, KEY_POWER, 0);
	input_sync(pwr->idev);

	return IRQ_HANDLED;
}

static int tps6594_pb_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct tps6594_pwrbutton *pwr;
	struct input_dev *idev;
	int error;
	int push_irq;
	int release_irq;

	pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL);
	if (!pwr)
		return -ENOMEM;

	idev = devm_input_allocate_device(dev);
	if (!idev)
		return -ENOMEM;

	idev->name = pdev->name;
	snprintf(pwr->phys, sizeof(pwr->phys), "%s/input0",
		 pdev->name);
	idev->phys = pwr->phys;
	idev->id.bustype = BUS_I2C;

	input_set_capability(idev, EV_KEY, KEY_POWER);

	pwr->dev = dev;
	pwr->idev = idev;
	device_init_wakeup(dev, true);

	push_irq = platform_get_irq(pdev, 0);
	if (push_irq < 0)
		return -EINVAL;

	release_irq = platform_get_irq(pdev, 1);
	if (release_irq < 0)
		return -EINVAL;

	error = devm_request_threaded_irq(dev, push_irq, NULL,
					  tps6594_pb_push_irq,
					  IRQF_ONESHOT,
					  pdev->resource[0].name, pwr);
	if (error) {
		dev_err(dev, "failed to request push IRQ #%d: %d\n", push_irq,
			error);
		return error;
	}

	error = devm_request_threaded_irq(dev, release_irq, NULL,
					  tps6594_pb_release_irq,
					  IRQF_ONESHOT,
					  pdev->resource[1].name, pwr);
	if (error) {
		dev_err(dev, "failed to request release IRQ #%d: %d\n",
			release_irq, error);
		return error;
	}

	error = input_register_device(idev);
	if (error) {
		dev_err(dev, "Can't register power button: %d\n", error);
		return error;
	}

	return 0;
}

static const struct platform_device_id tps6594_pwrbtn_id_table[] = {
	{ "tps6594-pwrbutton", },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, tps6594_pwrbtn_id_table);

static struct platform_driver tps6594_pb_driver = {
	.probe = tps6594_pb_probe,
	.driver = {
		.name = "tps6594_pwrbutton",
	},
	.id_table = tps6594_pwrbtn_id_table,
};
module_platform_driver(tps6594_pb_driver);

MODULE_DESCRIPTION("TPS6594 Power Button");
MODULE_LICENSE("GPL");