diff mbox series

[10/18] mfd: adp5585: add support for key events

Message ID 20250313-dev-adp5589-fw-v1-10-20e80d4bd4ea@analog.com (mailing list archive)
State New
Headers show
Series mfd: adp5585: support keymap events and drop legacy Input driver | expand

Commit Message

Nuno Sá via B4 Relay March 13, 2025, 2:19 p.m. UTC
From: Nuno Sá <nuno.sa@analog.com>

This adds support for key events. Basically, it adds support for all the
FW parsing and configuration of the keys (also making sure there's no
overlaps). They can either be part of a matrix keymap (in which case
events will be handled by an input device) or they can be gpi's (in which
case events will be handled by the gpiochip device via gpio_keys). There's
also support for unlock keys as for reset keys.

This patch adds all the foundation needed by subsequent changes where the
child devices (actually handling the events) can "register" a callback
to handle the event.

Also to note that enabling the internal oscillator in now done as part of
adp5585_setup().

We also enable/disable the IRQ (if present) in the corresponding PM
event.

Signed-off-by: Nuno Sá <nuno.sa@analog.com>
---
 drivers/mfd/adp5585.c       | 550 +++++++++++++++++++++++++++++++++++++++++++-
 include/linux/mfd/adp5585.h |  96 ++++++++
 2 files changed, 641 insertions(+), 5 deletions(-)

Comments

kernel test robot March 14, 2025, 9:43 a.m. UTC | #1
Hi Nuno,

kernel test robot noticed the following build errors:

[auto build test ERROR on 4d395cb071a343196ca524d3694790f06978fe91]

url:    https://github.com/intel-lab-lkp/linux/commits/Nuno-S-via-B4-Relay/dt-bindings-mfd-adp5585-ease-on-the-required-properties/20250313-222511
base:   4d395cb071a343196ca524d3694790f06978fe91
patch link:    https://lore.kernel.org/r/20250313-dev-adp5589-fw-v1-10-20e80d4bd4ea%40analog.com
patch subject: [PATCH 10/18] mfd: adp5585: add support for key events
config: sparc-randconfig-001-20250314 (https://download.01.org/0day-ci/archive/20250314/202503141730.dPtGWqXX-lkp@intel.com/config)
compiler: sparc-linux-gcc (GCC) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250314/202503141730.dPtGWqXX-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202503141730.dPtGWqXX-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/mfd/adp5585.c: In function 'adp5585_keys_reset_parse':
>> drivers/mfd/adp5585.c:485:47: error: implicit declaration of function 'FIELD_PREP' [-Wimplicit-function-declaration]
     485 |                         adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET1_POL, 1);
         |                                               ^~~~~~~~~~
   drivers/mfd/adp5585.c: In function 'adp5585_report_events':
