1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
278a56aabSPhil Blundell /*
378a56aabSPhil Blundell * Driver for keys on GPIO lines capable of generating interrupts.
478a56aabSPhil Blundell *
578a56aabSPhil Blundell * Copyright 2005 Phil Blundell
6fd05d089SDavid Jander * Copyright 2010, 2011 David Jander <david@protonic.nl>
778a56aabSPhil Blundell */
878a56aabSPhil Blundell
978a56aabSPhil Blundell #include <linux/module.h>
1078a56aabSPhil Blundell
11019002f2SPaul Cercueil #include <linux/hrtimer.h>
1278a56aabSPhil Blundell #include <linux/init.h>
1378a56aabSPhil Blundell #include <linux/fs.h>
1478a56aabSPhil Blundell #include <linux/interrupt.h>
1578a56aabSPhil Blundell #include <linux/irq.h>
1678a56aabSPhil Blundell #include <linux/sched.h>
1778a56aabSPhil Blundell #include <linux/pm.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
1978a56aabSPhil Blundell #include <linux/sysctl.h>
2078a56aabSPhil Blundell #include <linux/proc_fs.h>
2178a56aabSPhil Blundell #include <linux/delay.h>
2278a56aabSPhil Blundell #include <linux/platform_device.h>
2378a56aabSPhil Blundell #include <linux/input.h>
2449015beeSDavid Brownell #include <linux/gpio_keys.h>
25da0d03feSJani Nikula #include <linux/workqueue.h>
26111bc59cSBen Dooks #include <linux/gpio.h>
275feeca3cSGeert Uytterhoeven #include <linux/gpio/consumer.h>
28415a4caaSSachin Kamat #include <linux/of.h>
29f2d347ffSAlexander Stein #include <linux/of_irq.h>
30d8ee4a1cSLaxman Dewangan #include <linux/spinlock.h>
3183fc580dSJeffy Chen #include <dt-bindings/input/gpio-keys.h>
3278a56aabSPhil Blundell
33a33466e3SDmitry Baryshkov struct gpio_button_data {
34d9080921SDmitry Torokhov const struct gpio_keys_button *button;
35a33466e3SDmitry Baryshkov struct input_dev *input;
365feeca3cSGeert Uytterhoeven struct gpio_desc *gpiod;
378ed92556SDmitry Torokhov
3883e4947aSHans de Goede unsigned short *code;
3983e4947aSHans de Goede
40019002f2SPaul Cercueil struct hrtimer release_timer;
418ed92556SDmitry Torokhov unsigned int release_delay; /* in msecs, for IRQ-only buttons */
428ed92556SDmitry Torokhov
438ed92556SDmitry Torokhov struct delayed_work work;
44c9efb0baSPaul Cercueil struct hrtimer debounce_timer;
458ed92556SDmitry Torokhov unsigned int software_debounce; /* in msecs, for GPIO-driven buttons */
468ed92556SDmitry Torokhov
47d8ee4a1cSLaxman Dewangan unsigned int irq;
4883fc580dSJeffy Chen unsigned int wakeup_trigger_type;
49d8ee4a1cSLaxman Dewangan spinlock_t lock;
509e3af04fSMika Westerberg bool disabled;
51d8ee4a1cSLaxman Dewangan bool key_pressed;
520f107573SJoseph Lo bool suspended;
53c9efb0baSPaul Cercueil bool debounce_use_hrtimer;
54a33466e3SDmitry Baryshkov };
55a33466e3SDmitry Baryshkov
56a33466e3SDmitry Baryshkov struct gpio_keys_drvdata {
57219edc71SAlexandre Pereira da Silva const struct gpio_keys_platform_data *pdata;
58a33466e3SDmitry Baryshkov struct input_dev *input;
599e3af04fSMika Westerberg struct mutex disable_lock;
6083e4947aSHans de Goede unsigned short *keymap;
61a1b9b65eSGustavo A. R. Silva struct gpio_button_data data[];
62a33466e3SDmitry Baryshkov };
63a33466e3SDmitry Baryshkov
649e3af04fSMika Westerberg /*
659e3af04fSMika Westerberg * SYSFS interface for enabling/disabling keys and switches:
669e3af04fSMika Westerberg *
679e3af04fSMika Westerberg * There are 4 attributes under /sys/devices/platform/gpio-keys/
689e3af04fSMika Westerberg * keys [ro] - bitmap of keys (EV_KEY) which can be
699e3af04fSMika Westerberg * disabled
709e3af04fSMika Westerberg * switches [ro] - bitmap of switches (EV_SW) which can be
719e3af04fSMika Westerberg * disabled
729e3af04fSMika Westerberg * disabled_keys [rw] - bitmap of keys currently disabled
739e3af04fSMika Westerberg * disabled_switches [rw] - bitmap of switches currently disabled
749e3af04fSMika Westerberg *
759e3af04fSMika Westerberg * Userland can change these values and hence disable event generation
769e3af04fSMika Westerberg * for each key (or switch). Disabling a key means its interrupt line
779e3af04fSMika Westerberg * is disabled.
789e3af04fSMika Westerberg *
799e3af04fSMika Westerberg * For example, if we have following switches set up as gpio-keys:
809e3af04fSMika Westerberg * SW_DOCK = 5
819e3af04fSMika Westerberg * SW_CAMERA_LENS_COVER = 9
829e3af04fSMika Westerberg * SW_KEYPAD_SLIDE = 10
839e3af04fSMika Westerberg * SW_FRONT_PROXIMITY = 11
849e3af04fSMika Westerberg * This is read from switches:
859e3af04fSMika Westerberg * 11-9,5
869e3af04fSMika Westerberg * Next we want to disable proximity (11) and dock (5), we write:
879e3af04fSMika Westerberg * 11,5
889e3af04fSMika Westerberg * to file disabled_switches. Now proximity and dock IRQs are disabled.
899e3af04fSMika Westerberg * This can be verified by reading the file disabled_switches:
909e3af04fSMika Westerberg * 11,5
919e3af04fSMika Westerberg * If we now want to enable proximity (11) switch we write:
929e3af04fSMika Westerberg * 5
939e3af04fSMika Westerberg * to disabled_switches.
949e3af04fSMika Westerberg *
959e3af04fSMika Westerberg * We can disable only those keys which don't allow sharing the irq.
969e3af04fSMika Westerberg */
979e3af04fSMika Westerberg
989e3af04fSMika Westerberg /**
999e3af04fSMika Westerberg * get_n_events_by_type() - returns maximum number of events per @type
1009e3af04fSMika Westerberg * @type: type of button (%EV_KEY, %EV_SW)
1019e3af04fSMika Westerberg *
1029e3af04fSMika Westerberg * Return value of this function can be used to allocate bitmap
1039e3af04fSMika Westerberg * large enough to hold all bits for given type.
1049e3af04fSMika Westerberg */
get_n_events_by_type(int type)1058679ee42SDmitry Torokhov static int get_n_events_by_type(int type)
1069e3af04fSMika Westerberg {
1079e3af04fSMika Westerberg BUG_ON(type != EV_SW && type != EV_KEY);
1089e3af04fSMika Westerberg
1099e3af04fSMika Westerberg return (type == EV_KEY) ? KEY_CNT : SW_CNT;
1109e3af04fSMika Westerberg }
1119e3af04fSMika Westerberg
1129e3af04fSMika Westerberg /**
1138679ee42SDmitry Torokhov * get_bm_events_by_type() - returns bitmap of supported events per @type
1142216c0e4SLee Jones * @dev: input device from which bitmap is retrieved
1158679ee42SDmitry Torokhov * @type: type of button (%EV_KEY, %EV_SW)
1168679ee42SDmitry Torokhov *
1178679ee42SDmitry Torokhov * Return value of this function can be used to allocate bitmap
1188679ee42SDmitry Torokhov * large enough to hold all bits for given type.
1198679ee42SDmitry Torokhov */
get_bm_events_by_type(struct input_dev * dev,int type)1208679ee42SDmitry Torokhov static const unsigned long *get_bm_events_by_type(struct input_dev *dev,
1218679ee42SDmitry Torokhov int type)
1228679ee42SDmitry Torokhov {
1238679ee42SDmitry Torokhov BUG_ON(type != EV_SW && type != EV_KEY);
1248679ee42SDmitry Torokhov
1258679ee42SDmitry Torokhov return (type == EV_KEY) ? dev->keybit : dev->swbit;
1268679ee42SDmitry Torokhov }
1278679ee42SDmitry Torokhov
gpio_keys_quiesce_key(void * data)1282531fdbfSDmitry Torokhov static void gpio_keys_quiesce_key(void *data)
1292531fdbfSDmitry Torokhov {
1302531fdbfSDmitry Torokhov struct gpio_button_data *bdata = data;
1312531fdbfSDmitry Torokhov
1322531fdbfSDmitry Torokhov if (!bdata->gpiod)
1332531fdbfSDmitry Torokhov hrtimer_cancel(&bdata->release_timer);
134cee409bbSLad Prabhakar else if (bdata->debounce_use_hrtimer)
1352531fdbfSDmitry Torokhov hrtimer_cancel(&bdata->debounce_timer);
1362531fdbfSDmitry Torokhov else
1372531fdbfSDmitry Torokhov cancel_delayed_work_sync(&bdata->work);
1382531fdbfSDmitry Torokhov }
1392531fdbfSDmitry Torokhov
1408679ee42SDmitry Torokhov /**
1419e3af04fSMika Westerberg * gpio_keys_disable_button() - disables given GPIO button
1429e3af04fSMika Westerberg * @bdata: button data for button to be disabled
1439e3af04fSMika Westerberg *
1449e3af04fSMika Westerberg * Disables button pointed by @bdata. This is done by masking
1459e3af04fSMika Westerberg * IRQ line. After this function is called, button won't generate
1469e3af04fSMika Westerberg * input events anymore. Note that one can only disable buttons
1479e3af04fSMika Westerberg * that don't share IRQs.
1489e3af04fSMika Westerberg *
1499e3af04fSMika Westerberg * Make sure that @bdata->disable_lock is locked when entering
1509e3af04fSMika Westerberg * this function to avoid races when concurrent threads are
1519e3af04fSMika Westerberg * disabling buttons at the same time.
1529e3af04fSMika Westerberg */
gpio_keys_disable_button(struct gpio_button_data * bdata)1539e3af04fSMika Westerberg static void gpio_keys_disable_button(struct gpio_button_data *bdata)
1549e3af04fSMika Westerberg {
1559e3af04fSMika Westerberg if (!bdata->disabled) {
1569e3af04fSMika Westerberg /*
1578ed92556SDmitry Torokhov * Disable IRQ and associated timer/work structure.
1589e3af04fSMika Westerberg */
159d8ee4a1cSLaxman Dewangan disable_irq(bdata->irq);
1602531fdbfSDmitry Torokhov gpio_keys_quiesce_key(bdata);
1619e3af04fSMika Westerberg bdata->disabled = true;
1629e3af04fSMika Westerberg }
1639e3af04fSMika Westerberg }
1649e3af04fSMika Westerberg
1659e3af04fSMika Westerberg /**
1669e3af04fSMika Westerberg * gpio_keys_enable_button() - enables given GPIO button
1679e3af04fSMika Westerberg * @bdata: button data for button to be disabled
1689e3af04fSMika Westerberg *
1699e3af04fSMika Westerberg * Enables given button pointed by @bdata.
1709e3af04fSMika Westerberg *
1719e3af04fSMika Westerberg * Make sure that @bdata->disable_lock is locked when entering
1729e3af04fSMika Westerberg * this function to avoid races with concurrent threads trying
1739e3af04fSMika Westerberg * to enable the same button at the same time.
1749e3af04fSMika Westerberg */
gpio_keys_enable_button(struct gpio_button_data * bdata)1759e3af04fSMika Westerberg static void gpio_keys_enable_button(struct gpio_button_data *bdata)
1769e3af04fSMika Westerberg {
1779e3af04fSMika Westerberg if (bdata->disabled) {
178d8ee4a1cSLaxman Dewangan enable_irq(bdata->irq);
1799e3af04fSMika Westerberg bdata->disabled = false;
1809e3af04fSMika Westerberg }
1819e3af04fSMika Westerberg }
1829e3af04fSMika Westerberg
1839e3af04fSMika Westerberg /**
1849e3af04fSMika Westerberg * gpio_keys_attr_show_helper() - fill in stringified bitmap of buttons
1859e3af04fSMika Westerberg * @ddata: pointer to drvdata
1869e3af04fSMika Westerberg * @buf: buffer where stringified bitmap is written
1879e3af04fSMika Westerberg * @type: button type (%EV_KEY, %EV_SW)
1889e3af04fSMika Westerberg * @only_disabled: does caller want only those buttons that are
1899e3af04fSMika Westerberg * currently disabled or all buttons that can be
1909e3af04fSMika Westerberg * disabled
1919e3af04fSMika Westerberg *
1929e3af04fSMika Westerberg * This function writes buttons that can be disabled to @buf. If
1939e3af04fSMika Westerberg * @only_disabled is true, then @buf contains only those buttons
1949e3af04fSMika Westerberg * that are currently disabled. Returns 0 on success or negative
1959e3af04fSMika Westerberg * errno on failure.
1969e3af04fSMika Westerberg */
gpio_keys_attr_show_helper(struct gpio_keys_drvdata * ddata,char * buf,unsigned int type,bool only_disabled)1979e3af04fSMika Westerberg static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
1989e3af04fSMika Westerberg char *buf, unsigned int type,
1999e3af04fSMika Westerberg bool only_disabled)
2009e3af04fSMika Westerberg {
2019e3af04fSMika Westerberg int n_events = get_n_events_by_type(type);
2029e3af04fSMika Westerberg unsigned long *bits;
2039e3af04fSMika Westerberg ssize_t ret;
2049e3af04fSMika Westerberg int i;
2059e3af04fSMika Westerberg
2064e2ec39dSAndy Shevchenko bits = bitmap_zalloc(n_events, GFP_KERNEL);
2079e3af04fSMika Westerberg if (!bits)
2089e3af04fSMika Westerberg return -ENOMEM;
2099e3af04fSMika Westerberg
210219edc71SAlexandre Pereira da Silva for (i = 0; i < ddata->pdata->nbuttons; i++) {
2119e3af04fSMika Westerberg struct gpio_button_data *bdata = &ddata->data[i];
2129e3af04fSMika Westerberg
2139e3af04fSMika Westerberg if (bdata->button->type != type)
2149e3af04fSMika Westerberg continue;
2159e3af04fSMika Westerberg
2169e3af04fSMika Westerberg if (only_disabled && !bdata->disabled)
2179e3af04fSMika Westerberg continue;
2189e3af04fSMika Westerberg
21983e4947aSHans de Goede __set_bit(*bdata->code, bits);
2209e3af04fSMika Westerberg }
2219e3af04fSMika Westerberg
2220b480037STejun Heo ret = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", n_events, bits);
2239e3af04fSMika Westerberg buf[ret++] = '\n';
2249e3af04fSMika Westerberg buf[ret] = '\0';
2259e3af04fSMika Westerberg
2264e2ec39dSAndy Shevchenko bitmap_free(bits);
2279e3af04fSMika Westerberg
2289e3af04fSMika Westerberg return ret;
2299e3af04fSMika Westerberg }
2309e3af04fSMika Westerberg
2319e3af04fSMika Westerberg /**
2329e3af04fSMika Westerberg * gpio_keys_attr_store_helper() - enable/disable buttons based on given bitmap
2339e3af04fSMika Westerberg * @ddata: pointer to drvdata
2349e3af04fSMika Westerberg * @buf: buffer from userspace that contains stringified bitmap
2359e3af04fSMika Westerberg * @type: button type (%EV_KEY, %EV_SW)
2369e3af04fSMika Westerberg *
2379e3af04fSMika Westerberg * This function parses stringified bitmap from @buf and disables/enables
238a16ca239SDmitry Torokhov * GPIO buttons accordingly. Returns 0 on success and negative error
2399e3af04fSMika Westerberg * on failure.
2409e3af04fSMika Westerberg */
gpio_keys_attr_store_helper(struct gpio_keys_drvdata * ddata,const char * buf,unsigned int type)2419e3af04fSMika Westerberg static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
2429e3af04fSMika Westerberg const char *buf, unsigned int type)
2439e3af04fSMika Westerberg {
2449e3af04fSMika Westerberg int n_events = get_n_events_by_type(type);
2458679ee42SDmitry Torokhov const unsigned long *bitmap = get_bm_events_by_type(ddata->input, type);
2469e3af04fSMika Westerberg unsigned long *bits;
2479e3af04fSMika Westerberg ssize_t error;
2489e3af04fSMika Westerberg int i;
2499e3af04fSMika Westerberg
25008a6df09SChristophe JAILLET bits = bitmap_alloc(n_events, GFP_KERNEL);
2519e3af04fSMika Westerberg if (!bits)
2529e3af04fSMika Westerberg return -ENOMEM;
2539e3af04fSMika Westerberg
2549e3af04fSMika Westerberg error = bitmap_parselist(buf, bits, n_events);
2559e3af04fSMika Westerberg if (error)
2569e3af04fSMika Westerberg goto out;
2579e3af04fSMika Westerberg
2589e3af04fSMika Westerberg /* First validate */
2598679ee42SDmitry Torokhov if (!bitmap_subset(bits, bitmap, n_events)) {
2608679ee42SDmitry Torokhov error = -EINVAL;
2618679ee42SDmitry Torokhov goto out;
2628679ee42SDmitry Torokhov }
2638679ee42SDmitry Torokhov
264219edc71SAlexandre Pereira da Silva for (i = 0; i < ddata->pdata->nbuttons; i++) {
2659e3af04fSMika Westerberg struct gpio_button_data *bdata = &ddata->data[i];
2669e3af04fSMika Westerberg
2679e3af04fSMika Westerberg if (bdata->button->type != type)
2689e3af04fSMika Westerberg continue;
2699e3af04fSMika Westerberg
27083e4947aSHans de Goede if (test_bit(*bdata->code, bits) &&
2719e3af04fSMika Westerberg !bdata->button->can_disable) {
2729e3af04fSMika Westerberg error = -EINVAL;
2739e3af04fSMika Westerberg goto out;
2749e3af04fSMika Westerberg }
2759e3af04fSMika Westerberg }
2769e3af04fSMika Westerberg
2779e3af04fSMika Westerberg mutex_lock(&ddata->disable_lock);
2789e3af04fSMika Westerberg
279219edc71SAlexandre Pereira da Silva for (i = 0; i < ddata->pdata->nbuttons; i++) {
2809e3af04fSMika Westerberg struct gpio_button_data *bdata = &ddata->data[i];
2819e3af04fSMika Westerberg
2829e3af04fSMika Westerberg if (bdata->button->type != type)
2839e3af04fSMika Westerberg continue;
2849e3af04fSMika Westerberg
28583e4947aSHans de Goede if (test_bit(*bdata->code, bits))
2869e3af04fSMika Westerberg gpio_keys_disable_button(bdata);
2879e3af04fSMika Westerberg else
2889e3af04fSMika Westerberg gpio_keys_enable_button(bdata);
2899e3af04fSMika Westerberg }
2909e3af04fSMika Westerberg
2919e3af04fSMika Westerberg mutex_unlock(&ddata->disable_lock);
2929e3af04fSMika Westerberg
2939e3af04fSMika Westerberg out:
2944e2ec39dSAndy Shevchenko bitmap_free(bits);
2959e3af04fSMika Westerberg return error;
2969e3af04fSMika Westerberg }
2979e3af04fSMika Westerberg
2989e3af04fSMika Westerberg #define ATTR_SHOW_FN(name, type, only_disabled) \
2999e3af04fSMika Westerberg static ssize_t gpio_keys_show_##name(struct device *dev, \
3009e3af04fSMika Westerberg struct device_attribute *attr, \
3019e3af04fSMika Westerberg char *buf) \
3029e3af04fSMika Westerberg { \
3039e3af04fSMika Westerberg struct platform_device *pdev = to_platform_device(dev); \
3049e3af04fSMika Westerberg struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \
3059e3af04fSMika Westerberg \
3069e3af04fSMika Westerberg return gpio_keys_attr_show_helper(ddata, buf, \
3079e3af04fSMika Westerberg type, only_disabled); \
3089e3af04fSMika Westerberg }
3099e3af04fSMika Westerberg
3109e3af04fSMika Westerberg ATTR_SHOW_FN(keys, EV_KEY, false);
3119e3af04fSMika Westerberg ATTR_SHOW_FN(switches, EV_SW, false);
3129e3af04fSMika Westerberg ATTR_SHOW_FN(disabled_keys, EV_KEY, true);
3139e3af04fSMika Westerberg ATTR_SHOW_FN(disabled_switches, EV_SW, true);
3149e3af04fSMika Westerberg
3159e3af04fSMika Westerberg /*
3169e3af04fSMika Westerberg * ATTRIBUTES:
3179e3af04fSMika Westerberg *
3189e3af04fSMika Westerberg * /sys/devices/platform/gpio-keys/keys [ro]
3199e3af04fSMika Westerberg * /sys/devices/platform/gpio-keys/switches [ro]
3209e3af04fSMika Westerberg */
3219e3af04fSMika Westerberg static DEVICE_ATTR(keys, S_IRUGO, gpio_keys_show_keys, NULL);
3229e3af04fSMika Westerberg static DEVICE_ATTR(switches, S_IRUGO, gpio_keys_show_switches, NULL);
3239e3af04fSMika Westerberg
3249e3af04fSMika Westerberg #define ATTR_STORE_FN(name, type) \
3259e3af04fSMika Westerberg static ssize_t gpio_keys_store_##name(struct device *dev, \
3269e3af04fSMika Westerberg struct device_attribute *attr, \
3279e3af04fSMika Westerberg const char *buf, \
3289e3af04fSMika Westerberg size_t count) \
3299e3af04fSMika Westerberg { \
3309e3af04fSMika Westerberg struct platform_device *pdev = to_platform_device(dev); \
3319e3af04fSMika Westerberg struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \
3329e3af04fSMika Westerberg ssize_t error; \
3339e3af04fSMika Westerberg \
3349e3af04fSMika Westerberg error = gpio_keys_attr_store_helper(ddata, buf, type); \
3359e3af04fSMika Westerberg if (error) \
3369e3af04fSMika Westerberg return error; \
3379e3af04fSMika Westerberg \
3389e3af04fSMika Westerberg return count; \
3399e3af04fSMika Westerberg }
3409e3af04fSMika Westerberg
3419e3af04fSMika Westerberg ATTR_STORE_FN(disabled_keys, EV_KEY);
3429e3af04fSMika Westerberg ATTR_STORE_FN(disabled_switches, EV_SW);
3439e3af04fSMika Westerberg
3449e3af04fSMika Westerberg /*
3459e3af04fSMika Westerberg * ATTRIBUTES:
3469e3af04fSMika Westerberg *
3479e3af04fSMika Westerberg * /sys/devices/platform/gpio-keys/disabled_keys [rw]
3489e3af04fSMika Westerberg * /sys/devices/platform/gpio-keys/disables_switches [rw]
3499e3af04fSMika Westerberg */
3509e3af04fSMika Westerberg static DEVICE_ATTR(disabled_keys, S_IWUSR | S_IRUGO,
3519e3af04fSMika Westerberg gpio_keys_show_disabled_keys,
3529e3af04fSMika Westerberg gpio_keys_store_disabled_keys);
3539e3af04fSMika Westerberg static DEVICE_ATTR(disabled_switches, S_IWUSR | S_IRUGO,
3549e3af04fSMika Westerberg gpio_keys_show_disabled_switches,
3559e3af04fSMika Westerberg gpio_keys_store_disabled_switches);
3569e3af04fSMika Westerberg
3579e3af04fSMika Westerberg static struct attribute *gpio_keys_attrs[] = {
3589e3af04fSMika Westerberg &dev_attr_keys.attr,
3599e3af04fSMika Westerberg &dev_attr_switches.attr,
3609e3af04fSMika Westerberg &dev_attr_disabled_keys.attr,
3619e3af04fSMika Westerberg &dev_attr_disabled_switches.attr,
3629e3af04fSMika Westerberg NULL,
3639e3af04fSMika Westerberg };
364cf1b2a20SGreg Kroah-Hartman ATTRIBUTE_GROUPS(gpio_keys);
3659e3af04fSMika Westerberg
gpio_keys_gpio_report_event(struct gpio_button_data * bdata)366d8ee4a1cSLaxman Dewangan static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
36778a56aabSPhil Blundell {
368d9080921SDmitry Torokhov const struct gpio_keys_button *button = bdata->button;
369ce25d7e9SUwe Kleine-König struct input_dev *input = bdata->input;
37084767d00SRoman Moravcik unsigned int type = button->type ?: EV_KEY;
3715feeca3cSGeert Uytterhoeven int state;
37284767d00SRoman Moravcik
373c9efb0baSPaul Cercueil state = bdata->debounce_use_hrtimer ?
374c9efb0baSPaul Cercueil gpiod_get_value(bdata->gpiod) :
375c9efb0baSPaul Cercueil gpiod_get_value_cansleep(bdata->gpiod);
37677fa0554SBjorn Andersson if (state < 0) {
3775feeca3cSGeert Uytterhoeven dev_err(input->dev.parent,
3785feeca3cSGeert Uytterhoeven "failed to get gpio state: %d\n", state);
37977fa0554SBjorn Andersson return;
38077fa0554SBjorn Andersson }
38177fa0554SBjorn Andersson
38292a47674SAlexander Stein if (type == EV_ABS) {
38392a47674SAlexander Stein if (state)
38492a47674SAlexander Stein input_event(input, type, button->code, button->value);
38592a47674SAlexander Stein } else {
38683e4947aSHans de Goede input_event(input, type, *bdata->code, state);
38792a47674SAlexander Stein }
388a33466e3SDmitry Baryshkov }
389a33466e3SDmitry Baryshkov
gpio_keys_debounce_event(struct gpio_button_data * bdata)390c9efb0baSPaul Cercueil static void gpio_keys_debounce_event(struct gpio_button_data *bdata)
3916ee88d71SDaniel Mack {
392d8ee4a1cSLaxman Dewangan gpio_keys_gpio_report_event(bdata);
39336a8fc6fSPaul Cercueil input_sync(bdata->input);
3942fba26c6SNeilBrown
3952fba26c6SNeilBrown if (bdata->button->wakeup)
3962fba26c6SNeilBrown pm_relax(bdata->input->dev.parent);
3976ee88d71SDaniel Mack }
3986ee88d71SDaniel Mack
gpio_keys_gpio_work_func(struct work_struct * work)399c9efb0baSPaul Cercueil static void gpio_keys_gpio_work_func(struct work_struct *work)
400c9efb0baSPaul Cercueil {
401c9efb0baSPaul Cercueil struct gpio_button_data *bdata =
402c9efb0baSPaul Cercueil container_of(work, struct gpio_button_data, work.work);
403c9efb0baSPaul Cercueil
404c9efb0baSPaul Cercueil gpio_keys_debounce_event(bdata);
405c9efb0baSPaul Cercueil }
406c9efb0baSPaul Cercueil
gpio_keys_debounce_timer(struct hrtimer * t)407c9efb0baSPaul Cercueil static enum hrtimer_restart gpio_keys_debounce_timer(struct hrtimer *t)
408c9efb0baSPaul Cercueil {
409c9efb0baSPaul Cercueil struct gpio_button_data *bdata =
410c9efb0baSPaul Cercueil container_of(t, struct gpio_button_data, debounce_timer);
411c9efb0baSPaul Cercueil
412c9efb0baSPaul Cercueil gpio_keys_debounce_event(bdata);
413c9efb0baSPaul Cercueil
414c9efb0baSPaul Cercueil return HRTIMER_NORESTART;
415c9efb0baSPaul Cercueil }
416c9efb0baSPaul Cercueil
gpio_keys_gpio_isr(int irq,void * dev_id)417d8ee4a1cSLaxman Dewangan static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
418a33466e3SDmitry Baryshkov {
41957ffe9d5SUwe Kleine-König struct gpio_button_data *bdata = dev_id;
420a33466e3SDmitry Baryshkov
421d8ee4a1cSLaxman Dewangan BUG_ON(irq != bdata->irq);
422a33466e3SDmitry Baryshkov
4230f107573SJoseph Lo if (bdata->button->wakeup) {
4240f107573SJoseph Lo const struct gpio_keys_button *button = bdata->button;
4250f107573SJoseph Lo
4262fba26c6SNeilBrown pm_stay_awake(bdata->input->dev.parent);
4270f107573SJoseph Lo if (bdata->suspended &&
4280f107573SJoseph Lo (button->type == 0 || button->type == EV_KEY)) {
4290f107573SJoseph Lo /*
4300f107573SJoseph Lo * Simulate wakeup key press in case the key has
4310f107573SJoseph Lo * already released by the time we got interrupt
4320f107573SJoseph Lo * handler to run.
4330f107573SJoseph Lo */
4340f107573SJoseph Lo input_report_key(bdata->input, button->code, 1);
4350f107573SJoseph Lo }
4360f107573SJoseph Lo }
4378ed92556SDmitry Torokhov
438c9efb0baSPaul Cercueil if (bdata->debounce_use_hrtimer) {
439c9efb0baSPaul Cercueil hrtimer_start(&bdata->debounce_timer,
440c9efb0baSPaul Cercueil ms_to_ktime(bdata->software_debounce),
441c9efb0baSPaul Cercueil HRTIMER_MODE_REL);
442c9efb0baSPaul Cercueil } else {
4438ed92556SDmitry Torokhov mod_delayed_work(system_wq,
4448ed92556SDmitry Torokhov &bdata->work,
4458ed92556SDmitry Torokhov msecs_to_jiffies(bdata->software_debounce));
446c9efb0baSPaul Cercueil }
447a33466e3SDmitry Baryshkov
4481164ec1aSDavid Brownell return IRQ_HANDLED;
44978a56aabSPhil Blundell }
45078a56aabSPhil Blundell
gpio_keys_irq_timer(struct hrtimer * t)451019002f2SPaul Cercueil static enum hrtimer_restart gpio_keys_irq_timer(struct hrtimer *t)
452d8ee4a1cSLaxman Dewangan {
453019002f2SPaul Cercueil struct gpio_button_data *bdata = container_of(t,
454019002f2SPaul Cercueil struct gpio_button_data,
455019002f2SPaul Cercueil release_timer);
456d8ee4a1cSLaxman Dewangan struct input_dev *input = bdata->input;
457d8ee4a1cSLaxman Dewangan
458d8ee4a1cSLaxman Dewangan if (bdata->key_pressed) {
4593615536cSGeert Uytterhoeven input_report_key(input, *bdata->code, 0);
460d8ee4a1cSLaxman Dewangan input_sync(input);
461d8ee4a1cSLaxman Dewangan bdata->key_pressed = false;
462d8ee4a1cSLaxman Dewangan }
463019002f2SPaul Cercueil
464019002f2SPaul Cercueil return HRTIMER_NORESTART;
465d8ee4a1cSLaxman Dewangan }
466d8ee4a1cSLaxman Dewangan
gpio_keys_irq_isr(int irq,void * dev_id)467d8ee4a1cSLaxman Dewangan static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
468d8ee4a1cSLaxman Dewangan {
469d8ee4a1cSLaxman Dewangan struct gpio_button_data *bdata = dev_id;
470d8ee4a1cSLaxman Dewangan struct input_dev *input = bdata->input;
471d8ee4a1cSLaxman Dewangan unsigned long flags;
472d8ee4a1cSLaxman Dewangan
473d8ee4a1cSLaxman Dewangan BUG_ON(irq != bdata->irq);
474d8ee4a1cSLaxman Dewangan
475d8ee4a1cSLaxman Dewangan spin_lock_irqsave(&bdata->lock, flags);
476d8ee4a1cSLaxman Dewangan
477d8ee4a1cSLaxman Dewangan if (!bdata->key_pressed) {
4782fba26c6SNeilBrown if (bdata->button->wakeup)
4792fba26c6SNeilBrown pm_wakeup_event(bdata->input->dev.parent, 0);
4802fba26c6SNeilBrown
4813615536cSGeert Uytterhoeven input_report_key(input, *bdata->code, 1);
482d8ee4a1cSLaxman Dewangan input_sync(input);
483d8ee4a1cSLaxman Dewangan
4848ed92556SDmitry Torokhov if (!bdata->release_delay) {
4853615536cSGeert Uytterhoeven input_report_key(input, *bdata->code, 0);
486d8ee4a1cSLaxman Dewangan input_sync(input);
487d8ee4a1cSLaxman Dewangan goto out;
488d8ee4a1cSLaxman Dewangan }
489d8ee4a1cSLaxman Dewangan
490d8ee4a1cSLaxman Dewangan bdata->key_pressed = true;
491d8ee4a1cSLaxman Dewangan }
492d8ee4a1cSLaxman Dewangan
4938ed92556SDmitry Torokhov if (bdata->release_delay)
494019002f2SPaul Cercueil hrtimer_start(&bdata->release_timer,
495019002f2SPaul Cercueil ms_to_ktime(bdata->release_delay),
496019002f2SPaul Cercueil HRTIMER_MODE_REL_HARD);
497d8ee4a1cSLaxman Dewangan out:
498d8ee4a1cSLaxman Dewangan spin_unlock_irqrestore(&bdata->lock, flags);
499d8ee4a1cSLaxman Dewangan return IRQ_HANDLED;
500d8ee4a1cSLaxman Dewangan }
501d8ee4a1cSLaxman Dewangan
gpio_keys_setup_key(struct platform_device * pdev,struct input_dev * input,struct gpio_keys_drvdata * ddata,const struct gpio_keys_button * button,int idx,struct fwnode_handle * child)5025298cc4cSBill Pemberton static int gpio_keys_setup_key(struct platform_device *pdev,
503d9080921SDmitry Torokhov struct input_dev *input,
50483e4947aSHans de Goede struct gpio_keys_drvdata *ddata,
505700a38b2SDmitry Torokhov const struct gpio_keys_button *button,
50683e4947aSHans de Goede int idx,
507700a38b2SDmitry Torokhov struct fwnode_handle *child)
508bc8f1eafSBen Dooks {
50992a47674SAlexander Stein const char *desc = button->desc ? button->desc : "gpio_keys";
5109e3af04fSMika Westerberg struct device *dev = &pdev->dev;
51183e4947aSHans de Goede struct gpio_button_data *bdata = &ddata->data[idx];
512d8ee4a1cSLaxman Dewangan irq_handler_t isr;
5139e3af04fSMika Westerberg unsigned long irqflags;
51427245519SAlexander Shiyan int irq;
51527245519SAlexander Shiyan int error;
516bc8f1eafSBen Dooks
517d9080921SDmitry Torokhov bdata->input = input;
518d9080921SDmitry Torokhov bdata->button = button;
519d8ee4a1cSLaxman Dewangan spin_lock_init(&bdata->lock);
520d8ee4a1cSLaxman Dewangan
521700a38b2SDmitry Torokhov if (child) {
5222a60f598SDmitry Torokhov bdata->gpiod = devm_fwnode_gpiod_get(dev, child,
5232a60f598SDmitry Torokhov NULL, GPIOD_IN, desc);
524700a38b2SDmitry Torokhov if (IS_ERR(bdata->gpiod)) {
525700a38b2SDmitry Torokhov error = PTR_ERR(bdata->gpiod);
526*904ef2c4SGeert Uytterhoeven if (error != -ENOENT)
527*904ef2c4SGeert Uytterhoeven return dev_err_probe(dev, error,
528*904ef2c4SGeert Uytterhoeven "failed to get gpio\n");
529*904ef2c4SGeert Uytterhoeven
530700a38b2SDmitry Torokhov /*
531700a38b2SDmitry Torokhov * GPIO is optional, we may be dealing with
532700a38b2SDmitry Torokhov * purely interrupt-driven setup.
533700a38b2SDmitry Torokhov */
534700a38b2SDmitry Torokhov bdata->gpiod = NULL;
535700a38b2SDmitry Torokhov }
536700a38b2SDmitry Torokhov } else if (gpio_is_valid(button->gpio)) {
5375feeca3cSGeert Uytterhoeven /*
5385feeca3cSGeert Uytterhoeven * Legacy GPIO number, so request the GPIO here and
5395feeca3cSGeert Uytterhoeven * convert it to descriptor.
5405feeca3cSGeert Uytterhoeven */
5415feeca3cSGeert Uytterhoeven unsigned flags = GPIOF_IN;
542bc8f1eafSBen Dooks
5435feeca3cSGeert Uytterhoeven if (button->active_low)
5445feeca3cSGeert Uytterhoeven flags |= GPIOF_ACTIVE_LOW;
5455feeca3cSGeert Uytterhoeven
546b4e66e7dSGuenter Roeck error = devm_gpio_request_one(dev, button->gpio, flags, desc);
547bc8f1eafSBen Dooks if (error < 0) {
548d8ee4a1cSLaxman Dewangan dev_err(dev, "Failed to request GPIO %d, error %d\n",
549bc8f1eafSBen Dooks button->gpio, error);
550d8ee4a1cSLaxman Dewangan return error;
551bc8f1eafSBen Dooks }
552bc8f1eafSBen Dooks
5535feeca3cSGeert Uytterhoeven bdata->gpiod = gpio_to_desc(button->gpio);
5545feeca3cSGeert Uytterhoeven if (!bdata->gpiod)
5555feeca3cSGeert Uytterhoeven return -EINVAL;
556700a38b2SDmitry Torokhov }
5575feeca3cSGeert Uytterhoeven
558700a38b2SDmitry Torokhov if (bdata->gpiod) {
55983fc580dSJeffy Chen bool active_low = gpiod_is_active_low(bdata->gpiod);
56083fc580dSJeffy Chen
56128ed684fSGrazvydas Ignotas if (button->debounce_interval) {
5625feeca3cSGeert Uytterhoeven error = gpiod_set_debounce(bdata->gpiod,
56328ed684fSGrazvydas Ignotas button->debounce_interval * 1000);
56428ed684fSGrazvydas Ignotas /* use timer if gpiolib doesn't provide debounce */
56528ed684fSGrazvydas Ignotas if (error < 0)
5668ed92556SDmitry Torokhov bdata->software_debounce =
567d8ee4a1cSLaxman Dewangan button->debounce_interval;
568c9efb0baSPaul Cercueil
569c9efb0baSPaul Cercueil /*
570c9efb0baSPaul Cercueil * If reading the GPIO won't sleep, we can use a
571c9efb0baSPaul Cercueil * hrtimer instead of a standard timer for the software
572c9efb0baSPaul Cercueil * debounce, to reduce the latency as much as possible.
573c9efb0baSPaul Cercueil */
574c9efb0baSPaul Cercueil bdata->debounce_use_hrtimer =
575c9efb0baSPaul Cercueil !gpiod_cansleep(bdata->gpiod);
57628ed684fSGrazvydas Ignotas }
57728ed684fSGrazvydas Ignotas
57897d86e07SDmitry Torokhov if (button->irq) {
57997d86e07SDmitry Torokhov bdata->irq = button->irq;
58097d86e07SDmitry Torokhov } else {
5815feeca3cSGeert Uytterhoeven irq = gpiod_to_irq(bdata->gpiod);
582bc8f1eafSBen Dooks if (irq < 0) {
583bc8f1eafSBen Dooks error = irq;
584d8ee4a1cSLaxman Dewangan dev_err(dev,
585d8ee4a1cSLaxman Dewangan "Unable to get irq number for GPIO %d, error %d\n",
586bc8f1eafSBen Dooks button->gpio, error);
58727245519SAlexander Shiyan return error;
588d8ee4a1cSLaxman Dewangan }
589d8ee4a1cSLaxman Dewangan bdata->irq = irq;
59097d86e07SDmitry Torokhov }
591d8ee4a1cSLaxman Dewangan
5928ed92556SDmitry Torokhov INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func);
593d8ee4a1cSLaxman Dewangan
594c9efb0baSPaul Cercueil hrtimer_init(&bdata->debounce_timer,
595c9efb0baSPaul Cercueil CLOCK_REALTIME, HRTIMER_MODE_REL);
596c9efb0baSPaul Cercueil bdata->debounce_timer.function = gpio_keys_debounce_timer;
597c9efb0baSPaul Cercueil
598d8ee4a1cSLaxman Dewangan isr = gpio_keys_gpio_isr;
599d8ee4a1cSLaxman Dewangan irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
600d8ee4a1cSLaxman Dewangan
60183fc580dSJeffy Chen switch (button->wakeup_event_action) {
60283fc580dSJeffy Chen case EV_ACT_ASSERTED:
60383fc580dSJeffy Chen bdata->wakeup_trigger_type = active_low ?
60483fc580dSJeffy Chen IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
60583fc580dSJeffy Chen break;
60683fc580dSJeffy Chen case EV_ACT_DEASSERTED:
60783fc580dSJeffy Chen bdata->wakeup_trigger_type = active_low ?
60883fc580dSJeffy Chen IRQ_TYPE_EDGE_RISING : IRQ_TYPE_EDGE_FALLING;
60983fc580dSJeffy Chen break;
61083fc580dSJeffy Chen case EV_ACT_ANY:
61183fc580dSJeffy Chen default:
61283fc580dSJeffy Chen /*
61383fc580dSJeffy Chen * For other cases, we are OK letting suspend/resume
61483fc580dSJeffy Chen * not reconfigure the trigger type.
61583fc580dSJeffy Chen */
61683fc580dSJeffy Chen break;
61783fc580dSJeffy Chen }
618d8ee4a1cSLaxman Dewangan } else {
619d8ee4a1cSLaxman Dewangan if (!button->irq) {
620700a38b2SDmitry Torokhov dev_err(dev, "Found button without gpio or irq\n");
621d8ee4a1cSLaxman Dewangan return -EINVAL;
622d8ee4a1cSLaxman Dewangan }
623700a38b2SDmitry Torokhov
624d8ee4a1cSLaxman Dewangan bdata->irq = button->irq;
625d8ee4a1cSLaxman Dewangan
626d8ee4a1cSLaxman Dewangan if (button->type && button->type != EV_KEY) {
627d8ee4a1cSLaxman Dewangan dev_err(dev, "Only EV_KEY allowed for IRQ buttons.\n");
628d8ee4a1cSLaxman Dewangan return -EINVAL;
629bc8f1eafSBen Dooks }
630bc8f1eafSBen Dooks
6318ed92556SDmitry Torokhov bdata->release_delay = button->debounce_interval;
632019002f2SPaul Cercueil hrtimer_init(&bdata->release_timer,
633019002f2SPaul Cercueil CLOCK_REALTIME, HRTIMER_MODE_REL_HARD);
634019002f2SPaul Cercueil bdata->release_timer.function = gpio_keys_irq_timer;
635d8ee4a1cSLaxman Dewangan
636d8ee4a1cSLaxman Dewangan isr = gpio_keys_irq_isr;
637d8ee4a1cSLaxman Dewangan irqflags = 0;
63883fc580dSJeffy Chen
63983fc580dSJeffy Chen /*
64083fc580dSJeffy Chen * For IRQ buttons, there is no interrupt for release.
64183fc580dSJeffy Chen * So we don't need to reconfigure the trigger type for wakeup.
64283fc580dSJeffy Chen */
643d8ee4a1cSLaxman Dewangan }
644d8ee4a1cSLaxman Dewangan
64583e4947aSHans de Goede bdata->code = &ddata->keymap[idx];
64683e4947aSHans de Goede *bdata->code = button->code;
64783e4947aSHans de Goede input_set_capability(input, button->type ?: EV_KEY, *bdata->code);
648d8ee4a1cSLaxman Dewangan
6499e3af04fSMika Westerberg /*
6508ed92556SDmitry Torokhov * Install custom action to cancel release timer and
65127245519SAlexander Shiyan * workqueue item.
65227245519SAlexander Shiyan */
653b4e66e7dSGuenter Roeck error = devm_add_action(dev, gpio_keys_quiesce_key, bdata);
65427245519SAlexander Shiyan if (error) {
655b4e66e7dSGuenter Roeck dev_err(dev, "failed to register quiesce action, error: %d\n",
65627245519SAlexander Shiyan error);
65727245519SAlexander Shiyan return error;
65827245519SAlexander Shiyan }
65927245519SAlexander Shiyan
66027245519SAlexander Shiyan /*
6619e3af04fSMika Westerberg * If platform has specified that the button can be disabled,
6629e3af04fSMika Westerberg * we don't want it to share the interrupt line.
6639e3af04fSMika Westerberg */
6649e3af04fSMika Westerberg if (!button->can_disable)
6659e3af04fSMika Westerberg irqflags |= IRQF_SHARED;
6669e3af04fSMika Westerberg
667b4e66e7dSGuenter Roeck error = devm_request_any_context_irq(dev, bdata->irq, isr, irqflags,
668b4e66e7dSGuenter Roeck desc, bdata);
66994a8cab8SPhilippe Langlais if (error < 0) {
670bc8f1eafSBen Dooks dev_err(dev, "Unable to claim irq %d; error %d\n",
671d8ee4a1cSLaxman Dewangan bdata->irq, error);
67227245519SAlexander Shiyan return error;
673bc8f1eafSBen Dooks }
674bc8f1eafSBen Dooks
675bc8f1eafSBen Dooks return 0;
676bc8f1eafSBen Dooks }
677bc8f1eafSBen Dooks
gpio_keys_report_state(struct gpio_keys_drvdata * ddata)6785b76d7b4SDmitry Torokhov static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
6795b76d7b4SDmitry Torokhov {
6805b76d7b4SDmitry Torokhov struct input_dev *input = ddata->input;
6815b76d7b4SDmitry Torokhov int i;
6825b76d7b4SDmitry Torokhov
6835b76d7b4SDmitry Torokhov for (i = 0; i < ddata->pdata->nbuttons; i++) {
6845b76d7b4SDmitry Torokhov struct gpio_button_data *bdata = &ddata->data[i];
6855feeca3cSGeert Uytterhoeven if (bdata->gpiod)
6865b76d7b4SDmitry Torokhov gpio_keys_gpio_report_event(bdata);
6875b76d7b4SDmitry Torokhov }
6885b76d7b4SDmitry Torokhov input_sync(input);
6895b76d7b4SDmitry Torokhov }
6905b76d7b4SDmitry Torokhov
gpio_keys_open(struct input_dev * input)691173bdd74SShubhrajyoti D static int gpio_keys_open(struct input_dev *input)
692173bdd74SShubhrajyoti D {
693173bdd74SShubhrajyoti D struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
694219edc71SAlexandre Pereira da Silva const struct gpio_keys_platform_data *pdata = ddata->pdata;
6955b76d7b4SDmitry Torokhov int error;
696173bdd74SShubhrajyoti D
6975b76d7b4SDmitry Torokhov if (pdata->enable) {
6985b76d7b4SDmitry Torokhov error = pdata->enable(input->dev.parent);
6995b76d7b4SDmitry Torokhov if (error)
7005b76d7b4SDmitry Torokhov return error;
7015b76d7b4SDmitry Torokhov }
7025b76d7b4SDmitry Torokhov
7035b76d7b4SDmitry Torokhov /* Report current state of buttons that are connected to GPIOs */
7045b76d7b4SDmitry Torokhov gpio_keys_report_state(ddata);
7055b76d7b4SDmitry Torokhov
7065b76d7b4SDmitry Torokhov return 0;
707173bdd74SShubhrajyoti D }
708173bdd74SShubhrajyoti D
gpio_keys_close(struct input_dev * input)709173bdd74SShubhrajyoti D static void gpio_keys_close(struct input_dev *input)
710173bdd74SShubhrajyoti D {
711173bdd74SShubhrajyoti D struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
712219edc71SAlexandre Pereira da Silva const struct gpio_keys_platform_data *pdata = ddata->pdata;
713173bdd74SShubhrajyoti D
714219edc71SAlexandre Pereira da Silva if (pdata->disable)
715219edc71SAlexandre Pereira da Silva pdata->disable(input->dev.parent);
716173bdd74SShubhrajyoti D }
717173bdd74SShubhrajyoti D
718fd05d089SDavid Jander /*
719fd05d089SDavid Jander * Handlers for alternative sources of platform_data
720fd05d089SDavid Jander */
721219edc71SAlexandre Pereira da Silva
722fd05d089SDavid Jander /*
723700a38b2SDmitry Torokhov * Translate properties into platform_data
724fd05d089SDavid Jander */
7255298cc4cSBill Pemberton static struct gpio_keys_platform_data *
gpio_keys_get_devtree_pdata(struct device * dev)726219edc71SAlexandre Pereira da Silva gpio_keys_get_devtree_pdata(struct device *dev)
727fd05d089SDavid Jander {
728219edc71SAlexandre Pereira da Silva struct gpio_keys_platform_data *pdata;
729219edc71SAlexandre Pereira da Silva struct gpio_keys_button *button;
730700a38b2SDmitry Torokhov struct fwnode_handle *child;
731219edc71SAlexandre Pereira da Silva int nbuttons;
732fd05d089SDavid Jander
733700a38b2SDmitry Torokhov nbuttons = device_get_child_node_count(dev);
7345d422f2eSAndy Shevchenko if (nbuttons == 0)
7355d422f2eSAndy Shevchenko return ERR_PTR(-ENODEV);
736219edc71SAlexandre Pereira da Silva
7375d422f2eSAndy Shevchenko pdata = devm_kzalloc(dev,
7385d422f2eSAndy Shevchenko sizeof(*pdata) + nbuttons * sizeof(*button),
739219edc71SAlexandre Pereira da Silva GFP_KERNEL);
7405d422f2eSAndy Shevchenko if (!pdata)
7415d422f2eSAndy Shevchenko return ERR_PTR(-ENOMEM);
742219edc71SAlexandre Pereira da Silva
7430f78ba96SDmitry Torokhov button = (struct gpio_keys_button *)(pdata + 1);
7440f78ba96SDmitry Torokhov
7450f78ba96SDmitry Torokhov pdata->buttons = button;
746219edc71SAlexandre Pereira da Silva pdata->nbuttons = nbuttons;
747fd05d089SDavid Jander
748700a38b2SDmitry Torokhov pdata->rep = device_property_read_bool(dev, "autorepeat");
749fd05d089SDavid Jander
750700a38b2SDmitry Torokhov device_property_read_string(dev, "label", &pdata->name);
751c4dc5f8cSLaxman Dewangan
752700a38b2SDmitry Torokhov device_for_each_child_node(dev, child) {
753700a38b2SDmitry Torokhov if (is_of_node(child))
754700a38b2SDmitry Torokhov button->irq =
755700a38b2SDmitry Torokhov irq_of_parse_and_map(to_of_node(child), 0);
756fd05d089SDavid Jander
757700a38b2SDmitry Torokhov if (fwnode_property_read_u32(child, "linux,code",
758700a38b2SDmitry Torokhov &button->code)) {
759700a38b2SDmitry Torokhov dev_err(dev, "Button without keycode\n");
760700a38b2SDmitry Torokhov fwnode_handle_put(child);
76197d86e07SDmitry Torokhov return ERR_PTR(-EINVAL);
76297d86e07SDmitry Torokhov }
763fd05d089SDavid Jander
764700a38b2SDmitry Torokhov fwnode_property_read_string(child, "label", &button->desc);
765fd05d089SDavid Jander
766700a38b2SDmitry Torokhov if (fwnode_property_read_u32(child, "linux,input-type",
767700a38b2SDmitry Torokhov &button->type))
768219edc71SAlexandre Pereira da Silva button->type = EV_KEY;
769fd05d089SDavid Jander
7704b665e17SGergo Koteles fwnode_property_read_u32(child, "linux,input-value",
7714b665e17SGergo Koteles (u32 *)&button->value);
7724b665e17SGergo Koteles
773700a38b2SDmitry Torokhov button->wakeup =
774700a38b2SDmitry Torokhov fwnode_property_read_bool(child, "wakeup-source") ||
77599b4ffbdSDmitry Torokhov /* legacy name */
776700a38b2SDmitry Torokhov fwnode_property_read_bool(child, "gpio-key,wakeup");
777219edc71SAlexandre Pereira da Silva
77883fc580dSJeffy Chen fwnode_property_read_u32(child, "wakeup-event-action",
77983fc580dSJeffy Chen &button->wakeup_event_action);
78083fc580dSJeffy Chen
781700a38b2SDmitry Torokhov button->can_disable =
782700a38b2SDmitry Torokhov fwnode_property_read_bool(child, "linux,can-disable");
78397d86e07SDmitry Torokhov
784700a38b2SDmitry Torokhov if (fwnode_property_read_u32(child, "debounce-interval",
785219edc71SAlexandre Pereira da Silva &button->debounce_interval))
786219edc71SAlexandre Pereira da Silva button->debounce_interval = 5;
7870f78ba96SDmitry Torokhov
7880f78ba96SDmitry Torokhov button++;
789219edc71SAlexandre Pereira da Silva }
790219edc71SAlexandre Pereira da Silva
791219edc71SAlexandre Pereira da Silva return pdata;
792fd05d089SDavid Jander }
793fd05d089SDavid Jander
79422daae31SJingoo Han static const struct of_device_id gpio_keys_of_match[] = {
795fd05d089SDavid Jander { .compatible = "gpio-keys", },
796fd05d089SDavid Jander { },
797fd05d089SDavid Jander };
798fd05d089SDavid Jander MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
799fd05d089SDavid Jander
gpio_keys_probe(struct platform_device * pdev)8005298cc4cSBill Pemberton static int gpio_keys_probe(struct platform_device *pdev)
80178a56aabSPhil Blundell {
802db19fd8bSBen Dooks struct device *dev = &pdev->dev;
803219edc71SAlexandre Pereira da Silva const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
804700a38b2SDmitry Torokhov struct fwnode_handle *child = NULL;
805219edc71SAlexandre Pereira da Silva struct gpio_keys_drvdata *ddata;
80678a56aabSPhil Blundell struct input_dev *input;
80778a56aabSPhil Blundell int i, error;
808e15b0213SAnti Sullin int wakeup = 0;
80978a56aabSPhil Blundell
810fd05d089SDavid Jander if (!pdata) {
811219edc71SAlexandre Pereira da Silva pdata = gpio_keys_get_devtree_pdata(dev);
812219edc71SAlexandre Pereira da Silva if (IS_ERR(pdata))
813219edc71SAlexandre Pereira da Silva return PTR_ERR(pdata);
814fd05d089SDavid Jander }
815fd05d089SDavid Jander
816002cdb95SGustavo A. R. Silva ddata = devm_kzalloc(dev, struct_size(ddata, data, pdata->nbuttons),
817002cdb95SGustavo A. R. Silva GFP_KERNEL);
8185d422f2eSAndy Shevchenko if (!ddata) {
819db19fd8bSBen Dooks dev_err(dev, "failed to allocate state\n");
8205d422f2eSAndy Shevchenko return -ENOMEM;
8215d422f2eSAndy Shevchenko }
8225d422f2eSAndy Shevchenko
82383e4947aSHans de Goede ddata->keymap = devm_kcalloc(dev,
82483e4947aSHans de Goede pdata->nbuttons, sizeof(ddata->keymap[0]),
82583e4947aSHans de Goede GFP_KERNEL);
82683e4947aSHans de Goede if (!ddata->keymap)
82783e4947aSHans de Goede return -ENOMEM;
82883e4947aSHans de Goede
8295d422f2eSAndy Shevchenko input = devm_input_allocate_device(dev);
8305d422f2eSAndy Shevchenko if (!input) {
8315d422f2eSAndy Shevchenko dev_err(dev, "failed to allocate input device\n");
8325d422f2eSAndy Shevchenko return -ENOMEM;
833a33466e3SDmitry Baryshkov }
83478a56aabSPhil Blundell
835219edc71SAlexandre Pereira da Silva ddata->pdata = pdata;
8369e3af04fSMika Westerberg ddata->input = input;
8379e3af04fSMika Westerberg mutex_init(&ddata->disable_lock);
8389e3af04fSMika Westerberg
839a33466e3SDmitry Baryshkov platform_set_drvdata(pdev, ddata);
840173bdd74SShubhrajyoti D input_set_drvdata(input, ddata);
84178a56aabSPhil Blundell
84246711277SAlexander Stein input->name = pdata->name ? : pdev->name;
84378a56aabSPhil Blundell input->phys = "gpio-keys/input0";
844b4e66e7dSGuenter Roeck input->dev.parent = dev;
845173bdd74SShubhrajyoti D input->open = gpio_keys_open;
846173bdd74SShubhrajyoti D input->close = gpio_keys_close;
84778a56aabSPhil Blundell
84878a56aabSPhil Blundell input->id.bustype = BUS_HOST;
84978a56aabSPhil Blundell input->id.vendor = 0x0001;
85078a56aabSPhil Blundell input->id.product = 0x0001;
85178a56aabSPhil Blundell input->id.version = 0x0100;
85278a56aabSPhil Blundell
85383e4947aSHans de Goede input->keycode = ddata->keymap;
85483e4947aSHans de Goede input->keycodesize = sizeof(ddata->keymap[0]);
85583e4947aSHans de Goede input->keycodemax = pdata->nbuttons;
85683e4947aSHans de Goede
857b67b4b11SDominic Curran /* Enable auto repeat feature of Linux input subsystem */
858b67b4b11SDominic Curran if (pdata->rep)
859b67b4b11SDominic Curran __set_bit(EV_REP, input->evbit);
860b67b4b11SDominic Curran
86178a56aabSPhil Blundell for (i = 0; i < pdata->nbuttons; i++) {
862d9080921SDmitry Torokhov const struct gpio_keys_button *button = &pdata->buttons[i];
86378a56aabSPhil Blundell
864700a38b2SDmitry Torokhov if (!dev_get_platdata(dev)) {
865b4e66e7dSGuenter Roeck child = device_get_next_child_node(dev, child);
866700a38b2SDmitry Torokhov if (!child) {
867b4e66e7dSGuenter Roeck dev_err(dev,
868700a38b2SDmitry Torokhov "missing child device node for entry %d\n",
869700a38b2SDmitry Torokhov i);
870700a38b2SDmitry Torokhov return -EINVAL;
871700a38b2SDmitry Torokhov }
872700a38b2SDmitry Torokhov }
873700a38b2SDmitry Torokhov
87483e4947aSHans de Goede error = gpio_keys_setup_key(pdev, input, ddata,
87583e4947aSHans de Goede button, i, child);
876700a38b2SDmitry Torokhov if (error) {
877700a38b2SDmitry Torokhov fwnode_handle_put(child);
87827245519SAlexander Shiyan return error;
879700a38b2SDmitry Torokhov }
88084767d00SRoman Moravcik
881e15b0213SAnti Sullin if (button->wakeup)
882e15b0213SAnti Sullin wakeup = 1;
88378a56aabSPhil Blundell }
88478a56aabSPhil Blundell
885700a38b2SDmitry Torokhov fwnode_handle_put(child);
886700a38b2SDmitry Torokhov
88778a56aabSPhil Blundell error = input_register_device(input);
88878a56aabSPhil Blundell if (error) {
8899e3af04fSMika Westerberg dev_err(dev, "Unable to register input device, error: %d\n",
8909e3af04fSMika Westerberg error);
89178a56aabSPhil Blundell return error;
89278a56aabSPhil Blundell }
89378a56aabSPhil Blundell
8943184125eSDmitry Torokhov device_init_wakeup(dev, wakeup);
8959e3af04fSMika Westerberg
89678a56aabSPhil Blundell return 0;
89778a56aabSPhil Blundell }
89878a56aabSPhil Blundell
89983fc580dSJeffy Chen static int __maybe_unused
gpio_keys_button_enable_wakeup(struct gpio_button_data * bdata)90083fc580dSJeffy Chen gpio_keys_button_enable_wakeup(struct gpio_button_data *bdata)
90183fc580dSJeffy Chen {
90283fc580dSJeffy Chen int error;
90383fc580dSJeffy Chen
90483fc580dSJeffy Chen error = enable_irq_wake(bdata->irq);
90583fc580dSJeffy Chen if (error) {
90683fc580dSJeffy Chen dev_err(bdata->input->dev.parent,
90783fc580dSJeffy Chen "failed to configure IRQ %d as wakeup source: %d\n",
90883fc580dSJeffy Chen bdata->irq, error);
90983fc580dSJeffy Chen return error;
91083fc580dSJeffy Chen }
91183fc580dSJeffy Chen
91283fc580dSJeffy Chen if (bdata->wakeup_trigger_type) {
91383fc580dSJeffy Chen error = irq_set_irq_type(bdata->irq,
91483fc580dSJeffy Chen bdata->wakeup_trigger_type);
91583fc580dSJeffy Chen if (error) {
91683fc580dSJeffy Chen dev_err(bdata->input->dev.parent,
91783fc580dSJeffy Chen "failed to set wakeup trigger %08x for IRQ %d: %d\n",
91883fc580dSJeffy Chen bdata->wakeup_trigger_type, bdata->irq, error);
91983fc580dSJeffy Chen disable_irq_wake(bdata->irq);
92083fc580dSJeffy Chen return error;
92183fc580dSJeffy Chen }
92283fc580dSJeffy Chen }
92383fc580dSJeffy Chen
92483fc580dSJeffy Chen return 0;
92583fc580dSJeffy Chen }
92683fc580dSJeffy Chen
92783fc580dSJeffy Chen static void __maybe_unused
gpio_keys_button_disable_wakeup(struct gpio_button_data * bdata)92883fc580dSJeffy Chen gpio_keys_button_disable_wakeup(struct gpio_button_data *bdata)
92983fc580dSJeffy Chen {
93083fc580dSJeffy Chen int error;
93183fc580dSJeffy Chen
93283fc580dSJeffy Chen /*
93383fc580dSJeffy Chen * The trigger type is always both edges for gpio-based keys and we do
93483fc580dSJeffy Chen * not support changing wakeup trigger for interrupt-based keys.
93583fc580dSJeffy Chen */
93683fc580dSJeffy Chen if (bdata->wakeup_trigger_type) {
93783fc580dSJeffy Chen error = irq_set_irq_type(bdata->irq, IRQ_TYPE_EDGE_BOTH);
93883fc580dSJeffy Chen if (error)
93983fc580dSJeffy Chen dev_warn(bdata->input->dev.parent,
94083fc580dSJeffy Chen "failed to restore interrupt trigger for IRQ %d: %d\n",
94183fc580dSJeffy Chen bdata->irq, error);
94283fc580dSJeffy Chen }
94383fc580dSJeffy Chen
94483fc580dSJeffy Chen error = disable_irq_wake(bdata->irq);
94583fc580dSJeffy Chen if (error)
94683fc580dSJeffy Chen dev_warn(bdata->input->dev.parent,
94783fc580dSJeffy Chen "failed to disable IRQ %d as wake source: %d\n",
94883fc580dSJeffy Chen bdata->irq, error);
94983fc580dSJeffy Chen }
95083fc580dSJeffy Chen
95183fc580dSJeffy Chen static int __maybe_unused
gpio_keys_enable_wakeup(struct gpio_keys_drvdata * ddata)95283fc580dSJeffy Chen gpio_keys_enable_wakeup(struct gpio_keys_drvdata *ddata)
95383fc580dSJeffy Chen {
95483fc580dSJeffy Chen struct gpio_button_data *bdata;
95583fc580dSJeffy Chen int error;
95683fc580dSJeffy Chen int i;
95783fc580dSJeffy Chen
95883fc580dSJeffy Chen for (i = 0; i < ddata->pdata->nbuttons; i++) {
95983fc580dSJeffy Chen bdata = &ddata->data[i];
96083fc580dSJeffy Chen if (bdata->button->wakeup) {
96183fc580dSJeffy Chen error = gpio_keys_button_enable_wakeup(bdata);
96283fc580dSJeffy Chen if (error)
96383fc580dSJeffy Chen goto err_out;
96483fc580dSJeffy Chen }
96583fc580dSJeffy Chen bdata->suspended = true;
96683fc580dSJeffy Chen }
96783fc580dSJeffy Chen
96883fc580dSJeffy Chen return 0;
96983fc580dSJeffy Chen
97083fc580dSJeffy Chen err_out:
97183fc580dSJeffy Chen while (i--) {
97283fc580dSJeffy Chen bdata = &ddata->data[i];
97383fc580dSJeffy Chen if (bdata->button->wakeup)
97483fc580dSJeffy Chen gpio_keys_button_disable_wakeup(bdata);
97583fc580dSJeffy Chen bdata->suspended = false;
97683fc580dSJeffy Chen }
97783fc580dSJeffy Chen
97883fc580dSJeffy Chen return error;
97983fc580dSJeffy Chen }
98083fc580dSJeffy Chen
98183fc580dSJeffy Chen static void __maybe_unused
gpio_keys_disable_wakeup(struct gpio_keys_drvdata * ddata)98283fc580dSJeffy Chen gpio_keys_disable_wakeup(struct gpio_keys_drvdata *ddata)
98383fc580dSJeffy Chen {
98483fc580dSJeffy Chen struct gpio_button_data *bdata;
98583fc580dSJeffy Chen int i;
98683fc580dSJeffy Chen
98783fc580dSJeffy Chen for (i = 0; i < ddata->pdata->nbuttons; i++) {
98883fc580dSJeffy Chen bdata = &ddata->data[i];
98983fc580dSJeffy Chen bdata->suspended = false;
99083fc580dSJeffy Chen if (irqd_is_wakeup_set(irq_get_irq_data(bdata->irq)))
99183fc580dSJeffy Chen gpio_keys_button_disable_wakeup(bdata);
99283fc580dSJeffy Chen }
99383fc580dSJeffy Chen }
99483fc580dSJeffy Chen
gpio_keys_suspend(struct device * dev)995ba4de5d9SJonathan Cameron static int gpio_keys_suspend(struct device *dev)
996e15b0213SAnti Sullin {
997fd05d089SDavid Jander struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
998dda19a92SJonas Aaberg struct input_dev *input = ddata->input;
99983fc580dSJeffy Chen int error;
1000e15b0213SAnti Sullin
1001fd05d089SDavid Jander if (device_may_wakeup(dev)) {
100283fc580dSJeffy Chen error = gpio_keys_enable_wakeup(ddata);
100383fc580dSJeffy Chen if (error)
100483fc580dSJeffy Chen return error;
1005dda19a92SJonas Aaberg } else {
1006dda19a92SJonas Aaberg mutex_lock(&input->mutex);
1007d69f0a43SAndrzej Pietrasiewicz if (input_device_enabled(input))
1008dda19a92SJonas Aaberg gpio_keys_close(input);
1009dda19a92SJonas Aaberg mutex_unlock(&input->mutex);
1010e15b0213SAnti Sullin }
1011e15b0213SAnti Sullin
1012e15b0213SAnti Sullin return 0;
1013e15b0213SAnti Sullin }
1014e15b0213SAnti Sullin
gpio_keys_resume(struct device * dev)1015ba4de5d9SJonathan Cameron static int gpio_keys_resume(struct device *dev)
1016e15b0213SAnti Sullin {
1017fd05d089SDavid Jander struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
1018dda19a92SJonas Aaberg struct input_dev *input = ddata->input;
1019dda19a92SJonas Aaberg int error = 0;
1020e15b0213SAnti Sullin
1021dda19a92SJonas Aaberg if (device_may_wakeup(dev)) {
102283fc580dSJeffy Chen gpio_keys_disable_wakeup(ddata);
1023dda19a92SJonas Aaberg } else {
1024dda19a92SJonas Aaberg mutex_lock(&input->mutex);
1025d69f0a43SAndrzej Pietrasiewicz if (input_device_enabled(input))
1026dda19a92SJonas Aaberg error = gpio_keys_open(input);
1027dda19a92SJonas Aaberg mutex_unlock(&input->mutex);
1028dda19a92SJonas Aaberg }
1029dda19a92SJonas Aaberg
1030dda19a92SJonas Aaberg if (error)
1031dda19a92SJonas Aaberg return error;
10325b76d7b4SDmitry Torokhov
10335b76d7b4SDmitry Torokhov gpio_keys_report_state(ddata);
1034e15b0213SAnti Sullin return 0;
1035e15b0213SAnti Sullin }
1036e15b0213SAnti Sullin
1037ba4de5d9SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
1038bdda8216SDmitry Torokhov
gpio_keys_shutdown(struct platform_device * pdev)1039a5c5e50cSFlorian Fainelli static void gpio_keys_shutdown(struct platform_device *pdev)
1040a5c5e50cSFlorian Fainelli {
1041a5c5e50cSFlorian Fainelli int ret;
1042a5c5e50cSFlorian Fainelli
1043a5c5e50cSFlorian Fainelli ret = gpio_keys_suspend(&pdev->dev);
1044a5c5e50cSFlorian Fainelli if (ret)
1045a5c5e50cSFlorian Fainelli dev_err(&pdev->dev, "failed to shutdown\n");
1046a5c5e50cSFlorian Fainelli }
1047a5c5e50cSFlorian Fainelli
10489b07044cSUwe Kleine-König static struct platform_driver gpio_keys_device_driver = {
104978a56aabSPhil Blundell .probe = gpio_keys_probe,
1050a5c5e50cSFlorian Fainelli .shutdown = gpio_keys_shutdown,
105178a56aabSPhil Blundell .driver = {
105278a56aabSPhil Blundell .name = "gpio-keys",
1053ba4de5d9SJonathan Cameron .pm = pm_sleep_ptr(&gpio_keys_pm_ops),
1054700a38b2SDmitry Torokhov .of_match_table = gpio_keys_of_match,
1055cf1b2a20SGreg Kroah-Hartman .dev_groups = gpio_keys_groups,
105678a56aabSPhil Blundell }
105778a56aabSPhil Blundell };
105878a56aabSPhil Blundell
gpio_keys_init(void)105978a56aabSPhil Blundell static int __init gpio_keys_init(void)
106078a56aabSPhil Blundell {
106178a56aabSPhil Blundell return platform_driver_register(&gpio_keys_device_driver);
106278a56aabSPhil Blundell }
106378a56aabSPhil Blundell
gpio_keys_exit(void)106478a56aabSPhil Blundell static void __exit gpio_keys_exit(void)
106578a56aabSPhil Blundell {
106678a56aabSPhil Blundell platform_driver_unregister(&gpio_keys_device_driver);
106778a56aabSPhil Blundell }
106878a56aabSPhil Blundell
1069b2330205SDavid Jander late_initcall(gpio_keys_init);
107078a56aabSPhil Blundell module_exit(gpio_keys_exit);
107178a56aabSPhil Blundell
107278a56aabSPhil Blundell MODULE_LICENSE("GPL");
107378a56aabSPhil Blundell MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
10747e2ecdf4SDavid Jander MODULE_DESCRIPTION("Keyboard driver for GPIOs");
1075d7b5247bSKay Sievers MODULE_ALIAS("platform:gpio-keys");
1076