From nobody Thu Sep 24 15:10:13 2026 Received: from mail-wm2-f13.google.com (mail-wm2-f13.google.com [74.125.225.141]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8FE8C421245 for ; Tue, 22 Sep 2026 16:57:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.141 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790096271; cv=none; b=MTDCHxJ6NKWiPGSkC0Tazbsx/FkJJe8YY185I1e8CZnEt+FVNQYB4C/B+Fic8V+OKKndnbY34Kvnsm/0+zqGz461NS9y9mprDHjj91TD9oOFr0Lutls7Zjcw10p9gXP4S7oJJIbc+m6HhKhnrUOaIBKzCcrYs9TNC37QJxZwBzo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790096271; c=relaxed/simple; bh=aid97Yjimc76nz+M6o0QWk1KtiDp95Qtk/akmNNnZ3Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UqsqAcCSh3f5u44ibcRco9hgAwzb+/jYLOEC5vp+gcRa4xAbqUwMvmwEgagSWkmwM8sYWC/xx3zh25j5wMfIhY1sds2Eu3iNxzALnbmkOUp0BL6yrkwKd/lFIW+/ZZQjdMWxg+5YkcIXO4QG9lgJGmUSZ7t2+rje0tt7QQxDYAQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=b7MlO8GL; arc=none smtp.client-ip=74.125.225.141 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="b7MlO8GL" Received: by mail-wm2-f13.google.com with SMTP id 5b1f17b1804b1-49ccfd61ecaso38955985e9.3 for ; Tue, 22 Sep 2026 09:57:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790096268; x=1790701068; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Qdwj3z7uTqgFd/9Tfs5y2p+1zT+FzwY0f8o+/81CJMs=; b=b7MlO8GLMCViwPcId7mm4Ioo2dqkBXcWt9Q/mxK1t+h0RkhUDQR3ZCtTMHiP6ORKqA r+mbYqcRTIy2eAZYNBHDzTa5OORT2inB3NsQbIVEb40CkTtML64Kjp1bHkfiROIgMbjr pvV9EKpfpC/x75de7w86rxcOoQHN8YTweBqL9Zurk+VeqMiwJ0G3nWX/rzLvZJCDzkRR 5dBfbox/zL1JaJVrzD/QKscyTTZxqRrPu88UvTA9SYDl1gwed5BDNo2tP4p6JQ44pemp uazuvCnIpiry0ggzr0y2lea8PKDZxYZ6ilBwu6mF3m1pWxlygNoiV0Z2sGIGtskK3WBP frDw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790096268; x=1790701068; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=Qdwj3z7uTqgFd/9Tfs5y2p+1zT+FzwY0f8o+/81CJMs=; b=EK74aLvX5Z2LBmEIzjN2IvBU9d9I9pGG6MQYScZzy3NFI4qnPOoFa+tJjT/0ZVj1I/ F8n7t8WaL09qrklaFV5iUZF0PPgzSaGbLAOJnkeyNK91/Xa4C2FG0yJBBF25K58sgLhh RRK/AKbsJdZ47z5NnMeF8MtSm/cIHCh+jLvNjo3gXnCDvAohr+mH3Zi9t3t2XNVpdUSb CjGU8jrCSq/SPezqPfrb5ChBVxNlYnTIZ8Bfuhjt6WrpY8X5IXbxmdO+EnWQ8t8Dfux9 MdsdArG+c6LfwYUPIDhY4FEbwEA0lsldNgWJFnhojoyBZvo6ozyqixVn4a2PzMVSdtxA p6zQ== X-Forwarded-Encrypted: i=1; AKwUvBy0jk7ASFop1zHz27a22K1pY7UNMRKbbwk92Vfj/a1v8prwH1G49AQWLtqVav7pUGx9HGuoFtjYW48XlMg=@vger.kernel.org X-Gm-Message-State: AFuF++mWc1OC7y7MYPG0hqMm1KOdBP9o948OAcTua9/XHBSh2FgJgNMl 8FzBtVMpsoq6g/veXYgAcRIhGX5XrM751Au7bSEaczMH1zPISyzfKIHm X-Gm-Gg: AYBFou25c29y6vQb4g7NhkXZKqBSduZaJefGLz26BCLOJvXLKs8kAWd5+OG+qDySQlj d0u1TTofN+DAzAgJ1OFfaHzFqd9yB2/dteuArOKR1zFpBiCogAW+NTazj/LYbPcDrYEO87bpuZo KiF7rqyjOWcI/KXdD7R6v9wmvufh5xPsMsbSGCf82du62TICFzMmCZjI7ETSN91xTSO34NDwJP2 00SKzpi5QHp/p0Xpf/WjCnUoDWkEM4C3Nx699/XVw6LdTofgKGqxKA62z7DTcUUUzgT/CqXXZmt NIdMyt/TqrzNFZ8IJvlL0hrMIT/si/peQoYjv1FOiOsj3s2O8YB9kq2D7UDF/ue4ggwSij+7j23 qa2MSkD0ef7yLU0mHjIF9JkbOTiWDjpmUGdkB285aWpMrRKLByuIIhxc1Lp5Mr8/9edjuFZlfEa bhi6EZzJT4jsc2I0O/5JUzVf8sMJ/2Yfrg0joN7byRIIM7RVqc27iLj4IRianLXWWixhS2Wp/g+ t7hDyyNHx9bLlklYw== X-Received: by 2002:a05:600c:19cb:b0:49e:8184:f619 with SMTP id 5b1f17b1804b1-49fc57410f2mr206302025e9.22.1790096267744; Tue, 22 Sep 2026 09:57:47 -0700 (PDT) Received: from localhost.localdomain ([94.252.75.113]) by smtp.googlemail.com with ESMTPSA id 5b1f17b1804b1-49fdabe8a2asm68693625e9.4.2026.09.22.09.57.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Sep 2026 09:57:47 -0700 (PDT) From: Oleg Keri To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , "Bryan O'Donoghue" , Guenter Roeck , Bjorn Andersson , Konrad Dybcio , Abel Vesa Cc: linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, linux-hwmon@vger.kernel.org, Conor Dooley Subject: [PATCH v4 1/3] dt-bindings: embedded-controller: add Lenovo Yoga Slim 7x Gen 11 EC Date: Tue, 22 Sep 2026 18:57:35 +0200 Message-ID: <20260922165737.260443-2-okerixx@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260922165737.260443-1-okerixx@gmail.com> References: <20260922165737.260443-1-okerixx@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Document the Compal embedded controller found on the Lenovo Yoga Slim 7x Gen 11, a Qualcomm Snapdragon X2 Elite (glymur) laptop. It sits on I2C at address 0x70 and is distinct from the Qualcomm reference EC that the reference designs place at 0x76. Signed-off-by: Oleg Keri Acked-by: Conor Dooley --- .../lenovo,yoga-slim7x-gen11-ec.yaml | 56 +++++++++++++++++++ MAINTAINERS | 8 +++ 2 files changed, 64 insertions(+) create mode 100644 Documentation/devicetree/bindings/embedded-controller/l= enovo,yoga-slim7x-gen11-ec.yaml diff --git a/Documentation/devicetree/bindings/embedded-controller/lenovo,y= oga-slim7x-gen11-ec.yaml b/Documentation/devicetree/bindings/embedded-contr= oller/lenovo,yoga-slim7x-gen11-ec.yaml new file mode 100644 index 000000000000..37337de86b0b --- /dev/null +++ b/Documentation/devicetree/bindings/embedded-controller/lenovo,yoga-sli= m7x-gen11-ec.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/embedded-controller/lenovo,yoga-slim7x-= gen11-ec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Lenovo Yoga Slim 7x Gen 11 Embedded Controller + +maintainers: + - Oleg Keri + +description: + The Lenovo Yoga Slim 7x Gen 11, a Qualcomm Snapdragon X2 Elite (glymur) + laptop, has a Compal embedded controller on I2C. It reports board + thermistors, battery cell voltages and CPU fan speed, and drives the + keyboard backlight. + + This controller is not the Qualcomm reference EC that the Snapdragon + reference designs place at address 0x76; it speaks a different command + set and answers at 0x70. + +properties: + compatible: + const: lenovo,yoga-slim7x-gen11-ec + + reg: + const: 0x70 + + interrupts: + maxItems: 1 + description: + The controller pulses this line while it has events queued. + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells =3D <1>; + #size-cells =3D <0>; + + embedded-controller@70 { + compatible =3D "lenovo,yoga-slim7x-gen11-ec"; + reg =3D <0x70>; + + interrupts-extended =3D <&tlmm 66 IRQ_TYPE_EDGE_FALLING>; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index be096be5fff6..11d459c17caf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14966,6 +14966,14 @@ S: Maintained F: Documentation/ABI/testing/sysfs-driver-lenovo-yb9-kbdock F: drivers/platform/x86/lenovo/yb9-kbdock.c =20 +LENOVO YOGA SLIM 7X GEN 11 EMBEDDED CONTROLLER DRIVER +M: Oleg Keri +L: linux-arm-msm@vger.kernel.org +S: Maintained +F: Documentation/ABI/testing/sysfs-driver-lenovo-yoga-slim7x-gen11-ec +F: Documentation/devicetree/bindings/embedded-controller/lenovo,yoga-slim7= x-gen11-ec.yaml +F: drivers/platform/arm64/lenovo-yoga-slim7x-gen11-ec.c + LETSKETCH HID TABLET DRIVER M: Hans de Goede L: linux-input@vger.kernel.org --=20 2.55.0 From nobody Thu Sep 24 15:10:13 2026 Received: from mail-wm2-f13.google.com (mail-wm2-f13.google.com [74.125.225.141]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9F3A353ED17 for ; Tue, 22 Sep 2026 16:57:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.141 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790096274; cv=none; b=DGT7yYyjsKv0W6oov6vmBf5fbZmh1L0ThbpwIkOHasyLUj8gRnpdvvsJX452FtHuF+pccjxyEj96VpqrzV03wTb9MWLxXUwCMNrUBRCPkDyvpI148arIxDe3IgeDc9m07aIp9cNP32sGcNy+KIA2/H0Sv9mXBkf3aXOpdYdNGZc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790096274; c=relaxed/simple; bh=F6htOE/HRZVeijnC3jHjibN8ViFgtzxO8l90NZBgUss=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uPfdqZ7Mr3gRXIw2fRwCPXSREgwpfduRycEDYv2/99DlotmPAXT2wCIrEFlINlj2NMCl++TW06rxFHTUQkf9Kv4yNgacHBNYak2h4oifLyn+aC3t58hypU46KsM7qAB2IQX6JLp+Nl04eoeTZ07kFphvnotb5ot1RzkZybQQCuM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=gk97ueVk; arc=none smtp.client-ip=74.125.225.141 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="gk97ueVk" Received: by mail-wm2-f13.google.com with SMTP id 5b1f17b1804b1-49d1ca5b0d6so169085e9.0 for ; Tue, 22 Sep 2026 09:57:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790096269; x=1790701069; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Pn8Ei1uL+/xRmAAxSxsGU249FRLrFn5bzMJ/RIWp/WY=; b=gk97ueVkFVhKdrLL3MwdsLWvE1y9cWbh8/kVSdtaN+fDg6IDHQFA8+49DfKBWpapzb PAEQIoaezZdZYCiV9ZUieW26cPRp7hXii6uwVPwIbljLAFgAFP+Y/bVECTVstA/U4hXk E3E5UHbGHkxb7jTPn29LBtl1RBlQxkhlfdOX0Q41bX5Z6v7tvC9Xmrrz8+DMi6HtD3Ib SDy12/blIPLBr+7lEtpqeuXFyMjKTt8k6uAlVUq5j/9lT5FhZu4of7Jx6YzVsd3lDa5u /O9+jUG/LXwvCriC9z+//OTeg8QkiTrpAQ0DZYHKOOfVKWxMQ7hGmDPRVegEONvDOKod j43A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790096269; x=1790701069; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=Pn8Ei1uL+/xRmAAxSxsGU249FRLrFn5bzMJ/RIWp/WY=; b=NfeLz7uvd2lKjDyIYlSAcufiH4vWt/dEzkkzDwhrRL5u3xBfib7k0xdCV0D+cfkoLU n3e0n9wInA58G5D++kHSuY4GBnhLkb1ezhsiedr23rW35ktAQ/eHITjOBPtrdAtS+wpo Rn06jWQBxZjpQik57gXt2RWu9Pd16DvQ7JG/Amx3sQilDxf+XtuUPkCl2yrWJR3kjPU+ IJfOPoTDeT7KrzmbBJa+6s2ETq+GmQCUNbX8bvDScMWKsf8d0ipDpr+cLtf93mVX6cRp Kbhu6j4H5ED+7UROpITjgf0cKVwZNFFz58wql208DmdQqKZPTZvGD9FmavRGvB9p+GVD eKuw== X-Forwarded-Encrypted: i=1; AKwUvByyj6Bk6BwlkAMeqEkn4rGFZDyTL0jsxwP4rpkVNtgukg0rQqOB9PZEhT0PIyuE+nGun+ReHPCNGvSZpE8=@vger.kernel.org X-Gm-Message-State: AFuF++lZxgh2zpYM9J/lklXA5xMPfnB4FRNTOa0zm+J0DcZzKmSpzS1b qLbHARFQI/7mXWoTGvNOPO2HzP7qzQihXTki8gU0ILQgLjMOmKhWuuOB X-Gm-Gg: AYBFou2XS3ypSi1dfv/SI6UDTlr2n7+ASpGwB/0FFl+9o1XB/kOxeuXI0RLO/qKjOHg QfgdqyPkI8rTRnj4g0cKvsKhaj9v/54vD9QO+w/mIlUX+uHGUg5ePRW92gMfTyMkxGz1xKN0FFa K5zR2m66vvgUekqBKZeXCb60Xz93WLUaSHKFDJXQZh0n82VcSkEJqbpKrIH4bGdyT1IuKdbO+TV c/agtYBIw/DfGYnai7jfHnBHvx8FlhctMw4YF7hfpUNjrp+o1qtwDIck98syOvwMFcZfc14gN4O l3wuTKxKRXsi/16JcgK7wY2dVzNHdWFv4K6SsRdnPeMtGnvR8H5d67z14GRpLMWzE/BkWXW8Rt6 ctvAL1tdDdjXRNFlC4UhMTv8m2i40KIx6k0Ijg+XS1W2U16OEHLoLgQvxl6HnPuuaeytstBRbM1 UKueW1TYyF3neF7qSU+0LU+7F3wJtYQRD4IZS/WmpNJMmdVIkZm1Ebag+xnBKu76tDPhwulwmaX FWVyT4= X-Received: by 2002:a05:600c:358c:b0:499:be2d:c290 with SMTP id 5b1f17b1804b1-49fc56b4ebemr254883965e9.9.1790096268759; Tue, 22 Sep 2026 09:57:48 -0700 (PDT) Received: from localhost.localdomain ([94.252.75.113]) by smtp.googlemail.com with ESMTPSA id 5b1f17b1804b1-49fdabe8a2asm68693625e9.4.2026.09.22.09.57.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Sep 2026 09:57:48 -0700 (PDT) From: Oleg Keri To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , "Bryan O'Donoghue" , Guenter Roeck , Bjorn Andersson , Konrad Dybcio , Abel Vesa Cc: linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, linux-hwmon@vger.kernel.org Subject: [PATCH v4 2/3] platform/arm64: add Lenovo Yoga Slim 7x Gen 11 EC driver Date: Tue, 22 Sep 2026 18:57:36 +0200 Message-ID: <20260922165737.260443-3-okerixx@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260922165737.260443-1-okerixx@gmail.com> References: <20260922165737.260443-1-okerixx@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The Lenovo Yoga Slim 7x Gen 11 (Qualcomm glymur / Snapdragon X2 Elite) carries a Compal EF06 embedded controller on I2C at address 0x70. The platform firmware describes it as an ACPI GenericSerialBus region, but the machine boots from device tree, so nothing otherwise talks to it. Commands are exchanged with two raw I2C block transfers: a 7 byte write to register 0x02 carrying the command and up to six arguments, then a 6 byte read of register 0x01 for the result, with a short delay in between before the result register is valid. The EC offers no way to match a result to its command; the delay is the one the vendor ACPI code uses, and the one value that lives in a mailbox shared with other EC activity, the cell voltages, is validated against a signature and retried. Expose what the EC offers that the rest of the kernel does not already provide: - five board thermistors as hwmon temperature channels. These are charger, CPU voltage regulator, 5 V rail and ambient sensors, not die sensors, and read considerably cooler than tsens - the four battery cell voltages, which live in a banked mailbox shared with other EC activity; readings are validated against a signature and retried, and cached briefly so that all four channels come from one coherent sample - CPU fan speed in RPM - the keyboard backlight as an LED, off/low/high - Fn-lock as a read/write sysfs attribute, matching the ideapad-laptop interface. The EC reports Fn+Esc as an event but keeps no state of its own, so the driver owns the bit and toggles it on the key - the mic-mute and airplane-mode keys as KEY_MICMUTE and KEY_RFKILL. These reach the host only as EC events; they are not on the keyboard's HID interface and have no GPIO of their own The EC signals pending events on a dedicated line, and keeps pulsing it until they are read - so the queue must be drained completely on every interrupt, including codes this driver ignores. Leaving one behind makes the controller pulse indefinitely. Fan speed is reported but not controlled. The EC accepts a manual setpoint, however it enforces no thermal floor over it: with the fan pinned at roughly 2000 RPM under full load the SoC rose from 69 to 91 degrees in 30 seconds without the EC ever overriding. Exposing pwm1_enable or fan1_target would therefore let userspace overheat the machine, so neither is implemented. Note this is the Gen 11 machine specifically. Its EC differs from the Qualcomm reference EC that the reference designs place at address 0x76, which is not populated here, and so EC_QCOM_HAMOA does not drive it. Signed-off-by: Oleg Keri --- .../sysfs-driver-lenovo-yoga-slim7x-gen11-ec | 21 + drivers/platform/arm64/Kconfig | 23 + drivers/platform/arm64/Makefile | 1 + .../arm64/lenovo-yoga-slim7x-gen11-ec.c | 671 ++++++++++++++++++ 4 files changed, 716 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-driver-lenovo-yoga-slim= 7x-gen11-ec create mode 100644 drivers/platform/arm64/lenovo-yoga-slim7x-gen11-ec.c diff --git a/Documentation/ABI/testing/sysfs-driver-lenovo-yoga-slim7x-gen1= 1-ec b/Documentation/ABI/testing/sysfs-driver-lenovo-yoga-slim7x-gen11-ec new file mode 100644 index 000000000000..155ed0252b47 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-lenovo-yoga-slim7x-gen11-ec @@ -0,0 +1,21 @@ +What: /sys/bus/i2c/devices/*/fn_lock +Date: September 2026 +KernelVersion: 7.4 +Contact: Oleg Keri +Description: + Control fn-lock mode. + + * 1 -> Switched On + * 0 -> Switched Off + + When switched on, the function keys act as F1..F12 and the + multimedia functions require the Fn modifier. + + The embedded controller reports the Fn+Esc key as an event but + keeps no state of its own, so this attribute is the state: the + driver toggles it when the key is pressed, and writing it takes + effect immediately. + + For example:: + + # echo "0" > /sys/bus/i2c/devices/9-0070/fn_lock diff --git a/drivers/platform/arm64/Kconfig b/drivers/platform/arm64/Kconfig index e32e01b2a9bd..7581432e69b0 100644 --- a/drivers/platform/arm64/Kconfig +++ b/drivers/platform/arm64/Kconfig @@ -90,6 +90,29 @@ config EC_LENOVO_THINKPAD_T14S =20 Say M or Y here to include this support. =20 +config EC_LENOVO_YOGA_SLIM7X_GEN11 + tristate "Lenovo Yoga Slim 7x Gen 11 Embedded Controller driver" + depends on ARCH_QCOM || COMPILE_TEST + depends on I2C + depends on INPUT + depends on HWMON + select NEW_LEDS + select LEDS_CLASS + help + Say Y here to enable the EC driver for the (Snapdragon X2 Elite, + glymur-based) Lenovo Yoga Slim 7x Gen 11 laptop. The EC provides + thermistors, battery cell voltages and CPU fan speed as hwmon + channels, and the keyboard backlight as an LED. + + This is the Gen 11 (glymur) machine specifically. Its EC is a Compal + design at i2c address 0x70 and speaks a different protocol from the + Qualcomm reference EC that the reference designs place at 0x76, so + EC_QCOM_HAMOA does not drive it - and conversely this driver does not + cover the X1E-based Yoga Slim 7x Gen 9. + + To compile this driver as a module, choose M here: the module will + be called lenovo-yoga-slim7x-gen11-ec. + config EC_QCOM_HAMOA tristate "Embedded Controller driver for Qualcomm Hamoa/Glymur reference = devices" depends on ARCH_QCOM || COMPILE_TEST diff --git a/drivers/platform/arm64/Makefile b/drivers/platform/arm64/Makef= ile index 7681be4a46e9..605cca4d42a9 100644 --- a/drivers/platform/arm64/Makefile +++ b/drivers/platform/arm64/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_EC_ACER_ASPIRE1) +=3D acer-aspire1-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 +obj-$(CONFIG_EC_LENOVO_YOGA_SLIM7X_GEN11) +=3D lenovo-yoga-slim7x-gen11-ec= .o obj-$(CONFIG_EC_QCOM_HAMOA) +=3D qcom-hamoa-ec.o diff --git a/drivers/platform/arm64/lenovo-yoga-slim7x-gen11-ec.c b/drivers= /platform/arm64/lenovo-yoga-slim7x-gen11-ec.c new file mode 100644 index 000000000000..a16849877dd7 --- /dev/null +++ b/drivers/platform/arm64/lenovo-yoga-slim7x-gen11-ec.c @@ -0,0 +1,671 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SLIM7X11_EC_BLOCK_READ 0x01 +#define SLIM7X11_EC_BLOCK_WRITE 0x02 +#define SLIM7X11_EC_RESP_LEN 6 +#define SLIM7X11_EC_REQ_LEN 7 + +#define SLIM7X11_EC_CMD_RAM_READ 0xb0 +#define SLIM7X11_EC_CMD_RAM_WRITE 0xb1 +#define SLIM7X11_EC_CMD_BANK_READ 0xb4 +#define SLIM7X11_EC_CMD_FAN 0x46 +#define SLIM7X11_EC_FAN_GET_SPEED 0x81 + +#define SLIM7X11_EC_CMD_EVENT 0x84 +#define SLIM7X11_EC_EVT_MAX_DRAIN 64 +#define SLIM7X11_EC_EVT_FN_LOCK 0x0f +#define SLIM7X11_EC_EVT_MIC_MUTE 0x18 +#define SLIM7X11_EC_EVT_FLIGHT_MODE 0x19 + +#define SLIM7X11_EC_SCUK 0x1c +#define SLIM7X11_EC_SCUK_FN_LOCK BIT(7) +#define SLIM7X11_EC_SCUK_FN_LOCK_IND BIT(5) +#define SLIM7X11_EC_SCUK_FN_LOCK_MASK (SLIM7X11_EC_SCUK_FN_LOCK | SLIM7X11= _EC_SCUK_FN_LOCK_IND) + +#define SLIM7X11_EC_KBLT 0x03 +#define SLIM7X11_EC_KBLT_LEVEL GENMASK(1, 0) +#define SLIM7X11_EC_KBLT_AUTO 3 +#define SLIM7X11_EC_KBLT_MAX 2 + +#define SLIM7X11_EC_TEMP_FIRST 0x12 +#define SLIM7X11_EC_NUM_TEMP 6 +#define SLIM7X11_EC_TEMP_MAX 120 + +#define SLIM7X11_EC_CELL_BANK 0x0b +#define SLIM7X11_EC_CELL_SIG_LO 0x02 +#define SLIM7X11_EC_CELL_SIG_HI 0x0c +#define SLIM7X11_EC_CELL_FIRST 0x04 +#define SLIM7X11_EC_NUM_CELL 4 +#define SLIM7X11_EC_CELL_MIN_MV 2000 +#define SLIM7X11_EC_CELL_MAX_MV 5000 +#define SLIM7X11_EC_CELL_TRIES 10 + +#define SLIM7X11_EC_CACHE_MS 2000 +#define SLIM7X11_EC_STALE_MS 10000 + +struct slim7x11_ec { + struct i2c_client *client; + /* serializes all EC access */ + struct mutex lock; + unsigned long temp_present; + unsigned long cell_read_at; + u16 cell[SLIM7X11_EC_NUM_CELL]; + bool cell_cached; + struct led_classdev kbd_led; + u8 kblt_level; + bool kblt_restore; + struct input_dev *keys; +}; + +static int slim7x11_ec_command(struct slim7x11_ec *ec, u8 cmd, u8 arg0, u8= arg1, + u8 resp[SLIM7X11_EC_RESP_LEN]) +{ + u8 req[SLIM7X11_EC_REQ_LEN] =3D { cmd, arg0, arg1 }; + int ret; + + lockdep_assert_held(&ec->lock); + + ret =3D i2c_smbus_write_i2c_block_data(ec->client, SLIM7X11_EC_BLOCK_WRIT= E, + sizeof(req), req); + if (ret < 0) + return ret; + + usleep_range(2000, 3000); + + ret =3D i2c_smbus_read_i2c_block_data(ec->client, SLIM7X11_EC_BLOCK_READ, + SLIM7X11_EC_RESP_LEN, resp); + if (ret < 0) + return ret; + if (ret !=3D SLIM7X11_EC_RESP_LEN) + return -EIO; + + return 0; +} + +static int slim7x11_ec_ram_read(struct slim7x11_ec *ec, u8 addr, u8 *val) +{ + u8 resp[SLIM7X11_EC_RESP_LEN]; + int ret; + + ret =3D slim7x11_ec_command(ec, SLIM7X11_EC_CMD_RAM_READ, addr, 0, resp); + if (ret) + return ret; + + *val =3D resp[0]; + return 0; +} + +static int slim7x11_ec_bank_read(struct slim7x11_ec *ec, u8 bank, u8 addr,= u8 *val) +{ + u8 resp[SLIM7X11_EC_RESP_LEN]; + int ret; + + ret =3D slim7x11_ec_command(ec, SLIM7X11_EC_CMD_BANK_READ, bank, addr, re= sp); + if (ret) + return ret; + + *val =3D resp[0]; + return 0; +} + +static int slim7x11_ec_ram_write(struct slim7x11_ec *ec, u8 addr, u8 val) +{ + u8 resp[SLIM7X11_EC_RESP_LEN]; + + return slim7x11_ec_command(ec, SLIM7X11_EC_CMD_RAM_WRITE, addr, val, resp= ); +} + +static int slim7x11_ec_fan_read(struct slim7x11_ec *ec, long *rpm) +{ + u8 resp[SLIM7X11_EC_RESP_LEN]; + int ret; + + ret =3D slim7x11_ec_command(ec, SLIM7X11_EC_CMD_FAN, SLIM7X11_EC_FAN_GET_= SPEED, 0, + resp); + if (ret) + return ret; + + *rpm =3D resp[0] * 100; + return 0; +} + +static int slim7x11_ec_refresh_cells(struct slim7x11_ec *ec) +{ + unsigned int try; + int ret; + + if (ec->cell_cached && + time_before(jiffies, ec->cell_read_at + msecs_to_jiffies(SLIM7X11_EC_= CACHE_MS))) + return 0; + + for (try =3D 0; try < SLIM7X11_EC_CELL_TRIES; try++) { + u16 cell[SLIM7X11_EC_NUM_CELL]; + u8 sig[3]; + unsigned int i; + bool ok =3D true; + + ret =3D slim7x11_ec_bank_read(ec, SLIM7X11_EC_CELL_BANK, + SLIM7X11_EC_CELL_SIG_LO, &sig[0]); + if (ret) + return ret; + + ret =3D slim7x11_ec_bank_read(ec, SLIM7X11_EC_CELL_BANK, + SLIM7X11_EC_CELL_SIG_LO + 1, &sig[1]); + if (ret) + return ret; + + ret =3D slim7x11_ec_bank_read(ec, SLIM7X11_EC_CELL_BANK, + SLIM7X11_EC_CELL_SIG_HI, &sig[2]); + if (ret) + return ret; + + if (sig[0] !=3D 0x01 || sig[1] !=3D 0x01 || sig[2] !=3D 0x03) + continue; + + for (i =3D 0; i < ARRAY_SIZE(cell); i++) { + u8 lsb, msb; + + ret =3D slim7x11_ec_bank_read(ec, SLIM7X11_EC_CELL_BANK, + SLIM7X11_EC_CELL_FIRST + i * 2, &lsb); + if (ret) + return ret; + + ret =3D slim7x11_ec_bank_read(ec, SLIM7X11_EC_CELL_BANK, + SLIM7X11_EC_CELL_FIRST + i * 2 + 1, &msb); + if (ret) + return ret; + + cell[i] =3D lsb | (msb << 8); + if (cell[i] < SLIM7X11_EC_CELL_MIN_MV || + cell[i] > SLIM7X11_EC_CELL_MAX_MV) + ok =3D false; + } + + if (!ok) + continue; + + memcpy(ec->cell, cell, sizeof(cell)); + ec->cell_cached =3D true; + ec->cell_read_at =3D jiffies; + + return 0; + } + + if (ec->cell_cached && + time_before(jiffies, ec->cell_read_at + msecs_to_jiffies(SLIM7X11_EC_= STALE_MS))) + return 0; + + return -EAGAIN; +} + +static umode_t slim7x11_ec_is_visible(const void *drvdata, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct slim7x11_ec *ec =3D drvdata; + + switch (type) { + case hwmon_temp: + if (!(ec->temp_present & BIT(channel))) + return 0; + return 0444; + case hwmon_in: + return 0444; + case hwmon_fan: + return 0444; + default: + return 0; + } +} + +static int slim7x11_ec_read(struct device *dev, enum hwmon_sensor_types ty= pe, + u32 attr, int channel, long *val) +{ + struct slim7x11_ec *ec =3D dev_get_drvdata(dev); + int ret; + u8 raw; + + guard(mutex)(&ec->lock); + + switch (type) { + case hwmon_temp: + ret =3D slim7x11_ec_ram_read(ec, SLIM7X11_EC_TEMP_FIRST + channel, &raw); + if (ret) + return ret; + if (!raw) + return -ENODATA; + if (raw > SLIM7X11_EC_TEMP_MAX) + return -EIO; + *val =3D raw * MILLIDEGREE_PER_DEGREE; + return 0; + case hwmon_in: + ret =3D slim7x11_ec_refresh_cells(ec); + if (ret) + return ret; + *val =3D ec->cell[channel]; + return 0; + case hwmon_fan: + return slim7x11_ec_fan_read(ec, val); + default: + return -EOPNOTSUPP; + } +} + +static const char * const slim7x11_ec_temp_labels[SLIM7X11_EC_NUM_TEMP] = =3D { + "Charger A", + "CPU VR", + "5V rail", + "Ambient", + "Charger B", + "Thermistor 6", +}; + +static const char * const slim7x11_ec_cell_labels[SLIM7X11_EC_NUM_CELL] = =3D { + "Cell 1", "Cell 2", "Cell 3", "Cell 4", +}; + +static int slim7x11_ec_read_string(struct device *dev, enum hwmon_sensor_t= ypes type, + u32 attr, int channel, const char **str) +{ + switch (type) { + case hwmon_temp: + *str =3D slim7x11_ec_temp_labels[channel]; + return 0; + case hwmon_in: + *str =3D slim7x11_ec_cell_labels[channel]; + return 0; + case hwmon_fan: + *str =3D "CPU fan"; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static enum led_brightness slim7x11_ec_kbd_led_get(struct led_classdev *le= d) +{ + struct slim7x11_ec *ec =3D container_of(led, struct slim7x11_ec, kbd_led); + u8 raw; + + guard(mutex)(&ec->lock); + + if (slim7x11_ec_ram_read(ec, SLIM7X11_EC_KBLT, &raw)) + return 0; + + raw =3D FIELD_GET(SLIM7X11_EC_KBLT_LEVEL, raw); + + if (raw =3D=3D SLIM7X11_EC_KBLT_AUTO) + return SLIM7X11_EC_KBLT_MAX; + + return raw; +} + +static int slim7x11_ec_kbd_led_level(struct slim7x11_ec *ec, u8 level, u8 = *old) +{ + u8 raw; + int ret; + + ret =3D slim7x11_ec_ram_read(ec, SLIM7X11_EC_KBLT, &raw); + if (ret) + return ret; + + if (old) + *old =3D FIELD_GET(SLIM7X11_EC_KBLT_LEVEL, raw); + + raw &=3D ~SLIM7X11_EC_KBLT_LEVEL; + raw |=3D FIELD_PREP(SLIM7X11_EC_KBLT_LEVEL, level); + + return slim7x11_ec_ram_write(ec, SLIM7X11_EC_KBLT, raw); +} + +static int slim7x11_ec_kbd_led_set(struct led_classdev *led, + enum led_brightness brightness) +{ + struct slim7x11_ec *ec =3D container_of(led, struct slim7x11_ec, kbd_led); + + guard(mutex)(&ec->lock); + + return slim7x11_ec_kbd_led_level(ec, brightness, NULL); +} + +static const struct hwmon_ops slim7x11_ec_hwmon_ops =3D { + .is_visible =3D slim7x11_ec_is_visible, + .read =3D slim7x11_ec_read, + .read_string =3D slim7x11_ec_read_string, +}; + +static const struct hwmon_channel_info * const slim7x11_ec_hwmon_info[] = =3D { + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL), + 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, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL), + HWMON_CHANNEL_INFO(fan, + HWMON_F_INPUT | HWMON_F_LABEL), + NULL +}; + +static const struct hwmon_chip_info slim7x11_ec_chip_info =3D { + .ops =3D &slim7x11_ec_hwmon_ops, + .info =3D slim7x11_ec_hwmon_info, +}; + +static int slim7x11_ec_fn_lock_toggle(struct slim7x11_ec *ec) +{ + u8 raw; + int ret; + + ret =3D slim7x11_ec_ram_read(ec, SLIM7X11_EC_SCUK, &raw); + if (ret) + return ret; + + if (raw & SLIM7X11_EC_SCUK_FN_LOCK) + raw &=3D ~SLIM7X11_EC_SCUK_FN_LOCK_MASK; + else + raw |=3D SLIM7X11_EC_SCUK_FN_LOCK_MASK; + + return slim7x11_ec_ram_write(ec, SLIM7X11_EC_SCUK, raw); +} + +static void slim7x11_ec_report_key(struct slim7x11_ec *ec, unsigned int co= de) +{ + if (!ec->keys) + return; + + input_report_key(ec->keys, code, 1); + input_sync(ec->keys); + input_report_key(ec->keys, code, 0); + input_sync(ec->keys); +} + +static irqreturn_t slim7x11_ec_irq(int irq, void *data) +{ + struct slim7x11_ec *ec =3D data; + unsigned int i; + + guard(mutex)(&ec->lock); + + for (i =3D 0; i < SLIM7X11_EC_EVT_MAX_DRAIN; i++) { + u8 resp[SLIM7X11_EC_RESP_LEN]; + + if (slim7x11_ec_command(ec, SLIM7X11_EC_CMD_EVENT, 0, 0, resp)) + break; + if (!resp[0]) + break; + + switch (resp[0]) { + case SLIM7X11_EC_EVT_FN_LOCK: + slim7x11_ec_fn_lock_toggle(ec); + break; + case SLIM7X11_EC_EVT_MIC_MUTE: + slim7x11_ec_report_key(ec, KEY_MICMUTE); + break; + case SLIM7X11_EC_EVT_FLIGHT_MODE: + slim7x11_ec_report_key(ec, KEY_RFKILL); + break; + default: + break; + } + } + + return IRQ_HANDLED; +} + +static void slim7x11_ec_register_keys(struct slim7x11_ec *ec) +{ + struct device *dev =3D &ec->client->dev; + struct input_dev *input; + int ret; + + input =3D devm_input_allocate_device(dev); + if (!input) { + dev_warn(dev, "no memory for the hotkey device\n"); + return; + } + + input->name =3D "Lenovo Yoga Slim 7x hotkeys"; + input->phys =3D "lenovo-yoga-slim7x-gen11-ec/input0"; + input->id.bustype =3D BUS_I2C; + input_set_capability(input, EV_KEY, KEY_MICMUTE); + input_set_capability(input, EV_KEY, KEY_RFKILL); + + ret =3D input_register_device(input); + if (ret) { + dev_warn(dev, "cannot register the hotkey device: %d\n", ret); + return; + } + + ec->keys =3D input; +} + +static ssize_t fn_lock_show(struct device *dev, struct device_attribute *a= ttr, + char *buf) +{ + struct slim7x11_ec *ec =3D dev_get_drvdata(dev); + u8 raw; + int ret; + + scoped_guard(mutex, &ec->lock) + ret =3D slim7x11_ec_ram_read(ec, SLIM7X11_EC_SCUK, &raw); + + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", !!(raw & SLIM7X11_EC_SCUK_FN_LOCK)); +} + +static ssize_t fn_lock_store(struct device *dev, struct device_attribute *= attr, + const char *buf, size_t count) +{ + struct slim7x11_ec *ec =3D dev_get_drvdata(dev); + bool enable; + u8 raw; + int ret; + + ret =3D kstrtobool(buf, &enable); + if (ret) + return ret; + + guard(mutex)(&ec->lock); + + ret =3D slim7x11_ec_ram_read(ec, SLIM7X11_EC_SCUK, &raw); + if (ret) + return ret; + + if (enable) + raw |=3D SLIM7X11_EC_SCUK_FN_LOCK_MASK; + else + raw &=3D ~SLIM7X11_EC_SCUK_FN_LOCK_MASK; + + ret =3D slim7x11_ec_ram_write(ec, SLIM7X11_EC_SCUK, raw); + if (ret) + return ret; + + return count; +} +static DEVICE_ATTR_RW(fn_lock); + +static struct attribute *slim7x11_ec_attrs[] =3D { + &dev_attr_fn_lock.attr, + NULL +}; +ATTRIBUTE_GROUPS(slim7x11_ec); + +static int slim7x11_ec_probe(struct i2c_client *client) +{ + struct device *dev =3D &client->dev; + struct device *hwmon; + struct slim7x11_ec *ec; + unsigned int i; + int ret; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_I2C_BLOCK)) { + return dev_err_probe(dev, -ENODEV, + "adapter does not support SMBus block transfers\n"); + } + + 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; + + scoped_guard(mutex, &ec->lock) { + for (i =3D 0; i < SLIM7X11_EC_NUM_TEMP; i++) { + u8 raw; + + ret =3D slim7x11_ec_ram_read(ec, SLIM7X11_EC_TEMP_FIRST + i, + &raw); + if (ret) { + return dev_err_probe(dev, ret, + "failed to read thermistor %u\n", + i); + } + + if (raw > 0 && raw <=3D SLIM7X11_EC_TEMP_MAX) + ec->temp_present |=3D BIT(i); + } + } + + if (!ec->temp_present) { + return dev_err_probe(dev, -ENODEV, + "no thermistor reported a usable value\n"); + } + + dev_dbg(dev, "thermistors present: %#lx\n", ec->temp_present); + + hwmon =3D devm_hwmon_device_register_with_info(dev, "yoga_slim7x_ec", ec, + &slim7x11_ec_chip_info, NULL); + if (IS_ERR(hwmon)) + return PTR_ERR(hwmon); + + ec->kbd_led.name =3D "platform::kbd_backlight"; + ec->kbd_led.max_brightness =3D SLIM7X11_EC_KBLT_MAX; + ec->kbd_led.brightness_get =3D slim7x11_ec_kbd_led_get; + ec->kbd_led.brightness_set_blocking =3D slim7x11_ec_kbd_led_set; + + ret =3D devm_led_classdev_register(dev, &ec->kbd_led); + if (ret) { + return dev_err_probe(dev, ret, + "failed to register keyboard backlight\n"); + } + + if (client->irq) { + slim7x11_ec_register_keys(ec); + + ret =3D devm_request_threaded_irq(dev, client->irq, NULL, + slim7x11_ec_irq, IRQF_ONESHOT, + "lenovo-yoga-slim7x-gen11-ec", ec); + if (ret) + return dev_err_probe(dev, ret, "cannot request the EC interrupt\n"); + + scoped_guard(mutex, &ec->lock) { + for (i =3D 0; i < SLIM7X11_EC_EVT_MAX_DRAIN; i++) { + u8 resp[SLIM7X11_EC_RESP_LEN]; + + if (slim7x11_ec_command(ec, SLIM7X11_EC_CMD_EVENT, 0, 0, resp)) + break; + if (!resp[0]) + break; + } + } + } + + return 0; +} + +static int slim7x11_ec_suspend(struct device *dev) +{ + struct slim7x11_ec *ec =3D dev_get_drvdata(dev); + + guard(mutex)(&ec->lock); + ec->kblt_restore =3D !slim7x11_ec_kbd_led_level(ec, 0, &ec->kblt_level); + + return 0; +} + +static int slim7x11_ec_resume(struct device *dev) +{ + struct slim7x11_ec *ec =3D dev_get_drvdata(dev); + + guard(mutex)(&ec->lock); + ec->cell_cached =3D false; + + if (ec->kblt_restore) { + ec->kblt_restore =3D false; + slim7x11_ec_kbd_led_level(ec, ec->kblt_level, NULL); + } + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(slim7x11_ec_pm_ops, slim7x11_ec_suspend, s= lim7x11_ec_resume); + +static const struct of_device_id slim7x11_ec_of_match[] =3D { + { .compatible =3D "lenovo,yoga-slim7x-gen11-ec" }, + { } +}; +MODULE_DEVICE_TABLE(of, slim7x11_ec_of_match); + +static const struct i2c_device_id slim7x11_ec_i2c_id[] =3D { + { "slim7x-gen11-ec" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, slim7x11_ec_i2c_id); + +static struct i2c_driver slim7x11_ec_driver =3D { + .driver =3D { + .name =3D "lenovo-yoga-slim7x-gen11-ec", + .of_match_table =3D slim7x11_ec_of_match, + .dev_groups =3D slim7x11_ec_groups, + .pm =3D pm_sleep_ptr(&slim7x11_ec_pm_ops), + }, + .probe =3D slim7x11_ec_probe, + .id_table =3D slim7x11_ec_i2c_id, +}; +module_i2c_driver(slim7x11_ec_driver); + +MODULE_AUTHOR("Oleg Keri "); +MODULE_DESCRIPTION("Lenovo Yoga Slim 7x Gen 11 embedded controller"); +MODULE_LICENSE("GPL"); --=20 2.55.0 From nobody Thu Sep 24 15:10:13 2026 Received: from mail-wr2-f12.google.com (mail-wr2-f12.google.com [74.125.225.76]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D0A6B56E06A for ; Tue, 22 Sep 2026 16:57:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.76 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790096274; cv=none; b=mZBUiXqON7tp3kyfx8ftAo3cfb6NwpnhtaLgyTucCZrby32y0hS33SGnyD80rvx1+jdGXlkTbUQLnkYvovOORxNBZ5VlsXyNoGEQlxU12FOt8UZWidPq+12zM4wSbHTWiPVh//SkgheY3ZinD+06VroZeFdRKq9gPAGRq2ZgzJo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790096274; c=relaxed/simple; bh=gQp5P6A4HKZPmr2RXt5nnsqu1turFNqjNRfQGzceh+w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gw1uZrXyYhAS5naxf0xy9+7c8tjd+IliIYOz9YliafGHn/TgtQH0ZkNAWn0wXAuBSIRtLq2OmrLAqbRGirbun/U1vgm+1ZQxPF3zpKyV/qu6WB86Mi3X8lZwP5Dujo/N280mdANo8zcthYCA93QQxMTYDSU/RZzI2tEn7bSkIRQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ZABkxZUf; arc=none smtp.client-ip=74.125.225.76 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ZABkxZUf" Received: by mail-wr2-f12.google.com with SMTP id ffacd0b85a97d-484366874b0so102325f8f.2 for ; Tue, 22 Sep 2026 09:57:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790096270; x=1790701070; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=/eycLZYI0OnWON4y4DQc42djuKTXBLKJTdaLEQ0NYzI=; b=ZABkxZUf0otGT+/5inGL3hhjZ1nWQrK0hU9ek87pyACpySKaLceOTqRKQEvfQ9IQJa Vl1WQTc4mF/d2ivT3nZsoIzlT8DAyWRM7C1w5Rfgs/io9rTSZmZNenfmUJKSm9G4XcPk gtW4S7a3qe1DKqv25xVInlKdZ7lQX0Bi9uJJkn9WS4RyBb+bWNZ3o/LPF9Kxq7zTH0TC FdPsD669QYi+pD8PfEBLKffMjPBVZBGej3TwSS6QrGsl4ATmlROiOeHVz1pD0PsLENkm 5g8si/AE/bzLFdGn67Sulg9uwoZ1dOe8+0rI6DiPQR/pcQuQ8bqbSy4VtQAHzizMlx07 mPNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790096270; x=1790701070; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=/eycLZYI0OnWON4y4DQc42djuKTXBLKJTdaLEQ0NYzI=; b=paw2JqHgv8KUif4x6sWaN5KcAXDSI7/iD6rMrnFLviyrGHm1kGMBmTdrdpJDOEESVW VAPSUS//fx51vNH901ca6BiQRHEydxTI4NM3ofba4pK5Uh/AqSh73ZUK39jCaX3qnE+0 ZXIPsQIij1RbenEzuG57/wgCvgggskTmCbri8SOCgxAGZKh9BKZkfj5C+xjyigBQfxam 7PO4VtPCOVBaAf+B3kVCf+zpeEklWSnmAkSj2HuaVDGlrUsMPBEyZK8ngkBuAN9BrtS2 EDW3Ox82nGI9c+xDmx9JKAhcFWNX3I6YOPdeMCtPKtRoRn8vqUNRW/PWkecBQn0P3CYJ Rmyw== X-Forwarded-Encrypted: i=1; AKwUvByCZ2ihV/4SUBuaJaBI/HMp4vVR43PuZt/GLKi3cef9BO8FXFvmmTC7WnnHu8OiuN4Psw+Wvbpr2oO6trU=@vger.kernel.org X-Gm-Message-State: AFuF++nMCXmkLm24B0WKomr7zOO4DHeOYu/Qa4xUmDPIunZkk6fX02rT XgM96kpbqrLMycsuwBvVPk3MTqoxkCLNECKdvYMwgs5I+zIad4PGjyFW X-Gm-Gg: AYBFou095qsBkK8M+zT1XyGN6Mppqa1A+pvI+HDaFeFgr2N5OchP+5yN1i+LDfBKULt q2UbEvWuWJEvbqGaYXQpiZX8H0HvtKaU2/HVD+YfLAGP4Hol/8897DyqQu3Weo/WYuxkmjkyaS4 g13ZGj4fiwlRrlqYSUzZJ4euhY/My0LM9HhP07dVQH0wPFbJ/6RkDW+V3cAGHI2h1ZnQGafEFGl nvgSQeod4rt5U19Bsz6FfejVrOUHbbMv/+mwzaM4Te6IP0bstUSdypY5PqKCYYo0o+WFEa8ax7v BN0e+D6/Bmf6j2Ljigk72XFDM7d8ERh/jSIZBbmk5qrZjp2MJ4BMUvTSn+rE9PKNlJlf/vAzjjv bRkUX/GER/rrekWgUI/bKeXnbehWASCFHQG95EznAjXfFkUi8+J6MeNZTZY+A9qj8kaxjDw6F95 y2GhuRT1ModecZGYFVN3TRhWJoARNphrQWHY/Sxqymf7GFt9BKKH/7yVRXz5TydwqI83ynCcAFj KElM/Y= X-Received: by 2002:a05:600c:64c5:b0:49e:6c11:c4fc with SMTP id 5b1f17b1804b1-49fc56aa4e8mr216310585e9.7.1790096269744; Tue, 22 Sep 2026 09:57:49 -0700 (PDT) Received: from localhost.localdomain ([94.252.75.113]) by smtp.googlemail.com with ESMTPSA id 5b1f17b1804b1-49fdabe8a2asm68693625e9.4.2026.09.22.09.57.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Sep 2026 09:57:49 -0700 (PDT) From: Oleg Keri To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , "Bryan O'Donoghue" , Guenter Roeck , Bjorn Andersson , Konrad Dybcio , Abel Vesa Cc: linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, platform-driver-x86@vger.kernel.org, linux-hwmon@vger.kernel.org Subject: [PATCH v4 3/3] arm64: dts: qcom: glymur-lenovo-yoga-slim7x: add the embedded controller Date: Tue, 22 Sep 2026 18:57:37 +0200 Message-ID: <20260922165737.260443-4-okerixx@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260922165737.260443-1-okerixx@gmail.com> References: <20260922165737.260443-1-okerixx@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Describe the Compal embedded controller on I2C at address 0x70. It provides the board thermistors, the battery cell voltages and the CPU fan speed, and drives the keyboard backlight. Its interrupt line is TLMM gpio66, falling edge, for which the file already carries a pin state. That state leaves the pin without a bias. gpio66 has no external pull and floats when the EC is not driving it, which shows up as a steady stream of spurious edges; the vendor ACPI tables describe the same pin as GpioInt(Edge, ActiveLow, Exclusive, PullUp). Enable the pull-up. Signed-off-by: Oleg Keri Reviewed-by: Abel Vesa Reviewed-by: Konrad Dybcio --- .../boot/dts/qcom/glymur-lenovo-yoga-slim7x.dts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/glymur-lenovo-yoga-slim7x.dts b/arch/= arm64/boot/dts/qcom/glymur-lenovo-yoga-slim7x.dts index 769f195c99d9..bc840fd8e458 100644 --- a/arch/arm64/boot/dts/qcom/glymur-lenovo-yoga-slim7x.dts +++ b/arch/arm64/boot/dts/qcom/glymur-lenovo-yoga-slim7x.dts @@ -659,7 +659,15 @@ &i2c9 { =20 status =3D "okay"; =20 - /* EC @ 0x70, irq =3D TLMM 66 */ + embedded-controller@70 { + compatible =3D "lenovo,yoga-slim7x-gen11-ec"; + reg =3D <0x70>; + + interrupts-extended =3D <&tlmm 66 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-0 =3D <&ec_int_n_default>; + pinctrl-names =3D "default"; + }; }; =20 &lpass_vamacro { @@ -990,7 +998,7 @@ reset-n-pins { ec_int_n_default: ec-int-n-state { pins =3D "gpio66"; function =3D "gpio"; - bias-disable; + bias-pull-up; }; =20 kybd_default: kybd-default-state { base-commit: 5c4d4169604b335c38bbc79bc1fc03042981fc6f --=20 2.55.0