diff options
| author | Nuno Sá <nuno.sa@analog.com> | 2025-07-01 15:32:09 +0100 |
|---|---|---|
| committer | Lee Jones <lee@kernel.org> | 2025-07-01 21:50:51 +0100 |
| commit | bd113a13e1fa51789f55987369b80e1d8bc19389 (patch) | |
| tree | 9f64ee316fe5341cca81a4c320ebf80f249aa105 /drivers/mfd | |
| parent | 333812da70d5f71bf5e176f6d55a5f716301b5fc (diff) | |
mfd: adp5585: Add support for input devices
The ADP558x family supports a built in keypad matrix decoder which can
be added as an Input device. In order to both support the Input and the
GPIO device, we need to create a bitmap of the supported pins and track
their usage since they can either be used as GPIOs (GPIs) or as part of
the keymap.
We also need to mark special pins busy in case some features are being
used (ex: pwm or reset events).
Signed-off-by: Nuno Sá <nuno.sa@analog.com>
Link: https://lore.kernel.org/r/20250701-dev-adp5589-fw-v7-14-b1fcfe9e9826@analog.com
Signed-off-by: Lee Jones <lee@kernel.org>
Diffstat (limited to 'drivers/mfd')
| -rw-r--r-- | drivers/mfd/adp5585.c | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/drivers/mfd/adp5585.c b/drivers/mfd/adp5585.c index 30014deee41f..8f0fd7374426 100644 --- a/drivers/mfd/adp5585.c +++ b/drivers/mfd/adp5585.c @@ -22,17 +22,20 @@ enum { ADP5585_DEV_GPIO, ADP5585_DEV_PWM, + ADP5585_DEV_INPUT, ADP5585_DEV_MAX }; static const struct mfd_cell adp5585_devs[ADP5585_DEV_MAX] = { MFD_CELL_NAME("adp5585-gpio"), MFD_CELL_NAME("adp5585-pwm"), + MFD_CELL_NAME("adp5585-keys"), }; static const struct mfd_cell adp5589_devs[] = { MFD_CELL_NAME("adp5589-gpio"), MFD_CELL_NAME("adp5589-pwm"), + MFD_CELL_NAME("adp5589-keys"), }; static const struct regmap_range adp5585_volatile_ranges[] = { @@ -172,6 +175,7 @@ static const struct adp5585_regs adp5585_regs = { .reset_cfg = ADP5585_RESET_CFG, .reset1_event_a = ADP5585_RESET1_EVENT_A, .reset2_event_a = ADP5585_RESET2_EVENT_A, + .pin_cfg_a = ADP5585_PIN_CONFIG_A, }; static const struct adp5585_regs adp5589_regs = { @@ -182,6 +186,7 @@ static const struct adp5585_regs adp5589_regs = { .reset_cfg = ADP5589_RESET_CFG, .reset1_event_a = ADP5589_RESET1_EVENT_A, .reset2_event_a = ADP5589_RESET2_EVENT_A, + .pin_cfg_a = ADP5589_PIN_CONFIG_A, }; static int adp5585_validate_event(const struct adp5585_dev *adp5585, unsigned int ev) @@ -239,6 +244,8 @@ static struct regmap_config *adp5585_fill_variant_config(struct adp5585_dev *adp case ADP5585_04: adp5585->id = ADP5585_MAN_ID_VALUE; adp5585->regs = &adp5585_regs; + adp5585->n_pins = ADP5585_PIN_MAX; + adp5585->reset2_out = ADP5585_RESET2_OUT; if (adp5585->variant == ADP5585_01) adp5585->has_pin6 = true; regmap_config = devm_kmemdup(adp5585->dev, &adp5585_regmap_config_template, @@ -251,6 +258,8 @@ static struct regmap_config *adp5585_fill_variant_config(struct adp5585_dev *adp adp5585->regs = &adp5589_regs; adp5585->has_unlock = true; adp5585->has_pin6 = true; + adp5585->n_pins = ADP5589_PIN_MAX; + adp5585->reset2_out = ADP5589_RESET2_OUT; regmap_config = devm_kmemdup(adp5585->dev, &adp5589_regmap_config_template, sizeof(*regmap_config), GFP_KERNEL); break; @@ -439,6 +448,8 @@ static int adp5585_add_devices(const struct adp5585_dev *adp5585) cells = adp5589_devs; if (device_property_present(dev, "#pwm-cells")) { + /* Make sure the PWM output pin is not used by the GPIO or INPUT devices */ + __set_bit(ADP5585_PWM_OUT, adp5585->pin_usage); ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, &cells[ADP5585_DEV_PWM], 1, NULL, 0, NULL); if (ret) @@ -452,6 +463,13 @@ static int adp5585_add_devices(const struct adp5585_dev *adp5585) return dev_err_probe(dev, ret, "Failed to add GPIO device\n"); } + if (device_property_present(adp5585->dev, "adi,keypad-pins")) { + ret = devm_mfd_add_devices(adp5585->dev, PLATFORM_DEVID_AUTO, + &cells[ADP5585_DEV_INPUT], 1, NULL, 0, NULL); + if (ret) + return dev_err_probe(dev, ret, "Failed to add input device\n"); + } + return 0; } @@ -518,6 +536,10 @@ static int adp5585_setup(struct adp5585_dev *adp5585) unsigned int reg_val = 0, i; int ret; + /* If pin_6 (ROW5/GPI6) is not available, make sure to mark it as "busy" */ + if (!adp5585->has_pin6) + __set_bit(ADP5585_ROW5, adp5585->pin_usage); + /* Configure the device with reset and unlock events */ for (i = 0; i < adp5585->nkeys_unlock; i++) { ret = regmap_write(adp5585->regmap, ADP5589_UNLOCK1 + i, @@ -542,6 +564,9 @@ static int adp5585_setup(struct adp5585_dev *adp5585) adp5585->reset1_keys[i] | ADP5585_RESET_EV_PRESS); if (ret) return ret; + + /* Mark that pin as not usable for the INPUT and GPIO devices. */ + __set_bit(ADP5585_RESET1_OUT, adp5585->pin_usage); } for (i = 0; i < adp5585->nkeys_reset2; i++) { @@ -549,6 +574,8 @@ static int adp5585_setup(struct adp5585_dev *adp5585) adp5585->reset2_keys[i] | ADP5585_RESET_EV_PRESS); if (ret) return ret; + + __set_bit(adp5585->reset2_out, adp5585->pin_usage); } if (adp5585->nkeys_reset1 || adp5585->nkeys_reset2) { @@ -697,6 +724,10 @@ static int adp5585_i2c_probe(struct i2c_client *i2c) return dev_err_probe(&i2c->dev, -ENODEV, "Invalid device ID 0x%02x\n", id); + adp5585->pin_usage = devm_bitmap_zalloc(&i2c->dev, adp5585->n_pins, GFP_KERNEL); + if (!adp5585->pin_usage) + return -ENOMEM; + ret = adp5585_parse_fw(adp5585); if (ret) return ret; |
