GNU Linux-libre 5.19-rc6-gnu
[releases.git] / 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         u32 n_rows;
28         u32 n_cols;
29         DECLARE_BITMAP(keymap_state, MTK_KPD_NUM_BITS);
30 };
31
32 static const struct regmap_config mt6779_keypad_regmap_cfg = {
33         .reg_bits = 32,
34         .val_bits = 32,
35         .reg_stride = sizeof(u32),
36         .max_register = 36,
37 };
38
39 static irqreturn_t mt6779_keypad_irq_handler(int irq, void *dev_id)
40 {
41         struct mt6779_keypad *keypad = dev_id;
42         const unsigned short *keycode = keypad->input_dev->keycode;
43         DECLARE_BITMAP(new_state, MTK_KPD_NUM_BITS);
44         DECLARE_BITMAP(change, MTK_KPD_NUM_BITS);
45         unsigned int bit_nr;
46         unsigned int row, col;
47         unsigned int scancode;
48         unsigned int row_shift = get_count_order(keypad->n_cols);
49         bool pressed;
50
51         regmap_bulk_read(keypad->regmap, MTK_KPD_MEM,
52                          new_state, MTK_KPD_NUM_MEMS);
53
54         bitmap_xor(change, new_state, keypad->keymap_state, MTK_KPD_NUM_BITS);
55
56         for_each_set_bit(bit_nr, change, MTK_KPD_NUM_BITS) {
57                 /*
58                  * Registers are 32bits, but only bits [15:0] are used to
59                  * indicate key status.
60                  */
61                 if (bit_nr % 32 >= 16)
62                         continue;
63
64                 row = bit_nr / 32;
65                 col = bit_nr % 32;
66                 scancode = MATRIX_SCAN_CODE(row, col, row_shift);
67                 /* 1: not pressed, 0: pressed */
68                 pressed = !test_bit(bit_nr, new_state);
69                 dev_dbg(&keypad->input_dev->dev, "%s",
70                         pressed ? "pressed" : "released");
71
72                 input_event(keypad->input_dev, EV_MSC, MSC_SCAN, scancode);
73                 input_report_key(keypad->input_dev, keycode[scancode], pressed);
74                 input_sync(keypad->input_dev);
75
76                 dev_dbg(&keypad->input_dev->dev,
77                         "report Linux keycode = %d\n", keycode[scancode]);
78         }
79
80         bitmap_copy(keypad->keymap_state, new_state, MTK_KPD_NUM_BITS);
81
82         return IRQ_HANDLED;
83 }
84
85 static void mt6779_keypad_clk_disable(void *data)
86 {
87         clk_disable_unprepare(data);
88 }
89
90 static int mt6779_keypad_pdrv_probe(struct platform_device *pdev)
91 {
92         struct mt6779_keypad *keypad;
93         void __iomem *base;
94         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         base = devm_platform_ioremap_resource(pdev, 0);
104         if (IS_ERR(base))
105                 return PTR_ERR(base);
106
107         keypad->regmap = devm_regmap_init_mmio(&pdev->dev, 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");