All of lore.kernel.org
 help / color / mirror / Atom feed
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
To: Jiri Kosina <jikos@kernel.org>,
	Bastien Nocera <hadess@hadess.net>,
	Peter Hutterer <peter.hutterer@who-t.net>,
	Nestor Lopez Casado <nlopezcasad@logitech.com>,
	Olivier Gay <ogay@logitech.com>, Simon Wood <simon@mungewell.org>
Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 09/17] HID: logitech-hidpp: enable HID++ 1.0 battery reporting
Date: Tue, 17 Jan 2017 15:35:39 +0100	[thread overview]
Message-ID: <20170117143547.30488-10-benjamin.tissoires@redhat.com> (raw)
In-Reply-To: <20170117143547.30488-1-benjamin.tissoires@redhat.com>

Also enable battery reporting for HID++ 1.0 devices through 2 registers:
0x07: battery status -> reports only 4 levels (critical, low, good, full)
0x0D: battery mileage -> reports true pourcentage

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/hid/hid-logitech-hidpp.c | 209 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 208 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 91ea553..1fd95c2 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -393,6 +393,198 @@ static void hidpp_prefix_name(char **name, int name_length)
 #define HIDPP_SET_LONG_REGISTER				0x82
 #define HIDPP_GET_LONG_REGISTER				0x83
 
+#define HIDPP_REG_GENERAL				0x00
+
+static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev)
+{
+	struct hidpp_report response;
+	int ret;
+	u8 params[3] = { 0 };
+
+	ret = hidpp_send_rap_command_sync(hidpp_dev,
+					REPORT_ID_HIDPP_SHORT,
+					HIDPP_GET_REGISTER,
+					HIDPP_REG_GENERAL,
+					NULL, 0, &response);
+	if (ret)
+		return ret;
+
+	memcpy(params, response.rap.params, 3);
+
+	/* Set the battery bit */
+	params[0] |= BIT(4);
+
+	return hidpp_send_rap_command_sync(hidpp_dev,
+					REPORT_ID_HIDPP_SHORT,
+					HIDPP_SET_REGISTER,
+					HIDPP_REG_GENERAL,
+					params, 3, &response);
+}
+
+#define HIDPP_REG_BATTERY_STATUS			0x07
+
+static int hidpp10_battery_status_map_level(u8 param)
+{
+	int level;
+
+	switch (param) {
+	case 1 ... 2:
+		level = 5;
+		break;
+	case 3 ... 4:
+		level = 20;
+		break;
+	case 5 ... 6:
+		level = 55;
+		break;
+	case 7:
+		level = 90;
+		break;
+	default:
+		level = 0;
+	}
+
+	return level;
+}
+
+static int hidpp10_battery_status_map_status(u8 param)
+{
+	int status;
+
+	switch (param) {
+	case 0x00:
+		/* discharging (in use) */
+		status = POWER_SUPPLY_STATUS_DISCHARGING;
+		break;
+	case 0x21: /* (standard) charging */
+	case 0x24: /* fast charging */
+	case 0x25: /* slow charging */
+		status = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	case 0x26: /* topping charge */
+	case 0x22: /* charge complete */
+		status = POWER_SUPPLY_STATUS_FULL;
+		break;
+	/*
+	 * 0x01...0x1F = reserved (not charging)
+	 * 0x20 = unknown
+	 * 0x23 = charging error
+	 * 0x27..0xff = reserved
+	 */
+	default:
+		status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		break;
+	}
+
+	return status;
+}
+
+static int hidpp10_query_battery_status(struct hidpp_device *hidpp)
+{
+	struct hidpp_report response;
+	int ret;
+
+	ret = hidpp_send_rap_command_sync(hidpp,
+					REPORT_ID_HIDPP_SHORT,
+					HIDPP_GET_REGISTER,
+					HIDPP_REG_BATTERY_STATUS,
+					NULL, 0, &response);
+	if (ret)
+		return ret;
+
+	hidpp->battery.level =
+		hidpp10_battery_status_map_level(response.rap.params[0]);
+
+	hidpp->battery.status =
+		hidpp10_battery_status_map_status(response.rap.params[1]);
+
+	return 0;
+}
+
+#define HIDPP_REG_BATTERY_MILEAGE			0x0D
+
+static int hidpp10_battery_mileage_map_status(u8 param)
+{
+	int status;
+
+	switch (param >> 6) {
+	case 0x00:
+		/* discharging (in use) */
+		status = POWER_SUPPLY_STATUS_DISCHARGING;
+		break;
+	case 0x01: /* charging */
+		status = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	case 0x02: /* charge complete */
+		status = POWER_SUPPLY_STATUS_FULL;
+		break;
+	/*
+	 * 0x03 = charging error
+	 */
+	default:
+		status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		break;
+	}
+
+	return status;
+}
+
+static int hidpp10_query_battery_mileage(struct hidpp_device *hidpp)
+{
+	struct hidpp_report response;
+	int ret;
+
+	ret = hidpp_send_rap_command_sync(hidpp,
+					REPORT_ID_HIDPP_SHORT,
+					HIDPP_GET_REGISTER,
+					HIDPP_REG_BATTERY_MILEAGE,
+					NULL, 0, &response);
+	if (ret)
+		return ret;
+
+	hidpp->battery.level = response.rap.params[0];
+
+	hidpp->battery.status =
+		hidpp10_battery_mileage_map_status(response.rap.params[2]);
+
+	return 0;
+}
+
+static int hidpp10_battery_event(struct hidpp_device *hidpp, u8 *data, int size)
+{
+	struct hidpp_report *report = (struct hidpp_report *)data;
+	int status, level;
+	bool changed;
+
+	if (report->report_id != REPORT_ID_HIDPP_SHORT)
+		return 0;
+
+	switch (report->rap.reg_address) {
+	case HIDPP_REG_BATTERY_STATUS:
+		level = hidpp10_battery_status_map_level(report->rap.params[0]);
+		status = hidpp10_battery_status_map_status(report->rap.params[1]);
+		break;
+	case HIDPP_REG_BATTERY_MILEAGE:
+		level = report->rap.params[0];
+		status = hidpp10_battery_mileage_map_status(report->rap.params[2]);
+		break;
+	default:
+		return 0;
+	}
+
+	changed = level != hidpp->battery.level ||
+		  status != hidpp->battery.status;
+
+	if (changed) {
+		hidpp->battery.level = level;
+		hidpp->battery.status = status;
+		if (hidpp->battery.ps)
+			power_supply_changed(hidpp->battery.ps);
+	}
+
+	return 0;
+}
+
 #define HIDPP_REG_PAIRING_INFORMATION			0xB5
 #define DEVICE_NAME					0x40
 
