mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 20:51:03 +02:00
Merge branch 'for-5.12/logitech' into for-linus
- support for "Unified Battery (1004) feature" from Filipe Laíns
This commit is contained in:
@@ -647,7 +647,7 @@ static void lg_g15_input_close(struct input_dev *dev)
|
|||||||
|
|
||||||
static int lg_g15_register_led(struct lg_g15_data *g15, int i)
|
static int lg_g15_register_led(struct lg_g15_data *g15, int i)
|
||||||
{
|
{
|
||||||
const char * const led_names[] = {
|
static const char * const led_names[] = {
|
||||||
"g15::kbd_backlight",
|
"g15::kbd_backlight",
|
||||||
"g15::lcd_backlight",
|
"g15::lcd_backlight",
|
||||||
"g15::macro_preset1",
|
"g15::macro_preset1",
|
||||||
|
@@ -92,6 +92,8 @@ MODULE_PARM_DESC(disable_tap_to_click,
|
|||||||
#define HIDPP_CAPABILITY_BATTERY_MILEAGE BIT(2)
|
#define HIDPP_CAPABILITY_BATTERY_MILEAGE BIT(2)
|
||||||
#define HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS BIT(3)
|
#define HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS BIT(3)
|
||||||
#define HIDPP_CAPABILITY_BATTERY_VOLTAGE BIT(4)
|
#define HIDPP_CAPABILITY_BATTERY_VOLTAGE BIT(4)
|
||||||
|
#define HIDPP_CAPABILITY_BATTERY_PERCENTAGE BIT(5)
|
||||||
|
#define HIDPP_CAPABILITY_UNIFIED_BATTERY BIT(6)
|
||||||
|
|
||||||
#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
|
#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
|
||||||
|
|
||||||
@@ -152,6 +154,7 @@ struct hidpp_battery {
|
|||||||
int voltage;
|
int voltage;
|
||||||
int charge_type;
|
int charge_type;
|
||||||
bool online;
|
bool online;
|
||||||
|
u8 supported_levels_1004;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1171,7 +1174,7 @@ static int hidpp20_batterylevel_get_battery_info(struct hidpp_device *hidpp,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hidpp20_query_battery_info(struct hidpp_device *hidpp)
|
static int hidpp20_query_battery_info_1000(struct hidpp_device *hidpp)
|
||||||
{
|
{
|
||||||
u8 feature_type;
|
u8 feature_type;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1208,7 +1211,7 @@ static int hidpp20_query_battery_info(struct hidpp_device *hidpp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hidpp20_battery_event(struct hidpp_device *hidpp,
|
static int hidpp20_battery_event_1000(struct hidpp_device *hidpp,
|
||||||
u8 *data, int size)
|
u8 *data, int size)
|
||||||
{
|
{
|
||||||
struct hidpp_report *report = (struct hidpp_report *)data;
|
struct hidpp_report *report = (struct hidpp_report *)data;
|
||||||
@@ -1380,6 +1383,224 @@ static int hidpp20_battery_voltage_event(struct hidpp_device *hidpp,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* 0x1004: Unified battery */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#define HIDPP_PAGE_UNIFIED_BATTERY 0x1004
|
||||||
|
|
||||||
|
#define CMD_UNIFIED_BATTERY_GET_CAPABILITIES 0x00
|
||||||
|
#define CMD_UNIFIED_BATTERY_GET_STATUS 0x10
|
||||||
|
|
||||||
|
#define EVENT_UNIFIED_BATTERY_STATUS_EVENT 0x00
|
||||||
|
|
||||||
|
#define FLAG_UNIFIED_BATTERY_LEVEL_CRITICAL BIT(0)
|
||||||
|
#define FLAG_UNIFIED_BATTERY_LEVEL_LOW BIT(1)
|
||||||
|
#define FLAG_UNIFIED_BATTERY_LEVEL_GOOD BIT(2)
|
||||||
|
#define FLAG_UNIFIED_BATTERY_LEVEL_FULL BIT(3)
|
||||||
|
|
||||||
|
#define FLAG_UNIFIED_BATTERY_FLAGS_RECHARGEABLE BIT(0)
|
||||||
|
#define FLAG_UNIFIED_BATTERY_FLAGS_STATE_OF_CHARGE BIT(1)
|
||||||
|
|
||||||
|
static int hidpp20_unifiedbattery_get_capabilities(struct hidpp_device *hidpp,
|
||||||
|
u8 feature_index)
|
||||||
|
{
|
||||||
|
struct hidpp_report response;
|
||||||
|
int ret;
|
||||||
|
u8 *params = (u8 *)response.fap.params;
|
||||||
|
|
||||||
|
if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS ||
|
||||||
|
hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE) {
|
||||||
|
/* we have already set the device capabilities, so let's skip */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hidpp_send_fap_command_sync(hidpp, feature_index,
|
||||||
|
CMD_UNIFIED_BATTERY_GET_CAPABILITIES,
|
||||||
|
NULL, 0, &response);
|
||||||
|
/* Ignore these intermittent errors */
|
||||||
|
if (ret == HIDPP_ERROR_RESOURCE_ERROR)
|
||||||
|
return -EIO;
|
||||||
|
if (ret > 0) {
|
||||||
|
hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
|
||||||
|
__func__, ret);
|
||||||
|
return -EPROTO;
|
||||||
|
}
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the device supports state of charge (battery percentage) we won't
|
||||||
|
* export the battery level information. there are 4 possible battery
|
||||||
|
* levels and they all are optional, this means that the device might
|
||||||
|
* not support any of them, we are just better off with the battery
|
||||||
|
* percentage.
|
||||||
|
*/
|
||||||
|
if (params[1] & FLAG_UNIFIED_BATTERY_FLAGS_STATE_OF_CHARGE) {
|
||||||
|
hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_PERCENTAGE;
|
||||||
|
hidpp->battery.supported_levels_1004 = 0;
|
||||||
|
} else {
|
||||||
|
hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS;
|
||||||
|
hidpp->battery.supported_levels_1004 = params[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hidpp20_unifiedbattery_map_status(struct hidpp_device *hidpp,
|
||||||
|
u8 charging_status,
|
||||||
|
u8 external_power_status)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
|
switch (charging_status) {
|
||||||
|
case 0: /* discharging */
|
||||||
|
status = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||||
|
break;
|
||||||
|
case 1: /* charging */
|
||||||
|
case 2: /* charging slow */
|
||||||
|
status = POWER_SUPPLY_STATUS_CHARGING;
|
||||||
|
break;
|
||||||
|
case 3: /* complete */
|
||||||
|
status = POWER_SUPPLY_STATUS_FULL;
|
||||||
|
break;
|
||||||
|
case 4: /* error */
|
||||||
|
status = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||||
|
hid_info(hidpp->hid_dev, "%s: charging error",
|
||||||
|
hidpp->name);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
status = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hidpp20_unifiedbattery_map_level(struct hidpp_device *hidpp,
|
||||||
|
u8 battery_level)
|
||||||
|
{
|
||||||
|
/* cler unsupported level bits */
|
||||||
|
battery_level &= hidpp->battery.supported_levels_1004;
|
||||||
|
|
||||||
|
if (battery_level & FLAG_UNIFIED_BATTERY_LEVEL_FULL)
|
||||||
|
return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
|
||||||
|
else if (battery_level & FLAG_UNIFIED_BATTERY_LEVEL_GOOD)
|
||||||
|
return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
|
||||||
|
else if (battery_level & FLAG_UNIFIED_BATTERY_LEVEL_LOW)
|
||||||
|
return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
|
||||||
|
else if (battery_level & FLAG_UNIFIED_BATTERY_LEVEL_CRITICAL)
|
||||||
|
return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
|
||||||
|
|
||||||
|
return POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hidpp20_unifiedbattery_get_status(struct hidpp_device *hidpp,
|
||||||
|
u8 feature_index,
|
||||||
|
u8 *state_of_charge,
|
||||||
|
int *status,
|
||||||
|
int *level)
|
||||||
|
{
|
||||||
|
struct hidpp_report response;
|
||||||
|
int ret;
|
||||||
|
u8 *params = (u8 *)response.fap.params;
|
||||||
|
|
||||||
|
ret = hidpp_send_fap_command_sync(hidpp, feature_index,
|
||||||
|
CMD_UNIFIED_BATTERY_GET_STATUS,
|
||||||
|
NULL, 0, &response);
|
||||||
|
/* Ignore these intermittent errors */
|
||||||
|
if (ret == HIDPP_ERROR_RESOURCE_ERROR)
|
||||||
|
return -EIO;
|
||||||
|
if (ret > 0) {
|
||||||
|
hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
|
||||||
|
__func__, ret);
|
||||||
|
return -EPROTO;
|
||||||
|
}
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*state_of_charge = params[0];
|
||||||
|
*status = hidpp20_unifiedbattery_map_status(hidpp, params[2], params[3]);
|
||||||
|
*level = hidpp20_unifiedbattery_map_level(hidpp, params[1]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hidpp20_query_battery_info_1004(struct hidpp_device *hidpp)
|
||||||
|
{
|
||||||
|
u8 feature_type;
|
||||||
|
int ret;
|
||||||
|
u8 state_of_charge;
|
||||||
|
int status, level;
|
||||||
|
|
||||||
|
if (hidpp->battery.feature_index == 0xff) {
|
||||||
|
ret = hidpp_root_get_feature(hidpp,
|
||||||
|
HIDPP_PAGE_UNIFIED_BATTERY,
|
||||||
|
&hidpp->battery.feature_index,
|
||||||
|
&feature_type);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hidpp20_unifiedbattery_get_capabilities(hidpp,
|
||||||
|
hidpp->battery.feature_index);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = hidpp20_unifiedbattery_get_status(hidpp,
|
||||||
|
hidpp->battery.feature_index,
|
||||||
|
&state_of_charge,
|
||||||
|
&status,
|
||||||
|
&level);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
hidpp->capabilities |= HIDPP_CAPABILITY_UNIFIED_BATTERY;
|
||||||
|
hidpp->battery.capacity = state_of_charge;
|
||||||
|
hidpp->battery.status = status;
|
||||||
|
hidpp->battery.level = level;
|
||||||
|
hidpp->battery.online = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hidpp20_battery_event_1004(struct hidpp_device *hidpp,
|
||||||
|
u8 *data, int size)
|
||||||
|
{
|
||||||
|
struct hidpp_report *report = (struct hidpp_report *)data;
|
||||||
|
u8 *params = (u8 *)report->fap.params;
|
||||||
|
int state_of_charge, status, level;
|
||||||
|
bool changed;
|
||||||
|
|
||||||
|
if (report->fap.feature_index != hidpp->battery.feature_index ||
|
||||||
|
report->fap.funcindex_clientid != EVENT_UNIFIED_BATTERY_STATUS_EVENT)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
state_of_charge = params[0];
|
||||||
|
status = hidpp20_unifiedbattery_map_status(hidpp, params[2], params[3]);
|
||||||
|
level = hidpp20_unifiedbattery_map_level(hidpp, params[1]);
|
||||||
|
|
||||||
|
changed = status != hidpp->battery.status ||
|
||||||
|
(state_of_charge != hidpp->battery.capacity &&
|
||||||
|
hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE) ||
|
||||||
|
(level != hidpp->battery.level &&
|
||||||
|
hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS);
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
hidpp->battery.capacity = state_of_charge;
|
||||||
|
hidpp->battery.status = status;
|
||||||
|
hidpp->battery.level = level;
|
||||||
|
if (hidpp->battery.ps)
|
||||||
|
power_supply_changed(hidpp->battery.ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Battery feature helpers */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
static enum power_supply_property hidpp_battery_props[] = {
|
static enum power_supply_property hidpp_battery_props[] = {
|
||||||
POWER_SUPPLY_PROP_ONLINE,
|
POWER_SUPPLY_PROP_ONLINE,
|
||||||
POWER_SUPPLY_PROP_STATUS,
|
POWER_SUPPLY_PROP_STATUS,
|
||||||
@@ -3307,7 +3528,10 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY) {
|
if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY) {
|
||||||
ret = hidpp20_battery_event(hidpp, data, size);
|
ret = hidpp20_battery_event_1000(hidpp, data, size);
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
ret = hidpp20_battery_event_1004(hidpp, data, size);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
ret = hidpp_solar_battery_event(hidpp, data, size);
|
ret = hidpp_solar_battery_event(hidpp, data, size);
|
||||||
@@ -3443,9 +3667,14 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
|
|||||||
if (hidpp->quirks & HIDPP_QUIRK_CLASS_K750)
|
if (hidpp->quirks & HIDPP_QUIRK_CLASS_K750)
|
||||||
ret = hidpp_solar_request_battery_event(hidpp);
|
ret = hidpp_solar_request_battery_event(hidpp);
|
||||||
else {
|
else {
|
||||||
ret = hidpp20_query_battery_voltage_info(hidpp);
|
/* we only support one battery feature right now, so let's
|
||||||
|
first check the ones that support battery level first
|
||||||
|
and leave voltage for last */
|
||||||
|
ret = hidpp20_query_battery_info_1000(hidpp);
|
||||||
if (ret)
|
if (ret)
|
||||||
ret = hidpp20_query_battery_info(hidpp);
|
ret = hidpp20_query_battery_info_1004(hidpp);
|
||||||
|
if (ret)
|
||||||
|
ret = hidpp20_query_battery_voltage_info(hidpp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
@@ -3473,7 +3702,8 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
|
|||||||
|
|
||||||
num_battery_props = ARRAY_SIZE(hidpp_battery_props) - 3;
|
num_battery_props = ARRAY_SIZE(hidpp_battery_props) - 3;
|
||||||
|
|
||||||
if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE)
|
if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE ||
|
||||||
|
hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE)
|
||||||
battery_props[num_battery_props++] =
|
battery_props[num_battery_props++] =
|
||||||
POWER_SUPPLY_PROP_CAPACITY;
|
POWER_SUPPLY_PROP_CAPACITY;
|
||||||
|
|
||||||
@@ -3650,8 +3880,10 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
|
|||||||
} else if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY) {
|
} else if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY) {
|
||||||
if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE)
|
if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE)
|
||||||
hidpp20_query_battery_voltage_info(hidpp);
|
hidpp20_query_battery_voltage_info(hidpp);
|
||||||
|
else if (hidpp->capabilities & HIDPP_CAPABILITY_UNIFIED_BATTERY)
|
||||||
|
hidpp20_query_battery_info_1004(hidpp);
|
||||||
else
|
else
|
||||||
hidpp20_query_battery_info(hidpp);
|
hidpp20_query_battery_info_1000(hidpp);
|
||||||
}
|
}
|
||||||
if (hidpp->battery.ps)
|
if (hidpp->battery.ps)
|
||||||
power_supply_changed(hidpp->battery.ps);
|
power_supply_changed(hidpp->battery.ps);
|
||||||
|
Reference in New Issue
Block a user