@@ -91,6 +91,7 @@ MODULE_PARM_DESC(disable_tap_to_click,
91
91
#define HIDPP_CAPABILITY_HIDPP20_BATTERY BIT(1)
92
92
#define HIDPP_CAPABILITY_BATTERY_MILEAGE BIT(2)
93
93
#define HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS BIT(3)
94
+ #define HIDPP_CAPABILITY_BATTERY_VOLTAGE BIT(4)
94
95
95
96
/*
96
97
* There are two hidpp protocols in use, the first version hidpp10 is known
@@ -139,12 +140,15 @@ struct hidpp_report {
139
140
struct hidpp_battery {
140
141
u8 feature_index ;
141
142
u8 solar_feature_index ;
143
+ u8 voltage_feature_index ;
142
144
struct power_supply_desc desc ;
143
145
struct power_supply * ps ;
144
146
char name [64 ];
145
147
int status ;
146
148
int capacity ;
147
149
int level ;
150
+ int voltage ;
151
+ int charge_type ;
148
152
bool online ;
149
153
};
150
154
@@ -1237,6 +1241,144 @@ static int hidpp20_battery_event(struct hidpp_device *hidpp,
1237
1241
return 0 ;
1238
1242
}
1239
1243
1244
+ /* -------------------------------------------------------------------------- */
1245
+ /* 0x1001: Battery voltage */
1246
+ /* -------------------------------------------------------------------------- */
1247
+
1248
+ #define HIDPP_PAGE_BATTERY_VOLTAGE 0x1001
1249
+
1250
+ #define CMD_BATTERY_VOLTAGE_GET_BATTERY_VOLTAGE 0x00
1251
+
1252
+ #define EVENT_BATTERY_VOLTAGE_STATUS_BROADCAST 0x00
1253
+
1254
+ static int hidpp20_battery_map_status_voltage (u8 data [3 ], int * voltage ,
1255
+ int * level , int * charge_type )
1256
+ {
1257
+ int status ;
1258
+
1259
+ long charge_sts = (long )data [2 ];
1260
+
1261
+ * level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN ;
1262
+ switch (data [2 ] & 0xe0 ) {
1263
+ case 0x00 :
1264
+ status = POWER_SUPPLY_STATUS_CHARGING ;
1265
+ break ;
1266
+ case 0x20 :
1267
+ status = POWER_SUPPLY_STATUS_FULL ;
1268
+ * level = POWER_SUPPLY_CAPACITY_LEVEL_FULL ;
1269
+ break ;
1270
+ case 0x40 :
1271
+ status = POWER_SUPPLY_STATUS_DISCHARGING ;
1272
+ break ;
1273
+ case 0xe0 :
1274
+ status = POWER_SUPPLY_STATUS_NOT_CHARGING ;
1275
+ break ;
1276
+ default :
1277
+ status = POWER_SUPPLY_STATUS_UNKNOWN ;
1278
+ }
1279
+
1280
+ * charge_type = POWER_SUPPLY_CHARGE_TYPE_STANDARD ;
1281
+ if (test_bit (3 , & charge_sts )) {
1282
+ * charge_type = POWER_SUPPLY_CHARGE_TYPE_FAST ;
1283
+ }
1284
+ if (test_bit (4 , & charge_sts )) {
1285
+ * charge_type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE ;
1286
+ }
1287
+
1288
+ if (test_bit (5 , & charge_sts )) {
1289
+ * level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL ;
1290
+ }
1291
+
1292
+ * voltage = get_unaligned_be16 (data );
1293
+
1294
+ return status ;
1295
+ }
1296
+
1297
+ static int hidpp20_battery_get_battery_voltage (struct hidpp_device * hidpp ,
1298
+ u8 feature_index ,
1299
+ int * status , int * voltage ,
1300
+ int * level , int * charge_type )
1301
+ {
1302
+ struct hidpp_report response ;
1303
+ int ret ;
1304
+ u8 * params = (u8 * )response .fap .params ;
1305
+
1306
+ ret = hidpp_send_fap_command_sync (hidpp , feature_index ,
1307
+ CMD_BATTERY_VOLTAGE_GET_BATTERY_VOLTAGE ,
1308
+ NULL , 0 , & response );
1309
+
1310
+ if (ret > 0 ) {
1311
+ hid_err (hidpp -> hid_dev , "%s: received protocol error 0x%02x\n" ,
1312
+ __func__ , ret );
1313
+ return - EPROTO ;
1314
+ }
1315
+ if (ret )
1316
+ return ret ;
1317
+
1318
+ hidpp -> capabilities |= HIDPP_CAPABILITY_BATTERY_VOLTAGE ;
1319
+
1320
+ * status = hidpp20_battery_map_status_voltage (params , voltage ,
1321
+ level , charge_type );
1322
+
1323
+ return 0 ;
1324
+ }
1325
+
1326
+ static int hidpp20_query_battery_voltage_info (struct hidpp_device * hidpp )
1327
+ {
1328
+ u8 feature_type ;
1329
+ int ret ;
1330
+ int status , voltage , level , charge_type ;
1331
+
1332
+ if (hidpp -> battery .voltage_feature_index == 0xff ) {
1333
+ ret = hidpp_root_get_feature (hidpp , HIDPP_PAGE_BATTERY_VOLTAGE ,
1334
+ & hidpp -> battery .voltage_feature_index ,
1335
+ & feature_type );
1336
+ if (ret )
1337
+ return ret ;
1338
+ }
1339
+
1340
+ ret = hidpp20_battery_get_battery_voltage (hidpp ,
1341
+ hidpp -> battery .voltage_feature_index ,
1342
+ & status , & voltage , & level , & charge_type );
1343
+
1344
+ if (ret )
1345
+ return ret ;
1346
+
1347
+ hidpp -> battery .status = status ;
1348
+ hidpp -> battery .voltage = voltage ;
1349
+ hidpp -> battery .level = level ;
1350
+ hidpp -> battery .charge_type = charge_type ;
1351
+ hidpp -> battery .online = status != POWER_SUPPLY_STATUS_NOT_CHARGING ;
1352
+
1353
+ return 0 ;
1354
+ }
1355
+
1356
+ static int hidpp20_battery_voltage_event (struct hidpp_device * hidpp ,
1357
+ u8 * data , int size )
1358
+ {
1359
+ struct hidpp_report * report = (struct hidpp_report * )data ;
1360
+ int status , voltage , level , charge_type ;
1361
+
1362
+ if (report -> fap .feature_index != hidpp -> battery .voltage_feature_index ||
1363
+ report -> fap .funcindex_clientid != EVENT_BATTERY_VOLTAGE_STATUS_BROADCAST )
1364
+ return 0 ;
1365
+
1366
+ status = hidpp20_battery_map_status_voltage (report -> fap .params , & voltage ,
1367
+ & level , & charge_type );
1368
+
1369
+ hidpp -> battery .online = status != POWER_SUPPLY_STATUS_NOT_CHARGING ;
1370
+
1371
+ if (voltage != hidpp -> battery .voltage || status != hidpp -> battery .status ) {
1372
+ hidpp -> battery .voltage = voltage ;
1373
+ hidpp -> battery .status = status ;
1374
+ hidpp -> battery .level = level ;
1375
+ hidpp -> battery .charge_type = charge_type ;
1376
+ if (hidpp -> battery .ps )
1377
+ power_supply_changed (hidpp -> battery .ps );
1378
+ }
1379
+ return 0 ;
1380
+ }
1381
+
1240
1382
static enum power_supply_property hidpp_battery_props [] = {
1241
1383
POWER_SUPPLY_PROP_ONLINE ,
1242
1384
POWER_SUPPLY_PROP_STATUS ,
@@ -1246,6 +1388,7 @@ static enum power_supply_property hidpp_battery_props[] = {
1246
1388
POWER_SUPPLY_PROP_SERIAL_NUMBER ,
1247
1389
0 , /* placeholder for POWER_SUPPLY_PROP_CAPACITY, */
1248
1390
0 , /* placeholder for POWER_SUPPLY_PROP_CAPACITY_LEVEL, */
1391
+ 0 , /* placeholder for POWER_SUPPLY_PROP_VOLTAGE_NOW, */
1249
1392
};
1250
1393
1251
1394
static int hidpp_battery_get_property (struct power_supply * psy ,
@@ -1283,6 +1426,13 @@ static int hidpp_battery_get_property(struct power_supply *psy,
1283
1426
case POWER_SUPPLY_PROP_SERIAL_NUMBER :
1284
1427
val -> strval = hidpp -> hid_dev -> uniq ;
1285
1428
break ;
1429
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW :
1430
+ /* hardware reports voltage in in mV. sysfs expects uV */
1431
+ val -> intval = hidpp -> battery .voltage * 1000 ;
1432
+ break ;
1433
+ case POWER_SUPPLY_PROP_CHARGE_TYPE :
1434
+ val -> intval = hidpp -> battery .charge_type ;
1435
+ break ;
1286
1436
default :
1287
1437
ret = - EINVAL ;
1288
1438
break ;
@@ -3139,6 +3289,9 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
3139
3289
ret = hidpp_solar_battery_event (hidpp , data , size );
3140
3290
if (ret != 0 )
3141
3291
return ret ;
3292
+ ret = hidpp20_battery_voltage_event (hidpp , data , size );
3293
+ if (ret != 0 )
3294
+ return ret ;
3142
3295
}
3143
3296
3144
3297
if (hidpp -> capabilities & HIDPP_CAPABILITY_HIDPP10_BATTERY ) {
@@ -3260,12 +3413,16 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
3260
3413
3261
3414
hidpp -> battery .feature_index = 0xff ;
3262
3415
hidpp -> battery .solar_feature_index = 0xff ;
3416
+ hidpp -> battery .voltage_feature_index = 0xff ;
3263
3417
3264
3418
if (hidpp -> protocol_major >= 2 ) {
3265
3419
if (hidpp -> quirks & HIDPP_QUIRK_CLASS_K750 )
3266
3420
ret = hidpp_solar_request_battery_event (hidpp );
3267
- else
3268
- ret = hidpp20_query_battery_info (hidpp );
3421
+ else {
3422
+ ret = hidpp20_query_battery_voltage_info (hidpp );
3423
+ if (ret )
3424
+ ret = hidpp20_query_battery_info (hidpp );
3425
+ }
3269
3426
3270
3427
if (ret )
3271
3428
return ret ;
@@ -3290,7 +3447,7 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
3290
3447
if (!battery_props )
3291
3448
return - ENOMEM ;
3292
3449
3293
- num_battery_props = ARRAY_SIZE (hidpp_battery_props ) - 2 ;
3450
+ num_battery_props = ARRAY_SIZE (hidpp_battery_props ) - 3 ;
3294
3451
3295
3452
if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE )
3296
3453
battery_props [num_battery_props ++ ] =
@@ -3300,6 +3457,10 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
3300
3457
battery_props [num_battery_props ++ ] =
3301
3458
POWER_SUPPLY_PROP_CAPACITY_LEVEL ;
3302
3459
3460
+ if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE )
3461
+ battery_props [num_battery_props ++ ] =
3462
+ POWER_SUPPLY_PROP_VOLTAGE_NOW ;
3463
+
3303
3464
battery = & hidpp -> battery ;
3304
3465
3305
3466
n = atomic_inc_return (& battery_no ) - 1 ;
@@ -3463,7 +3624,10 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
3463
3624
else
3464
3625
hidpp10_query_battery_status (hidpp );
3465
3626
} else if (hidpp -> capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY ) {
3466
- hidpp20_query_battery_info (hidpp );
3627
+ if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE )
3628
+ hidpp20_query_battery_voltage_info (hidpp );
3629
+ else
3630
+ hidpp20_query_battery_info (hidpp );
3467
3631
}
3468
3632
if (hidpp -> battery .ps )
3469
3633
power_supply_changed (hidpp -> battery .ps );
0 commit comments