[PATCH resend 0/4] Input: axp20x-pek and gpio_keys patches

STALE3446d

7 messages, 2 authors, 2017-03-09 · open the first message on its own page

[PATCH resend 0/4] Input: axp20x-pek and gpio_keys patches

From: Hans de Goede <hidden>
Date: 2017-03-08 09:20:21

Hi,

These 4 patches seem to have fallen through the cracks, so I'm
resending them. They have been rebased on top of 4.11-rc1 (trivial
rebase).

Regards,

Hans

[PATCH resend 1/4] Input: axp20x-pek - Use our own device for errors

From: Hans de Goede <hidden>
Date: 2017-03-08 09:00:57

Before this commit axp20x-pek was mixing 2 style error reporting calls:
dev_err(&pdev->dev, ...);
dev_err(axp20x->dev, ...);

But the second is our parent device, not our own device, so switch to
using &pdev->dev everywhere.

Signed-off-by: Hans de Goede <redacted>
---
 drivers/input/misc/axp20x-pek.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c
index 1ac898d..a041365 100644
--- a/drivers/input/misc/axp20x-pek.c
+++ b/drivers/input/misc/axp20x-pek.c
@@ -239,7 +239,7 @@ static int axp20x_pek_probe(struct platform_device *pdev)
 					     axp20x_pek_irq, 0,
 					     "axp20x-pek-dbr", idev);
 	if (error < 0) {
-		dev_err(axp20x->dev, "Failed to request dbr IRQ#%d: %d\n",
+		dev_err(&pdev->dev, "Failed to request dbr IRQ#%d: %d\n",
 			axp20x_pek->irq_dbr, error);
 		return error;
 	}
@@ -248,14 +248,14 @@ static int axp20x_pek_probe(struct platform_device *pdev)
 					  axp20x_pek_irq, 0,
 					  "axp20x-pek-dbf", idev);
 	if (error < 0) {
-		dev_err(axp20x->dev, "Failed to request dbf IRQ#%d: %d\n",
+		dev_err(&pdev->dev, "Failed to request dbf IRQ#%d: %d\n",
 			axp20x_pek->irq_dbf, error);
 		return error;
 	}
 
 	error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group);
 	if (error) {
-		dev_err(axp20x->dev, "Failed to create sysfs attributes: %d\n",
+		dev_err(&pdev->dev, "Failed to create sysfs attributes: %d\n",
 			error);
 		return error;
 	}
@@ -271,7 +271,7 @@ static int axp20x_pek_probe(struct platform_device *pdev)
 
 	error = input_register_device(idev);
 	if (error) {
-		dev_err(axp20x->dev, "Can't register input device: %d\n",
+		dev_err(&pdev->dev, "Can't register input device: %d\n",
 			error);
 		return error;
 	}
-- 
2.9.3

[PATCH resend 3/4] Input: axp20x-pek - Do not register input device on some systems

From: Hans de Goede <hidden>
Date: 2017-03-08 09:02:13

On some systems (Intel tablets with axp288 pmic) the powerbutton is
also connected to a gpio pin of the SoC, advertised through the
"INTCFD9" / "PNP0C40" acpi device. This leads to double reporting
of powerbutton events, which is undesirable, so one driver needs
to not report input events in this case.

Since the soc_button_array driver for the "PNP0C40" acpi device
also handles wake from suspend on these tablets and since the
axp20x-pel driver requires relative expensive i2c accrsses,
it is best for the axp20x-pek driver to not register an input device
in this case.

Note that this commit leaves the axp20x-driver bound to the
device, rather then returning -ENODEV, this is done so that the
sysfs attributes it offers are kept around.

Signed-off-by: Hans de Goede <redacted>
---
 drivers/input/misc/axp20x-pek.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c
index b7258ec..dbd2c89 100644
--- a/drivers/input/misc/axp20x-pek.c
+++ b/drivers/input/misc/axp20x-pek.c
@@ -13,6 +13,7 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/acpi.h>
 #include <linux/errno.h>
 #include <linux/irq.h>
 #include <linux/init.h>
@@ -267,9 +268,16 @@ static int axp20x_pek_probe(struct platform_device *pdev)
 
 	axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent);
 
-	error = axp20x_pek_probe_input_device(axp20x_pek, pdev);
-	if (error)
-		return error;
+	/*
+	 * Do not register the input device if there is an "INTCFD9"
+	 * gpio button ACPI device, that handles the power button too,
+	 * and otherwise we end up reporting all presses twice.
+	 */
+	if (!acpi_dev_found("INTCFD9")) {
+		error = axp20x_pek_probe_input_device(axp20x_pek, pdev);
+		if (error)
+			return error;
+	}
 
 	error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group);
 	if (error) {
-- 
2.9.3

[PATCH resend 4/4] Input: gpio_keys - Do not report wake button presses as evdev events

From: Hans de Goede <hidden>
Date: 2017-03-08 09:04:16

If a button is a wake button, it may still be bouncing from the press
to wakeup the device by the time the gpio interrupts get enabled again
and / or the gpio_keys_report_state call from gpio_keys_resume may
find the button still pressed and report this as a new press.

This is undesirable, esp. since the powerbutton on tablets is typically
a wakeup source and uses the gpio_keys driver on some tablets, leading
to userspace immediately re-suspending the tablet after the powerbutton
is pressed, due to it seeing a powerbutton press.

This commit ignores wakeup button presses for the first 1 second after
resume (and while resumed, as the workqueue may run before the resume
function runs), avoiding this problem.

Signed-off-by: Hans de Goede <redacted>
---
Note: maybe we should make WAKE_DEBOUNCE part of gpio_keys_button and
only do this when drivers / platform-data set this to a non-zero value ?
---
 drivers/input/keyboard/gpio_keys.c | 49 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 47 insertions(+), 2 deletions(-)
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index da3d362..e1488b5 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -31,6 +31,8 @@
 #include <linux/of_irq.h>
 #include <linux/spinlock.h>
 
+#define WAKE_DEBOUNCE msecs_to_jiffies(1000)
+
 struct gpio_button_data {
 	const struct gpio_keys_button *button;
 	struct input_dev *input;
@@ -44,10 +46,14 @@ struct gpio_button_data {
 	struct delayed_work work;
 	unsigned int software_debounce;	/* in msecs, for GPIO-driven buttons */
 
+	unsigned long resume_time;	/* in jiffies, for wakeup buttons */
+
 	unsigned int irq;
 	spinlock_t lock;
 	bool disabled;
 	bool key_pressed;
+	bool suspended;
+	bool resume_time_valid;
 };
 
 struct gpio_keys_drvdata {
@@ -356,6 +362,27 @@ static struct attribute_group gpio_keys_attr_group = {
 	.attrs = gpio_keys_attrs,
 };
 
+static bool gpio_keys_ignore_wakeup_button_press(struct gpio_button_data *bdata)
+{
+	unsigned long flags;
+	bool ret = false;
+
+	if (!bdata->button->wakeup)
+		return ret;
+
+	spin_lock_irqsave(&bdata->lock, flags);
+
+	if (bdata->suspended)
+		ret = true; /* Our resume method did not run yet */
+	else if (bdata->resume_time_valid &&
+		 time_before(jiffies, bdata->resume_time + WAKE_DEBOUNCE))
+		ret = true; /* Assume this is a wakeup press and ignore */
+
+	spin_unlock_irqrestore(&bdata->lock, flags);
+
+	return ret;
+}
+
 static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
 {
 	const struct gpio_keys_button *button = bdata->button;
@@ -370,6 +397,9 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
 		return;
 	}
 
+	if (state && gpio_keys_ignore_wakeup_button_press(bdata))
+		return;
+
 	if (type == EV_ABS) {
 		if (state)
 			input_event(input, type, button->code, button->value);
@@ -429,6 +459,9 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
 
 	BUG_ON(irq != bdata->irq);
 
+	if (gpio_keys_ignore_wakeup_button_press(bdata))
+		return IRQ_HANDLED;
+
 	spin_lock_irqsave(&bdata->lock, flags);
 
 	if (!bdata->key_pressed) {
@@ -848,13 +881,18 @@ static int __maybe_unused gpio_keys_suspend(struct device *dev)
 {
 	struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
 	struct input_dev *input = ddata->input;
+	unsigned long flags;
 	int i;
 
 	if (device_may_wakeup(dev)) {
 		for (i = 0; i < ddata->pdata->nbuttons; i++) {
 			struct gpio_button_data *bdata = &ddata->data[i];
-			if (bdata->button->wakeup)
+			if (bdata->button->wakeup) {
+				spin_lock_irqsave(&bdata->lock, flags);
+				bdata->suspended = true;
+				spin_unlock_irqrestore(&bdata->lock, flags);
 				enable_irq_wake(bdata->irq);
+			}
 		}
 	} else {
 		mutex_lock(&input->mutex);
@@ -870,14 +908,21 @@ static int __maybe_unused gpio_keys_resume(struct device *dev)
 {
 	struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
 	struct input_dev *input = ddata->input;
+	unsigned long flags;
 	int error = 0;
 	int i;
 
 	if (device_may_wakeup(dev)) {
 		for (i = 0; i < ddata->pdata->nbuttons; i++) {
 			struct gpio_button_data *bdata = &ddata->data[i];
-			if (bdata->button->wakeup)
+			if (bdata->button->wakeup) {
 				disable_irq_wake(bdata->irq);
+				spin_lock_irqsave(&bdata->lock, flags);
+				bdata->resume_time = jiffies;
+				bdata->resume_time_valid = true;
+				bdata->suspended = false;
+				spin_unlock_irqrestore(&bdata->lock, flags);
+			}
 		}
 	} else {
 		mutex_lock(&input->mutex);
-- 
2.9.3

[PATCH resend 2/4] Input: axp20x_pek - Add axp20x_pek_probe_input_device helper

From: Hans de Goede <hidden>
Date: 2017-03-08 09:20:21

Move all input device related initialization into a new
axp20x_pek_probe_input_device helper function.

This introduces one functional change, the input device is now
registered before the sysfs attr get registered. This is not a problem
as the sysfs attr are to configure some long press settings (forced
poweroff) in the hardware and do not interact with the input_device.

This is a preparation patch for not always registering the input dev.

Signed-off-by: Hans de Goede <redacted>
---
 drivers/input/misc/axp20x-pek.c | 47 +++++++++++++++++++++++++----------------
 1 file changed, 29 insertions(+), 18 deletions(-)
diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c
index a041365..b7258ec 100644
--- a/drivers/input/misc/axp20x-pek.c
+++ b/drivers/input/misc/axp20x-pek.c
@@ -188,21 +188,13 @@ static void axp20x_remove_sysfs_group(void *_data)
 	sysfs_remove_group(&dev->kobj, &axp20x_attribute_group);
 }
 
-static int axp20x_pek_probe(struct platform_device *pdev)
+static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek,
+					 struct platform_device *pdev)
 {
-	struct axp20x_pek *axp20x_pek;
-	struct axp20x_dev *axp20x;
+	struct axp20x_dev *axp20x = axp20x_pek->axp20x;
 	struct input_dev *idev;
 	int error;
 
-	axp20x_pek = devm_kzalloc(&pdev->dev, sizeof(struct axp20x_pek),
-				  GFP_KERNEL);
-	if (!axp20x_pek)
-		return -ENOMEM;
-
-	axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent);
-	axp20x = axp20x_pek->axp20x;
-
 	axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR");
 	if (axp20x_pek->irq_dbr < 0) {
 		dev_err(&pdev->dev, "No IRQ for PEK_DBR, error=%d\n",
@@ -253,6 +245,32 @@ static int axp20x_pek_probe(struct platform_device *pdev)
 		return error;
 	}
 
+	error = input_register_device(idev);
+	if (error) {
+		dev_err(&pdev->dev, "Can't register input device: %d\n",
+			error);
+		return error;
+	}
+
+	return 0;
+}
+
+static int axp20x_pek_probe(struct platform_device *pdev)
+{
+	struct axp20x_pek *axp20x_pek;
+	int error;
+
+	axp20x_pek = devm_kzalloc(&pdev->dev, sizeof(struct axp20x_pek),
+				  GFP_KERNEL);
+	if (!axp20x_pek)
+		return -ENOMEM;
+
+	axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent);
+
+	error = axp20x_pek_probe_input_device(axp20x_pek, pdev);
+	if (error)
+		return error;
+
 	error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group);
 	if (error) {
 		dev_err(&pdev->dev, "Failed to create sysfs attributes: %d\n",
@@ -269,13 +287,6 @@ static int axp20x_pek_probe(struct platform_device *pdev)
 		return error;
 	}
 
-	error = input_register_device(idev);
-	if (error) {
-		dev_err(&pdev->dev, "Can't register input device: %d\n",
-			error);
-		return error;
-	}
-
 	platform_set_drvdata(pdev, axp20x_pek);
 
 	return 0;
-- 
2.9.3

Re: [PATCH resend 3/4] Input: axp20x-pek - Do not register input device on some systems

From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Date: 2017-03-08 17:16:16

On Wed, Mar 08, 2017 at 09:54:12AM +0100, Hans de Goede wrote:
quoted hunk
On some systems (Intel tablets with axp288 pmic) the powerbutton is
also connected to a gpio pin of the SoC, advertised through the
"INTCFD9" / "PNP0C40" acpi device. This leads to double reporting
of powerbutton events, which is undesirable, so one driver needs
to not report input events in this case.

Since the soc_button_array driver for the "PNP0C40" acpi device
also handles wake from suspend on these tablets and since the
axp20x-pel driver requires relative expensive i2c accrsses,
it is best for the axp20x-pek driver to not register an input device
in this case.

Note that this commit leaves the axp20x-driver bound to the
device, rather then returning -ENODEV, this is done so that the
sysfs attributes it offers are kept around.

Signed-off-by: Hans de Goede <redacted>
---
 drivers/input/misc/axp20x-pek.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c
index b7258ec..dbd2c89 100644
--- a/drivers/input/misc/axp20x-pek.c
+++ b/drivers/input/misc/axp20x-pek.c
@@ -13,6 +13,7 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/acpi.h>
 #include <linux/errno.h>
 #include <linux/irq.h>
 #include <linux/init.h>
@@ -267,9 +268,16 @@ static int axp20x_pek_probe(struct platform_device *pdev)
 
 	axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent);
 
-	error = axp20x_pek_probe_input_device(axp20x_pek, pdev);
-	if (error)
-		return error;
+	/*
+	 * Do not register the input device if there is an "INTCFD9"
+	 * gpio button ACPI device, that handles the power button too,
+	 * and otherwise we end up reporting all presses twice.
+	 */
+	if (!acpi_dev_found("INTCFD9")) {
Should we also add "|| !IS_ENABLED(CONFIG_INPUT_SOC_BUTTON_ARRAY)"?

No need to resend, just shout if you agree/disagree.
+		error = axp20x_pek_probe_input_device(axp20x_pek, pdev);
+		if (error)
+			return error;
+	}
 
 	error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group);
 	if (error) {
-- 
2.9.3
-- 
Dmitry

Re: [PATCH resend 3/4] Input: axp20x-pek - Do not register input device on some systems

From: Hans de Goede <hidden>
Date: 2017-03-09 07:56:39

Hi,

On 08-03-17 18:16, Dmitry Torokhov wrote:
On Wed, Mar 08, 2017 at 09:54:12AM +0100, Hans de Goede wrote:
quoted
On some systems (Intel tablets with axp288 pmic) the powerbutton is
also connected to a gpio pin of the SoC, advertised through the
"INTCFD9" / "PNP0C40" acpi device. This leads to double reporting
of powerbutton events, which is undesirable, so one driver needs
to not report input events in this case.

Since the soc_button_array driver for the "PNP0C40" acpi device
also handles wake from suspend on these tablets and since the
axp20x-pel driver requires relative expensive i2c accrsses,
it is best for the axp20x-pek driver to not register an input device
in this case.

Note that this commit leaves the axp20x-driver bound to the
device, rather then returning -ENODEV, this is done so that the
sysfs attributes it offers are kept around.

Signed-off-by: Hans de Goede <redacted>
---
 drivers/input/misc/axp20x-pek.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c
index b7258ec..dbd2c89 100644
--- a/drivers/input/misc/axp20x-pek.c
+++ b/drivers/input/misc/axp20x-pek.c
@@ -13,6 +13,7 @@
  * GNU General Public License for more details.
  */

+#include <linux/acpi.h>
 #include <linux/errno.h>
 #include <linux/irq.h>
 #include <linux/init.h>
@@ -267,9 +268,16 @@ static int axp20x_pek_probe(struct platform_device *pdev)

 	axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent);

-	error = axp20x_pek_probe_input_device(axp20x_pek, pdev);
-	if (error)
-		return error;
+	/*
+	 * Do not register the input device if there is an "INTCFD9"
+	 * gpio button ACPI device, that handles the power button too,
+	 * and otherwise we end up reporting all presses twice.
+	 */
+	if (!acpi_dev_found("INTCFD9")) {
Should we also add "|| !IS_ENABLED(CONFIG_INPUT_SOC_BUTTON_ARRAY)"?
That would be a bit of a broken kernel config for the devices in
question, but yeah probably a good idea to add that.

Regards,

Hans

No need to resend, just shout if you agree/disagree.
quoted
+		error = axp20x_pek_probe_input_device(axp20x_pek, pdev);
+		if (error)
+			return error;
+	}

 	error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group);
 	if (error) {
--
2.9.3
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help