From nobody Thu Sep 24 16:08:42 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 59B6748B37D; Tue, 22 Sep 2026 09:33:53 +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=1790069634; cv=none; b=iddz4IPiH+fwYvGphUN95p7CoHGC18SDLIvBKQB20o6RJaLRrlvwr/uOdzz8qa8s8AhpvvURY/FRpW792WDFdMWQuiKkmte5yKYn7FtdloaLWkDtjb47gVWOw6TjT4N/YSvbUu9HjK8hgNsRigFqoxmwHXyIEg4Gj3OVjp7v8gw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790069634; c=relaxed/simple; bh=fukG1Ui5PBkqvvdH3tW976cRJ8fnu/oq1u8P+G/BURM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=eYxrXgo25TReikASY0BlOWXr7f27ljuUzRC3j3oRzqup/WafBp4TGiK/5RuUFWF2seo9Fe8MFhmRAfAO+Nt9g9lCzlGU18To9JlzqUb5PFbVfW0JTn18QGZ3MFNQcd1Oj6o+4e90voYfV5nPgaDUokRwtUm5t++Nwh4k8YDSP14= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=VU1sl1rJ; 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="VU1sl1rJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D72061F000FF; Tue, 22 Sep 2026 09:33:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790069633; bh=8i0cUFu0jRgK6xqFeljPYVRrStYw7lvWDEu8F1xhoQg=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=VU1sl1rJj2/L5/1M/7OS2zYFU4jtcBr0at4ST9JTj3mUvgP9+3CXNEo7lIxTm1/sW u+m0TdE33AW6Z4OVdmhEoA3h5xVTT2/3CouOL5Ll9U9U+Ptyl6LK63ly5lkbPtocwh bNUGdNaSECkIQ62NKjQHsre6qw1hok3ChtNjDZhpXPcLsDxbaoVZV3Y0tEgjJsdRUe I4WQ8qxQgkS4p+gZrSkszdxB8PzFmNFyMl1DAgltT1IbGEv/CCeZ+XAggxhKjrmxCn AVCa9QRyDYWEkEXeo3oZ9k0601waplKNUNFFnNQKyOwt8poFkZfEj6rahn/mzXw2nc OJdpxudv4+LsA== From: Konrad Dybcio Date: Tue, 22 Sep 2026 11:33:36 +0200 Subject: [PATCH v2 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: <20260922-topic-asus_ec-v2-1-0bd923d1b853@oss.qualcomm.com> References: <20260922-topic-asus_ec-v2-0-0bd923d1b853@oss.qualcomm.com> In-Reply-To: <20260922-topic-asus_ec-v2-0-0bd923d1b853@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.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1790069623; l=2660; i=konrad.dybcio@oss.qualcomm.com; s=20230215; h=from:subject:message-id; bh=L+8Ieu/vm8qRqfna3o9GyZSa+EbA82FtLSEHNV5okJ8=; b=Y85MnJi6sKAdG1+InZofc8ZrdVjaxpp11Dg5U4BNXB9muH/HPVhmMxdXQrSaUsA2nYhPQMBGK SG4FCkcnDeUC00lL3BLz5P1PWtMmD5H0JMDy65FUiNlpF8Xk5QmM9vR 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. Two separate compatibles are maintained since the two laptops' ECs seem to be generally alike, however assuming full compatibility with the limited available information does not spark confidence. Signed-off-by: Konrad Dybcio --- .../asus,zenbook-a16-ux3607oa-ec.yaml | 64 ++++++++++++++++++= ++++ 1 file changed, 64 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..c0bfad5d21c0 --- /dev/null +++ b/Documentation/devicetree/bindings/embedded-controller/asus,zenbook-a1= 6-ux3607oa-ec.yaml @@ -0,0 +1,64 @@ +# 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' + +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 Thu Sep 24 16:08:42 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 51E924D2EFA; Tue, 22 Sep 2026 09:33:58 +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=1790069640; cv=none; b=abcsmFIzQzwOqlI/Tbp77br+rBPF5xIrOzmFAwuBTkkBxh9AKY55cUBG//uuKHxD+GJO7SoRCMuwoeCcHak6hzLJdm/pEBbm8Qtgt+LQJq2QMfB4JLvZYmC2JgFu0BFBFclFliB9ziGpLUJfsheeEHFBMQxvT+32m0OqIxUA0Wg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790069640; c=relaxed/simple; bh=Ry3hogNGzUGKBkUAR9UkoTYXhhe9SYsHfW5ouNcEbVc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=nY92KKxJYj9IZf207ECzaKIj48YNYvXe4oZ/uS1FEBgX+feNmhtuW6KJgLWtSMe9PZIL65HgI9p6e/b5ZaJsvOukxtCpb7WNu1+6LVvSHYTltKS0RDcd4LVs/0hrjEEbZ28u36Z+cb1nOMnoMFQaSXlMwjl5qQniePCvK25Z6r0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=YN1KvMEJ; 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="YN1KvMEJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8F8B51F00893; Tue, 22 Sep 2026 09:33:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790069638; bh=GbyAHls438qnNjUVQj/fD51bBQnFYErnfLSByG/fYWY=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=YN1KvMEJGazmC7HqCJNNgkWM/IG9wEErgZ+nwpSCN7xkmlKSiYuaLbqLpyx5ZgvQ8 7Xbpije9ByK5uqomH/3tbVAP5vKu2zZ3pe4HC+ECklOw4mNnvd7YvX80XH6bbNzASo Y2QUweQcTHZAmVB1BssWX7Q2ss7XEjJANICHuiVreQk6grOOigYdzpaR7756uONbin RwpguAR49OJoxmnwRFOLUoDo/ymCxvAodTiJiB7D7BqBhHI2LJJ1AxeFA208zs5aU5 F6icEDWEBE3TEzb0GgzZkVxP3ZM1bbHk4IgypIj58Ajt0TiQjF2ukTtkS/u0scn77O 5CecTgdnpeHgQ== From: Konrad Dybcio Date: Tue, 22 Sep 2026 11:33:37 +0200 Subject: [PATCH v2 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: <20260922-topic-asus_ec-v2-2-0bd923d1b853@oss.qualcomm.com> References: <20260922-topic-asus_ec-v2-0-0bd923d1b853@oss.qualcomm.com> In-Reply-To: <20260922-topic-asus_ec-v2-0-0bd923d1b853@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.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1790069623; l=17844; i=konrad.dybcio@oss.qualcomm.com; s=20230215; h=from:subject:message-id; bh=z9Z9fo/7PB07mCNIK++hMA2MXBHqzcD4tl1+fUGI8G0=; b=2/e4e8r+bgqKMsMRS1euk3n9jWbrIfnYtfwiQTHv1pfmVzKK9+ouB8pXFxjxt6wM3SUg1YCbH +4O7oidvtOYC9mXgcnHRISCvH7ZWL2fD+ZYEIh8ui/OzN/zzJoyAxA2 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 Thu Sep 24 16:08:42 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 BCD834D7D25; Tue, 22 Sep 2026 09:34:03 +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=1790069645; cv=none; b=dE3hyqpf9nSOSJzk2IAz08c6ayZE2yS4r6dEK/VPgfyVvpXpNwrfoTFA749KEVer9Ag8zqZaPxeMKF7Fs1yVfBcbgUMikr1odK6Yhz2Dmzs6Y/Rp8BSeQC+oPd51StI8j+V2MiKFvpg3QcF2FS2EMRDTZCWfRqNhJVYLQDjjCeM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790069645; c=relaxed/simple; bh=T9i1ckYRk2YlQMM+01DQqtuhKwnhsccYfgUtXSGlVYw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=QuMQbZak9hol+rhtv1ATObxlh1/PkgJcY+PBt5FfXmW63dtc1x8cBSCVoKSu0Ln5A5o2b5PmgP8jAwbT+eUE/05nge3CO9khvrnqFlu4tNvZ2nrvRecUFpF3E613qx2EsW8QSYyrBS1NJfKVkD9ErhyJITQDdmWJJrA3JExtrkU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=bSspuHup; 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="bSspuHup" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 696531F000FF; Tue, 22 Sep 2026 09:33:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790069642; bh=G3AVsveDPuirxTcml86dPOKs9u+YlTr6p114pcgfNow=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=bSspuHupgQv7U9+sx6SPKwWsVpuQUL7rMZWW+YNw8Sq7CuaJAE7sc74t3nW7/qhdN nzZdUW9gsnrTXSZdqpM0a3lIBqtLRNcSjpMPiNIISf9t4iPE+nVFQchp580iWNgmUU GlSe9fdd4lx+LHqjSHy4pB9iuh4br++NLknm8oQOtlXDLTmS2mGEYvCnFo4hLaKqsG wN5sm58UCdJkJ+AN8fTbqFJ6oXFChW8hD0y1pCEXPEKU5xD3upNkQIq1N2o1fek2KY nDvksXyqOguw+oNr1sRzVwV8Umo89NoV+oufRGF9o/M62dXD95o9CMFeeOjdxMIVZ6 kiDcroqmrvZqA== From: Konrad Dybcio Date: Tue, 22 Sep 2026 11:33:38 +0200 Subject: [PATCH v2 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: <20260922-topic-asus_ec-v2-3-0bd923d1b853@oss.qualcomm.com> References: <20260922-topic-asus_ec-v2-0-0bd923d1b853@oss.qualcomm.com> In-Reply-To: <20260922-topic-asus_ec-v2-0-0bd923d1b853@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.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1790069623; l=1300; i=konrad.dybcio@oss.qualcomm.com; s=20230215; h=from:subject:message-id; bh=gP2ng+fwF0KAFGYtvh0+uoYCls2pmDASz/fi26pCJM0=; b=gXT1GQ0NskTFQu6P+G7JUBD40U6NI5QlW7GrqFIP1SFCZE6MTobJh4tmdeuJ1/jRYirWb7S/l cxnfor9Jph+CmjgXTsfw3Hem0h/YcdaRpLr7Q+YVVuofERcvjMLQr5e 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