@@ -2326,6 +2518,12 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
 			return ret;
 	}
 
+	if (hidpp->quirks & HIDPP_QUIRK_HIDPP10_BATTERY) {
+		ret = hidpp10_battery_event(hidpp, data, size);
+		if (ret != 0)
+			return ret;
+	}
+
 	if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
 		return wtp_raw_event(hdev, data, size);
 	else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560)
@@ -2359,7 +2557,16 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
 			return ret;
 		hidpp->quirks |= HIDPP_QUIRK_HIDPP20_BATTERY;
 	} else {
-		return -ENOENT;
+		ret = hidpp10_enable_battery_reporting(hidpp);
+		if (ret)
+			return -ENOENT;
+		ret = hidpp10_query_battery_status(hidpp);
+		if (ret) {
+			ret = hidpp10_query_battery_mileage(hidpp);
+			if (ret)
+				return -ENOENT;
+		}
+		hidpp->quirks |= HIDPP_QUIRK_HIDPP10_BATTERY;
 	}
 
 	battery = &hidpp->battery;
-- 
2.9.3

  parent reply	other threads:[~2017-01-17 14:36 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-01-17 14:35 [PATCH 00/17] Report power supply from hid-logitech-dj and others Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 01/17] HID: logitech-dj: allow devices to request full pairing information Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 02/17] HID: logitech-hidpp: Add scope to battery Benjamin Tissoires
2017-01-18 11:35   ` Bastien Nocera
2017-01-20 13:11   ` Jiri Kosina
2017-01-20 14:25     ` Benjamin Tissoires
2017-01-20 14:26       ` Jiri Kosina
2017-01-17 14:35 ` [PATCH 03/17] HID: logitech-hidpp: make sure we only register one battery per device Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 04/17] HID: logitech-hidpp: battery: remove overloads and provide ONLINE Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 05/17] HID: logitech-hidpp: forward device info in power_supply Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 06/17] HID: logitech-hidpp: create the battery for all types of HID++ devices Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 07/17] HID: logitech-hidpp: return an error if the feature is not present Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 08/17] HID: logitech-hidpp: add support for battery status for the K750 Benjamin Tissoires
2017-01-17 14:35 ` Benjamin Tissoires [this message]
2017-01-17 14:35 ` [PATCH 10/17] HID: logitech-hidpp: notify battery on connect Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 11/17] HID: logitech-hidpp: add a sysfs file to tell we support power_supply Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 12/17] HID: logitech-hidpp: allow non HID++ devices to be handled by this module Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 13/17] HID: logitech-hidpp: make .probe usbhid capable Benjamin Tissoires
2017-01-18  9:26   ` Benjamin Tissoires
2017-01-19 10:56     ` Jiri Kosina
2017-01-19 11:11       ` Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 14/17] HID: logitech-hidpp: do not query the name through HID++ for 1.0 devices Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 15/17] HID: logitech-hidpp: rework probe path for unifying devices Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 16/17] HID: logitech-hidpp: report battery for the G700 over wireless Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 17/17] HID: logitech-hidpp: retrieve the name of the gaming mice " Benjamin Tissoires
2017-01-23 14:35 ` [PATCH 00/17] Report power supply from hid-logitech-dj and others Bastien Nocera
2017-01-23 15:22   ` Benjamin Tissoires
2017-01-24 17:11   ` Bastien Nocera

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170117143547.30488-10-benjamin.tissoires@redhat.com \
    --to=benjamin.tissoires@redhat.com \
    --cc=hadess@hadess.net \
    --cc=jikos@kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nlopezcasad@logitech.com \
    --cc=ogay@logitech.com \
    --cc=peter.hutterer@who-t.net \
    --cc=simon@mungewell.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.