1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2017 MediaTek, Inc. |
4 | * |
5 | * Author: Chen Zhong <chen.zhong@mediatek.com> |
6 | */ |
7 | |
8 | #include <linux/input.h> |
9 | #include <linux/interrupt.h> |
10 | #include <linux/kernel.h> |
11 | #include <linux/mfd/mt6323/registers.h> |
12 | #include <linux/mfd/mt6331/registers.h> |
13 | #include <linux/mfd/mt6357/registers.h> |
14 | #include <linux/mfd/mt6358/registers.h> |
15 | #include <linux/mfd/mt6397/core.h> |
16 | #include <linux/mfd/mt6397/registers.h> |
17 | #include <linux/module.h> |
18 | #include <linux/of_device.h> |
19 | #include <linux/of.h> |
20 | #include <linux/platform_device.h> |
21 | #include <linux/regmap.h> |
22 | |
23 | #define MTK_PMIC_RST_DU_MASK GENMASK(9, 8) |
24 | #define MTK_PMIC_PWRKEY_RST BIT(6) |
25 | #define MTK_PMIC_HOMEKEY_RST BIT(5) |
26 | |
27 | #define MTK_PMIC_MT6331_RST_DU_MASK GENMASK(13, 12) |
28 | #define MTK_PMIC_MT6331_PWRKEY_RST BIT(9) |
29 | #define MTK_PMIC_MT6331_HOMEKEY_RST BIT(8) |
30 | |
31 | #define MTK_PMIC_PWRKEY_INDEX 0 |
32 | #define MTK_PMIC_HOMEKEY_INDEX 1 |
33 | #define MTK_PMIC_MAX_KEY_COUNT 2 |
34 | |
35 | struct mtk_pmic_keys_regs { |
36 | u32 deb_reg; |
37 | u32 deb_mask; |
38 | u32 intsel_reg; |
39 | u32 intsel_mask; |
40 | u32 rst_en_mask; |
41 | }; |
42 | |
43 | #define MTK_PMIC_KEYS_REGS(_deb_reg, _deb_mask, \ |
44 | _intsel_reg, _intsel_mask, _rst_mask) \ |
45 | { \ |
46 | .deb_reg = _deb_reg, \ |
47 | .deb_mask = _deb_mask, \ |
48 | .intsel_reg = _intsel_reg, \ |
49 | .intsel_mask = _intsel_mask, \ |
50 | .rst_en_mask = _rst_mask, \ |
51 | } |
52 | |
53 | struct mtk_pmic_regs { |
54 | const struct mtk_pmic_keys_regs keys_regs[MTK_PMIC_MAX_KEY_COUNT]; |
55 | u32 pmic_rst_reg; |
56 | u32 rst_lprst_mask; /* Long-press reset timeout bitmask */ |
57 | }; |
58 | |
59 | static const struct mtk_pmic_regs mt6397_regs = { |
60 | .keys_regs[MTK_PMIC_PWRKEY_INDEX] = |
61 | MTK_PMIC_KEYS_REGS(MT6397_CHRSTATUS, |
62 | 0x8, MT6397_INT_RSV, 0x10, MTK_PMIC_PWRKEY_RST), |
63 | .keys_regs[MTK_PMIC_HOMEKEY_INDEX] = |
64 | MTK_PMIC_KEYS_REGS(MT6397_OCSTATUS2, |
65 | 0x10, MT6397_INT_RSV, 0x8, MTK_PMIC_HOMEKEY_RST), |
66 | .pmic_rst_reg = MT6397_TOP_RST_MISC, |
67 | .rst_lprst_mask = MTK_PMIC_RST_DU_MASK, |
68 | }; |
69 | |
70 | static const struct mtk_pmic_regs mt6323_regs = { |
71 | .keys_regs[MTK_PMIC_PWRKEY_INDEX] = |
72 | MTK_PMIC_KEYS_REGS(MT6323_CHRSTATUS, |
73 | 0x2, MT6323_INT_MISC_CON, 0x10, MTK_PMIC_PWRKEY_RST), |
74 | .keys_regs[MTK_PMIC_HOMEKEY_INDEX] = |
75 | MTK_PMIC_KEYS_REGS(MT6323_CHRSTATUS, |
76 | 0x4, MT6323_INT_MISC_CON, 0x8, MTK_PMIC_HOMEKEY_RST), |
77 | .pmic_rst_reg = MT6323_TOP_RST_MISC, |
78 | .rst_lprst_mask = MTK_PMIC_RST_DU_MASK, |
79 | }; |
80 | |
81 | static const struct mtk_pmic_regs mt6331_regs = { |
82 | .keys_regs[MTK_PMIC_PWRKEY_INDEX] = |
83 | MTK_PMIC_KEYS_REGS(MT6331_TOPSTATUS, 0x2, |
84 | MT6331_INT_MISC_CON, 0x4, |
85 | MTK_PMIC_MT6331_PWRKEY_RST), |
86 | .keys_regs[MTK_PMIC_HOMEKEY_INDEX] = |
87 | MTK_PMIC_KEYS_REGS(MT6331_TOPSTATUS, 0x4, |
88 | MT6331_INT_MISC_CON, 0x2, |
89 | MTK_PMIC_MT6331_HOMEKEY_RST), |
90 | .pmic_rst_reg = MT6331_TOP_RST_MISC, |
91 | .rst_lprst_mask = MTK_PMIC_MT6331_RST_DU_MASK, |
92 | }; |
93 | |
94 | static const struct mtk_pmic_regs mt6357_regs = { |
95 | .keys_regs[MTK_PMIC_PWRKEY_INDEX] = |
96 | MTK_PMIC_KEYS_REGS(MT6357_TOPSTATUS, |
97 | 0x2, MT6357_PSC_TOP_INT_CON0, 0x5, |
98 | MTK_PMIC_PWRKEY_RST), |
99 | .keys_regs[MTK_PMIC_HOMEKEY_INDEX] = |
100 | MTK_PMIC_KEYS_REGS(MT6357_TOPSTATUS, |
101 | 0x8, MT6357_PSC_TOP_INT_CON0, 0xa, |
102 | MTK_PMIC_HOMEKEY_INDEX), |
103 | .pmic_rst_reg = MT6357_TOP_RST_MISC, |
104 | .rst_lprst_mask = MTK_PMIC_RST_DU_MASK, |
105 | }; |
106 | |
107 | static const struct mtk_pmic_regs mt6358_regs = { |
108 | .keys_regs[MTK_PMIC_PWRKEY_INDEX] = |
109 | MTK_PMIC_KEYS_REGS(MT6358_TOPSTATUS, |
110 | 0x2, MT6358_PSC_TOP_INT_CON0, 0x5, |
111 | MTK_PMIC_PWRKEY_RST), |
112 | .keys_regs[MTK_PMIC_HOMEKEY_INDEX] = |
113 | MTK_PMIC_KEYS_REGS(MT6358_TOPSTATUS, |
114 | 0x8, MT6358_PSC_TOP_INT_CON0, 0xa, |
115 | MTK_PMIC_HOMEKEY_RST), |
116 | .pmic_rst_reg = MT6358_TOP_RST_MISC, |
117 | .rst_lprst_mask = MTK_PMIC_RST_DU_MASK, |
118 | }; |
119 | |
120 | struct mtk_pmic_keys_info { |
121 | struct mtk_pmic_keys *keys; |
122 | const struct mtk_pmic_keys_regs *regs; |
123 | unsigned int keycode; |
124 | int irq; |
125 | int irq_r; /* optional: release irq if different */ |
126 | bool wakeup:1; |
127 | }; |
128 | |
129 | struct mtk_pmic_keys { |
130 | struct input_dev *input_dev; |
131 | struct device *dev; |
132 | struct regmap *regmap; |
133 | struct mtk_pmic_keys_info keys[MTK_PMIC_MAX_KEY_COUNT]; |
134 | }; |
135 | |
136 | enum mtk_pmic_keys_lp_mode { |
137 | LP_DISABLE, |
138 | LP_ONEKEY, |
139 | LP_TWOKEY, |
140 | }; |
141 | |
142 | static void mtk_pmic_keys_lp_reset_setup(struct mtk_pmic_keys *keys, |
143 | const struct mtk_pmic_regs *regs) |
144 | { |
145 | const struct mtk_pmic_keys_regs *kregs_home, *kregs_pwr; |
146 | u32 long_press_mode, long_press_debounce; |
147 | u32 value, mask; |
148 | int error; |
149 | |
150 | kregs_home = keys->keys[MTK_PMIC_HOMEKEY_INDEX].regs; |
151 | kregs_pwr = keys->keys[MTK_PMIC_PWRKEY_INDEX].regs; |
152 | |
153 | error = of_property_read_u32(np: keys->dev->of_node, propname: "power-off-time-sec" , |
154 | out_value: &long_press_debounce); |
155 | if (error) |
156 | long_press_debounce = 0; |
157 | |
158 | mask = regs->rst_lprst_mask; |
159 | value = long_press_debounce << (ffs(regs->rst_lprst_mask) - 1); |
160 | |
161 | error = of_property_read_u32(np: keys->dev->of_node, |
162 | propname: "mediatek,long-press-mode" , |
163 | out_value: &long_press_mode); |
164 | if (error) |
165 | long_press_mode = LP_DISABLE; |
166 | |
167 | switch (long_press_mode) { |
168 | case LP_TWOKEY: |
169 | value |= kregs_home->rst_en_mask; |
170 | fallthrough; |
171 | |
172 | case LP_ONEKEY: |
173 | value |= kregs_pwr->rst_en_mask; |
174 | fallthrough; |
175 | |
176 | case LP_DISABLE: |
177 | mask |= kregs_home->rst_en_mask; |
178 | mask |= kregs_pwr->rst_en_mask; |
179 | break; |
180 | |
181 | default: |
182 | break; |
183 | } |
184 | |
185 | regmap_update_bits(map: keys->regmap, reg: regs->pmic_rst_reg, mask, val: value); |
186 | } |
187 | |
188 | static irqreturn_t mtk_pmic_keys_irq_handler_thread(int irq, void *data) |
189 | { |
190 | struct mtk_pmic_keys_info *info = data; |
191 | u32 key_deb, pressed; |
192 | |
193 | regmap_read(map: info->keys->regmap, reg: info->regs->deb_reg, val: &key_deb); |
194 | |
195 | key_deb &= info->regs->deb_mask; |
196 | |
197 | pressed = !key_deb; |
198 | |
199 | input_report_key(dev: info->keys->input_dev, code: info->keycode, value: pressed); |
200 | input_sync(dev: info->keys->input_dev); |
201 | |
202 | dev_dbg(info->keys->dev, "(%s) key =%d using PMIC\n" , |
203 | pressed ? "pressed" : "released" , info->keycode); |
204 | |
205 | return IRQ_HANDLED; |
206 | } |
207 | |
208 | static int mtk_pmic_key_setup(struct mtk_pmic_keys *keys, |
209 | struct mtk_pmic_keys_info *info) |
210 | { |
211 | int ret; |
212 | |
213 | info->keys = keys; |
214 | |
215 | ret = regmap_update_bits(map: keys->regmap, reg: info->regs->intsel_reg, |
216 | mask: info->regs->intsel_mask, |
217 | val: info->regs->intsel_mask); |
218 | if (ret < 0) |
219 | return ret; |
220 | |
221 | ret = devm_request_threaded_irq(dev: keys->dev, irq: info->irq, NULL, |
222 | thread_fn: mtk_pmic_keys_irq_handler_thread, |
223 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, |
224 | devname: "mtk-pmic-keys" , dev_id: info); |
225 | if (ret) { |
226 | dev_err(keys->dev, "Failed to request IRQ: %d: %d\n" , |
227 | info->irq, ret); |
228 | return ret; |
229 | } |
230 | |
231 | if (info->irq_r > 0) { |
232 | ret = devm_request_threaded_irq(dev: keys->dev, irq: info->irq_r, NULL, |
233 | thread_fn: mtk_pmic_keys_irq_handler_thread, |
234 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, |
235 | devname: "mtk-pmic-keys" , dev_id: info); |
236 | if (ret) { |
237 | dev_err(keys->dev, "Failed to request IRQ_r: %d: %d\n" , |
238 | info->irq, ret); |
239 | return ret; |
240 | } |
241 | } |
242 | |
243 | input_set_capability(dev: keys->input_dev, EV_KEY, code: info->keycode); |
244 | |
245 | return 0; |
246 | } |
247 | |
248 | static int mtk_pmic_keys_suspend(struct device *dev) |
249 | { |
250 | struct mtk_pmic_keys *keys = dev_get_drvdata(dev); |
251 | int index; |
252 | |
253 | for (index = 0; index < MTK_PMIC_MAX_KEY_COUNT; index++) { |
254 | if (keys->keys[index].wakeup) { |
255 | enable_irq_wake(irq: keys->keys[index].irq); |
256 | if (keys->keys[index].irq_r > 0) |
257 | enable_irq_wake(irq: keys->keys[index].irq_r); |
258 | } |
259 | } |
260 | |
261 | return 0; |
262 | } |
263 | |
264 | static int mtk_pmic_keys_resume(struct device *dev) |
265 | { |
266 | struct mtk_pmic_keys *keys = dev_get_drvdata(dev); |
267 | int index; |
268 | |
269 | for (index = 0; index < MTK_PMIC_MAX_KEY_COUNT; index++) { |
270 | if (keys->keys[index].wakeup) { |
271 | disable_irq_wake(irq: keys->keys[index].irq); |
272 | if (keys->keys[index].irq_r > 0) |
273 | disable_irq_wake(irq: keys->keys[index].irq_r); |
274 | } |
275 | } |
276 | |
277 | return 0; |
278 | } |
279 | |
280 | static DEFINE_SIMPLE_DEV_PM_OPS(mtk_pmic_keys_pm_ops, mtk_pmic_keys_suspend, |
281 | mtk_pmic_keys_resume); |
282 | |
283 | static const struct of_device_id of_mtk_pmic_keys_match_tbl[] = { |
284 | { |
285 | .compatible = "mediatek,mt6397-keys" , |
286 | .data = &mt6397_regs, |
287 | }, { |
288 | .compatible = "mediatek,mt6323-keys" , |
289 | .data = &mt6323_regs, |
290 | }, { |
291 | .compatible = "mediatek,mt6331-keys" , |
292 | .data = &mt6331_regs, |
293 | }, { |
294 | .compatible = "mediatek,mt6357-keys" , |
295 | .data = &mt6357_regs, |
296 | }, { |
297 | .compatible = "mediatek,mt6358-keys" , |
298 | .data = &mt6358_regs, |
299 | }, { |
300 | /* sentinel */ |
301 | } |
302 | }; |
303 | MODULE_DEVICE_TABLE(of, of_mtk_pmic_keys_match_tbl); |
304 | |
305 | static int mtk_pmic_keys_probe(struct platform_device *pdev) |
306 | { |
307 | int error, index = 0; |
308 | unsigned int keycount; |
309 | struct mt6397_chip *pmic_chip = dev_get_drvdata(dev: pdev->dev.parent); |
310 | struct device_node *node = pdev->dev.of_node, *child; |
311 | static const char *const irqnames[] = { "powerkey" , "homekey" }; |
312 | static const char *const irqnames_r[] = { "powerkey_r" , "homekey_r" }; |
313 | struct mtk_pmic_keys *keys; |
314 | const struct mtk_pmic_regs *mtk_pmic_regs; |
315 | struct input_dev *input_dev; |
316 | const struct of_device_id *of_id = |
317 | of_match_device(matches: of_mtk_pmic_keys_match_tbl, dev: &pdev->dev); |
318 | |
319 | keys = devm_kzalloc(dev: &pdev->dev, size: sizeof(*keys), GFP_KERNEL); |
320 | if (!keys) |
321 | return -ENOMEM; |
322 | |
323 | keys->dev = &pdev->dev; |
324 | keys->regmap = pmic_chip->regmap; |
325 | mtk_pmic_regs = of_id->data; |
326 | |
327 | keys->input_dev = input_dev = devm_input_allocate_device(keys->dev); |
328 | if (!input_dev) { |
329 | dev_err(keys->dev, "input allocate device fail.\n" ); |
330 | return -ENOMEM; |
331 | } |
332 | |
333 | input_dev->name = "mtk-pmic-keys" ; |
334 | input_dev->id.bustype = BUS_HOST; |
335 | input_dev->id.vendor = 0x0001; |
336 | input_dev->id.product = 0x0001; |
337 | input_dev->id.version = 0x0001; |
338 | |
339 | keycount = of_get_available_child_count(np: node); |
340 | if (keycount > MTK_PMIC_MAX_KEY_COUNT || |
341 | keycount > ARRAY_SIZE(irqnames)) { |
342 | dev_err(keys->dev, "too many keys defined (%d)\n" , keycount); |
343 | return -EINVAL; |
344 | } |
345 | |
346 | for_each_child_of_node(node, child) { |
347 | keys->keys[index].regs = &mtk_pmic_regs->keys_regs[index]; |
348 | |
349 | keys->keys[index].irq = |
350 | platform_get_irq_byname(pdev, irqnames[index]); |
351 | if (keys->keys[index].irq < 0) { |
352 | of_node_put(node: child); |
353 | return keys->keys[index].irq; |
354 | } |
355 | |
356 | if (of_device_is_compatible(device: node, "mediatek,mt6358-keys" )) { |
357 | keys->keys[index].irq_r = platform_get_irq_byname(pdev, |
358 | irqnames_r[index]); |
359 | |
360 | if (keys->keys[index].irq_r < 0) { |
361 | of_node_put(node: child); |
362 | return keys->keys[index].irq_r; |
363 | } |
364 | } |
365 | |
366 | error = of_property_read_u32(np: child, |
367 | propname: "linux,keycodes" , out_value: &keys->keys[index].keycode); |
368 | if (error) { |
369 | dev_err(keys->dev, |
370 | "failed to read key:%d linux,keycode property: %d\n" , |
371 | index, error); |
372 | of_node_put(node: child); |
373 | return error; |
374 | } |
375 | |
376 | if (of_property_read_bool(np: child, propname: "wakeup-source" )) |
377 | keys->keys[index].wakeup = true; |
378 | |
379 | error = mtk_pmic_key_setup(keys, info: &keys->keys[index]); |
380 | if (error) { |
381 | of_node_put(node: child); |
382 | return error; |
383 | } |
384 | |
385 | index++; |
386 | } |
387 | |
388 | error = input_register_device(input_dev); |
389 | if (error) { |
390 | dev_err(&pdev->dev, |
391 | "register input device failed (%d)\n" , error); |
392 | return error; |
393 | } |
394 | |
395 | mtk_pmic_keys_lp_reset_setup(keys, regs: mtk_pmic_regs); |
396 | |
397 | platform_set_drvdata(pdev, data: keys); |
398 | |
399 | return 0; |
400 | } |
401 | |
402 | static struct platform_driver pmic_keys_pdrv = { |
403 | .probe = mtk_pmic_keys_probe, |
404 | .driver = { |
405 | .name = "mtk-pmic-keys" , |
406 | .of_match_table = of_mtk_pmic_keys_match_tbl, |
407 | .pm = pm_sleep_ptr(&mtk_pmic_keys_pm_ops), |
408 | }, |
409 | }; |
410 | |
411 | module_platform_driver(pmic_keys_pdrv); |
412 | |
413 | MODULE_LICENSE("GPL v2" ); |
414 | MODULE_AUTHOR("Chen Zhong <chen.zhong@mediatek.com>" ); |
415 | MODULE_DESCRIPTION("MTK pmic-keys driver v0.1" ); |
416 | |