* [PATCH 0/2] platform: arm64: HP OmniBook 5 16 embedded controller
@ 2026-11-09 10:49 Rahul Pon
2026-11-09 10:49 ` [PATCH 1/2] dt-bindings: embedded-controller: Add HP OmniBook 5 16 EC Rahul Pon
2026-11-09 10:49 ` [PATCH 2/2] platform: arm64: Add HP OmniBook 5 16 embedded controller driver Rahul Pon
0 siblings, 2 replies; 6+ messages in thread
From: Rahul Pon @ 2026-11-09 10:49 UTC (permalink / raw)
To: Hans de Goede, Ilpo Järvinen
Cc: Bryan O'Donoghue, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Guenter Roeck, platform-driver-x86, devicetree,
linux-hwmon, linux-arm-msm, linux-kernel
This series adds a binding and a driver for the embedded controller of
the HP OmniBook 5 Laptop 16-bf1xxx, a laptop with the Snapdragon X2
Plus/Elite SoC.
The EC sits on I2C at 0x76 and takes commands through a mailbox. Its
protocol and its command and event codes follow HP's ACPI methods on
this laptop. The driver exposes the fan speed and four thermistors
through hwmon (the thermistors can also serve as thermal sensors for
skin temperature zones), the mute and mic mute LEDs, the keyboard
backlight timeout and level, and the F9 and F11 hotkeys, which only the
EC reports.
The board device tree that uses this binding will follow in a separate
series to the Qualcomm maintainers.
Testing: the driver has run on the laptop since late September, on
Qualcomm's qcom-next (7.3, latest qcom-next-7.3-20261031). On
next-20261105 the series builds with W=1 and passes dt_binding_check.
Rahul Pon (2):
dt-bindings: embedded-controller: Add HP OmniBook 5 16 EC
platform: arm64: Add HP OmniBook 5 16 embedded controller driver
.../ABI/testing/sysfs-driver-hp-omnibook-5-ec | 19 +
.../hp,omnibook-5-16-bf1xxx-ec.yaml | 49 ++
MAINTAINERS | 8 +
drivers/platform/arm64/Kconfig | 17 +
drivers/platform/arm64/Makefile | 1 +
drivers/platform/arm64/hp-omnibook-5-ec.c | 417 ++++++++++++++++++
6 files changed, 511 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-driver-hp-omnibook-5-ec
create mode 100644 Documentation/devicetree/bindings/embedded-controller/hp,omnibook-5-16-bf1xxx-ec.yaml
create mode 100644 drivers/platform/arm64/hp-omnibook-5-ec.c
base-commit: ddfe51b0a0f5dc9e415cc2c8ad8db17532dd426b
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/2] dt-bindings: embedded-controller: Add HP OmniBook 5 16 EC
2026-11-09 10:49 [PATCH 0/2] platform: arm64: HP OmniBook 5 16 embedded controller Rahul Pon
@ 2026-11-09 10:49 ` Rahul Pon
2026-11-09 14:17 ` Krzysztof Kozlowski
2026-11-09 10:49 ` [PATCH 2/2] platform: arm64: Add HP OmniBook 5 16 embedded controller driver Rahul Pon
1 sibling, 1 reply; 6+ messages in thread
From: Rahul Pon @ 2026-11-09 10:49 UTC (permalink / raw)
To: Hans de Goede, Ilpo Järvinen
Cc: Bryan O'Donoghue, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Guenter Roeck, platform-driver-x86, devicetree,
linux-hwmon, linux-arm-msm, linux-kernel
The HP OmniBook 5 16 (Snapdragon X2) has an embedded controller on I2C
at address 0x76. It runs the fan and the keyboard backlight and reports
the fan speed and its thermistor temperatures.
Signed-off-by: Rahul Pon <theflyingrahul@gmail.com>
---
.../hp,omnibook-5-16-bf1xxx-ec.yaml | 49 +++++++++++++++++++
1 file changed, 49 insertions(+)
create mode 100644 Documentation/devicetree/bindings/embedded-controller/hp,omnibook-5-16-bf1xxx-ec.yaml
diff --git a/Documentation/devicetree/bindings/embedded-controller/hp,omnibook-5-16-bf1xxx-ec.yaml b/Documentation/devicetree/bindings/embedded-controller/hp,omnibook-5-16-bf1xxx-ec.yaml
new file mode 100644
index 0000000000..be4c845067
--- /dev/null
+++ b/Documentation/devicetree/bindings/embedded-controller/hp,omnibook-5-16-bf1xxx-ec.yaml
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/embedded-controller/hp,omnibook-5-16-bf1xxx-ec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: HP OmniBook 5 16 Embedded Controller
+
+maintainers:
+ - Rahul Pon <theflyingrahul@gmail.com>
+
+description:
+ The embedded controller of the HP OmniBook 5 16 (Snapdragon X2), on an
+ I2C bus. It runs the fan and the keyboard backlight and reports the fan
+ speed and its thermistor temperatures. Its four thermistors can serve
+ as thermal sensors, indexed 0 to 3.
+
+properties:
+ compatible:
+ const: hp,omnibook-5-16-bf1xxx-ec
+
+ reg:
+ const: 0x76
+
+ interrupts:
+ maxItems: 1
+
+ "#thermal-sensor-cells":
+ const: 1
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ embedded-controller@76 {
+ compatible = "hp,omnibook-5-16-bf1xxx-ec";
+ reg = <0x76>;
+ #thermal-sensor-cells = <1>;
+ };
+ };
+...
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/2] platform: arm64: Add HP OmniBook 5 16 embedded controller driver
2026-11-09 10:49 [PATCH 0/2] platform: arm64: HP OmniBook 5 16 embedded controller Rahul Pon
2026-11-09 10:49 ` [PATCH 1/2] dt-bindings: embedded-controller: Add HP OmniBook 5 16 EC Rahul Pon
@ 2026-11-09 10:49 ` Rahul Pon
2026-11-09 14:12 ` Konrad Dybcio
1 sibling, 1 reply; 6+ messages in thread
From: Rahul Pon @ 2026-11-09 10:49 UTC (permalink / raw)
To: Hans de Goede, Ilpo Järvinen
Cc: Bryan O'Donoghue, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Guenter Roeck, platform-driver-x86, devicetree,
linux-hwmon, linux-arm-msm, linux-kernel
The embedded controller of the HP OmniBook 5 16 (Snapdragon X2) sits on
I2C at address 0x76 and takes commands through a mailbox: wait for an
idle status (0xef), write the command and sub-command (0xed), wait for
completion, then read the 32-byte reply (0xee). Its interrupt line
signals events, read from register 0x00 and acknowledged by writing 0
back, as HP's ACPI does.
Expose:
- the fan speed and the four thermistors HP's thermal zones use, through
hwmon;
- the two EC LEDs HP's mute LED WMI methods drive, as the mute and mic
mute LEDs;
- the keyboard backlight timeout (30 s, 3 min or always on) and the
current backlight level as sysfs attributes; the EC runs the backlight
itself, and its backlight events notify the level attribute;
- the F9 (mic mute) and F11 (programmable) hotkeys, which only the EC
reports, as input events, using HP's WMI key codes as hp-wmi maps them.
The command codes, event codes and reply formats are the ones HP's ACPI
methods use on this laptop.
Signed-off-by: Rahul Pon <theflyingrahul@gmail.com>
---
.../ABI/testing/sysfs-driver-hp-omnibook-5-ec | 19 +
MAINTAINERS | 8 +
drivers/platform/arm64/Kconfig | 17 +
drivers/platform/arm64/Makefile | 1 +
drivers/platform/arm64/hp-omnibook-5-ec.c | 417 ++++++++++++++++++
5 files changed, 462 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-driver-hp-omnibook-5-ec
create mode 100644 drivers/platform/arm64/hp-omnibook-5-ec.c
diff --git a/Documentation/ABI/testing/sysfs-driver-hp-omnibook-5-ec b/Documentation/ABI/testing/sysfs-driver-hp-omnibook-5-ec
new file mode 100644
index 0000000000..4c6f5cb20e
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hp-omnibook-5-ec
@@ -0,0 +1,19 @@
+What: /sys/bus/i2c/devices/<bus>-0076/kbd_backlight_timeout
+Date: September 2026
+KernelVersion: 7.4
+Contact: Rahul Pon <theflyingrahul@gmail.com>
+Description:
+ (RW) How long the keyboard backlight of the HP OmniBook 5 16
+ stays on after the last key press, as the embedded controller
+ applies it: "30s", "3min" or "always". The Fn key still turns
+ the backlight on and off.
+
+What: /sys/bus/i2c/devices/<bus>-0076/kbd_backlight_level
+Date: September 2026
+KernelVersion: 7.4
+Contact: Rahul Pon <theflyingrahul@gmail.com>
+Description:
+ (RO) The keyboard backlight level of the HP OmniBook 5 16:
+ 0 (off), 1 or 2. Only the backlight key changes it, inside the
+ embedded controller. The attribute is notified when the EC
+ reports a change.
diff --git a/MAINTAINERS b/MAINTAINERS
index aa647f5d37..d043a2f8f6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12284,6 +12284,14 @@ L: platform-driver-x86@vger.kernel.org
S: Orphan
F: drivers/platform/x86/hp/tc1100-wmi.c
+HP OMNIBOOK 5 16 EMBEDDED CONTROLLER DRIVER
+M: Rahul Pon <theflyingrahul@gmail.com>
+L: platform-driver-x86@vger.kernel.org
+S: Maintained
+F: Documentation/ABI/testing/sysfs-driver-hp-omnibook-5-ec
+F: Documentation/devicetree/bindings/embedded-controller/hp,omnibook-5-16-bf1xxx-ec.yaml
+F: drivers/platform/arm64/hp-omnibook-5-ec.c
+
HP WMI HARDWARE MONITOR DRIVER
M: James Seo <james@equiv.tech>
L: linux-hwmon@vger.kernel.org
diff --git a/drivers/platform/arm64/Kconfig b/drivers/platform/arm64/Kconfig
index 3f879410b3..2b34f5ab1b 100644
--- a/drivers/platform/arm64/Kconfig
+++ b/drivers/platform/arm64/Kconfig
@@ -48,6 +48,23 @@ config EC_ASUS_GLYMUR
temperature sensors readout, fan monitoring, keyboard and EC event
reporting.
+config EC_HP_OMNIBOOK5
+ tristate "HP OmniBook 5 16 Embedded Controller driver"
+ depends on ARCH_QCOM || COMPILE_TEST
+ depends on I2C
+ depends on HWMON
+ depends on INPUT
+ select INPUT_SPARSEKMAP
+ select LEDS_CLASS
+ select NEW_LEDS
+ help
+ Driver for the Embedded Controller in the Snapdragon X2-based HP
+ OmniBook 5 16, which reports the fan speed, thermistor
+ temperatures and hotkeys, and drives the mute LEDs and the
+ keyboard backlight timeout.
+
+ Say M or Y here to include this support.
+
config EC_HUAWEI_GAOKUN
tristate "Huawei Matebook E Go Embedded Controller driver"
depends on ARCH_QCOM || COMPILE_TEST
diff --git a/drivers/platform/arm64/Makefile b/drivers/platform/arm64/Makefile
index 3bc3d4669c..6c72726eae 100644
--- a/drivers/platform/arm64/Makefile
+++ b/drivers/platform/arm64/Makefile
@@ -7,6 +7,7 @@
obj-$(CONFIG_EC_ACER_ASPIRE1) += acer-aspire1-ec.o
obj-$(CONFIG_EC_ASUS_GLYMUR) += asus-glymur-ec.o
+obj-$(CONFIG_EC_HP_OMNIBOOK5) += hp-omnibook-5-ec.o
obj-$(CONFIG_EC_HUAWEI_GAOKUN) += huawei-gaokun-ec.o
obj-$(CONFIG_EC_LENOVO_YOGA_C630) += lenovo-yoga-c630.o
obj-$(CONFIG_EC_LENOVO_THINKPAD_T14S) += lenovo-thinkpad-t14s.o
diff --git a/drivers/platform/arm64/hp-omnibook-5-ec.c b/drivers/platform/arm64/hp-omnibook-5-ec.c
new file mode 100644
index 0000000000..bfe20e12aa
--- /dev/null
+++ b/drivers/platform/arm64/hp-omnibook-5-ec.c
@@ -0,0 +1,417 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * HP OmniBook 5 16 (Snapdragon X2) embedded controller
+ *
+ * The EC takes commands through a mailbox: wait for an idle status, write
+ * the command, wait for it to complete, then read the reply. Command codes
+ * are the ones HP's ACPI tables use on this laptop.
+ */
+
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/hwmon.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/interrupt.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/unaligned.h>
+
+/* The pending event, cleared by writing 0 (HP's IC10.INTR, field CMD5) */
+#define HPEC_EVENT 0x00
+#define HPEC_STATUS 0xef
+#define HPEC_REQUEST 0xed
+#define HPEC_REPLY 0xee
+#define HPEC_REPLY_LEN 32
+
+#define HPEC_STATUS_IDLE 0x00
+#define HPEC_STATUS_DONE 0xe0
+#define HPEC_POLL_TRIES 20
+#define HPEC_POLL_US 5000
+
+#define HPEC_OS_FLAG 0x01
+#define HPEC_OS_FLAG_LEDS 0x84
+#define HPEC_KBD 0x05
+#define HPEC_KBD_TIMEOUT_GET 0xfe
+#define HPEC_KBD_LEVEL_GET 0xff
+#define HPEC_LED 0x06
+#define HPEC_LED_GET 0xff
+#define HPEC_LED_ON 0x80
+#define HPEC_THERMISTOR 0x26
+#define HPEC_THERMISTOR_INVALID 0xff
+#define HPEC_FAN 0xbc
+#define HPEC_FAN_RPM 0x03
+
+/* The four thermistors HP's thermal zones enable, in their order */
+static const u8 hpec_thermistors[] = { 0x00, 0x07, 0x04, 0x0a };
+
+static const char * const hpec_thermistor_labels[] = {
+ "EC thermistor 1", "EC thermistor 2", "EC thermistor 3", "EC thermistor 4",
+};
+
+/* EC events, with HP's WMI hotkey codes from hp-wmi where they exist */
+#define HPEC_EVENT_HOT 0x0b
+#define HPEC_EVENT_KBD 0x0d
+#define HPEC_EVENT_KBD_KEY 0x1d
+
+static const struct key_entry hpec_keymap[] = {
+ { KE_IGNORE, 0x0d, }, /* backlight key, run by the EC */
+ { KE_KEY, 0x11, { KEY_MICMUTE } }, /* F9, WMI 0x270 */
+ { KE_IGNORE, 0x1d, }, /* backlight key, run by the EC */
+ { KE_KEY, 0x1e, { KEY_PROG2 } }, /* F11, WMI 0x21a8 */
+ { KE_IGNORE, 0x30, }, /* fan and thermistor notices */
+ { KE_IGNORE, 0x31, },
+ { KE_IGNORE, 0x32, },
+ { KE_IGNORE, 0x33, },
+ { KE_IGNORE, 0x34, },
+ { KE_IGNORE, 0x35, },
+ { KE_IGNORE, 0x36, },
+ { KE_IGNORE, 0x37, },
+ { KE_IGNORE, 0x38, },
+ { KE_IGNORE, 0x88, }, /* Fn lock, WMI 0x21ab */
+ { KE_END, 0 }
+};
+
+/* Keyboard backlight timeout, in EC value order */
+static const char * const hpec_kbd_timeouts[] = { "30s", "3min", "always" };
+
+/* EC LEDs 8 and 9, which HP's mute LED WMI methods drive */
+static const struct {
+ const char *name;
+ const char *trigger;
+ u8 index;
+} hpec_leds[] = {
+ { "platform::mute", "audio-mute", 0x08 },
+ { "platform::micmute", "audio-micmute", 0x09 },
+};
+
+struct hpec;
+
+struct hpec_led {
+ struct led_classdev cdev;
+ struct hpec *ec;
+ u8 index;
+};
+
+struct hpec {
+ struct i2c_client *client;
+ struct mutex lock; /* serializes mailbox commands */
+ struct hpec_led leds[ARRAY_SIZE(hpec_leds)];
+ struct input_dev *input;
+};
+
+static int hpec_wait(struct hpec *ec, u8 status)
+{
+ int i, ret;
+
+ for (i = 0; i < HPEC_POLL_TRIES; i++) {
+ ret = i2c_smbus_read_byte_data(ec->client, HPEC_STATUS);
+ if (ret < 0)
+ return ret;
+ if (ret == status)
+ return 0;
+ fsleep(HPEC_POLL_US);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int hpec_command(struct hpec *ec, u8 cmd, u8 sub, u8 reply[HPEC_REPLY_LEN])
+{
+ u8 request[] = { cmd, sub };
+ int ret;
+
+ guard(mutex)(&ec->lock);
+
+ ret = hpec_wait(ec, HPEC_STATUS_IDLE);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_i2c_block_data(ec->client, HPEC_REQUEST,
+ sizeof(request), request);
+ if (ret)
+ return ret;
+
+ ret = hpec_wait(ec, HPEC_STATUS_DONE);
+ if (ret || !reply)
+ return ret;
+
+ ret = i2c_smbus_read_i2c_block_data(ec->client, HPEC_REPLY,
+ HPEC_REPLY_LEN, reply);
+ if (ret < 0)
+ return ret;
+
+ return ret == HPEC_REPLY_LEN ? 0 : -EIO;
+}
+
+static int hpec_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct hpec *ec = dev_get_drvdata(dev);
+ u8 reply[HPEC_REPLY_LEN];
+ int ret;
+
+ switch (type) {
+ case hwmon_fan:
+ ret = hpec_command(ec, HPEC_FAN, HPEC_FAN_RPM, reply);
+ if (ret)
+ return ret;
+ *val = get_unaligned_le16(reply);
+ return 0;
+ case hwmon_temp:
+ ret = hpec_command(ec, HPEC_THERMISTOR, hpec_thermistors[channel], reply);
+ if (ret)
+ return ret;
+ if (reply[0] == HPEC_THERMISTOR_INVALID)
+ return -ENODATA;
+ *val = reply[0] * 1000;
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int hpec_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ if (type != hwmon_temp)
+ return -EOPNOTSUPP;
+
+ *str = hpec_thermistor_labels[channel];
+ return 0;
+}
+
+static umode_t hpec_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ return 0444;
+}
+
+static const struct hwmon_ops hpec_hwmon_ops = {
+ .is_visible = hpec_hwmon_is_visible,
+ .read = hpec_hwmon_read,
+ .read_string = hpec_hwmon_read_string,
+};
+
+static const struct hwmon_channel_info * const hpec_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
+ HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
+ HWMON_CHANNEL_INFO(temp,
+ HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL),
+ NULL
+};
+
+static const struct hwmon_chip_info hpec_hwmon_chip = {
+ .ops = &hpec_hwmon_ops,
+ .info = hpec_hwmon_info,
+};
+
+static enum led_brightness hpec_led_get(struct led_classdev *cdev)
+{
+ struct hpec_led *led = container_of(cdev, struct hpec_led, cdev);
+ u8 reply[HPEC_REPLY_LEN];
+
+ if (hpec_command(led->ec, HPEC_LED, HPEC_LED_GET, reply))
+ return LED_OFF;
+
+ return (reply[1] >> (led->index - hpec_leds[0].index)) & 1;
+}
+
+static int hpec_led_set(struct led_classdev *cdev, enum led_brightness value)
+{
+ struct hpec_led *led = container_of(cdev, struct hpec_led, cdev);
+ int ret;
+
+ /* As HP's method does before every change */
+ ret = hpec_command(led->ec, HPEC_OS_FLAG, HPEC_OS_FLAG_LEDS, NULL);
+ if (ret)
+ return ret;
+
+ return hpec_command(led->ec, HPEC_LED,
+ led->index | (value ? HPEC_LED_ON : 0), NULL);
+}
+
+static irqreturn_t hpec_irq(int irq, void *data)
+{
+ struct hpec *ec = data;
+ struct device *dev = &ec->client->dev;
+ int event;
+
+ scoped_guard(mutex, &ec->lock) {
+ event = i2c_smbus_read_byte_data(ec->client, HPEC_EVENT);
+ if (event < 0) {
+ dev_err_ratelimited(dev, "cannot read EC event: %d\n", event);
+ return IRQ_HANDLED;
+ }
+ i2c_smbus_write_byte_data(ec->client, HPEC_EVENT, 0);
+ }
+
+ if (!event)
+ return IRQ_HANDLED;
+
+ if (event == HPEC_EVENT_KBD || event == HPEC_EVENT_KBD_KEY)
+ sysfs_notify(&dev->kobj, NULL, "kbd_backlight_level");
+
+ if (event == HPEC_EVENT_HOT) {
+ dev_crit(dev, "EC reports a critical temperature\n");
+ return IRQ_HANDLED;
+ }
+
+ if (!sparse_keymap_report_event(ec->input, event, 1, true))
+ dev_info_ratelimited(dev, "unknown EC event %#x\n", event);
+
+ return IRQ_HANDLED;
+}
+
+static ssize_t kbd_backlight_timeout_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hpec *ec = dev_get_drvdata(dev);
+ u8 reply[HPEC_REPLY_LEN];
+ int ret;
+
+ ret = hpec_command(ec, HPEC_KBD, HPEC_KBD_TIMEOUT_GET, reply);
+ if (ret)
+ return ret;
+
+ if (reply[0] >= ARRAY_SIZE(hpec_kbd_timeouts))
+ return sysfs_emit(buf, "%#x\n", reply[0]);
+
+ return sysfs_emit(buf, "%s\n", hpec_kbd_timeouts[reply[0]]);
+}
+
+static ssize_t kbd_backlight_timeout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hpec *ec = dev_get_drvdata(dev);
+ int i, ret;
+
+ i = sysfs_match_string(hpec_kbd_timeouts, buf);
+ if (i < 0)
+ return i;
+
+ ret = hpec_command(ec, HPEC_KBD, i, NULL);
+
+ return ret ?: count;
+}
+static DEVICE_ATTR_RW(kbd_backlight_timeout);
+
+/* The level is set only by the backlight key, inside the EC */
+static ssize_t kbd_backlight_level_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hpec *ec = dev_get_drvdata(dev);
+ u8 reply[HPEC_REPLY_LEN];
+ int ret;
+
+ ret = hpec_command(ec, HPEC_KBD, HPEC_KBD_LEVEL_GET, reply);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%u\n", reply[0]);
+}
+static DEVICE_ATTR_RO(kbd_backlight_level);
+
+static struct attribute *hpec_attrs[] = {
+ &dev_attr_kbd_backlight_level.attr,
+ &dev_attr_kbd_backlight_timeout.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(hpec);
+
+static int hpec_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct device *hwmon;
+ u8 reply[HPEC_REPLY_LEN];
+ struct hpec *ec;
+ unsigned int i;
+ int ret;
+
+ ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL);
+ if (!ec)
+ return -ENOMEM;
+
+ ec->client = client;
+ i2c_set_clientdata(client, ec);
+ ret = devm_mutex_init(dev, &ec->lock);
+ if (ret)
+ return ret;
+
+ ret = hpec_command(ec, HPEC_FAN, HPEC_FAN_RPM, reply);
+ if (ret)
+ return dev_err_probe(dev, ret, "EC does not answer\n");
+
+ ec->input = devm_input_allocate_device(dev);
+ if (!ec->input)
+ return -ENOMEM;
+
+ ec->input->name = "HP OmniBook 5 EC hotkeys";
+ ec->input->phys = "hp-omnibook-5-ec/input0";
+ ec->input->id.bustype = BUS_I2C;
+
+ ret = sparse_keymap_setup(ec->input, hpec_keymap, NULL);
+ if (ret)
+ return ret;
+
+ ret = input_register_device(ec->input);
+ if (ret)
+ return ret;
+
+ hwmon = devm_hwmon_device_register_with_info(dev, "hp_omnibook_ec", ec,
+ &hpec_hwmon_chip, NULL);
+ if (IS_ERR(hwmon))
+ return PTR_ERR(hwmon);
+
+ for (i = 0; i < ARRAY_SIZE(hpec_leds); i++) {
+ struct hpec_led *led = &ec->leds[i];
+
+ led->ec = ec;
+ led->index = hpec_leds[i].index;
+ led->cdev.name = hpec_leds[i].name;
+ led->cdev.default_trigger = hpec_leds[i].trigger;
+ led->cdev.max_brightness = 1;
+ led->cdev.brightness_get = hpec_led_get;
+ led->cdev.brightness_set_blocking = hpec_led_set;
+
+ ret = devm_led_classdev_register(dev, &led->cdev);
+ if (ret)
+ return ret;
+ }
+
+ if (client->irq > 0) {
+ ret = devm_request_threaded_irq(dev, client->irq, NULL, hpec_irq,
+ IRQF_ONESHOT, "hp-omnibook-5-ec", ec);
+ if (ret)
+ return dev_err_probe(dev, ret, "cannot request the EC interrupt\n");
+ }
+
+ return 0;
+}
+
+static const struct of_device_id hpec_of_match[] = {
+ { .compatible = "hp,omnibook-5-16-bf1xxx-ec" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, hpec_of_match);
+
+static struct i2c_driver hpec_driver = {
+ .driver = {
+ .name = "hp-omnibook-5-ec",
+ .of_match_table = hpec_of_match,
+ .dev_groups = hpec_groups,
+ },
+ .probe = hpec_probe,
+};
+module_i2c_driver(hpec_driver);
+
+MODULE_DESCRIPTION("HP OmniBook 5 16 embedded controller");
+MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] platform: arm64: Add HP OmniBook 5 16 embedded controller driver
2026-11-09 10:49 ` [PATCH 2/2] platform: arm64: Add HP OmniBook 5 16 embedded controller driver Rahul Pon
@ 2026-11-09 14:12 ` Konrad Dybcio
2026-11-09 14:16 ` Ilpo Järvinen
0 siblings, 1 reply; 6+ messages in thread
From: Konrad Dybcio @ 2026-11-09 14:12 UTC (permalink / raw)
To: Rahul Pon, Hans de Goede, Ilpo Järvinen
Cc: Bryan O'Donoghue, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Guenter Roeck, platform-driver-x86, devicetree,
linux-hwmon, linux-arm-msm, linux-kernel
On 11/9/26 11:49 AM, Rahul Pon wrote:
> The embedded controller of the HP OmniBook 5 16 (Snapdragon X2) sits on
> I2C at address 0x76 and takes commands through a mailbox: wait for an
> idle status (0xef), write the command and sub-command (0xed), wait for
> completion, then read the 32-byte reply (0xee). Its interrupt line
> signals events, read from register 0x00 and acknowledged by writing 0
> back, as HP's ACPI does.
[...]
> +What: /sys/bus/i2c/devices/<bus>-0076/kbd_backlight_level
> +Date: September 2026
> +KernelVersion: 7.4
> +Contact: Rahul Pon <theflyingrahul@gmail.com>
> +Description:
> + (RO) The keyboard backlight level of the HP OmniBook 5 16:
> + 0 (off), 1 or 2. Only the backlight key changes it, inside the
> + embedded controller. The attribute is notified when the EC
> + reports a change.
That's already reported in <led_subdevice_path>/brightness
[...]
> +static enum led_brightness hpec_led_get(struct led_classdev *cdev)
> +{
> + struct hpec_led *led = container_of(cdev, struct hpec_led, cdev);
> + u8 reply[HPEC_REPLY_LEN];
> +
> + if (hpec_command(led->ec, HPEC_LED, HPEC_LED_GET, reply))
> + return LED_OFF;
> +
> + return (reply[1] >> (led->index - hpec_leds[0].index)) & 1;
"& 1" -> "& BIT(0)"
Konrad
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] platform: arm64: Add HP OmniBook 5 16 embedded controller driver
2026-11-09 14:12 ` Konrad Dybcio
@ 2026-11-09 14:16 ` Ilpo Järvinen
0 siblings, 0 replies; 6+ messages in thread
From: Ilpo Järvinen @ 2026-11-09 14:16 UTC (permalink / raw)
To: Rahul Pon
Cc: Hans de Goede, Konrad Dybcio, Bryan O'Donoghue, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Guenter Roeck,
platform-driver-x86, devicetree, linux-hwmon, linux-arm-msm,
LKML
On Mon, 9 Nov 2026, Konrad Dybcio wrote:
> On 11/9/26 11:49 AM, Rahul Pon wrote:
> > The embedded controller of the HP OmniBook 5 16 (Snapdragon X2) sits on
> > I2C at address 0x76 and takes commands through a mailbox: wait for an
> > idle status (0xef), write the command and sub-command (0xed), wait for
> > completion, then read the 32-byte reply (0xee). Its interrupt line
> > signals events, read from register 0x00 and acknowledged by writing 0
> > back, as HP's ACPI does.
>
> [...]
>
> > +What: /sys/bus/i2c/devices/<bus>-0076/kbd_backlight_level
> > +Date: September 2026
> > +KernelVersion: 7.4
> > +Contact: Rahul Pon <theflyingrahul@gmail.com>
> > +Description:
> > + (RO) The keyboard backlight level of the HP OmniBook 5 16:
> > + 0 (off), 1 or 2. Only the backlight key changes it, inside the
> > + embedded controller. The attribute is notified when the EC
> > + reports a change.
>
> That's already reported in <led_subdevice_path>/brightness
>
> [...]
>
>
> > +static enum led_brightness hpec_led_get(struct led_classdev *cdev)
> > +{
> > + struct hpec_led *led = container_of(cdev, struct hpec_led, cdev);
> > + u8 reply[HPEC_REPLY_LEN];
> > +
> > + if (hpec_command(led->ec, HPEC_LED, HPEC_LED_GET, reply))
> > + return LED_OFF;
> > +
> > + return (reply[1] >> (led->index - hpec_leds[0].index)) & 1;
>
> "& 1" -> "& BIT(0)"
If that could be named with a define, even better.
--
i.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] dt-bindings: embedded-controller: Add HP OmniBook 5 16 EC
2026-11-09 10:49 ` [PATCH 1/2] dt-bindings: embedded-controller: Add HP OmniBook 5 16 EC Rahul Pon
@ 2026-11-09 14:17 ` Krzysztof Kozlowski
0 siblings, 0 replies; 6+ messages in thread
From: Krzysztof Kozlowski @ 2026-11-09 14:17 UTC (permalink / raw)
To: Rahul Pon, Hans de Goede, Ilpo Järvinen
Cc: Bryan O'Donoghue, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Guenter Roeck, platform-driver-x86, devicetree,
linux-hwmon, linux-arm-msm, linux-kernel
On 09/11/2026 11:49, Rahul Pon wrote:
> The HP OmniBook 5 16 (Snapdragon X2) has an embedded controller on I2C
> at address 0x76. It runs the fan and the keyboard backlight and reports
> the fan speed and its thermistor temperatures.
>
> Signed-off-by: Rahul Pon <theflyingrahul@gmail.com>
> ---
> .../hp,omnibook-5-16-bf1xxx-ec.yaml | 49 +++++++++++++++++++
> 1 file changed, 49 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/embedded-controller/hp,omnibook-5-16-bf1xxx-ec.yaml
>
> diff --git a/Documentation/devicetree/bindings/embedded-controller/hp,omnibook-5-16-bf1xxx-ec.yaml b/Documentation/devicetree/bindings/embedded-controller/hp,omnibook-5-16-bf1xxx-ec.yaml
> new file mode 100644
> index 0000000000..be4c845067
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/embedded-controller/hp,omnibook-5-16-bf1xxx-ec.yaml
> @@ -0,0 +1,49 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/embedded-controller/hp,omnibook-5-16-bf1xxx-ec.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: HP OmniBook 5 16 Embedded Controller
> +
> +maintainers:
> + - Rahul Pon <theflyingrahul@gmail.com>
> +
> +description:
> + The embedded controller of the HP OmniBook 5 16 (Snapdragon X2), on an
> + I2C bus. It runs the fan and the keyboard backlight and reports the fan
> + speed and its thermistor temperatures. Its four thermistors can serve
> + as thermal sensors, indexed 0 to 3.
> +
> +properties:
> + compatible:
> + const: hp,omnibook-5-16-bf1xxx-ec
> +
> + reg:
> + const: 0x76
> +
> + interrupts:
> + maxItems: 1
> +
> + "#thermal-sensor-cells":
> + const: 1
Looks incomplete, test your DTS. Your driver mentions interrupt.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-11-09 14:18 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-09 10:49 [PATCH 0/2] platform: arm64: HP OmniBook 5 16 embedded controller Rahul Pon
2026-11-09 10:49 ` [PATCH 1/2] dt-bindings: embedded-controller: Add HP OmniBook 5 16 EC Rahul Pon
2026-11-09 14:17 ` Krzysztof Kozlowski
2026-11-09 10:49 ` [PATCH 2/2] platform: arm64: Add HP OmniBook 5 16 embedded controller driver Rahul Pon
2026-11-09 14:12 ` Konrad Dybcio
2026-11-09 14:16 ` Ilpo Järvinen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®