]>
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> | |
5a0e3ad6 | 20 | #include <linux/slab.h> |
d0a82132 DR |
21 | |
22 | struct pcap_keys { | |
23 | struct pcap_chip *pcap; | |
24 | struct input_dev *input; | |
25 | }; | |
26 | ||
27 | /* PCAP2 interrupts us on keypress */ | |
28 | static irqreturn_t pcap_keys_handler(int irq, void *_pcap_keys) | |
29 | { | |
30 | struct pcap_keys *pcap_keys = _pcap_keys; | |
31 | int pirq = irq_to_pcap(pcap_keys->pcap, irq); | |
32 | u32 pstat; | |
33 | ||
34 | ezx_pcap_read(pcap_keys->pcap, PCAP_REG_PSTAT, &pstat); | |
35 | pstat &= 1 << pirq; | |
36 | ||
37 | switch (pirq) { | |
38 | case PCAP_IRQ_ONOFF: | |
39 | input_report_key(pcap_keys->input, KEY_POWER, !pstat); | |
40 | break; | |
41 | case PCAP_IRQ_MIC: | |
42 | input_report_key(pcap_keys->input, KEY_HP, !pstat); | |
43 | break; | |
44 | } | |
45 | ||
46 | input_sync(pcap_keys->input); | |
47 | ||
48 | return IRQ_HANDLED; | |
49 | } | |
50 | ||
51 | static int __devinit pcap_keys_probe(struct platform_device *pdev) | |
52 | { | |
53 | int err = -ENOMEM; | |
54 | struct pcap_keys *pcap_keys; | |
55 | struct input_dev *input_dev; | |
56 | ||
57 | pcap_keys = kmalloc(sizeof(struct pcap_keys), GFP_KERNEL); | |
58 | if (!pcap_keys) | |
59 | return err; | |
60 | ||
61 | pcap_keys->pcap = dev_get_drvdata(pdev->dev.parent); | |
62 | ||
63 | input_dev = input_allocate_device(); | |
64 | if (!input_dev) | |
65 | goto fail; | |
66 | ||
67 | pcap_keys->input = input_dev; | |
68 | ||
69 | platform_set_drvdata(pdev, pcap_keys); | |
70 | input_dev->name = pdev->name; | |
71 | input_dev->phys = "pcap-keys/input0"; | |
72 | input_dev->id.bustype = BUS_HOST; | |
73 | input_dev->dev.parent = &pdev->dev; | |
74 | ||
75 | __set_bit(EV_KEY, input_dev->evbit); | |
76 | __set_bit(KEY_POWER, input_dev->keybit); | |
77 | __set_bit(KEY_HP, input_dev->keybit); | |
78 | ||
79 | err = input_register_device(input_dev); | |
80 | if (err) | |
81 | goto fail_allocate; | |
82 | ||
83 | err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), | |
84 | pcap_keys_handler, 0, "Power key", pcap_keys); | |
85 | if (err) | |
86 | goto fail_register; | |
87 | ||
88 | err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC), | |
89 | pcap_keys_handler, 0, "Headphone button", pcap_keys); | |
90 | if (err) | |
91 | goto fail_pwrkey; | |
92 | ||
93 | return 0; | |
94 | ||
95 | fail_pwrkey: | |
96 | free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys); | |
97 | fail_register: | |
98 | input_unregister_device(input_dev); | |
99 | goto fail; | |
100 | fail_allocate: | |
101 | input_free_device(input_dev); | |
102 | fail: | |
103 | kfree(pcap_keys); | |
104 | return err; | |
105 | } | |
106 | ||
107 | static int __devexit pcap_keys_remove(struct platform_device *pdev) | |
108 | { | |
109 | struct pcap_keys *pcap_keys = platform_get_drvdata(pdev); | |
110 | ||
111 | free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys); | |
112 | free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC), pcap_keys); | |
113 | ||
114 | input_unregister_device(pcap_keys->input); | |
115 | kfree(pcap_keys); | |
116 | ||
117 | return 0; | |
118 | } | |
119 | ||
120 | static struct platform_driver pcap_keys_device_driver = { | |
121 | .probe = pcap_keys_probe, | |
1cb0aa88 | 122 | .remove = pcap_keys_remove, |
d0a82132 DR |
123 | .driver = { |
124 | .name = "pcap-keys", | |
125 | .owner = THIS_MODULE, | |
126 | } | |
127 | }; | |
840a746b | 128 | module_platform_driver(pcap_keys_device_driver); |
d0a82132 DR |
129 | |
130 | MODULE_DESCRIPTION("Motorola PCAP2 input events driver"); | |
131 | MODULE_AUTHOR("Ilya Petrov <ilya.muromec@gmail.com>"); | |
132 | MODULE_LICENSE("GPL"); | |
133 | MODULE_ALIAS("platform:pcap_keys"); |