Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f38074c3 authored by Shantanu Jain's avatar Shantanu Jain
Browse files

input: keyboard: add syscore_ops support to gpio_key driver



Add syscore_ops support for gpio-keys driver to service
wakeable irq handler before the CPUs resume after
suspend state.

Signed-off-by: default avatarShantanu Jain <shjain@codeaurora.org>
Change-Id: I7fe266661abfd469c68309a66aed0cb0fa2de33e
parent ec7db6c5
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@ Optional properties:
			config defined in pin groups of interrupt and reset gpio.
			"gpio_ts_suspend" : Disabled configuration of pins, this should specify sleep
			config defined in pin groups of interrupt and reset gpio.
	- name		: input device name.
	- use-syscore	: use syscore functionality for driver.

Each button (key) is represented as a sub-node of "gpio-keys":
Subnode properties:
@@ -42,6 +44,7 @@ Example nodes:
			pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
			pinctrl-0 = <&gpio_key_active>;
			pinctrl-1 = <&gpio_key_suspend>;
			use-syscore;
			button@21 {
				label = "GPIO Key UP";
				linux,code = <103>;
+75 −2
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
 *
 * Copyright 2005 Phil Blundell
 * Copyright 2010, 2011 David Jander <david@protonic.nl>
 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
@@ -31,6 +32,7 @@
#include <linux/of_gpio.h>
#include <linux/spinlock.h>
#include <linux/pinctrl/consumer.h>
#include <linux/syscore_ops.h>

struct gpio_button_data {
	const struct gpio_keys_button *button;
@@ -52,6 +54,11 @@ struct gpio_keys_drvdata {
	struct gpio_button_data data[0];
};

static struct device *global_dev;
static struct syscore_ops gpio_keys_syscore_pm_ops;

static void gpio_keys_syscore_resume(void);

/*
 * SYSFS interface for enabling/disabling keys and switches:
 *
@@ -330,7 +337,9 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
	const struct gpio_keys_button *button = bdata->button;
	struct input_dev *input = bdata->input;
	unsigned int type = button->type ?: EV_KEY;
	int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;
	int state;

	state = (__gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;

	if (type == EV_ABS) {
		if (state)
@@ -651,6 +660,8 @@ gpio_keys_get_devtree_pdata(struct device *dev)
	pdata->nbuttons = nbuttons;

	pdata->rep = !!of_get_property(node, "autorepeat", NULL);
	pdata->name = of_get_property(node, "input-name", NULL);
	pdata->use_syscore = of_property_read_bool(node, "use-syscore");

	i = 0;
	for_each_child_of_node(node, pp) {
@@ -749,6 +760,7 @@ static int gpio_keys_probe(struct platform_device *pdev)
		return -ENOMEM;
	}

	global_dev = dev;
	ddata->pdata = pdata;
	ddata->input = input;
	mutex_init(&ddata->disable_lock);
@@ -817,6 +829,11 @@ static int gpio_keys_probe(struct platform_device *pdev)

	device_init_wakeup(&pdev->dev, wakeup);

	if (pdata->use_syscore)
		gpio_keys_syscore_pm_ops.resume = gpio_keys_syscore_resume;

	register_syscore_ops(&gpio_keys_syscore_pm_ops);

	return 0;

err_remove_group:
@@ -839,6 +856,7 @@ err_setup_key:
static int gpio_keys_remove(struct platform_device *pdev)
{
	sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
	unregister_syscore_ops(&gpio_keys_syscore_pm_ops);

	device_init_wakeup(&pdev->dev, 0);

@@ -846,6 +864,41 @@ static int gpio_keys_remove(struct platform_device *pdev)
}

#ifdef CONFIG_PM_SLEEP
static void gpio_keys_syscore_resume(void)
{
	struct gpio_keys_drvdata *ddata = dev_get_drvdata(global_dev);
	struct input_dev *input = ddata->input;
	struct gpio_button_data *bdata = NULL;
	int error = 0;
	int i;

	if (ddata->key_pinctrl) {
		error = gpio_keys_pinctrl_configure(ddata, true);
		if (error) {
			dev_err(global_dev, "failed to put the pin in resume state\n");
			return;
		}
	}

	if (device_may_wakeup(global_dev)) {
		for (i = 0; i < ddata->pdata->nbuttons; i++) {
			bdata = &ddata->data[i];
			if (bdata->button->wakeup)
				disable_irq_wake(bdata->irq);
		}
	} else {
		mutex_lock(&input->mutex);
		if (input->users)
			error = gpio_keys_open(input);
		mutex_unlock(&input->mutex);
	}

	if (error)
		return;

	gpio_keys_report_state(ddata);
}

static int gpio_keys_suspend(struct device *dev)
{
	struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
@@ -883,6 +936,11 @@ static int gpio_keys_resume(struct device *dev)
	int error = 0;
	int i;

	if (ddata->pdata->use_syscore == true) {
		dev_dbg(global_dev, "Using syscore resume, no need of this resume.\n");
		return 0;
	}

	if (ddata->key_pinctrl) {
		error = gpio_keys_pinctrl_configure(ddata, true);
		if (error) {
@@ -910,6 +968,21 @@ static int gpio_keys_resume(struct device *dev)
	gpio_keys_report_state(ddata);
	return 0;
}

#else

static void gpio_keys_syscore_resume(void){}

static int gpio_keys_suspend(struct device *dev)
{
	return 0;
}

static int gpio_keys_resume(struct device *dev)
{
	return 0;
}

#endif

static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
+2 −1
Original line number Diff line number Diff line
@@ -51,7 +51,8 @@ struct gpio_keys_platform_data {
	unsigned int rep:1;
	int (*enable)(struct device *dev);
	void (*disable)(struct device *dev);
	const char *name;
	const char *name;		/* input device name */
	bool use_syscore;
};

#endif