Commit | Line | Data |
---|---|---|
d0a82132 DR |
1 | /* |
2 | * Input driver for PCAP events: | |
3 | * * Power key | |
4 | * * Headphone button | |
5 | * | |
6 | * Copyright (c) 2008,2009 Ilya Petrov <ilya.muromec@gmail.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | * | |
12 | */ | |
13 | ||
14 | #include <linux/module.h> | |
15 | #include <linux/init.h> | |
16 | #include <linux/interrupt.h> | |
17 | #include <linux/platform_device.h> | |
18 | #include <linux/input.h> | |
19 | #include <linux/mfd/ezx-pcap.h> | |
20 | ||
21 | struct pcap_keys { | |
22 | struct pcap_chip *pcap; | |
23 | struct input_dev *input; | |
24 | }; | |
25 | ||
26 | /* PCAP2 interrupts us on keypress */ | |
27 | static irqreturn_t pcap_keys_handler(int irq, void *_pcap_keys) | |
28 | { | |
29 | struct pcap_keys *pcap_keys = _pcap_keys; | |
30 | int pirq = irq_to_pcap(pcap_keys->pcap, irq); | |
31 | u32 pstat; | |
32 | ||
33 | ezx_pcap_read(pcap_keys->pcap, PCAP_REG_PSTAT, &pstat); | |
34 | pstat &= 1 << pirq; | |
35 | ||
36 | switch (pirq) { | |
37 | case PCAP_IRQ_ONOFF: | |
38 | input_report_key(pcap_keys->input, KEY_POWER, !pstat); | |
39 | break; | |
40 | case PCAP_IRQ_MIC: | |
41 | input_report_key(pcap_keys->input, KEY_HP, !pstat); | |
42 | break; | |
43 | } | |
44 | ||
45 | input_sync(pcap_keys->input); | |
46 | ||
47 | return IRQ_HANDLED; | |
48 | } | |
49 | ||
50 | static int __devinit pcap_keys_probe(struct platform_device *pdev) | |
51 | { | |
52 | int err = -ENOMEM; | |
53 | struct pcap_keys *pcap_keys; | |
54 | struct input_dev *input_dev; | |
55 | ||
56 | pcap_keys = kmalloc(sizeof(struct pcap_keys), GFP_KERNEL); | |
57 | if (!pcap_keys) | |
58 | return err; | |
59 | ||
60 | pcap_keys->pcap = dev_get_drvdata(pdev->dev.parent); | |
61 | ||
62 | input_dev = input_allocate_device(); | |
63 | if (!input_dev) | |
64 | goto fail; | |
65 | ||
66 | pcap_keys->input = input_dev; | |
67 | ||
68 | platform_set_drvdata(pdev, pcap_keys); | |
69 | input_dev->name = pdev->name; | |
70 | input_dev->phys = "pcap-keys/input0"; | |
71 | input_dev->id.bustype = BUS_HOST; | |
72 | input_dev->dev.parent = &pdev->dev; | |
73 | ||
74 | __set_bit(EV_KEY, input_dev->evbit); | |
75 | __set_bit(KEY_POWER, input_dev->keybit); | |
76 | __set_bit(KEY_HP, input_dev->keybit); | |
77 | ||
78 | err = input_register_device(input_dev); | |
79 | if (err) | |
80 | goto fail_allocate; | |
81 | ||
82 | err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), | |
83 | pcap_keys_handler, 0, "Power key", pcap_keys); | |
84 | if (err) | |
85 | goto fail_register; | |
86 | ||
87 | err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC), | |
88 | pcap_keys_handler, 0, "Headphone button", pcap_keys); | |
89 | if (err) | |
90 | goto fail_pwrkey; | |
91 | ||
92 | return 0; | |
93 | ||
94 | fail_pwrkey: | |
95 | free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys); | |
96 | fail_register: | |
97 | input_unregister_device(input_dev); | |
98 | goto fail; | |
99 | fail_allocate: | |
100 | input_free_device(input_dev); | |
101 | fail: | |
102 | kfree(pcap_keys); | |
103 | return err; | |
104 | } | |
105 | ||
106 | static int __devexit pcap_keys_remove(struct platform_device *pdev) | |
107 | { | |
108 | struct pcap_keys *pcap_keys = platform_get_drvdata(pdev); | |
109 | ||
110 | free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys); | |
111 | free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC), pcap_keys); | |
112 | ||
113 | input_unregister_device(pcap_keys->input); | |
114 | kfree(pcap_keys); | |
115 | ||
116 | return 0; | |
117 | } | |
118 | ||
119 | static struct platform_driver pcap_keys_device_driver = { | |
120 | .probe = pcap_keys_probe, | |
121 | .remove = __devexit_p(pcap_keys_remove), | |
122 | .driver = { | |
123 | .name = "pcap-keys", | |
124 | .owner = THIS_MODULE, | |
125 | } | |
126 | }; | |
127 | ||
128 | static int __init pcap_keys_init(void) | |
129 | { | |
130 | return platform_driver_register(&pcap_keys_device_driver); | |
131 | }; | |
132 | ||
133 | static void __exit pcap_keys_exit(void) | |
134 | { | |
135 | platform_driver_unregister(&pcap_keys_device_driver); | |
136 | }; | |
137 | ||
138 | module_init(pcap_keys_init); | |
139 | module_exit(pcap_keys_exit); | |
140 | ||
141 | MODULE_DESCRIPTION("Motorola PCAP2 input events driver"); | |
142 | MODULE_AUTHOR("Ilya Petrov <ilya.muromec@gmail.com>"); | |
143 | MODULE_LICENSE("GPL"); | |
144 | MODULE_ALIAS("platform:pcap_keys"); |