summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/it7258_ts_i2c.txt2
-rw-r--r--drivers/input/touchscreen/it7258_ts_i2c.c99
2 files changed, 82 insertions, 19 deletions
diff --git a/Documentation/devicetree/bindings/input/touchscreen/it7258_ts_i2c.txt b/Documentation/devicetree/bindings/input/touchscreen/it7258_ts_i2c.txt
index 0c41e9e31d9b..ac59a0950f8a 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/it7258_ts_i2c.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/it7258_ts_i2c.txt
@@ -21,6 +21,7 @@ Required properties:
Optional properties:
- avdd-supply : Analog power supply needed to power device
- vdd-supply : Power source required to pull up i2c bus
+ - ite,wakeup : boolean, use this to support touch-to-wake feature.
Example:
i2c@f9927000 {
@@ -33,5 +34,6 @@ Example:
vdd-supply = <&pm8226_lvs1>;
ite,reset-gpio = <&msmgpio 16 0x00>;
ite,irq-gpio = <&msmgpio 17 0x2008>;
+ ite,wakeup;
};
};
diff --git a/drivers/input/touchscreen/it7258_ts_i2c.c b/drivers/input/touchscreen/it7258_ts_i2c.c
index c2b77472446b..61028e1b1d88 100644
--- a/drivers/input/touchscreen/it7258_ts_i2c.c
+++ b/drivers/input/touchscreen/it7258_ts_i2c.c
@@ -148,6 +148,7 @@ struct IT7260_ts_platform_data {
u32 irq_gpio_flags;
u32 reset_gpio;
u32 reset_gpio_flags;
+ bool wakeup;
};
struct IT7260_ts_data {
@@ -156,6 +157,9 @@ struct IT7260_ts_data {
const struct IT7260_ts_platform_data *pdata;
struct regulator *vdd;
struct regulator *avdd;
+ bool device_needs_wakeup;
+ bool suspended;
+ struct work_struct work_pm_relax;
#ifdef CONFIG_FB
struct notifier_block fb_notif;
#endif
@@ -166,7 +170,6 @@ static int8_t fwUploadResult;
static int8_t calibrationWasSuccessful;
static bool devicePresent;
static bool hadFingerDown;
-static bool isDeviceSuspend;
static struct input_dev *input_dev;
static struct IT7260_ts_data *gl_ts;
@@ -185,7 +188,7 @@ static int IT7260_debug_suspend_set(void *_data, u64 val)
static int IT7260_debug_suspend_get(void *_data, u64 *val)
{
- *val = isDeviceSuspend;
+ *val = gl_ts->suspended;
return 0;
}
@@ -631,22 +634,27 @@ 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
*/
- *buf = isDeviceSuspend ? '1' : '0';
+ *buf = gl_ts->suspended ? '1' : '0';
return 1;
}
static ssize_t sysfsSleepStore(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- int goToSleepVal, ret;
+ int go_to_sleep, ret;
ret = kstrtoint(buf, 10, &goToSleepVal);
- if ((isDeviceSuspend && goToSleepVal > 0) || (!isDeviceSuspend &&
- goToSleepVal == 0))
+ /* (gl_ts->suspended == true && goToSleepVal > 0) means
+ * device is already suspended and you want it to be in sleep,
+ * (gl_ts->suspended == false && goToSleepVal == 0) means
+ * device is already active and you also want it to be active.
+ */
+ if ((gl_ts->suspended && go_to_sleep > 0) ||
+ (!gl_ts->suspended && go_to_sleep == 0))
dev_err(dev, "duplicate request to %s chip\n",
- goToSleepVal ? "sleep" : "wake");
- else if (goToSleepVal) {
+ go_to_sleep ? "sleep" : "wake");
+ else if (go_to_sleep) {
disable_irq(gl_ts->client->irq);
IT7260_ts_chipLowPowerMode(true);
dev_dbg(dev, "touch is going to sleep...\n");
@@ -655,12 +663,11 @@ static ssize_t sysfsSleepStore(struct device *dev,
enable_irq(gl_ts->client->irq);
dev_dbg(dev, "touch is going to wake!\n");
}
- isDeviceSuspend = goToSleepVal;
+ gl_ts->suspended = go_to_sleep;
return count;
}
-
static DEVICE_ATTR(status, S_IRUGO|S_IWUSR|S_IWGRP,
sysfsStatusShow, sysfsStatusStore);
static DEVICE_ATTR(version, S_IRUGO|S_IWUSR|S_IWGRP,
@@ -745,6 +752,23 @@ static irqreturn_t IT7260_ts_threaded_handler(int irq, void *devid)
uint8_t pressure = FD_PRESSURE_NONE;
uint16_t x, y;
+ /* This code adds the touch-to-wake functioanlity to the ITE tech
+ * driver. When the device is in suspend driver, it sends the
+ * KEY_WAKEUP event to wake the device. The pm_stay_awake() call
+ * tells the pm core to stay awake until the CPU cores up already. The
+ * schedule_work() call schedule a work that tells the pm core to relax
+ * once the CPU cores are up.
+ */
+ if (gl_ts->device_needs_wakeup) {
+ pm_stay_awake(&gl_ts->client->dev);
+ gl_ts->device_needs_wakeup = false;
+ input_report_key(gl_ts->input_dev, KEY_WAKEUP, 1);
+ input_sync(gl_ts->input_dev);
+ input_report_key(gl_ts->input_dev, KEY_WAKEUP, 0);
+ input_sync(gl_ts->input_dev);
+ schedule_work(&gl_ts->work_pm_relax);
+ }
+
/* verify there is point data to read & it is readable and valid */
i2cReadNoReadyCheck(BUF_QUERY, &devStatus, sizeof(devStatus));
if (!((devStatus & PT_INFO_BITS) & PT_INFO_YES)) {
@@ -791,6 +815,11 @@ static irqreturn_t IT7260_ts_threaded_handler(int irq, void *devid)
return IRQ_HANDLED;
}
+static void IT7260_ts_work_func(struct work_struct *work)
+{
+ pm_relax(&gl_ts->client->dev);
+}
+
static bool chipIdentifyIT7260(void)
{
static const uint8_t cmdIdent[] = {CMD_IDENT_CHIP};
@@ -949,6 +978,9 @@ static int IT7260_ts_probe(struct i2c_client *client,
return pdata->irq_gpio;
}
+ pdata->wakeup = of_property_read_bool(client->dev.of_node,
+ "ite,wakeup");
+
if (!chipIdentifyIT7260()) {
LOGI("chipIdentifyIT7260 FAIL");
goto err_ident_fail_or_input_alloc;
@@ -973,7 +1005,6 @@ static int IT7260_ts_probe(struct i2c_client *client,
set_bit(INPUT_PROP_DIRECT,input_dev->propbit);
set_bit(BTN_TOUCH, input_dev->keybit);
set_bit(KEY_SLEEP,input_dev->keybit);
- set_bit(KEY_WAKEUP,input_dev->keybit);
set_bit(KEY_POWER,input_dev->keybit);
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
SCREEN_X_RESOLUTION, 0, 0);
@@ -981,6 +1012,12 @@ static int IT7260_ts_probe(struct i2c_client *client,
SCREEN_Y_RESOLUTION, 0, 0);
input_set_drvdata(gl_ts->input_dev, gl_ts);
+ if (pdata->wakeup) {
+ set_bit(KEY_WAKEUP, gl_ts->input_dev->keybit);
+ INIT_WORK(&gl_ts->work_pm_relax, IT7260_ts_work_func);
+ device_init_wakeup(&client->dev, pdata->wakeup);
+ }
+
if (input_register_device(input_dev)) {
LOGE("failed to register input device\n");
goto err_input_register;
@@ -1051,6 +1088,10 @@ err_irq_reg:
input_dev = NULL;
err_input_register:
+ if (pdata->wakeup) {
+ cancel_work_sync(&gl_ts->work_pm_relax);
+ device_init_wakeup(&client->dev, false);
+ }
if (input_dev)
input_free_device(input_dev);
@@ -1072,6 +1113,10 @@ static int IT7260_ts_remove(struct i2c_client *client)
dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n");
#endif
sysfs_remove_group(&(client->dev.kobj), &it7260_attr_group);
+ if (gl_ts->pdata->wakeup) {
+ cancel_work_sync(&gl_ts->work_pm_relax);
+ device_init_wakeup(&client->dev, false);
+ }
devicePresent = false;
return 0;
}
@@ -1087,10 +1132,10 @@ static int fb_notifier_callback(struct notifier_block *self,
if (event == FB_EVENT_BLANK) {
blank = evdata->data;
if (*blank == FB_BLANK_UNBLANK)
- IT7260_ts_resume(&(gl_ts->input_dev->dev));
+ IT7260_ts_resume(&(gl_ts->client->dev));
else if (*blank == FB_BLANK_POWERDOWN ||
*blank == FB_BLANK_VSYNC_SUSPEND)
- IT7260_ts_suspend(&(gl_ts->input_dev->dev));
+ IT7260_ts_suspend(&(gl_ts->client->dev));
}
}
@@ -1101,33 +1146,49 @@ static int fb_notifier_callback(struct notifier_block *self,
#ifdef CONFIG_PM
static int IT7260_ts_resume(struct device *dev)
{
- if (!isDeviceSuspend) {
+ if (!gl_ts->suspended) {
dev_info(dev, "Already in resume state\n");
return 0;
}
- /* put the device in active powr mode */
+ if (device_may_wakeup(dev)) {
+ if (gl_ts->device_needs_wakeup) {
+ gl_ts->device_needs_wakeup = false;
+ disable_irq_wake(gl_ts->client->irq);
+ }
+ return 0;
+ }
+
+ /* put the device in active power mode */
IT7260_ts_chipLowPowerMode(false);
enable_irq(gl_ts->client->irq);
- isDeviceSuspend = false;
+ gl_ts->suspended = false;
return 0;
}
static int IT7260_ts_suspend(struct device *dev)
{
- if (isDeviceSuspend) {
+ if (gl_ts->suspended) {
dev_info(dev, "Already in suspend state\n");
return 0;
}
+ if (device_may_wakeup(dev)) {
+ if (!gl_ts->device_needs_wakeup) {
+ gl_ts->device_needs_wakeup = true;
+ enable_irq_wake(gl_ts->client->irq);
+ }
+ return 0;
+ }
+
disable_irq(gl_ts->client->irq);
- /* put the device in active powr mode */
+ /* put the device in low power mode */
IT7260_ts_chipLowPowerMode(true);
IT7260_ts_release_all();
- isDeviceSuspend = true;
+ gl_ts->suspended = true;
return 0;
}