Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Input: mt6779-keypad - add MediaTek keypad driver

This patch adds matrix keypad support for Mediatek SoCs.

Signed-off-by: fengping.yu <fengping.yu@mediatek.com>
Reviewed-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Mattijs Korpershoek <mkorpershoek@baylibre.com>
Signed-off-by: Mattijs Korpershoek <mkorpershoek@baylibre.com>
Link: https://lore.kernel.org/r/20220303154302.252041-3-mkorpershoek@baylibre.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

fengping.yu and committed by
Dmitry Torokhov
f28af984 60b2a803

+234
+12
drivers/input/keyboard/Kconfig
··· 779 779 To compile this driver as a module, choose M here: the 780 780 module will be called bcm-keypad. 781 781 782 + config KEYBOARD_MT6779 783 + tristate "MediaTek Keypad Support" 784 + depends on ARCH_MEDIATEK || COMPILE_TEST 785 + select REGMAP_MMIO 786 + select INPUT_MATRIXKMAP 787 + help 788 + Say Y here if you want to use the keypad on MediaTek SoCs. 789 + If unsure, say N. 790 + 791 + To compile this driver as a module, choose M here: the 792 + module will be called mt6779-keypad. 793 + 782 794 config KEYBOARD_MTK_PMIC 783 795 tristate "MediaTek PMIC keys support" 784 796 depends on MFD_MT6397
+1
drivers/input/keyboard/Makefile
··· 44 44 obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o 45 45 obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o 46 46 obj-$(CONFIG_KEYBOARD_MPR121) += mpr121_touchkey.o 47 + obj-$(CONFIG_KEYBOARD_MT6779) += mt6779-keypad.o 47 48 obj-$(CONFIG_KEYBOARD_MTK_PMIC) += mtk-pmic-keys.o 48 49 obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o 49 50 obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o
+221
drivers/input/keyboard/mt6779-keypad.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2022 MediaTek Inc. 4 + * Author Fengping Yu <fengping.yu@mediatek.com> 5 + */ 6 + #include <linux/bitops.h> 7 + #include <linux/clk.h> 8 + #include <linux/input/matrix_keypad.h> 9 + #include <linux/interrupt.h> 10 + #include <linux/module.h> 11 + #include <linux/property.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/regmap.h> 14 + 15 + #define MTK_KPD_NAME "mt6779-keypad" 16 + #define MTK_KPD_MEM 0x0004 17 + #define MTK_KPD_DEBOUNCE 0x0018 18 + #define MTK_KPD_DEBOUNCE_MASK GENMASK(13, 0) 19 + #define MTK_KPD_DEBOUNCE_MAX_MS 256 20 + #define MTK_KPD_NUM_MEMS 5 21 + #define MTK_KPD_NUM_BITS 136 /* 4*32+8 MEM5 only use 8 BITS */ 22 + 23 + struct mt6779_keypad { 24 + struct regmap *regmap; 25 + struct input_dev *input_dev; 26 + struct clk *clk; 27 + void __iomem *base; 28 + u32 n_rows; 29 + u32 n_cols; 30 + DECLARE_BITMAP(keymap_state, MTK_KPD_NUM_BITS); 31 + }; 32 + 33 + static const struct regmap_config mt6779_keypad_regmap_cfg = { 34 + .reg_bits = 32, 35 + .val_bits = 32, 36 + .reg_stride = sizeof(u32), 37 + .max_register = 36, 38 + }; 39 + 40 + static irqreturn_t mt6779_keypad_irq_handler(int irq, void *dev_id) 41 + { 42 + struct mt6779_keypad *keypad = dev_id; 43 + const unsigned short *keycode = keypad->input_dev->keycode; 44 + DECLARE_BITMAP(new_state, MTK_KPD_NUM_BITS); 45 + DECLARE_BITMAP(change, MTK_KPD_NUM_BITS); 46 + unsigned int bit_nr; 47 + unsigned int row, col; 48 + unsigned int scancode; 49 + unsigned int row_shift = get_count_order(keypad->n_cols); 50 + bool pressed; 51 + 52 + regmap_bulk_read(keypad->regmap, MTK_KPD_MEM, 53 + new_state, MTK_KPD_NUM_MEMS); 54 + 55 + bitmap_xor(change, new_state, keypad->keymap_state, MTK_KPD_NUM_BITS); 56 + 57 + for_each_set_bit(bit_nr, change, MTK_KPD_NUM_BITS) { 58 + /* 59 + * Registers are 32bits, but only bits [15:0] are used to 60 + * indicate key status. 61 + */ 62 + if (bit_nr % 32 >= 16) 63 + continue; 64 + 65 + row = bit_nr / 32; 66 + col = bit_nr % 32; 67 + scancode = MATRIX_SCAN_CODE(row, col, row_shift); 68 + /* 1: not pressed, 0: pressed */ 69 + pressed = !test_bit(bit_nr, new_state); 70 + dev_dbg(&keypad->input_dev->dev, "%s", 71 + pressed ? "pressed" : "released"); 72 + 73 + input_event(keypad->input_dev, EV_MSC, MSC_SCAN, scancode); 74 + input_report_key(keypad->input_dev, keycode[scancode], pressed); 75 + input_sync(keypad->input_dev); 76 + 77 + dev_dbg(&keypad->input_dev->dev, 78 + "report Linux keycode = %d\n", keycode[scancode]); 79 + } 80 + 81 + bitmap_copy(keypad->keymap_state, new_state, MTK_KPD_NUM_BITS); 82 + 83 + return IRQ_HANDLED; 84 + } 85 + 86 + static void mt6779_keypad_clk_disable(void *data) 87 + { 88 + clk_disable_unprepare(data); 89 + } 90 + 91 + static int mt6779_keypad_pdrv_probe(struct platform_device *pdev) 92 + { 93 + struct mt6779_keypad *keypad; 94 + unsigned int irq; 95 + u32 debounce; 96 + bool wakeup; 97 + int error; 98 + 99 + keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL); 100 + if (!keypad) 101 + return -ENOMEM; 102 + 103 + keypad->base = devm_platform_ioremap_resource(pdev, 0); 104 + if (IS_ERR(keypad->base)) 105 + return PTR_ERR(keypad->base); 106 + 107 + keypad->regmap = devm_regmap_init_mmio(&pdev->dev, keypad->base, 108 + &mt6779_keypad_regmap_cfg); 109 + if (IS_ERR(keypad->regmap)) { 110 + dev_err(&pdev->dev, 111 + "regmap init failed:%pe\n", keypad->regmap); 112 + return PTR_ERR(keypad->regmap); 113 + } 114 + 115 + bitmap_fill(keypad->keymap_state, MTK_KPD_NUM_BITS); 116 + 117 + keypad->input_dev = devm_input_allocate_device(&pdev->dev); 118 + if (!keypad->input_dev) { 119 + dev_err(&pdev->dev, "Failed to allocate input dev\n"); 120 + return -ENOMEM; 121 + } 122 + 123 + keypad->input_dev->name = MTK_KPD_NAME; 124 + keypad->input_dev->id.bustype = BUS_HOST; 125 + 126 + error = matrix_keypad_parse_properties(&pdev->dev, &keypad->n_rows, 127 + &keypad->n_cols); 128 + if (error) { 129 + dev_err(&pdev->dev, "Failed to parse keypad params\n"); 130 + return error; 131 + } 132 + 133 + if (device_property_read_u32(&pdev->dev, "debounce-delay-ms", 134 + &debounce)) 135 + debounce = 16; 136 + 137 + if (debounce > MTK_KPD_DEBOUNCE_MAX_MS) { 138 + dev_err(&pdev->dev, 139 + "Debounce time exceeds the maximum allowed time %dms\n", 140 + MTK_KPD_DEBOUNCE_MAX_MS); 141 + return -EINVAL; 142 + } 143 + 144 + wakeup = device_property_read_bool(&pdev->dev, "wakeup-source"); 145 + 146 + dev_dbg(&pdev->dev, "n_row=%d n_col=%d debounce=%d\n", 147 + keypad->n_rows, keypad->n_cols, debounce); 148 + 149 + error = matrix_keypad_build_keymap(NULL, NULL, 150 + keypad->n_rows, keypad->n_cols, 151 + NULL, keypad->input_dev); 152 + if (error) { 153 + dev_err(&pdev->dev, "Failed to build keymap\n"); 154 + return error; 155 + } 156 + 157 + input_set_capability(keypad->input_dev, EV_MSC, MSC_SCAN); 158 + 159 + regmap_write(keypad->regmap, MTK_KPD_DEBOUNCE, 160 + (debounce * (1 << 5)) & MTK_KPD_DEBOUNCE_MASK); 161 + 162 + keypad->clk = devm_clk_get(&pdev->dev, "kpd"); 163 + if (IS_ERR(keypad->clk)) 164 + return PTR_ERR(keypad->clk); 165 + 166 + error = clk_prepare_enable(keypad->clk); 167 + if (error) { 168 + dev_err(&pdev->dev, "cannot prepare/enable keypad clock\n"); 169 + return error; 170 + } 171 + 172 + error = devm_add_action_or_reset(&pdev->dev, mt6779_keypad_clk_disable, 173 + keypad->clk); 174 + if (error) 175 + return error; 176 + 177 + irq = platform_get_irq(pdev, 0); 178 + if (irq < 0) 179 + return irq; 180 + 181 + error = devm_request_threaded_irq(&pdev->dev, irq, 182 + NULL, mt6779_keypad_irq_handler, 183 + IRQF_ONESHOT, MTK_KPD_NAME, keypad); 184 + if (error) { 185 + dev_err(&pdev->dev, "Failed to request IRQ#%d: %d\n", 186 + irq, error); 187 + return error; 188 + } 189 + 190 + error = input_register_device(keypad->input_dev); 191 + if (error) { 192 + dev_err(&pdev->dev, "Failed to register device\n"); 193 + return error; 194 + } 195 + 196 + error = device_init_wakeup(&pdev->dev, wakeup); 197 + if (error) 198 + dev_warn(&pdev->dev, "device_init_wakeup() failed: %d\n", 199 + error); 200 + 201 + return 0; 202 + } 203 + 204 + static const struct of_device_id mt6779_keypad_of_match[] = { 205 + { .compatible = "mediatek,mt6779-keypad" }, 206 + { .compatible = "mediatek,mt6873-keypad" }, 207 + { /* sentinel */ } 208 + }; 209 + 210 + static struct platform_driver mt6779_keypad_pdrv = { 211 + .probe = mt6779_keypad_pdrv_probe, 212 + .driver = { 213 + .name = MTK_KPD_NAME, 214 + .of_match_table = mt6779_keypad_of_match, 215 + }, 216 + }; 217 + module_platform_driver(mt6779_keypad_pdrv); 218 + 219 + MODULE_AUTHOR("Mediatek Corporation"); 220 + MODULE_DESCRIPTION("MTK Keypad (KPD) Driver"); 221 + MODULE_LICENSE("GPL");