@@ -91,6 +91,7 @@ MODULE_PARM_DESC(disable_tap_to_click,
9191#define HIDPP_CAPABILITY_HIDPP20_BATTERY BIT(1)
9292#define HIDPP_CAPABILITY_BATTERY_MILEAGE BIT(2)
9393#define HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS BIT(3)
94+ #define HIDPP_CAPABILITY_BATTERY_VOLTAGE BIT(4)
9495
9596/*
9697 * There are two hidpp protocols in use, the first version hidpp10 is known
@@ -139,12 +140,15 @@ struct hidpp_report {
139140struct hidpp_battery {
140141 u8 feature_index ;
141142 u8 solar_feature_index ;
143+ u8 voltage_feature_index ;
142144 struct power_supply_desc desc ;
143145 struct power_supply * ps ;
144146 char name [64 ];
145147 int status ;
146148 int capacity ;
147149 int level ;
150+ int voltage ;
151+ int charge_type ;
148152 bool online ;
149153};
150154
@@ -1237,6 +1241,144 @@ static int hidpp20_battery_event(struct hidpp_device *hidpp,
12371241 return 0 ;
12381242}
12391243
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+
12401382static enum power_supply_property hidpp_battery_props [] = {
12411383 POWER_SUPPLY_PROP_ONLINE ,
12421384 POWER_SUPPLY_PROP_STATUS ,
@@ -1246,6 +1388,7 @@ static enum power_supply_property hidpp_battery_props[] = {
12461388 POWER_SUPPLY_PROP_SERIAL_NUMBER ,
12471389 0 , /* placeholder for POWER_SUPPLY_PROP_CAPACITY, */
12481390 0 , /* placeholder for POWER_SUPPLY_PROP_CAPACITY_LEVEL, */
1391+ 0 , /* placeholder for POWER_SUPPLY_PROP_VOLTAGE_NOW, */
12491392};
12501393
12511394static int hidpp_battery_get_property (struct power_supply * psy ,
@@ -1283,6 +1426,13 @@ static int hidpp_battery_get_property(struct power_supply *psy,
12831426 case POWER_SUPPLY_PROP_SERIAL_NUMBER :
12841427 val -> strval = hidpp -> hid_dev -> uniq ;
12851428 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 ;
12861436 default :
12871437 ret = - EINVAL ;
12881438 break ;
@@ -3139,6 +3289,9 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
31393289 ret = hidpp_solar_battery_event (hidpp , data , size );
31403290 if (ret != 0 )
31413291 return ret ;
3292+ ret = hidpp20_battery_voltage_event (hidpp , data , size );
3293+ if (ret != 0 )
3294+ return ret ;
31423295 }
31433296
31443297 if (hidpp -> capabilities & HIDPP_CAPABILITY_HIDPP10_BATTERY ) {
@@ -3260,12 +3413,16 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
32603413
32613414 hidpp -> battery .feature_index = 0xff ;
32623415 hidpp -> battery .solar_feature_index = 0xff ;
3416+ hidpp -> battery .voltage_feature_index = 0xff ;
32633417
32643418 if (hidpp -> protocol_major >= 2 ) {
32653419 if (hidpp -> quirks & HIDPP_QUIRK_CLASS_K750 )
32663420 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+ }
32693426
32703427 if (ret )
32713428 return ret ;
@@ -3290,7 +3447,7 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
32903447 if (!battery_props )
32913448 return - ENOMEM ;
32923449
3293- num_battery_props = ARRAY_SIZE (hidpp_battery_props ) - 2 ;
3450+ num_battery_props = ARRAY_SIZE (hidpp_battery_props ) - 3 ;
32943451
32953452 if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE )
32963453 battery_props [num_battery_props ++ ] =
@@ -3300,6 +3457,10 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
33003457 battery_props [num_battery_props ++ ] =
33013458 POWER_SUPPLY_PROP_CAPACITY_LEVEL ;
33023459
3460+ if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE )
3461+ battery_props [num_battery_props ++ ] =
3462+ POWER_SUPPLY_PROP_VOLTAGE_NOW ;
3463+
33033464 battery = & hidpp -> battery ;
33043465
33053466 n = atomic_inc_return (& battery_no ) - 1 ;
@@ -3463,7 +3624,10 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
34633624 else
34643625 hidpp10_query_battery_status (hidpp );
34653626 } 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 );
34673631 }
34683632 if (hidpp -> battery .ps )
34693633 power_supply_changed (hidpp -> battery .ps );
0 commit comments