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.h> |
9 | #include <linux/input/matrix_keypad.h> |
10 | #include <linux/interrupt.h> |
11 | #include <linux/module.h> |
12 | #include <linux/property.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/regmap.h> |
15 | |
16 | #define MTK_KPD_NAME "mt6779-keypad" |
17 | #define MTK_KPD_MEM 0x0004 |
18 | #define MTK_KPD_DEBOUNCE 0x0018 |
19 | #define MTK_KPD_DEBOUNCE_MASK GENMASK(13, 0) |
20 | #define MTK_KPD_DEBOUNCE_MAX_MS 256 |
21 | #define MTK_KPD_SEL 0x0020 |
22 | #define MTK_KPD_SEL_DOUBLE_KP_MODE BIT(0) |
23 | #define MTK_KPD_SEL_COL GENMASK(15, 10) |
24 | #define MTK_KPD_SEL_ROW GENMASK(9, 4) |
25 | #define MTK_KPD_SEL_COLMASK(c) GENMASK((c) + 9, 10) |
26 | #define MTK_KPD_SEL_ROWMASK(r) GENMASK((r) + 3, 4) |
27 | #define MTK_KPD_NUM_MEMS 5 |
28 | #define MTK_KPD_NUM_BITS 136 /* 4*32+8 MEM5 only use 8 BITS */ |
29 | |
30 | struct mt6779_keypad { |
31 | struct regmap *regmap; |
32 | struct input_dev *input_dev; |
33 | struct clk *clk; |
34 | u32 n_rows; |
35 | u32 n_cols; |
36 | void (*calc_row_col)(unsigned int key, |
37 | unsigned int *row, unsigned int *col); |
38 | DECLARE_BITMAP(keymap_state, MTK_KPD_NUM_BITS); |
39 | }; |
40 | |
41 | static const struct regmap_config mt6779_keypad_regmap_cfg = { |
42 | .reg_bits = 32, |
43 | .val_bits = 32, |
44 | .reg_stride = sizeof(u32), |
45 | .max_register = 36, |
46 | }; |
47 | |
48 | static irqreturn_t mt6779_keypad_irq_handler(int irq, void *dev_id) |
49 | { |
50 | struct mt6779_keypad *keypad = dev_id; |
51 | const unsigned short *keycode = keypad->input_dev->keycode; |
52 | DECLARE_BITMAP(new_state, MTK_KPD_NUM_BITS); |
53 | DECLARE_BITMAP(change, MTK_KPD_NUM_BITS); |
54 | unsigned int bit_nr, key; |
55 | unsigned int row, col; |
56 | unsigned int scancode; |
57 | unsigned int row_shift = get_count_order(count: keypad->n_cols); |
58 | bool pressed; |
59 | |
60 | regmap_bulk_read(map: keypad->regmap, MTK_KPD_MEM, |
61 | val: new_state, MTK_KPD_NUM_MEMS); |
62 | |
63 | bitmap_xor(dst: change, src1: new_state, src2: keypad->keymap_state, MTK_KPD_NUM_BITS); |
64 | |
65 | for_each_set_bit(bit_nr, change, MTK_KPD_NUM_BITS) { |
66 | /* |
67 | * Registers are 32bits, but only bits [15:0] are used to |
68 | * indicate key status. |
69 | */ |
70 | if (bit_nr % 32 >= 16) |
71 | continue; |
72 | |
73 | key = bit_nr / 32 * 16 + bit_nr % 32; |
74 | keypad->calc_row_col(key, &row, &col); |
75 | |
76 | scancode = MATRIX_SCAN_CODE(row, col, row_shift); |
77 | /* 1: not pressed, 0: pressed */ |
78 | pressed = !test_bit(bit_nr, new_state); |
79 | dev_dbg(&keypad->input_dev->dev, "%s" , |
80 | pressed ? "pressed" : "released" ); |
81 | |
82 | input_event(dev: keypad->input_dev, EV_MSC, MSC_SCAN, value: scancode); |
83 | input_report_key(dev: keypad->input_dev, code: keycode[scancode], value: pressed); |
84 | input_sync(dev: keypad->input_dev); |
85 | |
86 | dev_dbg(&keypad->input_dev->dev, |
87 | "report Linux keycode = %d\n" , keycode[scancode]); |
88 | } |
89 | |
90 | bitmap_copy(dst: keypad->keymap_state, src: new_state, MTK_KPD_NUM_BITS); |
91 | |
92 | return IRQ_HANDLED; |
93 | } |
94 | |
95 | static void mt6779_keypad_clk_disable(void *data) |
96 | { |
97 | clk_disable_unprepare(clk: data); |
98 | } |
99 | |
100 | static void mt6779_keypad_calc_row_col_single(unsigned int key, |
101 | unsigned int *row, |
102 | unsigned int *col) |
103 | { |
104 | *row = key / 9; |
105 | *col = key % 9; |
106 | } |
107 | |
108 | static void mt6779_keypad_calc_row_col_double(unsigned int key, |
109 | unsigned int *row, |
110 | unsigned int *col) |
111 | { |
112 | *row = key / 13; |
113 | *col = (key % 13) / 2; |
114 | } |
115 | |
116 | static int mt6779_keypad_pdrv_probe(struct platform_device *pdev) |
117 | { |
118 | struct mt6779_keypad *keypad; |
119 | void __iomem *base; |
120 | int irq; |
121 | u32 debounce; |
122 | u32 keys_per_group; |
123 | bool wakeup; |
124 | int error; |
125 | |
126 | keypad = devm_kzalloc(dev: &pdev->dev, size: sizeof(*keypad), GFP_KERNEL); |
127 | if (!keypad) |
128 | return -ENOMEM; |
129 | |
130 | base = devm_platform_ioremap_resource(pdev, index: 0); |
131 | if (IS_ERR(ptr: base)) |
132 | return PTR_ERR(ptr: base); |
133 | |
134 | keypad->regmap = devm_regmap_init_mmio(&pdev->dev, base, |
135 | &mt6779_keypad_regmap_cfg); |
136 | if (IS_ERR(ptr: keypad->regmap)) { |
137 | dev_err(&pdev->dev, |
138 | "regmap init failed:%pe\n" , keypad->regmap); |
139 | return PTR_ERR(ptr: keypad->regmap); |
140 | } |
141 | |
142 | bitmap_fill(dst: keypad->keymap_state, MTK_KPD_NUM_BITS); |
143 | |
144 | keypad->input_dev = devm_input_allocate_device(&pdev->dev); |
145 | if (!keypad->input_dev) { |
146 | dev_err(&pdev->dev, "Failed to allocate input dev\n" ); |
147 | return -ENOMEM; |
148 | } |
149 | |
150 | keypad->input_dev->name = MTK_KPD_NAME; |
151 | keypad->input_dev->id.bustype = BUS_HOST; |
152 | |
153 | error = matrix_keypad_parse_properties(dev: &pdev->dev, rows: &keypad->n_rows, |
154 | cols: &keypad->n_cols); |
155 | if (error) { |
156 | dev_err(&pdev->dev, "Failed to parse keypad params\n" ); |
157 | return error; |
158 | } |
159 | |
160 | if (device_property_read_u32(dev: &pdev->dev, propname: "debounce-delay-ms" , |
161 | val: &debounce)) |
162 | debounce = 16; |
163 | |
164 | if (debounce > MTK_KPD_DEBOUNCE_MAX_MS) { |
165 | dev_err(&pdev->dev, |
166 | "Debounce time exceeds the maximum allowed time %dms\n" , |
167 | MTK_KPD_DEBOUNCE_MAX_MS); |
168 | return -EINVAL; |
169 | } |
170 | |
171 | if (device_property_read_u32(dev: &pdev->dev, propname: "mediatek,keys-per-group" , |
172 | val: &keys_per_group)) |
173 | keys_per_group = 1; |
174 | |
175 | switch (keys_per_group) { |
176 | case 1: |
177 | keypad->calc_row_col = mt6779_keypad_calc_row_col_single; |
178 | break; |
179 | case 2: |
180 | keypad->calc_row_col = mt6779_keypad_calc_row_col_double; |
181 | break; |
182 | default: |
183 | dev_err(&pdev->dev, |
184 | "Invalid keys-per-group: %d\n" , keys_per_group); |
185 | return -EINVAL; |
186 | } |
187 | |
188 | wakeup = device_property_read_bool(dev: &pdev->dev, propname: "wakeup-source" ); |
189 | |
190 | dev_dbg(&pdev->dev, "n_row=%d n_col=%d debounce=%d\n" , |
191 | keypad->n_rows, keypad->n_cols, debounce); |
192 | |
193 | error = matrix_keypad_build_keymap(NULL, NULL, |
194 | rows: keypad->n_rows, cols: keypad->n_cols, |
195 | NULL, input_dev: keypad->input_dev); |
196 | if (error) { |
197 | dev_err(&pdev->dev, "Failed to build keymap\n" ); |
198 | return error; |
199 | } |
200 | |
201 | input_set_capability(dev: keypad->input_dev, EV_MSC, MSC_SCAN); |
202 | |
203 | regmap_write(map: keypad->regmap, MTK_KPD_DEBOUNCE, |
204 | val: (debounce * (1 << 5)) & MTK_KPD_DEBOUNCE_MASK); |
205 | |
206 | if (keys_per_group == 2) |
207 | regmap_update_bits(map: keypad->regmap, MTK_KPD_SEL, |
208 | MTK_KPD_SEL_DOUBLE_KP_MODE, |
209 | MTK_KPD_SEL_DOUBLE_KP_MODE); |
210 | |
211 | regmap_update_bits(map: keypad->regmap, MTK_KPD_SEL, MTK_KPD_SEL_ROW, |
212 | MTK_KPD_SEL_ROWMASK(keypad->n_rows)); |
213 | regmap_update_bits(map: keypad->regmap, MTK_KPD_SEL, MTK_KPD_SEL_COL, |
214 | MTK_KPD_SEL_COLMASK(keypad->n_cols)); |
215 | |
216 | keypad->clk = devm_clk_get(dev: &pdev->dev, id: "kpd" ); |
217 | if (IS_ERR(ptr: keypad->clk)) |
218 | return PTR_ERR(ptr: keypad->clk); |
219 | |
220 | error = clk_prepare_enable(clk: keypad->clk); |
221 | if (error) { |
222 | dev_err(&pdev->dev, "cannot prepare/enable keypad clock\n" ); |
223 | return error; |
224 | } |
225 | |
226 | error = devm_add_action_or_reset(&pdev->dev, mt6779_keypad_clk_disable, |
227 | keypad->clk); |
228 | if (error) |
229 | return error; |
230 | |
231 | irq = platform_get_irq(pdev, 0); |
232 | if (irq < 0) |
233 | return irq; |
234 | |
235 | error = devm_request_threaded_irq(dev: &pdev->dev, irq, |
236 | NULL, thread_fn: mt6779_keypad_irq_handler, |
237 | IRQF_ONESHOT, MTK_KPD_NAME, dev_id: keypad); |
238 | if (error) { |
239 | dev_err(&pdev->dev, "Failed to request IRQ#%d: %d\n" , |
240 | irq, error); |
241 | return error; |
242 | } |
243 | |
244 | error = input_register_device(keypad->input_dev); |
245 | if (error) { |
246 | dev_err(&pdev->dev, "Failed to register device\n" ); |
247 | return error; |
248 | } |
249 | |
250 | error = device_init_wakeup(dev: &pdev->dev, enable: wakeup); |
251 | if (error) |
252 | dev_warn(&pdev->dev, "device_init_wakeup() failed: %d\n" , |
253 | error); |
254 | |
255 | return 0; |
256 | } |
257 | |
258 | static const struct of_device_id mt6779_keypad_of_match[] = { |
259 | { .compatible = "mediatek,mt6779-keypad" }, |
260 | { .compatible = "mediatek,mt6873-keypad" }, |
261 | { /* sentinel */ } |
262 | }; |
263 | |
264 | static struct platform_driver mt6779_keypad_pdrv = { |
265 | .probe = mt6779_keypad_pdrv_probe, |
266 | .driver = { |
267 | .name = MTK_KPD_NAME, |
268 | .of_match_table = mt6779_keypad_of_match, |
269 | }, |
270 | }; |
271 | module_platform_driver(mt6779_keypad_pdrv); |
272 | |
273 | MODULE_AUTHOR("Mediatek Corporation" ); |
274 | MODULE_DESCRIPTION("MTK Keypad (KPD) Driver" ); |
275 | MODULE_LICENSE("GPL" ); |
276 | |