aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorFrank Praznik <frank.praznik@oh.rr.com>2014-01-27 10:17:36 -0500
committerJiri Kosina <jkosina@suse.cz>2014-01-28 14:37:45 -0500
commitd902f4724ccd0c6b8f2b0a7d22af428c637b6dda (patch)
tree6c10a4adbefaf51b07265713de5b772bf32c01fa /drivers/hid
parent4988abf1749241bc80600a6b3283d03898d2717c (diff)
HID: sony: add battery status reporting for the Sixaxis and Dualshock 4
Add battery status reporting for the Sixaxis and Dualshock 4 controllers. Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-sony.c186
1 files changed, 185 insertions, 1 deletions
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 12354055d474..04fd611d3099 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -30,6 +30,8 @@
30#include <linux/slab.h> 30#include <linux/slab.h>
31#include <linux/usb.h> 31#include <linux/usb.h>
32#include <linux/leds.h> 32#include <linux/leds.h>
33#include <linux/power_supply.h>
34#include <linux/spinlock.h>
33 35
34#include "hid-ids.h" 36#include "hid-ids.h"
35 37
@@ -42,6 +44,7 @@
42#define DUALSHOCK4_CONTROLLER_BT BIT(6) 44#define DUALSHOCK4_CONTROLLER_BT BIT(6)
43 45
44#define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER_USB | BUZZ_CONTROLLER | DUALSHOCK4_CONTROLLER_USB) 46#define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER_USB | BUZZ_CONTROLLER | DUALSHOCK4_CONTROLLER_USB)
47#define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT | DUALSHOCK4_CONTROLLER_USB)
45 48
46#define MAX_LEDS 4 49#define MAX_LEDS 4
47 50
@@ -487,18 +490,30 @@ static const unsigned int buzz_keymap[] = {
487 [20] = BTN_TRIGGER_HAPPY20, 490 [20] = BTN_TRIGGER_HAPPY20,
488}; 491};
489 492
493static enum power_supply_property sony_battery_props[] = {
494 POWER_SUPPLY_PROP_PRESENT,
495 POWER_SUPPLY_PROP_CAPACITY,
496 POWER_SUPPLY_PROP_SCOPE,
497 POWER_SUPPLY_PROP_STATUS,
498};
499
490struct sony_sc { 500struct sony_sc {
501 spinlock_t lock;
491 struct hid_device *hdev; 502 struct hid_device *hdev;
492 struct led_classdev *leds[MAX_LEDS]; 503 struct led_classdev *leds[MAX_LEDS];
493 struct hid_report *output_report; 504 struct hid_report *output_report;
494 unsigned long quirks; 505 unsigned long quirks;
495 struct work_struct state_worker; 506 struct work_struct state_worker;
507 struct power_supply battery;
496 508
497#ifdef CONFIG_SONY_FF 509#ifdef CONFIG_SONY_FF
498 __u8 left; 510 __u8 left;
499 __u8 right; 511 __u8 right;
500#endif 512#endif
501 513
514 __u8 cable_state;
515 __u8 battery_charging;
516 __u8 battery_capacity;
502 __u8 led_state[MAX_LEDS]; 517 __u8 led_state[MAX_LEDS];
503 __u8 led_count; 518 __u8 led_count;
504}; 519};
@@ -599,6 +614,63 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
599 return rdesc; 614 return rdesc;
600} 615}
601 616
617static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size)
618{
619 static const __u8 sixaxis_battery_capacity[] = { 0, 1, 25, 50, 75, 100 };
620 unsigned long flags;
621 __u8 cable_state, battery_capacity, battery_charging;
622
623 /* The sixaxis is charging if the battery value is 0xee
624 * and it is fully charged if the value is 0xef.
625 * It does not report the actual level while charging so it
626 * is set to 100% while charging is in progress.
627 */
628 if (rd[30] >= 0xee) {
629 battery_capacity = 100;
630 battery_charging = rd[30] & 0x01;
631 } else {
632 battery_capacity = sixaxis_battery_capacity[rd[30]];
633 battery_charging = 0;
634 }
635 cable_state = (rd[31] >> 4) & 0x01;
636
637 spin_lock_irqsave(&sc->lock, flags);
638 sc->cable_state = cable_state;
639 sc->battery_capacity = battery_capacity;
640 sc->battery_charging = battery_charging;
641 spin_unlock_irqrestore(&sc->lock, flags);
642}
643
644static void dualshock4_parse_report(struct sony_sc *sc, __u8 *rd, int size)
645{
646 unsigned long flags;
647 __u8 cable_state, battery_capacity, battery_charging;
648
649 /* The lower 4 bits of byte 30 contain the battery level
650 * and the 5th bit contains the USB cable state.
651 */
652 cable_state = (rd[30] >> 4) & 0x01;
653 battery_capacity = rd[30] & 0x0F;
654
655 /* On USB the Dualshock 4 battery level goes from 0 to 11.
656 * A battery level of 11 means fully charged.
657 */
658 if (cable_state && battery_capacity == 11)
659 battery_charging = 0;
660 else
661 battery_charging = 1;
662
663 if (battery_capacity > 10)
664 battery_capacity--;
665 battery_capacity *= 10;
666
667 spin_lock_irqsave(&sc->lock, flags);
668 sc->cable_state = cable_state;
669 sc->battery_capacity = battery_capacity;
670 sc->battery_charging = battery_charging;
671 spin_unlock_irqrestore(&sc->lock, flags);
672}
673
602static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, 674static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
603 __u8 *rd, int size) 675 __u8 *rd, int size)
604{ 676{
@@ -613,6 +685,11 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
613 swap(rd[43], rd[44]); 685 swap(rd[43], rd[44]);
614 swap(rd[45], rd[46]); 686 swap(rd[45], rd[46]);
615 swap(rd[47], rd[48]); 687 swap(rd[47], rd[48]);
688
689 sixaxis_parse_report(sc, rd, size);
690 } else if ((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && rd[0] == 0x01 &&
691 size == 64) {
692 dualshock4_parse_report(sc, rd, size);
616 } 693 }
617 694
618 return 0; 695 return 0;
@@ -1011,6 +1088,91 @@ static void sony_destroy_ff(struct hid_device *hdev)
1011} 1088}
1012#endif 1089#endif
1013 1090
1091static int sony_battery_get_property(struct power_supply *psy,
1092 enum power_supply_property psp,
1093 union power_supply_propval *val)
1094{
1095 struct sony_sc *sc = container_of(psy, struct sony_sc, battery);
1096 unsigned long flags;
1097 int ret = 0;
1098 u8 battery_charging, battery_capacity, cable_state;
1099
1100 spin_lock_irqsave(&sc->lock, flags);
1101 battery_charging = sc->battery_charging;
1102 battery_capacity = sc->battery_capacity;
1103 cable_state = sc->cable_state;
1104 spin_unlock_irqrestore(&sc->lock, flags);
1105
1106 switch (psp) {
1107 case POWER_SUPPLY_PROP_PRESENT:
1108 val->intval = 1;
1109 break;
1110 case POWER_SUPPLY_PROP_SCOPE:
1111 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
1112 break;
1113 case POWER_SUPPLY_PROP_CAPACITY:
1114 val->intval = battery_capacity;
1115 break;
1116 case POWER_SUPPLY_PROP_STATUS:
1117 if (battery_charging)
1118 val->intval = POWER_SUPPLY_STATUS_CHARGING;
1119 else
1120 if (battery_capacity == 100 && cable_state)
1121 val->intval = POWER_SUPPLY_STATUS_FULL;
1122 else
1123 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
1124 break;
1125 default:
1126 ret = -EINVAL;
1127 break;
1128 }
1129 return ret;
1130}
1131
1132static int sony_battery_probe(struct sony_sc *sc)
1133{
1134 static atomic_t power_id_seq = ATOMIC_INIT(0);
1135 unsigned long power_id;
1136 struct hid_device *hdev = sc->hdev;
1137 int ret;
1138
1139 power_id = (unsigned long)atomic_inc_return(&power_id_seq);
1140
1141 sc->battery.properties = sony_battery_props;
1142 sc->battery.num_properties = ARRAY_SIZE(sony_battery_props);
1143 sc->battery.get_property = sony_battery_get_property;
1144 sc->battery.type = POWER_SUPPLY_TYPE_BATTERY;
1145 sc->battery.use_for_apm = 0;
1146 sc->battery.name = kasprintf(GFP_KERNEL, "sony_controller_battery_%lu",
1147 power_id);
1148 if (!sc->battery.name)
1149 return -ENOMEM;
1150
1151 ret = power_supply_register(&hdev->dev, &sc->battery);
1152 if (ret) {
1153 hid_err(hdev, "Unable to register battery device\n");
1154 goto err_free;
1155 }
1156
1157 power_supply_powers(&sc->battery, &hdev->dev);
1158 return 0;
1159
1160err_free:
1161 kfree(sc->battery.name);
1162 sc->battery.name = NULL;
1163 return ret;
1164}
1165
1166static void sony_battery_remove(struct sony_sc *sc)
1167{
1168 if (!sc->battery.name)
1169 return;
1170
1171 power_supply_unregister(&sc->battery);
1172 kfree(sc->battery.name);
1173 sc->battery.name = NULL;
1174}
1175
1014static int sony_set_output_report(struct sony_sc *sc, int req_id, int req_size) 1176static int sony_set_output_report(struct sony_sc *sc, int req_id, int req_size)
1015{ 1177{
1016 struct list_head *head, *list; 1178 struct list_head *head, *list;
@@ -1101,14 +1263,31 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
1101 goto err_stop; 1263 goto err_stop;
1102 } 1264 }
1103 1265
1266 if (sc->quirks & SONY_BATTERY_SUPPORT) {
1267 ret = sony_battery_probe(sc);
1268 if (ret < 0)
1269 goto err_stop;
1270
1271 /* Open the device to receive reports with battery info */
1272 ret = hid_hw_open(hdev);
1273 if (ret < 0) {
1274 hid_err(hdev, "hw open failed\n");
1275 goto err_stop;
1276 }
1277 }
1278
1104 ret = sony_init_ff(hdev); 1279 ret = sony_init_ff(hdev);
1105 if (ret < 0) 1280 if (ret < 0)
1106 goto err_stop; 1281 goto err_close;
1107 1282
1108 return 0; 1283 return 0;
1284err_close:
1285 hid_hw_close(hdev);
1109err_stop: 1286err_stop:
1110 if (sc->quirks & SONY_LED_SUPPORT) 1287 if (sc->quirks & SONY_LED_SUPPORT)
1111 sony_leds_remove(hdev); 1288 sony_leds_remove(hdev);
1289 if (sc->quirks & SONY_BATTERY_SUPPORT)
1290 sony_battery_remove(sc);
1112 hid_hw_stop(hdev); 1291 hid_hw_stop(hdev);
1113 return ret; 1292 return ret;
1114} 1293}
@@ -1120,6 +1299,11 @@ static void sony_remove(struct hid_device *hdev)
1120 if (sc->quirks & SONY_LED_SUPPORT) 1299 if (sc->quirks & SONY_LED_SUPPORT)
1121 sony_leds_remove(hdev); 1300 sony_leds_remove(hdev);
1122 1301
1302 if (sc->quirks & SONY_BATTERY_SUPPORT) {
1303 hid_hw_close(hdev);
1304 sony_battery_remove(sc);
1305 }
1306
1123 sony_destroy_ff(hdev); 1307 sony_destroy_ff(hdev);
1124 1308
1125 hid_hw_stop(hdev); 1309 hid_hw_stop(hdev);