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

Commit a31a1c27 authored by Alex Saiko's avatar Alex Saiko Committed by Razziell
Browse files

input: Introduce State Notifier (adapted for markw)



This driver is used to help another drivers handle different tasks
for different device's states (active/suspended). It gets the current
state from reliable source (MDSS Panel in this case) and exports it
to kernel space.

This can become a reliable generic replacement for LCD Notify.

Change-Id: Ie41a96e201dff8e80bbb7d4f98f01a1c2131f565
Signed-off-by: default avatarPranav Vashi <neobuddy89@gmail.com>
Signed-off-by: default avatarAlex Saiko <solcmdr@gmail.com>
parent 178ab59e
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -1171,6 +1171,20 @@ config TOUCHSCREEN_MAXIM_STI
	  To compile this driver as a module, choose M here: the
	  module will be called maxim_sti.


config TOUCHSCREEN_STATE_NOTIFIER
	bool "Notify screen state to touch driver"
	depends on FB_MSM_MDSS
	default y
	help
	  Report the current screen state (Active/Suspended) to kernel
	  space. This could be used by another kernel (and user) space
	  drivers to handle some simple tasks depending on the device's
	  current state.

	  Note that State Notifier uses 5 seconds delay (by default)
	  before swithcing to STATE_SUSPEND.

source "drivers/input/touchscreen/gt9xx/Kconfig"

config TOUCHSCREEN_FT5346
+1 −0
Original line number Diff line number Diff line
@@ -96,3 +96,4 @@ obj-$(CONFIG_TOUCHSCREEN_FT5435) += ft5435/
obj-$(CONFIG_TOUCHSCREEN_IST3038C)       += ist3038c/
obj-$(CONFIG_TOUCHSCREEN_GT9XX)		+= gt9xx/
obj-$(CONFIG_TOUCHSCREEN_GT9XX_MIDO)    += gt9xx_mido/
obj-$(CONFIG_TOUCHSCREEN_STATE_NOTIFIER) += state_notifier.o
+188 −0
Original line number Diff line number Diff line
/*
 * Touchscreen State Notifier
 *
 * Copyright (C) 2013-2017, Pranav Vashi <neobuddy89@gmail.com>
 * Copyright (C) 2017, Alex Saiko <solcmdr@gmail.com>
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/export.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/input/state_notifier.h>

#define DEFAULT_SUSPEND_DEFER_TIME	5
#define TAG				"state_notifier"

bool state_suspended;
module_param_named(state_suspended, state_suspended, bool, 0444);

struct work_struct resume_work;
static struct delayed_work suspend_work;
static struct workqueue_struct *susp_wq;
static struct kobject *state_notifier_kobj;

static bool suspend_in_progress;
static unsigned int suspend_defer_time = DEFAULT_SUSPEND_DEFER_TIME;

static BLOCKING_NOTIFIER_HEAD(state_notifier_list);

/**
 * state_register_client - register a client notifier
 * @nb: notifier block to callback on events
 */
