aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHungNien Chen <hn.chen@weidahitech.com>2016-11-09 22:47:13 -0500
committerJiri Kosina <jkosina@suse.cz>2016-11-10 04:23:31 -0500
commit71af01a8c85ad89449209594133bdfdfaa9f1e2a (patch)
tree59ed8a66644bc22e2c94ef470ffe05ff50598218
parent93d26aeab54cc91119760bc4f1f22bff9a987d70 (diff)
HID: i2c-hid: add a simple quirk to fix device defects
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>
-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 cd59c79eebdd..c36ec6d01b8b 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -1030,6 +1030,10 @@
1030#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH 0x0500 1030#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH 0x0500
1031#define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET 0x0502 1031#define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET 0x0502
1032 1032
1033#define USB_VENDOR_ID_WEIDA 0x2575
1034#define USB_DEVICE_ID_WEIDA_8752 0xC300
1035#define USB_DEVICE_ID_WEIDA_8755 0xC301
1036
1033#define USB_VENDOR_ID_WISEGROUP 0x0925 1037#define USB_VENDOR_ID_WISEGROUP 0x0925
1034#define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005 1038#define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005
1035#define USB_DEVICE_ID_SUPER_JOY_BOX_3 0x8888 1039#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 fe6b4e0eab4a..ce518795cb30 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -40,6 +40,11 @@
40 40
41#include <linux/i2c/i2c-hid.h> 41#include <linux/i2c/i2c-hid.h>
42 42
43#include "../hid-ids.h"
44
45/* quirks to control the device */
46#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0)
47
43/* flags */ 48/* flags */
44#define I2C_HID_STARTED 0 49#define I2C_HID_STARTED 0
45#define I2C_HID_RESET_PENDING 1 50#define I2C_HID_RESET_PENDING 1
@@ -142,6 +147,7 @@ struct i2c_hid {
142 char *argsbuf; /* Command arguments buffer */ 147 char *argsbuf; /* Command arguments buffer */
143 148
144 unsigned long flags; /* device flags */ 149 unsigned long flags; /* device flags */
150 unsigned long quirks; /* Various quirks */
145 151
146 wait_queue_head_t wait; /* For waiting the interrupt */ 152 wait_queue_head_t wait; /* For waiting the interrupt */
147 153
@@ -151,6 +157,39 @@ struct i2c_hid {
151 struct mutex reset_lock; 157 struct mutex reset_lock;
152}; 158};
153 159
160static const struct i2c_hid_quirks {
161 __u16 idVendor;
162 __u16 idProduct;
163 __u32 quirks;
164} i2c_hid_quirks[] = {
165 { USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8752,
166 I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
167 { USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8755,
168 I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
169 { 0, 0 }
170};
171
172/*
173 * i2c_hid_lookup_quirk: return any quirks associated with a I2C HID device
174 * @idVendor: the 16-bit vendor ID
175 * @idProduct: the 16-bit product ID
176 *
177 * Returns: a u32 quirks value.
178 */
179static u32 i2c_hid_lookup_quirk(const u16 idVendor, const u16 idProduct)
180{
181 u32 quirks = 0;
182 int n;
183
184 for (n = 0; i2c_hid_quirks[n].idVendor; n++)
185 if (i2c_hid_quirks[n].idVendor == idVendor &&
186 (i2c_hid_quirks[n].idProduct == (__u16)HID_ANY_ID ||
187 i2c_hid_quirks[n].idProduct == idProduct))
188 quirks = i2c_hid_quirks[n].quirks;
189
190 return quirks;
191}
192
154static int __i2c_hid_command(struct i2c_client *client, 193static int __i2c_hid_command(struct i2c_client *client,
155 const struct i2c_hid_cmd *command, u8 reportID, 194 const struct i2c_hid_cmd *command, u8 reportID,
156 u8 reportType, u8 *args, int args_len, 195 u8 reportType, u8 *args, int args_len,
@@ -343,11 +382,27 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state)
343 382
344 i2c_hid_dbg(ihid, "%s\n", __func__); 383 i2c_hid_dbg(ihid, "%s\n", __func__);
345 384
385 /*
386 * Some devices require to send a command to wakeup before power on.
387 * The call will get a return value (EREMOTEIO) but device will be
388 * triggered and activated. After that, it goes like a normal device.
389 */
390 if (power_state == I2C_HID_PWR_ON &&
391 ihid->quirks & I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV) {
392 ret = i2c_hid_command(client, &hid_set_power_cmd, NULL, 0);
393
394 /* Device was already activated */
395 if (!ret)
396 goto set_pwr_exit;
397 }
398
346 ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state, 399 ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state,
347 0, NULL, 0, NULL, 0); 400 0, NULL, 0, NULL, 0);
401
348 if (ret) 402 if (ret)
349 dev_err(&client->dev, "failed to change power setting.\n"); 403 dev_err(&client->dev, "failed to change power setting.\n");
350 404
405set_pwr_exit:
351 return ret; 406 return ret;
352} 407}
353 408
@@ -1032,6 +1087,8 @@ static int i2c_hid_probe(struct i2c_client *client,
1032 client->name, hid->vendor, hid->product); 1087 client->name, hid->vendor, hid->product);
1033 strlcpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys)); 1088 strlcpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys));
1034 1089
1090 ihid->quirks = i2c_hid_lookup_quirk(hid->vendor, hid->product);
1091
1035 ret = hid_add_device(hid); 1092 ret = hid_add_device(hid);
1036 if (ret) { 1093 if (ret) {
1037 if (ret != -ENODEV) 1094 if (ret != -ENODEV)