>> drivers/mfd/adp5585.c:654:27: error: implicit declaration of function 'FIELD_GET' [-Wimplicit-function-declaration]
     654 |                 key_val = FIELD_GET(ADP5585_KEY_EVENT_MASK, key);
         |                           ^~~~~~~~~
   drivers/mfd/adp5585.c: At top level:
   drivers/mfd/adp5585.c:271:34: warning: 'adp5585_02_info' defined but not used [-Wunused-const-variable=]
     271 | static const struct adp5585_info adp5585_02_info = {
         |                                  ^~~~~~~~~~~~~~~
   drivers/mfd/adp5585.c:258:34: warning: 'adp5585_01_info' defined but not used [-Wunused-const-variable=]
     258 | static const struct adp5585_info adp5585_01_info = {
         |                                  ^~~~~~~~~~~~~~~
   drivers/mfd/adp5585.c:246:34: warning: 'adp5585_info' defined but not used [-Wunused-const-variable=]
     246 | static const struct adp5585_info adp5585_info = {
         |                                  ^~~~~~~~~~~~
   drivers/mfd/adp5585.c:49:41: warning: 'adp5589_volatile_regs' defined but not used [-Wunused-const-variable=]
      49 | static const struct regmap_access_table adp5589_volatile_regs = {
         |                                         ^~~~~~~~~~~~~~~~~~~~~


vim +/FIELD_PREP +485 drivers/mfd/adp5585.c

   464	
   465	static int adp5585_keys_reset_parse(struct adp5585_dev *adp5585)
   466	{
   467		const struct adp5585_info *info = adp5585->info;
   468		struct device *dev = adp5585->dev;
   469		u32 prop_val;
   470		int ret;
   471	
   472		ret = adp5585_keys_parse_array(adp5585, "adi,reset1-keys",
   473					       adp5585->reset1_keys,
   474					       &adp5585->nkeys_reset1,
   475					       ARRAY_SIZE(adp5585->reset1_keys), true);
   476		if (ret)
   477			return ret;
   478	
   479		if (adp5585->nkeys_reset1 > 0) {
   480			if (test_bit(ADP5585_ROW4, adp5585->keypad))
   481				return dev_err_probe(dev, -EINVAL,
   482						     "Invalid reset1 output(R4) being used in the keypad\n");
   483	
   484			if (device_property_read_bool(dev, "adi,reset1-active-high"))
 > 485				adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET1_POL, 1);
   486		}
   487	
   488		ret = adp5585_keys_parse_array(adp5585, "adi,reset2-keys",
   489					       adp5585->reset2_keys,
   490					       &adp5585->nkeys_reset2,
   491					       ARRAY_SIZE(adp5585->reset2_keys), true);
   492		if (ret)
   493			return ret;
   494	
   495		if (adp5585->nkeys_reset2 > 0) {
   496			if (test_bit(info->max_rows + ADP5585_COL4, adp5585->keypad))
   497				return dev_err_probe(dev, -EINVAL,
   498						     "Invalid reset2 output(C4) being used in the keypad\n");
   499	
   500			if (device_property_read_bool(dev, "adi,reset2-active-high"))
   501				adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET2_POL, 1);
   502		}
   503	
   504		if (!adp5585->nkeys_reset1 && !adp5585->nkeys_reset2)
   505			return 0;
   506	
   507		if (device_property_read_bool(dev, "adi,rst-passtrough-enable"))
   508			adp5585->reset_cfg |= FIELD_PREP(ADP5585_RST_PASSTHRU_EN, 1);
   509	
   510		ret = device_property_read_u32(dev, "adi,reset-trigger-ms", &prop_val);
   511		if (!ret) {
   512			switch (prop_val) {
   513			case 0:
   514				adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 0);
   515				break;
   516			case 1000:
   517				adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 1);
   518				break;
   519			case 1500:
   520				adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 2);
   521				break;
   522			case 2000:
   523				adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 3);
   524				break;
   525			case 2500:
   526				adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 4);
   527				break;
   528			case 3000:
   529				adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 5);
   530				break;
   531			case 3500:
   532				adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 6);
   533				break;
   534			case 4000:
   535				adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 7);
   536				break;
   537			default:
   538				return dev_err_probe(dev, -EINVAL,
   539						     "Invalid value(%u) for adi,reset-trigger-ms\n",
   540						     prop_val);
   541			}
   542		}
   543	
   544		ret = device_property_read_u32(dev, "adi,reset-pulse-width-us",
   545					       &prop_val);
   546		if (!ret) {
   547			switch (prop_val) {
   548			case 500:
   549				adp5585->reset_cfg |= FIELD_PREP(ADP5585_PULSE_WIDTH, 0);
   550				break;
   551			case 1000:
   552				adp5585->reset_cfg |= FIELD_PREP(ADP5585_PULSE_WIDTH, 1);
   553				break;
   554			case 2000:
   555				adp5585->reset_cfg |= FIELD_PREP(ADP5585_PULSE_WIDTH, 2);
   556				break;
   557			case 10000:
   558				adp5585->reset_cfg |= FIELD_PREP(ADP5585_PULSE_WIDTH, 3);
   559				break;
   560			default:
   561				return dev_err_probe(dev, -EINVAL,
   562						     "Invalid value(%u) for adi,reset-pulse-width-us\n",
   563						     prop_val);
   564			}
   565		}
   566	
   567		return 0;
   568	}
   569	
   570	static int adp5585_parse_fw(struct device *dev, struct adp5585_dev *adp5585)
   571	{
   572		const struct adp5585_info *info = adp5585->info;
   573		unsigned int n_pins = info->max_cols + info->max_rows;
   574		unsigned int *keypad_pins;
   575		unsigned int prop_val;
   576		int n_keys, key, ret;
   577	
   578		adp5585->keypad = devm_bitmap_zalloc(dev, n_pins, GFP_KERNEL);
   579		if (!adp5585->keypad)
   580			return -ENOMEM;
   581	
   582		if (device_property_present(dev, "#pwm-cells"))
   583			adp5585->has_pwm = true;
   584	
   585		n_keys = device_property_count_u32(dev, "adi,keypad-pins");
   586		if (n_keys <= 0)
   587			goto no_keypad;
   588		if (n_keys > n_pins)
   589			return -EINVAL;
   590	
   591		keypad_pins = devm_kcalloc(dev, n_keys, sizeof(*keypad_pins),
   592					   GFP_KERNEL);
   593		if (!keypad_pins)
   594			return -ENOMEM;
   595	
   596		ret = device_property_read_u32_array(dev, "adi,keypad-pins",
   597						     keypad_pins, n_keys);
   598		if (ret)
   599			return ret;
   600	
   601		for (key = 0; key < n_keys; key++) {
   602			if (keypad_pins[key] >= n_pins)
   603				return -EINVAL;
   604			if (adp5585->has_pwm && keypad_pins[key] == ADP5585_ROW3)
   605				return dev_err_probe(dev, -EINVAL,
   606						     "Invalid PWM pin being used in the keypad\n");
   607			if (!info->has_row5 && keypad_pins[key] == ADP5585_ROW5)
   608				return dev_err_probe(dev, -EINVAL,
   609						     "Invalid row5 being used in the keypad\n");
   610			__set_bit(keypad_pins[key], adp5585->keypad);
   611		}
   612	
   613	no_keypad:
   614		ret = device_property_read_u32(dev, "adi,key-poll-ms", &prop_val);
   615		if (!ret) {
   616			switch (prop_val) {
   617			case 10:
   618				fallthrough;
   619			case 20:
   620				fallthrough;
   621			case 30:
   622				fallthrough;
   623			case 40:
   624				adp5585->key_poll_time = prop_val / 10 - 1;
   625				break;
   626			default:
   627				return dev_err_probe(dev, -EINVAL,
   628						     "Invalid value(%u) for adi,key-poll-ms\n",
   629						     prop_val);
   630			}
   631		}
   632	
   633		ret = adp5585_keys_unlock_parse(adp5585);
   634		if (ret)
   635			return ret;
   636	
   637		return adp5585_keys_reset_parse(adp5585);
   638	}
   639	
   640	static void adp5585_report_events(struct adp5585_dev *adp5585, int ev_cnt)
   641	{
   642		unsigned int i;
   643	
   644		guard(mutex)(&adp5585->ev_lock);
   645	
   646		for (i = 0; i < ev_cnt; i++) {
   647			unsigned int key, key_val, key_press;
   648			int ret;
   649	
   650			ret = regmap_read(adp5585->regmap, ADP5585_FIFO_1 + i, &key);
   651			if (ret)
   652				return;
   653	
 > 654			key_val = FIELD_GET(ADP5585_KEY_EVENT_MASK, key);
   655			key_press = FIELD_GET(ADP5585_KEV_EV_PRESS_MASK, key);
   656	
   657			if (key_val >= adp5585->info->gpi_ev_base &&
   658			    key_val <= adp5585->info->gpi_ev_end) {
   659				unsigned int gpi = key_val - adp5585->info->gpi_ev_base;
   660	
   661				if (adp5585->gpio_irq_handle)
   662					adp5585->gpio_irq_handle(adp5585->gpio_dev, gpi,
   663								 key_press);
   664			} else if (adp5585->keys_irq_handle) {
   665				adp5585->keys_irq_handle(adp5585->input_dev, key_val,
   666							 key_press);
   667			}
   668		}
   669	}
   670
