diff mbox series

[1/5] HID: logitech-hidpp: Add support for ADC measurement feature

Message ID 20230223132452.37958-1-hadess@hadess.net (mailing list archive)
State Superseded
Headers show
Series [1/5] HID: logitech-hidpp: Add support for ADC measurement feature | expand

Commit Message

Bastien Nocera Feb. 23, 2023, 1:24 p.m. UTC
This is used in a number of headsets to report the voltage of the
battery.

The voltage to capacity conversion is based on the C implementation
in HeadsetControl.

Signed-off-by: Bastien Nocera <hadess@hadess.net>
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=216483
---
 drivers/hid/hid-logitech-hidpp.c | 174 ++++++++++++++++++++++++++++++-
 1 file changed, 172 insertions(+), 2 deletions(-)

Comments

Greg KH Feb. 23, 2023, 1:56 p.m. UTC | #1
On Thu, Feb 23, 2023 at 02:24:48PM +0100, Bastien Nocera wrote:
> This is used in a number of headsets to report the voltage of the
> battery.
> 
> The voltage to capacity conversion is based on the C implementation
> in HeadsetControl.

What is "HeadsetControl"?

> 
> Signed-off-by: Bastien Nocera <hadess@hadess.net>
> BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=216483
> ---
>  drivers/hid/hid-logitech-hidpp.c | 174 ++++++++++++++++++++++++++++++-
>  1 file changed, 172 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
> index ff1fcebf2ec7..f6365cdf2e21 100644
> --- a/drivers/hid/hid-logitech-hidpp.c
> +++ b/drivers/hid/hid-logitech-hidpp.c
> @@ -94,6 +94,7 @@ MODULE_PARM_DESC(disable_tap_to_click,
>  #define HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL	BIT(7)
>  #define HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL	BIT(8)
>  #define HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL	BIT(9)
> +#define HIDPP_CAPABILITY_ADC_MEASUREMENT	BIT(10)
>  
>  #define lg_map_key_clear(c)  hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
>  
> @@ -145,6 +146,7 @@ struct hidpp_battery {
>  	u8 feature_index;
>  	u8 solar_feature_index;
>  	u8 voltage_feature_index;
> +	u8 adc_measurement_feature_index;
>  	struct power_supply_desc desc;
>  	struct power_supply *ps;
>  	char name[64];
> @@ -1744,6 +1746,164 @@ static int hidpp_set_wireless_feature_index(struct hidpp_device *hidpp)
>  	return ret;
>  }
>  
> +/* -------------------------------------------------------------------------- */
> +/* 0x1f20: ADC measurement                                                    */
> +/* -------------------------------------------------------------------------- */
> +
> +#define HIDPP_PAGE_ADC_MEASUREMENT 0x1f20
> +
> +#define CMD_ADC_MEASUREMENT_GET_ADC_MEASUREMENT 0x00
> +
> +#define EVENT_ADC_MEASUREMENT_STATUS_BROADCAST 0x00
> +
> +static int hidpp20_map_adc_measurement_1f20_capacity(struct hid_device *hid_dev, int voltage)
> +{
> +	/* NB: This voltage curve doesn't necessarily map perfectly to all
> +	 * devices that implement the ADC_MEASUREMENT feature. This is because
> +	 * there are a few devices that use different battery technology.
> +	 *
> +	 * Adapted from:
> +	 * https://github.com/Sapd/HeadsetControl/blob/acd972be0468e039b93aae81221f20a54d2d60f7/src/devices/logitech_g633_g933_935.c#L44-L52
> +	 */
> +

No need for a blank line.

> +	static const int voltages[] = {
> +		4030, 4024, 4018, 4011, 4003, 3994, 3985, 3975, 3963, 3951,
> +		3937, 3922, 3907, 3893, 3880, 3868, 3857, 3846, 3837, 3828,
> +		3820, 3812, 3805, 3798, 3791, 3785, 3779, 3773, 3768, 3762,
> +		3757, 3752, 3747, 3742, 3738, 3733, 3729, 3724, 3720, 3716,
> +		3712, 3708, 3704, 3700, 3696, 3692, 3688, 3685, 3681, 3677,
> +		3674, 3670, 3667, 3663, 3660, 3657, 3653, 3650, 3646, 3643,
> +		3640, 3637, 3633, 3630, 3627, 3624, 3620, 3617, 3614, 3611,
> +		3608, 3604, 3601, 3598, 3595, 3592, 3589, 3585, 3582, 3579,
> +		3576, 3573, 3569, 3566, 3563, 3560, 3556, 3553, 3550, 3546,
> +		3543, 3539, 3536, 3532, 3529, 3525, 3499, 3466, 3433, 3399,
> +	};
> +
> +	int i;
> +
> +	BUILD_BUG_ON(ARRAY_SIZE(voltages) != 100);

Why is 100 magic?  If you want it to be 100, say so up in the declaraion
so that the code will enforce that.

> +
> +	if (voltage == 0)
> +		return 0;
> +
> +	if (unlikely(voltage < 3400 || voltage >= 5000))

Why unlikely?  That should only ever be used if you can measure the
performance impact, otherwise please remove it.

> +		hid_warn_once(hid_dev,
> +			      "%s: possibly using the wrong voltage curve\n",
> +			      __func__);
> +
> +	for (i = 0; i < ARRAY_SIZE(voltages); i++) {
> +		if (voltage >= voltages[i])
> +			return ARRAY_SIZE(voltages) - i;
> +	}
> +
> +	return 0;
> +}
> +
> +static int hidpp20_map_adc_measurement_1f20(u8 data[3], int *voltage)
> +{
> +	int status, flags;
> +
> +	flags = (int) data[2];

Why is this now an int?

> +
> +	switch (flags) {
> +	case 0x01:
> +		status = POWER_SUPPLY_STATUS_DISCHARGING;
> +		break;
> +	case 0x03:
> +		status = POWER_SUPPLY_STATUS_CHARGING;
> +		break;
> +	case 0x07:
> +		status = POWER_SUPPLY_STATUS_FULL;
> +		break;
> +	case 0x0F:
> +	default:

You are only checking it for a range 1-f, u8 is just fine, right?

> +		status = POWER_SUPPLY_STATUS_UNKNOWN;
> +		break;
> +	}
> +
> +	*voltage = get_unaligned_be16(data);
> +
> +	dbg_hid("%s: Parsed 1f20 data as flag 0x%02x voltage %dmV\n",
> +		__func__, flags, *voltage);

I doubt you need the __func__ line, right?  dynamic debug provides that
for you automatically if you ask for it.

thanks,

greg k-h
Bastien Nocera Feb. 23, 2023, 2:57 p.m. UTC | #2
On Thu, 2023-02-23 at 14:56 +0100, Greg Kroah-Hartman wrote:
> On Thu, Feb 23, 2023 at 02:24:48PM +0100, Bastien Nocera wrote:
> > This is used in a number of headsets to report the voltage of the
> > battery.
> > 
> > The voltage to capacity conversion is based on the C implementation
> > in HeadsetControl.
> 
> What is "HeadsetControl"?

It the software referenced in the comment after which I don't need a
blank line, just below this comment ;)

> 
> > 
> > Signed-off-by: Bastien Nocera <hadess@hadess.net>
> > BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=216483
> > ---
> >  drivers/hid/hid-logitech-hidpp.c | 174
> > ++++++++++++++++++++++++++++++-
> >  1 file changed, 172 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-
> > logitech-hidpp.c
> > index ff1fcebf2ec7..f6365cdf2e21 100644
> > --- a/drivers/hid/hid-logitech-hidpp.c
> > +++ b/drivers/hid/hid-logitech-hidpp.c
> > @@ -94,6 +94,7 @@ MODULE_PARM_DESC(disable_tap_to_click,
> >  #define HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL  BIT(7)
> >  #define HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL BIT(8)
> >  #define HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL   BIT(9)
> > +#define HIDPP_CAPABILITY_ADC_MEASUREMENT       BIT(10)
> >  
> >  #define lg_map_key_clear(c)  hid_map_usage_clear(hi, usage, bit,
> > max, EV_KEY, (c))
> >  
> > @@ -145,6 +146,7 @@ struct hidpp_battery {
> >         u8 feature_index;
> >         u8 solar_feature_index;
> >         u8 voltage_feature_index;
> > +       u8 adc_measurement_feature_index;
> >         struct power_supply_desc desc;
> >         struct power_supply *ps;
> >         char name[64];
> > @@ -1744,6 +1746,164 @@ static int
> > hidpp_set_wireless_feature_index(struct hidpp_device *hidpp)
> >         return ret;
> >  }
> >  
> > +/* ---------------------------------------------------------------
> > ----------- */
> > +/* 0x1f20: ADC
> > measurement                                                    */
> > +/* ---------------------------------------------------------------
> > ----------- */
> > +
> > +#define HIDPP_PAGE_ADC_MEASUREMENT 0x1f20
> > +
> > +#define CMD_ADC_MEASUREMENT_GET_ADC_MEASUREMENT 0x00
> > +
> > +#define EVENT_ADC_MEASUREMENT_STATUS_BROADCAST 0x00
> > +
> > +static int hidpp20_map_adc_measurement_1f20_capacity(struct
> > hid_device *hid_dev, int voltage)
> > +{
> > +       /* NB: This voltage curve doesn't necessarily map perfectly
> > to all
> > +        * devices that implement the ADC_MEASUREMENT feature. This
> > is because
> > +        * there are a few devices that use different battery
> > technology.
> > +        *
> > +        * Adapted from:
> > +        *
> > https://github.com/Sapd/HeadsetControl/blob/acd972be0468e039b93aae81221f20a54d2d60f7/src/devices/logitech_g633_g933_935.c#L44-L52
> > +        */
> > +

This is the software ^^^^^^^^^^

> No need for a blank line.

Sure.

> > +       static const int voltages[] = {
> > +               4030, 4024, 4018, 4011, 4003, 3994, 3985, 3975,
> > 3963, 3951,
> > +               3937, 3922, 3907, 3893, 3880, 3868, 3857, 3846,
> > 3837, 3828,
> > +               3820, 3812, 3805, 3798, 3791, 3785, 3779, 3773,
> > 3768, 3762,
> > +               3757, 3752, 3747, 3742, 3738, 3733, 3729, 3724,
> > 3720, 3716,
> > +               3712, 3708, 3704, 3700, 3696, 3692, 3688, 3685,
> > 3681, 3677,
> > +               3674, 3670, 3667, 3663, 3660, 3657, 3653, 3650,
> > 3646, 3643,
> > +               3640, 3637, 3633, 3630, 3627, 3624, 3620, 3617,
> > 3614, 3611,
> > +               3608, 3604, 3601, 3598, 3595, 3592, 3589, 3585,
> > 3582, 3579,
> > +               3576, 3573, 3569, 3566, 3563, 3560, 3556, 3553,
> > 3550, 3546,
> > +               3543, 3539, 3536, 3532, 3529, 3525, 3499, 3466,
> > 3433, 3399,
> > +       };
> > +
> > +       int i;
> > +
> > +       BUILD_BUG_ON(ARRAY_SIZE(voltages) != 100);
> 
> Why is 100 magic?  If you want it to be 100, say so up in the
> declaraion
> so that the code will enforce that.

It's the same pattern used in hidpp20_map_battery_capacity() in the
same file. I'll send a patch to fix that too.

> 
> > +
> > +       if (voltage == 0)
> > +               return 0;
> > +
> > +       if (unlikely(voltage < 3400 || voltage >= 5000))
> 
> Why unlikely?  That should only ever be used if you can measure the
> performance impact, otherwise please remove it.
> 
> > +               hid_warn_once(hid_dev,
> > +                             "%s: possibly using the wrong voltage
> > curve\n",
> > +                             __func__);
> > +
> > +       for (i = 0; i < ARRAY_SIZE(voltages); i++) {
> > +               if (voltage >= voltages[i])
> > +                       return ARRAY_SIZE(voltages) - i;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static int hidpp20_map_adc_measurement_1f20(u8 data[3], int
> > *voltage)
> > +{
> > +       int status, flags;
> > +
> > +       flags = (int) data[2];
> 
> Why is this now an int?

Sure.

> > +
> > +       switch (flags) {
> > +       case 0x01:
> > +               status = POWER_SUPPLY_STATUS_DISCHARGING;
> > +               break;
> > +       case 0x03:
> > +               status = POWER_SUPPLY_STATUS_CHARGING;
> > +               break;
> > +       case 0x07:
> > +               status = POWER_SUPPLY_STATUS_FULL;
> > +               break;
> > +       case 0x0F:
> > +       default:
> 
> You are only checking it for a range 1-f, u8 is just fine, right?

Sure.

> 
> > +               status = POWER_SUPPLY_STATUS_UNKNOWN;
> > +               break;
> > +       }
> > +
> > +       *voltage = get_unaligned_be16(data);
> > +
> > +       dbg_hid("%s: Parsed 1f20 data as flag 0x%02x voltage
> > %dmV\n",
> > +               __func__, flags, *voltage);
> 
> I doubt you need the __func__ line, right?  dynamic debug provides
> that
> for you automatically if you ask for it.

Removed.
diff mbox series

Patch

diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index ff1fcebf2ec7..f6365cdf2e21 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -94,6 +94,7 @@  MODULE_PARM_DESC(disable_tap_to_click,
 #define HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL	BIT(7)
 #define HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL	BIT(8)
 #define HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL	BIT(9)
+#define HIDPP_CAPABILITY_ADC_MEASUREMENT	BIT(10)
 
 #define lg_map_key_clear(c)  hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
 
@@ -145,6 +146,7 @@  struct hidpp_battery {
 	u8 feature_index;
 	u8 solar_feature_index;
 	u8 voltage_feature_index;
+	u8 adc_measurement_feature_index;
 	struct power_supply_desc desc;
 	struct power_supply *ps;
 	char name[64];
@@ -1744,6 +1746,164 @@  static int hidpp_set_wireless_feature_index(struct hidpp_device *hidpp)
 	return ret;
 }
 
+/* -------------------------------------------------------------------------- */
+/* 0x1f20: ADC measurement                                                    */
+/* -------------------------------------------------------------------------- */
+
+#define HIDPP_PAGE_ADC_MEASUREMENT 0x1f20
+
+#define CMD_ADC_MEASUREMENT_GET_ADC_MEASUREMENT 0x00
+
+#define EVENT_ADC_MEASUREMENT_STATUS_BROADCAST 0x00
+
+static int hidpp20_map_adc_measurement_1f20_capacity(struct hid_device *hid_dev, int voltage)
+{
+	/* NB: This voltage curve doesn't necessarily map perfectly to all
+	 * devices that implement the ADC_MEASUREMENT feature. This is because
+	 * there are a few devices that use different battery technology.
+	 *
+	 * Adapted from:
+	 * https://github.com/Sapd/HeadsetControl/blob/acd972be0468e039b93aae81221f20a54d2d60f7/src/devices/logitech_g633_g933_935.c#L44-L52
+	 */
+
+	static const int voltages[] = {
+		4030, 4024, 4018, 4011, 4003, 3994, 3985, 3975, 3963, 3951,
+		3937, 3922, 3907, 3893, 3880, 3868, 3857, 3846, 3837, 3828,
+		3820, 3812, 3805, 3798, 3791, 3785, 3779, 3773, 3768, 3762,
+		3757, 3752, 3747, 3742, 3738, 3733, 3729, 3724, 3720, 3716,
+		3712, 3708, 3704, 3700, 3696, 3692, 3688, 3685, 3681, 3677,
+		3674, 3670, 3667, 3663, 3660, 3657, 3653, 3650, 3646, 3643,
+		3640, 3637, 3633, 3630, 3627, 3624, 3620, 3617, 3614, 3611,
+		3608, 3604, 3601, 3598, 3595, 3592, 3589, 3585, 3582, 3579,
+		3576, 3573, 3569, 3566, 3563, 3560, 3556, 3553, 3550, 3546,
+		3543, 3539, 3536, 3532, 3529, 3525, 3499, 3466, 3433, 3399,
+	};
+
+	int i;
+
+	BUILD_BUG_ON(ARRAY_SIZE(voltages) != 100);
+
+	if (voltage == 0)
+		return 0;
+
+	if (unlikely(voltage < 3400 || voltage >= 5000))
+		hid_warn_once(hid_dev,
+			      "%s: possibly using the wrong voltage curve\n",
+			      __func__);
+
+	for (i = 0; i < ARRAY_SIZE(voltages); i++) {
+		if (voltage >= voltages[i])
+			return ARRAY_SIZE(voltages) - i;
+	}
+
+	return 0;
+}
+
+static int hidpp20_map_adc_measurement_1f20(u8 data[3], int *voltage)
+{
+	int status, flags;
+
+	flags = (int) data[2];
+
+	switch (flags) {
+	case 0x01:
+		status = POWER_SUPPLY_STATUS_DISCHARGING;
+		break;
+	case 0x03:
+		status = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	case 0x07:
+		status = POWER_SUPPLY_STATUS_FULL;
+		break;
+	case 0x0F:
+	default:
+		status = POWER_SUPPLY_STATUS_UNKNOWN;
+		break;
+	}
+
+	*voltage = get_unaligned_be16(data);
+
+	dbg_hid("%s: Parsed 1f20 data as flag 0x%02x voltage %dmV\n",
+		__func__, flags, *voltage);
+
+	return status;
+}
+
+/* Return value is whether the device is online */
+static bool hidpp20_get_adc_measurement_1f20(struct hidpp_device *hidpp,
+						 u8 feature_index,
+						 int *status, int *voltage)
+{
+	struct hidpp_report response;
+	int ret;
+	u8 *params = (u8 *)response.fap.params;
+
+	*status = POWER_SUPPLY_STATUS_UNKNOWN;
+	*voltage = 0;
+	ret = hidpp_send_fap_command_sync(hidpp, feature_index,
+					  CMD_ADC_MEASUREMENT_GET_ADC_MEASUREMENT,
+					  NULL, 0, &response);
+
+	if (ret > 0) {
+		hid_dbg(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
+			__func__, ret);
+		return false;
+	}
+
+	*status = hidpp20_map_adc_measurement_1f20(params, voltage);
+	return true;
+}
+
+static int hidpp20_query_adc_measurement_info_1f20(struct hidpp_device *hidpp)
+{
+	u8 feature_type;
+
+	if (hidpp->battery.adc_measurement_feature_index == 0xff) {
+		int ret;
+
+		ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_ADC_MEASUREMENT,
+					     &hidpp->battery.adc_measurement_feature_index,
+					     &feature_type);
+		if (ret)
+			return ret;
+
+		hidpp->capabilities |= HIDPP_CAPABILITY_ADC_MEASUREMENT;
+	}
+
+	hidpp->battery.online = hidpp20_get_adc_measurement_1f20(hidpp,
+								 hidpp->battery.adc_measurement_feature_index,
+								 &hidpp->battery.status,
+								 &hidpp->battery.voltage);
+	hidpp->battery.capacity = hidpp20_map_adc_measurement_1f20_capacity(hidpp->hid_dev,
+									    hidpp->battery.voltage);
+
+	return 0;
+}
+
+static int hidpp20_adc_measurement_event_1f20(struct hidpp_device *hidpp,
+					    u8 *data, int size)
+{
+	struct hidpp_report *report = (struct hidpp_report *)data;
+	int status, voltage;
+
+	if (report->fap.feature_index != hidpp->battery.adc_measurement_feature_index ||
+		report->fap.funcindex_clientid != EVENT_ADC_MEASUREMENT_STATUS_BROADCAST)
+		return 0;
+
+	status = hidpp20_map_adc_measurement_1f20(report->fap.params, &voltage);
+
+	hidpp->battery.online = status != POWER_SUPPLY_STATUS_UNKNOWN;
+
+	if (voltage != hidpp->battery.voltage || status != hidpp->battery.status) {
+		hidpp->battery.status = status;
+		hidpp->battery.voltage = voltage;
+		hidpp->battery.capacity = hidpp20_map_adc_measurement_1f20_capacity(hidpp->hid_dev, voltage);
+		if (hidpp->battery.ps)
+			power_supply_changed(hidpp->battery.ps);
+	}
+	return 0;
+}
+
 /* -------------------------------------------------------------------------- */
 /* 0x2120: Hi-resolution scrolling                                            */
 /* -------------------------------------------------------------------------- */
@@ -3662,6 +3822,9 @@  static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
 		ret = hidpp20_battery_voltage_event(hidpp, data, size);
 		if (ret != 0)
 			return ret;
+		ret = hidpp20_adc_measurement_event_1f20(hidpp, data, size);
+		if (ret != 0)
+			return ret;
 	}
 
 	if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP10_BATTERY) {
@@ -3785,6 +3948,7 @@  static int hidpp_initialize_battery(struct hidpp_device *hidpp)
 	hidpp->battery.feature_index = 0xff;
 	hidpp->battery.solar_feature_index = 0xff;
 	hidpp->battery.voltage_feature_index = 0xff;
+	hidpp->battery.adc_measurement_feature_index = 0xff;
 
 	if (hidpp->protocol_major >= 2) {
 		if (hidpp->quirks & HIDPP_QUIRK_CLASS_K750)
@@ -3798,6 +3962,8 @@  static int hidpp_initialize_battery(struct hidpp_device *hidpp)
 				ret = hidpp20_query_battery_info_1004(hidpp);
 			if (ret)
 				ret = hidpp20_query_battery_voltage_info(hidpp);
+			if (ret)
+				ret = hidpp20_query_adc_measurement_info_1f20(hidpp);
 		}
 
 		if (ret)
@@ -3827,7 +3993,8 @@  static int hidpp_initialize_battery(struct hidpp_device *hidpp)
 
 	if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE ||
 	    hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE ||
-	    hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE)
+	    hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE ||
+	    hidpp->capabilities & HIDPP_CAPABILITY_ADC_MEASUREMENT)
 		battery_props[num_battery_props++] =
 				POWER_SUPPLY_PROP_CAPACITY;
 
@@ -3835,7 +4002,8 @@  static int hidpp_initialize_battery(struct hidpp_device *hidpp)
 		battery_props[num_battery_props++] =
 				POWER_SUPPLY_PROP_CAPACITY_LEVEL;
 
-	if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE)
+	if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE ||
+	    hidpp->capabilities & HIDPP_CAPABILITY_ADC_MEASUREMENT)
 		battery_props[num_battery_props++] =
 			POWER_SUPPLY_PROP_VOLTAGE_NOW;
 
@@ -4008,6 +4176,8 @@  static void hidpp_connect_event(struct hidpp_device *hidpp)
 			hidpp20_query_battery_voltage_info(hidpp);
 		else if (hidpp->capabilities & HIDPP_CAPABILITY_UNIFIED_BATTERY)
 			hidpp20_query_battery_info_1004(hidpp);
+		else if (hidpp->capabilities & HIDPP_CAPABILITY_ADC_MEASUREMENT)
+			hidpp20_query_adc_measurement_info_1f20(hidpp);
 		else
 			hidpp20_query_battery_info_1000(hidpp);
 	}