diff options
-rw-r--r-- | drivers/input/keyboard/gpio_keys.c | 89 | ||||
-rw-r--r-- | include/linux/gpio_keys.h | 1 |
2 files changed, 70 insertions, 20 deletions
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index bbd00c3fe98c..be58730e636a 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c | |||
@@ -26,23 +26,54 @@ | |||
26 | 26 | ||
27 | #include <asm/gpio.h> | 27 | #include <asm/gpio.h> |
28 | 28 | ||
29 | struct gpio_button_data { | ||
30 | struct gpio_keys_button *button; | ||
31 | struct input_dev *input; | ||
32 | struct timer_list timer; | ||
33 | }; | ||
34 | |||
35 | struct gpio_keys_drvdata { | ||
36 | struct input_dev *input; | ||
37 | struct gpio_button_data data[0]; | ||
38 | }; | ||
39 | |||
40 | static void gpio_keys_report_event(struct gpio_keys_button *button, | ||
41 | struct input_dev *input) | ||
42 | { | ||
43 | unsigned int type = button->type ?: EV_KEY; | ||
44 | int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low; | ||
45 | |||
46 | input_event(input, type, button->code, !!state); | ||
47 | input_sync(input); | ||
48 | } | ||
49 | |||
50 | static void gpio_check_button(unsigned long _data) | ||
51 | { | ||
52 | struct gpio_button_data *data = (struct gpio_button_data *)_data; | ||
53 | |||
54 | gpio_keys_report_event(data->button, data->input); | ||
55 | } | ||
56 | |||
29 | static irqreturn_t gpio_keys_isr(int irq, void *dev_id) | 57 | static irqreturn_t gpio_keys_isr(int irq, void *dev_id) |
30 | { | 58 | { |
31 | int i; | ||
32 | struct platform_device *pdev = dev_id; | 59 | struct platform_device *pdev = dev_id; |
33 | struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; | 60 | struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; |
34 | struct input_dev *input = platform_get_drvdata(pdev); | 61 | struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); |
62 | int i; | ||
35 | 63 | ||
36 | for (i = 0; i < pdata->nbuttons; i++) { | 64 | for (i = 0; i < pdata->nbuttons; i++) { |
37 | struct gpio_keys_button *button = &pdata->buttons[i]; | 65 | struct gpio_keys_button *button = &pdata->buttons[i]; |
38 | int gpio = button->gpio; | ||
39 | 66 | ||
40 | if (irq == gpio_to_irq(gpio)) { | 67 | if (irq == gpio_to_irq(button->gpio)) { |
41 | unsigned int type = button->type ?: EV_KEY; | 68 | struct gpio_button_data *bdata = &ddata->data[i]; |
42 | int state = (gpio_get_value(gpio) ? 1 : 0) ^ button->active_low; | 69 | |
70 | if (button->debounce_interval) | ||
71 | mod_timer(&bdata->timer, | ||
72 | jiffies + | ||
73 | msecs_to_jiffies(button->debounce_interval)); | ||
74 | else | ||
75 | gpio_keys_report_event(button, bdata->input); | ||
43 | 76 | ||
44 | input_event(input, type, button->code, !!state); | ||
45 | input_sync(input); | ||
46 | return IRQ_HANDLED; | 77 | return IRQ_HANDLED; |
47 | } | 78 | } |
48 | } | 79 | } |
@@ -53,17 +84,21 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id) | |||
53 | static int __devinit gpio_keys_probe(struct platform_device *pdev) | 84 | static int __devinit gpio_keys_probe(struct platform_device *pdev) |
54 | { | 85 | { |
55 | struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; | 86 | struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; |
87 | struct gpio_keys_drvdata *ddata; | ||
56 | struct input_dev *input; | 88 | struct input_dev *input; |
57 | int i, error; | 89 | int i, error; |
58 | int wakeup = 0; | 90 | int wakeup = 0; |
59 | 91 | ||
92 | ddata = kzalloc(sizeof(struct gpio_keys_drvdata) + | ||
93 | pdata->nbuttons * sizeof(struct gpio_button_data), | ||
94 | GFP_KERNEL); | ||
60 | input = input_allocate_device(); | 95 | input = input_allocate_device(); |
61 | if (!input) | 96 | if (!ddata || !input) { |
62 | return -ENOMEM; | 97 | error = -ENOMEM; |
63 | 98 | goto fail1; | |
64 | platform_set_drvdata(pdev, input); | 99 | } |
65 | 100 | ||
66 | input->evbit[0] = BIT_MASK(EV_KEY); | 101 | platform_set_drvdata(pdev, ddata); |
67 | 102 | ||
68 | input->name = pdev->name; | 103 | input->name = pdev->name; |
69 | input->phys = "gpio-keys/input0"; | 104 | input->phys = "gpio-keys/input0"; |
@@ -74,16 +109,23 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) | |||
74 | input->id.product = 0x0001; | 109 | input->id.product = 0x0001; |
75 | input->id.version = 0x0100; | 110 | input->id.version = 0x0100; |
76 | 111 | ||
112 | ddata->input = input; | ||
113 | |||
77 | for (i = 0; i < pdata->nbuttons; i++) { | 114 | for (i = 0; i < pdata->nbuttons; i++) { |
78 | struct gpio_keys_button *button = &pdata->buttons[i]; | 115 | struct gpio_keys_button *button = &pdata->buttons[i]; |
116 | struct gpio_button_data *bdata = &ddata->data[i]; | ||
79 | int irq; | 117 | int irq; |
80 | unsigned int type = button->type ?: EV_KEY; | 118 | unsigned int type = button->type ?: EV_KEY; |
81 | 119 | ||
120 | bdata->input = input; | ||
121 | setup_timer(&bdata->timer, | ||
122 | gpio_check_button, (unsigned long)bdata); | ||
123 | |||
82 | error = gpio_request(button->gpio, button->desc ?: "gpio_keys"); | 124 | error = gpio_request(button->gpio, button->desc ?: "gpio_keys"); |
83 | if (error < 0) { | 125 | if (error < 0) { |
84 | pr_err("gpio-keys: failed to request GPIO %d," | 126 | pr_err("gpio-keys: failed to request GPIO %d," |
85 | " error %d\n", button->gpio, error); | 127 | " error %d\n", button->gpio, error); |
86 | goto fail; | 128 | goto fail2; |
87 | } | 129 | } |
88 | 130 | ||
89 | error = gpio_direction_input(button->gpio); | 131 | error = gpio_direction_input(button->gpio); |
@@ -92,7 +134,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) | |||
92 | " direction for GPIO %d, error %d\n", | 134 | " direction for GPIO %d, error %d\n", |
93 | button->gpio, error); | 135 | button->gpio, error); |
94 | gpio_free(button->gpio); | 136 | gpio_free(button->gpio); |
95 | goto fail; | 137 | goto fail2; |
96 | } | 138 | } |
97 | 139 | ||
98 | irq = gpio_to_irq(button->gpio); | 140 | irq = gpio_to_irq(button->gpio); |
@@ -102,7 +144,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) | |||
102 | " for GPIO %d, error %d\n", | 144 | " for GPIO %d, error %d\n", |
103 | button->gpio, error); | 145 | button->gpio, error); |
104 | gpio_free(button->gpio); | 146 | gpio_free(button->gpio); |
105 | goto fail; | 147 | goto fail2; |
106 | } | 148 | } |
107 | 149 | ||
108 | error = request_irq(irq, gpio_keys_isr, | 150 | error = request_irq(irq, gpio_keys_isr, |
@@ -114,7 +156,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) | |||
114 | pr_err("gpio-keys: Unable to claim irq %d; error %d\n", | 156 | pr_err("gpio-keys: Unable to claim irq %d; error %d\n", |
115 | irq, error); | 157 | irq, error); |
116 | gpio_free(button->gpio); | 158 | gpio_free(button->gpio); |
117 | goto fail; | 159 | goto fail2; |
118 | } | 160 | } |
119 | 161 | ||
120 | if (button->wakeup) | 162 | if (button->wakeup) |
@@ -127,21 +169,25 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) | |||
127 | if (error) { | 169 | if (error) { |
128 | pr_err("gpio-keys: Unable to register input device, " | 170 | pr_err("gpio-keys: Unable to register input device, " |
129 | "error: %d\n", error); | 171 | "error: %d\n", error); |
130 | goto fail; | 172 | goto fail2; |
131 | } | 173 | } |
132 | 174 | ||
133 | device_init_wakeup(&pdev->dev, wakeup); | 175 | device_init_wakeup(&pdev->dev, wakeup); |
134 | 176 | ||
135 | return 0; | 177 | return 0; |
136 | 178 | ||
137 | fail: | 179 | fail2: |
138 | while (--i >= 0) { | 180 | while (--i >= 0) { |
139 | free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev); | 181 | free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev); |
182 | if (pdata->buttons[i].debounce_interval) | ||
183 | del_timer_sync(&ddata->data[i].timer); | ||
140 | gpio_free(pdata->buttons[i].gpio); | 184 | gpio_free(pdata->buttons[i].gpio); |
141 | } | 185 | } |
142 | 186 | ||
143 | platform_set_drvdata(pdev, NULL); | 187 | platform_set_drvdata(pdev, NULL); |
188 | fail1: | ||
144 | input_free_device(input); | 189 | input_free_device(input); |
190 | kfree(ddata); | ||
145 | 191 | ||
146 | return error; | 192 | return error; |
147 | } | 193 | } |
@@ -149,7 +195,8 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) | |||
149 | static int __devexit gpio_keys_remove(struct platform_device *pdev) | 195 | static int __devexit gpio_keys_remove(struct platform_device *pdev) |
150 | { | 196 | { |
151 | struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; | 197 | struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; |
152 | struct input_dev *input = platform_get_drvdata(pdev); | 198 | struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); |
199 | struct input_dev *input = ddata->input; | ||
153 | int i; | 200 | int i; |
154 | 201 | ||
155 | device_init_wakeup(&pdev->dev, 0); | 202 | device_init_wakeup(&pdev->dev, 0); |
@@ -157,6 +204,8 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev) | |||
157 | for (i = 0; i < pdata->nbuttons; i++) { | 204 | for (i = 0; i < pdata->nbuttons; i++) { |
158 | int irq = gpio_to_irq(pdata->buttons[i].gpio); | 205 | int irq = gpio_to_irq(pdata->buttons[i].gpio); |
159 | free_irq(irq, pdev); | 206 | free_irq(irq, pdev); |
207 | if (pdata->buttons[i].debounce_interval) | ||
208 | del_timer_sync(&ddata->data[i].timer); | ||
160 | gpio_free(pdata->buttons[i].gpio); | 209 | gpio_free(pdata->buttons[i].gpio); |
161 | } | 210 | } |
162 | 211 | ||
diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h index c6d3a9de5634..ec6ecd74781d 100644 --- a/include/linux/gpio_keys.h +++ b/include/linux/gpio_keys.h | |||
@@ -9,6 +9,7 @@ struct gpio_keys_button { | |||
9 | char *desc; | 9 | char *desc; |
10 | int type; /* input event type (EV_KEY, EV_SW) */ | 10 | int type; /* input event type (EV_KEY, EV_SW) */ |
11 | int wakeup; /* configure the button as a wake-up source */ | 11 | int wakeup; /* configure the button as a wake-up source */ |
12 | int debounce_interval; /* debounce ticks interval in msecs */ | ||
12 | }; | 13 | }; |
13 | 14 | ||
14 | struct gpio_keys_platform_data { | 15 | struct gpio_keys_platform_data { |