int state_register_client(struct notifier_block *nb)
{
	return blocking_notifier_chain_register(&state_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(state_register_client);

/**
 * state_unregister_client - unregister a client notifier
 * @nb: notifier block to callback on events
 */
int state_unregister_client(struct notifier_block *nb)
{
	return blocking_notifier_chain_unregister(&state_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(state_unregister_client);

/**
 * state_notifier_call_chain - notify clients on state_events
 * @val: Value passed unmodified to notifier function
 * @v: pointer passed unmodified to notifier function
 */
int state_notifier_call_chain(unsigned long val, void *v)
{
	return blocking_notifier_call_chain(&state_notifier_list, val, v);
}
EXPORT_SYMBOL_GPL(state_notifier_call_chain);

static void __suspend_work(struct work_struct *work)
{
	state_notifier_call_chain(STATE_NOTIFIER_SUSPEND, NULL);
	msleep_interruptible(50);

	state_suspended = true;
	suspend_in_progress = false;

	pr_info("%s: successfully suspended\n", TAG);
}

static void __resume_work(struct work_struct *work)
{
	state_notifier_call_chain(STATE_NOTIFIER_ACTIVE, NULL);
	msleep_interruptible(50);

	state_suspended = false;

	pr_info("%s: successfully resumed\n", TAG);
}

void state_suspend(void)
{
	pr_info("%s: going into suspend\n", TAG);

	if (state_suspended || suspend_in_progress)
		return;

	suspend_in_progress = true;

	queue_delayed_work_on(0, susp_wq, &suspend_work,
		msecs_to_jiffies(suspend_defer_time * 1000));
}
EXPORT_SYMBOL_GPL(state_suspend);

void state_resume(void)
{
	pr_info("%s: resuming\n", TAG);

	cancel_delayed_work_sync(&suspend_work);
	suspend_in_progress = false;

	if (state_suspended)
		queue_work_on(0, susp_wq, &resume_work);
}
EXPORT_SYMBOL_GPL(state_resume);

static ssize_t show_suspend_defer_time(struct kobject *kobj,
				       struct kobj_attribute *attr,
				       char *buf)
{
	return scnprintf(buf, SZ_8, "%d\n", suspend_defer_time);
}

static ssize_t store_suspend_defer_time(struct kobject *kobj,
					struct kobj_attribute *attr,
					const char *buf, size_t count)
{
	int ret, val;

	ret = sscanf(buf, "%d", &val);
	if (ret != 1 || val < 0 || val > 30 ||
	    val == suspend_defer_time)
		return -EINVAL;

	suspend_defer_time = val;

	return count;
}

static struct kobj_attribute suspend_defer_time_attribute =
	__ATTR(suspend_defer_time, S_IWUSR | S_IRUGO,
		show_suspend_defer_time, store_suspend_defer_time);

static struct attribute *state_notifier_attrs[] = {
	&suspend_defer_time_attribute.attr,
	NULL,
};

static struct attribute_group state_notifier_attr_group = {
	.attrs = state_notifier_attrs,
};

static int __init state_notifier_init(void)
{
	int ret = -EFAULT;

	susp_wq = create_singlethread_workqueue("state_susp_wq");
	if (!susp_wq) {
		pr_err("%s: unable to allocate workqueue\n", TAG);
		goto fail;
	}

	state_notifier_kobj = kobject_create_and_add("state_notifier",
						kernel_kobj);
	if (!state_notifier_kobj) {
		pr_err("%s: unable to create kobject\n", TAG);
		goto fail;
	}

	ret = sysfs_create_group(state_notifier_kobj,
				&state_notifier_attr_group);
	if (ret) {
		pr_err("%s: unable to create sysfs group\n", TAG);
		kobject_put(state_notifier_kobj);
		goto fail;
	}

	INIT_DELAYED_WORK(&suspend_work, __suspend_work);
	INIT_WORK(&resume_work, __resume_work);

fail:
	return ret;
}

subsys_initcall(state_notifier_init);

MODULE_AUTHOR("Pranav Vashi <neobuddy89@gmail.com>");
MODULE_DESCRIPTION("State notifier module");
MODULE_LICENSE("GPLv2");
+10 −0
Original line number Diff line number Diff line
@@ -27,6 +27,10 @@
#include <linux/msm-bus.h>
#include <linux/pm_qos.h>

#ifdef CONFIG_TOUCHSCREEN_STATE_NOTIFIER
#include <linux/input/state_notifier.h>
#endif

#include "mdss.h"
#include "mdss_panel.h"
#include "mdss_dsi.h"
@@ -2671,6 +2675,9 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
		ctrl_pdata->ctrl_state |= CTRL_STATE_MDP_ACTIVE;
		if (ctrl_pdata->on_cmds.link_state == DSI_HS_MODE)
			rc = mdss_dsi_unblank(pdata);
#ifdef CONFIG_TOUCHSCREEN_STATE_NOTIFIER
		state_resume();
#endif
		pdata->panel_info.esd_rdy = true;
		break;
	case MDSS_EVENT_BLANK:
@@ -2685,6 +2692,9 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
		if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE)
			rc = mdss_dsi_blank(pdata, power_state);
		rc = mdss_dsi_off(pdata, power_state);
#ifdef CONFIG_TOUCHSCREEN_STATE_NOTIFIER
		state_suspend();
#endif
		break;
	case MDSS_EVENT_CONT_SPLASH_FINISH:
		if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE)
+35 −0
Original line number Diff line number Diff line
/*
 * Touchscreen State Notifier
 *
 * Copyright (C) 2013-2017, Pranav Vashi <neobuddy89@gmail.com>
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef __TOUCHSCEEEN_STATE_NOTIFIER__
#define __TOUCHSCEEEN_STATE_NOTIFIER__

#include <linux/notifier.h>

#define STATE_NOTIFIER_ACTIVE		0x01
#define STATE_NOTIFIER_SUSPEND		0x02

struct state_event {
	void *data;
};

extern bool state_suspended;
extern void state_suspend(void);
extern void state_resume(void);
int state_register_client(struct notifier_block *nb);
int state_unregister_client(struct notifier_block *nb);
int state_notifier_call_chain(unsigned long val, void *v);

#endif /* __TOUCHSCEEEN_STATE_NOTIFIER__ */