Skip to content

Commit fc590a3

Browse files
author
Jiri Kosina
committed
Merge branch 'for-5.12/logitech' into for-linus
- support for "Unified Battery (1004) feature" from Filipe Laíns
2 parents 7eb275f + 4d30083 commit fc590a3

File tree

2 files changed

+240
-8
lines changed

2 files changed

+240
-8
lines changed

drivers/hid/hid-lg-g15.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ static void lg_g15_input_close(struct input_dev *dev)
647647

648648
static int lg_g15_register_led(struct lg_g15_data *g15, int i)
649649
{
650-
const char * const led_names[] = {
650+
static const char * const led_names[] = {
651651
"g15::kbd_backlight",
652652
"g15::lcd_backlight",
653653
"g15::macro_preset1",

drivers/hid/hid-logitech-hidpp.c

Lines changed: 239 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ MODULE_PARM_DESC(disable_tap_to_click,
9292
#define HIDPP_CAPABILITY_BATTERY_MILEAGE BIT(2)
9393
#define HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS BIT(3)
9494
#define HIDPP_CAPABILITY_BATTERY_VOLTAGE BIT(4)
95+
#define HIDPP_CAPABILITY_BATTERY_PERCENTAGE BIT(5)
96+
#define HIDPP_CAPABILITY_UNIFIED_BATTERY BIT(6)
9597

9698
#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
9799

@@ -152,6 +154,7 @@ struct hidpp_battery {
152154
int voltage;
153155
int charge_type;
154156
bool online;
157+
u8 supported_levels_1004;
155158
};
156159

157160
/**
@@ -1171,7 +1174,7 @@ static int hidpp20_batterylevel_get_battery_info(struct hidpp_device *hidpp,
11711174
return 0;
11721175
}
11731176

1174-
static int hidpp20_query_battery_info(struct hidpp_device *hidpp)
1177+
static int hidpp20_query_battery_info_1000(struct hidpp_device *hidpp)
11751178
{
11761179
u8 feature_type;
11771180
int ret;
@@ -1208,7 +1211,7 @@ static int hidpp20_query_battery_info(struct hidpp_device *hidpp)
12081211
return 0;
12091212
}
12101213

1211-
static int hidpp20_battery_event(struct hidpp_device *hidpp,
1214+
static int hidpp20_battery_event_1000(struct hidpp_device *hidpp,
12121215
u8 *data, int size)
12131216
{
12141217
struct hidpp_report *report = (struct hidpp_report *)data;
@@ -1380,6 +1383,224 @@ static int hidpp20_battery_voltage_event(struct hidpp_device *hidpp,
13801383
return 0;
13811384
}
13821385

1386+
/* -------------------------------------------------------------------------- */
1387+
/* 0x1004: Unified battery */
1388+
/* -------------------------------------------------------------------------- */
1389+
1390+
#define HIDPP_PAGE_UNIFIED_BATTERY 0x1004
1391+
1392+
#define CMD_UNIFIED_BATTERY_GET_CAPABILITIES 0x00
1393+
#define CMD_UNIFIED_BATTERY_GET_STATUS 0x10
1394+
1395+
#define EVENT_UNIFIED_BATTERY_STATUS_EVENT 0x00
1396+
1397+
#define FLAG_UNIFIED_BATTERY_LEVEL_CRITICAL BIT(0)
1398+
#define FLAG_UNIFIED_BATTERY_LEVEL_LOW BIT(1)
1399+
#define FLAG_UNIFIED_BATTERY_LEVEL_GOOD BIT(2)
1400+
#define FLAG_UNIFIED_BATTERY_LEVEL_FULL BIT(3)
1401+
1402+
#define FLAG_UNIFIED_BATTERY_FLAGS_RECHARGEABLE BIT(0)
1403+
#define FLAG_UNIFIED_BATTERY_FLAGS_STATE_OF_CHARGE BIT(1)
1404+
1405+
static int hidpp20_unifiedbattery_get_capabilities(struct hidpp_device *hidpp,
1406+
u8 feature_index)
1407+
{
1408+
struct hidpp_report response;
1409+
int ret;
1410+
u8 *params = (u8 *)response.fap.params;
1411+
1412+
if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS ||
1413+
hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE) {
1414+
/* we have already set the device capabilities, so let's skip */
1415+
return 0;
1416+
}
1417+
1418+
ret = hidpp_send_fap_command_sync(hidpp, feature_index,
1419+
CMD_UNIFIED_BATTERY_GET_CAPABILITIES,
1420+
NULL, 0, &response);
1421+
/* Ignore these intermittent errors */
1422+
if (ret == HIDPP_ERROR_RESOURCE_ERROR)
1423+
return -EIO;
1424+
if (ret > 0) {
1425+
hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
1426+
__func__, ret);
1427+
return -EPROTO;
1428+
}
1429+
if (ret)
1430+
return ret;
1431+
1432+
/*
1433+
* If the device supports state of charge (battery percentage) we won't
1434+
* export the battery level information. there are 4 possible battery
1435+
* levels and they all are optional, this means that the device might
1436+
* not support any of them, we are just better off with the battery
1437+
* percentage.
1438+
*/
1439+
if (params[1] & FLAG_UNIFIED_BATTERY_FLAGS_STATE_OF_CHARGE) {
1440+
hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_PERCENTAGE;
1441+
hidpp->battery.supported_levels_1004 = 0;
1442+
} else {
1443+
hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS;
1444+
hidpp->battery.supported_levels_1004 = params[0];
1445+
}
1446+
1447+
return 0;
1448+
}
1449+
1450+
static int hidpp20_unifiedbattery_map_status(struct hidpp_device *hidpp,
1451+
u8 charging_status,
1452+
u8 external_power_status)
1453+
{
1454+
int status;
1455+
1456+
switch (charging_status) {
1457+
case 0: /* discharging */
1458+
status = POWER_SUPPLY_STATUS_DISCHARGING;
1459+
break;
1460+
case 1: /* charging */
1461+
case 2: /* charging slow */
1462+
status = POWER_SUPPLY_STATUS_CHARGING;
1463+
break;
1464+
case 3: /* complete */
1465+
status = POWER_SUPPLY_STATUS_FULL;
1466+
break;
1467+
case 4: /* error */
1468+
status = POWER_SUPPLY_STATUS_NOT_CHARGING;
1469+
hid_info(hidpp->hid_dev, "%s: charging error",
1470+
hidpp->name);
1471+
break;
1472+
default:
1473+
status = POWER_SUPPLY_STATUS_NOT_CHARGING;
1474+
break;
1475+
}
1476+
1477+
return status;
1478+
}
1479+
1480+
static int hidpp20_unifiedbattery_map_level(struct hidpp_device *hidpp,
1481+
u8 battery_level)
1482+
{
1483+
/* cler unsupported level bits */
1484+
battery_level &= hidpp->battery.supported_levels_1004;
1485+
1486+
if (battery_level & FLAG_UNIFIED_BATTERY_LEVEL_FULL)
1487+
return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
1488+
else if (battery_level & FLAG_UNIFIED_BATTERY_LEVEL_GOOD)
1489+
return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
1490+
else if (battery_level & FLAG_UNIFIED_BATTERY_LEVEL_LOW)
1491+
return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
1492+
else if (battery_level & FLAG_UNIFIED_BATTERY_LEVEL_CRITICAL)
1493+
return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
1494+
1495+
return POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
1496+
}
1497+
1498+
static int hidpp20_unifiedbattery_get_status(struct hidpp_device *hidpp,
1499+
u8 feature_index,
1500+
u8 *state_of_charge,
1501+
int *status,
1502+
int *level)
1503+
{
1504+
struct hidpp_report response;
1505+
int ret;
1506+
u8 *params = (u8 *)response.fap.params;
1507+
1508+
ret = hidpp_send_fap_command_sync(hidpp, feature_index,
1509+
CMD_UNIFIED_BATTERY_GET_STATUS,
1510+
NULL, 0, &response);
1511+
/* Ignore these intermittent errors */
1512+
if (ret == HIDPP_ERROR_RESOURCE_ERROR)
1513+
return -EIO;
1514+
if (ret > 0) {
1515+
hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
1516+
__func__, ret);
1517+
return -EPROTO;
1518+
}
1519+
if (ret)
1520+
return ret;
1521+
1522+
*state_of_charge = params[0];
1523+
*status = hidpp20_unifiedbattery_map_status(hidpp, params[2], params[3]);
1524+
*level = hidpp20_unifiedbattery_map_level(hidpp, params[1]);
1525+
1526+
return 0;
1527+
}
1528+
1529+
static int hidpp20_query_battery_info_1004(struct hidpp_device *hidpp)
1530+
{
1531+
u8 feature_type;
1532+
int ret;
1533+
u8 state_of_charge;
1534+
int status, level;
1535+
1536+
if (hidpp->battery.feature_index == 0xff) {
1537+
ret = hidpp_root_get_feature(hidpp,
1538+
HIDPP_PAGE_UNIFIED_BATTERY,
1539+
&hidpp->battery.feature_index,
1540+
&feature_type);
1541+
if (ret)
1542+
return ret;
1543+
}
1544+
1545+
ret = hidpp20_unifiedbattery_get_capabilities(hidpp,
1546+
hidpp->battery.feature_index);
1547+
if (ret)
1548+
return ret;
1549+
1550+
ret = hidpp20_unifiedbattery_get_status(hidpp,
1551+
hidpp->battery.feature_index,
1552+
&state_of_charge,
1553+
&status,
1554+
&level);
1555+
if (ret)
1556+
return ret;
1557+
1558+
hidpp->capabilities |= HIDPP_CAPABILITY_UNIFIED_BATTERY;
1559+
hidpp->battery.capacity = state_of_charge;
1560+
hidpp->battery.status = status;
1561+
hidpp->battery.level = level;
1562+
hidpp->battery.online = true;
1563+
1564+
return 0;
1565+
}
1566+
1567+
static int hidpp20_battery_event_1004(struct hidpp_device *hidpp,
1568+
u8 *data, int size)
1569+
{
1570+
struct hidpp_report *report = (struct hidpp_report *)data;
1571+
u8 *params = (u8 *)report->fap.params;
1572+
int state_of_charge, status, level;
1573+
bool changed;
1574+
1575+
if (report->fap.feature_index != hidpp->battery.feature_index ||
1576+
report->fap.funcindex_clientid != EVENT_UNIFIED_BATTERY_STATUS_EVENT)
1577+
return 0;
1578+
1579+
state_of_charge = params[0];
1580+
status = hidpp20_unifiedbattery_map_status(hidpp, params[2], params[3]);
1581+
level = hidpp20_unifiedbattery_map_level(hidpp, params[1]);
1582+
1583+
changed = status != hidpp->battery.status ||
1584+
(state_of_charge != hidpp->battery.capacity &&
1585+
hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE) ||
1586+
(level != hidpp->battery.level &&
1587+
hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS);
1588+
1589+
if (changed) {
1590+
hidpp->battery.capacity = state_of_charge;
1591+
hidpp->battery.status = status;
1592+
hidpp->battery.level = level;
1593+
if (hidpp->battery.ps)
1594+
power_supply_changed(hidpp->battery.ps);
1595+
}
1596+
1597+
return 0;
1598+
}
1599+
1600+
/* -------------------------------------------------------------------------- */
1601+
/* Battery feature helpers */
1602+
/* -------------------------------------------------------------------------- */
1603+
13831604
static enum power_supply_property hidpp_battery_props[] = {
13841605
POWER_SUPPLY_PROP_ONLINE,
13851606
POWER_SUPPLY_PROP_STATUS,
@@ -3307,7 +3528,10 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
33073528
}
33083529

33093530
if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY) {
3310-
ret = hidpp20_battery_event(hidpp, data, size);
3531+
ret = hidpp20_battery_event_1000(hidpp, data, size);
3532+
if (ret != 0)
3533+
return ret;
3534+
ret = hidpp20_battery_event_1004(hidpp, data, size);
33113535
if (ret != 0)
33123536
return ret;
33133537
ret = hidpp_solar_battery_event(hidpp, data, size);
@@ -3443,9 +3667,14 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
34433667
if (hidpp->quirks & HIDPP_QUIRK_CLASS_K750)
34443668
ret = hidpp_solar_request_battery_event(hidpp);
34453669
else {
3446-
ret = hidpp20_query_battery_voltage_info(hidpp);
3670+
/* we only support one battery feature right now, so let's
3671+
first check the ones that support battery level first
3672+
and leave voltage for last */
3673+
ret = hidpp20_query_battery_info_1000(hidpp);
3674+
if (ret)
3675+
ret = hidpp20_query_battery_info_1004(hidpp);
34473676
if (ret)
3448-
ret = hidpp20_query_battery_info(hidpp);
3677+
ret = hidpp20_query_battery_voltage_info(hidpp);
34493678
}
34503679

34513680
if (ret)
@@ -3473,7 +3702,8 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
34733702

34743703
num_battery_props = ARRAY_SIZE(hidpp_battery_props) - 3;
34753704

3476-
if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE)
3705+
if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE ||
3706+
hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE)
34773707
battery_props[num_battery_props++] =
34783708
POWER_SUPPLY_PROP_CAPACITY;
34793709

@@ -3650,8 +3880,10 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
36503880
} else if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY) {
36513881
if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE)
36523882
hidpp20_query_battery_voltage_info(hidpp);
3883+
else if (hidpp->capabilities & HIDPP_CAPABILITY_UNIFIED_BATTERY)
3884+
hidpp20_query_battery_info_1004(hidpp);
36533885
else
3654-
hidpp20_query_battery_info(hidpp);
3886+
hidpp20_query_battery_info_1000(hidpp);
36553887
}
36563888
if (hidpp->battery.ps)
36573889
power_supply_changed(hidpp->battery.ps);

0 commit comments

Comments
 (0)