aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHungNien Chen <hn.chen@weidahitech.com>2017-04-04 15:32:03 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-04-12 06:41:15 -0400
commitee670af5feede68f0ad22b329626594b8aebefc3 (patch)
treec4b4b3c9cc0237c96aa8fe10898b49a2bb26bd41
parentd640c41bced65d82592e4d01a61715d78dede2ae (diff)
HID: i2c-hid: add a simple quirk to fix device defects
[ Upstream commit 71af01a8c85ad89449209594133bdfdfaa9f1e2a ] Certain devices produced by Weida Tech need to have a wakeup command sent to them before powering on. The call itself will come back with error, but the device can be powered on afterwards. [jkosina@suse.cz: rewrite changelog] [jkosina@suse.cz: remove unused device ID addition] Signed-off-by: HungNien Chen <hn.chen@weidahitech.com> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz> Signed-off-by: Sasha Levin <alexander.levin@verizon.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/hid/hid-ids.h4
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c57
2 files changed, 61 insertions, 0 deletions
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index e95495cd0e82..da42f0ffba3a 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -1039,6 +1039,10 @@
1039#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH 0x0500 1039#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH 0x0500
1040#define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET 0x0502 1040#define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET 0x0502
1041 1041
1042#define USB_VENDOR_ID_WEIDA 0x2575
1043#define USB_DEVICE_ID_WEIDA_8752 0xC300
1044#define USB_DEVICE_ID_WEIDA_8755 0xC301
1045
1042#define USB_VENDOR_ID_WISEGROUP 0x0925 1046#define USB_VENDOR_ID_WISEGROUP 0x0925
1043#define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005 1047#define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005
1044#define USB_DEVICE_ID_SUPER_JOY_BOX_3 0x8888 1048#define USB_DEVICE_ID_SUPER_JOY_BOX_3 0x8888
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index b3ec4f2de875..b1bce804fe97 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -41,6 +41,11 @@
41 41
42#include <linux/i2c/i2c-hid.h> 42#include <linux/i2c/i2c-hid.h>
43 43
44#include "../hid-ids.h"
45
46/* quirks to control the device */
47#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0)
48
44/* flags */ 49/* flags */
45#define I2C_HID_STARTED 0 50#define I2C_HID_STARTED 0
46#define I2C_HID_RESET_PENDING 1 51#define I2C_HID_RESET_PENDING 1
@@ -143,6 +148,7 @@ struct i2c_hid {
143 char *argsbuf; /* Command arguments buffer */ 148 char *argsbuf; /* Command arguments buffer */
144 149
145 unsigned long flags; /* device flags */ 150 unsigned long flags; /* device flags */
151 unsigned long quirks; /* Various quirks */
146 152
147 wait_queue_head_t wait; /* For waiting the interrupt */ 153 wait_queue_head_t wait; /* For waiting the interrupt */
148 struct gpio_desc *desc; 154 struct gpio_desc *desc;
@@ -154,6 +160,39 @@ struct i2c_hid {
154 struct mutex reset_lock; 160 struct mutex reset_lock;
155}; 161};
156 162
163static const struct i2c_hid_quirks {
164 __u16 idVendor;
165 __u16 idProduct;
166 __u32 quirks;
167} i2c_hid_quirks[] = {
168 { USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8752,
169 I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
170 { USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8755,
171 I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
172 { 0, 0 }
173};
174
175/*
176 * i2c_hid_lookup_quirk: return any quirks associated with a I2C HID device
177 * @idVendor: the 16-bit vendor ID
178 * @idProduct: the 16-bit product ID
179 *
180 * Returns: a u32 quirks value.
181 */
182static u32 i2c_hid_lookup_quirk(const u16 idVendor, const u16 idProduct)
183{
184 u32 quirks = 0;
185 int n;
186
187 for (n = 0; i2c_hid_quirks[n].idVendor; n++)
188 if (i2c_hid_quirks[n].idVendor == idVendor &&
189 (i2c_hid_quirks[n].idProduct == (__u16)HID_ANY_ID ||
190 i2c_hid_quirks[n].idProduct == idProduct))
191 quirks = i2c_hid_quirks[n].quirks;
192
193 return quirks;
194}
195
157static int __i2c_hid_command(struct i2c_client *client, 196static int __i2c_hid_command(struct i2c_client *client,
158 const struct i2c_hid_cmd *command, u8 reportID, 197 const struct i2c_hid_cmd *command, u8 reportID,
159 u8 reportType, u8 *args, int args_len, 198 u8 reportType, u8 *args, int args_len,
@@ -346,11 +385,27 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state)
346 385
347 i2c_hid_dbg(ihid, "%s\n", __func__); 386 i2c_hid_dbg(ihid, "%s\n", __func__);
348 387
388 /*
389 * Some devices require to send a command to wakeup before power on.
390 * The call will get a return value (EREMOTEIO) but device will be
391 * triggered and activated. After that, it goes like a normal device.
392 */
393 if (power_state == I2C_HID_PWR_ON &&
394 ihid->quirks & I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV) {
395 ret = i2c_hid_command(client, &hid_set_power_cmd, NULL, 0);
396
397 /* Device was already activated */
398 if (!ret)
399 goto set_pwr_exit;
400 }
401
349 ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state, 402 ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state,
350 0, NULL, 0, NULL, 0); 403 0, NULL, 0, NULL, 0);
404
351 if (ret) 405 if (ret)
352 dev_err(&client->dev, "failed to change power setting.\n"); 406 dev_err(&client->dev, "failed to change power setting.\n");
353 407
408set_pwr_exit:
354 return ret; 409 return ret;
355} 410}
356 411
@@ -1050,6 +1105,8 @@ static int i2c_hid_probe(struct i2c_client *client,
1050 client->name, hid->vendor, hid->product); 1105 client->name, hid->vendor, hid->product);
1051 strlcpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys)); 1106 strlcpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys));
1052 1107
1108 ihid->quirks = i2c_hid_lookup_quirk(hid->vendor, hid->product);
1109
1053 ret = hid_add_device(hid); 1110 ret = hid_add_device(hid);
1054 if (ret) { 1111 if (ret) {
1055 if (ret != -ENODEV) 1112 if (ret != -ENODEV)