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

Commit a444cab6 authored by Shantanu Jain's avatar Shantanu Jain Committed by Gerrit - the friendly Code Review server
Browse files

input: touchscreen: add suspend-resume and fb support



Add suspend-resume and fb notification support for
ITE tech touchscreen driver.

Change-Id: I9a601412fb9a3935c0eadad5157bb1fd819b29dd
Signed-off-by: default avatarShantanu Jain <shjain@codeaurora.org>
parent 70dede53
Loading
Loading
Loading
Loading
+137 −48
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/of_gpio.h>
#include <linux/fb.h>

#define MAX_BUFFER_SIZE			144
#define DEVICE_NAME			"IT7260"
@@ -99,6 +100,11 @@
/* use this to include integers in commands */
#define CMD_UINT16(v)		((uint8_t)(v)) , ((uint8_t)((v) >> 8))

/* Function declarations */
static int fb_notifier_callback(struct notifier_block *self,
			unsigned long event, void *data);
static int IT7260_ts_resume(struct device *dev);
static int IT7260_ts_suspend(struct device *dev);

struct FingerData {
	uint8_t xLo;
@@ -148,13 +154,14 @@ struct IT7260_ts_data {
	const struct IT7260_ts_platform_data *pdata;
	struct regulator *vdd;
	struct regulator *avdd;
#ifdef CONFIG_FB
	struct notifier_block fb_notif;
#endif
};

static int8_t fwUploadResult;
static int8_t calibrationWasSuccessful;
static bool devicePresent;
static DEFINE_MUTEX(sleepModeMutex);
static bool chipAwake;
static bool hadFingerDown;
static bool isDeviceSuspend;
static struct input_dev *input_dev;
@@ -414,6 +421,21 @@ static bool chipGetVersions(uint8_t *verFw, uint8_t *verCfg, bool logIt)
	return ret;
}

static int IT7260_ts_chipLowPowerMode(bool low)
{
	static const uint8_t cmdGoSleep[] = {CMD_PWR_CTL,
					0x00, PWR_CTL_SLEEP_MODE};
	uint8_t dummy;

	if (low)
		i2cWriteNoReadyCheck(BUF_COMMAND, cmdGoSleep,
					sizeof(cmdGoSleep));
	else
		i2cReadNoReadyCheck(BUF_QUERY, &dummy, sizeof(dummy));

	return 0;
}

