From 170031ff27dd7a07fdedee7f3710a19dcdf889bd Mon Sep 17 00:00:00 2001 From: Job Sava Date: Tue, 26 Aug 2025 15:46:29 +0200 Subject: [PATCH 1/3] 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: Job Sava Signed-off-by: Michael Walle Acked-by: Dmitry Torokhov Link: https://lore.kernel.org/r/20250826134631.1499936-2-mwalle@kernel.org Signed-off-by: Lee Jones --- drivers/input/misc/Kconfig | 10 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/tps6594-pwrbutton.c | 126 +++++++++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 drivers/input/misc/tps6594-pwrbutton.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 0fb21c99a5e3..cce51358242f 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -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 diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index d468c8140b93..bb12f883851c 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -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 diff --git a/drivers/input/misc/tps6594-pwrbutton.c b/drivers/input/misc/tps6594-pwrbutton.c new file mode 100644 index 000000000000..cd039b3866dc --- /dev/null +++ b/drivers/input/misc/tps6594-pwrbutton.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * power button driver for TI TPS6594 PMICs + * + * Copyright (C) 2025 Critical Link LLC - https://www.criticallink.com/ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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"); From d766ca01c208bdf0f36098607efe1e250ccf41c5 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Tue, 26 Aug 2025 15:46:30 +0200 Subject: [PATCH 2/3] mfd: tps6594: Add power button functionality The PMIC has a multi-function pin PB/EN/VSENSE. If it is configured as push-button (PB), add the corresponding device for it. Co-developed-by: Job Sava Signed-off-by: Job Sava Signed-off-by: Michael Walle Link: https://lore.kernel.org/r/20250826134631.1499936-3-mwalle@kernel.org Signed-off-by: Lee Jones --- drivers/mfd/tps6594-core.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/tps6594-core.c b/drivers/mfd/tps6594-core.c index c16c37e36617..9195c9059489 100644 --- a/drivers/mfd/tps6594-core.c +++ b/drivers/mfd/tps6594-core.c @@ -20,6 +20,8 @@ #include #define TPS6594_CRC_SYNC_TIMEOUT_MS 150 +#define TPS65224_EN_SEL_PB 1 +#define TPS65224_GPIO3_SEL_PB 3 /* Completion to synchronize CRC feature enabling on all PMICs */ static DECLARE_COMPLETION(tps6594_crc_comp); @@ -128,6 +130,12 @@ static const struct resource tps6594_rtc_resources[] = { DEFINE_RES_IRQ_NAMED(TPS6594_IRQ_POWER_UP, TPS6594_IRQ_NAME_POWERUP), }; +static const struct resource tps6594_pwrbutton_resources[] = { + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_FALL, TPS65224_IRQ_NAME_PB_FALL), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_RISE, TPS65224_IRQ_NAME_PB_RISE), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_SHORT, TPS65224_IRQ_NAME_PB_SHORT), +}; + static const struct mfd_cell tps6594_common_cells[] = { MFD_CELL_RES("tps6594-regulator", tps6594_regulator_resources), MFD_CELL_RES("tps6594-pinctrl", tps6594_pinctrl_resources), @@ -318,8 +326,6 @@ static const struct resource tps65224_pfsm_resources[] = { DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_REG_UNLOCK, TPS65224_IRQ_NAME_REG_UNLOCK), DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_TWARN, TPS65224_IRQ_NAME_TWARN), DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_LONG, TPS65224_IRQ_NAME_PB_LONG), - DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_FALL, TPS65224_IRQ_NAME_PB_FALL), - DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_RISE, TPS65224_IRQ_NAME_PB_RISE), DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_TSD_ORD, TPS65224_IRQ_NAME_TSD_ORD), DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_BIST_FAIL, TPS65224_IRQ_NAME_BIST_FAIL), DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_REG_CRC_ERR, TPS65224_IRQ_NAME_REG_CRC_ERR), @@ -347,6 +353,12 @@ static const struct mfd_cell tps65224_common_cells[] = { MFD_CELL_RES("tps6594-regulator", tps65224_regulator_resources), }; +static const struct mfd_cell tps6594_pwrbutton_cell = { + .name = "tps6594-pwrbutton", + .resources = tps6594_pwrbutton_resources, + .num_resources = ARRAY_SIZE(tps6594_pwrbutton_resources), +}; + static const struct regmap_irq tps65224_irqs[] = { /* INT_BUCK register */ REGMAP_IRQ_REG(TPS65224_IRQ_BUCK1_UVOV, 0, TPS65224_BIT_BUCK1_UVOV_INT), @@ -681,6 +693,7 @@ int tps6594_device_init(struct tps6594 *tps, bool enable_crc) struct device *dev = tps->dev; int ret; struct regmap_irq_chip *irq_chip; + unsigned int pwr_on, gpio3_cfg; const struct mfd_cell *cells; int n_cells; @@ -727,6 +740,27 @@ int tps6594_device_init(struct tps6594 *tps, bool enable_crc) if (ret) return dev_err_probe(dev, ret, "Failed to add common child devices\n"); + /* If either the PB/EN/VSENSE or GPIO3 is configured as PB, register a driver for it */ + if (tps->chip_id == TPS65224 || tps->chip_id == TPS652G1) { + ret = regmap_read(tps->regmap, TPS6594_REG_NPWRON_CONF, &pwr_on); + if (ret) + return dev_err_probe(dev, ret, "Failed to read PB/EN/VSENSE config\n"); + + ret = regmap_read(tps->regmap, TPS6594_REG_GPIOX_CONF(2), &gpio3_cfg); + if (ret) + return dev_err_probe(dev, ret, "Failed to read GPIO3 config\n"); + + if (FIELD_GET(TPS65224_MASK_EN_PB_VSENSE_CONFIG, pwr_on) == TPS65224_EN_SEL_PB || + FIELD_GET(TPS65224_MASK_GPIO_SEL, gpio3_cfg) == TPS65224_GPIO3_SEL_PB) { + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, + &tps6594_pwrbutton_cell, 1, NULL, 0, + regmap_irq_get_domain(tps->irq_data)); + if (ret) + return dev_err_probe(dev, ret, + "Failed to add power button device.\n"); + } + } + /* No RTC for LP8764, TPS65224 and TPS652G1 */ if (tps->chip_id != LP8764 && tps->chip_id != TPS65224 && tps->chip_id != TPS652G1) { ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, tps6594_rtc_cells, From 2215a87b02ad8d353cd3edebd1bed01db2458986 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Tue, 26 Aug 2025 15:46:31 +0200 Subject: [PATCH 3/3] mfd: tps6594: Add board power-off support Add a system level power-off handler if the "system-power-controller" flag is set for this device in the device tree. A power-off request is triggered by writing the TRIGGER_I2C_0 bit (which is actually just a convention and really depends on the freely programmable FSM). Co-developed-by: Job Sava Signed-off-by: Job Sava Signed-off-by: Michael Walle Link: https://lore.kernel.org/r/20250826134631.1499936-4-mwalle@kernel.org Signed-off-by: Lee Jones --- drivers/mfd/tps6594-core.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/mfd/tps6594-core.c b/drivers/mfd/tps6594-core.c index 9195c9059489..7127af7142f5 100644 --- a/drivers/mfd/tps6594-core.c +++ b/drivers/mfd/tps6594-core.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -688,6 +689,19 @@ static int tps6594_enable_crc(struct tps6594 *tps) return ret; } +static int tps6594_power_off_handler(struct sys_off_data *data) +{ + struct tps6594 *tps = data->cb_data; + int ret; + + ret = regmap_update_bits(tps->regmap, TPS6594_REG_FSM_I2C_TRIGGERS, + TPS6594_BIT_TRIGGER_I2C(0), TPS6594_BIT_TRIGGER_I2C(0)); + if (ret) + return notifier_from_errno(ret); + + return NOTIFY_DONE; +} + int tps6594_device_init(struct tps6594 *tps, bool enable_crc) { struct device *dev = tps->dev; @@ -770,6 +784,12 @@ int tps6594_device_init(struct tps6594 *tps, bool enable_crc) return dev_err_probe(dev, ret, "Failed to add RTC child device\n"); } + if (of_device_is_system_power_controller(dev->of_node)) { + ret = devm_register_power_off_handler(tps->dev, tps6594_power_off_handler, tps); + if (ret) + return dev_err_probe(dev, ret, "Failed to register power-off handler\n"); + } + return 0; } EXPORT_SYMBOL_GPL(tps6594_device_init);