diff options
author | HungNien Chen <hn.chen@weidahitech.com> | 2017-04-04 15:32:03 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-04-12 06:41:15 -0400 |
commit | ee670af5feede68f0ad22b329626594b8aebefc3 (patch) | |
tree | c4b4b3c9cc0237c96aa8fe10898b49a2bb26bd41 | |
parent | d640c41bced65d82592e4d01a61715d78dede2ae (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.h | 4 | ||||
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid.c | 57 |
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 | ||
163 | static 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 | */ | ||
182 | static 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 | |||
157 | static int __i2c_hid_command(struct i2c_client *client, | 196 | static 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 | ||
408 | set_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) |