diff mbox series

Patch

diff --git a/drivers/mfd/adp5585.c b/drivers/mfd/adp5585.c
index 2fedc1c7cd08a7b3a8c7188d3e7cdfdf3122a214..a96de4e6a3a12e2c91528835c2061795e6ff3ed0 100644
--- a/drivers/mfd/adp5585.c
+++ b/drivers/mfd/adp5585.c
@@ -13,6 +13,7 @@ 
 #include <linux/i2c.h>
 #include <linux/mfd/adp5585.h>
 #include <linux/mfd/core.h>
+#include <linux/minmax.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
@@ -205,11 +206,19 @@  static const struct adp5585_regs adp5585_regs = {
 	.gpo_out_a = ADP5585_GPO_OUT_MODE_A,
 	.gpio_dir_a = ADP5585_GPIO_DIRECTION_A,
 	.gpi_stat_a = ADP5585_GPI_STATUS_A,
+	.gpi_ev_a = ADP5585_GPI_EVENT_EN_A,
+	.gpi_int_lvl_a = ADP5585_GPI_INT_LEVEL_A,
 	.pwm_cfg = ADP5585_PWM_CFG,
 	.pwm_offt_low = ADP5585_PWM_OFFT_LOW,
 	.pwm_ont_low = ADP5585_PWM_ONT_LOW,
+	.reset_cfg = ADP5585_RESET_CFG,
 	.gen_cfg = ADP5585_GENERAL_CFG,
 	.ext_cfg = ADP5585_PIN_CONFIG_C,
+	.pin_cfg_a = ADP5585_PIN_CONFIG_A,
+	.poll_ptime_cfg = ADP5585_POLL_PTIME_CFG,
+	.int_en = ADP5585_INT_EN,
+	.reset1_event_a = ADP5585_RESET1_EVENT_A,
+	.reset2_event_a = ADP5585_RESET2_EVENT_A,
 };
 
 static const struct adp5585_regs adp5589_regs = {
@@ -219,11 +228,19 @@  static const struct adp5585_regs adp5589_regs = {
 	.gpo_out_a = ADP5589_GPO_OUT_MODE_A,
 	.gpio_dir_a = ADP5589_GPIO_DIRECTION_A,
 	.gpi_stat_a = ADP5589_GPI_STATUS_A,
+	.gpi_ev_a = ADP5589_GPI_EVENT_EN_A,
+	.gpi_int_lvl_a = ADP5589_GPI_INT_LEVEL_A,
 	.pwm_cfg = ADP5589_PWM_CFG,
 	.pwm_offt_low = ADP5589_PWM_OFFT_LOW,
 	.pwm_ont_low = ADP5589_PWM_ONT_LOW,
+	.reset_cfg = ADP5589_RESET_CFG,
 	.gen_cfg = ADP5589_GENERAL_CFG,
 	.ext_cfg = ADP5589_PIN_CONFIG_D,
+	.pin_cfg_a = ADP5589_PIN_CONFIG_A,
+	.poll_ptime_cfg = ADP5589_POLL_PTIME_CFG,
+	.int_en = ADP5589_INT_EN,
+	.reset1_event_a = ADP5589_RESET1_EVENT_A,
+	.reset2_event_a = ADP5589_RESET2_EVENT_A,
 };
 
 static const struct adp5585_info adp5585_info = {
@@ -234,6 +251,8 @@  static const struct adp5585_info adp5585_info = {
 	.regs = &adp5585_regs,
 	.max_rows = ADP5585_MAX_ROW_NUM,
 	.max_cols = ADP5585_MAX_COL_NUM,
+	.gpi_ev_base = ADP5585_GPI_EVENT_START,
+	.gpi_ev_end = ADP5585_GPI_EVENT_END,
 };
 
 static const struct adp5585_info adp5585_01_info = {
@@ -241,9 +260,12 @@  static const struct adp5585_info adp5585_01_info = {
 	.regmap_config = &adp5585_regmap_configs[ADP5585_REGMAP_00],
 	.n_devs = ARRAY_SIZE(adp5585_devs),
 	.id = ADP5585_MAN_ID_VALUE,
+	.has_row5 = true,
 	.regs = &adp5585_regs,
 	.max_rows = ADP5585_MAX_ROW_NUM,
 	.max_cols = ADP5585_MAX_COL_NUM,
+	.gpi_ev_base = ADP5585_GPI_EVENT_START,
+	.gpi_ev_end = ADP5585_GPI_EVENT_END,
 };
 
 static const struct adp5585_info adp5585_02_info = {
@@ -254,6 +276,8 @@  static const struct adp5585_info adp5585_02_info = {
 	.regs = &adp5585_regs,
 	.max_rows = ADP5585_MAX_ROW_NUM,
 	.max_cols = ADP5585_MAX_COL_NUM,
+	.gpi_ev_base = ADP5585_GPI_EVENT_START,
+	.gpi_ev_end = ADP5585_GPI_EVENT_END,
 };
 
 static const struct adp5585_info adp5585_04_info = {
@@ -264,6 +288,8 @@  static const struct adp5585_info adp5585_04_info = {
 	.regs = &adp5585_regs,
 	.max_rows = ADP5585_MAX_ROW_NUM,
 	.max_cols = ADP5585_MAX_COL_NUM,
+	.gpi_ev_base = ADP5585_GPI_EVENT_START,
+	.gpi_ev_end = ADP5585_GPI_EVENT_END,
 };
 
 static const struct adp5585_info adp5589_info = {
@@ -271,9 +297,13 @@  static const struct adp5585_info adp5589_info = {
 	.regmap_config = &adp5585_regmap_configs[ADP5589_REGMAP_00],
 	.n_devs = ARRAY_SIZE(adp5589_devs),
 	.id = ADP5589_MAN_ID_VALUE,
+	.has_row5 = true,
+	.has_unlock = true,
 	.regs = &adp5589_regs,
 	.max_rows = ADP5589_MAX_ROW_NUM,
 	.max_cols = ADP5589_MAX_COL_NUM,
+	.gpi_ev_base = ADP5589_GPI_EVENT_START,
+	.gpi_ev_end = ADP5589_GPI_EVENT_END,
 };
 
 static const struct adp5585_info adp5589_01_info = {
@@ -281,9 +311,13 @@  static const struct adp5585_info adp5589_01_info = {
 	.regmap_config = &adp5585_regmap_configs[ADP5589_REGMAP_01],
 	.n_devs = ARRAY_SIZE(adp5589_devs),
 	.id = ADP5589_MAN_ID_VALUE,
+	.has_row5 = true,
+	.has_unlock = true,
 	.regs = &adp5589_regs,
 	.max_rows = ADP5589_MAX_ROW_NUM,
 	.max_cols = ADP5589_MAX_COL_NUM,
+	.gpi_ev_base = ADP5589_GPI_EVENT_START,
+	.gpi_ev_end = ADP5589_GPI_EVENT_END,
 };
 
 static const struct adp5585_info adp5589_02_info = {
@@ -291,11 +325,379 @@  static const struct adp5585_info adp5589_02_info = {
 	.regmap_config = &adp5585_regmap_configs[ADP5589_REGMAP_02],
 	.n_devs = ARRAY_SIZE(adp5589_devs),
 	.id = ADP5589_MAN_ID_VALUE,
+	.has_row5 = true,
+	.has_unlock = true,
 	.regs = &adp5589_regs,
 	.max_rows = ADP5589_MAX_ROW_NUM,
 	.max_cols = ADP5589_MAX_COL_NUM,
+	.gpi_ev_base = ADP5589_GPI_EVENT_START,
+	.gpi_ev_end = ADP5589_GPI_EVENT_END,
 };
 
+static int adp5585_keys_validate_key(const struct adp5585_dev *adp5585, u32 key,
+				     bool is_gpi)
+{
+	const struct adp5585_info *info = adp5585->info;
+	struct device *dev = adp5585->dev;
+	u32 row, col;
+
+	if (is_gpi) {
+		u32 gpi = key - adp5585->info->gpi_ev_base;
+
+		if (!info->has_row5 && gpi == ADP5585_ROW5)
+			return dev_err_probe(dev, -EINVAL,
+					     "Invalid unlock/reset GPI(%u) not supported\n",
+					     gpi);
+
+		/* check if it's being used in the keypad */
+		if (test_bit(gpi, adp5585->keypad))
+			return dev_err_probe(dev, -EINVAL,
+					     "Invalid unlock/reset GPI(%u) being used in the keypad\n",
+					     gpi);
+
+		return 0;
+	}
+
+	row = (key - 1) / info->max_cols;
+	col = (key - 1) % info->max_cols;
+
+	/* both the row and col must be part of the keypad */
+	if (test_bit(row, adp5585->keypad) &&
+	    test_bit(col + info->max_rows, adp5585->keypad))
+		return 0;
+
+	return dev_err_probe(dev, -EINVAL,
+			     "Invalid unlock/reset key(%u) not used in the keypad\n", key);
+}
+
+static int adp5585_keys_parse_array(const struct adp5585_dev *adp5585,
+				    const char *prop, u32 *keys, u32 *n_keys,
+				    u32 max_keys, bool reset_key)
+{
+	const struct adp5585_info *info = adp5585->info;
+	struct device *dev = adp5585->dev;
+	unsigned int key, max_keypad;
+	int ret;
+
+	ret = device_property_count_u32(dev, prop);
+	if (ret < 0)
+		return 0;
+
+	*n_keys = ret;
+
+	if (!info->has_unlock && !reset_key)
+		return dev_err_probe(dev, -EOPNOTSUPP,
+				     "Unlock keys not supported\n");
+
+	if (*n_keys > max_keys)
+		return dev_err_probe(dev, -EINVAL,
+				     "Invalid number of keys(%u > %u) for %s\n",
+				     *n_keys, max_keys, prop);
+
+	ret = device_property_read_u32_array(dev, prop, keys, *n_keys);
+	if (ret)
+		return ret;
+
+	max_keypad = adp5585->info->max_rows * adp5585->info->max_cols;
+
+	for (key = 0; key < *n_keys; key++) {
+		/* part of the keypad... */
+		if (in_range(keys[key], 1, max_keypad)) {
+			/* is it part of the keypad?! */
+			ret = adp5585_keys_validate_key(adp5585, keys[key],
+							false);
+			if (ret)
+				return ret;
+
+			continue;
+		}
+
+		/* part of gpio-keys... */
+		if (in_range(keys[key], adp5585->info->gpi_ev_base,
+			     info->max_cols + info->max_rows)) {
+			/* is the GPI being used as part of the keypad?! */
+			ret = adp5585_keys_validate_key(adp5585, keys[key],
+							true);
+			if (ret)
+				return ret;
+
+			continue;
+		}
+
+		if (!reset_key && keys[key] == 127)
+			continue;
+
+		return dev_err_probe(dev, -EINVAL, "Invalid key(%u) for %s\n",
+				     keys[key], prop);
+	}
+
+	return 0;
+}
+
+static int adp5585_keys_unlock_parse(struct adp5585_dev *adp5585)
+{
+	struct device *dev = adp5585->dev;
+	int ret;
+
+	ret = adp5585_keys_parse_array(adp5585, "adi,unlock-keys",
+				       adp5585->unlock_keys,
+				       &adp5585->nkeys_unlock,
+				       ARRAY_SIZE(adp5585->unlock_keys), false);
+	if (ret)
+		return ret;
+	if (!adp5585->nkeys_unlock)
+		/* no unlock keys */
+		return 0;
+
+	ret = device_property_read_u32(dev, "adi,unlock-trigger-sec",
+				       &adp5585->unlock_time);
+	if (!ret) {
+		if (adp5585->unlock_time > ADP5585_MAX_UNLOCK_TIME_SEC)
+			return dev_err_probe(dev, -EINVAL,
+					     "Invalid unlock time(%u > %d)\n",
+					     adp5585->unlock_time,
+					     ADP5585_MAX_UNLOCK_TIME_SEC);
+	}
+
+	return 0;
+}
+
+static int adp5585_keys_reset_parse(struct adp5585_dev *adp5585)
+{
+	const struct adp5585_info *info = adp5585->info;
+	struct device *dev = adp5585->dev;
+	u32 prop_val;
+	int ret;
+
+	ret = adp5585_keys_parse_array(adp5585, "adi,reset1-keys",
+				       adp5585->reset1_keys,
+				       &adp5585->nkeys_reset1,
+				       ARRAY_SIZE(adp5585->reset1_keys), true);
+	if (ret)
+		return ret;
+
+	if (adp5585->nkeys_reset1 > 0) {
+		if (test_bit(ADP5585_ROW4, adp5585->keypad))
+			return dev_err_probe(dev, -EINVAL,
+					     "Invalid reset1 output(R4) being used in the keypad\n");
+
+		if (device_property_read_bool(dev, "adi,reset1-active-high"))
+			adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET1_POL, 1);
+	}
+
+	ret = adp5585_keys_parse_array(adp5585, "adi,reset2-keys",
+				       adp5585->reset2_keys,
+				       &adp5585->nkeys_reset2,
+				       ARRAY_SIZE(adp5585->reset2_keys), true);
+	if (ret)
+		return ret;
+
+	if (adp5585->nkeys_reset2 > 0) {
+		if (test_bit(info->max_rows + ADP5585_COL4, adp5585->keypad))
+			return dev_err_probe(dev, -EINVAL,
+					     "Invalid reset2 output(C4) being used in the keypad\n");
+
+		if (device_property_read_bool(dev, "adi,reset2-active-high"))
+			adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET2_POL, 1);
+	}
+
+	if (!adp5585->nkeys_reset1 && !adp5585->nkeys_reset2)
+		return 0;
+
+	if (device_property_read_bool(dev, "adi,rst-passtrough-enable"))
+		adp5585->reset_cfg |= FIELD_PREP(ADP5585_RST_PASSTHRU_EN, 1);
+
+	ret = device_property_read_u32(dev, "adi,reset-trigger-ms", &prop_val);
+	if (!ret) {
+		switch (prop_val) {
+		case 0:
+			adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 0);
+			break;
+		case 1000:
+			adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 1);
+			break;
+		case 1500:
+			adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 2);
+			break;
+		case 2000:
+			adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 3);
+			break;
+		case 2500:
+			adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 4);
+			break;
+		case 3000:
+			adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 5);
+			break;
+		case 3500:
+			adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 6);
+			break;
+		case 4000:
+			adp5585->reset_cfg |= FIELD_PREP(ADP5585_RESET_TRIG_TIME, 7);
+			break;
+		default:
+			return dev_err_probe(dev, -EINVAL,
+					     "Invalid value(%u) for adi,reset-trigger-ms\n",
+					     prop_val);
+		}
+	}
+
+	ret = device_property_read_u32(dev, "adi,reset-pulse-width-us",
+				       &prop_val);
+	if (!ret) {
+		switch (prop_val) {
+		case 500:
+			adp5585->reset_cfg |= FIELD_PREP(ADP5585_PULSE_WIDTH, 0);
+			break;
+		case 1000:
+			adp5585->reset_cfg |= FIELD_PREP(ADP5585_PULSE_WIDTH, 1);
+			break;
+		case 2000:
+			adp5585->reset_cfg |= FIELD_PREP(ADP5585_PULSE_WIDTH, 2);
+			break;
+		case 10000:
+			adp5585->reset_cfg |= FIELD_PREP(ADP5585_PULSE_WIDTH, 3);
+			break;
+		default:
+			return dev_err_probe(dev, -EINVAL,
+					     "Invalid value(%u) for adi,reset-pulse-width-us\n",
+					     prop_val);
+		}
+	}
+
+	return 0;
+}
+
+static int adp5585_parse_fw(struct device *dev, struct adp5585_dev *adp5585)
+{
+	const struct adp5585_info *info = adp5585->info;
+	unsigned int n_pins = info->max_cols + info->max_rows;
+	unsigned int *keypad_pins;
+	unsigned int prop_val;
+	int n_keys, key, ret;
+
+	adp5585->keypad = devm_bitmap_zalloc(dev, n_pins, GFP_KERNEL);
+	if (!adp5585->keypad)
+		return -ENOMEM;
+
+	if (device_property_present(dev, "#pwm-cells"))
+		adp5585->has_pwm = true;
+
+	n_keys = device_property_count_u32(dev, "adi,keypad-pins");
+	if (n_keys <= 0)
+		goto no_keypad;
+	if (n_keys > n_pins)
+		return -EINVAL;
+
+	keypad_pins = devm_kcalloc(dev, n_keys, sizeof(*keypad_pins),
+				   GFP_KERNEL);
+	if (!keypad_pins)
+		return -ENOMEM;
+
+	ret = device_property_read_u32_array(dev, "adi,keypad-pins",
+					     keypad_pins, n_keys);
+	if (ret)
+		return ret;
+
+	for (key = 0; key < n_keys; key++) {
+		if (keypad_pins[key] >= n_pins)
+			return -EINVAL;
+		if (adp5585->has_pwm && keypad_pins[key] == ADP5585_ROW3)
+			return dev_err_probe(dev, -EINVAL,
+					     "Invalid PWM pin being used in the keypad\n");
+		if (!info->has_row5 && keypad_pins[key] == ADP5585_ROW5)
+			return dev_err_probe(dev, -EINVAL,
+					     "Invalid row5 being used in the keypad\n");
+		__set_bit(keypad_pins[key], adp5585->keypad);
+	}
+
+no_keypad:
+	ret = device_property_read_u32(dev, "adi,key-poll-ms", &prop_val);
+	if (!ret) {
+		switch (prop_val) {
+		case 10:
+			fallthrough;
+		case 20:
+			fallthrough;
+		case 30:
+			fallthrough;
+		case 40:
+			adp5585->key_poll_time = prop_val / 10 - 1;
+			break;
+		default:
+			return dev_err_probe(dev, -EINVAL,
+					     "Invalid value(%u) for adi,key-poll-ms\n",
+					     prop_val);
+		}
+	}
+
+	ret = adp5585_keys_unlock_parse(adp5585);
+	if (ret)
+		return ret;
+
+	return adp5585_keys_reset_parse(adp5585);
+}
+
+static void adp5585_report_events(struct adp5585_dev *adp5585, int ev_cnt)
+{
+	unsigned int i;
+
+	guard(mutex)(&adp5585->ev_lock);
+
+	for (i = 0; i < ev_cnt; i++) {
+		unsigned int key, key_val, key_press;
+		int ret;
+
+		ret = regmap_read(adp5585->regmap, ADP5585_FIFO_1 + i, &key);
+		if (ret)
+			return;
+
+		key_val = FIELD_GET(ADP5585_KEY_EVENT_MASK, key);
+		key_press = FIELD_GET(ADP5585_KEV_EV_PRESS_MASK, key);
+
+		if (key_val >= adp5585->info->gpi_ev_base &&
+		    key_val <= adp5585->info->gpi_ev_end) {
+			unsigned int gpi = key_val - adp5585->info->gpi_ev_base;
+
+			if (adp5585->gpio_irq_handle)
+				adp5585->gpio_irq_handle(adp5585->gpio_dev, gpi,
+							 key_press);
+		} else if (adp5585->keys_irq_handle) {
+			adp5585->keys_irq_handle(adp5585->input_dev, key_val,
+						 key_press);
+		}
+	}
+}
+
+static irqreturn_t adp5585_irq(int irq, void *data)
+{
+	struct adp5585_dev *adp5585 = data;
+	unsigned int status, ev_cnt;
+	int ret;
+
+	ret = regmap_read(adp5585->regmap, ADP5585_INT_STATUS, &status);
+	if (ret)
+		return IRQ_HANDLED;
+
+	if (status & ADP5585_OVRFLOW_INT)
+		dev_err_ratelimited(adp5585->dev, "Event Overflow Error\n");
+
+	if (!(status & ADP5585_EVENT_INT))
+		goto out_irq;
+
+	ret = regmap_read(adp5585->regmap, ADP5585_STATUS, &ev_cnt);
+	if (ret)
+		goto out_irq;
+
+	ev_cnt = FIELD_GET(ADP5585_EC_MASK, ev_cnt);
+	if (!ev_cnt)
+		goto out_irq;
+
+	adp5585_report_events(adp5585, ev_cnt);
+out_irq:
+	regmap_write(adp5585->regmap, ADP5585_INT_STATUS, status);
+	return IRQ_HANDLED;
+}
+
 static void adp5585_osc_disable(void *data)
 {
 	const struct adp5585_dev *adp5585 = data;
@@ -303,6 +705,128 @@  static void adp5585_osc_disable(void *data)
 	regmap_write(adp5585->regmap, ADP5585_GENERAL_CFG, 0);
 }
 
