From: Svyatoslav Ryhel Date: Tue, 25 Mar 2025 18:23:07 +0000 (+0200) Subject: input: add support for CPCAP power button X-Git-Tag: v2025.07-rc1~69^2~12 X-Git-Url: http://git.openpandora.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a9bf7e70c587b67bdb27ffd739c3553d1e08d573;p=pandora-u-boot.git input: add support for CPCAP power button CPCAP has a dedicated interrupt for power button. Implement this to have more input control over the devices. Signed-off-by: Svyatoslav Ryhel --- diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index c2b365af11d..c09f0ae795e 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -55,6 +55,12 @@ config BUTTON_KEYBOARD dt node to define button-event mapping. For example, an arrows and enter may be implemented to navigate boot menu. +config CPCAP_POWER_BUTTON + bool "Enable power button of CPCAP PMIC support" + depends on DM_KEYBOARD && DM_PMIC_CPCAP + help + Enable support for a dedicated power button of the CPCAP PMIC. + config CROS_EC_KEYB bool "Enable Chrome OS EC keyboard support" depends on INPUT diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 8d4107b8848..1303fcdb0b7 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_$(PHASE_)CROS_EC_KEYB) += cros_ec_keyb.o obj-$(CONFIG_$(PHASE_)OF_CONTROL) += key_matrix.o obj-$(CONFIG_$(PHASE_)DM_KEYBOARD) += input.o keyboard-uclass.o obj-$(CONFIG_BUTTON_KEYBOARD) += button_kbd.o +obj-$(CONFIG_CPCAP_POWER_BUTTON) += cpcap_pwrbutton.o ifndef CONFIG_XPL_BUILD diff --git a/drivers/input/cpcap_pwrbutton.c b/drivers/input/cpcap_pwrbutton.c new file mode 100644 index 00000000000..c8ad39d33ca --- /dev/null +++ b/drivers/input/cpcap_pwrbutton.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright(C) 2025 Svyatoslav Ryhel + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const unsigned int cpcpap_to_reg[] = { + CPCAP_REG_INT1, + CPCAP_REG_INT2, + CPCAP_REG_INT3, + CPCAP_REG_INT4, +}; + +/** + * struct cpcap_pwrbutton_priv + * + * @bank: id of interrupt bank co-responding to an IRQ register + * @id: id of interrupt pin co-responding to the bit in IRQ register + * @keycode: linux key code + * @old_state: holder of last button state + * @skip: holder of keycode skip state. This is required since both pressing + * and releasing generate same event and cause key send duplication. + */ +struct cpcap_pwrbutton_priv { + u32 bank; + u32 id; + + u32 keycode; + + bool old_state; + bool skip; +}; + +static int cpcap_pwrbutton_read_keys(struct input_config *input) +{ + struct udevice *dev = input->dev; + struct cpcap_pwrbutton_priv *priv = dev_get_priv(dev); + u32 value, state_changed; + bool state; + + value = pmic_reg_read(dev->parent, cpcpap_to_reg[priv->bank]) & + BIT(priv->id); + + /* Interrupt bit is cleared by writing it to interrupt reg */ + pmic_reg_write(dev->parent, cpcpap_to_reg[priv->bank], BIT(priv->id)); + + state = value >> priv->id; + state_changed = state != priv->old_state; + + if (state_changed && !priv->skip) { + priv->old_state = state; + input_add_keycode(input, priv->keycode, state); + } + + if (state) + priv->skip = !priv->skip; + + return 0; +} + +static int cpcap_pwrbutton_of_to_plat(struct udevice *dev) +{ + struct cpcap_pwrbutton_priv *priv = dev_get_priv(dev); + ofnode irq_parent; + u32 irq_desc; + int ret; + + /* Check interrupt parent, driver supports only CPCAP as parent */ + irq_parent = ofnode_parse_phandle(dev_ofnode(dev), "interrupt-parent", 0); + if (!ofnode_device_is_compatible(irq_parent, "motorola,cpcap")) + return -EINVAL; + + ret = dev_read_u32(dev, "interrupts", &irq_desc); + if (ret) + return ret; + + /* IRQ registers are 16 bit wide */ + priv->bank = irq_desc / 16; + priv->id = irq_desc % 16; + + ret = dev_read_u32(dev, "linux,code", &priv->keycode); + if (ret) + return ret; + + priv->old_state = false; + priv->skip = false; + return 0; +} + +static int cpcap_pwrbutton_probe(struct udevice *dev) +{ + struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev); + struct stdio_dev *sdev = &uc_priv->sdev; + struct input_config *input = &uc_priv->input; + int ret; + + input_init(input, false); + input_add_tables(input, false); + + /* Register the device */ + input->dev = dev; + input->read_keys = cpcap_pwrbutton_read_keys; + strcpy(sdev->name, "cpcap-pwrbutton"); + ret = input_stdio_register(sdev); + if (ret) { + log_debug("%s: input_stdio_register() failed\n", __func__); + return ret; + } + + return 0; +} + +static const struct udevice_id cpcap_pwrbutton_ids[] = { + { .compatible = "motorola,cpcap-pwrbutton" }, + { } +}; + +U_BOOT_DRIVER(cpcap_pwrbutton) = { + .name = "cpcap_pwrbutton", + .id = UCLASS_KEYBOARD, + .of_match = cpcap_pwrbutton_ids, + .of_to_plat = cpcap_pwrbutton_of_to_plat, + .probe = cpcap_pwrbutton_probe, + .priv_auto = sizeof(struct cpcap_pwrbutton_priv), +};