Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

platform: arm64: thinkpad-t14s-ec: add system PM hooks

Improve support for system suspend. The register information has been
extracted from the ACPI DSDT code handling Windows Modern Standby. I
took over the weird multi-write function from the ACPI DSDT code where
it is called ECWS.

In addition to writing to the 0xE0 register, the ACPI Windows Modern
Standby code also does some changes to the thermal configuration. This
part is not implemented.

After this patch the laptop's power and LID LEDs will switch into the
typical breathing animation when the system is suspended and enabled
normally again after resuming.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
Link: https://patch.msgid.link/20251119-thinkpad-t14s-ec-improvements-v2-3-441219857c02@kernel.org
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>

authored by

Sebastian Reichel and committed by
Ilpo Järvinen
fc62cb6a f72c8ab5

+46 -8
+46 -8
drivers/platform/arm64/lenovo-thinkpad-t14s.c
··· 20 20 #include <linux/module.h> 21 21 #include <linux/regmap.h> 22 22 #include <linux/slab.h> 23 + #include <linux/pm.h> 23 24 24 25 #define T14S_EC_CMD_ECRD 0x02 25 26 #define T14S_EC_CMD_ECWR 0x03 26 27 #define T14S_EC_CMD_EVT 0xf0 27 28 28 - #define T14S_EC_REG_LED 0x0c 29 - #define T14S_EC_REG_KBD_BL1 0x0d 30 - #define T14S_EC_REG_KBD_BL2 0xe1 31 - #define T14S_EC_KBD_BL1_MASK GENMASK_U8(7, 6) 32 - #define T14S_EC_KBD_BL2_MASK GENMASK_U8(3, 2) 33 - #define T14S_EC_REG_AUD 0x30 34 - #define T14S_EC_MIC_MUTE_LED BIT(5) 35 - #define T14S_EC_SPK_MUTE_LED BIT(6) 29 + #define T14S_EC_REG_LED 0x0c 30 + #define T14S_EC_REG_KBD_BL1 0x0d 31 + #define T14S_EC_REG_MODERN_STANDBY 0xe0 32 + #define T14S_EC_MODERN_STANDBY_ENTRY BIT(1) 33 + #define T14S_EC_MODERN_STANDBY_EXIT BIT(0) 34 + #define T14S_EC_REG_KBD_BL2 0xe1 35 + #define T14S_EC_KBD_BL1_MASK GENMASK_U8(7, 6) 36 + #define T14S_EC_KBD_BL2_MASK GENMASK_U8(3, 2) 37 + #define T14S_EC_REG_AUD 0x30 38 + #define T14S_EC_MIC_MUTE_LED BIT(5) 39 + #define T14S_EC_SPK_MUTE_LED BIT(6) 36 40 37 41 #define T14S_EC_EVT_NONE 0x00 38 42 #define T14S_EC_EVT_KEY_FN_4 0x13 ··· 200 196 out: 201 197 i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); 202 198 return ret; 199 + } 200 + 201 + static void t14s_ec_write_sequence(struct t14s_ec *ec, u8 reg, u8 val, u8 cnt) 202 + { 203 + int i; 204 + 205 + for (i = 0; i < cnt; i++) 206 + regmap_write(ec->regmap, reg, val); 203 207 } 204 208 205 209 static int t14s_led_set_status(struct t14s_ec *ec, ··· 562 550 return -ENOMEM; 563 551 564 552 ec->dev = dev; 553 + i2c_set_clientdata(client, ec); 565 554 566 555 ec->regmap = devm_regmap_init(dev, &t14s_ec_regmap_bus, 567 556 ec, &t14s_ec_regmap_config); ··· 602 589 return 0; 603 590 } 604 591 592 + static int t14s_ec_suspend(struct device *dev) 593 + { 594 + struct t14s_ec *ec = dev_get_drvdata(dev); 595 + 596 + t14s_ec_write_sequence(ec, T14S_EC_REG_MODERN_STANDBY, 597 + T14S_EC_MODERN_STANDBY_ENTRY, 3); 598 + 599 + return 0; 600 + } 601 + 602 + static int t14s_ec_resume(struct device *dev) 603 + { 604 + struct t14s_ec *ec = dev_get_drvdata(dev); 605 + 606 + t14s_ec_write_sequence(ec, T14S_EC_REG_MODERN_STANDBY, 607 + T14S_EC_MODERN_STANDBY_EXIT, 3); 608 + 609 + return 0; 610 + } 611 + 605 612 static const struct of_device_id t14s_ec_of_match[] = { 606 613 { .compatible = "lenovo,thinkpad-t14s-ec" }, 607 614 {} ··· 634 601 }; 635 602 MODULE_DEVICE_TABLE(i2c, t14s_ec_i2c_id_table); 636 603 604 + static const struct dev_pm_ops t14s_ec_pm_ops = { 605 + SYSTEM_SLEEP_PM_OPS(t14s_ec_suspend, t14s_ec_resume) 606 + }; 607 + 637 608 static struct i2c_driver t14s_ec_i2c_driver = { 638 609 .driver = { 639 610 .name = "thinkpad-t14s-ec", 640 611 .of_match_table = t14s_ec_of_match, 612 + .pm = &t14s_ec_pm_ops, 641 613 }, 642 614 .probe = t14s_ec_probe, 643 615 .id_table = t14s_ec_i2c_id_table,