// SPDX-License-Identifier: GPL-2.0-only /* * Analog Devices ADP5585 Keys driver * * Copyright (C) 2025 Analog Devices, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* As needed for the matrix parsing code */ #define ADP5589_MAX_KEYMAPSIZE 123 struct adp5585_kpad_chip { u8 key_ev_min; u8 key_ev_max; u8 max_rows; u8 max_cols; }; struct adp5585_kpad { const struct adp5585_kpad_chip *info; struct notifier_block nb; struct input_dev *input; unsigned short keycode[ADP5589_MAX_KEYMAPSIZE]; struct device *dev; unsigned long keypad; int row_shift; }; static int adp5585_keys_validate_events(const struct adp5585_kpad *kpad, const u32 *events, u32 n_events) { unsigned int ev; u32 row, col; for (ev = 0; ev < n_events; ev++) { if (events[ev] < kpad->info->key_ev_min || events[ev] > kpad->info->key_ev_max) continue; /* * if the event is to be generated by the keymap, we need to make * sure that the pins are part of it! */ row = (events[ev] - 1) / kpad->info->max_cols; col = (events[ev] - 1) % kpad->info->max_cols; if (test_bit(row, &kpad->keypad) && test_bit(col + kpad->info->max_rows, &kpad->keypad)) continue; return dev_err_probe(kpad->dev, -EINVAL, "Invalid unlock/reset event(%u) not used in the keypad\n", events[ev]); } return 0; } static int adp5585_keys_check_special_events(const struct adp5585_dev *adp5585, const struct adp5585_kpad *kpad) { int error; error = adp5585_keys_validate_events(kpad, adp5585->unlock_keys, adp5585->nkeys_unlock); if (error) return error; error = adp5585_keys_validate_events(kpad, adp5585->reset1_keys, adp5585->nkeys_reset1); if (error) return error; return adp5585_keys_validate_events(kpad, adp5585->reset2_keys, adp5585->nkeys_reset2); } static void adp5585_keys_pins_free(void *data) { struct adp5585_kpad *kpad = data; struct adp5585_dev *adp5585 = dev_get_drvdata(kpad->dev->parent); unsigned int pin; for_each_set_bit(pin, &kpad->keypad, adp5585->n_pins) clear_bit(pin, adp5585->pin_usage); } static int adp5585_keys_parse_fw(const struct adp5585_dev *adp5585, struct adp5585_kpad *kpad) { struct device *dev = kpad->dev; u32 cols = 0, rows = 0, pin; int error, n_pins; /* * We do not check for errors (or no value) since the input device is * only added if this property is present in the first place. */ n_pins = device_property_count_u32(dev, "adi,keypad-pins"); if (n_pins > adp5585->n_pins) return dev_err_probe(dev, -EINVAL, "Too many keypad pins (%d) defined (max=%d)\n", n_pins, adp5585->n_pins); unsigned int *keypad_pins __free(kfree) = kcalloc(n_pins, sizeof(*keypad_pins), GFP_KERNEL); if (!keypad_pins) return -ENOMEM; error = device_property_read_u32_array(dev, "adi,keypad-pins", keypad_pins, n_pins); if (error) return error; /* * We can add the action here since it makes the code easier and nothing * "bad" will happen out of it. Worst case, it will be a no-op and no * bit will set. */ error = devm_add_action_or_reset(dev, adp5585_keys_pins_free, kpad); if (error) return error; for (pin = 0; pin < n_pins; pin++) { if (keypad_pins[pin] >= adp5585->n_pins) return dev_err_probe(dev, -EINVAL, "Invalid keypad pin(%u) defined\n", keypad_pins[pin]); if (test_and_set_bit(keypad_pins[pin], adp5585->pin_usage)) return dev_err_probe(dev, -EBUSY, "Keypad pin(%u) already used\n", keypad_pins[pin]); __set_bit(keypad_pins[pin], &kpad->keypad); } /* * Note that given that we get a mask (and the HW allows it), we * can have holes in our keypad (eg: row0, row1 and row7 enabled). * However, for the matrix parsing functions we need to pass the * number of rows/cols as the maximum row/col used plus 1. This * pretty much means we will also have holes in our SW keypad. */ rows = find_last_bit(&kpad->keypad, kpad->info->max_rows) + 1; if (rows == kpad->info->max_rows + 1) return dev_err_probe(dev, -EINVAL, "Now rows defined in the keypad!\n"); cols = find_last_bit(&kpad->keypad, kpad->info->max_cols + kpad->info->max_rows); if (cols < kpad->info->max_rows) return dev_err_probe(dev, -EINVAL, "No columns defined in the keypad!\n"); cols = cols + 1 - kpad->info->max_rows; error = matrix_keypad_build_keymap(NULL, NULL, rows, cols, kpad->keycode, kpad->input); if (error) return error; kpad->row_shift = get_count_order(cols); if (device_property_read_bool(kpad->dev, "autorepeat")) __set_bit(EV_REP, kpad->input->evbit); error = adp5585_keys_check_special_events(adp5585, kpad); if (error) return error; return 0; } static int adp5585_keys_setup(const struct adp5585_dev *adp5585, struct adp5585_kpad *kpad) { unsigned long keys_bits, start = 0, nbits = kpad->info->max_rows; const struct adp5585_regs *regs = adp5585->regs; unsigned int i = 0, max_cols = kpad->info->max_cols; int error; /* * Take care as the below assumes max_rows is always less or equal than * 8 which is true for the supported devices. If we happen to add * another device we need to make sure this still holds true. Although * adding a new device is very unlikely. */ do { keys_bits = bitmap_read(&kpad->keypad, start, nbits); if (keys_bits) { error = regmap_write(adp5585->regmap, regs->pin_cfg_a + i, keys_bits); if (error) return error; } start += nbits; if (max_cols > 8) { nbits = 8; max_cols -= nbits; } else { nbits = max_cols; } i++; } while (start < kpad->info->max_rows + kpad->info->max_cols); return 0; } static int adp5585_keys_ev_handle(struct notifier_block *nb, unsigned long key, void *data) { struct adp5585_kpad *kpad = container_of(nb, struct adp5585_kpad, nb); unsigned long key_press = (unsigned long)data; unsigned int row, col, code; /* make sure the event is for us */ if (key < kpad->info->key_ev_min || key > kpad->info->key_ev_max) return NOTIFY_DONE; /* * Unlikely but lets be on the safe side! We do not return any error * because the event was indeed for us but with some weird value. So, * we still want the caller know that the right handler was called. */ if (!key) return NOTIFY_BAD; row = (key - 1) / (kpad->info->max_cols); col = (key - 1) % (kpad->info->max_cols); code = MATRIX_SCAN_CODE(row, col, kpad->row_shift); dev_dbg_ratelimited(kpad->dev, "report key(%lu) r(%d) c(%d) code(%d)\n", key, row, col, kpad->keycode[code]); input_report_key(kpad->input, kpad->keycode[code], key_press); input_sync(kpad->input); return NOTIFY_STOP; } static void adp5585_keys_unreg_notifier(void *data) { struct adp5585_kpad *kpad = data; struct adp5585_dev *adp5585 = dev_get_drvdata(kpad->dev->parent); blocking_notifier_chain_unregister(&adp5585->event_notifier, &kpad->nb); } static int adp5585_keys_probe(struct platform_device *pdev) { const struct platform_device_id *id = platform_get_device_id(pdev); struct adp5585_dev *adp5585 = dev_get_drvdata(pdev->dev.parent); struct device *dev = &pdev->dev; struct adp5585_kpad *kpad; unsigned int revid; const char *phys; int error; kpad = devm_kzalloc(dev, sizeof(*kpad), GFP_KERNEL); if (!kpad) return -ENOMEM; if (!adp5585->irq) return dev_err_probe(dev, -EINVAL, "IRQ is mandatory for the keypad\n"); kpad->dev = dev; kpad->input = devm_input_allocate_device(dev); if (!kpad->input) return -ENOMEM; kpad->info = (const struct adp5585_kpad_chip *)id->driver_data; if (!kpad->info) return -ENODEV; error = regmap_read(adp5585->regmap, ADP5585_ID, &revid); if (error) return dev_err_probe(dev, error, "Failed to read device ID\n"); phys = devm_kasprintf(dev, GFP_KERNEL, "%s/input0", pdev->name); if (!phys) return -ENOMEM; kpad->input->name = pdev->name; kpad->input->phys = phys; kpad->input->id.bustype = BUS_I2C; kpad->input->id.vendor = 0x0001; kpad->input->id.product = 0x0001; kpad->input->id.version = revid & ADP5585_REV_ID_MASK; device_set_of_node_from_dev(dev, dev->parent); error = adp5585_keys_parse_fw(adp5585, kpad); if (error) return error; error = adp5585_keys_setup(adp5585, kpad); if (error) return error; kpad->nb.notifier_call = adp5585_keys_ev_handle; error = blocking_notifier_chain_register(&adp5585->event_notifier, &kpad->nb); if (error) return error; error = devm_add_action_or_reset(dev, adp5585_keys_unreg_notifier, kpad); if (error) return error; error = input_register_device(kpad->input); if (error) return dev_err_probe(dev, error, "Failed to register input device\n"); return 0; } static const struct adp5585_kpad_chip adp5585_kpad_chip_info = { .max_rows = 6, .max_cols = 5, .key_ev_min = ADP5585_ROW5_KEY_EVENT_START, .key_ev_max = ADP5585_ROW5_KEY_EVENT_END, }; static const struct adp5585_kpad_chip adp5589_kpad_chip_info = { .max_rows = 8, .max_cols = 11, .key_ev_min = ADP5589_KEY_EVENT_START, .key_ev_max = ADP5589_KEY_EVENT_END, }; static const struct platform_device_id adp5585_keys_id_table[] = { { "adp5585-keys", (kernel_ulong_t)&adp5585_kpad_chip_info }, { "adp5589-keys", (kernel_ulong_t)&adp5589_kpad_chip_info }, { } }; MODULE_DEVICE_TABLE(platform, adp5585_keys_id_table); static struct platform_driver adp5585_keys_driver = { .driver = { .name = "adp5585-keys", }, .probe = adp5585_keys_probe, .id_table = adp5585_keys_id_table, }; module_platform_driver(adp5585_keys_driver); MODULE_AUTHOR("Nuno Sá "); MODULE_DESCRIPTION("ADP5585 Keys Driver"); MODULE_LICENSE("GPL");