^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Cirrus Logic CLPS711X Keypad driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/of_gpio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/input/matrix_keypad.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/mfd/syscon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/mfd/syscon/clps711x.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define CLPS711X_KEYPAD_COL_COUNT 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct clps711x_gpio_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct gpio_desc *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) DECLARE_BITMAP(last_state, CLPS711X_KEYPAD_COL_COUNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct clps711x_keypad_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct regmap *syscon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) int row_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) unsigned int row_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct clps711x_gpio_data *gpio_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static void clps711x_keypad_poll(struct input_dev *input)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) const unsigned short *keycodes = input->keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct clps711x_keypad_data *priv = input_get_drvdata(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) bool sync = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) int col, row;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) for (col = 0; col < CLPS711X_KEYPAD_COL_COUNT; col++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /* Assert column */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) regmap_update_bits(priv->syscon, SYSCON_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) SYSCON1_KBDSCAN_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) SYSCON1_KBDSCAN(8 + col));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /* Scan rows */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) for (row = 0; row < priv->row_count; row++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct clps711x_gpio_data *data = &priv->gpio_data[row];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) bool state, state1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /* Read twice for protection against fluctuations */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) state = gpiod_get_value_cansleep(data->desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) cond_resched();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) state1 = gpiod_get_value_cansleep(data->desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) } while (state != state1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (test_bit(col, data->last_state) != state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) int code = MATRIX_SCAN_CODE(row, col,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) priv->row_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) set_bit(col, data->last_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) input_event(input,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) EV_MSC, MSC_SCAN, code);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) clear_bit(col, data->last_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (keycodes[code])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) input_report_key(input,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) keycodes[code], state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) sync = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) /* Set all columns to low */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) regmap_update_bits(priv->syscon, SYSCON_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) SYSCON1_KBDSCAN_MASK, SYSCON1_KBDSCAN(1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (sync)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) input_sync(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static int clps711x_keypad_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct clps711x_keypad_data *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct device_node *np = dev->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct input_dev *input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) u32 poll_interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) int i, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) priv->syscon =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) syscon_regmap_lookup_by_compatible("cirrus,ep7209-syscon1");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (IS_ERR(priv->syscon))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return PTR_ERR(priv->syscon);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) priv->row_count = of_gpio_named_count(np, "row-gpios");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (priv->row_count < 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) priv->gpio_data = devm_kcalloc(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) priv->row_count, sizeof(*priv->gpio_data),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (!priv->gpio_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) priv->row_shift = get_count_order(CLPS711X_KEYPAD_COL_COUNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) for (i = 0; i < priv->row_count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) struct clps711x_gpio_data *data = &priv->gpio_data[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) data->desc = devm_gpiod_get_index(dev, "row", i, GPIOD_IN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (IS_ERR(data->desc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return PTR_ERR(data->desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) err = of_property_read_u32(np, "poll-interval", &poll_interval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) input = devm_input_allocate_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (!input)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) input_set_drvdata(input, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) input->name = pdev->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) input->dev.parent = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) input->id.bustype = BUS_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) input->id.vendor = 0x0001;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) input->id.product = 0x0001;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) input->id.version = 0x0100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) err = matrix_keypad_build_keymap(NULL, NULL, priv->row_count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) CLPS711X_KEYPAD_COL_COUNT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) NULL, input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) input_set_capability(input, EV_MSC, MSC_SCAN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (of_property_read_bool(np, "autorepeat"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) __set_bit(EV_REP, input->evbit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /* Set all columns to low */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) regmap_update_bits(priv->syscon, SYSCON_OFFSET, SYSCON1_KBDSCAN_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) SYSCON1_KBDSCAN(1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) err = input_setup_polling(input, clps711x_keypad_poll);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) input_set_poll_interval(input, poll_interval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) err = input_register_device(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) static const struct of_device_id clps711x_keypad_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) { .compatible = "cirrus,ep7209-keypad", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) MODULE_DEVICE_TABLE(of, clps711x_keypad_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static struct platform_driver clps711x_keypad_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .name = "clps711x-keypad",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) .of_match_table = clps711x_keypad_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) .probe = clps711x_keypad_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) module_platform_driver(clps711x_keypad_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) MODULE_DESCRIPTION("Cirrus Logic CLPS711X Keypad driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) MODULE_LICENSE("GPL");