FILE
ideapad-laptop.c
File preview with syntax highlighting.
linux-6.19.14/drivers/platform/x86/lenovo/ideapad-laptop.c
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * ideapad-laptop.c - Lenovo IdeaPad ACPI Extras 4 * 5 * Copyright © 2010 Intel Corporation 6 * Copyright © 2010 David Woodhouse <dwmw2@infradead.org> 7 */ 8 9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 11#include <linux/acpi.h> 12#include <linux/backlight.h> 13#include <linux/bitfield.h> 14#include <linux/bitops.h> 15#include <linux/bug.h> 16#include <linux/cleanup.h> 17#include <linux/debugfs.h> 18#include <linux/delay.h> 19#include <linux/device.h> 20#include <linux/dmi.h> 21#include <linux/i8042.h> 22#include <linux/init.h> 23#include <linux/input.h> 24#include <linux/input/sparse-keymap.h> 25#include <linux/jiffies.h> 26#include <linux/kernel.h> 27#include <linux/leds.h> 28#include <linux/module.h> 29#include <linux/platform_device.h> 30#include <linux/platform_profile.h> 31#include <linux/power_supply.h> 32#include <linux/rfkill.h> 33#include <linux/seq_file.h> 34#include <linux/string_choices.h> 35#include <linux/sysfs.h> 36#include <linux/types.h> 37#include <linux/wmi.h> 38#include "ideapad-laptop.h" 39 40#include <acpi/battery.h> 41#include <acpi/video.h> 42 43#include <dt-bindings/leds/common.h> 44 45#define IDEAPAD_RFKILL_DEV_NUM 3 46 47enum { 48 CFG_CAP_BT_BIT = 16, 49 CFG_CAP_3G_BIT = 17, 50 CFG_CAP_WIFI_BIT = 18, 51 CFG_CAP_CAM_BIT = 19, 52 53 /* 54 * These are OnScreenDisplay support bits that can be useful to determine 55 * whether a hotkey exists/should show OSD. But they aren't particularly 56 * meaningful since they were introduced later, i.e. 2010 IdeaPads 57 * don't have these, but they still have had OSD for hotkeys. 58 */ 59 CFG_OSD_NUMLK_BIT = 27, 60 CFG_OSD_CAPSLK_BIT = 28, 61 CFG_OSD_MICMUTE_BIT = 29, 62 CFG_OSD_TOUCHPAD_BIT = 30, 63 CFG_OSD_CAM_BIT = 31, 64}; 65 66/* 67 * There are two charge modes supported by the GBMD/SBMC interface: 68 * - "Rapid Charge": increase power to speed up charging 69 * - "Conservation Mode": stop charging at 60-80% (depends on model) 70 * 71 * The interface doesn't prohibit enabling both modes at the same time. 72 * However, doing so is essentially meaningless, and the manufacturer utilities 73 * on Windows always make them mutually exclusive. 74 */ 75 76enum { 77 GBMD_RAPID_CHARGE_STATE_BIT = 2, 78 GBMD_CONSERVATION_STATE_BIT = 5, 79 GBMD_RAPID_CHARGE_SUPPORTED_BIT = 17, 80}; 81 82enum { 83 SBMC_CONSERVATION_ON = 3, 84 SBMC_CONSERVATION_OFF = 5, 85 SBMC_RAPID_CHARGE_ON = 7, 86 SBMC_RAPID_CHARGE_OFF = 8, 87}; 88 89enum { 90 HALS_KBD_BL_SUPPORT_BIT = 4, 91 HALS_KBD_BL_STATE_BIT = 5, 92 HALS_USB_CHARGING_SUPPORT_BIT = 6, 93 HALS_USB_CHARGING_STATE_BIT = 7, 94 HALS_FNLOCK_SUPPORT_BIT = 9, 95 HALS_FNLOCK_STATE_BIT = 10, 96 HALS_HOTKEYS_PRIMARY_BIT = 11, 97}; 98 99enum { 100 SALS_KBD_BL_ON = 0x8, 101 SALS_KBD_BL_OFF = 0x9, 102 SALS_USB_CHARGING_ON = 0xa, 103 SALS_USB_CHARGING_OFF = 0xb, 104 SALS_FNLOCK_ON = 0xe, 105 SALS_FNLOCK_OFF = 0xf, 106}; 107 108enum { 109 VPCCMD_R_VPC1 = 0x10, 110 VPCCMD_R_BL_MAX, 111 VPCCMD_R_BL, 112 VPCCMD_W_BL, 113 VPCCMD_R_WIFI, 114 VPCCMD_W_WIFI, 115 VPCCMD_R_BT, 116 VPCCMD_W_BT, 117 VPCCMD_R_BL_POWER, 118 VPCCMD_R_NOVO, 119 VPCCMD_R_VPC2, 120 VPCCMD_R_TOUCHPAD, 121 VPCCMD_W_TOUCHPAD, 122 VPCCMD_R_CAMERA, 123 VPCCMD_W_CAMERA, 124 VPCCMD_R_3G, 125 VPCCMD_W_3G, 126 VPCCMD_R_ODD, /* 0x21 */ 127 VPCCMD_W_FAN, 128 VPCCMD_R_RF, 129 VPCCMD_W_RF, 130 VPCCMD_W_YMC = 0x2A, 131 VPCCMD_R_FAN = 0x2B, 132 VPCCMD_R_SPECIAL_BUTTONS = 0x31, 133 VPCCMD_W_BL_POWER = 0x33, 134}; 135 136/* 137 * These correspond to the number of supported states - 1 138 * Future keyboard types may need a new system, if there's a collision 139 * KBD_BL_TRISTATE_AUTO has no way to report or set the auto state 140 * so it effectively has 3 states, but needs to handle 4 141 */ 142enum { 143 KBD_BL_STANDARD = 1, 144 KBD_BL_TRISTATE = 2, 145 KBD_BL_TRISTATE_AUTO = 3, 146}; 147 148#define KBD_BL_QUERY_TYPE 0x1 149#define KBD_BL_TRISTATE_TYPE 0x5 150#define KBD_BL_TRISTATE_AUTO_TYPE 0x7 151 152#define KBD_BL_COMMAND_GET 0x2 153#define KBD_BL_COMMAND_SET 0x3 154#define KBD_BL_COMMAND_TYPE GENMASK(7, 4) 155 156#define KBD_BL_GET_BRIGHTNESS GENMASK(15, 1) 157#define KBD_BL_SET_BRIGHTNESS GENMASK(19, 16) 158 159#define KBD_BL_KBLC_CHANGED_EVENT 12 160 161struct ideapad_dytc_priv { 162 enum platform_profile_option current_profile; 163 struct device *ppdev; /* platform profile device */ 164 struct mutex mutex; /* protects the DYTC interface */ 165 struct ideapad_private *priv; 166}; 167 168struct ideapad_rfk_priv { 169 int dev; 170 struct ideapad_private *priv; 171}; 172 173struct ideapad_private { 174 struct acpi_device *adev; 175 struct mutex vpc_mutex; /* protects the VPC calls */ 176 struct mutex gbmd_sbmc_mutex; /* protects GBMD/SBMC calls */ 177 struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM]; 178 struct ideapad_rfk_priv rfk_priv[IDEAPAD_RFKILL_DEV_NUM]; 179 struct platform_device *platform_device; 180 struct input_dev *inputdev; 181 struct backlight_device *blightdev; 182 struct ideapad_dytc_priv *dytc; 183 struct dentry *debug; 184 struct acpi_battery_hook battery_hook; 185 const struct power_supply_ext *battery_ext; 186 unsigned long cfg; 187 unsigned long r_touchpad_val; 188 struct { 189 bool rapid_charge : 1; 190 bool conservation_mode : 1; 191 bool dytc : 1; 192 bool fan_mode : 1; 193 bool fn_lock : 1; 194 bool set_fn_lock_led : 1; 195 bool hw_rfkill_switch : 1; 196 bool kbd_bl : 1; 197 bool touchpad_ctrl_via_ec : 1; 198 bool ctrl_ps2_aux_port : 1; 199 bool usb_charging : 1; 200 bool ymc_ec_trigger : 1; 201 } features; 202 struct { 203 bool initialized; 204 int type; 205 struct led_classdev led; 206 unsigned int last_brightness; 207 } kbd_bl; 208 struct { 209 bool initialized; 210 struct led_classdev led; 211 unsigned int last_brightness; 212 } fn_lock; 213}; 214 215static bool no_bt_rfkill; 216module_param(no_bt_rfkill, bool, 0444); 217MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth."); 218 219static bool allow_v4_dytc; 220module_param(allow_v4_dytc, bool, 0444); 221MODULE_PARM_DESC(allow_v4_dytc, 222 "Enable DYTC version 4 platform-profile support. " 223 "If you need this please report this to: platform-driver-x86@vger.kernel.org"); 224 225static bool hw_rfkill_switch; 226module_param(hw_rfkill_switch, bool, 0444); 227MODULE_PARM_DESC(hw_rfkill_switch, 228 "Enable rfkill support for laptops with a hw on/off wifi switch/slider. " 229 "If you need this please report this to: platform-driver-x86@vger.kernel.org"); 230 231static bool set_fn_lock_led; 232module_param(set_fn_lock_led, bool, 0444); 233MODULE_PARM_DESC(set_fn_lock_led, 234 "Enable driver based updates of the fn-lock LED on fn-lock changes. " 235 "If you need this please report this to: platform-driver-x86@vger.kernel.org"); 236 237static bool ctrl_ps2_aux_port; 238module_param(ctrl_ps2_aux_port, bool, 0444); 239MODULE_PARM_DESC(ctrl_ps2_aux_port, 240 "Enable driver based PS/2 aux port en-/dis-abling on touchpad on/off toggle. " 241 "If you need this please report this to: platform-driver-x86@vger.kernel.org"); 242 243static bool touchpad_ctrl_via_ec; 244module_param(touchpad_ctrl_via_ec, bool, 0444); 245MODULE_PARM_DESC(touchpad_ctrl_via_ec, 246 "Enable registering a 'touchpad' sysfs-attribute which can be used to manually " 247 "tell the EC to enable/disable the touchpad. This may not work on all models."); 248 249static bool ymc_ec_trigger __read_mostly; 250module_param(ymc_ec_trigger, bool, 0444); 251MODULE_PARM_DESC(ymc_ec_trigger, 252 "Enable EC triggering work-around to force emitting tablet mode events. " 253 "If you need this please report this to: platform-driver-x86@vger.kernel.org"); 254 255/* 256 * shared data 257 */ 258 259static struct ideapad_private *ideapad_shared; 260static DEFINE_MUTEX(ideapad_shared_mutex); 261 262static int ideapad_shared_init(struct ideapad_private *priv) 263{ 264 int ret; 265 266 guard(mutex)(&ideapad_shared_mutex); 267 268 if (!ideapad_shared) { 269 ideapad_shared = priv; 270 ret = 0; 271 } else { 272 dev_warn(&priv->adev->dev, "found multiple platform devices\n"); 273 ret = -EINVAL; 274 } 275 276 return ret; 277} 278 279static void ideapad_shared_exit(struct ideapad_private *priv) 280{ 281 guard(mutex)(&ideapad_shared_mutex); 282 283 if (ideapad_shared == priv) 284 ideapad_shared = NULL; 285} 286 287/* 288 * ACPI Helpers 289 */ 290#define IDEAPAD_EC_TIMEOUT 200 /* in ms */ 291 292/* 293 * Some models (e.g., ThinkBook since 2024) have a low tolerance for being 294 * polled too frequently. Doing so may break the state machine in the EC, 295 * resulting in a hard shutdown. 296 * 297 * It is also observed that frequent polls may disturb the ongoing operation 298 * and notably delay the availability of EC response. 299 * 300 * These values are used as the delay before the first poll and the interval 301 * between subsequent polls to solve the above issues. 302 */ 303#define IDEAPAD_EC_POLL_MIN_US 150 304#define IDEAPAD_EC_POLL_MAX_US 300 305 306static int eval_int(acpi_handle handle, const char *name, unsigned long *res) 307{ 308 unsigned long long result; 309 acpi_status status; 310 311 status = acpi_evaluate_integer(handle, (char *)name, NULL, &result); 312 if (ACPI_FAILURE(status)) 313 return -EIO; 314 315 *res = result; 316 317 return 0; 318} 319 320static int eval_int_with_arg(acpi_handle handle, const char *name, unsigned long arg, 321 unsigned long *res) 322{ 323 struct acpi_object_list params; 324 unsigned long long result; 325 union acpi_object in_obj; 326 acpi_status status; 327 328 params.count = 1; 329 params.pointer = &in_obj; 330 in_obj.type = ACPI_TYPE_INTEGER; 331 in_obj.integer.value = arg; 332 333 status = acpi_evaluate_integer(handle, (char *)name, ¶ms, &result); 334 if (ACPI_FAILURE(status)) 335 return -EIO; 336 337 if (res) 338 *res = result; 339 340 return 0; 341} 342 343static int exec_simple_method(acpi_handle handle, const char *name, unsigned long arg) 344{ 345 acpi_status status = acpi_execute_simple_method(handle, (char *)name, arg); 346 347 return ACPI_FAILURE(status) ? -EIO : 0; 348} 349 350static int eval_gbmd(acpi_handle handle, unsigned long *res) 351{ 352 return eval_int(handle, "GBMD", res); 353} 354 355static int exec_sbmc(acpi_handle handle, unsigned long arg) 356{ 357 return exec_simple_method(handle, "SBMC", arg); 358} 359 360static int eval_hals(acpi_handle handle, unsigned long *res) 361{ 362 return eval_int(handle, "HALS", res); 363} 364 365static int exec_sals(acpi_handle handle, unsigned long arg) 366{ 367 return exec_simple_method(handle, "SALS", arg); 368} 369 370static int exec_kblc(acpi_handle handle, unsigned long arg) 371{ 372 return exec_simple_method(handle, "KBLC", arg); 373} 374 375static int eval_kblc(acpi_handle handle, unsigned long cmd, unsigned long *res) 376{ 377 return eval_int_with_arg(handle, "KBLC", cmd, res); 378} 379 380static int eval_dytc(acpi_handle handle, unsigned long cmd, unsigned long *res) 381{ 382 return eval_int_with_arg(handle, "DYTC", cmd, res); 383} 384 385static int eval_vpcr(acpi_handle handle, unsigned long cmd, unsigned long *res) 386{ 387 return eval_int_with_arg(handle, "VPCR", cmd, res); 388} 389 390static int eval_vpcw(acpi_handle handle, unsigned long cmd, unsigned long data) 391{ 392 struct acpi_object_list params; 393 union acpi_object in_obj[2]; 394 acpi_status status; 395 396 params.count = 2; 397 params.pointer = in_obj; 398 in_obj[0].type = ACPI_TYPE_INTEGER; 399 in_obj[0].integer.value = cmd; 400 in_obj[1].type = ACPI_TYPE_INTEGER; 401 in_obj[1].integer.value = data; 402 403 status = acpi_evaluate_object(handle, "VPCW", ¶ms, NULL); 404 if (ACPI_FAILURE(status)) 405 return -EIO; 406 407 return 0; 408} 409 410static int read_ec_data(acpi_handle handle, unsigned long cmd, unsigned long *data) 411{ 412 unsigned long end_jiffies, val; 413 int err; 414 415 err = eval_vpcw(handle, 1, cmd); 416 if (err) 417 return err; 418 419 end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1; 420 421 while (time_before(jiffies, end_jiffies)) { 422 usleep_range(IDEAPAD_EC_POLL_MIN_US, IDEAPAD_EC_POLL_MAX_US); 423 424 err = eval_vpcr(handle, 1, &val); 425 if (err) 426 return err; 427 428 if (val == 0) 429 return eval_vpcr(handle, 0, data); 430 } 431 432 acpi_handle_err(handle, "timeout in %s\n", __func__); 433 434 return -ETIMEDOUT; 435} 436 437static int write_ec_cmd(acpi_handle handle, unsigned long cmd, unsigned long data) 438{ 439 unsigned long end_jiffies, val; 440 int err; 441 442 err = eval_vpcw(handle, 0, data); 443 if (err) 444 return err; 445 446 err = eval_vpcw(handle, 1, cmd); 447 if (err) 448 return err; 449 450 end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1; 451 452 while (time_before(jiffies, end_jiffies)) { 453 usleep_range(IDEAPAD_EC_POLL_MIN_US, IDEAPAD_EC_POLL_MAX_US); 454 455 err = eval_vpcr(handle, 1, &val); 456 if (err) 457 return err; 458 459 if (val == 0) 460 return 0; 461 } 462 463 acpi_handle_err(handle, "timeout in %s\n", __func__); 464 465 return -ETIMEDOUT; 466} 467 468/* 469 * debugfs 470 */ 471static int debugfs_status_show(struct seq_file *s, void *data) 472{ 473 struct ideapad_private *priv = s->private; 474 unsigned long value; 475 476 scoped_guard(mutex, &priv->vpc_mutex) { 477 if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value)) 478 seq_printf(s, "Backlight max: %lu\n", value); 479 if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value)) 480 seq_printf(s, "Backlight now: %lu\n", value); 481 if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &value)) 482 seq_printf(s, "BL power value: %s (%lu)\n", str_on_off(value), value); 483 484 seq_puts(s, "=====================\n"); 485 486 if (!read_ec_data(priv->adev->handle, VPCCMD_R_RF, &value)) 487 seq_printf(s, "Radio status: %s (%lu)\n", str_on_off(value), value); 488 if (!read_ec_data(priv->adev->handle, VPCCMD_R_WIFI, &value)) 489 seq_printf(s, "Wifi status: %s (%lu)\n", str_on_off(value), value); 490 if (!read_ec_data(priv->adev->handle, VPCCMD_R_BT, &value)) 491 seq_printf(s, "BT status: %s (%lu)\n", str_on_off(value), value); 492 if (!read_ec_data(priv->adev->handle, VPCCMD_R_3G, &value)) 493 seq_printf(s, "3G status: %s (%lu)\n", str_on_off(value), value); 494 495 seq_puts(s, "=====================\n"); 496 497 if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value)) 498 seq_printf(s, "Touchpad status: %s (%lu)\n", str_on_off(value), value); 499 if (!read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &value)) 500 seq_printf(s, "Camera status: %s (%lu)\n", str_on_off(value), value); 501 } 502 503 seq_puts(s, "=====================\n"); 504 505 scoped_guard(mutex, &priv->gbmd_sbmc_mutex) { 506 if (!eval_gbmd(priv->adev->handle, &value)) 507 seq_printf(s, "GBMD: %#010lx\n", value); 508 } 509 510 if (!eval_hals(priv->adev->handle, &value)) 511 seq_printf(s, "HALS: %#010lx\n", value); 512 513 return 0; 514} 515DEFINE_SHOW_ATTRIBUTE(debugfs_status); 516 517static int debugfs_cfg_show(struct seq_file *s, void *data) 518{ 519 struct ideapad_private *priv = s->private; 520 521 seq_printf(s, "_CFG: %#010lx\n\n", priv->cfg); 522 523 seq_puts(s, "Capabilities:"); 524 if (test_bit(CFG_CAP_BT_BIT, &priv->cfg)) 525 seq_puts(s, " bluetooth"); 526 if (test_bit(CFG_CAP_3G_BIT, &priv->cfg)) 527 seq_puts(s, " 3G"); 528 if (test_bit(CFG_CAP_WIFI_BIT, &priv->cfg)) 529 seq_puts(s, " wifi"); 530 if (test_bit(CFG_CAP_CAM_BIT, &priv->cfg)) 531 seq_puts(s, " camera"); 532 seq_puts(s, "\n"); 533 534 seq_puts(s, "OSD support:"); 535 if (test_bit(CFG_OSD_NUMLK_BIT, &priv->cfg)) 536 seq_puts(s, " num-lock"); 537 if (test_bit(CFG_OSD_CAPSLK_BIT, &priv->cfg)) 538 seq_puts(s, " caps-lock"); 539 if (test_bit(CFG_OSD_MICMUTE_BIT, &priv->cfg)) 540 seq_puts(s, " mic-mute"); 541 if (test_bit(CFG_OSD_TOUCHPAD_BIT, &priv->cfg)) 542 seq_puts(s, " touchpad"); 543 if (test_bit(CFG_OSD_CAM_BIT, &priv->cfg)) 544 seq_puts(s, " camera"); 545 seq_puts(s, "\n"); 546 547 seq_puts(s, "Graphics: "); 548 switch (priv->cfg & 0x700) { 549 case 0x100: 550 seq_puts(s, "Intel"); 551 break; 552 case 0x200: 553 seq_puts(s, "ATI"); 554 break; 555 case 0x300: 556 seq_puts(s, "Nvidia"); 557 break; 558 case 0x400: 559 seq_puts(s, "Intel and ATI"); 560 break; 561 case 0x500: 562 seq_puts(s, "Intel and Nvidia"); 563 break; 564 } 565 seq_puts(s, "\n"); 566 567 return 0; 568} 569DEFINE_SHOW_ATTRIBUTE(debugfs_cfg); 570 571static void ideapad_debugfs_init(struct ideapad_private *priv) 572{ 573 struct dentry *dir; 574 575 dir = debugfs_create_dir("ideapad", NULL); 576 priv->debug = dir; 577 578 debugfs_create_file("cfg", 0444, dir, priv, &debugfs_cfg_fops); 579 debugfs_create_file("status", 0444, dir, priv, &debugfs_status_fops); 580} 581 582static void ideapad_debugfs_exit(struct ideapad_private *priv) 583{ 584 debugfs_remove_recursive(priv->debug); 585 priv->debug = NULL; 586} 587 588/* 589 * sysfs 590 */ 591static ssize_t camera_power_show(struct device *dev, 592 struct device_attribute *attr, 593 char *buf) 594{ 595 struct ideapad_private *priv = dev_get_drvdata(dev); 596 unsigned long result = 0; 597 int err; 598 599 scoped_guard(mutex, &priv->vpc_mutex) { 600 err = read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &result); 601 if (err) 602 return err; 603 } 604 605 return sysfs_emit(buf, "%d\n", !!result); 606} 607 608static ssize_t camera_power_store(struct device *dev, 609 struct device_attribute *attr, 610 const char *buf, size_t count) 611{ 612 struct ideapad_private *priv = dev_get_drvdata(dev); 613 bool state; 614 int err; 615 616 err = kstrtobool(buf, &state); 617 if (err) 618 return err; 619 620 scoped_guard(mutex, &priv->vpc_mutex) { 621 err = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state); 622 if (err) 623 return err; 624 } 625 626 return count; 627} 628 629static DEVICE_ATTR_RW(camera_power); 630 631static void show_conservation_mode_deprecation_warning(struct device *dev) 632{ 633 dev_warn_once(dev, "conservation_mode attribute has been deprecated, see charge_types.\n"); 634} 635 636static ssize_t conservation_mode_show(struct device *dev, 637 struct device_attribute *attr, 638 char *buf) 639{ 640 struct ideapad_private *priv = dev_get_drvdata(dev); 641 unsigned long result; 642 int err; 643 644 show_conservation_mode_deprecation_warning(dev); 645 646 scoped_guard(mutex, &priv->gbmd_sbmc_mutex) { 647 err = eval_gbmd(priv->adev->handle, &result); 648 if (err) 649 return err; 650 } 651 652 /* 653 * For backward compatibility, ignore Rapid Charge while reporting the 654 * state of Conservation Mode. 655 */ 656 return sysfs_emit(buf, "%d\n", !!test_bit(GBMD_CONSERVATION_STATE_BIT, &result)); 657} 658 659static ssize_t conservation_mode_store(struct device *dev, 660 struct device_attribute *attr, 661 const char *buf, size_t count) 662{ 663 struct ideapad_private *priv = dev_get_drvdata(dev); 664 bool state; 665 int err; 666 667 show_conservation_mode_deprecation_warning(dev); 668 669 err = kstrtobool(buf, &state); 670 if (err) 671 return err; 672 673 guard(mutex)(&priv->gbmd_sbmc_mutex); 674 675 /* 676 * Prevent mutually exclusive modes from being set at the same time, 677 * but do not disable Rapid Charge while disabling Conservation Mode. 678 */ 679 if (priv->features.rapid_charge && state) { 680 err = exec_sbmc(priv->adev->handle, SBMC_RAPID_CHARGE_OFF); 681 if (err) 682 return err; 683 } 684 685 err = exec_sbmc(priv->adev->handle, state ? SBMC_CONSERVATION_ON : SBMC_CONSERVATION_OFF); 686 if (err) 687 return err; 688 689 return count; 690} 691 692static DEVICE_ATTR_RW(conservation_mode); 693 694static ssize_t fan_mode_show(struct device *dev, 695 struct device_attribute *attr, 696 char *buf) 697{ 698 struct ideapad_private *priv = dev_get_drvdata(dev); 699 unsigned long result = 0; 700 int err; 701 702 scoped_guard(mutex, &priv->vpc_mutex) { 703 err = read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &result); 704 if (err) 705 return err; 706 } 707 708 return sysfs_emit(buf, "%lu\n", result); 709} 710 711static ssize_t fan_mode_store(struct device *dev, 712 struct device_attribute *attr, 713 const char *buf, size_t count) 714{ 715 struct ideapad_private *priv = dev_get_drvdata(dev); 716 unsigned int state; 717 int err; 718 719 err = kstrtouint(buf, 0, &state); 720 if (err) 721 return err; 722 723 if (state > 4 || state == 3) 724 return -EINVAL; 725 726 scoped_guard(mutex, &priv->vpc_mutex) { 727 err = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state); 728 if (err) 729 return err; 730 } 731 732 return count; 733} 734 735static DEVICE_ATTR_RW(fan_mode); 736 737static int ideapad_fn_lock_get(struct ideapad_private *priv) 738{ 739 unsigned long hals; 740 int err; 741 742 err = eval_hals(priv->adev->handle, &hals); 743 if (err) 744 return err; 745 746 return !!test_bit(HALS_FNLOCK_STATE_BIT, &hals); 747} 748 749static int ideapad_fn_lock_set(struct ideapad_private *priv, bool state) 750{ 751 return exec_sals(priv->adev->handle, 752 state ? SALS_FNLOCK_ON : SALS_FNLOCK_OFF); 753} 754 755static void ideapad_fn_lock_led_notify(struct ideapad_private *priv, int brightness) 756{ 757 if (!priv->fn_lock.initialized) 758 return; 759 760 if (brightness == priv->fn_lock.last_brightness) 761 return; 762 763 priv->fn_lock.last_brightness = brightness; 764 765 led_classdev_notify_brightness_hw_changed(&priv->fn_lock.led, brightness); 766} 767 768static ssize_t fn_lock_show(struct device *dev, 769 struct device_attribute *attr, 770 char *buf) 771{ 772 struct ideapad_private *priv = dev_get_drvdata(dev); 773 int brightness; 774 775 brightness = ideapad_fn_lock_get(priv); 776 if (brightness < 0) 777 return brightness; 778 779 return sysfs_emit(buf, "%d\n", brightness); 780} 781 782static ssize_t fn_lock_store(struct device *dev, 783 struct device_attribute *attr, 784 const char *buf, size_t count) 785{ 786 struct ideapad_private *priv = dev_get_drvdata(dev); 787 bool state; 788 int err; 789 790 err = kstrtobool(buf, &state); 791 if (err) 792 return err; 793 794 err = ideapad_fn_lock_set(priv, state); 795 if (err) 796 return err; 797 798 ideapad_fn_lock_led_notify(priv, state); 799 800 return count; 801} 802 803static DEVICE_ATTR_RW(fn_lock); 804 805static ssize_t touchpad_show(struct device *dev, 806 struct device_attribute *attr, 807 char *buf) 808{ 809 struct ideapad_private *priv = dev_get_drvdata(dev); 810 unsigned long result = 0; 811 int err; 812 813 scoped_guard(mutex, &priv->vpc_mutex) { 814 err = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result); 815 if (err) 816 return err; 817 } 818 819 priv->r_touchpad_val = result; 820 821 return sysfs_emit(buf, "%d\n", !!result); 822} 823 824static ssize_t touchpad_store(struct device *dev, 825 struct device_attribute *attr, 826 const char *buf, size_t count) 827{ 828 struct ideapad_private *priv = dev_get_drvdata(dev); 829 bool state; 830 int err; 831 832 err = kstrtobool(buf, &state); 833 if (err) 834 return err; 835 836 scoped_guard(mutex, &priv->vpc_mutex) { 837 err = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state); 838 if (err) 839 return err; 840 } 841 842 priv->r_touchpad_val = state; 843 844 return count; 845} 846 847static DEVICE_ATTR_RW(touchpad); 848 849static ssize_t usb_charging_show(struct device *dev, 850 struct device_attribute *attr, 851 char *buf) 852{ 853 struct ideapad_private *priv = dev_get_drvdata(dev); 854 unsigned long hals; 855 int err; 856 857 err = eval_hals(priv->adev->handle, &hals); 858 if (err) 859 return err; 860 861 return sysfs_emit(buf, "%d\n", !!test_bit(HALS_USB_CHARGING_STATE_BIT, &hals)); 862} 863 864static ssize_t usb_charging_store(struct device *dev, 865 struct device_attribute *attr, 866 const char *buf, size_t count) 867{ 868 struct ideapad_private *priv = dev_get_drvdata(dev); 869 bool state; 870 int err; 871 872 err = kstrtobool(buf, &state); 873 if (err) 874 return err; 875 876 err = exec_sals(priv->adev->handle, state ? SALS_USB_CHARGING_ON : SALS_USB_CHARGING_OFF); 877 if (err) 878 return err; 879 880 return count; 881} 882 883static DEVICE_ATTR_RW(usb_charging); 884 885static struct attribute *ideapad_attributes[] = { 886 &dev_attr_camera_power.attr, 887 &dev_attr_conservation_mode.attr, 888 &dev_attr_fan_mode.attr, 889 &dev_attr_fn_lock.attr, 890 &dev_attr_touchpad.attr, 891 &dev_attr_usb_charging.attr, 892 NULL 893}; 894 895static umode_t ideapad_is_visible(struct kobject *kobj, 896 struct attribute *attr, 897 int idx) 898{ 899 struct device *dev = kobj_to_dev(kobj); 900 struct ideapad_private *priv = dev_get_drvdata(dev); 901 bool supported = true; 902 903 if (attr == &dev_attr_camera_power.attr) 904 supported = test_bit(CFG_CAP_CAM_BIT, &priv->cfg); 905 else if (attr == &dev_attr_conservation_mode.attr) 906 supported = priv->features.conservation_mode; 907 else if (attr == &dev_attr_fan_mode.attr) 908 supported = priv->features.fan_mode; 909 else if (attr == &dev_attr_fn_lock.attr) 910 supported = priv->features.fn_lock; 911 else if (attr == &dev_attr_touchpad.attr) 912 supported = priv->features.touchpad_ctrl_via_ec; 913 else if (attr == &dev_attr_usb_charging.attr) 914 supported = priv->features.usb_charging; 915 916 return supported ? attr->mode : 0; 917} 918 919static const struct attribute_group ideapad_attribute_group = { 920 .is_visible = ideapad_is_visible, 921 .attrs = ideapad_attributes 922}; 923__ATTRIBUTE_GROUPS(ideapad_attribute); 924 925/* 926 * DYTC Platform profile 927 */ 928#define DYTC_CMD_QUERY 0 /* To get DYTC status - enable/revision */ 929#define DYTC_CMD_SET 1 /* To enable/disable IC function mode */ 930#define DYTC_CMD_GET 2 /* To get current IC function and mode */ 931#define DYTC_CMD_RESET 0x1ff /* To reset back to default */ 932 933#define DYTC_QUERY_ENABLE_BIT 8 /* Bit 8 - 0 = disabled, 1 = enabled */ 934#define DYTC_QUERY_SUBREV_BIT 16 /* Bits 16 - 27 - sub revision */ 935#define DYTC_QUERY_REV_BIT 28 /* Bits 28 - 31 - revision */ 936 937#define DYTC_GET_FUNCTION_BIT 8 /* Bits 8-11 - function setting */ 938#define DYTC_GET_MODE_BIT 12 /* Bits 12-15 - mode setting */ 939 940#define DYTC_SET_FUNCTION_BIT 12 /* Bits 12-15 - function setting */ 941#define DYTC_SET_MODE_BIT 16 /* Bits 16-19 - mode setting */ 942#define DYTC_SET_VALID_BIT 20 /* Bit 20 - 1 = on, 0 = off */ 943 944#define DYTC_FUNCTION_STD 0 /* Function = 0, standard mode */ 945#define DYTC_FUNCTION_CQL 1 /* Function = 1, lap mode */ 946#define DYTC_FUNCTION_MMC 11 /* Function = 11, desk mode */ 947 948#define DYTC_MODE_PERFORM 2 /* High power mode aka performance */ 949#define DYTC_MODE_LOW_POWER 3 /* Low power mode aka quiet */ 950#define DYTC_MODE_BALANCE 0xF /* Default mode aka balanced */ 951 952#define DYTC_SET_COMMAND(function, mode, on) \ 953 (DYTC_CMD_SET | (function) << DYTC_SET_FUNCTION_BIT | \ 954 (mode) << DYTC_SET_MODE_BIT | \ 955 (on) << DYTC_SET_VALID_BIT) 956 957#define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 0) 958 959#define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 1) 960 961static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile) 962{ 963 switch (dytcmode) { 964 case DYTC_MODE_LOW_POWER: 965 *profile = PLATFORM_PROFILE_LOW_POWER; 966 break; 967 case DYTC_MODE_BALANCE: 968 *profile = PLATFORM_PROFILE_BALANCED; 969 break; 970 case DYTC_MODE_PERFORM: 971 *profile = PLATFORM_PROFILE_PERFORMANCE; 972 break; 973 default: /* Unknown mode */ 974 return -EINVAL; 975 } 976 977 return 0; 978} 979 980static int convert_profile_to_dytc(enum platform_profile_option profile, int *perfmode) 981{ 982 switch (profile) { 983 case PLATFORM_PROFILE_LOW_POWER: 984 *perfmode = DYTC_MODE_LOW_POWER; 985 break; 986 case PLATFORM_PROFILE_BALANCED: 987 *perfmode = DYTC_MODE_BALANCE; 988 break; 989 case PLATFORM_PROFILE_PERFORMANCE: 990 *perfmode = DYTC_MODE_PERFORM; 991 break; 992 default: /* Unknown profile */ 993 return -EOPNOTSUPP; 994 } 995 996 return 0; 997} 998 999/* 1000 * dytc_profile_get: Function to register with platform_profile 1001 * handler. Returns current platform profile. 1002 */ 1003static int dytc_profile_get(struct device *dev, 1004 enum platform_profile_option *profile) 1005{ 1006 struct ideapad_dytc_priv *dytc = dev_get_drvdata(dev); 1007 1008 *profile = dytc->current_profile; 1009 return 0; 1010} 1011 1012/* 1013 * Helper function - check if we are in CQL mode and if we are 1014 * - disable CQL, 1015 * - run the command 1016 * - enable CQL 1017 * If not in CQL mode, just run the command 1018 */ 1019static int dytc_cql_command(struct ideapad_private *priv, unsigned long cmd, 1020 unsigned long *output) 1021{ 1022 int err, cmd_err, cur_funcmode; 1023 1024 /* Determine if we are in CQL mode. This alters the commands we do */ 1025 err = eval_dytc(priv->adev->handle, DYTC_CMD_GET, output); 1026 if (err) 1027 return err; 1028 1029 cur_funcmode = (*output >> DYTC_GET_FUNCTION_BIT) & 0xF; 1030 /* Check if we're OK to return immediately */ 1031 if (cmd == DYTC_CMD_GET && cur_funcmode != DYTC_FUNCTION_CQL) 1032 return 0; 1033 1034 if (cur_funcmode == DYTC_FUNCTION_CQL) { 1035 err = eval_dytc(priv->adev->handle, DYTC_DISABLE_CQL, NULL); 1036 if (err) 1037 return err; 1038 } 1039 1040 cmd_err = eval_dytc(priv->adev->handle, cmd, output); 1041 /* Check return condition after we've restored CQL state */ 1042 1043 if (cur_funcmode == DYTC_FUNCTION_CQL) { 1044 err = eval_dytc(priv->adev->handle, DYTC_ENABLE_CQL, NULL); 1045 if (err) 1046 return err; 1047 } 1048 1049 return cmd_err; 1050} 1051 1052/* 1053 * dytc_profile_set: Function to register with platform_profile 1054 * handler. Sets current platform profile. 1055 */ 1056static int dytc_profile_set(struct device *dev, 1057 enum platform_profile_option profile) 1058{ 1059 struct ideapad_dytc_priv *dytc = dev_get_drvdata(dev); 1060 struct ideapad_private *priv = dytc->priv; 1061 unsigned long output; 1062 int err; 1063 1064 scoped_guard(mutex_intr, &dytc->mutex) { 1065 if (profile == PLATFORM_PROFILE_BALANCED) { 1066 /* To get back to balanced mode we just issue a reset command */ 1067 err = eval_dytc(priv->adev->handle, DYTC_CMD_RESET, NULL); 1068 if (err) 1069 return err; 1070 } else { 1071 int perfmode; 1072 1073 err = convert_profile_to_dytc(profile, &perfmode); 1074 if (err) 1075 return err; 1076 1077 /* Determine if we are in CQL mode. This alters the commands we do */ 1078 err = dytc_cql_command(priv, 1079 DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1), 1080 &output); 1081 if (err) 1082 return err; 1083 } 1084 1085 /* Success - update current profile */ 1086 dytc->current_profile = profile; 1087 return 0; 1088 } 1089 1090 return -EINTR; 1091} 1092 1093static int dytc_profile_probe(void *drvdata, unsigned long *choices) 1094{ 1095 set_bit(PLATFORM_PROFILE_LOW_POWER, choices); 1096 set_bit(PLATFORM_PROFILE_BALANCED, choices); 1097 set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); 1098 1099 return 0; 1100} 1101 1102static void dytc_profile_refresh(struct ideapad_private *priv) 1103{ 1104 enum platform_profile_option profile; 1105 unsigned long output; 1106 int err, perfmode; 1107 1108 scoped_guard(mutex, &priv->dytc->mutex) 1109 err = dytc_cql_command(priv, DYTC_CMD_GET, &output); 1110 if (err) 1111 return; 1112 1113 perfmode = (output >> DYTC_GET_MODE_BIT) & 0xF; 1114 1115 if (convert_dytc_to_profile(perfmode, &profile)) 1116 return; 1117 1118 if (profile != priv->dytc->current_profile) { 1119 priv->dytc->current_profile = profile; 1120 platform_profile_notify(priv->dytc->ppdev); 1121 } 1122} 1123 1124static const struct dmi_system_id ideapad_dytc_v4_allow_table[] = { 1125 { 1126 /* Ideapad 5 Pro 16ACH6 */ 1127 .matches = { 1128 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 1129 DMI_MATCH(DMI_PRODUCT_NAME, "82L5") 1130 } 1131 }, 1132 { 1133 /* Ideapad 5 15ITL05 */ 1134 .matches = { 1135 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 1136 DMI_MATCH(DMI_PRODUCT_VERSION, "IdeaPad 5 15ITL05") 1137 } 1138 }, 1139 {} 1140}; 1141 1142static const struct platform_profile_ops dytc_profile_ops = { 1143 .probe = dytc_profile_probe, 1144 .profile_get = dytc_profile_get, 1145 .profile_set = dytc_profile_set, 1146}; 1147 1148static int ideapad_dytc_profile_init(struct ideapad_private *priv) 1149{ 1150 int err, dytc_version; 1151 unsigned long output; 1152 1153 if (!priv->features.dytc) 1154 return -ENODEV; 1155 1156 err = eval_dytc(priv->adev->handle, DYTC_CMD_QUERY, &output); 1157 /* For all other errors we can flag the failure */ 1158 if (err) 1159 return err; 1160 1161 /* Check DYTC is enabled and supports mode setting */ 1162 if (!test_bit(DYTC_QUERY_ENABLE_BIT, &output)) { 1163 dev_info(&priv->platform_device->dev, "DYTC_QUERY_ENABLE_BIT returned false\n"); 1164 return -ENODEV; 1165 } 1166 1167 dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF; 1168 1169 if (dytc_version < 4) { 1170 dev_info(&priv->platform_device->dev, "DYTC_VERSION < 4 is not supported\n"); 1171 return -ENODEV; 1172 } 1173 1174 if (dytc_version < 5 && 1175 !(allow_v4_dytc || dmi_check_system(ideapad_dytc_v4_allow_table))) { 1176 dev_info(&priv->platform_device->dev, 1177 "DYTC_VERSION 4 support may not work. Pass ideapad_laptop.allow_v4_dytc=Y on the kernel commandline to enable\n"); 1178 return -ENODEV; 1179 } 1180 1181 priv->dytc = kzalloc(sizeof(*priv->dytc), GFP_KERNEL); 1182 if (!priv->dytc) 1183 return -ENOMEM; 1184 1185 mutex_init(&priv->dytc->mutex); 1186 1187 priv->dytc->priv = priv; 1188 1189 /* Create platform_profile structure and register */ 1190 priv->dytc->ppdev = devm_platform_profile_register(&priv->platform_device->dev, 1191 "ideapad-laptop", priv->dytc, 1192 &dytc_profile_ops); 1193 if (IS_ERR(priv->dytc->ppdev)) { 1194 err = PTR_ERR(priv->dytc->ppdev); 1195 goto pp_reg_failed; 1196 } 1197 1198 /* Ensure initial values are correct */ 1199 dytc_profile_refresh(priv); 1200 1201 return 0; 1202 1203pp_reg_failed: 1204 mutex_destroy(&priv->dytc->mutex); 1205 kfree(priv->dytc); 1206 priv->dytc = NULL; 1207 1208 return err; 1209} 1210 1211static void ideapad_dytc_profile_exit(struct ideapad_private *priv) 1212{ 1213 if (!priv->dytc) 1214 return; 1215 1216 mutex_destroy(&priv->dytc->mutex); 1217 kfree(priv->dytc); 1218 1219 priv->dytc = NULL; 1220} 1221 1222/* 1223 * Rfkill 1224 */ 1225struct ideapad_rfk_data { 1226 char *name; 1227 int cfgbit; 1228 int opcode; 1229 int type; 1230}; 1231 1232static const struct ideapad_rfk_data ideapad_rfk_data[] = { 1233 { "ideapad_wlan", CFG_CAP_WIFI_BIT, VPCCMD_W_WIFI, RFKILL_TYPE_WLAN }, 1234 { "ideapad_bluetooth", CFG_CAP_BT_BIT, VPCCMD_W_BT, RFKILL_TYPE_BLUETOOTH }, 1235 { "ideapad_3g", CFG_CAP_3G_BIT, VPCCMD_W_3G, RFKILL_TYPE_WWAN }, 1236}; 1237 1238static int ideapad_rfk_set(void *data, bool blocked) 1239{ 1240 struct ideapad_rfk_priv *priv = data; 1241 int opcode = ideapad_rfk_data[priv->dev].opcode; 1242 1243 guard(mutex)(&priv->priv->vpc_mutex); 1244 1245 return write_ec_cmd(priv->priv->adev->handle, opcode, !blocked); 1246} 1247 1248static const struct rfkill_ops ideapad_rfk_ops = { 1249 .set_block = ideapad_rfk_set, 1250}; 1251 1252static void ideapad_sync_rfk_state(struct ideapad_private *priv) 1253{ 1254 unsigned long hw_blocked = 0; 1255 int i; 1256 1257 if (priv->features.hw_rfkill_switch) { 1258 guard(mutex)(&priv->vpc_mutex); 1259 1260 if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked)) 1261 return; 1262 hw_blocked = !hw_blocked; 1263 } 1264 1265 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) 1266 if (priv->rfk[i]) 1267 rfkill_set_hw_state(priv->rfk[i], hw_blocked); 1268} 1269 1270static int ideapad_register_rfkill(struct ideapad_private *priv, int dev) 1271{ 1272 unsigned long rf_enabled; 1273 int err; 1274 1275 if (no_bt_rfkill && ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH) { 1276 /* Force to enable bluetooth when no_bt_rfkill=1 */ 1277 write_ec_cmd(priv->adev->handle, ideapad_rfk_data[dev].opcode, 1); 1278 return 0; 1279 } 1280 1281 priv->rfk_priv[dev].dev = dev; 1282 priv->rfk_priv[dev].priv = priv; 1283 1284 priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev].name, 1285 &priv->platform_device->dev, 1286 ideapad_rfk_data[dev].type, 1287 &ideapad_rfk_ops, 1288 &priv->rfk_priv[dev]); 1289 if (!priv->rfk[dev]) 1290 return -ENOMEM; 1291 1292 err = read_ec_data(priv->adev->handle, ideapad_rfk_data[dev].opcode - 1, &rf_enabled); 1293 if (err) 1294 rf_enabled = 1; 1295 1296 rfkill_init_sw_state(priv->rfk[dev], !rf_enabled); 1297 1298 err = rfkill_register(priv->rfk[dev]); 1299 if (err) 1300 rfkill_destroy(priv->rfk[dev]); 1301 1302 return err; 1303} 1304 1305static void ideapad_unregister_rfkill(struct ideapad_private *priv, int dev) 1306{ 1307 if (!priv->rfk[dev]) 1308 return; 1309 1310 rfkill_unregister(priv->rfk[dev]); 1311 rfkill_destroy(priv->rfk[dev]); 1312} 1313 1314/* 1315 * input device 1316 */ 1317#define IDEAPAD_WMI_KEY 0x100 1318 1319static const struct key_entry ideapad_keymap[] = { 1320 { KE_KEY, 6, { KEY_SWITCHVIDEOMODE } }, 1321 { KE_KEY, 7, { KEY_CAMERA } }, 1322 { KE_KEY, 8, { KEY_MICMUTE } }, 1323 { KE_KEY, 11, { KEY_F16 } }, 1324 { KE_KEY, 13, { KEY_WLAN } }, 1325 { KE_KEY, 16, { KEY_PROG1 } }, 1326 { KE_KEY, 17, { KEY_PROG2 } }, 1327 { KE_KEY, 64, { KEY_PROG3 } }, 1328 { KE_KEY, 65, { KEY_PROG4 } }, 1329 { KE_KEY, 66, { KEY_TOUCHPAD_OFF } }, 1330 { KE_KEY, 67, { KEY_TOUCHPAD_ON } }, 1331 { KE_KEY, 128, { KEY_ESC } }, 1332 1333 /* 1334 * WMI keys 1335 */ 1336 1337 /* FnLock (handled by the firmware) */ 1338 { KE_IGNORE, 0x02 | IDEAPAD_WMI_KEY }, 1339 /* Esc (handled by the firmware) */ 1340 { KE_IGNORE, 0x03 | IDEAPAD_WMI_KEY }, 1341 /* Customizable Lenovo Hotkey ("star" with 'S' inside) */ 1342 { KE_KEY, 0x01 | IDEAPAD_WMI_KEY, { KEY_FAVORITES } }, 1343 { KE_KEY, 0x04 | IDEAPAD_WMI_KEY, { KEY_SELECTIVE_SCREENSHOT } }, 1344 /* Lenovo Support */ 1345 { KE_KEY, 0x07 | IDEAPAD_WMI_KEY, { KEY_HELP } }, 1346 { KE_KEY, 0x0e | IDEAPAD_WMI_KEY, { KEY_PICKUP_PHONE } }, 1347 { KE_KEY, 0x0f | IDEAPAD_WMI_KEY, { KEY_HANGUP_PHONE } }, 1348 /* Refresh Rate Toggle (Fn+R) */ 1349 { KE_KEY, 0x10 | IDEAPAD_WMI_KEY, { KEY_REFRESH_RATE_TOGGLE } }, 1350 /* Dark mode toggle */ 1351 { KE_KEY, 0x13 | IDEAPAD_WMI_KEY, { KEY_PROG1 } }, 1352 /* Sound profile switch */ 1353 { KE_KEY, 0x12 | IDEAPAD_WMI_KEY, { KEY_PROG2 } }, 1354 /* Lenovo Virtual Background application */ 1355 { KE_KEY, 0x28 | IDEAPAD_WMI_KEY, { KEY_PROG3 } }, 1356 /* Lenovo Support */ 1357 { KE_KEY, 0x27 | IDEAPAD_WMI_KEY, { KEY_HELP } }, 1358 /* Refresh Rate Toggle */ 1359 { KE_KEY, 0x0a | IDEAPAD_WMI_KEY, { KEY_REFRESH_RATE_TOGGLE } }, 1360 /* Specific to some newer models */ 1361 { KE_KEY, 0x3e | IDEAPAD_WMI_KEY, { KEY_MICMUTE } }, 1362 { KE_KEY, 0x3f | IDEAPAD_WMI_KEY, { KEY_RFKILL } }, 1363 /* Star- (User Assignable Key) */ 1364 { KE_KEY, 0x44 | IDEAPAD_WMI_KEY, { KEY_PROG1 } }, 1365 /* Eye */ 1366 { KE_KEY, 0x45 | IDEAPAD_WMI_KEY, { KEY_PROG3 } }, 1367 /* Performance toggle also Fn+Q, handled inside ideapad_wmi_notify() */ 1368 { KE_KEY, 0x3d | IDEAPAD_WMI_KEY, { KEY_PROG4 } }, 1369 /* shift + prtsc */ 1370 { KE_KEY, 0x2d | IDEAPAD_WMI_KEY, { KEY_SELECTIVE_SCREENSHOT } }, 1371 { KE_KEY, 0x29 | IDEAPAD_WMI_KEY, { KEY_TOUCHPAD_TOGGLE } }, 1372 { KE_KEY, 0x2a | IDEAPAD_WMI_KEY, { KEY_ROOT_MENU } }, 1373 1374 { KE_END }, 1375}; 1376 1377static int ideapad_input_init(struct ideapad_private *priv) 1378{ 1379 struct input_dev *inputdev; 1380 int err; 1381 1382 inputdev = input_allocate_device(); 1383 if (!inputdev) 1384 return -ENOMEM; 1385 1386 inputdev->name = "Ideapad extra buttons"; 1387 inputdev->phys = "ideapad/input0"; 1388 inputdev->id.bustype = BUS_HOST; 1389 inputdev->dev.parent = &priv->platform_device->dev; 1390 1391 err = sparse_keymap_setup(inputdev, ideapad_keymap, NULL); 1392 if (err) { 1393 dev_err(&priv->platform_device->dev, 1394 "Could not set up input device keymap: %d\n", err); 1395 goto err_free_dev; 1396 } 1397 1398 err = input_register_device(inputdev); 1399 if (err) { 1400 dev_err(&priv->platform_device->dev, 1401 "Could not register input device: %d\n", err); 1402 goto err_free_dev; 1403 } 1404 1405 priv->inputdev = inputdev; 1406 1407 return 0; 1408 1409err_free_dev: 1410 input_free_device(inputdev); 1411 1412 return err; 1413} 1414 1415static void ideapad_input_exit(struct ideapad_private *priv) 1416{ 1417 input_unregister_device(priv->inputdev); 1418 priv->inputdev = NULL; 1419} 1420 1421static void ideapad_input_report(struct ideapad_private *priv, 1422 unsigned long scancode) 1423{ 1424 sparse_keymap_report_event(priv->inputdev, scancode, 1, true); 1425} 1426 1427static void ideapad_input_novokey(struct ideapad_private *priv) 1428{ 1429 unsigned long long_pressed; 1430 1431 scoped_guard(mutex, &priv->vpc_mutex) 1432 if (read_ec_data(priv->adev->handle, VPCCMD_R_NOVO, &long_pressed)) 1433 return; 1434 1435 if (long_pressed) 1436 ideapad_input_report(priv, 17); 1437 else 1438 ideapad_input_report(priv, 16); 1439} 1440 1441static void ideapad_check_special_buttons(struct ideapad_private *priv) 1442{ 1443 unsigned long bit, value; 1444 1445 scoped_guard(mutex, &priv->vpc_mutex) 1446 if (read_ec_data(priv->adev->handle, VPCCMD_R_SPECIAL_BUTTONS, &value)) 1447 return; 1448 1449 for_each_set_bit (bit, &value, 16) { 1450 switch (bit) { 1451 case 6: /* Z570 */ 1452 case 0: /* Z580 */ 1453 /* Thermal Management / Performance Mode button */ 1454 if (priv->dytc) 1455 platform_profile_cycle(); 1456 else 1457 ideapad_input_report(priv, 65); 1458 break; 1459 case 1: 1460 /* OneKey Theater button */ 1461 ideapad_input_report(priv, 64); 1462 break; 1463 default: 1464 dev_info(&priv->platform_device->dev, 1465 "Unknown special button: %lu\n", bit); 1466 break; 1467 } 1468 } 1469} 1470 1471/* 1472 * backlight 1473 */ 1474static int ideapad_backlight_get_brightness(struct backlight_device *blightdev) 1475{ 1476 struct ideapad_private *priv = bl_get_data(blightdev); 1477 unsigned long now; 1478 int err; 1479 1480 guard(mutex)(&priv->vpc_mutex); 1481 1482 err = read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now); 1483 if (err) 1484 return err; 1485 1486 return now; 1487} 1488 1489static int ideapad_backlight_update_status(struct backlight_device *blightdev) 1490{ 1491 struct ideapad_private *priv = bl_get_data(blightdev); 1492 int err; 1493 1494 guard(mutex)(&priv->vpc_mutex); 1495 1496 err = write_ec_cmd(priv->adev->handle, VPCCMD_W_BL, 1497 blightdev->props.brightness); 1498 if (err) 1499 return err; 1500 1501 err = write_ec_cmd(priv->adev->handle, VPCCMD_W_BL_POWER, 1502 blightdev->props.power != BACKLIGHT_POWER_OFF); 1503 if (err) 1504 return err; 1505 1506 return 0; 1507} 1508 1509static const struct backlight_ops ideapad_backlight_ops = { 1510 .get_brightness = ideapad_backlight_get_brightness, 1511 .update_status = ideapad_backlight_update_status, 1512}; 1513 1514static int ideapad_backlight_init(struct ideapad_private *priv) 1515{ 1516 struct backlight_device *blightdev; 1517 struct backlight_properties props; 1518 unsigned long max, now, power; 1519 int err; 1520 1521 err = read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &max); 1522 if (err) 1523 return err; 1524 1525 err = read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now); 1526 if (err) 1527 return err; 1528 1529 err = read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power); 1530 if (err) 1531 return err; 1532 1533 memset(&props, 0, sizeof(props)); 1534 1535 props.max_brightness = max; 1536 props.type = BACKLIGHT_PLATFORM; 1537 1538 blightdev = backlight_device_register("ideapad", 1539 &priv->platform_device->dev, 1540 priv, 1541 &ideapad_backlight_ops, 1542 &props); 1543 if (IS_ERR(blightdev)) { 1544 err = PTR_ERR(blightdev); 1545 dev_err(&priv->platform_device->dev, 1546 "Could not register backlight device: %d\n", err); 1547 return err; 1548 } 1549 1550 priv->blightdev = blightdev; 1551 blightdev->props.brightness = now; 1552 blightdev->props.power = power ? BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF; 1553 1554 backlight_update_status(blightdev); 1555 1556 return 0; 1557} 1558 1559static void ideapad_backlight_exit(struct ideapad_private *priv) 1560{ 1561 backlight_device_unregister(priv->blightdev); 1562 priv->blightdev = NULL; 1563} 1564 1565static void ideapad_backlight_notify_power(struct ideapad_private *priv) 1566{ 1567 struct backlight_device *blightdev = priv->blightdev; 1568 unsigned long power; 1569 1570 if (!blightdev) 1571 return; 1572 1573 guard(mutex)(&priv->vpc_mutex); 1574 1575 if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power)) 1576 return; 1577 1578 blightdev->props.power = power ? BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF; 1579} 1580 1581static void ideapad_backlight_notify_brightness(struct ideapad_private *priv) 1582{ 1583 unsigned long now; 1584 1585 /* if we control brightness via acpi video driver */ 1586 if (!priv->blightdev) 1587 scoped_guard(mutex, &priv->vpc_mutex) 1588 read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now); 1589 else 1590 backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY); 1591} 1592 1593/* 1594 * keyboard backlight 1595 */ 1596static int ideapad_kbd_bl_check_tristate(int type) 1597{ 1598 return (type == KBD_BL_TRISTATE) || (type == KBD_BL_TRISTATE_AUTO); 1599} 1600 1601static int ideapad_kbd_bl_brightness_get(struct ideapad_private *priv) 1602{ 1603 unsigned long value; 1604 int err; 1605 1606 if (ideapad_kbd_bl_check_tristate(priv->kbd_bl.type)) { 1607 err = eval_kblc(priv->adev->handle, 1608 FIELD_PREP(KBD_BL_COMMAND_TYPE, priv->kbd_bl.type) | 1609 KBD_BL_COMMAND_GET, 1610 &value); 1611 1612 if (err) 1613 return err; 1614 1615 /* Convert returned value to brightness level */ 1616 value = FIELD_GET(KBD_BL_GET_BRIGHTNESS, value); 1617 1618 /* Off, low or high */ 1619 if (value <= priv->kbd_bl.led.max_brightness) 1620 return value; 1621 1622 /* Auto, report as off */ 1623 if (value == priv->kbd_bl.led.max_brightness + 1) 1624 return 0; 1625 1626 /* Unknown value */ 1627 dev_warn(&priv->platform_device->dev, 1628 "Unknown keyboard backlight value: %lu", value); 1629 return -EINVAL; 1630 } 1631 1632 err = eval_hals(priv->adev->handle, &value); 1633 if (err) 1634 return err; 1635 1636 return !!test_bit(HALS_KBD_BL_STATE_BIT, &value); 1637} 1638 1639static enum led_brightness ideapad_kbd_bl_led_cdev_brightness_get(struct led_classdev *led_cdev) 1640{ 1641 struct ideapad_private *priv = container_of(led_cdev, struct ideapad_private, kbd_bl.led); 1642 1643 return ideapad_kbd_bl_brightness_get(priv); 1644} 1645 1646static int ideapad_kbd_bl_brightness_set(struct ideapad_private *priv, unsigned int brightness) 1647{ 1648 int err; 1649 unsigned long value; 1650 int type = priv->kbd_bl.type; 1651 1652 if (ideapad_kbd_bl_check_tristate(type)) { 1653 if (brightness > priv->kbd_bl.led.max_brightness) 1654 return -EINVAL; 1655 1656 value = FIELD_PREP(KBD_BL_SET_BRIGHTNESS, brightness) | 1657 FIELD_PREP(KBD_BL_COMMAND_TYPE, type) | 1658 KBD_BL_COMMAND_SET; 1659 err = exec_kblc(priv->adev->handle, value); 1660 } else { 1661 err = exec_sals(priv->adev->handle, brightness ? SALS_KBD_BL_ON : SALS_KBD_BL_OFF); 1662 } 1663 1664 if (err) 1665 return err; 1666 1667 priv->kbd_bl.last_brightness = brightness; 1668 1669 return 0; 1670} 1671 1672static int ideapad_kbd_bl_led_cdev_brightness_set(struct led_classdev *led_cdev, 1673 enum led_brightness brightness) 1674{ 1675 struct ideapad_private *priv = container_of(led_cdev, struct ideapad_private, kbd_bl.led); 1676 1677 return ideapad_kbd_bl_brightness_set(priv, brightness); 1678} 1679 1680static void ideapad_kbd_bl_notify(struct ideapad_private *priv) 1681{ 1682 int brightness; 1683 1684 if (!priv->kbd_bl.initialized) 1685 return; 1686 1687 brightness = ideapad_kbd_bl_brightness_get(priv); 1688 if (brightness < 0) 1689 return; 1690 1691 if (brightness == priv->kbd_bl.last_brightness) 1692 return; 1693 1694 priv->kbd_bl.last_brightness = brightness; 1695 1696 led_classdev_notify_brightness_hw_changed(&priv->kbd_bl.led, brightness); 1697} 1698 1699static int ideapad_kbd_bl_init(struct ideapad_private *priv) 1700{ 1701 int brightness, err; 1702 1703 if (!priv->features.kbd_bl) 1704 return -ENODEV; 1705 1706 if (WARN_ON(priv->kbd_bl.initialized)) 1707 return -EEXIST; 1708 1709 if (ideapad_kbd_bl_check_tristate(priv->kbd_bl.type)) { 1710 priv->kbd_bl.led.max_brightness = 2; 1711 } else { 1712 priv->kbd_bl.led.max_brightness = 1; 1713 } 1714 1715 brightness = ideapad_kbd_bl_brightness_get(priv); 1716 if (brightness < 0) 1717 return brightness; 1718 1719 priv->kbd_bl.last_brightness = brightness; 1720 priv->kbd_bl.led.name = "platform::" LED_FUNCTION_KBD_BACKLIGHT; 1721 priv->kbd_bl.led.brightness_get = ideapad_kbd_bl_led_cdev_brightness_get; 1722 priv->kbd_bl.led.brightness_set_blocking = ideapad_kbd_bl_led_cdev_brightness_set; 1723 priv->kbd_bl.led.flags = LED_BRIGHT_HW_CHANGED | LED_RETAIN_AT_SHUTDOWN; 1724 1725 err = led_classdev_register(&priv->platform_device->dev, &priv->kbd_bl.led); 1726 if (err) 1727 return err; 1728 1729 priv->kbd_bl.initialized = true; 1730 1731 return 0; 1732} 1733 1734static void ideapad_kbd_bl_exit(struct ideapad_private *priv) 1735{ 1736 if (!priv->kbd_bl.initialized) 1737 return; 1738 1739 priv->kbd_bl.initialized = false; 1740 1741 led_classdev_unregister(&priv->kbd_bl.led); 1742} 1743 1744/* 1745 * FnLock LED 1746 */ 1747static enum led_brightness ideapad_fn_lock_led_cdev_get(struct led_classdev *led_cdev) 1748{ 1749 struct ideapad_private *priv = container_of(led_cdev, struct ideapad_private, fn_lock.led); 1750 1751 return ideapad_fn_lock_get(priv); 1752} 1753 1754static int ideapad_fn_lock_led_cdev_set(struct led_classdev *led_cdev, 1755 enum led_brightness brightness) 1756{ 1757 struct ideapad_private *priv = container_of(led_cdev, struct ideapad_private, fn_lock.led); 1758 1759 return ideapad_fn_lock_set(priv, brightness); 1760} 1761 1762static int ideapad_fn_lock_led_init(struct ideapad_private *priv) 1763{ 1764 int brightness, err; 1765 1766 if (!priv->features.fn_lock) 1767 return -ENODEV; 1768 1769 if (WARN_ON(priv->fn_lock.initialized)) 1770 return -EEXIST; 1771 1772 priv->fn_lock.led.max_brightness = 1; 1773 1774 brightness = ideapad_fn_lock_get(priv); 1775 if (brightness < 0) 1776 return brightness; 1777 1778 priv->fn_lock.last_brightness = brightness; 1779 priv->fn_lock.led.name = "platform::" LED_FUNCTION_FNLOCK; 1780 priv->fn_lock.led.brightness_get = ideapad_fn_lock_led_cdev_get; 1781 priv->fn_lock.led.brightness_set_blocking = ideapad_fn_lock_led_cdev_set; 1782 priv->fn_lock.led.flags = LED_BRIGHT_HW_CHANGED | LED_RETAIN_AT_SHUTDOWN; 1783 1784 err = led_classdev_register(&priv->platform_device->dev, &priv->fn_lock.led); 1785 if (err) 1786 return err; 1787 1788 priv->fn_lock.initialized = true; 1789 1790 return 0; 1791} 1792 1793static void ideapad_fn_lock_led_exit(struct ideapad_private *priv) 1794{ 1795 if (!priv->fn_lock.initialized) 1796 return; 1797 1798 priv->fn_lock.initialized = false; 1799 1800 led_classdev_unregister(&priv->fn_lock.led); 1801} 1802 1803/* 1804 * module init/exit 1805 */ 1806static void ideapad_sync_touchpad_state(struct ideapad_private *priv, bool send_events) 1807{ 1808 unsigned long value; 1809 unsigned char param; 1810 int ret; 1811 1812 /* Without reading from EC touchpad LED doesn't switch state */ 1813 scoped_guard(mutex, &priv->vpc_mutex) 1814 ret = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value); 1815 if (ret) 1816 return; 1817 1818 /* 1819 * Some IdeaPads don't really turn off touchpad - they only 1820 * switch the LED state. We (de)activate KBC AUX port to turn 1821 * touchpad off and on. We send KEY_TOUCHPAD_OFF and 1822 * KEY_TOUCHPAD_ON to not to get out of sync with LED 1823 */ 1824 if (priv->features.ctrl_ps2_aux_port) 1825 i8042_command(¶m, value ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE); 1826 1827 /* 1828 * On older models the EC controls the touchpad and toggles it on/off 1829 * itself, in this case we report KEY_TOUCHPAD_ON/_OFF. Some models do 1830 * an acpi-notify with VPC bit 5 set on resume, so this function get 1831 * called with send_events=true on every resume. Therefor if the EC did 1832 * not toggle, do nothing to avoid sending spurious KEY_TOUCHPAD_TOGGLE. 1833 */ 1834 if (send_events && value != priv->r_touchpad_val) { 1835 ideapad_input_report(priv, value ? 67 : 66); 1836 sysfs_notify(&priv->platform_device->dev.kobj, NULL, "touchpad"); 1837 } 1838 1839 priv->r_touchpad_val = value; 1840} 1841 1842static const struct dmi_system_id ymc_ec_trigger_quirk_dmi_table[] = { 1843 { 1844 /* Lenovo Yoga 7 14ARB7 */ 1845 .matches = { 1846 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 1847 DMI_MATCH(DMI_PRODUCT_NAME, "82QF"), 1848 }, 1849 }, 1850 { 1851 /* Lenovo Yoga 7 14ACN6 */ 1852 .matches = { 1853 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 1854 DMI_MATCH(DMI_PRODUCT_NAME, "82N7"), 1855 }, 1856 }, 1857 { } 1858}; 1859 1860static void ideapad_laptop_trigger_ec(void) 1861{ 1862 struct ideapad_private *priv; 1863 int ret; 1864 1865 guard(mutex)(&ideapad_shared_mutex); 1866 1867 priv = ideapad_shared; 1868 if (!priv) 1869 return; 1870 1871 if (!priv->features.ymc_ec_trigger) 1872 return; 1873 1874 scoped_guard(mutex, &priv->vpc_mutex) 1875 ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_YMC, 1); 1876 if (ret) 1877 dev_warn(&priv->platform_device->dev, "Could not write YMC: %d\n", ret); 1878} 1879 1880static int ideapad_laptop_nb_notify(struct notifier_block *nb, 1881 unsigned long action, void *data) 1882{ 1883 switch (action) { 1884 case IDEAPAD_LAPTOP_YMC_EVENT: 1885 ideapad_laptop_trigger_ec(); 1886 break; 1887 } 1888 1889 return 0; 1890} 1891 1892static struct notifier_block ideapad_laptop_notifier = { 1893 .notifier_call = ideapad_laptop_nb_notify, 1894}; 1895 1896static BLOCKING_NOTIFIER_HEAD(ideapad_laptop_chain_head); 1897 1898int ideapad_laptop_register_notifier(struct notifier_block *nb) 1899{ 1900 return blocking_notifier_chain_register(&ideapad_laptop_chain_head, nb); 1901} 1902EXPORT_SYMBOL_NS_GPL(ideapad_laptop_register_notifier, "IDEAPAD_LAPTOP"); 1903 1904int ideapad_laptop_unregister_notifier(struct notifier_block *nb) 1905{ 1906 return blocking_notifier_chain_unregister(&ideapad_laptop_chain_head, nb); 1907} 1908EXPORT_SYMBOL_NS_GPL(ideapad_laptop_unregister_notifier, "IDEAPAD_LAPTOP"); 1909 1910void ideapad_laptop_call_notifier(unsigned long action, void *data) 1911{ 1912 blocking_notifier_call_chain(&ideapad_laptop_chain_head, action, data); 1913} 1914EXPORT_SYMBOL_NS_GPL(ideapad_laptop_call_notifier, "IDEAPAD_LAPTOP"); 1915 1916static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data) 1917{ 1918 struct ideapad_private *priv = data; 1919 unsigned long vpc1, vpc2, bit; 1920 1921 scoped_guard(mutex, &priv->vpc_mutex) { 1922 if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1)) 1923 return; 1924 1925 if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2)) 1926 return; 1927 } 1928 1929 vpc1 = (vpc2 << 8) | vpc1; 1930 1931 for_each_set_bit (bit, &vpc1, 16) { 1932 switch (bit) { 1933 case 13: 1934 case 11: 1935 case 8: 1936 case 7: 1937 case 6: 1938 ideapad_input_report(priv, bit); 1939 break; 1940 case 10: 1941 /* 1942 * This event gets send on a Yoga 300-11IBR when the EC 1943 * believes that the device has changed between laptop/ 1944 * tent/stand/tablet mode. The EC relies on getting 1945 * angle info from 2 accelerometers through a special 1946 * windows service calling a DSM on the DUAL250E ACPI- 1947 * device. Linux does not do this, making the laptop/ 1948 * tent/stand/tablet mode info unreliable, so we simply 1949 * ignore these events. 1950 */ 1951 break; 1952 case 9: 1953 ideapad_sync_rfk_state(priv); 1954 break; 1955 case 5: 1956 ideapad_sync_touchpad_state(priv, true); 1957 break; 1958 case 4: 1959 ideapad_backlight_notify_brightness(priv); 1960 break; 1961 case 3: 1962 ideapad_input_novokey(priv); 1963 break; 1964 case 2: 1965 ideapad_backlight_notify_power(priv); 1966 break; 1967 case KBD_BL_KBLC_CHANGED_EVENT: 1968 case 1: 1969 /* 1970 * Some IdeaPads report event 1 every ~20 1971 * seconds while on battery power; some 1972 * report this when changing to/from tablet 1973 * mode; some report this when the keyboard 1974 * backlight has changed. 1975 */ 1976 ideapad_kbd_bl_notify(priv); 1977 break; 1978 case 0: 1979 ideapad_check_special_buttons(priv); 1980 break; 1981 default: 1982 dev_info(&priv->platform_device->dev, 1983 "Unknown event: %lu\n", bit); 1984 } 1985 } 1986} 1987 1988/* On some models we need to call exec_sals(SALS_FNLOCK_ON/OFF) to set the LED */ 1989static const struct dmi_system_id set_fn_lock_led_list[] = { 1990 { 1991 /* https://bugzilla.kernel.org/show_bug.cgi?id=212671 */ 1992 .matches = { 1993 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 1994 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion R7000P2020H"), 1995 } 1996 }, 1997 { 1998 .matches = { 1999 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 2000 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion 5 15ARH05"), 2001 } 2002 }, 2003 {} 2004}; 2005 2006/* 2007 * Some ideapads have a hardware rfkill switch, but most do not have one. 2008 * Reading VPCCMD_R_RF always results in 0 on models without a hardware rfkill, 2009 * switch causing ideapad_laptop to wrongly report all radios as hw-blocked. 2010 * There used to be a long list of DMI ids for models without a hw rfkill 2011 * switch here, but that resulted in playing whack a mole. 2012 * More importantly wrongly reporting the wifi radio as hw-blocked, results in 2013 * non working wifi. Whereas not reporting it hw-blocked, when it actually is 2014 * hw-blocked results in an empty SSID list, which is a much more benign 2015 * failure mode. 2016 * So the default now is the much safer option of assuming there is no 2017 * hardware rfkill switch. This default also actually matches most hardware, 2018 * since having a hw rfkill switch is quite rare on modern hardware, so this 2019 * also leads to a much shorter list. 2020 */ 2021static const struct dmi_system_id hw_rfkill_list[] = { 2022 {} 2023}; 2024 2025/* 2026 * On some models the EC toggles the touchpad muted LED on touchpad toggle 2027 * hotkey presses, but the EC does not actually disable the touchpad itself. 2028 * On these models the driver needs to explicitly enable/disable the i8042 2029 * (PS/2) aux port. 2030 */ 2031static const struct dmi_system_id ctrl_ps2_aux_port_list[] = { 2032 { 2033 /* Lenovo Ideapad Z570 */ 2034 .matches = { 2035 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 2036 DMI_MATCH(DMI_PRODUCT_VERSION, "Ideapad Z570"), 2037 }, 2038 }, 2039 {} 2040}; 2041 2042static int ideapad_psy_ext_set_prop(struct power_supply *psy, 2043 const struct power_supply_ext *ext, 2044 void *ext_data, 2045 enum power_supply_property psp, 2046 const union power_supply_propval *val) 2047{ 2048 struct ideapad_private *priv = ext_data; 2049 unsigned long op1, op2; 2050 int err; 2051 2052 switch (val->intval) { 2053 case POWER_SUPPLY_CHARGE_TYPE_FAST: 2054 if (WARN_ON(!priv->features.rapid_charge)) 2055 return -EINVAL; 2056 2057 op1 = SBMC_CONSERVATION_OFF; 2058 op2 = SBMC_RAPID_CHARGE_ON; 2059 break; 2060 case POWER_SUPPLY_CHARGE_TYPE_LONGLIFE: 2061 op1 = SBMC_RAPID_CHARGE_OFF; 2062 op2 = SBMC_CONSERVATION_ON; 2063 break; 2064 case POWER_SUPPLY_CHARGE_TYPE_STANDARD: 2065 op1 = SBMC_RAPID_CHARGE_OFF; 2066 op2 = SBMC_CONSERVATION_OFF; 2067 break; 2068 default: 2069 return -EINVAL; 2070 } 2071 2072 guard(mutex)(&priv->gbmd_sbmc_mutex); 2073 2074 /* If !rapid_charge, op1 must be SBMC_RAPID_CHARGE_OFF. Skip it. */ 2075 if (priv->features.rapid_charge) { 2076 err = exec_sbmc(priv->adev->handle, op1); 2077 if (err) 2078 return err; 2079 } 2080 2081 return exec_sbmc(priv->adev->handle, op2); 2082} 2083 2084static int ideapad_psy_ext_get_prop(struct power_supply *psy, 2085 const struct power_supply_ext *ext, 2086 void *ext_data, 2087 enum power_supply_property psp, 2088 union power_supply_propval *val) 2089{ 2090 struct ideapad_private *priv = ext_data; 2091 bool is_rapid_charge, is_conservation; 2092 unsigned long result; 2093 int err; 2094 2095 scoped_guard(mutex, &priv->gbmd_sbmc_mutex) { 2096 err = eval_gbmd(priv->adev->handle, &result); 2097 if (err) 2098 return err; 2099 } 2100 2101 is_rapid_charge = (priv->features.rapid_charge && 2102 test_bit(GBMD_RAPID_CHARGE_STATE_BIT, &result)); 2103 is_conservation = test_bit(GBMD_CONSERVATION_STATE_BIT, &result); 2104 2105 if (unlikely(is_rapid_charge && is_conservation)) { 2106 dev_err(&priv->platform_device->dev, 2107 "unexpected charge_types: both [Fast] and [Long_Life] are enabled\n"); 2108 return -EINVAL; 2109 } 2110 2111 if (is_rapid_charge) 2112 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; 2113 else if (is_conservation) 2114 val->intval = POWER_SUPPLY_CHARGE_TYPE_LONGLIFE; 2115 else 2116 val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD; 2117 2118 return 0; 2119} 2120 2121static int ideapad_psy_prop_is_writeable(struct power_supply *psy, 2122 const struct power_supply_ext *ext, 2123 void *data, 2124 enum power_supply_property psp) 2125{ 2126 return true; 2127} 2128 2129static const enum power_supply_property ideapad_power_supply_props[] = { 2130 POWER_SUPPLY_PROP_CHARGE_TYPES, 2131}; 2132 2133#define DEFINE_IDEAPAD_POWER_SUPPLY_EXTENSION(_name, _charge_types) \ 2134 static const struct power_supply_ext _name = { \ 2135 .name = "ideapad_laptop", \ 2136 .properties = ideapad_power_supply_props, \ 2137 .num_properties = ARRAY_SIZE(ideapad_power_supply_props), \ 2138 .charge_types = _charge_types, \ 2139 .get_property = ideapad_psy_ext_get_prop, \ 2140 .set_property = ideapad_psy_ext_set_prop, \ 2141 .property_is_writeable = ideapad_psy_prop_is_writeable, \ 2142 } 2143 2144DEFINE_IDEAPAD_POWER_SUPPLY_EXTENSION(ideapad_battery_ext_v1, 2145 (BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) | 2146 BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE)) 2147); 2148 2149DEFINE_IDEAPAD_POWER_SUPPLY_EXTENSION(ideapad_battery_ext_v2, 2150 (BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) | 2151 BIT(POWER_SUPPLY_CHARGE_TYPE_FAST) | 2152 BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE)) 2153); 2154 2155static int ideapad_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) 2156{ 2157 struct ideapad_private *priv = container_of(hook, struct ideapad_private, battery_hook); 2158 2159 return power_supply_register_extension(battery, priv->battery_ext, 2160 &priv->platform_device->dev, priv); 2161} 2162 2163static int ideapad_battery_remove(struct power_supply *battery, 2164 struct acpi_battery_hook *hook) 2165{ 2166 struct ideapad_private *priv = container_of(hook, struct ideapad_private, battery_hook); 2167 2168 power_supply_unregister_extension(battery, priv->battery_ext); 2169 2170 return 0; 2171} 2172 2173static int ideapad_check_features(struct ideapad_private *priv) 2174{ 2175 acpi_handle handle = priv->adev->handle; 2176 unsigned long val; 2177 int err; 2178 2179 priv->features.set_fn_lock_led = 2180 set_fn_lock_led || dmi_check_system(set_fn_lock_led_list); 2181 priv->features.hw_rfkill_switch = 2182 hw_rfkill_switch || dmi_check_system(hw_rfkill_list); 2183 priv->features.ctrl_ps2_aux_port = 2184 ctrl_ps2_aux_port || dmi_check_system(ctrl_ps2_aux_port_list); 2185 priv->features.touchpad_ctrl_via_ec = touchpad_ctrl_via_ec; 2186 priv->features.ymc_ec_trigger = 2187 ymc_ec_trigger || dmi_check_system(ymc_ec_trigger_quirk_dmi_table); 2188 2189 if (!read_ec_data(handle, VPCCMD_R_FAN, &val)) 2190 priv->features.fan_mode = true; 2191 2192 if (acpi_has_method(handle, "GBMD") && acpi_has_method(handle, "SBMC")) { 2193 /* Not acquiring gbmd_sbmc_mutex as race condition is impossible on init */ 2194 if (!eval_gbmd(handle, &val)) { 2195 priv->features.conservation_mode = true; 2196 priv->features.rapid_charge = test_bit(GBMD_RAPID_CHARGE_SUPPORTED_BIT, 2197 &val); 2198 2199 priv->battery_ext = priv->features.rapid_charge 2200 ? &ideapad_battery_ext_v2 2201 : &ideapad_battery_ext_v1; 2202 2203 priv->battery_hook.add_battery = ideapad_battery_add; 2204 priv->battery_hook.remove_battery = ideapad_battery_remove; 2205 priv->battery_hook.name = "Ideapad Battery Extension"; 2206 2207 err = devm_battery_hook_register(&priv->platform_device->dev, 2208 &priv->battery_hook); 2209 if (err) 2210 return err; 2211 } 2212 } 2213 2214 if (acpi_has_method(handle, "DYTC")) 2215 priv->features.dytc = true; 2216 2217 if (acpi_has_method(handle, "HALS") && acpi_has_method(handle, "SALS")) { 2218 if (!eval_hals(handle, &val)) { 2219 if (test_bit(HALS_FNLOCK_SUPPORT_BIT, &val)) 2220 priv->features.fn_lock = true; 2221 2222 if (test_bit(HALS_KBD_BL_SUPPORT_BIT, &val)) { 2223 priv->features.kbd_bl = true; 2224 priv->kbd_bl.type = KBD_BL_STANDARD; 2225 } 2226 2227 if (test_bit(HALS_USB_CHARGING_SUPPORT_BIT, &val)) 2228 priv->features.usb_charging = true; 2229 } 2230 } 2231 2232 if (acpi_has_method(handle, "KBLC")) { 2233 if (!eval_kblc(priv->adev->handle, KBD_BL_QUERY_TYPE, &val)) { 2234 if (val == KBD_BL_TRISTATE_TYPE) { 2235 priv->features.kbd_bl = true; 2236 priv->kbd_bl.type = KBD_BL_TRISTATE; 2237 } else if (val == KBD_BL_TRISTATE_AUTO_TYPE) { 2238 priv->features.kbd_bl = true; 2239 priv->kbd_bl.type = KBD_BL_TRISTATE_AUTO; 2240 } else { 2241 dev_warn(&priv->platform_device->dev, 2242 "Unknown keyboard type: %lu", 2243 val); 2244 } 2245 } 2246 } 2247 2248 return 0; 2249} 2250 2251#if IS_ENABLED(CONFIG_ACPI_WMI) 2252/* 2253 * WMI driver 2254 */ 2255enum ideapad_wmi_event_type { 2256 IDEAPAD_WMI_EVENT_ESC, 2257 IDEAPAD_WMI_EVENT_FN_KEYS, 2258}; 2259 2260struct ideapad_wmi_private { 2261 enum ideapad_wmi_event_type event; 2262}; 2263 2264static int ideapad_wmi_probe(struct wmi_device *wdev, const void *context) 2265{ 2266 struct ideapad_wmi_private *wpriv; 2267 2268 wpriv = devm_kzalloc(&wdev->dev, sizeof(*wpriv), GFP_KERNEL); 2269 if (!wpriv) 2270 return -ENOMEM; 2271 2272 *wpriv = *(const struct ideapad_wmi_private *)context; 2273 2274 dev_set_drvdata(&wdev->dev, wpriv); 2275 return 0; 2276} 2277 2278static void ideapad_wmi_notify(struct wmi_device *wdev, union acpi_object *data) 2279{ 2280 struct ideapad_wmi_private *wpriv = dev_get_drvdata(&wdev->dev); 2281 struct ideapad_private *priv; 2282 2283 guard(mutex)(&ideapad_shared_mutex); 2284 2285 priv = ideapad_shared; 2286 if (!priv) 2287 return; 2288 2289 switch (wpriv->event) { 2290 case IDEAPAD_WMI_EVENT_ESC: 2291 ideapad_input_report(priv, 128); 2292 break; 2293 case IDEAPAD_WMI_EVENT_FN_KEYS: 2294 if (priv->features.set_fn_lock_led) { 2295 int brightness = ideapad_fn_lock_get(priv); 2296 2297 if (brightness >= 0) { 2298 ideapad_fn_lock_set(priv, brightness); 2299 ideapad_fn_lock_led_notify(priv, brightness); 2300 } 2301 } 2302 2303 if (data->type != ACPI_TYPE_INTEGER) { 2304 dev_warn(&wdev->dev, 2305 "WMI event data is not an integer\n"); 2306 break; 2307 } 2308 2309 dev_dbg(&wdev->dev, "WMI fn-key event: 0x%llx\n", 2310 data->integer.value); 2311 2312 /* performance button triggered by 0x3d */ 2313 if (data->integer.value == 0x3d && priv->dytc) { 2314 platform_profile_cycle(); 2315 break; 2316 } 2317 2318 /* 0x02 FnLock, 0x03 Esc */ 2319 if (data->integer.value == 0x02 || data->integer.value == 0x03) 2320 ideapad_fn_lock_led_notify(priv, data->integer.value == 0x02); 2321 2322 ideapad_input_report(priv, 2323 data->integer.value | IDEAPAD_WMI_KEY); 2324 2325 break; 2326 } 2327} 2328 2329static const struct ideapad_wmi_private ideapad_wmi_context_esc = { 2330 .event = IDEAPAD_WMI_EVENT_ESC 2331}; 2332 2333static const struct ideapad_wmi_private ideapad_wmi_context_fn_keys = { 2334 .event = IDEAPAD_WMI_EVENT_FN_KEYS 2335}; 2336 2337static const struct wmi_device_id ideapad_wmi_ids[] = { 2338 { "26CAB2E5-5CF1-46AE-AAC3-4A12B6BA50E6", &ideapad_wmi_context_esc }, /* Yoga 3 */ 2339 { "56322276-8493-4CE8-A783-98C991274F5E", &ideapad_wmi_context_esc }, /* Yoga 700 */ 2340 { "8FC0DE0C-B4E4-43FD-B0F3-8871711C1294", &ideapad_wmi_context_fn_keys }, /* Legion 5 */ 2341 {}, 2342}; 2343MODULE_DEVICE_TABLE(wmi, ideapad_wmi_ids); 2344 2345static struct wmi_driver ideapad_wmi_driver = { 2346 .driver = { 2347 .name = "ideapad_wmi", 2348 }, 2349 .id_table = ideapad_wmi_ids, 2350 .probe = ideapad_wmi_probe, 2351 .notify = ideapad_wmi_notify, 2352}; 2353 2354static int ideapad_wmi_driver_register(void) 2355{ 2356 return wmi_driver_register(&ideapad_wmi_driver); 2357} 2358 2359static void ideapad_wmi_driver_unregister(void) 2360{ 2361 return wmi_driver_unregister(&ideapad_wmi_driver); 2362} 2363 2364#else 2365static inline int ideapad_wmi_driver_register(void) { return 0; } 2366static inline void ideapad_wmi_driver_unregister(void) { } 2367#endif 2368 2369/* 2370 * ACPI driver 2371 */ 2372static int ideapad_acpi_add(struct platform_device *pdev) 2373{ 2374 struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); 2375 struct ideapad_private *priv; 2376 acpi_status status; 2377 unsigned long cfg; 2378 int err, i; 2379 2380 if (!adev || eval_int(adev->handle, "_CFG", &cfg)) 2381 return -ENODEV; 2382 2383 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 2384 if (!priv) 2385 return -ENOMEM; 2386 2387 dev_set_drvdata(&pdev->dev, priv); 2388 2389 priv->cfg = cfg; 2390 priv->adev = adev; 2391 priv->platform_device = pdev; 2392 2393 err = devm_mutex_init(&pdev->dev, &priv->vpc_mutex); 2394 if (err) 2395 return err; 2396 2397 err = devm_mutex_init(&pdev->dev, &priv->gbmd_sbmc_mutex); 2398 if (err) 2399 return err; 2400 2401 err = ideapad_check_features(priv); 2402 if (err) 2403 return err; 2404 2405 ideapad_debugfs_init(priv); 2406 2407 err = ideapad_input_init(priv); 2408 if (err) 2409 goto input_failed; 2410 2411 err = ideapad_kbd_bl_init(priv); 2412 if (err) { 2413 if (err != -ENODEV) 2414 dev_warn(&pdev->dev, "Could not set up keyboard backlight LED: %d\n", err); 2415 else 2416 dev_info(&pdev->dev, "Keyboard backlight control not available\n"); 2417 } 2418 2419 err = ideapad_fn_lock_led_init(priv); 2420 if (err) { 2421 if (err != -ENODEV) 2422 dev_warn(&pdev->dev, "Could not set up FnLock LED: %d\n", err); 2423 else 2424 dev_info(&pdev->dev, "FnLock control not available\n"); 2425 } 2426 2427 /* 2428 * On some models without a hw-switch (the yoga 2 13 at least) 2429 * VPCCMD_W_RF must be explicitly set to 1 for the wifi to work. 2430 */ 2431 if (!priv->features.hw_rfkill_switch) 2432 write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1); 2433 2434 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) 2435 if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg)) 2436 ideapad_register_rfkill(priv, i); 2437 2438 ideapad_sync_rfk_state(priv); 2439 ideapad_sync_touchpad_state(priv, false); 2440 2441 err = ideapad_dytc_profile_init(priv); 2442 if (err) { 2443 if (err != -ENODEV) 2444 dev_warn(&pdev->dev, "Could not set up DYTC interface: %d\n", err); 2445 else 2446 dev_info(&pdev->dev, "DYTC interface is not available\n"); 2447 } 2448 2449 if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { 2450 err = ideapad_backlight_init(priv); 2451 if (err && err != -ENODEV) 2452 goto backlight_failed; 2453 } 2454 2455 status = acpi_install_notify_handler(adev->handle, 2456 ACPI_DEVICE_NOTIFY, 2457 ideapad_acpi_notify, priv); 2458 if (ACPI_FAILURE(status)) { 2459 err = -EIO; 2460 goto notification_failed; 2461 } 2462 2463 err = ideapad_shared_init(priv); 2464 if (err) 2465 goto shared_init_failed; 2466 2467 ideapad_laptop_register_notifier(&ideapad_laptop_notifier); 2468 2469 return 0; 2470 2471shared_init_failed: 2472 acpi_remove_notify_handler(priv->adev->handle, 2473 ACPI_DEVICE_NOTIFY, 2474 ideapad_acpi_notify); 2475 2476notification_failed: 2477 ideapad_backlight_exit(priv); 2478 2479backlight_failed: 2480 ideapad_dytc_profile_exit(priv); 2481 2482 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) 2483 ideapad_unregister_rfkill(priv, i); 2484 2485 ideapad_fn_lock_led_exit(priv); 2486 ideapad_kbd_bl_exit(priv); 2487 ideapad_input_exit(priv); 2488 2489input_failed: 2490 ideapad_debugfs_exit(priv); 2491 2492 return err; 2493} 2494 2495static void ideapad_acpi_remove(struct platform_device *pdev) 2496{ 2497 struct ideapad_private *priv = dev_get_drvdata(&pdev->dev); 2498 int i; 2499 2500 ideapad_laptop_unregister_notifier(&ideapad_laptop_notifier); 2501 2502 ideapad_shared_exit(priv); 2503 2504 acpi_remove_notify_handler(priv->adev->handle, 2505 ACPI_DEVICE_NOTIFY, 2506 ideapad_acpi_notify); 2507 2508 ideapad_backlight_exit(priv); 2509 ideapad_dytc_profile_exit(priv); 2510 2511 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) 2512 ideapad_unregister_rfkill(priv, i); 2513 2514 ideapad_fn_lock_led_exit(priv); 2515 ideapad_kbd_bl_exit(priv); 2516 ideapad_input_exit(priv); 2517 ideapad_debugfs_exit(priv); 2518} 2519 2520#ifdef CONFIG_PM_SLEEP 2521static int ideapad_acpi_resume(struct device *dev) 2522{ 2523 struct ideapad_private *priv = dev_get_drvdata(dev); 2524 2525 ideapad_sync_rfk_state(priv); 2526 ideapad_sync_touchpad_state(priv, false); 2527 2528 if (priv->dytc) 2529 dytc_profile_refresh(priv); 2530 2531 return 0; 2532} 2533#endif 2534static SIMPLE_DEV_PM_OPS(ideapad_pm, NULL, ideapad_acpi_resume); 2535 2536static const struct acpi_device_id ideapad_device_ids[] = { 2537 {"VPC2004", 0}, 2538 {"", 0}, 2539}; 2540MODULE_DEVICE_TABLE(acpi, ideapad_device_ids); 2541 2542static struct platform_driver ideapad_acpi_driver = { 2543 .probe = ideapad_acpi_add, 2544 .remove = ideapad_acpi_remove, 2545 .driver = { 2546 .name = "ideapad_acpi", 2547 .pm = &ideapad_pm, 2548 .acpi_match_table = ACPI_PTR(ideapad_device_ids), 2549 .dev_groups = ideapad_attribute_groups, 2550 }, 2551}; 2552 2553static int __init ideapad_laptop_init(void) 2554{ 2555 int err; 2556 2557 err = ideapad_wmi_driver_register(); 2558 if (err) 2559 return err; 2560 2561 err = platform_driver_register(&ideapad_acpi_driver); 2562 if (err) { 2563 ideapad_wmi_driver_unregister(); 2564 return err; 2565 } 2566 2567 return 0; 2568} 2569module_init(ideapad_laptop_init) 2570 2571static void __exit ideapad_laptop_exit(void) 2572{ 2573 ideapad_wmi_driver_unregister(); 2574 platform_driver_unregister(&ideapad_acpi_driver); 2575} 2576module_exit(ideapad_laptop_exit) 2577 2578MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 2579MODULE_DESCRIPTION("IdeaPad ACPI Extras"); 2580MODULE_LICENSE("GPL");
~/
Read-only file preview.