Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'for-6.6/nvidia' into for-linus

LED fixes and Battery support for the Nvidia Shield by
Rahul Rameshbabu

+406 -20
+406 -20
drivers/hid/hid-nvidia-shield.c
··· 6 6 */ 7 7 8 8 #include <linux/hid.h> 9 + #include <linux/idr.h> 9 10 #include <linux/input-event-codes.h> 10 11 #include <linux/input.h> 12 + #include <linux/jiffies.h> 11 13 #include <linux/leds.h> 12 14 #include <linux/module.h> 15 + #include <linux/power_supply.h> 13 16 #include <linux/spinlock.h> 17 + #include <linux/timer.h> 14 18 #include <linux/workqueue.h> 15 19 16 20 #include "hid-ids.h" ··· 34 30 enum { 35 31 SHIELD_FW_VERSION_INITIALIZED = 0, 36 32 SHIELD_BOARD_INFO_INITIALIZED, 33 + SHIELD_BATTERY_STATS_INITIALIZED, 34 + SHIELD_CHARGER_STATE_INITIALIZED, 37 35 }; 38 36 39 37 enum { ··· 43 37 THUNDERSTRIKE_BOARD_INFO_UPDATE, 44 38 THUNDERSTRIKE_HAPTICS_UPDATE, 45 39 THUNDERSTRIKE_LED_UPDATE, 40 + THUNDERSTRIKE_POWER_SUPPLY_STATS_UPDATE, 46 41 }; 47 42 48 43 enum { ··· 55 48 enum { 56 49 THUNDERSTRIKE_HOSTCMD_ID_FW_VERSION = 1, 57 50 THUNDERSTRIKE_HOSTCMD_ID_LED = 6, 51 + THUNDERSTRIKE_HOSTCMD_ID_BATTERY, 58 52 THUNDERSTRIKE_HOSTCMD_ID_BOARD_INFO = 16, 59 53 THUNDERSTRIKE_HOSTCMD_ID_USB_INIT = 53, 60 54 THUNDERSTRIKE_HOSTCMD_ID_HAPTICS = 57, 61 - THUNDERSTRIKE_HOSTCMD_ID_BLUETOOTH_INIT = 58, 55 + THUNDERSTRIKE_HOSTCMD_ID_CHARGER, 56 + }; 57 + 58 + struct power_supply_dev { 59 + struct power_supply *psy; 60 + struct power_supply_desc desc; 61 + }; 62 + 63 + struct thunderstrike_psy_prop_values { 64 + int voltage_min; 65 + int voltage_now; 66 + int voltage_avg; 67 + int voltage_boot; 68 + int capacity; 69 + int status; 70 + int charge_type; 71 + int temp; 72 + }; 73 + 74 + static const enum power_supply_property thunderstrike_battery_props[] = { 75 + POWER_SUPPLY_PROP_STATUS, 76 + POWER_SUPPLY_PROP_CHARGE_TYPE, 77 + POWER_SUPPLY_PROP_PRESENT, 78 + POWER_SUPPLY_PROP_VOLTAGE_MIN, 79 + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 80 + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, 81 + POWER_SUPPLY_PROP_VOLTAGE_NOW, 82 + POWER_SUPPLY_PROP_VOLTAGE_AVG, 83 + POWER_SUPPLY_PROP_VOLTAGE_BOOT, 84 + POWER_SUPPLY_PROP_CAPACITY, 85 + POWER_SUPPLY_PROP_SCOPE, 86 + POWER_SUPPLY_PROP_TEMP, 87 + POWER_SUPPLY_PROP_TEMP_MIN, 88 + POWER_SUPPLY_PROP_TEMP_MAX, 89 + POWER_SUPPLY_PROP_TEMP_ALERT_MIN, 90 + POWER_SUPPLY_PROP_TEMP_ALERT_MAX, 62 91 }; 63 92 64 93 enum thunderstrike_led_state { ··· 102 59 THUNDERSTRIKE_LED_ON = 8, 103 60 } __packed; 104 61 static_assert(sizeof(enum thunderstrike_led_state) == 1); 62 + 63 + struct thunderstrike_hostcmd_battery { 64 + __le16 voltage_avg; 65 + u8 reserved_at_10; 66 + __le16 thermistor; 67 + __le16 voltage_min; 68 + __le16 voltage_boot; 69 + __le16 voltage_now; 70 + u8 capacity; 71 + } __packed; 72 + 73 + enum thunderstrike_charger_type { 74 + THUNDERSTRIKE_CHARGER_TYPE_NONE = 0, 75 + THUNDERSTRIKE_CHARGER_TYPE_TRICKLE, 76 + THUNDERSTRIKE_CHARGER_TYPE_NORMAL, 77 + } __packed; 78 + static_assert(sizeof(enum thunderstrike_charger_type) == 1); 79 + 80 + enum thunderstrike_charger_state { 81 + THUNDERSTRIKE_CHARGER_STATE_UNKNOWN = 0, 82 + THUNDERSTRIKE_CHARGER_STATE_DISABLED, 83 + THUNDERSTRIKE_CHARGER_STATE_CHARGING, 84 + THUNDERSTRIKE_CHARGER_STATE_FULL, 85 + THUNDERSTRIKE_CHARGER_STATE_FAILED = 8, 86 + } __packed; 87 + static_assert(sizeof(enum thunderstrike_charger_state) == 1); 88 + 89 + struct thunderstrike_hostcmd_charger { 90 + u8 connected; 91 + enum thunderstrike_charger_type type; 92 + enum thunderstrike_charger_state state; 93 + } __packed; 105 94 106 95 struct thunderstrike_hostcmd_board_info { 107 96 __le16 revision; ··· 155 80 struct thunderstrike_hostcmd_haptics motors; 156 81 __le16 fw_version; 157 82 enum thunderstrike_led_state led_state; 83 + struct thunderstrike_hostcmd_battery battery; 84 + struct thunderstrike_hostcmd_charger charger; 158 85 u8 payload[30]; 159 86 } __packed; 160 87 } __packed; ··· 186 109 /* Common struct for shield accessories. */ 187 110 struct shield_device { 188 111 struct hid_device *hdev; 112 + struct power_supply_dev battery_dev; 189 113 190 114 unsigned long initialized_flags; 191 115 const char *codename; ··· 197 119 } board_info; 198 120 }; 199 121 122 + /* 123 + * Non-trivial to uniquely identify Thunderstrike controllers at initialization 124 + * time. Use an ID allocator to help with this. 125 + */ 126 + static DEFINE_IDA(thunderstrike_ida); 127 + 200 128 struct thunderstrike { 201 129 struct shield_device base; 130 + 131 + int id; 202 132 203 133 /* Sub-devices */ 204 134 struct input_dev *haptics_dev; ··· 219 133 spinlock_t haptics_update_lock; 220 134 u8 led_state : 1; 221 135 enum thunderstrike_led_state led_value; 136 + struct thunderstrike_psy_prop_values psy_stats; 137 + spinlock_t psy_stats_lock; 138 + struct timer_list psy_stats_timer; 222 139 struct work_struct hostcmd_req_work; 223 140 }; 224 141 ··· 336 247 thunderstrike_send_hostcmd_request(ts); 337 248 } 338 249 250 + if (test_and_clear_bit(THUNDERSTRIKE_POWER_SUPPLY_STATS_UPDATE, &ts->update_flags)) { 251 + thunderstrike_hostcmd_req_report_init( 252 + report, THUNDERSTRIKE_HOSTCMD_ID_BATTERY); 253 + thunderstrike_send_hostcmd_request(ts); 254 + 255 + thunderstrike_hostcmd_req_report_init( 256 + report, THUNDERSTRIKE_HOSTCMD_ID_CHARGER); 257 + thunderstrike_send_hostcmd_request(ts); 258 + } 259 + 339 260 if (test_and_clear_bit(THUNDERSTRIKE_BOARD_INFO_UPDATE, &ts->update_flags)) { 340 261 thunderstrike_hostcmd_req_report_init( 341 262 report, THUNDERSTRIKE_HOSTCMD_ID_BOARD_INFO); ··· 451 352 schedule_work(&ts->hostcmd_req_work); 452 353 } 453 354 355 + static int thunderstrike_battery_get_property(struct power_supply *psy, 356 + enum power_supply_property psp, 357 + union power_supply_propval *val) 358 + { 359 + struct shield_device *shield_dev = power_supply_get_drvdata(psy); 360 + struct thunderstrike_psy_prop_values prop_values; 361 + struct thunderstrike *ts; 362 + int ret = 0; 363 + 364 + ts = container_of(shield_dev, struct thunderstrike, base); 365 + spin_lock(&ts->psy_stats_lock); 366 + prop_values = ts->psy_stats; 367 + spin_unlock(&ts->psy_stats_lock); 368 + 369 + switch (psp) { 370 + case POWER_SUPPLY_PROP_STATUS: 371 + val->intval = prop_values.status; 372 + break; 373 + case POWER_SUPPLY_PROP_CHARGE_TYPE: 374 + val->intval = prop_values.charge_type; 375 + break; 376 + case POWER_SUPPLY_PROP_PRESENT: 377 + val->intval = 1; 378 + break; 379 + case POWER_SUPPLY_PROP_VOLTAGE_MIN: 380 + val->intval = prop_values.voltage_min; 381 + break; 382 + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 383 + val->intval = 2900000; /* 2.9 V */ 384 + break; 385 + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: 386 + val->intval = 2200000; /* 2.2 V */ 387 + break; 388 + case POWER_SUPPLY_PROP_VOLTAGE_NOW: 389 + val->intval = prop_values.voltage_now; 390 + break; 391 + case POWER_SUPPLY_PROP_VOLTAGE_AVG: 392 + val->intval = prop_values.voltage_avg; 393 + break; 394 + case POWER_SUPPLY_PROP_VOLTAGE_BOOT: 395 + val->intval = prop_values.voltage_boot; 396 + break; 397 + case POWER_SUPPLY_PROP_CAPACITY: 398 + val->intval = prop_values.capacity; 399 + break; 400 + case POWER_SUPPLY_PROP_SCOPE: 401 + val->intval = POWER_SUPPLY_SCOPE_DEVICE; 402 + break; 403 + case POWER_SUPPLY_PROP_TEMP: 404 + val->intval = prop_values.temp; 405 + break; 406 + case POWER_SUPPLY_PROP_TEMP_MIN: 407 + val->intval = 0; /* 0 C */ 408 + break; 409 + case POWER_SUPPLY_PROP_TEMP_MAX: 410 + val->intval = 400; /* 40 C */ 411 + break; 412 + case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: 413 + val->intval = 15; /* 1.5 C */ 414 + break; 415 + case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: 416 + val->intval = 380; /* 38 C */ 417 + break; 418 + default: 419 + ret = -EINVAL; 420 + break; 421 + } 422 + 423 + return ret; 424 + } 425 + 426 + static inline void thunderstrike_request_psy_stats(struct thunderstrike *ts) 427 + { 428 + set_bit(THUNDERSTRIKE_POWER_SUPPLY_STATS_UPDATE, &ts->update_flags); 429 + schedule_work(&ts->hostcmd_req_work); 430 + } 431 + 432 + static void thunderstrike_psy_stats_timer_handler(struct timer_list *timer) 433 + { 434 + struct thunderstrike *ts = 435 + container_of(timer, struct thunderstrike, psy_stats_timer); 436 + 437 + thunderstrike_request_psy_stats(ts); 438 + /* Query battery statistics from device every five minutes */ 439 + mod_timer(timer, jiffies + 300 * HZ); 440 + } 441 + 454 442 static void 455 443 thunderstrike_parse_fw_version_payload(struct shield_device *shield_dev, 456 444 __le16 fw_version) ··· 602 416 hid_dbg(shield_dev->hdev, "Thunderstrike led HOSTCMD response, 0x%02X\n", led_state); 603 417 } 604 418 419 + static void thunderstrike_parse_battery_payload( 420 + struct shield_device *shield_dev, 421 + struct thunderstrike_hostcmd_battery *battery) 422 + { 423 + struct thunderstrike *ts = container_of(shield_dev, struct thunderstrike, base); 424 + u16 hostcmd_voltage_boot = le16_to_cpu(battery->voltage_boot); 425 + u16 hostcmd_voltage_avg = le16_to_cpu(battery->voltage_avg); 426 + u16 hostcmd_voltage_min = le16_to_cpu(battery->voltage_min); 427 + u16 hostcmd_voltage_now = le16_to_cpu(battery->voltage_now); 428 + u16 hostcmd_thermistor = le16_to_cpu(battery->thermistor); 429 + int voltage_boot, voltage_avg, voltage_min, voltage_now; 430 + struct hid_device *hdev = shield_dev->hdev; 431 + u8 capacity = battery->capacity; 432 + int temp; 433 + 434 + /* Convert thunderstrike device values to µV and tenths of degree Celsius */ 435 + voltage_boot = hostcmd_voltage_boot * 1000; 436 + voltage_avg = hostcmd_voltage_avg * 1000; 437 + voltage_min = hostcmd_voltage_min * 1000; 438 + voltage_now = hostcmd_voltage_now * 1000; 439 + temp = (1378 - (int)hostcmd_thermistor) * 10 / 19; 440 + 441 + /* Copy converted values */ 442 + spin_lock(&ts->psy_stats_lock); 443 + ts->psy_stats.voltage_boot = voltage_boot; 444 + ts->psy_stats.voltage_avg = voltage_avg; 445 + ts->psy_stats.voltage_min = voltage_min; 446 + ts->psy_stats.voltage_now = voltage_now; 447 + ts->psy_stats.capacity = capacity; 448 + ts->psy_stats.temp = temp; 449 + spin_unlock(&ts->psy_stats_lock); 450 + 451 + set_bit(SHIELD_BATTERY_STATS_INITIALIZED, &shield_dev->initialized_flags); 452 + 453 + hid_dbg(hdev, 454 + "Thunderstrike battery HOSTCMD response, voltage_avg: %u voltage_now: %u\n", 455 + hostcmd_voltage_avg, hostcmd_voltage_now); 456 + hid_dbg(hdev, 457 + "Thunderstrike battery HOSTCMD response, voltage_boot: %u voltage_min: %u\n", 458 + hostcmd_voltage_boot, hostcmd_voltage_min); 459 + hid_dbg(hdev, 460 + "Thunderstrike battery HOSTCMD response, thermistor: %u\n", 461 + hostcmd_thermistor); 462 + hid_dbg(hdev, 463 + "Thunderstrike battery HOSTCMD response, capacity: %u%%\n", 464 + capacity); 465 + } 466 + 467 + static void thunderstrike_parse_charger_payload( 468 + struct shield_device *shield_dev, 469 + struct thunderstrike_hostcmd_charger *charger) 470 + { 471 + struct thunderstrike *ts = container_of(shield_dev, struct thunderstrike, base); 472 + int charge_type = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; 473 + struct hid_device *hdev = shield_dev->hdev; 474 + int status = POWER_SUPPLY_STATUS_UNKNOWN; 475 + 476 + switch (charger->type) { 477 + case THUNDERSTRIKE_CHARGER_TYPE_NONE: 478 + charge_type = POWER_SUPPLY_CHARGE_TYPE_NONE; 479 + break; 480 + case THUNDERSTRIKE_CHARGER_TYPE_TRICKLE: 481 + charge_type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 482 + break; 483 + case THUNDERSTRIKE_CHARGER_TYPE_NORMAL: 484 + charge_type = POWER_SUPPLY_CHARGE_TYPE_STANDARD; 485 + break; 486 + default: 487 + hid_warn(hdev, "Unhandled Thunderstrike charger HOSTCMD type, %u\n", 488 + charger->type); 489 + break; 490 + } 491 + 492 + switch (charger->state) { 493 + case THUNDERSTRIKE_CHARGER_STATE_UNKNOWN: 494 + status = POWER_SUPPLY_STATUS_UNKNOWN; 495 + break; 496 + case THUNDERSTRIKE_CHARGER_STATE_DISABLED: 497 + /* Indicates charger is disconnected */ 498 + break; 499 + case THUNDERSTRIKE_CHARGER_STATE_CHARGING: 500 + status = POWER_SUPPLY_STATUS_CHARGING; 501 + break; 502 + case THUNDERSTRIKE_CHARGER_STATE_FULL: 503 + status = POWER_SUPPLY_STATUS_FULL; 504 + break; 505 + case THUNDERSTRIKE_CHARGER_STATE_FAILED: 506 + status = POWER_SUPPLY_STATUS_NOT_CHARGING; 507 + hid_err(hdev, "Thunderstrike device failed to charge\n"); 508 + break; 509 + default: 510 + hid_warn(hdev, "Unhandled Thunderstrike charger HOSTCMD state, %u\n", 511 + charger->state); 512 + break; 513 + } 514 + 515 + if (!charger->connected) 516 + status = POWER_SUPPLY_STATUS_DISCHARGING; 517 + 518 + spin_lock(&ts->psy_stats_lock); 519 + ts->psy_stats.charge_type = charge_type; 520 + ts->psy_stats.status = status; 521 + spin_unlock(&ts->psy_stats_lock); 522 + 523 + set_bit(SHIELD_CHARGER_STATE_INITIALIZED, &shield_dev->initialized_flags); 524 + 525 + hid_dbg(hdev, 526 + "Thunderstrike charger HOSTCMD response, connected: %u, type: %u, state: %u\n", 527 + charger->connected, charger->type, charger->state); 528 + } 529 + 530 + static inline void thunderstrike_device_init_info(struct shield_device *shield_dev) 531 + { 532 + struct thunderstrike *ts = 533 + container_of(shield_dev, struct thunderstrike, base); 534 + 535 + if (!test_bit(SHIELD_FW_VERSION_INITIALIZED, &shield_dev->initialized_flags)) 536 + thunderstrike_request_firmware_version(ts); 537 + 538 + if (!test_bit(SHIELD_BOARD_INFO_INITIALIZED, &shield_dev->initialized_flags)) 539 + thunderstrike_request_board_info(ts); 540 + 541 + if (!test_bit(SHIELD_BATTERY_STATS_INITIALIZED, &shield_dev->initialized_flags) || 542 + !test_bit(SHIELD_CHARGER_STATE_INITIALIZED, &shield_dev->initialized_flags)) 543 + thunderstrike_psy_stats_timer_handler(&ts->psy_stats_timer); 544 + } 545 + 605 546 static int thunderstrike_parse_report(struct shield_device *shield_dev, 606 547 struct hid_report *report, u8 *data, 607 548 int size) 608 549 { 609 550 struct thunderstrike_hostcmd_resp_report *hostcmd_resp_report; 610 - struct thunderstrike *ts = 611 - container_of(shield_dev, struct thunderstrike, base); 612 551 struct hid_device *hdev = shield_dev->hdev; 613 552 614 553 switch (report->id) { ··· 756 445 case THUNDERSTRIKE_HOSTCMD_ID_LED: 757 446 thunderstrike_parse_led_payload(shield_dev, hostcmd_resp_report->led_state); 758 447 break; 448 + case THUNDERSTRIKE_HOSTCMD_ID_BATTERY: 449 + thunderstrike_parse_battery_payload(shield_dev, 450 + &hostcmd_resp_report->battery); 451 + break; 759 452 case THUNDERSTRIKE_HOSTCMD_ID_BOARD_INFO: 760 453 thunderstrike_parse_board_info_payload( 761 454 shield_dev, &hostcmd_resp_report->board_info); ··· 768 453 thunderstrike_parse_haptics_payload( 769 454 shield_dev, &hostcmd_resp_report->motors); 770 455 break; 771 - 772 456 case THUNDERSTRIKE_HOSTCMD_ID_USB_INIT: 773 - case THUNDERSTRIKE_HOSTCMD_ID_BLUETOOTH_INIT: 774 457 /* May block HOSTCMD requests till received initially */ 775 - thunderstrike_request_firmware_version(ts); 776 - thunderstrike_request_board_info(ts); 777 - /* Only HOSTCMD that can be triggered without a request */ 778 - return 0; 458 + thunderstrike_device_init_info(shield_dev); 459 + break; 460 + case THUNDERSTRIKE_HOSTCMD_ID_CHARGER: 461 + /* May block HOSTCMD requests till received initially */ 462 + thunderstrike_device_init_info(shield_dev); 463 + 464 + thunderstrike_parse_charger_payload( 465 + shield_dev, &hostcmd_resp_report->charger); 466 + break; 779 467 default: 780 468 hid_warn(hdev, 781 469 "Unhandled Thunderstrike HOSTCMD id %d\n", ··· 798 480 { 799 481 struct led_classdev *led = &ts->led_dev; 800 482 801 - led->name = "thunderstrike:blue:led"; 483 + led->name = devm_kasprintf(&ts->base.hdev->dev, GFP_KERNEL, 484 + "thunderstrike%d:blue:led", ts->id); 802 485 led->max_brightness = 1; 803 486 led->flags = LED_CORE_SUSPENDRESUME; 804 487 led->brightness_get = &thunderstrike_led_get_brightness; 805 488 led->brightness_set = &thunderstrike_led_set_brightness; 806 489 807 490 return led_classdev_register(&ts->base.hdev->dev, led); 491 + } 492 + 493 + static inline int thunderstrike_psy_create(struct shield_device *shield_dev) 494 + { 495 + struct thunderstrike *ts = container_of(shield_dev, struct thunderstrike, base); 496 + struct power_supply_config psy_cfg = { .drv_data = shield_dev, }; 497 + struct hid_device *hdev = shield_dev->hdev; 498 + int ret; 499 + 500 + /* 501 + * Set an initial capacity and temperature value to avoid prematurely 502 + * triggering alerts. Will be replaced by values queried from initial 503 + * HOSTCMD requests. 504 + */ 505 + ts->psy_stats.capacity = 100; 506 + ts->psy_stats.temp = 182; 507 + 508 + shield_dev->battery_dev.desc.properties = thunderstrike_battery_props; 509 + shield_dev->battery_dev.desc.num_properties = 510 + ARRAY_SIZE(thunderstrike_battery_props); 511 + shield_dev->battery_dev.desc.get_property = thunderstrike_battery_get_property; 512 + shield_dev->battery_dev.desc.type = POWER_SUPPLY_TYPE_BATTERY; 513 + shield_dev->battery_dev.desc.name = 514 + devm_kasprintf(&ts->base.hdev->dev, GFP_KERNEL, 515 + "thunderstrike_%d", ts->id); 516 + 517 + shield_dev->battery_dev.psy = power_supply_register( 518 + &hdev->dev, &shield_dev->battery_dev.desc, &psy_cfg); 519 + if (IS_ERR(shield_dev->battery_dev.psy)) { 520 + hid_err(hdev, "Failed to register Thunderstrike battery device\n"); 521 + return PTR_ERR(shield_dev->battery_dev.psy); 522 + } 523 + 524 + ret = power_supply_powers(shield_dev->battery_dev.psy, &hdev->dev); 525 + if (ret) { 526 + hid_err(hdev, "Failed to associate battery device to Thunderstrike\n"); 527 + goto err; 528 + } 529 + 530 + return 0; 531 + 532 + err: 533 + power_supply_unregister(shield_dev->battery_dev.psy); 534 + return ret; 808 535 } 809 536 810 537 static struct shield_device *thunderstrike_create(struct hid_device *hdev) ··· 872 509 shield_dev->codename = "Thunderstrike"; 873 510 874 511 spin_lock_init(&ts->haptics_update_lock); 512 + spin_lock_init(&ts->psy_stats_lock); 875 513 INIT_WORK(&ts->hostcmd_req_work, thunderstrike_hostcmd_req_work_handler); 876 514 877 515 hid_set_drvdata(hdev, shield_dev); 878 516 517 + ts->id = ida_alloc(&thunderstrike_ida, GFP_KERNEL); 518 + if (ts->id < 0) 519 + return ERR_PTR(ts->id); 520 + 521 + ts->haptics_dev = shield_haptics_create(shield_dev, thunderstrike_play_effect); 522 + if (IS_ERR(ts->haptics_dev)) { 523 + hid_err(hdev, "Failed to create Thunderstrike haptics instance\n"); 524 + ret = PTR_ERR(ts->haptics_dev); 525 + goto err_id; 526 + } 527 + 528 + ret = thunderstrike_psy_create(shield_dev); 529 + if (ret) { 530 + hid_err(hdev, "Failed to create Thunderstrike power supply instance\n"); 531 + goto err_haptics; 532 + } 533 + 879 534 ret = thunderstrike_led_create(ts); 880 535 if (ret) { 881 536 hid_err(hdev, "Failed to create Thunderstrike LED instance\n"); 882 - return ERR_PTR(ret); 537 + goto err_psy; 883 538 } 884 539 885 - ts->haptics_dev = shield_haptics_create(shield_dev, thunderstrike_play_effect); 886 - if (IS_ERR(ts->haptics_dev)) 887 - goto err; 540 + timer_setup(&ts->psy_stats_timer, thunderstrike_psy_stats_timer_handler, 0); 888 541 889 542 hid_info(hdev, "Registered Thunderstrike controller\n"); 890 543 return shield_dev; 891 544 892 - err: 893 - led_classdev_unregister(&ts->led_dev); 894 - return ERR_CAST(ts->haptics_dev); 545 + err_psy: 546 + power_supply_unregister(shield_dev->battery_dev.psy); 547 + err_haptics: 548 + if (ts->haptics_dev) 549 + input_unregister_device(ts->haptics_dev); 550 + err_id: 551 + ida_free(&thunderstrike_ida, ts->id); 552 + return ERR_PTR(ret); 895 553 } 896 554 897 555 static int android_input_mapping(struct hid_device *hdev, struct hid_input *hi, ··· 1067 683 goto err_stop; 1068 684 } 1069 685 1070 - thunderstrike_request_firmware_version(ts); 1071 - thunderstrike_request_board_info(ts); 686 + thunderstrike_device_init_info(shield_dev); 1072 687 1073 688 return ret; 1074 689 ··· 1087 704 ts = container_of(dev, struct thunderstrike, base); 1088 705 1089 706 hid_hw_close(hdev); 1090 - led_classdev_unregister(&ts->led_dev); 707 + power_supply_unregister(dev->battery_dev.psy); 1091 708 if (ts->haptics_dev) 1092 709 input_unregister_device(ts->haptics_dev); 710 + led_classdev_unregister(&ts->led_dev); 711 + ida_free(&thunderstrike_ida, ts->id); 712 + del_timer_sync(&ts->psy_stats_timer); 1093 713 cancel_work_sync(&ts->hostcmd_req_work); 1094 714 hid_hw_stop(hdev); 1095 715 }