summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2025-10-04 15:28:18 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2025-10-04 15:28:18 -0700
commitb66451723c45b791fd2824d1b8f62fe498989e23 (patch)
treef178b8b9a4d8b20786378c98854bf4a62a0ee380
parentb4e5bb555594826bb98aaf8bcd9f957f0428cb07 (diff)
parentb8754092dfed4fc2fcdb0de32a029ba8f9b464b6 (diff)
downloadlinux-b66451723c45b791fd2824d1b8f62fe498989e23.tar.gz
linux-b66451723c45b791fd2824d1b8f62fe498989e23.tar.bz2
linux-b66451723c45b791fd2824d1b8f62fe498989e23.zip
Merge tag 'platform-drivers-x86-v6.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86
Pull x86 platform driver updates from Ilpo Järvinen: - amd/pmf: - Add support for adjusting PMF PPT and PPT APU thresholds - Extend custom BIOS inputs for more policies - Update ta_pmf_action structure to the latest PMF TA - arm64: - thinkpad-t14s-ec: Add EC driver for ThinkPad T14s Gen6 Snapdragon - int3472: - Increase handshake GPIO delay - intel/pmc: - SSRAM support for Lunar Lake and Panther Lake - Support reading substate requirements data from S0ix blockers (for platforms starting from Panther Lake) - Wildcat Lake support - intel-uncore-freq: - Solve duplicate sysfs entry warnings - Present unique domain ID per package - portwell-ec: - Support suspend/resume - Add hwmon support for voltage and temperature - redmi-wmi: - Add WMI driver for Redmibook keyboard - think-lmi: - Certificate support for ThinkCenter - x86-android-tables + others: - Convert away from legacy GPIO APIs - x86-android-tables: - Add support for Acer A1-840 tablet - Fix modules list for Lenovo devices - Stop using EPROBE_DEFER - Miscellaneous cleanups / refactoring / improvements * tag 'platform-drivers-x86-v6.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (63 commits) platform/x86: pcengines-apuv2: Use static device properties platform/x86: meraki-mx100: Use static device properties platform/x86: barco-p50-gpio: use software nodes for gpio-leds/keys platform/x86: x86-android-tablets: Stop using EPROBE_DEFER platform/x86: x86-android-tablets: Fix modules lists for Lenovo devices platform/x86: x86-android-tablets: Simplify lenovo_yoga_tab2_830_1050_exit() platform/x86: x86-android-tablets: Add support for Acer A1-840 tablet platform/x86: x86-android-tablets: Move Acer info to its own file platform/x86: x86-android-tablets: Update my email address platform/x86: x86-android-tablets: Simplify node-group [un]registration platform/x86: x86-android-tablets: use swnode_group instead of manual registering platform/x86: x86-android-tablets: replace bat_swnode with swnode_group platform/x86: x86-android-tablets: convert gpio_keys devices to GPIO references platform/x86: x86-android-tablets: remove support for GPIO lookup tables platform/x86: x86-android-tablets: convert Yoga Tab2 fast charger to GPIO references platform/x86: x86-android-tablets: convert HID-I2C devices to GPIO references platform/x86: x86-android-tablets: convert wm1502 devices to GPIO references platform/x86: x86-android-tablets: convert int3496 devices to GPIO references platform/x86: x86-android-tablets: convert EDT devices to GPIO references platform/x86: x86-android-tablets: convert Novatek devices to GPIO references ...
-rw-r--r--Documentation/devicetree/bindings/embedded-controller/lenovo,thinkpad-t14s-ec.yaml50
-rw-r--r--MAINTAINERS12
-rw-r--r--arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi24
-rw-r--r--drivers/platform/arm64/Kconfig20
-rw-r--r--drivers/platform/arm64/Makefile1
-rw-r--r--drivers/platform/arm64/lenovo-thinkpad-t14s.c616
-rw-r--r--drivers/platform/x86/Kconfig12
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/amd/hsmp/acpi.c4
-rw-r--r--drivers/platform/x86/amd/hsmp/plat.c4
-rw-r--r--drivers/platform/x86/amd/pmf/acpi.c87
-rw-r--r--drivers/platform/x86/amd/pmf/pmf.h77
-rw-r--r--drivers/platform/x86/amd/pmf/spc.c80
-rw-r--r--drivers/platform/x86/amd/pmf/sps.c2
-rw-r--r--drivers/platform/x86/amd/pmf/tee-if.c22
-rw-r--r--drivers/platform/x86/barco-p50-gpio.c104
-rw-r--r--drivers/platform/x86/dell/dell_rbu.c8
-rw-r--r--drivers/platform/x86/intel/int3472/discrete.c58
-rw-r--r--drivers/platform/x86/intel/pmc/Makefile2
-rw-r--r--drivers/platform/x86/intel/pmc/arl.c4
-rw-r--r--drivers/platform/x86/intel/pmc/core.c185
-rw-r--r--drivers/platform/x86/intel/pmc/core.h27
-rw-r--r--drivers/platform/x86/intel/pmc/lnl.c18
-rw-r--r--drivers/platform/x86/intel/pmc/mtl.c2
-rw-r--r--drivers/platform/x86/intel/pmc/ptl.c37
-rw-r--r--drivers/platform/x86/intel/pmc/ssram_telemetry.c1
-rw-r--r--drivers/platform/x86/intel/pmc/tgl.c4
-rw-r--r--drivers/platform/x86/intel/pmc/wcl.c486
-rw-r--r--drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c76
-rw-r--r--drivers/platform/x86/lenovo/think-lmi.c94
-rw-r--r--drivers/platform/x86/lenovo/think-lmi.h14
-rw-r--r--drivers/platform/x86/lenovo/wmi-capdata01.c2
-rw-r--r--drivers/platform/x86/lenovo/yoga-tab2-pro-1380-fastcharger.c5
-rw-r--r--drivers/platform/x86/meraki-mx100.c404
-rw-r--r--drivers/platform/x86/pcengines-apuv2.c192
-rw-r--r--drivers/platform/x86/portwell-ec.c194
-rw-r--r--drivers/platform/x86/quickstart.c10
-rw-r--r--drivers/platform/x86/redmi-wmi.c130
-rw-r--r--drivers/platform/x86/x86-android-tablets/Makefile2
-rw-r--r--drivers/platform/x86/x86-android-tablets/acer.c247
-rw-r--r--drivers/platform/x86/x86-android-tablets/asus.c108
-rw-r--r--drivers/platform/x86/x86-android-tablets/core.c121
-rw-r--r--drivers/platform/x86/x86-android-tablets/dmi.c12
-rw-r--r--drivers/platform/x86/x86-android-tablets/lenovo.c291
-rw-r--r--drivers/platform/x86/x86-android-tablets/other.c334
-rw-r--r--drivers/platform/x86/x86-android-tablets/shared-psy-info.c34
-rw-r--r--drivers/platform/x86/x86-android-tablets/shared-psy-info.h8
-rw-r--r--drivers/platform/x86/x86-android-tablets/vexia_atla10_ec.c2
-rw-r--r--drivers/platform/x86/x86-android-tablets/x86-android-tablets.h28
-rw-r--r--drivers/platform/x86/xiaomi-wmi.c10
-rw-r--r--sound/soc/intel/boards/bytcr_wm5102.c2
51 files changed, 3383 insertions, 885 deletions
diff --git a/Documentation/devicetree/bindings/embedded-controller/lenovo,thinkpad-t14s-ec.yaml b/Documentation/devicetree/bindings/embedded-controller/lenovo,thinkpad-t14s-ec.yaml
new file mode 100644
index 000000000000..c87ccb5b3086
--- /dev/null
+++ b/Documentation/devicetree/bindings/embedded-controller/lenovo,thinkpad-t14s-ec.yaml
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/embedded-controller/lenovo,thinkpad-t14s-ec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Lenovo Thinkpad T14s Embedded Controller
+
+maintainers:
+ - Sebastian Reichel <sre@kernel.org>
+
+description:
+ The Qualcomm Snapdragon-based Lenovo Thinkpad T14s has an Embedded Controller
+ (EC) which handles things such as keyboard backlight, LEDs or non-standard
+ keys.
+
+properties:
+ compatible:
+ const: lenovo,thinkpad-t14s-ec
+
+ reg:
+ const: 0x28
+
+ interrupts:
+ maxItems: 1
+
+ wakeup-source: true
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+additionalProperties: false
+
+examples:
+ - |+
+ #include <dt-bindings/interrupt-controller/irq.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ embedded-controller@28 {
+ compatible = "lenovo,thinkpad-t14s-ec";
+ reg = <0x28>;
+ interrupts-extended = <&tlmm 66 IRQ_TYPE_LEVEL_LOW>;
+ wakeup-source;
+ };
+ };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 7c909846fe39..439cf09de532 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21605,6 +21605,12 @@ S: Maintained
T: git https://github.com/pkshih/rtw.git
F: drivers/net/wireless/realtek/rtw89/
+REDMIBOOK WMI DRIVERS
+M: Gladyshev Ilya <foxido@foxido.dev>
+L: platform-driver-x86@vger.kernel.org
+S: Maintained
+F: drivers/platform/x86/redmi-wmi.c
+
REDPINE WIRELESS DRIVER
L: linux-wireless@vger.kernel.org
S: Orphan
@@ -25454,6 +25460,12 @@ W: http://thinkwiki.org/wiki/Ibm-acpi
T: git git://repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
F: drivers/platform/x86/lenovo/thinkpad_acpi.c
+THINKPAD T14S EMBEDDED CONTROLLER DRIVER
+M: Sebastian Reichel <sre@kernel.org>
+S: Maintained
+F: Documentation/devicetree/bindings/embedded-controller/lenovo,thinkpad-t14s-ec.yaml
+F: drivers/platform/arm64/lenovo-thinkpad-t14s.c
+
THINKPAD LMI DRIVER
M: Mark Pearson <mpearson-lenovo@squebb.ca>
L: platform-driver-x86@vger.kernel.org
diff --git a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi
index 0a989e9d3d23..654cbce9d6ec 100644
--- a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi
+++ b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi
@@ -887,6 +887,24 @@
};
};
+&i2c6 {
+ clock-frequency = <400000>;
+
+ status = "okay";
+
+ embedded-controller@28 {
+ compatible = "lenovo,thinkpad-t14s-ec";
+ reg = <0x28>;
+
+ interrupts-extended = <&tlmm 66 IRQ_TYPE_LEVEL_LOW>;
+
+ pinctrl-0 = <&ec_int_n_default>;
+ pinctrl-names = "default";
+
+ wakeup-source;
+ };
+};
+
&i2c7 {
clock-frequency = <400000>;
@@ -1269,6 +1287,12 @@
<72 2>, /* Secure EC I2C connection (?) */
<238 1>; /* UFS Reset */
+ ec_int_n_default: ec-int-n-state {
+ pins = "gpio66";
+ function = "gpio";
+ bias-disable;
+ };
+
eusb3_reset_n: eusb3-reset-n-state {
pins = "gpio6";
function = "gpio";
diff --git a/drivers/platform/arm64/Kconfig b/drivers/platform/arm64/Kconfig
index 06288aebc559..10f905d7d6bf 100644
--- a/drivers/platform/arm64/Kconfig
+++ b/drivers/platform/arm64/Kconfig
@@ -70,4 +70,24 @@ config EC_LENOVO_YOGA_C630
Say M or Y here to include this support.
+config EC_LENOVO_THINKPAD_T14S
+ tristate "Lenovo Thinkpad T14s Embedded Controller driver"
+ depends on ARCH_QCOM || COMPILE_TEST
+ depends on I2C
+ depends on INPUT
+ select INPUT_SPARSEKMAP
+ select LEDS_CLASS
+ select NEW_LEDS
+ select SND_CTL_LED if SND
+ help
+ Driver for the Embedded Controller in the Qualcomm Snapdragon-based
+ Lenovo Thinkpad T14s, which provides access to keyboard backlight
+ and status LEDs.
+
+ This driver provides support for the mentioned laptop where this
+ information is not properly exposed via the standard Qualcomm
+ devices.
+
+ Say M or Y here to include this support.
+
endif # ARM64_PLATFORM_DEVICES
diff --git a/drivers/platform/arm64/Makefile b/drivers/platform/arm64/Makefile
index 46a99eba3264..60c131cff6a1 100644
--- a/drivers/platform/arm64/Makefile
+++ b/drivers/platform/arm64/Makefile
@@ -8,3 +8,4 @@
obj-$(CONFIG_EC_ACER_ASPIRE1) += acer-aspire1-ec.o
obj-$(CONFIG_EC_HUAWEI_GAOKUN) += huawei-gaokun-ec.o
obj-$(CONFIG_EC_LENOVO_YOGA_C630) += lenovo-yoga-c630.o
+obj-$(CONFIG_EC_LENOVO_THINKPAD_T14S) += lenovo-thinkpad-t14s.o
diff --git a/drivers/platform/arm64/lenovo-thinkpad-t14s.c b/drivers/platform/arm64/lenovo-thinkpad-t14s.c
new file mode 100644
index 000000000000..1d5d11adaf32
--- /dev/null
+++ b/drivers/platform/arm64/lenovo-thinkpad-t14s.c
@@ -0,0 +1,616 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2025, Sebastian Reichel
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/container_of.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+#include <linux/interrupt.h>
+#include <linux/leds.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define T14S_EC_CMD_ECRD 0x02
+#define T14S_EC_CMD_ECWR 0x03
+#define T14S_EC_CMD_EVT 0xf0
+
+#define T14S_EC_REG_LED 0x0c
+#define T14S_EC_REG_KBD_BL1 0x0d
+#define T14S_EC_REG_KBD_BL2 0xe1
+#define T14S_EC_KBD_BL1_MASK GENMASK_U8(7, 6)
+#define T14S_EC_KBD_BL2_MASK GENMASK_U8(3, 2)
+#define T14S_EC_REG_AUD 0x30
+#define T14S_EC_MIC_MUTE_LED BIT(5)
+#define T14S_EC_SPK_MUTE_LED BIT(6)
+
+#define T14S_EC_EVT_NONE 0x00
+#define T14S_EC_EVT_KEY_FN_4 0x13
+#define T14S_EC_EVT_KEY_FN_F7 0x16
+#define T14S_EC_EVT_KEY_FN_SPACE 0x1f
+#define T14S_EC_EVT_KEY_TP_DOUBLE_TAP 0x20
+#define T14S_EC_EVT_AC_CONNECTED 0x26
+#define T14S_EC_EVT_AC_DISCONNECTED 0x27
+#define T14S_EC_EVT_KEY_POWER 0x28
+#define T14S_EC_EVT_LID_OPEN 0x2a
+#define T14S_EC_EVT_LID_CLOSED 0x2b
+#define T14S_EC_EVT_THERMAL_TZ40 0x5c
+#define T14S_EC_EVT_THERMAL_TZ42 0x5d
+#define T14S_EC_EVT_THERMAL_TZ39 0x5e
+#define T14S_EC_EVT_KEY_FN_F12 0x62
+#define T14S_EC_EVT_KEY_FN_TAB 0x63
+#define T14S_EC_EVT_KEY_FN_F8 0x64
+#define T14S_EC_EVT_KEY_FN_F10 0x65
+#define T14S_EC_EVT_KEY_FN_F4 0x6a
+#define T14S_EC_EVT_KEY_FN_D 0x6b
+#define T14S_EC_EVT_KEY_FN_T 0x6c
+#define T14S_EC_EVT_KEY_FN_H 0x6d
+#define T14S_EC_EVT_KEY_FN_M 0x6e
+#define T14S_EC_EVT_KEY_FN_L 0x6f
+#define T14S_EC_EVT_KEY_FN_RIGHT_SHIFT 0x71
+#define T14S_EC_EVT_KEY_FN_ESC 0x74
+#define T14S_EC_EVT_KEY_FN_N 0x79
+#define T14S_EC_EVT_KEY_FN_F11 0x7a
+#define T14S_EC_EVT_KEY_FN_G 0x7e
+
+/* Hardware LED blink rate is 1 Hz (500ms off, 500ms on) */
+#define T14S_EC_BLINK_RATE_ON_OFF_MS 500
+
+/*
+ * Add a virtual offset on all key event codes for sparse keymap handling,
+ * since the sparse keymap infrastructure does not map some raw key event
+ * codes used by the EC. For example 0x16 (T14S_EC_EVT_KEY_FN_F7) is mapped
+ * to KEY_MUTE if no offset is applied.
+ */
+#define T14S_EC_KEY_EVT_OFFSET 0x1000
+#define T14S_EC_KEY_ENTRY(key, value) \
+ { KE_KEY, T14S_EC_KEY_EVT_OFFSET + T14S_EC_EVT_KEY_##key, { value } }
+
+enum t14s_ec_led_status_t {
+ T14S_EC_LED_OFF = 0x00,
+ T14S_EC_LED_ON = 0x80,
+ T14S_EC_LED_BLINK = 0xc0,
+};
+
+struct t14s_ec_led_classdev {
+ struct led_classdev led_classdev;
+ int led;
+ enum t14s_ec_led_status_t cache;
+ struct t14s_ec *ec;
+};
+
+struct t14s_ec {
+ struct regmap *regmap;
+ struct device *dev;
+ struct t14s_ec_led_classdev led_pwr_btn;
+ struct t14s_ec_led_classdev led_chrg_orange;
+ struct t14s_ec_led_classdev led_chrg_white;
+ struct t14s_ec_led_classdev led_lid_logo_dot;
+ struct led_classdev kbd_backlight;
+ struct led_classdev led_mic_mute;
+ struct led_classdev led_spk_mute;
+ struct input_dev *inputdev;
+};
+
+static const struct regmap_config t14s_ec_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xff,
+};
+
+static int t14s_ec_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct t14s_ec *ec = context;
+ struct i2c_client *client = to_i2c_client(ec->dev);
+ u8 buf[5] = {T14S_EC_CMD_ECWR, reg, 0x00, 0x01, val};
+ int ret;
+
+ ret = i2c_master_send(client, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int t14s_ec_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct t14s_ec *ec = context;
+ struct i2c_client *client = to_i2c_client(ec->dev);
+ u8 buf[4] = {T14S_EC_CMD_ECRD, reg, 0x00, 0x01};
+ struct i2c_msg request, response;
+ u8 result;
+ int ret;
+
+ request.addr = client->addr;
+ request.flags = I2C_M_STOP;
+ request.len = sizeof(buf);
+ request.buf = buf;
+ response.addr = client->addr;
+ response.flags = I2C_M_RD;
+ response.len = 1;
+ response.buf = &result;
+
+ i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
+
+ ret = __i2c_transfer(client->adapter, &request, 1);
+ if (ret < 0)
+ goto out;
+
+ ret = __i2c_transfer(client->adapter, &response, 1);
+ if (ret < 0)
+ goto out;
+
+ *val = result;
+ ret = 0;
+
+out:
+ i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
+ return ret;
+}
+
+static const struct regmap_bus t14s_ec_regmap_bus = {
+ .reg_write = t14s_ec_write,
+ .reg_read = t14s_ec_read,
+};
+
+static int t14s_ec_read_evt(struct t14s_ec *ec, u8 *val)
+{
+ struct i2c_client *client = to_i2c_client(ec->dev);
+ u8 buf[4] = {T14S_EC_CMD_EVT, 0x00, 0x00, 0x01};
+ struct i2c_msg request, response;
+ int ret;
+
+ request.addr = client->addr;
+ request.flags = I2C_M_STOP;
+ request.len = sizeof(buf);
+ request.buf = buf;
+ response.addr = client->addr;
+ response.flags = I2C_M_RD;
+ response.len = 1;
+ response.buf = val;
+
+ i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
+
+ ret = __i2c_transfer(client->adapter, &request, 1);
+ if (ret < 0)
+ goto out;
+
+ ret = __i2c_transfer(client->adapter, &response, 1);
+ if (ret < 0)
+ goto out;
+
+ ret = 0;
+
+out:
+ i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
+ return ret;
+}
+
+static int t14s_led_set_status(struct t14s_ec *ec,
+ struct t14s_ec_led_classdev *led,
+ const enum t14s_ec_led_status_t ledstatus)
+{
+ int ret;
+
+ ret = regmap_write(ec->regmap, T14S_EC_REG_LED,
+ led->led | ledstatus);
+ if (ret < 0)
+ return ret;
+
+ led->cache = ledstatus;
+ return 0;
+}
+
+static int t14s_led_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct t14s_ec_led_classdev *led = container_of(led_cdev,
+ struct t14s_ec_led_classdev, led_classdev);
+ enum t14s_ec_led_status_t new_state;
+
+ if (brightness == LED_OFF)
+ new_state = T14S_EC_LED_OFF;
+ else if (led->cache == T14S_EC_LED_BLINK)
+ new_state = T14S_EC_LED_BLINK;
+ else
+ new_state = T14S_EC_LED_ON;
+
+ return t14s_led_set_status(led->ec, led, new_state);
+}
+
+static int t14s_led_blink_set(struct led_classdev *led_cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ struct t14s_ec_led_classdev *led = container_of(led_cdev,
+ struct t14s_ec_led_classdev, led_classdev);
+
+ if (*delay_on == 0 && *delay_off == 0) {
+ /* Userspace does not provide a blink rate; we can choose it */
+ *delay_on = T14S_EC_BLINK_RATE_ON_OFF_MS;
+ *delay_off = T14S_EC_BLINK_RATE_ON_OFF_MS;
+ } else if ((*delay_on != T14S_EC_BLINK_RATE_ON_OFF_MS) ||
+ (*delay_off != T14S_EC_BLINK_RATE_ON_OFF_MS))
+ return -EINVAL;
+
+ return t14s_led_set_status(led->ec, led, T14S_EC_LED_BLINK);
+}
+
+static int t14s_init_led(struct t14s_ec *ec, struct t14s_ec_led_classdev *led,
+ u8 id, const char *name)
+{
+ led->led_classdev.name = name;
+ led->led_classdev.flags = LED_RETAIN_AT_SHUTDOWN;
+ led->led_classdev.max_brightness = 1;
+ led->led_classdev.brightness_set_blocking = t14s_led_brightness_set;
+ led->led_classdev.blink_set = t14s_led_blink_set;
+ led->ec = ec;
+ led->led = id;
+
+ return devm_led_classdev_register(ec->dev, &led->led_classdev);
+}
+
+static int t14s_leds_probe(struct t14s_ec *ec)
+{
+ int ret;
+
+ ret = t14s_init_led(ec, &ec->led_pwr_btn, 0, "platform::power");
+ if (ret)
+ return ret;
+
+ ret = t14s_init_led(ec, &ec->led_chrg_orange, 1,
+ "platform:amber:battery-charging");
+ if (ret)
+ return ret;
+
+ ret = t14s_init_led(ec, &ec->led_chrg_white, 2,
+ "platform:white:battery-full");
+ if (ret)
+ return ret;
+
+ ret = t14s_init_led(ec, &ec->led_lid_logo_dot, 10,
+ "platform::lid_logo_dot");
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int t14s_kbd_bl_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct t14s_ec *ec = container_of(led_cdev, struct t14s_ec,
+ kbd_backlight);
+ int ret;
+ u8 val;
+
+ val = FIELD_PREP(T14S_EC_KBD_BL1_MASK, brightness);
+ ret = regmap_update_bits(ec->regmap, T14S_EC_REG_KBD_BL1,
+ T14S_EC_KBD_BL1_MASK, val);
+ if (ret < 0)
+ return ret;
+
+ val = FIELD_PREP(T14S_EC_KBD_BL2_MASK, brightness);
+ ret = regmap_update_bits(ec->regmap, T14S_EC_REG_KBD_BL2,
+ T14S_EC_KBD_BL2_MASK, val);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static enum led_brightness t14s_kbd_bl_get(struct led_classdev *led_cdev)
+{
+ struct t14s_ec *ec = container_of(led_cdev, struct t14s_ec,
+ kbd_backlight);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(ec->regmap, T14S_EC_REG_KBD_BL1, &val);
+ if (ret < 0)
+ return ret;
+
+ return FIELD_GET(T14S_EC_KBD_BL1_MASK, val);
+}
+
+static void t14s_kbd_bl_update(struct t14s_ec *ec)
+{
+ enum led_brightness brightness = t14s_kbd_bl_get(&ec->kbd_backlight);
+
+ led_classdev_notify_brightness_hw_changed(&ec->kbd_backlight, brightness);
+}
+
+static int t14s_kbd_backlight_probe(struct t14s_ec *ec)
+{
+ ec->kbd_backlight.name = "platform::kbd_backlight";
+ ec->kbd_backlight.flags = LED_BRIGHT_HW_CHANGED;
+ ec->kbd_backlight.max_brightness = 2;
+ ec->kbd_backlight.brightness_set_blocking = t14s_kbd_bl_set;
+ ec->kbd_backlight.brightness_get = t14s_kbd_bl_get;
+
+ return devm_led_classdev_register(ec->dev, &ec->kbd_backlight);
+}
+
+static enum led_brightness t14s_audio_led_get(struct t14s_ec *ec, u8 led_bit)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(ec->regmap, T14S_EC_REG_AUD, &val);
+ if (ret < 0)
+ return ret;
+
+ return !!(val & led_bit) ? LED_ON : LED_OFF;
+}
+
+static enum led_brightness t14s_audio_led_set(struct t14s_ec *ec,
+ u8 led_mask,
+ enum led_brightness brightness)
+{
+ return regmap_assign_bits(ec->regmap, T14S_EC_REG_AUD, led_mask, brightness > 0);
+}
+
+static enum led_brightness t14s_mic_mute_led_get(struct led_classdev *led_cdev)
+{
+ struct t14s_ec *ec = container_of(led_cdev, struct t14s_ec,
+ led_mic_mute);
+
+ return t14s_audio_led_get(ec, T14S_EC_MIC_MUTE_LED);
+}
+
+static int t14s_mic_mute_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct t14s_ec *ec = container_of(led_cdev, struct t14s_ec,
+ led_mic_mute);
+
+ return t14s_audio_led_set(ec, T14S_EC_MIC_MUTE_LED, brightness);
+}
+
+static enum led_brightness t14s_spk_mute_led_get(struct led_classdev *led_cdev)
+{
+ struct t14s_ec *ec = container_of(led_cdev, struct t14s_ec,
+ led_spk_mute);
+
+ return t14s_audio_led_get(ec, T14S_EC_SPK_MUTE_LED);
+}
+
+static int t14s_spk_mute_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct t14s_ec *ec = container_of(led_cdev, struct t14s_ec,
+ led_spk_mute);
+
+ return t14s_audio_led_set(ec, T14S_EC_SPK_MUTE_LED, brightness);
+}
+
+static int t14s_kbd_audio_led_probe(struct t14s_ec *ec)
+{
+ int ret;
+
+ ec->led_mic_mute.name = "platform::micmute";
+ ec->led_mic_mute.max_brightness = 1;
+ ec->led_mic_mute.default_trigger = "audio-micmute";
+ ec->led_mic_mute.brightness_set_blocking = t14s_mic_mute_led_set;
+ ec->led_mic_mute.brightness_get = t14s_mic_mute_led_get;
+
+ ec->led_spk_mute.name = "platform::mute";
+ ec->led_spk_mute.max_brightness = 1;