static ssize_t sysfsUpgradeStore(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
@@ -586,48 +608,33 @@ static ssize_t sysfsSleepShow(struct device *dev,
	 * leaking a byte of kernel data (by claiming to return a byte but not
	 * writing to buf. To fix this now we actually return the sleep status
	 */
	if (!mutex_lock_interruptible(&sleepModeMutex)) {
		*buf = chipAwake ? '1' : '0';
		mutex_unlock(&sleepModeMutex);
	*buf = isDeviceSuspend ? '1' : '0';
	return 1;
	} else {
		return -EINTR;
	}
}

static ssize_t sysfsSleepStore(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	static const uint8_t cmdGoSleep[] = {CMD_PWR_CTL,
					0x00, PWR_CTL_SLEEP_MODE};
	int goToSleepVal, ret;
	bool goToWake;
	uint8_t dummy;

	ret = kstrtoint(buf, 10, &goToSleepVal);
	/* convert to bool of proper polarity */
	goToWake = !goToSleepVal;

	if (!mutex_lock_interruptible(&sleepModeMutex)) {
		if ((chipAwake && goToWake) || (!chipAwake && !goToWake))
			LOGE("duplicate request to %s chip\n",
				goToWake ? "wake" : "sleep");
		else if (goToWake) {
			i2cReadNoReadyCheck(BUF_QUERY, &dummy, sizeof(dummy));
			enable_irq(gl_ts->client->irq);
			LOGI("touch is going to wake!\n");
		} else {

	if ((isDeviceSuspend && goToSleepVal > 0) || (!isDeviceSuspend &&
							goToSleepVal == 0))
		dev_err(dev, "duplicate request to %s chip\n",
			goToSleepVal ? "sleep" : "wake");
	else if (goToSleepVal) {
		disable_irq(gl_ts->client->irq);
			i2cWriteNoReadyCheck(BUF_COMMAND, cmdGoSleep,
						sizeof(cmdGoSleep));
			LOGI("touch is going to sleep...\n");
		}
		chipAwake = goToWake;
		mutex_unlock(&sleepModeMutex);
		return count;
		IT7260_ts_chipLowPowerMode(true);
		dev_dbg(dev, "touch is going to sleep...\n");
	} else {
		return -EINTR;
		IT7260_ts_chipLowPowerMode(false);
		enable_irq(gl_ts->client->irq);
		dev_dbg(dev, "touch is going to wake!\n");
	}
	isDeviceSuspend = goToSleepVal;

	return count;
}


@@ -684,6 +691,13 @@ void sendCalibrationCmd(void)
}
EXPORT_SYMBOL(sendCalibrationCmd);

static void IT7260_ts_release_all(void)
{
	input_report_key(gl_ts->input_dev, BTN_TOUCH, 0);
	input_mt_sync(gl_ts->input_dev);
	input_sync(gl_ts->input_dev);
}

static void readFingerData(uint16_t *xP, uint16_t *yP, uint8_t *pressureP,
						const struct FingerData *fd)
{
@@ -942,6 +956,7 @@ static int IT7260_ts_probe(struct i2c_client *client,
	set_bit(KEY_POWER,input_dev->keybit);
	input_set_abs_params(input_dev, ABS_X, 0, SCREEN_X_RESOLUTION, 0, 0);
	input_set_abs_params(input_dev, ABS_Y, 0, SCREEN_Y_RESOLUTION, 0, 0);
	input_set_drvdata(gl_ts->input_dev, gl_ts);

	if (input_register_device(input_dev)) {
		LOGE("failed to register input device\n");
@@ -959,6 +974,15 @@ static int IT7260_ts_probe(struct i2c_client *client,
		goto err_sysfs_grp_create_2;
	}

#if defined(CONFIG_FB)
	gl_ts->fb_notif.notifier_call = fb_notifier_callback;

	ret = fb_register_client(&gl_ts->fb_notif);
	if (ret)
		dev_err(&client->dev, "Unable to register fb_notifier: %d\n",
									ret);
#endif
	
	devicePresent = true;

	i2cWriteNoReadyCheck(BUF_COMMAND, cmdStart, sizeof(cmdStart));
@@ -991,45 +1015,110 @@ err_out:

static int IT7260_ts_remove(struct i2c_client *client)
{
#if defined(CONFIG_FB)
	if (fb_unregister_client(&gl_ts->fb_notif))
		dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n");
#endif
	devicePresent = false;
	return 0;
}

static const struct i2c_device_id IT7260_ts_id[] = {
	{ DEVICE_NAME, 0},
	{}
};
#if defined(CONFIG_FB)
static int fb_notifier_callback(struct notifier_block *self,
			unsigned long event, void *data)
{
	struct fb_event *evdata = data;
	int *blank;

MODULE_DEVICE_TABLE(i2c, IT7260_ts_id);
	if (evdata && evdata->data && gl_ts && gl_ts->client) {
		if (event == FB_EVENT_BLANK) {
			blank = evdata->data;
			if (*blank == FB_BLANK_UNBLANK)
				IT7260_ts_resume(&(gl_ts->input_dev->dev));
			else if (*blank == FB_BLANK_POWERDOWN ||
					*blank == FB_BLANK_VSYNC_SUSPEND)
				IT7260_ts_suspend(&(gl_ts->input_dev->dev));
		}
	}

static const struct of_device_id IT7260_match_table[] = {
	{ .compatible = "ite,it7260_ts",},
	{},
};
	return 0;
}
#endif

static int IT7260_ts_resume(struct i2c_client *i2cdev)
#ifdef CONFIG_PM
static int IT7260_ts_resume(struct device *dev)
{
	if (!isDeviceSuspend) {
		dev_info(dev, "Already in resume state\n");
		return 0;
	}

	/* put the device in active powr mode */
	IT7260_ts_chipLowPowerMode(false);

	enable_irq(gl_ts->client->irq);
	isDeviceSuspend	= false;
	return 0;
}

static int IT7260_ts_suspend(struct i2c_client *i2cdev, pm_message_t pmesg)
static int IT7260_ts_suspend(struct device *dev)
{
	if (isDeviceSuspend) {
		dev_info(dev, "Already in suspend state\n");
		return 0;
	}

	disable_irq(gl_ts->client->irq);

	/* put the device in active powr mode */
	IT7260_ts_chipLowPowerMode(true);

	IT7260_ts_release_all();
	isDeviceSuspend = true;

	return 0;
}

static const struct dev_pm_ops IT7260_ts_dev_pm_ops = {
	.suspend = IT7260_ts_suspend,
	.resume  = IT7260_ts_resume,
};
#else
static int IT7260_ts_resume(struct device *dev)
{
	return 0;
}

static int IT7260_ts_suspend(struct device *dev)
{
	return 0;
}
#endif

static const struct i2c_device_id IT7260_ts_id[] = {
	{ DEVICE_NAME, 0},
	{}
};

MODULE_DEVICE_TABLE(i2c, IT7260_ts_id);

static const struct of_device_id IT7260_match_table[] = {
	{ .compatible = "ite,it7260_ts",},
	{},
};

static struct i2c_driver IT7260_ts_driver = {
	.driver = {
		.owner = THIS_MODULE,
		.name = DEVICE_NAME,
		.of_match_table = IT7260_match_table,
#ifdef CONFIG_PM
		.pm = &IT7260_ts_dev_pm_ops,
#endif
	},
	.probe = IT7260_ts_probe,
	.remove = IT7260_ts_remove,
	.id_table = IT7260_ts_id,
	.resume   = IT7260_ts_resume,
	.suspend = IT7260_ts_suspend,
};

module_i2c_driver(IT7260_ts_driver);