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
next prev parent reply other threads:[~2017-01-17 14:35 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).