summaryrefslogtreecommitdiffstats
path: root/drivers/hid/i2c-hid
diff options
context:
space:
mode:
authorKai-Heng Feng2018-10-05 06:46:29 +0200
committerGreg Kroah-Hartman2018-11-27 16:13:02 +0100
commit48d49b635b66f3017ecd795c211190d6d1beca57 (patch)
tree952c3462dc42cb182997021ca1c8d39a295a63a4 /drivers/hid/i2c-hid
parents390/vdso: add missing FORCE to build targets (diff)
downloadkernel-qcow2-linux-48d49b635b66f3017ecd795c211190d6d1beca57.tar.gz
kernel-qcow2-linux-48d49b635b66f3017ecd795c211190d6d1beca57.tar.xz
kernel-qcow2-linux-48d49b635b66f3017ecd795c211190d6d1beca57.zip
HID: i2c-hid: Add a small delay after sleep command for Raydium touchpanel
[ Upstream commit 00b790ea545b6ef30221adef6e9c3707e03b82b5 ] Raydium touchpanel (2386:4B33) sometimes does not work in desktop session although it works in display manager. During user logging, the display manager exits, close the HID device, then the device gets runtime suspended and powered off. The desktop session begins shortly after, opens the HID device, then the device gets runtime resumed and powered on. If the trasition from display manager to desktop sesesion is fast, the touchpanel cannot switch from powered off to powered on in short timeframe. So add a small delay to workaround the issue. Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'drivers/hid/i2c-hid')
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index 4e3592e7a3f7..88daa388e1f6 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -48,6 +48,7 @@
#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0)
#define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(1)
#define I2C_HID_QUIRK_NO_RUNTIME_PM BIT(2)
+#define I2C_HID_QUIRK_DELAY_AFTER_SLEEP BIT(3)
/* flags */
#define I2C_HID_STARTED 0
@@ -157,6 +158,8 @@ struct i2c_hid {
bool irq_wake_enabled;
struct mutex reset_lock;
+
+ unsigned long sleep_delay;
};
static const struct i2c_hid_quirks {
@@ -171,6 +174,8 @@ static const struct i2c_hid_quirks {
{ I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288,
I2C_HID_QUIRK_NO_IRQ_AFTER_RESET |
I2C_HID_QUIRK_NO_RUNTIME_PM },
+ { I2C_VENDOR_ID_RAYDIUM, I2C_PRODUCT_ID_RAYDIUM_4B33,
+ I2C_HID_QUIRK_DELAY_AFTER_SLEEP },
{ 0, 0 }
};
@@ -386,6 +391,7 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
int ret;
+ unsigned long now, delay;
i2c_hid_dbg(ihid, "%s\n", __func__);
@@ -403,9 +409,22 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state)
goto set_pwr_exit;
}
+ if (ihid->quirks & I2C_HID_QUIRK_DELAY_AFTER_SLEEP &&
+ power_state == I2C_HID_PWR_ON) {
+ now = jiffies;
+ if (time_after(ihid->sleep_delay, now)) {
+ delay = jiffies_to_usecs(ihid->sleep_delay - now);
+ usleep_range(delay, delay + 1);
+ }
+ }
+
ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state,
0, NULL, 0, NULL, 0);
+ if (ihid->quirks & I2C_HID_QUIRK_DELAY_AFTER_SLEEP &&
+ power_state == I2C_HID_PWR_SLEEP)
+ ihid->sleep_delay = jiffies + msecs_to_jiffies(20);
+
if (ret)
dev_err(&client->dev, "failed to change power setting.\n");