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 */ 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 */ 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 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); 1342531fdbfSDmitry Torokhov 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 */ 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 */ 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 */ 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 */ 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 250*08a6df09SChristophe 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 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 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 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 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 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 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) { 45983e4947aSHans de Goede input_event(input, EV_KEY, *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 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 48183e4947aSHans de Goede input_event(input, EV_KEY, *bdata->code, 1); 482d8ee4a1cSLaxman Dewangan input_sync(input); 483d8ee4a1cSLaxman Dewangan 4848ed92556SDmitry Torokhov if (!bdata->release_delay) { 48583e4947aSHans de Goede input_event(input, EV_KEY, *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 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); 526700a38b2SDmitry Torokhov if (error == -ENOENT) { 527700a38b2SDmitry Torokhov /* 528700a38b2SDmitry Torokhov * GPIO is optional, we may be dealing with 529700a38b2SDmitry Torokhov * purely interrupt-driven setup. 530700a38b2SDmitry Torokhov */ 531700a38b2SDmitry Torokhov bdata->gpiod = NULL; 532700a38b2SDmitry Torokhov } else { 533700a38b2SDmitry Torokhov if (error != -EPROBE_DEFER) 534700a38b2SDmitry Torokhov dev_err(dev, "failed to get gpio: %d\n", 535700a38b2SDmitry Torokhov error); 536700a38b2SDmitry Torokhov return error; 537700a38b2SDmitry Torokhov } 538700a38b2SDmitry Torokhov } 539700a38b2SDmitry Torokhov } else if (gpio_is_valid(button->gpio)) { 5405feeca3cSGeert Uytterhoeven /* 5415feeca3cSGeert Uytterhoeven * Legacy GPIO number, so request the GPIO here and 5425feeca3cSGeert Uytterhoeven * convert it to descriptor. 5435feeca3cSGeert Uytterhoeven */ 5445feeca3cSGeert Uytterhoeven unsigned flags = GPIOF_IN; 545bc8f1eafSBen Dooks 5465feeca3cSGeert Uytterhoeven if (button->active_low) 5475feeca3cSGeert Uytterhoeven flags |= GPIOF_ACTIVE_LOW; 5485feeca3cSGeert Uytterhoeven 549b4e66e7dSGuenter Roeck error = devm_gpio_request_one(dev, button->gpio, flags, desc); 550bc8f1eafSBen Dooks if (error < 0) { 551d8ee4a1cSLaxman Dewangan dev_err(dev, "Failed to request GPIO %d, error %d\n", 552bc8f1eafSBen Dooks button->gpio, error); 553d8ee4a1cSLaxman Dewangan return error; 554bc8f1eafSBen Dooks } 555bc8f1eafSBen Dooks 5565feeca3cSGeert Uytterhoeven bdata->gpiod = gpio_to_desc(button->gpio); 5575feeca3cSGeert Uytterhoeven if (!bdata->gpiod) 5585feeca3cSGeert Uytterhoeven return -EINVAL; 559700a38b2SDmitry Torokhov } 5605feeca3cSGeert Uytterhoeven 561700a38b2SDmitry Torokhov if (bdata->gpiod) { 56283fc580dSJeffy Chen bool active_low = gpiod_is_active_low(bdata->gpiod); 56383fc580dSJeffy Chen 56428ed684fSGrazvydas Ignotas if (button->debounce_interval) { 5655feeca3cSGeert Uytterhoeven error = gpiod_set_debounce(bdata->gpiod, 56628ed684fSGrazvydas Ignotas button->debounce_interval * 1000); 56728ed684fSGrazvydas Ignotas /* use timer if gpiolib doesn't provide debounce */ 56828ed684fSGrazvydas Ignotas if (error < 0) 5698ed92556SDmitry Torokhov bdata->software_debounce = 570d8ee4a1cSLaxman Dewangan button->debounce_interval; 571c9efb0baSPaul Cercueil 572c9efb0baSPaul Cercueil /* 573c9efb0baSPaul Cercueil * If reading the GPIO won't sleep, we can use a 574c9efb0baSPaul Cercueil * hrtimer instead of a standard timer for the software 575c9efb0baSPaul Cercueil * debounce, to reduce the latency as much as possible. 576c9efb0baSPaul Cercueil */ 577c9efb0baSPaul Cercueil bdata->debounce_use_hrtimer = 578c9efb0baSPaul Cercueil !gpiod_cansleep(bdata->gpiod); 57928ed684fSGrazvydas Ignotas } 58028ed684fSGrazvydas Ignotas 58197d86e07SDmitry Torokhov if (button->irq) { 58297d86e07SDmitry Torokhov bdata->irq = button->irq; 58397d86e07SDmitry Torokhov } else { 5845feeca3cSGeert Uytterhoeven irq = gpiod_to_irq(bdata->gpiod); 585bc8f1eafSBen Dooks if (irq < 0) { 586bc8f1eafSBen Dooks error = irq; 587d8ee4a1cSLaxman Dewangan dev_err(dev, 588d8ee4a1cSLaxman Dewangan "Unable to get irq number for GPIO %d, error %d\n", 589bc8f1eafSBen Dooks button->gpio, error); 59027245519SAlexander Shiyan return error; 591d8ee4a1cSLaxman Dewangan } 592d8ee4a1cSLaxman Dewangan bdata->irq = irq; 59397d86e07SDmitry Torokhov } 594d8ee4a1cSLaxman Dewangan 5958ed92556SDmitry Torokhov INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func); 596d8ee4a1cSLaxman Dewangan 597c9efb0baSPaul Cercueil hrtimer_init(&bdata->debounce_timer, 598c9efb0baSPaul Cercueil CLOCK_REALTIME, HRTIMER_MODE_REL); 599c9efb0baSPaul Cercueil bdata->debounce_timer.function = gpio_keys_debounce_timer; 600c9efb0baSPaul Cercueil 601d8ee4a1cSLaxman Dewangan isr = gpio_keys_gpio_isr; 602d8ee4a1cSLaxman Dewangan irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; 603d8ee4a1cSLaxman Dewangan 60483fc580dSJeffy Chen switch (button->wakeup_event_action) { 60583fc580dSJeffy Chen case EV_ACT_ASSERTED: 60683fc580dSJeffy Chen bdata->wakeup_trigger_type = active_low ? 60783fc580dSJeffy Chen IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING; 60883fc580dSJeffy Chen break; 60983fc580dSJeffy Chen case EV_ACT_DEASSERTED: 61083fc580dSJeffy Chen bdata->wakeup_trigger_type = active_low ? 61183fc580dSJeffy Chen IRQ_TYPE_EDGE_RISING : IRQ_TYPE_EDGE_FALLING; 61283fc580dSJeffy Chen break; 61383fc580dSJeffy Chen case EV_ACT_ANY: 61483fc580dSJeffy Chen default: 61583fc580dSJeffy Chen /* 61683fc580dSJeffy Chen * For other cases, we are OK letting suspend/resume 61783fc580dSJeffy Chen * not reconfigure the trigger type. 61883fc580dSJeffy Chen */ 61983fc580dSJeffy Chen break; 62083fc580dSJeffy Chen } 621d8ee4a1cSLaxman Dewangan } else { 622d8ee4a1cSLaxman Dewangan if (!button->irq) { 623700a38b2SDmitry Torokhov dev_err(dev, "Found button without gpio or irq\n"); 624d8ee4a1cSLaxman Dewangan return -EINVAL; 625d8ee4a1cSLaxman Dewangan } 626700a38b2SDmitry Torokhov 627d8ee4a1cSLaxman Dewangan bdata->irq = button->irq; 628d8ee4a1cSLaxman Dewangan 629d8ee4a1cSLaxman Dewangan if (button->type && button->type != EV_KEY) { 630d8ee4a1cSLaxman Dewangan dev_err(dev, "Only EV_KEY allowed for IRQ buttons.\n"); 631d8ee4a1cSLaxman Dewangan return -EINVAL; 632bc8f1eafSBen Dooks } 633bc8f1eafSBen Dooks 6348ed92556SDmitry Torokhov bdata->release_delay = button->debounce_interval; 635019002f2SPaul Cercueil hrtimer_init(&bdata->release_timer, 636019002f2SPaul Cercueil CLOCK_REALTIME, HRTIMER_MODE_REL_HARD); 637019002f2SPaul Cercueil bdata->release_timer.function = gpio_keys_irq_timer; 638d8ee4a1cSLaxman Dewangan 639d8ee4a1cSLaxman Dewangan isr = gpio_keys_irq_isr; 640d8ee4a1cSLaxman Dewangan irqflags = 0; 64183fc580dSJeffy Chen 64283fc580dSJeffy Chen /* 64383fc580dSJeffy Chen * For IRQ buttons, there is no interrupt for release. 64483fc580dSJeffy Chen * So we don't need to reconfigure the trigger type for wakeup. 64583fc580dSJeffy Chen */ 646d8ee4a1cSLaxman Dewangan } 647d8ee4a1cSLaxman Dewangan 64883e4947aSHans de Goede bdata->code = &ddata->keymap[idx]; 64983e4947aSHans de Goede *bdata->code = button->code; 65083e4947aSHans de Goede input_set_capability(input, button->type ?: EV_KEY, *bdata->code); 651d8ee4a1cSLaxman Dewangan 6529e3af04fSMika Westerberg /* 6538ed92556SDmitry Torokhov * Install custom action to cancel release timer and 65427245519SAlexander Shiyan * workqueue item. 65527245519SAlexander Shiyan */ 656b4e66e7dSGuenter Roeck error = devm_add_action(dev, gpio_keys_quiesce_key, bdata); 65727245519SAlexander Shiyan if (error) { 658b4e66e7dSGuenter Roeck dev_err(dev, "failed to register quiesce action, error: %d\n", 65927245519SAlexander Shiyan error); 66027245519SAlexander Shiyan return error; 66127245519SAlexander Shiyan } 66227245519SAlexander Shiyan 66327245519SAlexander Shiyan /* 6649e3af04fSMika Westerberg * If platform has specified that the button can be disabled, 6659e3af04fSMika Westerberg * we don't want it to share the interrupt line. 6669e3af04fSMika Westerberg */ 6679e3af04fSMika Westerberg if (!button->can_disable) 6689e3af04fSMika Westerberg irqflags |= IRQF_SHARED; 6699e3af04fSMika Westerberg 670b4e66e7dSGuenter Roeck error = devm_request_any_context_irq(dev, bdata->irq, isr, irqflags, 671b4e66e7dSGuenter Roeck desc, bdata); 67294a8cab8SPhilippe Langlais if (error < 0) { 673bc8f1eafSBen Dooks dev_err(dev, "Unable to claim irq %d; error %d\n", 674d8ee4a1cSLaxman Dewangan bdata->irq, error); 67527245519SAlexander Shiyan return error; 676bc8f1eafSBen Dooks } 677bc8f1eafSBen Dooks 678bc8f1eafSBen Dooks return 0; 679bc8f1eafSBen Dooks } 680bc8f1eafSBen Dooks 6815b76d7b4SDmitry Torokhov static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata) 6825b76d7b4SDmitry Torokhov { 6835b76d7b4SDmitry Torokhov struct input_dev *input = ddata->input; 6845b76d7b4SDmitry Torokhov int i; 6855b76d7b4SDmitry Torokhov 6865b76d7b4SDmitry Torokhov for (i = 0; i < ddata->pdata->nbuttons; i++) { 6875b76d7b4SDmitry Torokhov struct gpio_button_data *bdata = &ddata->data[i]; 6885feeca3cSGeert Uytterhoeven if (bdata->gpiod) 6895b76d7b4SDmitry Torokhov gpio_keys_gpio_report_event(bdata); 6905b76d7b4SDmitry Torokhov } 6915b76d7b4SDmitry Torokhov input_sync(input); 6925b76d7b4SDmitry Torokhov } 6935b76d7b4SDmitry Torokhov 694173bdd74SShubhrajyoti D static int gpio_keys_open(struct input_dev *input) 695173bdd74SShubhrajyoti D { 696173bdd74SShubhrajyoti D struct gpio_keys_drvdata *ddata = input_get_drvdata(input); 697219edc71SAlexandre Pereira da Silva const struct gpio_keys_platform_data *pdata = ddata->pdata; 6985b76d7b4SDmitry Torokhov int error; 699173bdd74SShubhrajyoti D 7005b76d7b4SDmitry Torokhov if (pdata->enable) { 7015b76d7b4SDmitry Torokhov error = pdata->enable(input->dev.parent); 7025b76d7b4SDmitry Torokhov if (error) 7035b76d7b4SDmitry Torokhov return error; 7045b76d7b4SDmitry Torokhov } 7055b76d7b4SDmitry Torokhov 7065b76d7b4SDmitry Torokhov /* Report current state of buttons that are connected to GPIOs */ 7075b76d7b4SDmitry Torokhov gpio_keys_report_state(ddata); 7085b76d7b4SDmitry Torokhov 7095b76d7b4SDmitry Torokhov return 0; 710173bdd74SShubhrajyoti D } 711173bdd74SShubhrajyoti D 712173bdd74SShubhrajyoti D static void gpio_keys_close(struct input_dev *input) 713173bdd74SShubhrajyoti D { 714173bdd74SShubhrajyoti D struct gpio_keys_drvdata *ddata = input_get_drvdata(input); 715219edc71SAlexandre Pereira da Silva const struct gpio_keys_platform_data *pdata = ddata->pdata; 716173bdd74SShubhrajyoti D 717219edc71SAlexandre Pereira da Silva if (pdata->disable) 718219edc71SAlexandre Pereira da Silva pdata->disable(input->dev.parent); 719173bdd74SShubhrajyoti D } 720173bdd74SShubhrajyoti D 721fd05d089SDavid Jander /* 722fd05d089SDavid Jander * Handlers for alternative sources of platform_data 723fd05d089SDavid Jander */ 724219edc71SAlexandre Pereira da Silva 725fd05d089SDavid Jander /* 726700a38b2SDmitry Torokhov * Translate properties into platform_data 727fd05d089SDavid Jander */ 7285298cc4cSBill Pemberton static struct gpio_keys_platform_data * 729219edc71SAlexandre Pereira da Silva gpio_keys_get_devtree_pdata(struct device *dev) 730fd05d089SDavid Jander { 731219edc71SAlexandre Pereira da Silva struct gpio_keys_platform_data *pdata; 732219edc71SAlexandre Pereira da Silva struct gpio_keys_button *button; 733700a38b2SDmitry Torokhov struct fwnode_handle *child; 734219edc71SAlexandre Pereira da Silva int nbuttons; 735fd05d089SDavid Jander 736700a38b2SDmitry Torokhov nbuttons = device_get_child_node_count(dev); 7375d422f2eSAndy Shevchenko if (nbuttons == 0) 7385d422f2eSAndy Shevchenko return ERR_PTR(-ENODEV); 739219edc71SAlexandre Pereira da Silva 7405d422f2eSAndy Shevchenko pdata = devm_kzalloc(dev, 7415d422f2eSAndy Shevchenko sizeof(*pdata) + nbuttons * sizeof(*button), 742219edc71SAlexandre Pereira da Silva GFP_KERNEL); 7435d422f2eSAndy Shevchenko if (!pdata) 7445d422f2eSAndy Shevchenko return ERR_PTR(-ENOMEM); 745219edc71SAlexandre Pereira da Silva 7460f78ba96SDmitry Torokhov button = (struct gpio_keys_button *)(pdata + 1); 7470f78ba96SDmitry Torokhov 7480f78ba96SDmitry Torokhov pdata->buttons = button; 749219edc71SAlexandre Pereira da Silva pdata->nbuttons = nbuttons; 750fd05d089SDavid Jander 751700a38b2SDmitry Torokhov pdata->rep = device_property_read_bool(dev, "autorepeat"); 752fd05d089SDavid Jander 753700a38b2SDmitry Torokhov device_property_read_string(dev, "label", &pdata->name); 754c4dc5f8cSLaxman Dewangan 755700a38b2SDmitry Torokhov device_for_each_child_node(dev, child) { 756700a38b2SDmitry Torokhov if (is_of_node(child)) 757700a38b2SDmitry Torokhov button->irq = 758700a38b2SDmitry Torokhov irq_of_parse_and_map(to_of_node(child), 0); 759fd05d089SDavid Jander 760700a38b2SDmitry Torokhov if (fwnode_property_read_u32(child, "linux,code", 761700a38b2SDmitry Torokhov &button->code)) { 762700a38b2SDmitry Torokhov dev_err(dev, "Button without keycode\n"); 763700a38b2SDmitry Torokhov fwnode_handle_put(child); 76497d86e07SDmitry Torokhov return ERR_PTR(-EINVAL); 76597d86e07SDmitry Torokhov } 766fd05d089SDavid Jander 767700a38b2SDmitry Torokhov fwnode_property_read_string(child, "label", &button->desc); 768fd05d089SDavid Jander 769700a38b2SDmitry Torokhov if (fwnode_property_read_u32(child, "linux,input-type", 770700a38b2SDmitry Torokhov &button->type)) 771219edc71SAlexandre Pereira da Silva button->type = EV_KEY; 772fd05d089SDavid Jander 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 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 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 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 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 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 995f9645f22SDmitry Torokhov static int __maybe_unused 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 1015f9645f22SDmitry Torokhov static int __maybe_unused 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 1037bdda8216SDmitry Torokhov static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume); 1038bdda8216SDmitry Torokhov 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", 1053ae78e0e0SMike Rapoport .pm = &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 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 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