blob: 9b8079ca0fb4422c197e5de0762cd86d518047c6 [file] [log] [blame]
Phil Blundell78a56aa2007-01-18 00:44:09 -05001/*
2 * Driver for keys on GPIO lines capable of generating interrupts.
3 *
4 * Copyright 2005 Phil Blundell
David Janderfd05d082011-07-09 12:41:46 -07005 * Copyright 2010, 2011 David Jander <david@protonic.nl>
Phil Blundell78a56aa2007-01-18 00:44:09 -05006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/module.h>
Phil Blundell78a56aa2007-01-18 00:44:09 -050013
14#include <linux/init.h>
15#include <linux/fs.h>
16#include <linux/interrupt.h>
17#include <linux/irq.h>
18#include <linux/sched.h>
19#include <linux/pm.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090020#include <linux/slab.h>
Phil Blundell78a56aa2007-01-18 00:44:09 -050021#include <linux/sysctl.h>
22#include <linux/proc_fs.h>
23#include <linux/delay.h>
24#include <linux/platform_device.h>
25#include <linux/input.h>
David Brownell49015be2007-03-05 00:30:22 -080026#include <linux/gpio_keys.h>
Jani Nikulada0d03f2009-06-28 22:38:56 -070027#include <linux/workqueue.h>
Ben Dooks111bc592009-11-10 21:01:31 -080028#include <linux/gpio.h>
Geert Uytterhoevendb7c1702017-04-04 19:32:22 +000029#include <linux/gpio/consumer.h>
Sachin Kamat415a4ca2013-10-06 00:55:14 -070030#include <linux/of.h>
David Janderfd05d082011-07-09 12:41:46 -070031#include <linux/of_platform.h>
32#include <linux/of_gpio.h>
Alexander Steinf2d347f2014-11-25 11:53:45 -080033#include <linux/of_irq.h>
Laxman Dewangand8ee4a12012-03-19 17:54:31 -070034#include <linux/spinlock.h>
Phil Blundell78a56aa2007-01-18 00:44:09 -050035
Dmitry Baryshkova33466e2008-05-07 16:30:15 -040036struct gpio_button_data {
Dmitry Torokhovd9080922012-03-18 23:36:29 -070037 const struct gpio_keys_button *button;
Dmitry Baryshkova33466e2008-05-07 16:30:15 -040038 struct input_dev *input;
Geert Uytterhoevendb7c1702017-04-04 19:32:22 +000039 struct gpio_desc *gpiod;
Dmitry Torokhov8ed92552014-11-14 17:32:01 -080040
41 struct timer_list release_timer;
42 unsigned int release_delay; /* in msecs, for IRQ-only buttons */
43
44 struct delayed_work work;
45 unsigned int software_debounce; /* in msecs, for GPIO-driven buttons */
46
Laxman Dewangand8ee4a12012-03-19 17:54:31 -070047 unsigned int irq;
48 spinlock_t lock;
Mika Westerberg9e3af042010-02-04 00:48:00 -080049 bool disabled;
Laxman Dewangand8ee4a12012-03-19 17:54:31 -070050 bool key_pressed;
Dmitry Baryshkova33466e2008-05-07 16:30:15 -040051};
52
53struct gpio_keys_drvdata {
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -070054 const struct gpio_keys_platform_data *pdata;
Dmitry Baryshkova33466e2008-05-07 16:30:15 -040055 struct input_dev *input;
Mika Westerberg9e3af042010-02-04 00:48:00 -080056 struct mutex disable_lock;
Dmitry Baryshkova33466e2008-05-07 16:30:15 -040057 struct gpio_button_data data[0];
58};
59
Mika Westerberg9e3af042010-02-04 00:48:00 -080060/*
61 * SYSFS interface for enabling/disabling keys and switches:
62 *
63 * There are 4 attributes under /sys/devices/platform/gpio-keys/
64 * keys [ro] - bitmap of keys (EV_KEY) which can be
65 * disabled
66 * switches [ro] - bitmap of switches (EV_SW) which can be
67 * disabled
68 * disabled_keys [rw] - bitmap of keys currently disabled
69 * disabled_switches [rw] - bitmap of switches currently disabled
70 *
71 * Userland can change these values and hence disable event generation
72 * for each key (or switch). Disabling a key means its interrupt line
73 * is disabled.
74 *
75 * For example, if we have following switches set up as gpio-keys:
76 * SW_DOCK = 5
77 * SW_CAMERA_LENS_COVER = 9
78 * SW_KEYPAD_SLIDE = 10
79 * SW_FRONT_PROXIMITY = 11
80 * This is read from switches:
81 * 11-9,5
82 * Next we want to disable proximity (11) and dock (5), we write:
83 * 11,5
84 * to file disabled_switches. Now proximity and dock IRQs are disabled.
85 * This can be verified by reading the file disabled_switches:
86 * 11,5
87 * If we now want to enable proximity (11) switch we write:
88 * 5
89 * to disabled_switches.
90 *
91 * We can disable only those keys which don't allow sharing the irq.
92 */
93
94/**
95 * get_n_events_by_type() - returns maximum number of events per @type
96 * @type: type of button (%EV_KEY, %EV_SW)
97 *
98 * Return value of this function can be used to allocate bitmap
99 * large enough to hold all bits for given type.
100 */
Dmitry Torokhov8679ee42016-01-06 14:20:07 -0800101static int get_n_events_by_type(int type)
Mika Westerberg9e3af042010-02-04 00:48:00 -0800102{
103 BUG_ON(type != EV_SW && type != EV_KEY);
104
105 return (type == EV_KEY) ? KEY_CNT : SW_CNT;
106}
107
108/**
Dmitry Torokhov8679ee42016-01-06 14:20:07 -0800109 * get_bm_events_by_type() - returns bitmap of supported events per @type
110 * @input: input device from which bitmap is retrieved
111 * @type: type of button (%EV_KEY, %EV_SW)
112 *
113 * Return value of this function can be used to allocate bitmap
114 * large enough to hold all bits for given type.
115 */
116static const unsigned long *get_bm_events_by_type(struct input_dev *dev,
117 int type)
118{
119 BUG_ON(type != EV_SW && type != EV_KEY);
120
121 return (type == EV_KEY) ? dev->keybit : dev->swbit;
122}
123
124/**
Mika Westerberg9e3af042010-02-04 00:48:00 -0800125 * gpio_keys_disable_button() - disables given GPIO button
126 * @bdata: button data for button to be disabled
127 *
128 * Disables button pointed by @bdata. This is done by masking
129 * IRQ line. After this function is called, button won't generate
130 * input events anymore. Note that one can only disable buttons
131 * that don't share IRQs.
132 *
133 * Make sure that @bdata->disable_lock is locked when entering
134 * this function to avoid races when concurrent threads are
135 * disabling buttons at the same time.
136 */
137static void gpio_keys_disable_button(struct gpio_button_data *bdata)
138{
139 if (!bdata->disabled) {
140 /*
Dmitry Torokhov8ed92552014-11-14 17:32:01 -0800141 * Disable IRQ and associated timer/work structure.
Mika Westerberg9e3af042010-02-04 00:48:00 -0800142 */
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700143 disable_irq(bdata->irq);
Dmitry Torokhov8ed92552014-11-14 17:32:01 -0800144
Geert Uytterhoevendb7c1702017-04-04 19:32:22 +0000145 if (bdata->gpiod)
Dmitry Torokhov8ed92552014-11-14 17:32:01 -0800146 cancel_delayed_work_sync(&bdata->work);
147 else
148 del_timer_sync(&bdata->release_timer);
Mika Westerberg9e3af042010-02-04 00:48:00 -0800149
150 bdata->disabled = true;
151 }
152}
153
154/**
155 * gpio_keys_enable_button() - enables given GPIO button
156 * @bdata: button data for button to be disabled
157 *
158 * Enables given button pointed by @bdata.
159 *
160 * Make sure that @bdata->disable_lock is locked when entering
161 * this function to avoid races with concurrent threads trying
162 * to enable the same button at the same time.
163 */
164static void gpio_keys_enable_button(struct gpio_button_data *bdata)
165{
166 if (bdata->disabled) {
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700167 enable_irq(bdata->irq);
Mika Westerberg9e3af042010-02-04 00:48:00 -0800168 bdata->disabled = false;
169 }
170}
171
172/**
173 * gpio_keys_attr_show_helper() - fill in stringified bitmap of buttons
174 * @ddata: pointer to drvdata
175 * @buf: buffer where stringified bitmap is written
176 * @type: button type (%EV_KEY, %EV_SW)
177 * @only_disabled: does caller want only those buttons that are
178 * currently disabled or all buttons that can be
179 * disabled
180 *
181 * This function writes buttons that can be disabled to @buf. If
182 * @only_disabled is true, then @buf contains only those buttons
183 * that are currently disabled. Returns 0 on success or negative
184 * errno on failure.
185 */
186static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
187 char *buf, unsigned int type,
188 bool only_disabled)
189{
190 int n_events = get_n_events_by_type(type);
191 unsigned long *bits;
192 ssize_t ret;
193 int i;
194
195 bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
196 if (!bits)
197 return -ENOMEM;
198
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700199 for (i = 0; i < ddata->pdata->nbuttons; i++) {
Mika Westerberg9e3af042010-02-04 00:48:00 -0800200 struct gpio_button_data *bdata = &ddata->data[i];
201
202 if (bdata->button->type != type)
203 continue;
204
205 if (only_disabled && !bdata->disabled)
206 continue;
207
208 __set_bit(bdata->button->code, bits);
209 }
210
Tejun Heo0b480032015-02-13 14:37:48 -0800211 ret = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", n_events, bits);
Mika Westerberg9e3af042010-02-04 00:48:00 -0800212 buf[ret++] = '\n';
213 buf[ret] = '\0';
214
215 kfree(bits);
216
217 return ret;
218}
219
220/**
221 * gpio_keys_attr_store_helper() - enable/disable buttons based on given bitmap
222 * @ddata: pointer to drvdata
223 * @buf: buffer from userspace that contains stringified bitmap
224 * @type: button type (%EV_KEY, %EV_SW)
225 *
226 * This function parses stringified bitmap from @buf and disables/enables
Dmitry Torokhova16ca232012-03-18 23:36:30 -0700227 * GPIO buttons accordingly. Returns 0 on success and negative error
Mika Westerberg9e3af042010-02-04 00:48:00 -0800228 * on failure.
229 */
230static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
231 const char *buf, unsigned int type)
232{
233 int n_events = get_n_events_by_type(type);
Dmitry Torokhov8679ee42016-01-06 14:20:07 -0800234 const unsigned long *bitmap = get_bm_events_by_type(ddata->input, type);
Mika Westerberg9e3af042010-02-04 00:48:00 -0800235 unsigned long *bits;
236 ssize_t error;
237 int i;
238
239 bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
240 if (!bits)
241 return -ENOMEM;
242
243 error = bitmap_parselist(buf, bits, n_events);
244 if (error)
245 goto out;
246
247 /* First validate */
Dmitry Torokhov8679ee42016-01-06 14:20:07 -0800248 if (!bitmap_subset(bits, bitmap, n_events)) {
249 error = -EINVAL;
250 goto out;
251 }
252
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700253 for (i = 0; i < ddata->pdata->nbuttons; i++) {
Mika Westerberg9e3af042010-02-04 00:48:00 -0800254 struct gpio_button_data *bdata = &ddata->data[i];
255
256 if (bdata->button->type != type)
257 continue;
258
259 if (test_bit(bdata->button->code, bits) &&
260 !bdata->button->can_disable) {
261 error = -EINVAL;
262 goto out;
263 }
264 }
265
266 mutex_lock(&ddata->disable_lock);
267
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700268 for (i = 0; i < ddata->pdata->nbuttons; i++) {
Mika Westerberg9e3af042010-02-04 00:48:00 -0800269 struct gpio_button_data *bdata = &ddata->data[i];
270
271 if (bdata->button->type != type)
272 continue;
273
274 if (test_bit(bdata->button->code, bits))
275 gpio_keys_disable_button(bdata);
276 else
277 gpio_keys_enable_button(bdata);
278 }
279
280 mutex_unlock(&ddata->disable_lock);
281
282out:
283 kfree(bits);
284 return error;
285}
286
287#define ATTR_SHOW_FN(name, type, only_disabled) \
288static ssize_t gpio_keys_show_##name(struct device *dev, \
289 struct device_attribute *attr, \
290 char *buf) \
291{ \
292 struct platform_device *pdev = to_platform_device(dev); \
293 struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \
294 \
295 return gpio_keys_attr_show_helper(ddata, buf, \
296 type, only_disabled); \
297}
298
299ATTR_SHOW_FN(keys, EV_KEY, false);
300ATTR_SHOW_FN(switches, EV_SW, false);
301ATTR_SHOW_FN(disabled_keys, EV_KEY, true);
302ATTR_SHOW_FN(disabled_switches, EV_SW, true);
303
304/*
305 * ATTRIBUTES:
306 *
307 * /sys/devices/platform/gpio-keys/keys [ro]
308 * /sys/devices/platform/gpio-keys/switches [ro]
309 */
310static DEVICE_ATTR(keys, S_IRUGO, gpio_keys_show_keys, NULL);
311static DEVICE_ATTR(switches, S_IRUGO, gpio_keys_show_switches, NULL);
312
313#define ATTR_STORE_FN(name, type) \
314static ssize_t gpio_keys_store_##name(struct device *dev, \
315 struct device_attribute *attr, \
316 const char *buf, \
317 size_t count) \
318{ \
319 struct platform_device *pdev = to_platform_device(dev); \
320 struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \
321 ssize_t error; \
322 \
323 error = gpio_keys_attr_store_helper(ddata, buf, type); \
324 if (error) \
325 return error; \
326 \
327 return count; \
328}
329
330ATTR_STORE_FN(disabled_keys, EV_KEY);
331ATTR_STORE_FN(disabled_switches, EV_SW);
332
333/*
334 * ATTRIBUTES:
335 *
336 * /sys/devices/platform/gpio-keys/disabled_keys [rw]
337 * /sys/devices/platform/gpio-keys/disables_switches [rw]
338 */
339static DEVICE_ATTR(disabled_keys, S_IWUSR | S_IRUGO,
340 gpio_keys_show_disabled_keys,
341 gpio_keys_store_disabled_keys);
342static DEVICE_ATTR(disabled_switches, S_IWUSR | S_IRUGO,
343 gpio_keys_show_disabled_switches,
344 gpio_keys_store_disabled_switches);
345
346static struct attribute *gpio_keys_attrs[] = {
347 &dev_attr_keys.attr,
348 &dev_attr_switches.attr,
349 &dev_attr_disabled_keys.attr,
350 &dev_attr_disabled_switches.attr,
351 NULL,
352};
353
354static struct attribute_group gpio_keys_attr_group = {
355 .attrs = gpio_keys_attrs,
356};
357
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700358static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
Dmitry Baryshkova33466e2008-05-07 16:30:15 -0400359{
Dmitry Torokhovd9080922012-03-18 23:36:29 -0700360 const struct gpio_keys_button *button = bdata->button;
Uwe Kleine-Königce25d7e2008-08-08 12:14:36 -0400361 struct input_dev *input = bdata->input;
Dmitry Baryshkova33466e2008-05-07 16:30:15 -0400362 unsigned int type = button->type ?: EV_KEY;
Geert Uytterhoevendb7c1702017-04-04 19:32:22 +0000363 int state;
Dmitry Baryshkova33466e2008-05-07 16:30:15 -0400364
Geert Uytterhoevendb7c1702017-04-04 19:32:22 +0000365 state = gpiod_get_value_cansleep(bdata->gpiod);
Bjorn Andersson77fa0552015-10-02 10:44:00 -0700366 if (state < 0) {
Geert Uytterhoevendb7c1702017-04-04 19:32:22 +0000367 dev_err(input->dev.parent,
368 "failed to get gpio state: %d\n", state);
Bjorn Andersson77fa0552015-10-02 10:44:00 -0700369 return;
370 }
371
Alexander Stein92a47672011-04-11 23:34:37 -0700372 if (type == EV_ABS) {
373 if (state)
374 input_event(input, type, button->code, button->value);
375 } else {
Geert Uytterhoevendb7c1702017-04-04 19:32:22 +0000376 input_event(input, type, button->code, state);
Alexander Stein92a47672011-04-11 23:34:37 -0700377 }
Dmitry Baryshkova33466e2008-05-07 16:30:15 -0400378 input_sync(input);
379}
380
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700381static void gpio_keys_gpio_work_func(struct work_struct *work)
Daniel Mack6ee88d72009-11-30 00:04:02 -0800382{
383 struct gpio_button_data *bdata =
Dmitry Torokhov8ed92552014-11-14 17:32:01 -0800384 container_of(work, struct gpio_button_data, work.work);
Daniel Mack6ee88d72009-11-30 00:04:02 -0800385
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700386 gpio_keys_gpio_report_event(bdata);
NeilBrown2fba26c2012-07-29 22:18:47 -0700387
388 if (bdata->button->wakeup)
389 pm_relax(bdata->input->dev.parent);
Daniel Mack6ee88d72009-11-30 00:04:02 -0800390}
391
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700392static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
Phil Blundell78a56aa2007-01-18 00:44:09 -0500393{
Uwe Kleine-König57ffe9d2008-08-08 12:14:34 -0400394 struct gpio_button_data *bdata = dev_id;
Phil Blundell78a56aa2007-01-18 00:44:09 -0500395
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700396 BUG_ON(irq != bdata->irq);
Phil Blundell78a56aa2007-01-18 00:44:09 -0500397
NeilBrown2fba26c2012-07-29 22:18:47 -0700398 if (bdata->button->wakeup)
399 pm_stay_awake(bdata->input->dev.parent);
Dmitry Torokhov8ed92552014-11-14 17:32:01 -0800400
401 mod_delayed_work(system_wq,
402 &bdata->work,
403 msecs_to_jiffies(bdata->software_debounce));
Roman Moravcik84767d02007-05-01 00:39:13 -0400404
Uwe Kleine-König57ffe9d2008-08-08 12:14:34 -0400405 return IRQ_HANDLED;
Phil Blundell78a56aa2007-01-18 00:44:09 -0500406}
407
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700408static void gpio_keys_irq_timer(unsigned long _data)
409{
410 struct gpio_button_data *bdata = (struct gpio_button_data *)_data;
411 struct input_dev *input = bdata->input;
412 unsigned long flags;
413
414 spin_lock_irqsave(&bdata->lock, flags);
415 if (bdata->key_pressed) {
416 input_event(input, EV_KEY, bdata->button->code, 0);
417 input_sync(input);
418 bdata->key_pressed = false;
419 }
420 spin_unlock_irqrestore(&bdata->lock, flags);
421}
422
423static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
424{
425 struct gpio_button_data *bdata = dev_id;
426 const struct gpio_keys_button *button = bdata->button;
427 struct input_dev *input = bdata->input;
428 unsigned long flags;
429
430 BUG_ON(irq != bdata->irq);
431
432 spin_lock_irqsave(&bdata->lock, flags);
433
434 if (!bdata->key_pressed) {
NeilBrown2fba26c2012-07-29 22:18:47 -0700435 if (bdata->button->wakeup)
436 pm_wakeup_event(bdata->input->dev.parent, 0);
437
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700438 input_event(input, EV_KEY, button->code, 1);
439 input_sync(input);
440
Dmitry Torokhov8ed92552014-11-14 17:32:01 -0800441 if (!bdata->release_delay) {
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700442 input_event(input, EV_KEY, button->code, 0);
443 input_sync(input);
444 goto out;
445 }
446
447 bdata->key_pressed = true;
448 }
449
Dmitry Torokhov8ed92552014-11-14 17:32:01 -0800450 if (bdata->release_delay)
451 mod_timer(&bdata->release_timer,
452 jiffies + msecs_to_jiffies(bdata->release_delay));
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700453out:
454 spin_unlock_irqrestore(&bdata->lock, flags);
455 return IRQ_HANDLED;
456}
457
Alexander Shiyan27245512014-04-28 09:52:36 -0700458static void gpio_keys_quiesce_key(void *data)
459{
460 struct gpio_button_data *bdata = data;
461
Geert Uytterhoevendb7c1702017-04-04 19:32:22 +0000462 if (bdata->gpiod)
Dmitry Torokhov8ed92552014-11-14 17:32:01 -0800463 cancel_delayed_work_sync(&bdata->work);
464 else
465 del_timer_sync(&bdata->release_timer);
Alexander Shiyan27245512014-04-28 09:52:36 -0700466}
467
Bill Pemberton5298cc42012-11-23 21:38:25 -0800468static int gpio_keys_setup_key(struct platform_device *pdev,
469 struct input_dev *input,
470 struct gpio_button_data *bdata,
471 const struct gpio_keys_button *button)
Ben Dooksbc8f1ea2009-11-10 21:01:31 -0800472{
Alexander Stein92a47672011-04-11 23:34:37 -0700473 const char *desc = button->desc ? button->desc : "gpio_keys";
Mika Westerberg9e3af042010-02-04 00:48:00 -0800474 struct device *dev = &pdev->dev;
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700475 irq_handler_t isr;
Mika Westerberg9e3af042010-02-04 00:48:00 -0800476 unsigned long irqflags;
Alexander Shiyan27245512014-04-28 09:52:36 -0700477 int irq;
478 int error;
Ben Dooksbc8f1ea2009-11-10 21:01:31 -0800479
Dmitry Torokhovd9080922012-03-18 23:36:29 -0700480 bdata->input = input;
481 bdata->button = button;
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700482 spin_lock_init(&bdata->lock);
Ben Dooksbc8f1ea2009-11-10 21:01:31 -0800483
Geert Uytterhoevendb7c1702017-04-04 19:32:22 +0000484 /*
485 * Legacy GPIO number, so request the GPIO here and
486 * convert it to descriptor.
487 */
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700488 if (gpio_is_valid(button->gpio)) {
Geert Uytterhoevendb7c1702017-04-04 19:32:22 +0000489 unsigned flags = GPIOF_IN;
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700490
Geert Uytterhoevendb7c1702017-04-04 19:32:22 +0000491 if (button->active_low)
492 flags |= GPIOF_ACTIVE_LOW;
493
494 error = devm_gpio_request_one(&pdev->dev, button->gpio, flags,
495 desc);
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700496 if (error < 0) {
497 dev_err(dev, "Failed to request GPIO %d, error %d\n",
498 button->gpio, error);
499 return error;
500 }
501
Geert Uytterhoevendb7c1702017-04-04 19:32:22 +0000502 bdata->gpiod = gpio_to_desc(button->gpio);
503 if (!bdata->gpiod)
504 return -EINVAL;
505
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700506 if (button->debounce_interval) {
Geert Uytterhoevendb7c1702017-04-04 19:32:22 +0000507 error = gpiod_set_debounce(bdata->gpiod,
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700508 button->debounce_interval * 1000);
509 /* use timer if gpiolib doesn't provide debounce */
510 if (error < 0)
Dmitry Torokhov8ed92552014-11-14 17:32:01 -0800511 bdata->software_debounce =
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700512 button->debounce_interval;
513 }
514
Dmitry Torokhov97d86e02014-11-14 15:57:09 -0800515 if (button->irq) {
516 bdata->irq = button->irq;
517 } else {
Geert Uytterhoevendb7c1702017-04-04 19:32:22 +0000518 irq = gpiod_to_irq(bdata->gpiod);
Dmitry Torokhov97d86e02014-11-14 15:57:09 -0800519 if (irq < 0) {
520 error = irq;
521 dev_err(dev,
522 "Unable to get irq number for GPIO %d, error %d\n",
523 button->gpio, error);
524 return error;
525 }
526 bdata->irq = irq;
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700527 }
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700528
Dmitry Torokhov8ed92552014-11-14 17:32:01 -0800529 INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func);
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700530
531 isr = gpio_keys_gpio_isr;
532 irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
533
534 } else {
535 if (!button->irq) {
536 dev_err(dev, "No IRQ specified\n");
537 return -EINVAL;
538 }
539 bdata->irq = button->irq;
540
541 if (button->type && button->type != EV_KEY) {
542 dev_err(dev, "Only EV_KEY allowed for IRQ buttons.\n");
543 return -EINVAL;
544 }
545
Dmitry Torokhov8ed92552014-11-14 17:32:01 -0800546 bdata->release_delay = button->debounce_interval;
547 setup_timer(&bdata->release_timer,
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700548 gpio_keys_irq_timer, (unsigned long)bdata);
549
550 isr = gpio_keys_irq_isr;
551 irqflags = 0;
Ben Dooksbc8f1ea2009-11-10 21:01:31 -0800552 }
553
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700554 input_set_capability(input, button->type ?: EV_KEY, button->code);
Ben Dooksbc8f1ea2009-11-10 21:01:31 -0800555
Mika Westerberg9e3af042010-02-04 00:48:00 -0800556 /*
Dmitry Torokhov8ed92552014-11-14 17:32:01 -0800557 * Install custom action to cancel release timer and
Alexander Shiyan27245512014-04-28 09:52:36 -0700558 * workqueue item.
559 */
560 error = devm_add_action(&pdev->dev, gpio_keys_quiesce_key, bdata);
561 if (error) {
562 dev_err(&pdev->dev,
563 "failed to register quiesce action, error: %d\n",
564 error);
565 return error;
566 }
567
568 /*
Mika Westerberg9e3af042010-02-04 00:48:00 -0800569 * If platform has specified that the button can be disabled,
570 * we don't want it to share the interrupt line.
571 */
572 if (!button->can_disable)
573 irqflags |= IRQF_SHARED;
574
Alexander Shiyan27245512014-04-28 09:52:36 -0700575 error = devm_request_any_context_irq(&pdev->dev, bdata->irq,
576 isr, irqflags, desc, bdata);
Philippe Langlais94a8cab2011-01-20 23:09:30 -0800577 if (error < 0) {
Ben Dooksbc8f1ea2009-11-10 21:01:31 -0800578 dev_err(dev, "Unable to claim irq %d; error %d\n",
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700579 bdata->irq, error);
Alexander Shiyan27245512014-04-28 09:52:36 -0700580 return error;
Ben Dooksbc8f1ea2009-11-10 21:01:31 -0800581 }
582
583 return 0;
Ben Dooksbc8f1ea2009-11-10 21:01:31 -0800584}
585
Dmitry Torokhov5b76d7b2012-11-24 01:22:43 -0800586static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
587{
588 struct input_dev *input = ddata->input;
589 int i;
590
591 for (i = 0; i < ddata->pdata->nbuttons; i++) {
592 struct gpio_button_data *bdata = &ddata->data[i];
Geert Uytterhoevendb7c1702017-04-04 19:32:22 +0000593 if (bdata->gpiod)
Dmitry Torokhov5b76d7b2012-11-24 01:22:43 -0800594 gpio_keys_gpio_report_event(bdata);
595 }
596 input_sync(input);
597}
598
Shubhrajyoti D173bdd72010-08-03 19:44:40 -0700599static int gpio_keys_open(struct input_dev *input)
600{
601 struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700602 const struct gpio_keys_platform_data *pdata = ddata->pdata;
Dmitry Torokhov5b76d7b2012-11-24 01:22:43 -0800603 int error;
Shubhrajyoti D173bdd72010-08-03 19:44:40 -0700604
Dmitry Torokhov5b76d7b2012-11-24 01:22:43 -0800605 if (pdata->enable) {
606 error = pdata->enable(input->dev.parent);
607 if (error)
608 return error;
609 }
610
611 /* Report current state of buttons that are connected to GPIOs */
612 gpio_keys_report_state(ddata);
613
614 return 0;
Shubhrajyoti D173bdd72010-08-03 19:44:40 -0700615}
616
617static void gpio_keys_close(struct input_dev *input)
618{
619 struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700620 const struct gpio_keys_platform_data *pdata = ddata->pdata;
Shubhrajyoti D173bdd72010-08-03 19:44:40 -0700621
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700622 if (pdata->disable)
623 pdata->disable(input->dev.parent);
Shubhrajyoti D173bdd72010-08-03 19:44:40 -0700624}
625
David Janderfd05d082011-07-09 12:41:46 -0700626/*
627 * Handlers for alternative sources of platform_data
628 */
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700629
David Janderfd05d082011-07-09 12:41:46 -0700630#ifdef CONFIG_OF
631/*
632 * Translate OpenFirmware node properties into platform_data
633 */
Bill Pemberton5298cc42012-11-23 21:38:25 -0800634static struct gpio_keys_platform_data *
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700635gpio_keys_get_devtree_pdata(struct device *dev)
David Janderfd05d082011-07-09 12:41:46 -0700636{
637 struct device_node *node, *pp;
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700638 struct gpio_keys_platform_data *pdata;
639 struct gpio_keys_button *button;
640 int error;
641 int nbuttons;
David Janderfd05d082011-07-09 12:41:46 -0700642 int i;
David Janderfd05d082011-07-09 12:41:46 -0700643
644 node = dev->of_node;
Andy Shevchenko5d422f22014-04-25 14:21:59 -0700645 if (!node)
646 return ERR_PTR(-ENODEV);
David Janderfd05d082011-07-09 12:41:46 -0700647
Laxman Dewangan809d9512016-01-13 00:14:19 -0800648 nbuttons = of_get_available_child_count(node);
Andy Shevchenko5d422f22014-04-25 14:21:59 -0700649 if (nbuttons == 0)
650 return ERR_PTR(-ENODEV);
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700651
Andy Shevchenko5d422f22014-04-25 14:21:59 -0700652 pdata = devm_kzalloc(dev,
653 sizeof(*pdata) + nbuttons * sizeof(*button),
654 GFP_KERNEL);
655 if (!pdata)
656 return ERR_PTR(-ENOMEM);
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700657
658 pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
659 pdata->nbuttons = nbuttons;
David Janderfd05d082011-07-09 12:41:46 -0700660
Tobias Klausercca84692011-09-09 11:09:50 -0700661 pdata->rep = !!of_get_property(node, "autorepeat", NULL);
David Janderfd05d082011-07-09 12:41:46 -0700662
Laxman Dewanganc4dc5f82016-01-12 22:56:40 -0800663 of_property_read_string(node, "label", &pdata->name);
664
David Janderfd05d082011-07-09 12:41:46 -0700665 i = 0;
Laxman Dewangan809d9512016-01-13 00:14:19 -0800666 for_each_available_child_of_node(node, pp) {
David Janderfd05d082011-07-09 12:41:46 -0700667 enum of_gpio_flags flags;
668
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700669 button = &pdata->buttons[i++];
670
Dmitry Torokhov97d86e02014-11-14 15:57:09 -0800671 button->gpio = of_get_gpio_flags(pp, 0, &flags);
672 if (button->gpio < 0) {
673 error = button->gpio;
674 if (error != -ENOENT) {
Alexander Steinf2d347f2014-11-25 11:53:45 -0800675 if (error != -EPROBE_DEFER)
676 dev_err(dev,
677 "Failed to get gpio flags, error: %d\n",
678 error);
679 return ERR_PTR(error);
680 }
Dmitry Torokhov97d86e02014-11-14 15:57:09 -0800681 } else {
682 button->active_low = flags & OF_GPIO_ACTIVE_LOW;
David Janderfd05d082011-07-09 12:41:46 -0700683 }
684
Dmitry Torokhov97d86e02014-11-14 15:57:09 -0800685 button->irq = irq_of_parse_and_map(pp, 0);
686
687 if (!gpio_is_valid(button->gpio) && !button->irq) {
688 dev_err(dev, "Found button without gpios or irqs\n");
689 return ERR_PTR(-EINVAL);
690 }
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700691
692 if (of_property_read_u32(pp, "linux,code", &button->code)) {
693 dev_err(dev, "Button without keycode: 0x%x\n",
694 button->gpio);
Andy Shevchenko5d422f22014-04-25 14:21:59 -0700695 return ERR_PTR(-EINVAL);
David Janderfd05d082011-07-09 12:41:46 -0700696 }
David Janderfd05d082011-07-09 12:41:46 -0700697
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700698 button->desc = of_get_property(pp, "label", NULL);
David Janderfd05d082011-07-09 12:41:46 -0700699
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700700 if (of_property_read_u32(pp, "linux,input-type", &button->type))
701 button->type = EV_KEY;
David Janderfd05d082011-07-09 12:41:46 -0700702
Dmitry Torokhov99b4ffb2015-07-16 12:10:05 -0700703 button->wakeup = of_property_read_bool(pp, "wakeup-source") ||
704 /* legacy name */
705 of_property_read_bool(pp, "gpio-key,wakeup");
David Janderfd05d082011-07-09 12:41:46 -0700706
Dmitry Torokhov97d86e02014-11-14 15:57:09 -0800707 button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL);
708
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700709 if (of_property_read_u32(pp, "debounce-interval",
710 &button->debounce_interval))
711 button->debounce_interval = 5;
David Janderfd05d082011-07-09 12:41:46 -0700712 }
713
Andy Shevchenko5d422f22014-04-25 14:21:59 -0700714 if (pdata->nbuttons == 0)
715 return ERR_PTR(-EINVAL);
David Janderfd05d082011-07-09 12:41:46 -0700716
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700717 return pdata;
David Janderfd05d082011-07-09 12:41:46 -0700718}
719
Jingoo Han22daae32014-05-07 12:58:06 -0700720static const struct of_device_id gpio_keys_of_match[] = {
David Janderfd05d082011-07-09 12:41:46 -0700721 { .compatible = "gpio-keys", },
722 { },
723};
724MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
725
726#else
727
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700728static inline struct gpio_keys_platform_data *
729gpio_keys_get_devtree_pdata(struct device *dev)
David Janderfd05d082011-07-09 12:41:46 -0700730{
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700731 return ERR_PTR(-ENODEV);
David Janderfd05d082011-07-09 12:41:46 -0700732}
733
David Janderfd05d082011-07-09 12:41:46 -0700734#endif
735
Bill Pemberton5298cc42012-11-23 21:38:25 -0800736static int gpio_keys_probe(struct platform_device *pdev)
Phil Blundell78a56aa2007-01-18 00:44:09 -0500737{
Ben Dooksdb19fd82009-11-10 21:00:35 -0800738 struct device *dev = &pdev->dev;
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700739 const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
740 struct gpio_keys_drvdata *ddata;
Phil Blundell78a56aa2007-01-18 00:44:09 -0500741 struct input_dev *input;
Andy Shevchenko5d422f22014-04-25 14:21:59 -0700742 size_t size;
Phil Blundell78a56aa2007-01-18 00:44:09 -0500743 int i, error;
Anti Sulline15b0212007-09-26 00:01:17 -0400744 int wakeup = 0;
Phil Blundell78a56aa2007-01-18 00:44:09 -0500745
David Janderfd05d082011-07-09 12:41:46 -0700746 if (!pdata) {
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700747 pdata = gpio_keys_get_devtree_pdata(dev);
748 if (IS_ERR(pdata))
749 return PTR_ERR(pdata);
David Janderfd05d082011-07-09 12:41:46 -0700750 }
751
Andy Shevchenko5d422f22014-04-25 14:21:59 -0700752 size = sizeof(struct gpio_keys_drvdata) +
753 pdata->nbuttons * sizeof(struct gpio_button_data);
754 ddata = devm_kzalloc(dev, size, GFP_KERNEL);
755 if (!ddata) {
Ben Dooksdb19fd82009-11-10 21:00:35 -0800756 dev_err(dev, "failed to allocate state\n");
Andy Shevchenko5d422f22014-04-25 14:21:59 -0700757 return -ENOMEM;
758 }
759
760 input = devm_input_allocate_device(dev);
761 if (!input) {
762 dev_err(dev, "failed to allocate input device\n");
763 return -ENOMEM;
Dmitry Baryshkova33466e2008-05-07 16:30:15 -0400764 }
Phil Blundell78a56aa2007-01-18 00:44:09 -0500765
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700766 ddata->pdata = pdata;
Mika Westerberg9e3af042010-02-04 00:48:00 -0800767 ddata->input = input;
Mika Westerberg9e3af042010-02-04 00:48:00 -0800768 mutex_init(&ddata->disable_lock);
769
Dmitry Baryshkova33466e2008-05-07 16:30:15 -0400770 platform_set_drvdata(pdev, ddata);
Shubhrajyoti D173bdd72010-08-03 19:44:40 -0700771 input_set_drvdata(input, ddata);
Phil Blundell78a56aa2007-01-18 00:44:09 -0500772
Alexander Stein46711272011-04-11 23:34:48 -0700773 input->name = pdata->name ? : pdev->name;
Phil Blundell78a56aa2007-01-18 00:44:09 -0500774 input->phys = "gpio-keys/input0";
Dmitry Torokhov469ba4d2007-04-12 01:34:58 -0400775 input->dev.parent = &pdev->dev;
Shubhrajyoti D173bdd72010-08-03 19:44:40 -0700776 input->open = gpio_keys_open;
777 input->close = gpio_keys_close;
Phil Blundell78a56aa2007-01-18 00:44:09 -0500778
779 input->id.bustype = BUS_HOST;
780 input->id.vendor = 0x0001;
781 input->id.product = 0x0001;
782 input->id.version = 0x0100;
783
Dominic Curranb67b4b12008-10-27 22:30:53 -0400784 /* Enable auto repeat feature of Linux input subsystem */
785 if (pdata->rep)
786 __set_bit(EV_REP, input->evbit);
787
Phil Blundell78a56aa2007-01-18 00:44:09 -0500788 for (i = 0; i < pdata->nbuttons; i++) {
Dmitry Torokhovd9080922012-03-18 23:36:29 -0700789 const struct gpio_keys_button *button = &pdata->buttons[i];
Dmitry Baryshkova33466e2008-05-07 16:30:15 -0400790 struct gpio_button_data *bdata = &ddata->data[i];
Phil Blundell78a56aa2007-01-18 00:44:09 -0500791
Dmitry Torokhovd9080922012-03-18 23:36:29 -0700792 error = gpio_keys_setup_key(pdev, input, bdata, button);
Ben Dooksbc8f1ea2009-11-10 21:01:31 -0800793 if (error)
Alexander Shiyan27245512014-04-28 09:52:36 -0700794 return error;
Roman Moravcik84767d02007-05-01 00:39:13 -0400795
Anti Sulline15b0212007-09-26 00:01:17 -0400796 if (button->wakeup)
797 wakeup = 1;
Phil Blundell78a56aa2007-01-18 00:44:09 -0500798 }
799
Mika Westerberg9e3af042010-02-04 00:48:00 -0800800 error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
801 if (error) {
802 dev_err(dev, "Unable to export keys/switches, error: %d\n",
803 error);
Alexander Shiyan27245512014-04-28 09:52:36 -0700804 return error;
Mika Westerberg9e3af042010-02-04 00:48:00 -0800805 }
806
Phil Blundell78a56aa2007-01-18 00:44:09 -0500807 error = input_register_device(input);
808 if (error) {
Mika Westerberg9e3af042010-02-04 00:48:00 -0800809 dev_err(dev, "Unable to register input device, error: %d\n",
810 error);
Alexander Shiyan27245512014-04-28 09:52:36 -0700811 goto err_remove_group;
Phil Blundell78a56aa2007-01-18 00:44:09 -0500812 }
813
Anti Sulline15b0212007-09-26 00:01:17 -0400814 device_init_wakeup(&pdev->dev, wakeup);
815
Phil Blundell78a56aa2007-01-18 00:44:09 -0500816 return 0;
817
Alexander Shiyan27245512014-04-28 09:52:36 -0700818err_remove_group:
Mika Westerberg9e3af042010-02-04 00:48:00 -0800819 sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
Phil Blundell78a56aa2007-01-18 00:44:09 -0500820 return error;
821}
822
Bill Pembertone2619cf2012-11-23 21:50:47 -0800823static int gpio_keys_remove(struct platform_device *pdev)
Phil Blundell78a56aa2007-01-18 00:44:09 -0500824{
Mika Westerberg9e3af042010-02-04 00:48:00 -0800825 sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
826
Anti Sulline15b0212007-09-26 00:01:17 -0400827 device_init_wakeup(&pdev->dev, 0);
828
Phil Blundell78a56aa2007-01-18 00:44:09 -0500829 return 0;
830}
831
Dmitry Torokhovbdda8212011-07-09 12:41:46 -0700832#ifdef CONFIG_PM_SLEEP
Mike Rapoportae78e0e2009-07-22 23:02:54 -0700833static int gpio_keys_suspend(struct device *dev)
Anti Sulline15b0212007-09-26 00:01:17 -0400834{
David Janderfd05d082011-07-09 12:41:46 -0700835 struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
Jonas Aabergdda19a92012-11-24 00:10:29 -0800836 struct input_dev *input = ddata->input;
Anti Sulline15b0212007-09-26 00:01:17 -0400837 int i;
838
David Janderfd05d082011-07-09 12:41:46 -0700839 if (device_may_wakeup(dev)) {
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700840 for (i = 0; i < ddata->pdata->nbuttons; i++) {
Laxman Dewangand8ee4a12012-03-19 17:54:31 -0700841 struct gpio_button_data *bdata = &ddata->data[i];
842 if (bdata->button->wakeup)
843 enable_irq_wake(bdata->irq);
Anti Sulline15b0212007-09-26 00:01:17 -0400844 }
Jonas Aabergdda19a92012-11-24 00:10:29 -0800845 } else {
846 mutex_lock(&input->mutex);
847 if (input->users)
848 gpio_keys_close(input);
849 mutex_unlock(&input->mutex);
Anti Sulline15b0212007-09-26 00:01:17 -0400850 }
851
852 return 0;
853}
854
Mike Rapoportae78e0e2009-07-22 23:02:54 -0700855static int gpio_keys_resume(struct device *dev)
Anti Sulline15b0212007-09-26 00:01:17 -0400856{
David Janderfd05d082011-07-09 12:41:46 -0700857 struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
Jonas Aabergdda19a92012-11-24 00:10:29 -0800858 struct input_dev *input = ddata->input;
859 int error = 0;
Anti Sulline15b0212007-09-26 00:01:17 -0400860 int i;
861
Jonas Aabergdda19a92012-11-24 00:10:29 -0800862 if (device_may_wakeup(dev)) {
863 for (i = 0; i < ddata->pdata->nbuttons; i++) {
864 struct gpio_button_data *bdata = &ddata->data[i];
865 if (bdata->button->wakeup)
866 disable_irq_wake(bdata->irq);
867 }
868 } else {
869 mutex_lock(&input->mutex);
870 if (input->users)
871 error = gpio_keys_open(input);
872 mutex_unlock(&input->mutex);
Anti Sulline15b0212007-09-26 00:01:17 -0400873 }
Dmitry Torokhov5b76d7b2012-11-24 01:22:43 -0800874
Jonas Aabergdda19a92012-11-24 00:10:29 -0800875 if (error)
876 return error;
Anti Sulline15b0212007-09-26 00:01:17 -0400877
Jonas Aabergdda19a92012-11-24 00:10:29 -0800878 gpio_keys_report_state(ddata);
Anti Sulline15b0212007-09-26 00:01:17 -0400879 return 0;
880}
Anti Sulline15b0212007-09-26 00:01:17 -0400881#endif
882
Dmitry Torokhovbdda8212011-07-09 12:41:46 -0700883static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
884
Uwe Kleine-König9b070442008-07-30 10:34:02 -0400885static struct platform_driver gpio_keys_device_driver = {
Phil Blundell78a56aa2007-01-18 00:44:09 -0500886 .probe = gpio_keys_probe,
Bill Pemberton1cb0aa82012-11-23 21:27:39 -0800887 .remove = gpio_keys_remove,
Phil Blundell78a56aa2007-01-18 00:44:09 -0500888 .driver = {
889 .name = "gpio-keys",
Mike Rapoportae78e0e2009-07-22 23:02:54 -0700890 .pm = &gpio_keys_pm_ops,
Alexandre Pereira da Silva219edc72012-07-29 22:18:47 -0700891 .of_match_table = of_match_ptr(gpio_keys_of_match),
Phil Blundell78a56aa2007-01-18 00:44:09 -0500892 }
893};
894
895static int __init gpio_keys_init(void)
896{
897 return platform_driver_register(&gpio_keys_device_driver);
898}
899
900static void __exit gpio_keys_exit(void)
901{
902 platform_driver_unregister(&gpio_keys_device_driver);
903}
904
David Janderb2330202011-06-23 01:30:09 -0700905late_initcall(gpio_keys_init);
Phil Blundell78a56aa2007-01-18 00:44:09 -0500906module_exit(gpio_keys_exit);
907
908MODULE_LICENSE("GPL");
909MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
David Jander7e2ecdf2011-06-21 14:26:18 -0700910MODULE_DESCRIPTION("Keyboard driver for GPIOs");
Kay Sieversd7b52472008-04-18 00:24:42 -0400911MODULE_ALIAS("platform:gpio-keys");