mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [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®