1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* NXP PCF50633 Input Driver |
3 | * |
4 | * (C) 2006-2008 by Openmoko, Inc. |
5 | * Author: Balaji Rao <balajirrao@openmoko.org> |
6 | * All rights reserved. |
7 | * |
8 | * Broken down from monstrous PCF50633 driver mainly by |
9 | * Harald Welte, Andy Green and Werner Almesberger |
10 | */ |
11 | |
12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> |
14 | #include <linux/device.h> |
15 | #include <linux/platform_device.h> |
16 | #include <linux/input.h> |
17 | #include <linux/slab.h> |
18 | |
19 | #include <linux/mfd/pcf50633/core.h> |
20 | |
21 | #define PCF50633_OOCSTAT_ONKEY 0x01 |
22 | #define PCF50633_REG_OOCSTAT 0x12 |
23 | #define PCF50633_REG_OOCMODE 0x10 |
24 | |
25 | struct pcf50633_input { |
26 | struct pcf50633 *pcf; |
27 | struct input_dev *input_dev; |
28 | }; |
29 | |
30 | static void |
31 | pcf50633_input_irq(int irq, void *data) |
32 | { |
33 | struct pcf50633_input *input; |
34 | int onkey_released; |
35 | |
36 | input = data; |
37 | |
38 | /* We report only one event depending on the key press status */ |
39 | onkey_released = pcf50633_reg_read(input->pcf, PCF50633_REG_OOCSTAT) |
40 | & PCF50633_OOCSTAT_ONKEY; |
41 | |
42 | if (irq == PCF50633_IRQ_ONKEYF && !onkey_released) |
43 | input_report_key(dev: input->input_dev, KEY_POWER, value: 1); |
44 | else if (irq == PCF50633_IRQ_ONKEYR && onkey_released) |
45 | input_report_key(dev: input->input_dev, KEY_POWER, value: 0); |
46 | |
47 | input_sync(dev: input->input_dev); |
48 | } |
49 | |
50 | static int pcf50633_input_probe(struct platform_device *pdev) |
51 | { |
52 | struct pcf50633_input *input; |
53 | struct input_dev *input_dev; |
54 | int ret; |
55 | |
56 | |
57 | input = kzalloc(size: sizeof(*input), GFP_KERNEL); |
58 | if (!input) |
59 | return -ENOMEM; |
60 | |
61 | input_dev = input_allocate_device(); |
62 | if (!input_dev) { |
63 | kfree(objp: input); |
64 | return -ENOMEM; |
65 | } |
66 | |
67 | platform_set_drvdata(pdev, data: input); |
68 | input->pcf = dev_to_pcf50633(dev: pdev->dev.parent); |
69 | input->input_dev = input_dev; |
70 | |
71 | input_dev->name = "PCF50633 PMU events" ; |
72 | input_dev->id.bustype = BUS_I2C; |
73 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_PWR); |
74 | set_bit(KEY_POWER, addr: input_dev->keybit); |
75 | |
76 | ret = input_register_device(input_dev); |
77 | if (ret) { |
78 | input_free_device(dev: input_dev); |
79 | kfree(objp: input); |
80 | return ret; |
81 | } |
82 | pcf50633_register_irq(pcf: input->pcf, irq: PCF50633_IRQ_ONKEYR, |
83 | handler: pcf50633_input_irq, data: input); |
84 | pcf50633_register_irq(pcf: input->pcf, irq: PCF50633_IRQ_ONKEYF, |
85 | handler: pcf50633_input_irq, data: input); |
86 | |
87 | return 0; |
88 | } |
89 | |
90 | static int pcf50633_input_remove(struct platform_device *pdev) |
91 | { |
92 | struct pcf50633_input *input = platform_get_drvdata(pdev); |
93 | |
94 | pcf50633_free_irq(pcf: input->pcf, irq: PCF50633_IRQ_ONKEYR); |
95 | pcf50633_free_irq(pcf: input->pcf, irq: PCF50633_IRQ_ONKEYF); |
96 | |
97 | input_unregister_device(input->input_dev); |
98 | kfree(objp: input); |
99 | |
100 | return 0; |
101 | } |
102 | |
103 | static struct platform_driver pcf50633_input_driver = { |
104 | .driver = { |
105 | .name = "pcf50633-input" , |
106 | }, |
107 | .probe = pcf50633_input_probe, |
108 | .remove = pcf50633_input_remove, |
109 | }; |
110 | module_platform_driver(pcf50633_input_driver); |
111 | |
112 | MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>" ); |
113 | MODULE_DESCRIPTION("PCF50633 input driver" ); |
114 | MODULE_LICENSE("GPL" ); |
115 | MODULE_ALIAS("platform:pcf50633-input" ); |
116 | |