+static int adp5585_setup(struct adp5585_dev *adp5585)
+{
+	const struct adp5585_regs *regs = adp5585->info->regs;
+	unsigned int reg_val, i;
+	int ret;
+
+	for (i = 0; i < adp5585->nkeys_unlock; i++) {
+		ret = regmap_write(adp5585->regmap, ADP5589_UNLOCK1 + i,
+				   adp5585->unlock_keys[i] | ADP5589_UNLOCK_EV_PRESS);
+		if (ret)
+			return ret;
+	}
+
+	if (adp5585->nkeys_unlock) {
+		ret = regmap_update_bits(adp5585->regmap, ADP5589_UNLOCK_TIMERS,
+					 ADP5589_UNLOCK_TIMER,
+					 adp5585->unlock_time);
+		if (ret)
+			return ret;
+
+		ret = regmap_set_bits(adp5585->regmap, ADP5589_LOCK_CFG,
+				      ADP5589_LOCK_EN);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < adp5585->nkeys_reset1; i++) {
+		ret = regmap_write(adp5585->regmap, regs->reset1_event_a + i,
+				   adp5585->reset1_keys[i] | ADP5585_RESET_EV_PRESS);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < adp5585->nkeys_reset2; i++) {
+		ret = regmap_write(adp5585->regmap, regs->reset2_event_a + i,
+				   adp5585->reset2_keys[i] | ADP5585_RESET_EV_PRESS);
+		if (ret)
+			return ret;
+	}
+
+	if (adp5585->nkeys_reset1 || adp5585->nkeys_reset2) {
+		ret = regmap_write(adp5585->regmap, regs->reset_cfg,
+				   adp5585->reset_cfg);
+		if (ret)
+			return ret;
+
+		reg_val = 0;
+		if (adp5585->nkeys_reset1)
+			reg_val = ADP5585_R4_EXTEND_CFG_RESET1;
+		if (adp5585->nkeys_reset2)
+			reg_val |= ADP5585_C4_EXTEND_CFG_RESET2;
+
+		ret = regmap_update_bits(adp5585->regmap, regs->ext_cfg,
+					 ADP5585_C4_EXTEND_CFG_MASK |
+						 ADP5585_R4_EXTEND_CFG_MASK,
+					 reg_val);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < ADP5585_EV_MAX; i++) {
+		ret = regmap_read(adp5585->regmap, ADP5585_FIFO_1 + i,
+				  &reg_val);
+		if (ret)
+			return ret;
+	}
+
+	ret = regmap_write(adp5585->regmap, regs->poll_ptime_cfg,
+			   adp5585->key_poll_time);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(adp5585->regmap, regs->gen_cfg,
+			   ADP5585_OSC_FREQ_500KHZ | ADP5585_INT_CFG |
+			   ADP5585_OSC_EN);
+	if (ret)
+		return ret;
+
+	return devm_add_action_or_reset(adp5585->dev, adp5585_osc_disable,
+					adp5585);
+}
+
+static void adp5585_irq_disable(void *data)
+{
+	struct adp5585_dev *adp5585 = data;
+
+	regmap_write(adp5585->regmap, adp5585->info->regs->int_en, 0);
+}
+
+static int adp5585_irq_enable(struct i2c_client *i2c,
+			      struct adp5585_dev *adp5585)
+{
+	const struct adp5585_regs *regs = adp5585->info->regs;
+	unsigned int stat;
+	int ret;
+
+	if (i2c->irq <= 0)
+		return 0;
+
+	ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, adp5585_irq,
+					IRQF_ONESHOT, i2c->name, adp5585);
+	if (ret)
+		return ret;
+
+	/* clear any possible outstanding interrupt before enabling them... */
+	ret = regmap_read(adp5585->regmap, ADP5585_INT_STATUS, &stat);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(adp5585->regmap, ADP5585_INT_STATUS, stat);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(adp5585->regmap, regs->int_en,
+			   ADP5585_OVRFLOW_IEN | ADP5585_EVENT_IEN);
+	if (ret)
+		return ret;
+
+	return devm_add_action_or_reset(&i2c->dev, adp5585_irq_disable,
+					adp5585);
+}
+
 static int adp5585_i2c_probe(struct i2c_client *i2c)
 {
 	const struct adp5585_info *info;
@@ -321,6 +845,8 @@  static int adp5585_i2c_probe(struct i2c_client *i2c)
 		return -ENODEV;
 
 	adp5585->info = info;
+	adp5585->dev = &i2c->dev;
+	adp5585->irq = i2c->irq;
 
 	adp5585->regmap = devm_regmap_init_i2c(i2c, info->regmap_config);
 	if (IS_ERR(adp5585->regmap))
@@ -337,12 +863,15 @@  static int adp5585_i2c_probe(struct i2c_client *i2c)
 		return dev_err_probe(&i2c->dev, -ENODEV,
 				     "Invalid device ID 0x%02x\n", id);
 
-	ret = regmap_set_bits(adp5585->regmap, ADP5585_GENERAL_CFG,
-			      ADP5585_OSC_EN);
+	ret = adp5585_parse_fw(&i2c->dev, adp5585);
 	if (ret)
 		return ret;
 
-	ret = devm_add_action_or_reset(&i2c->dev, adp5585_osc_disable, adp5585);
+	ret = adp5585_setup(adp5585);
+	if (ret)
+		return ret;
+
+	ret = devm_mutex_init(&i2c->dev, &adp5585->ev_lock);
 	if (ret)
 		return ret;
 
@@ -353,13 +882,16 @@  static int adp5585_i2c_probe(struct i2c_client *i2c)
 		return dev_err_probe(&i2c->dev, ret,
 				     "Failed to add child devices\n");
 
-	return 0;
+	return adp5585_irq_enable(i2c, adp5585);
 }
 
 static int adp5585_suspend(struct device *dev)
 {
 	struct adp5585_dev *adp5585 = dev_get_drvdata(dev);
 
+	if (adp5585->irq)
+		disable_irq(adp5585->irq);
+
 	regcache_cache_only(adp5585->regmap, true);
 
 	return 0;
@@ -368,11 +900,19 @@  static int adp5585_suspend(struct device *dev)
 static int adp5585_resume(struct device *dev)
 {
 	struct adp5585_dev *adp5585 = dev_get_drvdata(dev);
+	int ret;
 
 	regcache_cache_only(adp5585->regmap, false);
 	regcache_mark_dirty(adp5585->regmap);
 
-	return regcache_sync(adp5585->regmap);
+	ret = regcache_sync(adp5585->regmap);
+	if (ret)
+		return ret;
+
+	if (adp5585->irq)
+		enable_irq(adp5585->irq);
+
+	return 0;
 }
 
 static DEFINE_SIMPLE_DEV_PM_OPS(adp5585_pm, adp5585_suspend, adp5585_resume);
diff --git a/include/linux/mfd/adp5585.h b/include/linux/mfd/adp5585.h
index dffe1449de01dacf8fe78cf0e87d1f176d11f620..3ec542bed9c1c44899cc869d957557813e2d0aab 100644
--- a/include/linux/mfd/adp5585.h
+++ b/include/linux/mfd/adp5585.h
@@ -10,13 +10,21 @@ 
 #define __MFD_ADP5585_H_
 
 #include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/mutex.h>
 
 #define ADP5585_ID			0x00
 #define		ADP5585_MAN_ID_VALUE		0x20
 #define		ADP5585_MAN_ID_MASK		GENMASK(7, 4)
+#define		ADP5585_REV_ID_MASK		GENMASK(3, 0)
 #define ADP5585_INT_STATUS		0x01
+#define		ADP5585_OVRFLOW_INT		BIT(2)
+#define		ADP5585_EVENT_INT		BIT(0)
 #define ADP5585_STATUS			0x02
+#define		ADP5585_EC_MASK			GENMASK(4, 0)
 #define ADP5585_FIFO_1			0x03
+#define		ADP5585_KEV_EV_PRESS_MASK	BIT(7)
+#define		ADP5585_KEY_EVENT_MASK		GENMASK(6, 0)
 #define ADP5585_FIFO_2			0x04
 #define ADP5585_FIFO_3			0x05
 #define ADP5585_FIFO_4			0x06
@@ -32,6 +40,7 @@ 
 #define ADP5585_FIFO_14			0x10
 #define ADP5585_FIFO_15			0x11
 #define ADP5585_FIFO_16			0x12
+#define		ADP5585_EV_MAX			(ADP5585_FIFO_16 - ADP5585_FIFO_1 + 1)
 #define ADP5585_GPI_INT_STAT_A		0x13
 #define ADP5585_GPI_INT_STAT_B		0x14
 #define ADP5585_GPI_STATUS_A		0x15
@@ -60,6 +69,7 @@ 
 #define ADP5585_GPIO_DIRECTION_A	0x27
 #define ADP5585_GPIO_DIRECTION_B	0x28
 #define ADP5585_RESET1_EVENT_A		0x29
+#define		ADP5585_RESET_EV_PRESS		BIT(7)
 #define ADP5585_RESET1_EVENT_B		0x2a
 #define ADP5585_RESET1_EVENT_C		0x2b
 #define ADP5585_RESET2_EVENT_A		0x2c
@@ -104,8 +114,17 @@ 
 #define		ADP5585_INT_CFG			BIT(1)
 #define		ADP5585_RST_CFG			BIT(0)
 #define ADP5585_INT_EN			0x3c
+#define		ADP5585_OVRFLOW_IEN		BIT(2)
+#define		ADP5585_EVENT_IEN		BIT(0)
 #define ADP5585_MAX_REG			ADP5585_INT_EN
 
+#define ADP5585_ROW3			3
+#define ADP5585_ROW4			4
+#define ADP5585_ROW5			5
+#define ADP5585_COL4			4
+#define ADP5585_MAX_UNLOCK_TIME_SEC	7
+#define ADP5585_GPI_EVENT_START		37
+#define ADP5585_GPI_EVENT_END		47
 #define ADP5585_MAX_ROW_NUM		6
 #define ADP5585_MAX_COL_NUM		5
 
@@ -124,18 +143,38 @@ 
 #define ADP5589_GPI_STATUS_A		0x16
 #define ADP5589_GPI_STATUS_C		0x18
 #define ADP5589_RPULL_CONFIG_A		0x19
+#define ADP5589_GPI_INT_LEVEL_A		0x1e
+#define ADP5589_GPI_EVENT_EN_A		0x21
 #define ADP5589_DEBOUNCE_DIS_A		0x27
 #define ADP5589_GPO_DATA_OUT_A		0x2a
 #define ADP5589_GPO_OUT_MODE_A		0x2d
 #define	ADP5589_GPIO_DIRECTION_A	0x30
+#define ADP5589_UNLOCK1			0x33
+#define		ADP5589_UNLOCK_EV_PRESS		BIT(7)
+#define ADP5589_UNLOCK_TIMERS		0x36
+#define		ADP5589_UNLOCK_TIMER		GENMASK(2, 0)
+#define ADP5589_LOCK_CFG		0x37
+#define		ADP5589_LOCK_EN			BIT(0)
+#define ADP5589_RESET1_EVENT_A		0x38
+#define ADP5589_RESET2_EVENT_A		0x3B
+#define ADP5589_RESET_CFG		0x3D
+#define		ADP5585_RESET2_POL		BIT(7)
+#define		ADP5585_RESET1_POL		BIT(6)
+#define		ADP5585_RST_PASSTHRU_EN		BIT(5)
+#define		ADP5585_RESET_TRIG_TIME		GENMASK(4, 2)
+#define		ADP5585_PULSE_WIDTH		GENMASK(1, 0)
 #define ADP5589_PWM_OFFT_LOW		0x3e
 #define ADP5589_PWM_ONT_LOW		0x40
 #define ADP5589_PWM_CFG			0x42
+#define ADP5589_POLL_PTIME_CFG		0x48
+#define ADP5589_PIN_CONFIG_A		0x49
 #define ADP5589_PIN_CONFIG_D		0x4C
 #define ADP5589_GENERAL_CFG		0x4d
 #define ADP5589_INT_EN			0x4e
 #define ADP5589_MAX_REG			ADP5589_INT_EN
 
+#define ADP5589_GPI_EVENT_START		97
+#define ADP5589_GPI_EVENT_END		115
 #define ADP5589_MAX_ROW_NUM		8
 #define ADP5589_MAX_COL_NUM		11
 
@@ -154,11 +193,19 @@  struct adp5585_regs {
 	unsigned int gpo_out_a;
 	unsigned int gpio_dir_a;
 	unsigned int gpi_stat_a;
+	unsigned int gpi_ev_a;
+	unsigned int gpi_int_lvl_a;
 	unsigned int pwm_cfg;
 	unsigned int pwm_offt_low;
 	unsigned int pwm_ont_low;
+	unsigned int reset_cfg;
 	unsigned int gen_cfg;
 	unsigned int ext_cfg;
+	unsigned int pin_cfg_a;
+	unsigned int poll_ptime_cfg;
+	unsigned int int_en;
+	unsigned int reset1_event_a;
+	unsigned int reset2_event_a;
 };
 
 struct adp5585_info {
@@ -169,6 +216,10 @@  struct adp5585_info {
 	unsigned int id;
 	u8 max_rows;
 	u8 max_cols;
+	u8 gpi_ev_base;
+	u8 gpi_ev_end;
+	bool has_row5;
+	bool has_unlock;
 };
 
 struct regmap;
@@ -176,6 +227,51 @@  struct regmap;
 struct adp5585_dev {
 	struct regmap *regmap;
 	const struct adp5585_info *info;
+	struct device *dev;
+	unsigned long *keypad;
+	void (*gpio_irq_handle)(struct device *dev, unsigned int off,
+				bool key_press);
+	struct device *gpio_dev;
+	void (*keys_irq_handle)(struct device *dev, unsigned int off,
+				bool key_press);
+	struct device *input_dev;
+	/*
+	 * Used to synchronize usage (and availability) of gpio_irq_handle()
+	 * and keys_irq_handle().
+	 */
+	struct mutex ev_lock;
+	int irq;
+	u32 key_poll_time;
+	u32 unlock_time;
+	u32 unlock_keys[2];
+	u32 nkeys_unlock;
+	u32 reset1_keys[3];
+	u32 nkeys_reset1;
+	u32 reset2_keys[2];
+	u32 nkeys_reset2;
+	u8 reset_cfg;
+	bool has_pwm;
 };
 
+static inline void adp5585_gpio_ev_handle_set(struct adp5585_dev *adp5585,
+					      void (*handle)(struct device *dev,
+							     unsigned int off,
+							     bool key_press),
+					      struct device *gpio_dev)
+{
+	guard(mutex)(&adp5585->ev_lock);
+	adp5585->gpio_irq_handle = handle;
+	adp5585->gpio_dev = gpio_dev;
+}
+
+static inline void adp5585_keys_ev_handle_set(struct adp5585_dev *adp5585,
+					      void (*handle)(struct device *dev,
+							     unsigned int off,
+							     bool key_press),
+					      struct device *input_dev)
+{
+	guard(mutex)(&adp5585->ev_lock);
+	adp5585->keys_irq_handle = handle;
+	adp5585->input_dev = input_dev;
+}
 #endif