From bce23786d0bf606326b7acd752017732da896d11 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Thu, 1 Feb 2018 11:42:08 +0800 Subject: touchpad_elan: Power off when USB is suspended without wake touchpad can be powered off when the USB interface is disabled without setting the remote wake feature (USB_REQ_FEATURE_DEVICE_REMOTE_WAKEUP), as events would be ignored anyway. BRANCH=none BUG=b:72683995 TEST=touchpad is disabled when lid is closed. Change-Id: I688fce16ab8c75330e588ec130fb2aa499fc0ed1 Signed-off-by: Nicolas Boichat Reviewed-on: https://chromium-review.googlesource.com/897069 Reviewed-by: Vincent Palatin --- driver/touchpad_elan.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) (limited to 'driver') diff --git a/driver/touchpad_elan.c b/driver/touchpad_elan.c index 9c5a924239..d8bf402ea4 100644 --- a/driver/touchpad_elan.c +++ b/driver/touchpad_elan.c @@ -16,6 +16,7 @@ #include "touchpad.h" #include "update_fw.h" #include "util.h" +#include "usb_api.h" #include "usb_hid_touchpad.h" /* Console output macros */ @@ -23,6 +24,9 @@ #define CPRINTF(format, args...) cprintf(CC_TOUCHPAD, format, ## args) #define CPRINTS(format, args...) cprints(CC_TOUCHPAD, format, ## args) +#define TASK_EVENT_POWERON TASK_EVENT_CUSTOM(1) +#define TASK_EVENT_POWEROFF TASK_EVENT_CUSTOM(2) + /******************************************************************************/ /* How to talk to the controller */ /******************************************************************************/ @@ -43,10 +47,13 @@ #define ETP_I2C_RESOLUTION_CMD 0x0108 #define ETP_I2C_PRESSURE_CMD 0x010A #define ETP_I2C_SET_CMD 0x0300 +#define ETP_I2C_POWER_CMD 0x0307 #define ETP_I2C_FW_CHECKSUM_CMD 0x030F #define ETP_ENABLE_ABS 0x0001 +#define ETP_DISABLE_POWER 0x0001 + #define ETP_I2C_REPORT_LEN 34 #define ETP_MAX_FINGERS 5 @@ -136,6 +143,35 @@ static int elan_tp_write_cmd(uint16_t reg, uint16_t val) return rv; } +/* Power is on by default. */ +static int elan_tp_power = 1; + +static int elan_tp_set_power(int enable) +{ + int rv; + uint16_t val; + + if ((enable && elan_tp_power) || (!enable && !elan_tp_power)) + return EC_SUCCESS; + + CPRINTS("elan TP power %s", enable ? "on" : "off"); + + rv = elan_tp_read_cmd(ETP_I2C_POWER_CMD, &val); + if (rv) + goto out; + + if (enable) + val &= ~ETP_DISABLE_POWER; + else + val |= ETP_DISABLE_POWER; + + rv = elan_tp_write_cmd(ETP_I2C_POWER_CMD, val); + + elan_tp_power = enable; +out: + return rv; +} + static int finger_status[ETP_MAX_FINGERS] = {0}; /* @@ -677,11 +713,34 @@ void touchpad_interrupt(enum gpio_signal signal) void touchpad_task(void *u) { + uint32_t event; + elan_tp_init(); while (1) { - task_wait_event(-1); + event = task_wait_event(-1); + + if (event & TASK_EVENT_WAKE) + elan_tp_read_report_retry(); - elan_tp_read_report_retry(); + if (event & TASK_EVENT_POWERON) + elan_tp_set_power(1); + else if (event & TASK_EVENT_POWEROFF) + elan_tp_set_power(0); } } + +#ifdef CONFIG_USB_SUSPEND +static void touchpad_usb_pm_change(void) +{ + /* + * If USB interface is suspended, and host is not asking us to do remote + * wakeup, we can turn off the touchpad. + */ + if (usb_is_suspended() && !usb_is_remote_wakeup_enabled()) + task_set_event(TASK_ID_TOUCHPAD, TASK_EVENT_POWEROFF, 0); + else + task_set_event(TASK_ID_TOUCHPAD, TASK_EVENT_POWERON, 0); +} +DECLARE_HOOK(HOOK_USB_PM_CHANGE, touchpad_usb_pm_change, HOOK_PRIO_DEFAULT); +#endif -- cgit v1.2.1