From nobody Fri Sep 25 02:44:30 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0EC824C9DED; Thu, 17 Sep 2026 10:55:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789642527; cv=none; b=UllADSOxjYnSVMzjPyppuxtc5yN+Tgypi4am1s2K1V+4agkuVBV5KhSLgNWognMuwrEIDkSZzSJnCM1V4vK5Y41t8zKBGj7ay7iIwFFH6L0EsWCoDy7K9B9Tuf7Q0BUKkcHeCMSvLqNkiCKxq+DhYg+N+S4IZ/zJxxCMmDlNT3o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789642527; c=relaxed/simple; bh=PoAR3hupbDtlPibwsrlBJ+xtFcQNU2hdxBYV5/qFLpI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=l3u4mFtlyHmGY8GiE41S64YR6s+u/5SjXoRVxeMhkwxCkuLXIe0V4XZPMUlMchxhNXQasqfq3jwCtyyPCPcNJWOsvyQNuLd+7HMvtCEcnhcq5QVAAahJHfUcjoghZQzyou/wF6AhOtGKwmTz4TRm7gpCrQWexzglhKJA+g4Lq2c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=dUYll1zt; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="dUYll1zt" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4C6A71F000FF; Thu, 17 Sep 2026 10:55:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789642516; bh=wHDObbB8BbjSPn9/VI/e2+anNPcai1BrOmtVw+ErO60=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=dUYll1ztdg5T+KzGtaRbIfTZIuHLcSXMrIRpK3+EVjIg9dyOM5fJGisN3j5AZ5l2V ojVUtjQrWwhJCbgbalRKTp9o131oMd0k+RAhXC0zOc2aDQU2lYXrOW9NRMVXBcoZmr Ig2dgJQYlHNiogwBDB8vaMDNsNzgQOfApG6S0NXRubgHTvi1J7BGkrEQ+9UiSrLqM+ C/76BtED5JdOftg5CNcW8i64ZdFz28YOco7BdXkUrD0vpf2oahd9nm/LrSeA6QOI// /bspbjKuVEjszRd+VEq8b8lwFV9v/OvBK7iUFZYpUjbutvNn3aAhVdnz/9JYW2sVMw fnpod9DdQQvpQ== From: Konrad Dybcio Date: Thu, 17 Sep 2026 12:54:56 +0200 Subject: [PATCH 1/3] dt-bindings: embedded-controller: Add ASUS Zenbook A16 EC Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260917-topic-asus_ec-v1-1-373516d347ae@oss.qualcomm.com> References: <20260917-topic-asus_ec-v1-0-373516d347ae@oss.qualcomm.com> In-Reply-To: <20260917-topic-asus_ec-v1-0-373516d347ae@oss.qualcomm.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Konrad Dybcio , Hans de Goede , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Bryan O'Donoghue , Guenter Roeck , Bjorn Andersson , Abel Vesa Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, linux-hwmon@vger.kernel.org, linux-arm-msm@vger.kernel.org, Konrad Dybcio X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1789642507; l=2464; i=konrad.dybcio@oss.qualcomm.com; s=20230215; h=from:subject:message-id; bh=XJtNb5bCJEpgetI4Sny1AMd3zSFrD7OZS124VAW59+4=; b=s1yOCdHfh3ZNC8utT7V/LXcFCr0/G0tdZ9Fc+Ty3/JUwoxC9i0RcgHRbUvPzz+oqTfzq+aQui 7ZUpCGuwDSwBNP4jF6OjLspWA0uarw+mzE4jt/xeSvifQlfF6vQaQDH X-Developer-Key: i=konrad.dybcio@oss.qualcomm.com; a=ed25519; pk=iclgkYvtl2w05SSXO5EjjSYlhFKsJ+5OSZBjOkQuEms= From: Konrad Dybcio Some Qualcomm Snapdragon X2 Elite (Extreme)-based ASUS laptops (at least the Zenbook A14 and A16) expose a custom, somewhat Qualcomm reference-derived EC interface. It allows for fan speed reporting, keyboard backlight setting and receiving of a number of miscellaneous sideband events. Introduce a binding for that class of devices. Signed-off-by: Konrad Dybcio --- .../asus,zenbook-a16-ux3607oa-ec.yaml | 65 ++++++++++++++++++= ++++ 1 file changed, 65 insertions(+) diff --git a/Documentation/devicetree/bindings/embedded-controller/asus,zen= book-a16-ux3607oa-ec.yaml b/Documentation/devicetree/bindings/embedded-cont= roller/asus,zenbook-a16-ux3607oa-ec.yaml new file mode 100644 index 000000000000..27e03c011ad6 --- /dev/null +++ b/Documentation/devicetree/bindings/embedded-controller/asus,zenbook-a1= 6-ux3607oa-ec.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/embedded-controller/asus,zenbook-a16-ux= 3607oa-ec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ASUS Zenbook A16 (UX3607OA)-class Embedded Controller + +maintainers: + - Konrad Dybcio + +description: + The Qualcomm Snapdragon X2 series-based ASUS Zenbook A16 (and similar + machines) come with a custom EC firmware, loosely based on the + Qualcomm reference ("Hamoa CRD EC") implementation, with a lot of + customization. + +properties: + compatible: + enum: + - asus,zenbook-a14-ux3407na-ec + - asus,zenbook-a16-ux3607oa-ec + + reg: + const: 0x76 + + interrupts: + maxItems: 1 + + "#thermal-sensor-cells": + const: 1 + + wakeup-source: true + +required: + - compatible + - reg + - interrupts + - '#thermal-sensor-cells' + - wakeup-source + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells =3D <1>; + #size-cells =3D <0>; + + embedded-controller@76 { + compatible =3D "asus,zenbook-a16-ux3607oa-ec"; + reg =3D <0x76>; + + interrupts-extended =3D <&tlmm 66 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-0 =3D <&ec_int_n_default>; + pinctrl-names =3D "default"; + + #thermal-sensor-cells =3D <1>; + + wakeup-source; + }; + }; +... --=20 2.55.0 From nobody Fri Sep 25 02:44:30 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C3EBE3CB57F; Thu, 17 Sep 2026 10:55:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789642544; cv=none; b=rjav+OcVTyOqixkUeLyPSWQRvdo1XsLUGC8SS2stRu8M5L86Pc/blQWsaIFs+UuHxc+138Wpji+4B0aZR1QhJEpSwUPxEWNEll3YbrakfL2sOX1sGRDSf262OZ9zgmb4Xv9ltLLhT8KV/axK0RcEUbXPWq7eaYA9Oma+tjSxxXw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789642544; c=relaxed/simple; bh=Ry3hogNGzUGKBkUAR9UkoTYXhhe9SYsHfW5ouNcEbVc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=E6fP1ZXE7SyGjjPxImomax/NXkTjA2adE43mAAE8+XqwuNAjBmxNfamrGoTY6e7pttcCcaajy2CtFE932D3HmmRdAEN52D9wOiX2LHIo8Gvv3u0Qdd+2wuEmeEnFj4+9Ywv85XvSvblX7lf3jZfb2vc0hvgp8OdkMsV22Czw578= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Ep3vuSmV; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Ep3vuSmV" Received: by smtp.kernel.org (Postfix) with ESMTPSA id F2F2C1F00898; Thu, 17 Sep 2026 10:55:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789642520; bh=GbyAHls438qnNjUVQj/fD51bBQnFYErnfLSByG/fYWY=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=Ep3vuSmVujNmUJXoax09awB6peHILRgVK8Uw4x25CqvFhnax5ICANfkKuGevNumIT aGlrpPTUUd3t9cu36LuSwN7HPDnS7GptrM1S835okSNJzcPqmTYlRfMaYZYnPfF119 kRdOMs1eacZheKw8O8FSvHJllQBUExGoDokI5CK2XngM7iyZK+8CF7s1STJJT0EDW8 nKjqIBAzZHbMmGjBwvT1czAANh2uun0w3w5iZKKLF+5GG/CJlV+eafWHZ/teZ+GsIO 6r6pDHc/FiVrjo+dmIMVUGVWpwNr936Dn/2gtLgtW2hAqKtIlplhOsIWbMWL2cIDg+ vG/iLOge/JeOw== From: Konrad Dybcio Date: Thu, 17 Sep 2026 12:54:57 +0200 Subject: [PATCH 2/3] platform: arm64: Add a driver for the EC found on ASUS Glymur machines Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260917-topic-asus_ec-v1-2-373516d347ae@oss.qualcomm.com> References: <20260917-topic-asus_ec-v1-0-373516d347ae@oss.qualcomm.com> In-Reply-To: <20260917-topic-asus_ec-v1-0-373516d347ae@oss.qualcomm.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Konrad Dybcio , Hans de Goede , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Bryan O'Donoghue , Guenter Roeck , Bjorn Andersson , Abel Vesa Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, linux-hwmon@vger.kernel.org, linux-arm-msm@vger.kernel.org, Konrad Dybcio X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1789642507; l=17844; i=konrad.dybcio@oss.qualcomm.com; s=20230215; h=from:subject:message-id; bh=z9Z9fo/7PB07mCNIK++hMA2MXBHqzcD4tl1+fUGI8G0=; b=J7TK3gFZz1FRyvsjQEM651DSSvXfIyDimQpuE6KAJLCQW9L0STd2Xx7MO9qNUu0n+nqta09cW /nU1+muKFtACv1pZXDPNeRmhSZoTSya4Ry/pr6imVqjBTgqdeFvUcdb X-Developer-Key: i=konrad.dybcio@oss.qualcomm.com; a=ed25519; pk=iclgkYvtl2w05SSXO5EjjSYlhFKsJ+5OSZBjOkQuEms= From: Konrad Dybcio Some Qualcomm Snapdragon X2 Elite (Extreme)-based ASUS laptops (at least the Zenbook A14 and A16) expose a custom, somewhat Qualcomm reference-derived EC interface. Introduce a driver to communicate with said EC, allowing for fan speed reporting, keyboard backlight setting and receiving of a number of miscellaneous sideband events. Assisted-by: LLM Signed-off-by: Konrad Dybcio --- drivers/platform/arm64/Kconfig | 16 + drivers/platform/arm64/Makefile | 1 + drivers/platform/arm64/asus-glymur-ec.c | 592 ++++++++++++++++++++++++++++= ++++ 3 files changed, 609 insertions(+) diff --git a/drivers/platform/arm64/Kconfig b/drivers/platform/arm64/Kconfig index e32e01b2a9bd..84c475c62990 100644 --- a/drivers/platform/arm64/Kconfig +++ b/drivers/platform/arm64/Kconfig @@ -33,6 +33,22 @@ config EC_ACER_ASPIRE1 laptop where this information is not properly exposed via the standard ACPI devices. =20 +config EC_ASUS_GLYMUR + tristate "ASUS Zenbook A16 (Qualcomm) Embedded Controller driver" + depends on ARCH_QCOM || COMPILE_TEST + depends on I2C + depends on HWMON + depends on INPUT + depends on PM + depends on THERMAL || THERMAL=3Dn + select NEW_LEDS + select LEDS_CLASS + help + Say M or Y here to enable the EC driver for the Qualcomm Snapdragon- + based ASUS Zenbook A16 (UX3607OA) and similar machines. It provides + temperature sensors readout, fan monitoring, keyboard and EC event + reporting. + 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/Makef= ile index 7681be4a46e9..7122e8ea325f 100644 --- a/drivers/platform/arm64/Makefile +++ b/drivers/platform/arm64/Makefile @@ -6,6 +6,7 @@ # =20 obj-$(CONFIG_EC_ACER_ASPIRE1) +=3D acer-aspire1-ec.o +obj-$(CONFIG_EC_ASUS_GLYMUR) +=3D asus-glymur-ec.o obj-$(CONFIG_EC_HUAWEI_GAOKUN) +=3D huawei-gaokun-ec.o obj-$(CONFIG_EC_LENOVO_YOGA_C630) +=3D lenovo-yoga-c630.o obj-$(CONFIG_EC_LENOVO_THINKPAD_T14S) +=3D lenovo-thinkpad-t14s.o diff --git a/drivers/platform/arm64/asus-glymur-ec.c b/drivers/platform/arm= 64/asus-glymur-ec.c new file mode 100644 index 000000000000..dec9b137b820 --- /dev/null +++ b/drivers/platform/arm64/asus-glymur-ec.c @@ -0,0 +1,592 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * The EC firmware on the ASUS Zenbook A16 looks to be derived from the + * 'Qualcomm Hamoa EC' reference base with many major modifications. Some = of + * the original interface is reused, albeit many of its core invariants (s= uch + * as the capabilities bitmap) are absent. + * + * It presents itself as two I2C devices: + * [0x5b] is the custom ASUS interface + * [0x76] is the Hamoa EC-derived interface + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Qualcomm-derived registers (main device @ 0x76) */ +#define ASUS_QCOM_EC_EVENT_CMD 0x05 + +#define ASUS_QCOM_EC_SUBCMD_FULL_VER 0x0f +#define ASUS_QCOM_EC_FULL_VER_LEN 7 + +/* This "read RAM" command isn't actually part of the Qualcomm standard */ +#define ASUS_QCOM_EC_RECM_OFFS 0x52 +#define ASUS_QCOM_EC_RECM_FRAME_LEN 5 + +#define ASUS_QCOM_EC_RAM_FAN_CPU 0x0602 +#define ASUS_QCOM_EC_RAM_AC_STATUS 0x0609 +#define ASUS_QCOM_EC_RAM_FAN_GPU 0x0624 + +#define ASUS_QCOM_EC_MODERN_STANDBY_CMD 0x23 +#define ASUS_QCOM_EC_MODERN_STANDBY_ENTER 0x07 +#define ASUS_QCOM_EC_MODERN_STANDBY_EXIT 0x08 + +/* ASUS-specific registers (secondary device @ 0x5b) */ +#define ASUS_EC_SUBDEV_ADDR 0x5b + +#define ASUS_EC_REQ_REG 0x10 +#define ASUS_EC_RESP_REG 0x11 + +#define ASUS_EC_PAGE_MAILBOX 0xc4 + #define ASUS_EC_MBOX_REG_CMD 0x30 + #define ASUS_EC_MBOX_REG_SUBCMD 0x31 + #define ASUS_EC_MBOX_REG_DATA 0x32 + +#define ASUS_EC_MBOX_CMD_KBD 0x01 + #define ASUS_EC_MBOX_SUBCMD_KBD_EN 0x81 + #define ASUS_EC_MBOX_DATA_KBD_EN 0x04 + #define ASUS_EC_MBOX_SUBCMD_KBD_LVL 0x87 + +#define ASUS_EC_MBOX_CMD_MISC 0x02 + #define ASUS_EC_MBOX_SUBCMD_MISC_ENABLE 0x83 + +#define ASUS_EC_PAGE_TEMPERATURE 0xc6 + #define ASUS_EC_TEMP_REG_CPU 0xa6 + #define ASUS_EC_TEMP_REG_SOC 0x2a + #define ASUS_EC_TEMP_MAX 0x7f + +#define ASUS_EC_KBD_MAX_BRIGHTNESS 3 + +static const u8 asus_ec_kbd_levels[] =3D { + [0] =3D 0x00, + [1] =3D 0x55, + [2] =3D 0xaa, + [3] =3D 0xff, +}; + +enum asus_ec_event { + ASUS_EC_EVT_CHARGE_STATE =3D 0x1c, + ASUS_EC_EVT_AC_STATE =3D 0x1d, + ASUS_EC_EVT_CRIT_TRIP =3D 0x1e, + ASUS_EC_EVT_THERMISTOR =3D 0x4f, + ASUS_EC_EVT_HOTKEY =3D 0xda, + ASUS_EC_EVT_FAN_STATUS =3D 0xdb, + ASUS_EC_EVT_THERMAL_TRIP =3D 0xe0, + ASUS_EC_EVT_CHARGE_COMMIT =3D 0xe4, +}; + +struct asus_ec { + struct i2c_client *client; + struct i2c_client *subdev_client; + /* Serializes all EC access across both I2C devices */ + struct mutex lock; + struct device *hwmon_dev; + struct led_classdev kbd_led; +}; + +static int asus_qcom_ec_write(struct asus_ec *ec, u8 offset, + const u8 *buf, u8 len) +{ + int ret; + + lockdep_assert_held(&ec->lock); + + ret =3D i2c_smbus_write_i2c_block_data(ec->client, offset, len, buf); + if (ret < 0) + dev_dbg(&ec->client->dev, + "Main device write off %#x len %u failed: %d\n", + offset, len, ret); + + return ret; +} + +static int asus_qcom_ec_read(struct asus_ec *ec, u8 offset, u8 *buf, u8 le= n) +{ + int ret; + + lockdep_assert_held(&ec->lock); + + ret =3D i2c_smbus_read_i2c_block_data(ec->client, offset, len, buf); + if (ret < 0) + return ret; + if (ret < len) { + dev_err(&ec->client->dev, + "Short read off %#x: got %d of %u bytes\n", + offset, ret, len); + return -EIO; + } + + return 0; +} + +static int asus_qcom_ec_read_ram(struct asus_ec *ec, u16 addr, u8 count, u= 16 *out) +{ + u8 frame[ASUS_QCOM_EC_RECM_FRAME_LEN] =3D { 0, 0, count, 0, 0 }; + u8 resp[ASUS_QCOM_EC_RECM_FRAME_LEN] =3D { }; + int ret; + + lockdep_assert_held(&ec->lock); + + if (count !=3D 1 && count !=3D 2) + return -EINVAL; + + put_unaligned_be16(addr, frame); + + ret =3D asus_qcom_ec_write(ec, ASUS_QCOM_EC_RECM_OFFS, frame, + ASUS_QCOM_EC_RECM_FRAME_LEN); + if (ret < 0) + return ret; + + ret =3D asus_qcom_ec_read(ec, ASUS_QCOM_EC_RECM_OFFS, resp, + ASUS_QCOM_EC_RECM_FRAME_LEN); + if (ret < 0) + return ret; + + *out =3D (count =3D=3D 2) ? get_unaligned_le16(resp) : resp[0]; + + return 0; +} + +static int asus_ec_readb(struct asus_ec *ec, u8 page, u8 reg, u8 *out) +{ + u8 sel[2] =3D { page, reg }; + int ret; + + lockdep_assert_held(&ec->lock); + + ret =3D i2c_smbus_write_i2c_block_data(ec->subdev_client, + ASUS_EC_REQ_REG, + sizeof(sel), sel); + if (ret < 0) + return ret; + + ret =3D i2c_smbus_read_byte_data(ec->subdev_client, ASUS_EC_RESP_REG); + if (ret < 0) + return ret; + + *out =3D ret; + + return 0; +} + +static int asus_ec_writeb(struct asus_ec *ec, u8 page, u8 reg, u8 data) +{ + u8 sel[2] =3D { page, reg }; + int ret; + + lockdep_assert_held(&ec->lock); + + ret =3D i2c_smbus_write_i2c_block_data(ec->subdev_client, + ASUS_EC_REQ_REG, + sizeof(sel), sel); + if (ret < 0) + return ret; + + return i2c_smbus_write_byte_data(ec->subdev_client, + ASUS_EC_RESP_REG, data); +} + +static int asus_ec_mailbox_cmd(struct asus_ec *ec, u8 cmd, u8 sub, u8 data) +{ + int ret, tries; + u8 status; + + lockdep_assert_held(&ec->lock); + + for (tries =3D 5; tries > 0; tries--) { + ret =3D asus_ec_readb(ec, ASUS_EC_PAGE_MAILBOX, + ASUS_EC_MBOX_REG_CMD, &status); + if (ret < 0) + return ret; + if (status =3D=3D 0) + break; + usleep_range(5000, 6000); + } + if (tries =3D=3D 0) + return -EBUSY; + + ret =3D asus_ec_writeb(ec, ASUS_EC_PAGE_MAILBOX, ASUS_EC_MBOX_REG_SUBCMD,= sub); + if (ret < 0) + return ret; + + ret =3D asus_ec_writeb(ec, ASUS_EC_PAGE_MAILBOX, ASUS_EC_MBOX_REG_DATA, d= ata); + if (ret < 0) + return ret; + + ret =3D asus_ec_writeb(ec, ASUS_EC_PAGE_MAILBOX, ASUS_EC_MBOX_REG_CMD, cm= d); + if (ret < 0) + return ret; + + for (tries =3D 5; tries > 0; tries--) { + ret =3D asus_ec_readb(ec, ASUS_EC_PAGE_MAILBOX, + ASUS_EC_MBOX_REG_CMD, &status); + if (ret < 0) + return ret; + if (status =3D=3D 0) + return 0; + + usleep_range(5000, 6000); + } + + return -ETIMEDOUT; +} + +static int asus_ec_enable_writes(struct asus_ec *ec) +{ + guard(mutex)(&ec->lock); + + return asus_ec_mailbox_cmd(ec, ASUS_EC_MBOX_CMD_MISC, + ASUS_EC_MBOX_SUBCMD_MISC_ENABLE, 1); +} + +static int asus_ec_read_version(struct asus_ec *ec, u8 *major, u8 *minor, = u8 *patch) +{ + u8 resp[ASUS_QCOM_EC_FULL_VER_LEN + 1]; + int ret; + + guard(mutex)(&ec->lock); + + ret =3D asus_qcom_ec_read(ec, ASUS_QCOM_EC_SUBCMD_FULL_VER, + resp, sizeof(resp)); + if (ret < 0) + return ret; + if (resp[0] < ASUS_QCOM_EC_FULL_VER_LEN) + return -EIO; + + *major =3D resp[3]; + *minor =3D resp[2]; + *patch =3D resp[1]; + + return 0; +} + +static int asus_ec_get_temp(struct asus_ec *ec, u8 reg, long *millideg) +{ + u8 raw; + int ret; + + guard(mutex)(&ec->lock); + + ret =3D asus_ec_readb(ec, ASUS_EC_PAGE_TEMPERATURE, reg, &raw); + if (ret < 0) + return ret; + if (raw > ASUS_EC_TEMP_MAX) + return -ENODATA; + + *millideg =3D raw * MILLIDEGREE_PER_DEGREE; + + return 0; +} + +static int asus_ec_get_fan_rpm(struct asus_ec *ec, u16 base, long *rpm) +{ + u16 val; + int ret; + + guard(mutex)(&ec->lock); + + ret =3D asus_qcom_ec_read_ram(ec, base, 2, &val); + if (ret < 0) + return ret; + + *rpm =3D val; + + return 0; +} + +static irqreturn_t asus_ec_irq(int irq, void *data) +{ + struct asus_ec *ec =3D data; + struct device *dev =3D &ec->client->dev; + int code; + + scoped_guard(mutex, &ec->lock) + code =3D i2c_smbus_read_byte_data(ec->client, ASUS_QCOM_EC_EVENT_CMD); + + if (code < 0) { + dev_err_ratelimited(dev, "Failed to read EC event: %d\n", code); + return IRQ_HANDLED; + } + if (code =3D=3D 0 || code =3D=3D 0xff) + return IRQ_HANDLED; + + switch (code) { + case ASUS_EC_EVT_HOTKEY: + /* Present in DSDT, don't know what triggers it */ + dev_dbg_ratelimited(dev, "EC hotkey event\n"); + break; + + case ASUS_EC_EVT_FAN_STATUS: + dev_dbg_ratelimited(dev, "Fan status changed\n"); + break; + + /* Maybe the temperature of the EC itself? */ + case ASUS_EC_EVT_THERMAL_TRIP: + case ASUS_EC_EVT_CRIT_TRIP: + /* ASUS_EC_TEMP_SOC climbing above 91 *C or falling below 92 *C */ + case ASUS_EC_EVT_THERMISTOR: + dev_dbg_ratelimited(dev, "Thermal event %#x\n", code); + break; + + case ASUS_EC_EVT_AC_STATE: { + u16 ac =3D 0; + int ret; + + /* TODO: ping SoCCP over the pmic_glink OEM-specific interface */ + scoped_guard(mutex, &ec->lock) + ret =3D asus_qcom_ec_read_ram(ec, ASUS_QCOM_EC_RAM_AC_STATUS, 1, &ac); + if (ret < 0) + dev_warn_ratelimited(dev, + "Failed to read AC status: %d\n", + ret); + else + dev_info_ratelimited(dev, "AC event: 0x%x\n", ac); + break; + } + case ASUS_EC_EVT_CHARGE_STATE: + case ASUS_EC_EVT_CHARGE_COMMIT: + break; + + default: + dev_info_ratelimited(dev, "unknown EC event: %#x\n", code); + break; + } + + return IRQ_HANDLED; +} + +static int asus_ec_kbd_led_set(struct led_classdev *led, + enum led_brightness brightness) +{ + struct asus_ec *ec =3D container_of(led, struct asus_ec, kbd_led); + int ret; + + if (brightness > ASUS_EC_KBD_MAX_BRIGHTNESS) + brightness =3D ASUS_EC_KBD_MAX_BRIGHTNESS; + + guard(mutex)(&ec->lock); + + ret =3D asus_ec_mailbox_cmd(ec, ASUS_EC_MBOX_CMD_KBD, ASUS_EC_MBOX_SUBCMD= _KBD_EN, + ASUS_EC_MBOX_DATA_KBD_EN); + if (ret < 0) + return ret; + + return asus_ec_mailbox_cmd(ec, ASUS_EC_MBOX_CMD_KBD, ASUS_EC_MBOX_SUBCMD_= KBD_LVL, + asus_ec_kbd_levels[brightness]); +} + +enum asus_ec_temp_channel { + /* External sensor? */ + ASUS_EC_TEMP_CPU, + /* Likely SoC-internal temp data communicated over a side channel */ + ASUS_EC_TEMP_SOC, + ASUS_EC_TEMP_COUNT, +}; + +static umode_t asus_ec_hwmon_is_visible(const void *data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_fan: + case hwmon_temp: + return 0444; + default: + return 0; + } +} + +static int asus_ec_hwmon_read(struct device *dev, + enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct asus_ec *ec =3D dev_get_drvdata(dev); + + switch (type) { + case hwmon_temp: + switch (channel) { + case ASUS_EC_TEMP_CPU: + return asus_ec_get_temp(ec, ASUS_EC_TEMP_REG_CPU, val); + case ASUS_EC_TEMP_SOC: + return asus_ec_get_temp(ec, ASUS_EC_TEMP_REG_SOC, val); + default: + return -EINVAL; + } + case hwmon_fan: + switch (channel) { + case 0: + return asus_ec_get_fan_rpm(ec, ASUS_QCOM_EC_RAM_FAN_CPU, val); + case 1: + return asus_ec_get_fan_rpm(ec, ASUS_QCOM_EC_RAM_FAN_GPU, val); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int asus_ec_hwmon_read_string(struct device *dev, + enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + if (type !=3D hwmon_temp || channel >=3D ASUS_EC_TEMP_COUNT) + return -EINVAL; + + switch (channel) { + case ASUS_EC_TEMP_CPU: + *str =3D "CPU"; + break; + case ASUS_EC_TEMP_SOC: + *str =3D "SoC"; + break; + } + + return 0; +} + +static const struct hwmon_channel_info * const asus_ec_hwmon_info[] =3D { + HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL), + HWMON_CHANNEL_INFO(fan, + HWMON_F_INPUT, + HWMON_F_INPUT), + NULL +}; + +static const struct hwmon_ops asus_ec_hwmon_ops =3D { + .is_visible =3D asus_ec_hwmon_is_visible, + .read =3D asus_ec_hwmon_read, + .read_string =3D asus_ec_hwmon_read_string, +}; + +static const struct hwmon_chip_info asus_ec_hwmon_chip_info =3D { + .ops =3D &asus_ec_hwmon_ops, + .info =3D asus_ec_hwmon_info, +}; + +static int asus_glymur_ec_probe(struct i2c_client *client) +{ + struct device *dev =3D &client->dev; + u8 major, minor, patch; + struct asus_ec *ec; + int ret; + + ec =3D devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL); + if (!ec) + return -ENOMEM; + + ec->client =3D client; + i2c_set_clientdata(client, ec); + + ret =3D devm_mutex_init(dev, &ec->lock); + if (ret) + return ret; + + ec->subdev_client =3D devm_i2c_new_dummy_device(dev, client->adapter, + ASUS_EC_SUBDEV_ADDR); + if (IS_ERR(ec->subdev_client)) + return dev_err_probe(dev, PTR_ERR(ec->subdev_client), + "Failed to register 0x5b EC device\n"); + + ret =3D asus_ec_enable_writes(ec); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to enable EC direct access: %d\n"= , ret); + + ret =3D asus_ec_read_version(ec, &major, &minor, &patch); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to read EC version: %d\n", ret); + + dev_dbg(dev, "ASUS Zenbook EC version %u.%u.%u\n", major, minor, patch); + + ec->kbd_led.name =3D "asus::kbd_backlight"; + ec->kbd_led.max_brightness =3D ASUS_EC_KBD_MAX_BRIGHTNESS; + ec->kbd_led.brightness_set_blocking =3D asus_ec_kbd_led_set; + ec->kbd_led.flags =3D LED_CORE_SUSPENDRESUME; + + ret =3D devm_led_classdev_register(dev, &ec->kbd_led); + if (ret) + return dev_err_probe(dev, ret, "Failed to register keyboard LED\n"); + + ret =3D devm_request_threaded_irq(dev, client->irq, NULL, asus_ec_irq, + IRQF_ONESHOT, dev_name(dev), ec); + if (ret) + return dev_err_probe(dev, ret, "Failed to request IRQ\n"); + + ec->hwmon_dev =3D devm_hwmon_device_register_with_info(dev, + "asus_glymur_ec", + ec, + &asus_ec_hwmon_chip_info, + NULL); + if (IS_ERR(ec->hwmon_dev)) + return dev_err_probe(dev, PTR_ERR(ec->hwmon_dev), + "Failed to register hwmon\n"); + + return 0; +} + +static int asus_glymur_ec_modern_standby(struct asus_ec *ec, u8 val) +{ + guard(mutex)(&ec->lock); + + return i2c_smbus_write_byte_data(ec->client, + ASUS_QCOM_EC_MODERN_STANDBY_CMD, val); +} + +static int asus_glymur_ec_suspend(struct device *dev) +{ + return asus_glymur_ec_modern_standby(dev_get_drvdata(dev), + ASUS_QCOM_EC_MODERN_STANDBY_ENTER); +} + +static int asus_glymur_ec_resume(struct device *dev) +{ + return asus_glymur_ec_modern_standby(dev_get_drvdata(dev), + ASUS_QCOM_EC_MODERN_STANDBY_EXIT); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(asus_glymur_ec_pm_ops, + asus_glymur_ec_suspend, + asus_glymur_ec_resume); + +static const struct of_device_id asus_glymur_ec_of_match[] =3D { + { .compatible =3D "asus,zenbook-a14-ux3407na-ec" }, + { .compatible =3D "asus,zenbook-a16-ux3607oa-ec" }, + {} +}; +MODULE_DEVICE_TABLE(of, asus_glymur_ec_of_match); + +static const struct i2c_device_id asus_glymur_ec_id[] =3D { + { "asus-glymur-ec" }, + {} +}; +MODULE_DEVICE_TABLE(i2c, asus_glymur_ec_id); + +static struct i2c_driver asus_glymur_ec_driver =3D { + .driver =3D { + .name =3D "asus-glymur-ec", + .of_match_table =3D asus_glymur_ec_of_match, + .pm =3D pm_sleep_ptr(&asus_glymur_ec_pm_ops), + }, + .probe =3D asus_glymur_ec_probe, + .id_table =3D asus_glymur_ec_id, +}; +module_i2c_driver(asus_glymur_ec_driver); + +MODULE_DESCRIPTION("ASUS Zenbook A16 (Qualcomm) Embedded Controller driver= "); +MODULE_LICENSE("GPL"); --=20 2.55.0 From nobody Fri Sep 25 02:44:30 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 69FEE489892; Thu, 17 Sep 2026 10:55:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789642541; cv=none; b=iDEXfbp31UwZ9Um9DruvUhnV9GITEGpUZDeni6asrd7z0b9azDYS9gRFnQYBbzKq2YMTtnNW9Mz8xPxI7pfybLhWWY7lZuW+QFWjR9v6dEJketzBpkCPLXa+wJKZ95rrMcZRCefALuYPt735UZenYYjwT9zg9hfMwq4auVFYQVk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789642541; c=relaxed/simple; bh=T9i1ckYRk2YlQMM+01DQqtuhKwnhsccYfgUtXSGlVYw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=U1s7sLLYxl9vw1tv59oUEHjuHz3Pva8lDyuw+YegH+UlfOFMbBdrD7/RFuOKEgA1fN8s04HgAq0Cs1fGfeJxCkNLjMWiEVP3W/4k8XMGLQuXJg2B8QECpt4LL9oc9o8CM7bxTTHs6Tioo54TQVOr40EfebVGQEVvsABtCbVcmh0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WcmK2vCq; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="WcmK2vCq" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 684711F00899; Thu, 17 Sep 2026 10:55:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789642524; bh=G3AVsveDPuirxTcml86dPOKs9u+YlTr6p114pcgfNow=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=WcmK2vCqBSys9dQ4joeOpE4ZrA2GeCXPc70HGEScKarkTXo0uOHiUJYCF9ISI3LJf 29Puwe4a67E0i7krv9oWeLZp0I4iIyOityuyG9PKBhABN5DNfRQ1sds7ZZ/8ycd4oM xxUswNWVA58eneqU/6Y4epKybWJPpG1NDQUsyEHtmykUbonq3X0coYFAQjWX7smQF8 8Yb5SLIvLEy2zv53L3wbsIObYeOfIG2ESq85X052LZgBHv9uqOsylk41gA3erDPNj6 leGOuUYeZLCSzm7cfDHBj/Y1A/MIhRu9xAhRLThXGs+Mj3fyGe8vSyg558xoLqGvXE HZSykZ2GdQGtQ== From: Konrad Dybcio Date: Thu, 17 Sep 2026 12:54:58 +0200 Subject: [PATCH 3/3] arm64: dts: qcom: glymur-zenbook-a16: Add Embedded Controller Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260917-topic-asus_ec-v1-3-373516d347ae@oss.qualcomm.com> References: <20260917-topic-asus_ec-v1-0-373516d347ae@oss.qualcomm.com> In-Reply-To: <20260917-topic-asus_ec-v1-0-373516d347ae@oss.qualcomm.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Konrad Dybcio , Hans de Goede , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Bryan O'Donoghue , Guenter Roeck , Bjorn Andersson , Abel Vesa Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, linux-hwmon@vger.kernel.org, linux-arm-msm@vger.kernel.org, Konrad Dybcio X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1789642507; l=1300; i=konrad.dybcio@oss.qualcomm.com; s=20230215; h=from:subject:message-id; bh=gP2ng+fwF0KAFGYtvh0+uoYCls2pmDASz/fi26pCJM0=; b=QEVMa/Eq4GUx+Gn6BsX6KMg+hH4qTbJs7sEBZb9YrLlM1+aUMQsyzL38dT1cL2yEa9ZNZ5/qj M6E4Q9HSIR7DC03hmVHtblHl7xhyEa5kgtXeLQeoEbh6vHxB7mCU6+R X-Developer-Key: i=konrad.dybcio@oss.qualcomm.com; a=ed25519; pk=iclgkYvtl2w05SSXO5EjjSYlhFKsJ+5OSZBjOkQuEms= From: Konrad Dybcio The Glymur-based Zenbook A16 features an Embedded Controller running custom ASUS firmware (which is loosely based on the reference Qualcomm Hamoa EC one with a lot of modifications). It provides keyboard backlight control, additional temperature sensor readouts, fan speed monitoring and a number of miscellaneous functions. Describe it. Signed-off-by: Konrad Dybcio Reviewed-by: Abel Vesa --- .../boot/dts/qcom/glymur-asus-zenbook-a16-ux3607oa.dts | 15 +++++++++++= ++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/glymur-asus-zenbook-a16-ux3607oa.dts = b/arch/arm64/boot/dts/qcom/glymur-asus-zenbook-a16-ux3607oa.dts index 40433dc2d6cf..d3356fcd25f0 100644 --- a/arch/arm64/boot/dts/qcom/glymur-asus-zenbook-a16-ux3607oa.dts +++ b/arch/arm64/boot/dts/qcom/glymur-asus-zenbook-a16-ux3607oa.dts @@ -670,8 +670,19 @@ &i2c9 { =20 status =3D "okay"; =20 - /* EC subdevice @ 0x5b */ - /* EC @ 0x76 */ + embedded-controller@76 { + compatible =3D "asus,zenbook-a16-ux3607oa-ec"; + reg =3D <0x76>; + + interrupts-extended =3D <&tlmm 66 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-0 =3D <&ec_int_n_default>; + pinctrl-names =3D "default"; + + #thermal-sensor-cells =3D <1>; + + wakeup-source; + }; }; =20 &i2c10 { --=20 2.55.0