xref: /openbmc/linux/drivers/input/keyboard/gpio_keys.c (revision 83fc580dcc2f0f36114477c4ac7adbe5c32329a3)
178a56aabSPhil Blundell /*
278a56aabSPhil Blundell  * Driver for keys on GPIO lines capable of generating interrupts.
378a56aabSPhil Blundell  *
478a56aabSPhil Blundell  * Copyright 2005 Phil Blundell
5fd05d089SDavid Jander  * Copyright 2010, 2011 David Jander <david@protonic.nl>
678a56aabSPhil Blundell  *
778a56aabSPhil Blundell  * This program is free software; you can redistribute it and/or modify
878a56aabSPhil Blundell  * it under the terms of the GNU General Public License version 2 as
978a56aabSPhil Blundell  * published by the Free Software Foundation.
1078a56aabSPhil Blundell  */
1178a56aabSPhil Blundell 
1278a56aabSPhil Blundell #include <linux/module.h>
1378a56aabSPhil Blundell 
1478a56aabSPhil Blundell #include <linux/init.h>
1578a56aabSPhil Blundell #include <linux/fs.h>
1678a56aabSPhil Blundell #include <linux/interrupt.h>
1778a56aabSPhil Blundell #include <linux/irq.h>
1878a56aabSPhil Blundell #include <linux/sched.h>
1978a56aabSPhil Blundell #include <linux/pm.h>
205a0e3ad6STejun Heo #include <linux/slab.h>
2178a56aabSPhil Blundell #include <linux/sysctl.h>
2278a56aabSPhil Blundell #include <linux/proc_fs.h>
2378a56aabSPhil Blundell #include <linux/delay.h>
2478a56aabSPhil Blundell #include <linux/platform_device.h>
2578a56aabSPhil Blundell #include <linux/input.h>
2649015beeSDavid Brownell #include <linux/gpio_keys.h>
27da0d03feSJani Nikula #include <linux/workqueue.h>
28111bc59cSBen Dooks #include <linux/gpio.h>
295feeca3cSGeert Uytterhoeven #include <linux/gpio/consumer.h>
30415a4caaSSachin Kamat #include <linux/of.h>
31f2d347ffSAlexander Stein #include <linux/of_irq.h>
32d8ee4a1cSLaxman Dewangan #include <linux/spinlock.h>
33*83fc580dSJeffy Chen #include <dt-bindings/input/gpio-keys.h>
3478a56aabSPhil Blundell 
35a33466e3SDmitry Baryshkov struct gpio_button_data {
36d9080921SDmitry Torokhov 	const struct gpio_keys_button *button;
37a33466e3SDmitry Baryshkov 	struct input_dev *input;
385feeca3cSGeert Uytterhoeven 	struct gpio_desc *gpiod;
398ed92556SDmitry Torokhov 
4083e4947aSHans de Goede 	unsigned short *code;
4183e4947aSHans de Goede 
428ed92556SDmitry Torokhov 	struct timer_list release_timer;
438ed92556SDmitry Torokhov 	unsigned int release_delay;	/* in msecs, for IRQ-only buttons */
448ed92556SDmitry Torokhov 
458ed92556SDmitry Torokhov 	struct delayed_work work;
468ed92556SDmitry Torokhov 	unsigned int software_debounce;	/* in msecs, for GPIO-driven buttons */
478ed92556SDmitry Torokhov 
48d8ee4a1cSLaxman Dewangan 	unsigned int irq;
49*83fc580dSJeffy Chen 	unsigned int wakeup_trigger_type;
50d8ee4a1cSLaxman Dewangan 	spinlock_t lock;
519e3af04fSMika Westerberg 	bool disabled;
52d8ee4a1cSLaxman Dewangan 	bool key_pressed;
530f107573SJoseph Lo 	bool suspended;
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;
61a33466e3SDmitry Baryshkov 	struct gpio_button_data data[0];
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
1148679ee42SDmitry Torokhov  * @input: 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 
1288679ee42SDmitry Torokhov /**
1299e3af04fSMika Westerberg  * gpio_keys_disable_button() - disables given GPIO button
1309e3af04fSMika Westerberg  * @bdata: button data for button to be disabled
1319e3af04fSMika Westerberg  *
1329e3af04fSMika Westerberg  * Disables button pointed by @bdata. This is done by masking
1339e3af04fSMika Westerberg  * IRQ line. After this function is called, button won't generate
1349e3af04fSMika Westerberg  * input events anymore. Note that one can only disable buttons
1359e3af04fSMika Westerberg  * that don't share IRQs.
1369e3af04fSMika Westerberg  *
1379e3af04fSMika Westerberg  * Make sure that @bdata->disable_lock is locked when entering
1389e3af04fSMika Westerberg  * this function to avoid races when concurrent threads are
1399e3af04fSMika Westerberg  * disabling buttons at the same time.
1409e3af04fSMika Westerberg  */
1419e3af04fSMika Westerberg static void gpio_keys_disable_button(struct gpio_button_data *bdata)
1429e3af04fSMika Westerberg {
1439e3af04fSMika Westerberg 	if (!bdata->disabled) {
1449e3af04fSMika Westerberg 		/*
1458ed92556SDmitry Torokhov 		 * Disable IRQ and associated timer/work structure.
1469e3af04fSMika Westerberg 		 */
147d8ee4a1cSLaxman Dewangan 		disable_irq(bdata->irq);
1488ed92556SDmitry Torokhov 
1495feeca3cSGeert Uytterhoeven 		if (bdata->gpiod)
1508ed92556SDmitry Torokhov 			cancel_delayed_work_sync(&bdata->work);
1518ed92556SDmitry Torokhov 		else
1528ed92556SDmitry Torokhov 			del_timer_sync(&bdata->release_timer);
1539e3af04fSMika Westerberg 
1549e3af04fSMika Westerberg 		bdata->disabled = true;
1559e3af04fSMika Westerberg 	}
1569e3af04fSMika Westerberg }
1579e3af04fSMika Westerberg 
1589e3af04fSMika Westerberg /**
1599e3af04fSMika Westerberg  * gpio_keys_enable_button() - enables given GPIO button
1609e3af04fSMika Westerberg  * @bdata: button data for button to be disabled
1619e3af04fSMika Westerberg  *
1629e3af04fSMika Westerberg  * Enables given button pointed by @bdata.
1639e3af04fSMika Westerberg  *
1649e3af04fSMika Westerberg  * Make sure that @bdata->disable_lock is locked when entering
1659e3af04fSMika Westerberg  * this function to avoid races with concurrent threads trying
1669e3af04fSMika Westerberg  * to enable the same button at the same time.
1679e3af04fSMika Westerberg  */
1689e3af04fSMika Westerberg static void gpio_keys_enable_button(struct gpio_button_data *bdata)
1699e3af04fSMika Westerberg {
1709e3af04fSMika Westerberg 	if (bdata->disabled) {
171d8ee4a1cSLaxman Dewangan 		enable_irq(bdata->irq);
1729e3af04fSMika Westerberg 		bdata->disabled = false;
1739e3af04fSMika Westerberg 	}
1749e3af04fSMika Westerberg }
1759e3af04fSMika Westerberg 
1769e3af04fSMika Westerberg /**
1779e3af04fSMika Westerberg  * gpio_keys_attr_show_helper() - fill in stringified bitmap of buttons
1789e3af04fSMika Westerberg  * @ddata: pointer to drvdata
1799e3af04fSMika Westerberg  * @buf: buffer where stringified bitmap is written
1809e3af04fSMika Westerberg  * @type: button type (%EV_KEY, %EV_SW)
1819e3af04fSMika Westerberg  * @only_disabled: does caller want only those buttons that are
1829e3af04fSMika Westerberg  *                 currently disabled or all buttons that can be
1839e3af04fSMika Westerberg  *                 disabled
1849e3af04fSMika Westerberg  *
1859e3af04fSMika Westerberg  * This function writes buttons that can be disabled to @buf. If
1869e3af04fSMika Westerberg  * @only_disabled is true, then @buf contains only those buttons
1879e3af04fSMika Westerberg  * that are currently disabled. Returns 0 on success or negative
1889e3af04fSMika Westerberg  * errno on failure.
1899e3af04fSMika Westerberg  */
1909e3af04fSMika Westerberg static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
1919e3af04fSMika Westerberg 					  char *buf, unsigned int type,
1929e3af04fSMika Westerberg 					  bool only_disabled)
1939e3af04fSMika Westerberg {
1949e3af04fSMika Westerberg 	int n_events = get_n_events_by_type(type);
1959e3af04fSMika Westerberg 	unsigned long *bits;
1969e3af04fSMika Westerberg 	ssize_t ret;
1979e3af04fSMika Westerberg 	int i;
1989e3af04fSMika Westerberg 
1999e3af04fSMika Westerberg 	bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
2009e3af04fSMika Westerberg 	if (!bits)
2019e3af04fSMika Westerberg 		return -ENOMEM;
2029e3af04fSMika Westerberg 
203219edc71SAlexandre Pereira da Silva 	for (i = 0; i < ddata->pdata->nbuttons; i++) {
2049e3af04fSMika Westerberg 		struct gpio_button_data *bdata = &ddata->data[i];
2059e3af04fSMika Westerberg 
2069e3af04fSMika Westerberg 		if (bdata->button->type != type)
2079e3af04fSMika Westerberg 			continue;
2089e3af04fSMika Westerberg 
2099e3af04fSMika Westerberg 		if (only_disabled && !bdata->disabled)
2109e3af04fSMika Westerberg 			continue;
2119e3af04fSMika Westerberg 
21283e4947aSHans de Goede 		__set_bit(*bdata->code, bits);
2139e3af04fSMika Westerberg 	}
2149e3af04fSMika Westerberg 
2150b480037STejun Heo 	ret = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", n_events, bits);
2169e3af04fSMika Westerberg 	buf[ret++] = '\n';
2179e3af04fSMika Westerberg 	buf[ret] = '\0';
2189e3af04fSMika Westerberg 
2199e3af04fSMika Westerberg 	kfree(bits);
2209e3af04fSMika Westerberg 
2219e3af04fSMika Westerberg 	return ret;
2229e3af04fSMika Westerberg }
2239e3af04fSMika Westerberg 
2249e3af04fSMika Westerberg /**
2259e3af04fSMika Westerberg  * gpio_keys_attr_store_helper() - enable/disable buttons based on given bitmap
2269e3af04fSMika Westerberg  * @ddata: pointer to drvdata
2279e3af04fSMika Westerberg  * @buf: buffer from userspace that contains stringified bitmap
2289e3af04fSMika Westerberg  * @type: button type (%EV_KEY, %EV_SW)
2299e3af04fSMika Westerberg  *
2309e3af04fSMika Westerberg  * This function parses stringified bitmap from @buf and disables/enables
231a16ca239SDmitry Torokhov  * GPIO buttons accordingly. Returns 0 on success and negative error
2329e3af04fSMika Westerberg  * on failure.
2339e3af04fSMika Westerberg  */
2349e3af04fSMika Westerberg static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
2359e3af04fSMika Westerberg 					   const char *buf, unsigned int type)
2369e3af04fSMika Westerberg {
2379e3af04fSMika Westerberg 	int n_events = get_n_events_by_type(type);
2388679ee42SDmitry Torokhov 	const unsigned long *bitmap = get_bm_events_by_type(ddata->input, type);
2399e3af04fSMika Westerberg 	unsigned long *bits;
2409e3af04fSMika Westerberg 	ssize_t error;
2419e3af04fSMika Westerberg 	int i;
2429e3af04fSMika Westerberg 
2439e3af04fSMika Westerberg 	bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
2449e3af04fSMika Westerberg 	if (!bits)
2459e3af04fSMika Westerberg 		return -ENOMEM;
2469e3af04fSMika Westerberg 
2479e3af04fSMika Westerberg 	error = bitmap_parselist(buf, bits, n_events);
2489e3af04fSMika Westerberg 	if (error)
2499e3af04fSMika Westerberg 		goto out;
2509e3af04fSMika Westerberg 
2519e3af04fSMika Westerberg 	/* First validate */
2528679ee42SDmitry Torokhov 	if (!bitmap_subset(bits, bitmap, n_events)) {
2538679ee42SDmitry Torokhov 		error = -EINVAL;
2548679ee42SDmitry Torokhov 		goto out;
2558679ee42SDmitry Torokhov 	}
2568679ee42SDmitry Torokhov 
257219edc71SAlexandre Pereira da Silva 	for (i = 0; i < ddata->pdata->nbuttons; i++) {
2589e3af04fSMika Westerberg 		struct gpio_button_data *bdata = &ddata->data[i];
2599e3af04fSMika Westerberg 
2609e3af04fSMika Westerberg 		if (bdata->button->type != type)
2619e3af04fSMika Westerberg 			continue;
2629e3af04fSMika Westerberg 
26383e4947aSHans de Goede 		if (test_bit(*bdata->code, bits) &&
2649e3af04fSMika Westerberg 		    !bdata->button->can_disable) {
2659e3af04fSMika Westerberg 			error = -EINVAL;
2669e3af04fSMika Westerberg 			goto out;
2679e3af04fSMika Westerberg 		}
2689e3af04fSMika Westerberg 	}
2699e3af04fSMika Westerberg 
2709e3af04fSMika Westerberg 	mutex_lock(&ddata->disable_lock);
2719e3af04fSMika Westerberg 
272219edc71SAlexandre Pereira da Silva 	for (i = 0; i < ddata->pdata->nbuttons; i++) {
2739e3af04fSMika Westerberg 		struct gpio_button_data *bdata = &ddata->data[i];
2749e3af04fSMika Westerberg 
2759e3af04fSMika Westerberg 		if (bdata->button->type != type)
2769e3af04fSMika Westerberg 			continue;
2779e3af04fSMika Westerberg 
27883e4947aSHans de Goede 		if (test_bit(*bdata->code, bits))
2799e3af04fSMika Westerberg 			gpio_keys_disable_button(bdata);
2809e3af04fSMika Westerberg 		else
2819e3af04fSMika Westerberg 			gpio_keys_enable_button(bdata);
2829e3af04fSMika Westerberg 	}
2839e3af04fSMika Westerberg 
2849e3af04fSMika Westerberg 	mutex_unlock(&ddata->disable_lock);
2859e3af04fSMika Westerberg 
2869e3af04fSMika Westerberg out:
2879e3af04fSMika Westerberg 	kfree(bits);
2889e3af04fSMika Westerberg 	return error;
2899e3af04fSMika Westerberg }
2909e3af04fSMika Westerberg 
2919e3af04fSMika Westerberg #define ATTR_SHOW_FN(name, type, only_disabled)				\
2929e3af04fSMika Westerberg static ssize_t gpio_keys_show_##name(struct device *dev,		\
2939e3af04fSMika Westerberg 				     struct device_attribute *attr,	\
2949e3af04fSMika Westerberg 				     char *buf)				\
2959e3af04fSMika Westerberg {									\
2969e3af04fSMika Westerberg 	struct platform_device *pdev = to_platform_device(dev);		\
2979e3af04fSMika Westerberg 	struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);	\
2989e3af04fSMika Westerberg 									\
2999e3af04fSMika Westerberg 	return gpio_keys_attr_show_helper(ddata, buf,			\
3009e3af04fSMika Westerberg 					  type, only_disabled);		\
3019e3af04fSMika Westerberg }
3029e3af04fSMika Westerberg 
3039e3af04fSMika Westerberg ATTR_SHOW_FN(keys, EV_KEY, false);
3049e3af04fSMika Westerberg ATTR_SHOW_FN(switches, EV_SW, false);
3059e3af04fSMika Westerberg ATTR_SHOW_FN(disabled_keys, EV_KEY, true);
3069e3af04fSMika Westerberg ATTR_SHOW_FN(disabled_switches, EV_SW, true);
3079e3af04fSMika Westerberg 
3089e3af04fSMika Westerberg /*
3099e3af04fSMika Westerberg  * ATTRIBUTES:
3109e3af04fSMika Westerberg  *
3119e3af04fSMika Westerberg  * /sys/devices/platform/gpio-keys/keys [ro]
3129e3af04fSMika Westerberg  * /sys/devices/platform/gpio-keys/switches [ro]
3139e3af04fSMika Westerberg  */
3149e3af04fSMika Westerberg static DEVICE_ATTR(keys, S_IRUGO, gpio_keys_show_keys, NULL);
3159e3af04fSMika Westerberg static DEVICE_ATTR(switches, S_IRUGO, gpio_keys_show_switches, NULL);
3169e3af04fSMika Westerberg 
3179e3af04fSMika Westerberg #define ATTR_STORE_FN(name, type)					\
3189e3af04fSMika Westerberg static ssize_t gpio_keys_store_##name(struct device *dev,		\
3199e3af04fSMika Westerberg 				      struct device_attribute *attr,	\
3209e3af04fSMika Westerberg 				      const char *buf,			\
3219e3af04fSMika Westerberg 				      size_t count)			\
3229e3af04fSMika Westerberg {									\
3239e3af04fSMika Westerberg 	struct platform_device *pdev = to_platform_device(dev);		\
3249e3af04fSMika Westerberg 	struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);	\
3259e3af04fSMika Westerberg 	ssize_t error;							\
3269e3af04fSMika Westerberg 									\
3279e3af04fSMika Westerberg 	error = gpio_keys_attr_store_helper(ddata, buf, type);		\
3289e3af04fSMika Westerberg 	if (error)							\
3299e3af04fSMika Westerberg 		return error;						\
3309e3af04fSMika Westerberg 									\
3319e3af04fSMika Westerberg 	return count;							\
3329e3af04fSMika Westerberg }
3339e3af04fSMika Westerberg 
3349e3af04fSMika Westerberg ATTR_STORE_FN(disabled_keys, EV_KEY);
3359e3af04fSMika Westerberg ATTR_STORE_FN(disabled_switches, EV_SW);
3369e3af04fSMika Westerberg 
3379e3af04fSMika Westerberg /*
3389e3af04fSMika Westerberg  * ATTRIBUTES:
3399e3af04fSMika Westerberg  *
3409e3af04fSMika Westerberg  * /sys/devices/platform/gpio-keys/disabled_keys [rw]
3419e3af04fSMika Westerberg  * /sys/devices/platform/gpio-keys/disables_switches [rw]
3429e3af04fSMika Westerberg  */
3439e3af04fSMika Westerberg static DEVICE_ATTR(disabled_keys, S_IWUSR | S_IRUGO,
3449e3af04fSMika Westerberg 		   gpio_keys_show_disabled_keys,
3459e3af04fSMika Westerberg 		   gpio_keys_store_disabled_keys);
3469e3af04fSMika Westerberg static DEVICE_ATTR(disabled_switches, S_IWUSR | S_IRUGO,
3479e3af04fSMika Westerberg 		   gpio_keys_show_disabled_switches,
3489e3af04fSMika Westerberg 		   gpio_keys_store_disabled_switches);
3499e3af04fSMika Westerberg 
3509e3af04fSMika Westerberg static struct attribute *gpio_keys_attrs[] = {
3519e3af04fSMika Westerberg 	&dev_attr_keys.attr,
3529e3af04fSMika Westerberg 	&dev_attr_switches.attr,
3539e3af04fSMika Westerberg 	&dev_attr_disabled_keys.attr,
3549e3af04fSMika Westerberg 	&dev_attr_disabled_switches.attr,
3559e3af04fSMika Westerberg 	NULL,
3569e3af04fSMika Westerberg };
3579e3af04fSMika Westerberg 
35821563a7eSArvind Yadav static const struct attribute_group gpio_keys_attr_group = {
3599e3af04fSMika Westerberg 	.attrs = gpio_keys_attrs,
3609e3af04fSMika Westerberg };
3619e3af04fSMika Westerberg 
362d8ee4a1cSLaxman Dewangan static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
36378a56aabSPhil Blundell {
364d9080921SDmitry Torokhov 	const struct gpio_keys_button *button = bdata->button;
365ce25d7e9SUwe Kleine-König 	struct input_dev *input = bdata->input;
36684767d00SRoman Moravcik 	unsigned int type = button->type ?: EV_KEY;
3675feeca3cSGeert Uytterhoeven 	int state;
36884767d00SRoman Moravcik 
3695feeca3cSGeert Uytterhoeven 	state = gpiod_get_value_cansleep(bdata->gpiod);
37077fa0554SBjorn Andersson 	if (state < 0) {
3715feeca3cSGeert Uytterhoeven 		dev_err(input->dev.parent,
3725feeca3cSGeert Uytterhoeven 			"failed to get gpio state: %d\n", state);
37377fa0554SBjorn Andersson 		return;
37477fa0554SBjorn Andersson 	}
37577fa0554SBjorn Andersson 
37692a47674SAlexander Stein 	if (type == EV_ABS) {
37792a47674SAlexander Stein 		if (state)
37892a47674SAlexander Stein 			input_event(input, type, button->code, button->value);
37992a47674SAlexander Stein 	} else {
38083e4947aSHans de Goede 		input_event(input, type, *bdata->code, state);
38192a47674SAlexander Stein 	}
38278a56aabSPhil Blundell 	input_sync(input);
383a33466e3SDmitry Baryshkov }
384a33466e3SDmitry Baryshkov 
385d8ee4a1cSLaxman Dewangan static void gpio_keys_gpio_work_func(struct work_struct *work)
3866ee88d71SDaniel Mack {
3876ee88d71SDaniel Mack 	struct gpio_button_data *bdata =
3888ed92556SDmitry Torokhov 		container_of(work, struct gpio_button_data, work.work);
3896ee88d71SDaniel Mack 
390d8ee4a1cSLaxman Dewangan 	gpio_keys_gpio_report_event(bdata);
3912fba26c6SNeilBrown 
3922fba26c6SNeilBrown 	if (bdata->button->wakeup)
3932fba26c6SNeilBrown 		pm_relax(bdata->input->dev.parent);
3946ee88d71SDaniel Mack }
3956ee88d71SDaniel Mack 
396d8ee4a1cSLaxman Dewangan static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
397a33466e3SDmitry Baryshkov {
39857ffe9d5SUwe Kleine-König 	struct gpio_button_data *bdata = dev_id;
399a33466e3SDmitry Baryshkov 
400d8ee4a1cSLaxman Dewangan 	BUG_ON(irq != bdata->irq);
401a33466e3SDmitry Baryshkov 
4020f107573SJoseph Lo 	if (bdata->button->wakeup) {
4030f107573SJoseph Lo 		const struct gpio_keys_button *button = bdata->button;
4040f107573SJoseph Lo 
4052fba26c6SNeilBrown 		pm_stay_awake(bdata->input->dev.parent);
4060f107573SJoseph Lo 		if (bdata->suspended  &&
4070f107573SJoseph Lo 		    (button->type == 0 || button->type == EV_KEY)) {
4080f107573SJoseph Lo 			/*
4090f107573SJoseph Lo 			 * Simulate wakeup key press in case the key has
4100f107573SJoseph Lo 			 * already released by the time we got interrupt
4110f107573SJoseph Lo 			 * handler to run.
4120f107573SJoseph Lo 			 */
4130f107573SJoseph Lo 			input_report_key(bdata->input, button->code, 1);
4140f107573SJoseph Lo 		}
4150f107573SJoseph Lo 	}
4168ed92556SDmitry Torokhov 
4178ed92556SDmitry Torokhov 	mod_delayed_work(system_wq,
4188ed92556SDmitry Torokhov 			 &bdata->work,
4198ed92556SDmitry Torokhov 			 msecs_to_jiffies(bdata->software_debounce));
420a33466e3SDmitry Baryshkov 
4211164ec1aSDavid Brownell 	return IRQ_HANDLED;
42278a56aabSPhil Blundell }
42378a56aabSPhil Blundell 
42482565a12Sstephen lu static void gpio_keys_irq_timer(struct timer_list *t)
425d8ee4a1cSLaxman Dewangan {
42682565a12Sstephen lu 	struct gpio_button_data *bdata = from_timer(bdata, t, release_timer);
427d8ee4a1cSLaxman Dewangan 	struct input_dev *input = bdata->input;
428d8ee4a1cSLaxman Dewangan 	unsigned long flags;
429d8ee4a1cSLaxman Dewangan 
430d8ee4a1cSLaxman Dewangan 	spin_lock_irqsave(&bdata->lock, flags);
431d8ee4a1cSLaxman Dewangan 	if (bdata->key_pressed) {
43283e4947aSHans de Goede 		input_event(input, EV_KEY, *bdata->code, 0);
433d8ee4a1cSLaxman Dewangan 		input_sync(input);
434d8ee4a1cSLaxman Dewangan 		bdata->key_pressed = false;
435d8ee4a1cSLaxman Dewangan 	}
436d8ee4a1cSLaxman Dewangan 	spin_unlock_irqrestore(&bdata->lock, flags);
437d8ee4a1cSLaxman Dewangan }
438d8ee4a1cSLaxman Dewangan 
439d8ee4a1cSLaxman Dewangan static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
440d8ee4a1cSLaxman Dewangan {
441d8ee4a1cSLaxman Dewangan 	struct gpio_button_data *bdata = dev_id;
442d8ee4a1cSLaxman Dewangan 	struct input_dev *input = bdata->input;
443d8ee4a1cSLaxman Dewangan 	unsigned long flags;
444d8ee4a1cSLaxman Dewangan 
445d8ee4a1cSLaxman Dewangan 	BUG_ON(irq != bdata->irq);
446d8ee4a1cSLaxman Dewangan 
447d8ee4a1cSLaxman Dewangan 	spin_lock_irqsave(&bdata->lock, flags);
448d8ee4a1cSLaxman Dewangan 
449d8ee4a1cSLaxman Dewangan 	if (!bdata->key_pressed) {
4502fba26c6SNeilBrown 		if (bdata->button->wakeup)
4512fba26c6SNeilBrown 			pm_wakeup_event(bdata->input->dev.parent, 0);
4522fba26c6SNeilBrown 
45383e4947aSHans de Goede 		input_event(input, EV_KEY, *bdata->code, 1);
454d8ee4a1cSLaxman Dewangan 		input_sync(input);
455d8ee4a1cSLaxman Dewangan 
4568ed92556SDmitry Torokhov 		if (!bdata->release_delay) {
45783e4947aSHans de Goede 			input_event(input, EV_KEY, *bdata->code, 0);
458d8ee4a1cSLaxman Dewangan 			input_sync(input);
459d8ee4a1cSLaxman Dewangan 			goto out;
460d8ee4a1cSLaxman Dewangan 		}
461d8ee4a1cSLaxman Dewangan 
462d8ee4a1cSLaxman Dewangan 		bdata->key_pressed = true;
463d8ee4a1cSLaxman Dewangan 	}
464d8ee4a1cSLaxman Dewangan 
4658ed92556SDmitry Torokhov 	if (bdata->release_delay)
4668ed92556SDmitry Torokhov 		mod_timer(&bdata->release_timer,
4678ed92556SDmitry Torokhov 			jiffies + msecs_to_jiffies(bdata->release_delay));
468d8ee4a1cSLaxman Dewangan out:
469d8ee4a1cSLaxman Dewangan 	spin_unlock_irqrestore(&bdata->lock, flags);
470d8ee4a1cSLaxman Dewangan 	return IRQ_HANDLED;
471d8ee4a1cSLaxman Dewangan }
472d8ee4a1cSLaxman Dewangan 
47327245519SAlexander Shiyan static void gpio_keys_quiesce_key(void *data)
47427245519SAlexander Shiyan {
47527245519SAlexander Shiyan 	struct gpio_button_data *bdata = data;
47627245519SAlexander Shiyan 
4775feeca3cSGeert Uytterhoeven 	if (bdata->gpiod)
4788ed92556SDmitry Torokhov 		cancel_delayed_work_sync(&bdata->work);
4798ed92556SDmitry Torokhov 	else
4808ed92556SDmitry Torokhov 		del_timer_sync(&bdata->release_timer);
48127245519SAlexander Shiyan }
48227245519SAlexander Shiyan 
4835298cc4cSBill Pemberton static int gpio_keys_setup_key(struct platform_device *pdev,
484d9080921SDmitry Torokhov 				struct input_dev *input,
48583e4947aSHans de Goede 				struct gpio_keys_drvdata *ddata,
486700a38b2SDmitry Torokhov 				const struct gpio_keys_button *button,
48783e4947aSHans de Goede 				int idx,
488700a38b2SDmitry Torokhov 				struct fwnode_handle *child)
489bc8f1eafSBen Dooks {
49092a47674SAlexander Stein 	const char *desc = button->desc ? button->desc : "gpio_keys";
4919e3af04fSMika Westerberg 	struct device *dev = &pdev->dev;
49283e4947aSHans de Goede 	struct gpio_button_data *bdata = &ddata->data[idx];
493d8ee4a1cSLaxman Dewangan 	irq_handler_t isr;
4949e3af04fSMika Westerberg 	unsigned long irqflags;
49527245519SAlexander Shiyan 	int irq;
49627245519SAlexander Shiyan 	int error;
497bc8f1eafSBen Dooks 
498d9080921SDmitry Torokhov 	bdata->input = input;
499d9080921SDmitry Torokhov 	bdata->button = button;
500d8ee4a1cSLaxman Dewangan 	spin_lock_init(&bdata->lock);
501d8ee4a1cSLaxman Dewangan 
502700a38b2SDmitry Torokhov 	if (child) {
5034b094797SBoris Brezillon 		bdata->gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL,
5044b094797SBoris Brezillon 								child,
5054b094797SBoris Brezillon 								GPIOD_IN,
5064b094797SBoris Brezillon 								desc);
507700a38b2SDmitry Torokhov 		if (IS_ERR(bdata->gpiod)) {
508700a38b2SDmitry Torokhov 			error = PTR_ERR(bdata->gpiod);
509700a38b2SDmitry Torokhov 			if (error == -ENOENT) {
510700a38b2SDmitry Torokhov 				/*
511700a38b2SDmitry Torokhov 				 * GPIO is optional, we may be dealing with
512700a38b2SDmitry Torokhov 				 * purely interrupt-driven setup.
513700a38b2SDmitry Torokhov 				 */
514700a38b2SDmitry Torokhov 				bdata->gpiod = NULL;
515700a38b2SDmitry Torokhov 			} else {
516700a38b2SDmitry Torokhov 				if (error != -EPROBE_DEFER)
517700a38b2SDmitry Torokhov 					dev_err(dev, "failed to get gpio: %d\n",
518700a38b2SDmitry Torokhov 						error);
519700a38b2SDmitry Torokhov 				return error;
520700a38b2SDmitry Torokhov 			}
521700a38b2SDmitry Torokhov 		}
522700a38b2SDmitry Torokhov 	} else if (gpio_is_valid(button->gpio)) {
5235feeca3cSGeert Uytterhoeven 		/*
5245feeca3cSGeert Uytterhoeven 		 * Legacy GPIO number, so request the GPIO here and
5255feeca3cSGeert Uytterhoeven 		 * convert it to descriptor.
5265feeca3cSGeert Uytterhoeven 		 */
5275feeca3cSGeert Uytterhoeven 		unsigned flags = GPIOF_IN;
528bc8f1eafSBen Dooks 
5295feeca3cSGeert Uytterhoeven 		if (button->active_low)
5305feeca3cSGeert Uytterhoeven 			flags |= GPIOF_ACTIVE_LOW;
5315feeca3cSGeert Uytterhoeven 
532b4e66e7dSGuenter Roeck 		error = devm_gpio_request_one(dev, button->gpio, flags, desc);
533bc8f1eafSBen Dooks 		if (error < 0) {
534d8ee4a1cSLaxman Dewangan 			dev_err(dev, "Failed to request GPIO %d, error %d\n",
535bc8f1eafSBen Dooks 				button->gpio, error);
536d8ee4a1cSLaxman Dewangan 			return error;
537bc8f1eafSBen Dooks 		}
538bc8f1eafSBen Dooks 
5395feeca3cSGeert Uytterhoeven 		bdata->gpiod = gpio_to_desc(button->gpio);
5405feeca3cSGeert Uytterhoeven 		if (!bdata->gpiod)
5415feeca3cSGeert Uytterhoeven 			return -EINVAL;
542700a38b2SDmitry Torokhov 	}
5435feeca3cSGeert Uytterhoeven 
544700a38b2SDmitry Torokhov 	if (bdata->gpiod) {
545*83fc580dSJeffy Chen 		bool active_low = gpiod_is_active_low(bdata->gpiod);
546*83fc580dSJeffy Chen 
54728ed684fSGrazvydas Ignotas 		if (button->debounce_interval) {
5485feeca3cSGeert Uytterhoeven 			error = gpiod_set_debounce(bdata->gpiod,
54928ed684fSGrazvydas Ignotas 					button->debounce_interval * 1000);
55028ed684fSGrazvydas Ignotas 			/* use timer if gpiolib doesn't provide debounce */
55128ed684fSGrazvydas Ignotas 			if (error < 0)
5528ed92556SDmitry Torokhov 				bdata->software_debounce =
553d8ee4a1cSLaxman Dewangan 						button->debounce_interval;
55428ed684fSGrazvydas Ignotas 		}
55528ed684fSGrazvydas Ignotas 
55697d86e07SDmitry Torokhov 		if (button->irq) {
55797d86e07SDmitry Torokhov 			bdata->irq = button->irq;
55897d86e07SDmitry Torokhov 		} else {
5595feeca3cSGeert Uytterhoeven 			irq = gpiod_to_irq(bdata->gpiod);
560bc8f1eafSBen Dooks 			if (irq < 0) {
561bc8f1eafSBen Dooks 				error = irq;
562d8ee4a1cSLaxman Dewangan 				dev_err(dev,
563d8ee4a1cSLaxman Dewangan 					"Unable to get irq number for GPIO %d, error %d\n",
564bc8f1eafSBen Dooks 					button->gpio, error);
56527245519SAlexander Shiyan 				return error;
566d8ee4a1cSLaxman Dewangan 			}
567d8ee4a1cSLaxman Dewangan 			bdata->irq = irq;
56897d86e07SDmitry Torokhov 		}
569d8ee4a1cSLaxman Dewangan 
5708ed92556SDmitry Torokhov 		INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func);
571d8ee4a1cSLaxman Dewangan 
572d8ee4a1cSLaxman Dewangan 		isr = gpio_keys_gpio_isr;
573d8ee4a1cSLaxman Dewangan 		irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
574d8ee4a1cSLaxman Dewangan 
575*83fc580dSJeffy Chen 		switch (button->wakeup_event_action) {
576*83fc580dSJeffy Chen 		case EV_ACT_ASSERTED:
577*83fc580dSJeffy Chen 			bdata->wakeup_trigger_type = active_low ?
578*83fc580dSJeffy Chen 				IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
579*83fc580dSJeffy Chen 			break;
580*83fc580dSJeffy Chen 		case EV_ACT_DEASSERTED:
581*83fc580dSJeffy Chen 			bdata->wakeup_trigger_type = active_low ?
582*83fc580dSJeffy Chen 				IRQ_TYPE_EDGE_RISING : IRQ_TYPE_EDGE_FALLING;
583*83fc580dSJeffy Chen 			break;
584*83fc580dSJeffy Chen 		case EV_ACT_ANY:
585*83fc580dSJeffy Chen 			/* fall through */
586*83fc580dSJeffy Chen 		default:
587*83fc580dSJeffy Chen 			/*
588*83fc580dSJeffy Chen 			 * For other cases, we are OK letting suspend/resume
589*83fc580dSJeffy Chen 			 * not reconfigure the trigger type.
590*83fc580dSJeffy Chen 			 */
591*83fc580dSJeffy Chen 			break;
592*83fc580dSJeffy Chen 		}
593d8ee4a1cSLaxman Dewangan 	} else {
594d8ee4a1cSLaxman Dewangan 		if (!button->irq) {
595700a38b2SDmitry Torokhov 			dev_err(dev, "Found button without gpio or irq\n");
596d8ee4a1cSLaxman Dewangan 			return -EINVAL;
597d8ee4a1cSLaxman Dewangan 		}
598700a38b2SDmitry Torokhov 
599d8ee4a1cSLaxman Dewangan 		bdata->irq = button->irq;
600d8ee4a1cSLaxman Dewangan 
601d8ee4a1cSLaxman Dewangan 		if (button->type && button->type != EV_KEY) {
602d8ee4a1cSLaxman Dewangan 			dev_err(dev, "Only EV_KEY allowed for IRQ buttons.\n");
603d8ee4a1cSLaxman Dewangan 			return -EINVAL;
604bc8f1eafSBen Dooks 		}
605bc8f1eafSBen Dooks 
6068ed92556SDmitry Torokhov 		bdata->release_delay = button->debounce_interval;
60782565a12Sstephen lu 		timer_setup(&bdata->release_timer, gpio_keys_irq_timer, 0);
608d8ee4a1cSLaxman Dewangan 
609d8ee4a1cSLaxman Dewangan 		isr = gpio_keys_irq_isr;
610d8ee4a1cSLaxman Dewangan 		irqflags = 0;
611*83fc580dSJeffy Chen 
612*83fc580dSJeffy Chen 		/*
613*83fc580dSJeffy Chen 		 * For IRQ buttons, there is no interrupt for release.
614*83fc580dSJeffy Chen 		 * So we don't need to reconfigure the trigger type for wakeup.
615*83fc580dSJeffy Chen 		 */
616d8ee4a1cSLaxman Dewangan 	}
617d8ee4a1cSLaxman Dewangan 
61883e4947aSHans de Goede 	bdata->code = &ddata->keymap[idx];
61983e4947aSHans de Goede 	*bdata->code = button->code;
62083e4947aSHans de Goede 	input_set_capability(input, button->type ?: EV_KEY, *bdata->code);
621d8ee4a1cSLaxman Dewangan 
6229e3af04fSMika Westerberg 	/*
6238ed92556SDmitry Torokhov 	 * Install custom action to cancel release timer and
62427245519SAlexander Shiyan 	 * workqueue item.
62527245519SAlexander Shiyan 	 */
626b4e66e7dSGuenter Roeck 	error = devm_add_action(dev, gpio_keys_quiesce_key, bdata);
62727245519SAlexander Shiyan 	if (error) {
628b4e66e7dSGuenter Roeck 		dev_err(dev, "failed to register quiesce action, error: %d\n",
62927245519SAlexander Shiyan 			error);
63027245519SAlexander Shiyan 		return error;
63127245519SAlexander Shiyan 	}
63227245519SAlexander Shiyan 
63327245519SAlexander Shiyan 	/*
6349e3af04fSMika Westerberg 	 * If platform has specified that the button can be disabled,
6359e3af04fSMika Westerberg 	 * we don't want it to share the interrupt line.
6369e3af04fSMika Westerberg 	 */
6379e3af04fSMika Westerberg 	if (!button->can_disable)
6389e3af04fSMika Westerberg 		irqflags |= IRQF_SHARED;
6399e3af04fSMika Westerberg 
640b4e66e7dSGuenter Roeck 	error = devm_request_any_context_irq(dev, bdata->irq, isr, irqflags,
641b4e66e7dSGuenter Roeck 					     desc, bdata);
64294a8cab8SPhilippe Langlais 	if (error < 0) {
643bc8f1eafSBen Dooks 		dev_err(dev, "Unable to claim irq %d; error %d\n",
644d8ee4a1cSLaxman Dewangan 			bdata->irq, error);
64527245519SAlexander Shiyan 		return error;
646bc8f1eafSBen Dooks 	}
647bc8f1eafSBen Dooks 
648bc8f1eafSBen Dooks 	return 0;
649bc8f1eafSBen Dooks }
650bc8f1eafSBen Dooks 
6515b76d7b4SDmitry Torokhov static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
6525b76d7b4SDmitry Torokhov {
6535b76d7b4SDmitry Torokhov 	struct input_dev *input = ddata->input;
6545b76d7b4SDmitry Torokhov 	int i;
6555b76d7b4SDmitry Torokhov 
6565b76d7b4SDmitry Torokhov 	for (i = 0; i < ddata->pdata->nbuttons; i++) {
6575b76d7b4SDmitry Torokhov 		struct gpio_button_data *bdata = &ddata->data[i];
6585feeca3cSGeert Uytterhoeven 		if (bdata->gpiod)
6595b76d7b4SDmitry Torokhov 			gpio_keys_gpio_report_event(bdata);
6605b76d7b4SDmitry Torokhov 	}
6615b76d7b4SDmitry Torokhov 	input_sync(input);
6625b76d7b4SDmitry Torokhov }
6635b76d7b4SDmitry Torokhov 
664173bdd74SShubhrajyoti D static int gpio_keys_open(struct input_dev *input)
665173bdd74SShubhrajyoti D {
666173bdd74SShubhrajyoti D 	struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
667219edc71SAlexandre Pereira da Silva 	const struct gpio_keys_platform_data *pdata = ddata->pdata;
6685b76d7b4SDmitry Torokhov 	int error;
669173bdd74SShubhrajyoti D 
6705b76d7b4SDmitry Torokhov 	if (pdata->enable) {
6715b76d7b4SDmitry Torokhov 		error = pdata->enable(input->dev.parent);
6725b76d7b4SDmitry Torokhov 		if (error)
6735b76d7b4SDmitry Torokhov 			return error;
6745b76d7b4SDmitry Torokhov 	}
6755b76d7b4SDmitry Torokhov 
6765b76d7b4SDmitry Torokhov 	/* Report current state of buttons that are connected to GPIOs */
6775b76d7b4SDmitry Torokhov 	gpio_keys_report_state(ddata);
6785b76d7b4SDmitry Torokhov 
6795b76d7b4SDmitry Torokhov 	return 0;
680173bdd74SShubhrajyoti D }
681173bdd74SShubhrajyoti D 
682173bdd74SShubhrajyoti D static void gpio_keys_close(struct input_dev *input)
683173bdd74SShubhrajyoti D {
684173bdd74SShubhrajyoti D 	struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
685219edc71SAlexandre Pereira da Silva 	const struct gpio_keys_platform_data *pdata = ddata->pdata;
686173bdd74SShubhrajyoti D 
687219edc71SAlexandre Pereira da Silva 	if (pdata->disable)
688219edc71SAlexandre Pereira da Silva 		pdata->disable(input->dev.parent);
689173bdd74SShubhrajyoti D }
690173bdd74SShubhrajyoti D 
691fd05d089SDavid Jander /*
692fd05d089SDavid Jander  * Handlers for alternative sources of platform_data
693fd05d089SDavid Jander  */
694219edc71SAlexandre Pereira da Silva 
695fd05d089SDavid Jander /*
696700a38b2SDmitry Torokhov  * Translate properties into platform_data
697fd05d089SDavid Jander  */
6985298cc4cSBill Pemberton static struct gpio_keys_platform_data *
699219edc71SAlexandre Pereira da Silva gpio_keys_get_devtree_pdata(struct device *dev)
700fd05d089SDavid Jander {
701219edc71SAlexandre Pereira da Silva 	struct gpio_keys_platform_data *pdata;
702219edc71SAlexandre Pereira da Silva 	struct gpio_keys_button *button;
703700a38b2SDmitry Torokhov 	struct fwnode_handle *child;
704219edc71SAlexandre Pereira da Silva 	int nbuttons;
705fd05d089SDavid Jander 
706700a38b2SDmitry Torokhov 	nbuttons = device_get_child_node_count(dev);
7075d422f2eSAndy Shevchenko 	if (nbuttons == 0)
7085d422f2eSAndy Shevchenko 		return ERR_PTR(-ENODEV);
709219edc71SAlexandre Pereira da Silva 
7105d422f2eSAndy Shevchenko 	pdata = devm_kzalloc(dev,
7115d422f2eSAndy Shevchenko 			     sizeof(*pdata) + nbuttons * sizeof(*button),
712219edc71SAlexandre Pereira da Silva 			     GFP_KERNEL);
7135d422f2eSAndy Shevchenko 	if (!pdata)
7145d422f2eSAndy Shevchenko 		return ERR_PTR(-ENOMEM);
715219edc71SAlexandre Pereira da Silva 
7160f78ba96SDmitry Torokhov 	button = (struct gpio_keys_button *)(pdata + 1);
7170f78ba96SDmitry Torokhov 
7180f78ba96SDmitry Torokhov 	pdata->buttons = button;
719219edc71SAlexandre Pereira da Silva 	pdata->nbuttons = nbuttons;
720fd05d089SDavid Jander 
721700a38b2SDmitry Torokhov 	pdata->rep = device_property_read_bool(dev, "autorepeat");
722fd05d089SDavid Jander 
723700a38b2SDmitry Torokhov 	device_property_read_string(dev, "label", &pdata->name);
724c4dc5f8cSLaxman Dewangan 
725700a38b2SDmitry Torokhov 	device_for_each_child_node(dev, child) {
726700a38b2SDmitry Torokhov 		if (is_of_node(child))
727700a38b2SDmitry Torokhov 			button->irq =
728700a38b2SDmitry Torokhov 				irq_of_parse_and_map(to_of_node(child), 0);
729fd05d089SDavid Jander 
730700a38b2SDmitry Torokhov 		if (fwnode_property_read_u32(child, "linux,code",
731700a38b2SDmitry Torokhov 					     &button->code)) {
732700a38b2SDmitry Torokhov 			dev_err(dev, "Button without keycode\n");
733700a38b2SDmitry Torokhov 			fwnode_handle_put(child);
73497d86e07SDmitry Torokhov 			return ERR_PTR(-EINVAL);
73597d86e07SDmitry Torokhov 		}
736fd05d089SDavid Jander 
737700a38b2SDmitry Torokhov 		fwnode_property_read_string(child, "label", &button->desc);
738fd05d089SDavid Jander 
739700a38b2SDmitry Torokhov 		if (fwnode_property_read_u32(child, "linux,input-type",
740700a38b2SDmitry Torokhov 					     &button->type))
741219edc71SAlexandre Pereira da Silva 			button->type = EV_KEY;
742fd05d089SDavid Jander 
743700a38b2SDmitry Torokhov 		button->wakeup =
744700a38b2SDmitry Torokhov 			fwnode_property_read_bool(child, "wakeup-source") ||
74599b4ffbdSDmitry Torokhov 			/* legacy name */
746700a38b2SDmitry Torokhov 			fwnode_property_read_bool(child, "gpio-key,wakeup");
747219edc71SAlexandre Pereira da Silva 
748*83fc580dSJeffy Chen 		fwnode_property_read_u32(child, "wakeup-event-action",
749*83fc580dSJeffy Chen 					 &button->wakeup_event_action);
750*83fc580dSJeffy Chen 
751700a38b2SDmitry Torokhov 		button->can_disable =
752700a38b2SDmitry Torokhov 			fwnode_property_read_bool(child, "linux,can-disable");
75397d86e07SDmitry Torokhov 
754700a38b2SDmitry Torokhov 		if (fwnode_property_read_u32(child, "debounce-interval",
755219edc71SAlexandre Pereira da Silva 					 &button->debounce_interval))
756219edc71SAlexandre Pereira da Silva 			button->debounce_interval = 5;
7570f78ba96SDmitry Torokhov 
7580f78ba96SDmitry Torokhov 		button++;
759219edc71SAlexandre Pereira da Silva 	}
760219edc71SAlexandre Pereira da Silva 
761219edc71SAlexandre Pereira da Silva 	return pdata;
762fd05d089SDavid Jander }
763fd05d089SDavid Jander 
76422daae31SJingoo Han static const struct of_device_id gpio_keys_of_match[] = {
765fd05d089SDavid Jander 	{ .compatible = "gpio-keys", },
766fd05d089SDavid Jander 	{ },
767fd05d089SDavid Jander };
768fd05d089SDavid Jander MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
769fd05d089SDavid Jander 
7705298cc4cSBill Pemberton static int gpio_keys_probe(struct platform_device *pdev)
77178a56aabSPhil Blundell {
772db19fd8bSBen Dooks 	struct device *dev = &pdev->dev;
773219edc71SAlexandre Pereira da Silva 	const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
774700a38b2SDmitry Torokhov 	struct fwnode_handle *child = NULL;
775219edc71SAlexandre Pereira da Silva 	struct gpio_keys_drvdata *ddata;
77678a56aabSPhil Blundell 	struct input_dev *input;
7775d422f2eSAndy Shevchenko 	size_t size;
77878a56aabSPhil Blundell 	int i, error;
779e15b0213SAnti Sullin 	int wakeup = 0;
78078a56aabSPhil Blundell 
781fd05d089SDavid Jander 	if (!pdata) {
782219edc71SAlexandre Pereira da Silva 		pdata = gpio_keys_get_devtree_pdata(dev);
783219edc71SAlexandre Pereira da Silva 		if (IS_ERR(pdata))
784219edc71SAlexandre Pereira da Silva 			return PTR_ERR(pdata);
785fd05d089SDavid Jander 	}
786fd05d089SDavid Jander 
7875d422f2eSAndy Shevchenko 	size = sizeof(struct gpio_keys_drvdata) +
7885d422f2eSAndy Shevchenko 			pdata->nbuttons * sizeof(struct gpio_button_data);
7895d422f2eSAndy Shevchenko 	ddata = devm_kzalloc(dev, size, GFP_KERNEL);
7905d422f2eSAndy Shevchenko 	if (!ddata) {
791db19fd8bSBen Dooks 		dev_err(dev, "failed to allocate state\n");
7925d422f2eSAndy Shevchenko 		return -ENOMEM;
7935d422f2eSAndy Shevchenko 	}
7945d422f2eSAndy Shevchenko 
79583e4947aSHans de Goede 	ddata->keymap = devm_kcalloc(dev,
79683e4947aSHans de Goede 				     pdata->nbuttons, sizeof(ddata->keymap[0]),
79783e4947aSHans de Goede 				     GFP_KERNEL);
79883e4947aSHans de Goede 	if (!ddata->keymap)
79983e4947aSHans de Goede 		return -ENOMEM;
80083e4947aSHans de Goede 
8015d422f2eSAndy Shevchenko 	input = devm_input_allocate_device(dev);
8025d422f2eSAndy Shevchenko 	if (!input) {
8035d422f2eSAndy Shevchenko 		dev_err(dev, "failed to allocate input device\n");
8045d422f2eSAndy Shevchenko 		return -ENOMEM;
805a33466e3SDmitry Baryshkov 	}
80678a56aabSPhil Blundell 
807219edc71SAlexandre Pereira da Silva 	ddata->pdata = pdata;
8089e3af04fSMika Westerberg 	ddata->input = input;
8099e3af04fSMika Westerberg 	mutex_init(&ddata->disable_lock);
8109e3af04fSMika Westerberg 
811a33466e3SDmitry Baryshkov 	platform_set_drvdata(pdev, ddata);
812173bdd74SShubhrajyoti D 	input_set_drvdata(input, ddata);
81378a56aabSPhil Blundell 
81446711277SAlexander Stein 	input->name = pdata->name ? : pdev->name;
81578a56aabSPhil Blundell 	input->phys = "gpio-keys/input0";
816b4e66e7dSGuenter Roeck 	input->dev.parent = dev;
817173bdd74SShubhrajyoti D 	input->open = gpio_keys_open;
818173bdd74SShubhrajyoti D 	input->close = gpio_keys_close;
81978a56aabSPhil Blundell 
82078a56aabSPhil Blundell 	input->id.bustype = BUS_HOST;
82178a56aabSPhil Blundell 	input->id.vendor = 0x0001;
82278a56aabSPhil Blundell 	input->id.product = 0x0001;
82378a56aabSPhil Blundell 	input->id.version = 0x0100;
82478a56aabSPhil Blundell 
82583e4947aSHans de Goede 	input->keycode = ddata->keymap;
82683e4947aSHans de Goede 	input->keycodesize = sizeof(ddata->keymap[0]);
82783e4947aSHans de Goede 	input->keycodemax = pdata->nbuttons;
82883e4947aSHans de Goede 
829b67b4b11SDominic Curran 	/* Enable auto repeat feature of Linux input subsystem */
830b67b4b11SDominic Curran 	if (pdata->rep)
831b67b4b11SDominic Curran 		__set_bit(EV_REP, input->evbit);
832b67b4b11SDominic Curran 
83378a56aabSPhil Blundell 	for (i = 0; i < pdata->nbuttons; i++) {
834d9080921SDmitry Torokhov 		const struct gpio_keys_button *button = &pdata->buttons[i];
83578a56aabSPhil Blundell 
836700a38b2SDmitry Torokhov 		if (!dev_get_platdata(dev)) {
837b4e66e7dSGuenter Roeck 			child = device_get_next_child_node(dev, child);
838700a38b2SDmitry Torokhov 			if (!child) {
839b4e66e7dSGuenter Roeck 				dev_err(dev,
840700a38b2SDmitry Torokhov 					"missing child device node for entry %d\n",
841700a38b2SDmitry Torokhov 					i);
842700a38b2SDmitry Torokhov 				return -EINVAL;
843700a38b2SDmitry Torokhov 			}
844700a38b2SDmitry Torokhov 		}
845700a38b2SDmitry Torokhov 
84683e4947aSHans de Goede 		error = gpio_keys_setup_key(pdev, input, ddata,
84783e4947aSHans de Goede 					    button, i, child);
848700a38b2SDmitry Torokhov 		if (error) {
849700a38b2SDmitry Torokhov 			fwnode_handle_put(child);
85027245519SAlexander Shiyan 			return error;
851700a38b2SDmitry Torokhov 		}
85284767d00SRoman Moravcik 
853e15b0213SAnti Sullin 		if (button->wakeup)
854e15b0213SAnti Sullin 			wakeup = 1;
85578a56aabSPhil Blundell 	}
85678a56aabSPhil Blundell 
857700a38b2SDmitry Torokhov 	fwnode_handle_put(child);
858700a38b2SDmitry Torokhov 
8593184125eSDmitry Torokhov 	error = devm_device_add_group(dev, &gpio_keys_attr_group);
8609e3af04fSMika Westerberg 	if (error) {
8619e3af04fSMika Westerberg 		dev_err(dev, "Unable to export keys/switches, error: %d\n",
8629e3af04fSMika Westerberg 			error);
86327245519SAlexander Shiyan 		return error;
8649e3af04fSMika Westerberg 	}
8659e3af04fSMika Westerberg 
86678a56aabSPhil Blundell 	error = input_register_device(input);
86778a56aabSPhil Blundell 	if (error) {
8689e3af04fSMika Westerberg 		dev_err(dev, "Unable to register input device, error: %d\n",
8699e3af04fSMika Westerberg 			error);
87078a56aabSPhil Blundell 		return error;
87178a56aabSPhil Blundell 	}
87278a56aabSPhil Blundell 
8733184125eSDmitry Torokhov 	device_init_wakeup(dev, wakeup);
8749e3af04fSMika Westerberg 
87578a56aabSPhil Blundell 	return 0;
87678a56aabSPhil Blundell }
87778a56aabSPhil Blundell 
878*83fc580dSJeffy Chen static int __maybe_unused
879*83fc580dSJeffy Chen gpio_keys_button_enable_wakeup(struct gpio_button_data *bdata)
880*83fc580dSJeffy Chen {
881*83fc580dSJeffy Chen 	int error;
882*83fc580dSJeffy Chen 
883*83fc580dSJeffy Chen 	error = enable_irq_wake(bdata->irq);
884*83fc580dSJeffy Chen 	if (error) {
885*83fc580dSJeffy Chen 		dev_err(bdata->input->dev.parent,
886*83fc580dSJeffy Chen 			"failed to configure IRQ %d as wakeup source: %d\n",
887*83fc580dSJeffy Chen 			bdata->irq, error);
888*83fc580dSJeffy Chen 		return error;
889*83fc580dSJeffy Chen 	}
890*83fc580dSJeffy Chen 
891*83fc580dSJeffy Chen 	if (bdata->wakeup_trigger_type) {
892*83fc580dSJeffy Chen 		error = irq_set_irq_type(bdata->irq,
893*83fc580dSJeffy Chen 					 bdata->wakeup_trigger_type);
894*83fc580dSJeffy Chen 		if (error) {
895*83fc580dSJeffy Chen 			dev_err(bdata->input->dev.parent,
896*83fc580dSJeffy Chen 				"failed to set wakeup trigger %08x for IRQ %d: %d\n",
897*83fc580dSJeffy Chen 				bdata->wakeup_trigger_type, bdata->irq, error);
898*83fc580dSJeffy Chen 			disable_irq_wake(bdata->irq);
899*83fc580dSJeffy Chen 			return error;
900*83fc580dSJeffy Chen 		}
901*83fc580dSJeffy Chen 	}
902*83fc580dSJeffy Chen 
903*83fc580dSJeffy Chen 	return 0;
904*83fc580dSJeffy Chen }
905*83fc580dSJeffy Chen 
906*83fc580dSJeffy Chen static void __maybe_unused
907*83fc580dSJeffy Chen gpio_keys_button_disable_wakeup(struct gpio_button_data *bdata)
908*83fc580dSJeffy Chen {
909*83fc580dSJeffy Chen 	int error;
910*83fc580dSJeffy Chen 
911*83fc580dSJeffy Chen 	/*
912*83fc580dSJeffy Chen 	 * The trigger type is always both edges for gpio-based keys and we do
913*83fc580dSJeffy Chen 	 * not support changing wakeup trigger for interrupt-based keys.
914*83fc580dSJeffy Chen 	 */
915*83fc580dSJeffy Chen 	if (bdata->wakeup_trigger_type) {
916*83fc580dSJeffy Chen 		error = irq_set_irq_type(bdata->irq, IRQ_TYPE_EDGE_BOTH);
917*83fc580dSJeffy Chen 		if (error)
918*83fc580dSJeffy Chen 			dev_warn(bdata->input->dev.parent,
919*83fc580dSJeffy Chen 				 "failed to restore interrupt trigger for IRQ %d: %d\n",
920*83fc580dSJeffy Chen 				 bdata->irq, error);
921*83fc580dSJeffy Chen 	}
922*83fc580dSJeffy Chen 
923*83fc580dSJeffy Chen 	error = disable_irq_wake(bdata->irq);
924*83fc580dSJeffy Chen 	if (error)
925*83fc580dSJeffy Chen 		dev_warn(bdata->input->dev.parent,
926*83fc580dSJeffy Chen 			 "failed to disable IRQ %d as wake source: %d\n",
927*83fc580dSJeffy Chen 			 bdata->irq, error);
928*83fc580dSJeffy Chen }
929*83fc580dSJeffy Chen 
930*83fc580dSJeffy Chen static int __maybe_unused
931*83fc580dSJeffy Chen gpio_keys_enable_wakeup(struct gpio_keys_drvdata *ddata)
932*83fc580dSJeffy Chen {
933*83fc580dSJeffy Chen 	struct gpio_button_data *bdata;
934*83fc580dSJeffy Chen 	int error;
935*83fc580dSJeffy Chen 	int i;
936*83fc580dSJeffy Chen 
937*83fc580dSJeffy Chen 	for (i = 0; i < ddata->pdata->nbuttons; i++) {
938*83fc580dSJeffy Chen 		bdata = &ddata->data[i];
939*83fc580dSJeffy Chen 		if (bdata->button->wakeup) {
940*83fc580dSJeffy Chen 			error = gpio_keys_button_enable_wakeup(bdata);
941*83fc580dSJeffy Chen 			if (error)
942*83fc580dSJeffy Chen 				goto err_out;
943*83fc580dSJeffy Chen 		}
944*83fc580dSJeffy Chen 		bdata->suspended = true;
945*83fc580dSJeffy Chen 	}
946*83fc580dSJeffy Chen 
947*83fc580dSJeffy Chen 	return 0;
948*83fc580dSJeffy Chen 
949*83fc580dSJeffy Chen err_out:
950*83fc580dSJeffy Chen 	while (i--) {
951*83fc580dSJeffy Chen 		bdata = &ddata->data[i];
952*83fc580dSJeffy Chen 		if (bdata->button->wakeup)
953*83fc580dSJeffy Chen 			gpio_keys_button_disable_wakeup(bdata);
954*83fc580dSJeffy Chen 		bdata->suspended = false;
955*83fc580dSJeffy Chen 	}
956*83fc580dSJeffy Chen 
957*83fc580dSJeffy Chen 	return error;
958*83fc580dSJeffy Chen }
959*83fc580dSJeffy Chen 
960*83fc580dSJeffy Chen static void __maybe_unused
961*83fc580dSJeffy Chen gpio_keys_disable_wakeup(struct gpio_keys_drvdata *ddata)
962*83fc580dSJeffy Chen {
963*83fc580dSJeffy Chen 	struct gpio_button_data *bdata;
964*83fc580dSJeffy Chen 	int i;
965*83fc580dSJeffy Chen 
966*83fc580dSJeffy Chen 	for (i = 0; i < ddata->pdata->nbuttons; i++) {
967*83fc580dSJeffy Chen 		bdata = &ddata->data[i];
968*83fc580dSJeffy Chen 		bdata->suspended = false;
969*83fc580dSJeffy Chen 		if (irqd_is_wakeup_set(irq_get_irq_data(bdata->irq)))
970*83fc580dSJeffy Chen 			gpio_keys_button_disable_wakeup(bdata);
971*83fc580dSJeffy Chen 	}
972*83fc580dSJeffy Chen }
973*83fc580dSJeffy Chen 
974f9645f22SDmitry Torokhov static int __maybe_unused gpio_keys_suspend(struct device *dev)
975e15b0213SAnti Sullin {
976fd05d089SDavid Jander 	struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
977dda19a92SJonas Aaberg 	struct input_dev *input = ddata->input;
978*83fc580dSJeffy Chen 	int error;
979e15b0213SAnti Sullin 
980fd05d089SDavid Jander 	if (device_may_wakeup(dev)) {
981*83fc580dSJeffy Chen 		error = gpio_keys_enable_wakeup(ddata);
982*83fc580dSJeffy Chen 		if (error)
983*83fc580dSJeffy Chen 			return error;
984dda19a92SJonas Aaberg 	} else {
985dda19a92SJonas Aaberg 		mutex_lock(&input->mutex);
986dda19a92SJonas Aaberg 		if (input->users)
987dda19a92SJonas Aaberg 			gpio_keys_close(input);
988dda19a92SJonas Aaberg 		mutex_unlock(&input->mutex);
989e15b0213SAnti Sullin 	}
990e15b0213SAnti Sullin 
991e15b0213SAnti Sullin 	return 0;
992e15b0213SAnti Sullin }
993e15b0213SAnti Sullin 
994f9645f22SDmitry Torokhov static int __maybe_unused gpio_keys_resume(struct device *dev)
995e15b0213SAnti Sullin {
996fd05d089SDavid Jander 	struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
997dda19a92SJonas Aaberg 	struct input_dev *input = ddata->input;
998dda19a92SJonas Aaberg 	int error = 0;
999e15b0213SAnti Sullin 
1000dda19a92SJonas Aaberg 	if (device_may_wakeup(dev)) {
1001*83fc580dSJeffy Chen 		gpio_keys_disable_wakeup(ddata);
1002dda19a92SJonas Aaberg 	} else {
1003dda19a92SJonas Aaberg 		mutex_lock(&input->mutex);
1004dda19a92SJonas Aaberg 		if (input->users)
1005dda19a92SJonas Aaberg 			error = gpio_keys_open(input);
1006dda19a92SJonas Aaberg 		mutex_unlock(&input->mutex);
1007dda19a92SJonas Aaberg 	}
1008dda19a92SJonas Aaberg 
1009dda19a92SJonas Aaberg 	if (error)
1010dda19a92SJonas Aaberg 		return error;
10115b76d7b4SDmitry Torokhov 
10125b76d7b4SDmitry Torokhov 	gpio_keys_report_state(ddata);
1013e15b0213SAnti Sullin 	return 0;
1014e15b0213SAnti Sullin }
1015e15b0213SAnti Sullin 
1016bdda8216SDmitry Torokhov static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
1017bdda8216SDmitry Torokhov 
10189b07044cSUwe Kleine-König static struct platform_driver gpio_keys_device_driver = {
101978a56aabSPhil Blundell 	.probe		= gpio_keys_probe,
102078a56aabSPhil Blundell 	.driver		= {
102178a56aabSPhil Blundell 		.name	= "gpio-keys",
1022ae78e0e0SMike Rapoport 		.pm	= &gpio_keys_pm_ops,
1023700a38b2SDmitry Torokhov 		.of_match_table = gpio_keys_of_match,
102478a56aabSPhil Blundell 	}
102578a56aabSPhil Blundell };
102678a56aabSPhil Blundell 
102778a56aabSPhil Blundell static int __init gpio_keys_init(void)
102878a56aabSPhil Blundell {
102978a56aabSPhil Blundell 	return platform_driver_register(&gpio_keys_device_driver);
103078a56aabSPhil Blundell }
103178a56aabSPhil Blundell 
103278a56aabSPhil Blundell static void __exit gpio_keys_exit(void)
103378a56aabSPhil Blundell {
103478a56aabSPhil Blundell 	platform_driver_unregister(&gpio_keys_device_driver);
103578a56aabSPhil Blundell }
103678a56aabSPhil Blundell 
1037b2330205SDavid Jander late_initcall(gpio_keys_init);
103878a56aabSPhil Blundell module_exit(gpio_keys_exit);
103978a56aabSPhil Blundell 
104078a56aabSPhil Blundell MODULE_LICENSE("GPL");
104178a56aabSPhil Blundell MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
10427e2ecdf4SDavid Jander MODULE_DESCRIPTION("Keyboard driver for GPIOs");
1043d7b5247bSKay Sievers MODULE_ALIAS("platform:gpio-keys");
1044