ideapad-laptop.c (0b9112a58836ad6a7e84eebec06a2de9778b7573) | ideapad-laptop.c (eabe533904cbcb6c7df530fd807cf2a3c3567d35) |
---|---|
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/kernel.h> 12#include <linux/module.h> 13#include <linux/init.h> 14#include <linux/types.h> 15#include <linux/acpi.h> 16#include <linux/rfkill.h> 17#include <linux/platform_device.h> | 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/kernel.h> 12#include <linux/module.h> 13#include <linux/init.h> 14#include <linux/types.h> 15#include <linux/acpi.h> 16#include <linux/rfkill.h> 17#include <linux/platform_device.h> |
18#include <linux/platform_profile.h> |
|
18#include <linux/input.h> 19#include <linux/input/sparse-keymap.h> 20#include <linux/backlight.h> 21#include <linux/fb.h> 22#include <linux/debugfs.h> 23#include <linux/seq_file.h> 24#include <linux/i8042.h> 25#include <linux/dmi.h> --- 46 unchanged lines hidden (view full) --- 72 VPCCMD_W_FAN, 73 VPCCMD_R_RF, 74 VPCCMD_W_RF, 75 VPCCMD_R_FAN = 0x2B, 76 VPCCMD_R_SPECIAL_BUTTONS = 0x31, 77 VPCCMD_W_BL_POWER = 0x33, 78}; 79 | 19#include <linux/input.h> 20#include <linux/input/sparse-keymap.h> 21#include <linux/backlight.h> 22#include <linux/fb.h> 23#include <linux/debugfs.h> 24#include <linux/seq_file.h> 25#include <linux/i8042.h> 26#include <linux/dmi.h> --- 46 unchanged lines hidden (view full) --- 73 VPCCMD_W_FAN, 74 VPCCMD_R_RF, 75 VPCCMD_W_RF, 76 VPCCMD_R_FAN = 0x2B, 77 VPCCMD_R_SPECIAL_BUTTONS = 0x31, 78 VPCCMD_W_BL_POWER = 0x33, 79}; 80 |
81struct ideapad_dytc_priv { 82 enum platform_profile_option current_profile; 83 struct platform_profile_handler pprof; 84 struct mutex mutex; 85 struct ideapad_private *priv; 86}; 87 |
|
80struct ideapad_rfk_priv { 81 int dev; 82 struct ideapad_private *priv; 83}; 84 85struct ideapad_private { 86 struct acpi_device *adev; 87 struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM]; 88 struct ideapad_rfk_priv rfk_priv[IDEAPAD_RFKILL_DEV_NUM]; 89 struct platform_device *platform_device; 90 struct input_dev *inputdev; 91 struct backlight_device *blightdev; | 88struct ideapad_rfk_priv { 89 int dev; 90 struct ideapad_private *priv; 91}; 92 93struct ideapad_private { 94 struct acpi_device *adev; 95 struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM]; 96 struct ideapad_rfk_priv rfk_priv[IDEAPAD_RFKILL_DEV_NUM]; 97 struct platform_device *platform_device; 98 struct input_dev *inputdev; 99 struct backlight_device *blightdev; |
100 struct ideapad_dytc_priv *dytc; |
|
92 struct dentry *debug; 93 unsigned long cfg; 94 bool has_hw_rfkill_switch; 95 bool has_touchpad_switch; 96 const char *fnesc_guid; 97}; 98 99static bool no_bt_rfkill; --- 32 unchanged lines hidden (view full) --- 132static int method_int1(acpi_handle handle, char *method, int cmd) 133{ 134 acpi_status status; 135 136 status = acpi_execute_simple_method(handle, method, cmd); 137 return ACPI_FAILURE(status) ? -1 : 0; 138} 139 | 101 struct dentry *debug; 102 unsigned long cfg; 103 bool has_hw_rfkill_switch; 104 bool has_touchpad_switch; 105 const char *fnesc_guid; 106}; 107 108static bool no_bt_rfkill; --- 32 unchanged lines hidden (view full) --- 141static int method_int1(acpi_handle handle, char *method, int cmd) 142{ 143 acpi_status status; 144 145 status = acpi_execute_simple_method(handle, method, cmd); 146 return ACPI_FAILURE(status) ? -1 : 0; 147} 148 |
149static int method_dytc(acpi_handle handle, int cmd, int *ret) 150{ 151 acpi_status status; 152 unsigned long long result; 153 struct acpi_object_list params; 154 union acpi_object in_obj; 155 156 params.count = 1; 157 params.pointer = &in_obj; 158 in_obj.type = ACPI_TYPE_INTEGER; 159 in_obj.integer.value = cmd; 160 161 status = acpi_evaluate_integer(handle, "DYTC", ¶ms, &result); 162 163 if (ACPI_FAILURE(status)) { 164 *ret = -1; 165 return -1; 166 } 167 *ret = result; 168 return 0; 169} 170 |
|
140static int method_vpcr(acpi_handle handle, int cmd, int *ret) 141{ 142 acpi_status status; 143 unsigned long long result; 144 struct acpi_object_list params; 145 union acpi_object in_obj; 146 147 params.count = 1; --- 397 unchanged lines hidden (view full) --- 545} 546 547static const struct attribute_group ideapad_attribute_group = { 548 .is_visible = ideapad_is_visible, 549 .attrs = ideapad_attributes 550}; 551 552/* | 171static int method_vpcr(acpi_handle handle, int cmd, int *ret) 172{ 173 acpi_status status; 174 unsigned long long result; 175 struct acpi_object_list params; 176 union acpi_object in_obj; 177 178 params.count = 1; --- 397 unchanged lines hidden (view full) --- 576} 577 578static const struct attribute_group ideapad_attribute_group = { 579 .is_visible = ideapad_is_visible, 580 .attrs = ideapad_attributes 581}; 582 583/* |
584 * DYTC Platform profile 585 */ 586#define DYTC_CMD_QUERY 0 /* To get DYTC status - enable/revision */ 587#define DYTC_CMD_SET 1 /* To enable/disable IC function mode */ 588#define DYTC_CMD_GET 2 /* To get current IC function and mode */ 589#define DYTC_CMD_RESET 0x1ff /* To reset back to default */ 590 591#define DYTC_QUERY_ENABLE_BIT 8 /* Bit 8 - 0 = disabled, 1 = enabled */ 592#define DYTC_QUERY_SUBREV_BIT 16 /* Bits 16 - 27 - sub revision */ 593#define DYTC_QUERY_REV_BIT 28 /* Bits 28 - 31 - revision */ 594 595#define DYTC_GET_FUNCTION_BIT 8 /* Bits 8-11 - function setting */ 596#define DYTC_GET_MODE_BIT 12 /* Bits 12-15 - mode setting */ 597 598#define DYTC_SET_FUNCTION_BIT 12 /* Bits 12-15 - function setting */ 599#define DYTC_SET_MODE_BIT 16 /* Bits 16-19 - mode setting */ 600#define DYTC_SET_VALID_BIT 20 /* Bit 20 - 1 = on, 0 = off */ 601 602#define DYTC_FUNCTION_STD 0 /* Function = 0, standard mode */ 603#define DYTC_FUNCTION_CQL 1 /* Function = 1, lap mode */ 604#define DYTC_FUNCTION_MMC 11 /* Function = 11, desk mode */ 605 606#define DYTC_MODE_PERFORM 2 /* High power mode aka performance */ 607#define DYTC_MODE_LOW_POWER 3 /* Low power mode aka quiet */ 608#define DYTC_MODE_BALANCE 0xF /* Default mode aka balanced */ 609 610#define DYTC_SET_COMMAND(function, mode, on) \ 611 (DYTC_CMD_SET | (function) << DYTC_SET_FUNCTION_BIT | \ 612 (mode) << DYTC_SET_MODE_BIT | \ 613 (on) << DYTC_SET_VALID_BIT) 614 615#define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 0) 616 617#define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 1) 618 619static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile) 620{ 621 switch (dytcmode) { 622 case DYTC_MODE_LOW_POWER: 623 *profile = PLATFORM_PROFILE_LOW_POWER; 624 break; 625 case DYTC_MODE_BALANCE: 626 *profile = PLATFORM_PROFILE_BALANCED; 627 break; 628 case DYTC_MODE_PERFORM: 629 *profile = PLATFORM_PROFILE_PERFORMANCE; 630 break; 631 default: /* Unknown mode */ 632 return -EINVAL; 633 } 634 return 0; 635} 636 637static int convert_profile_to_dytc(enum platform_profile_option profile, int *perfmode) 638{ 639 switch (profile) { 640 case PLATFORM_PROFILE_LOW_POWER: 641 *perfmode = DYTC_MODE_LOW_POWER; 642 break; 643 case PLATFORM_PROFILE_BALANCED: 644 *perfmode = DYTC_MODE_BALANCE; 645 break; 646 case PLATFORM_PROFILE_PERFORMANCE: 647 *perfmode = DYTC_MODE_PERFORM; 648 break; 649 default: /* Unknown profile */ 650 return -EOPNOTSUPP; 651 } 652 return 0; 653} 654 655/* 656 * dytc_profile_get: Function to register with platform_profile 657 * handler. Returns current platform profile. 658 */ 659int dytc_profile_get(struct platform_profile_handler *pprof, 660 enum platform_profile_option *profile) 661{ 662 struct ideapad_dytc_priv *dytc; 663 664 dytc = container_of(pprof, struct ideapad_dytc_priv, pprof); 665 *profile = dytc->current_profile; 666 return 0; 667} 668 669/* 670 * Helper function - check if we are in CQL mode and if we are 671 * - disable CQL, 672 * - run the command 673 * - enable CQL 674 * If not in CQL mode, just run the command 675 */ 676int dytc_cql_command(struct ideapad_private *priv, int command, int *output) 677{ 678 int err, cmd_err, dummy; 679 int cur_funcmode; 680 681 /* Determine if we are in CQL mode. This alters the commands we do */ 682 err = method_dytc(priv->adev->handle, DYTC_CMD_GET, output); 683 if (err) 684 return err; 685 686 cur_funcmode = (*output >> DYTC_GET_FUNCTION_BIT) & 0xF; 687 /* Check if we're OK to return immediately */ 688 if ((command == DYTC_CMD_GET) && (cur_funcmode != DYTC_FUNCTION_CQL)) 689 return 0; 690 691 if (cur_funcmode == DYTC_FUNCTION_CQL) { 692 err = method_dytc(priv->adev->handle, DYTC_DISABLE_CQL, &dummy); 693 if (err) 694 return err; 695 } 696 697 cmd_err = method_dytc(priv->adev->handle, command, output); 698 /* Check return condition after we've restored CQL state */ 699 700 if (cur_funcmode == DYTC_FUNCTION_CQL) { 701 err = method_dytc(priv->adev->handle, DYTC_ENABLE_CQL, &dummy); 702 if (err) 703 return err; 704 } 705 706 return cmd_err; 707} 708 709/* 710 * dytc_profile_set: Function to register with platform_profile 711 * handler. Sets current platform profile. 712 */ 713int dytc_profile_set(struct platform_profile_handler *pprof, 714 enum platform_profile_option profile) 715{ 716 struct ideapad_dytc_priv *dytc; 717 struct ideapad_private *priv; 718 int output; 719 int err; 720 721 dytc = container_of(pprof, struct ideapad_dytc_priv, pprof); 722 priv = dytc->priv; 723 724 err = mutex_lock_interruptible(&dytc->mutex); 725 if (err) 726 return err; 727 728 if (profile == PLATFORM_PROFILE_BALANCED) { 729 /* To get back to balanced mode we just issue a reset command */ 730 err = method_dytc(priv->adev->handle, DYTC_CMD_RESET, &output); 731 if (err) 732 goto unlock; 733 } else { 734 int perfmode; 735 736 err = convert_profile_to_dytc(profile, &perfmode); 737 if (err) 738 goto unlock; 739 740 /* Determine if we are in CQL mode. This alters the commands we do */ 741 err = dytc_cql_command(priv, 742 DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1), 743 &output); 744 if (err) 745 goto unlock; 746 } 747 /* Success - update current profile */ 748 dytc->current_profile = profile; 749unlock: 750 mutex_unlock(&dytc->mutex); 751 return err; 752} 753 754static void dytc_profile_refresh(struct ideapad_private *priv) 755{ 756 enum platform_profile_option profile; 757 int output, err; 758 int perfmode; 759 760 mutex_lock(&priv->dytc->mutex); 761 err = dytc_cql_command(priv, DYTC_CMD_GET, &output); 762 mutex_unlock(&priv->dytc->mutex); 763 if (err) 764 return; 765 766 perfmode = (output >> DYTC_GET_MODE_BIT) & 0xF; 767 convert_dytc_to_profile(perfmode, &profile); 768 if (profile != priv->dytc->current_profile) { 769 priv->dytc->current_profile = profile; 770 platform_profile_notify(); 771 } 772} 773 774static int ideapad_dytc_profile_init(struct ideapad_private *priv) 775{ 776 int err, output, dytc_version; 777 778 err = method_dytc(priv->adev->handle, DYTC_CMD_QUERY, &output); 779 /* For all other errors we can flag the failure */ 780 if (err) 781 return err; 782 783 /* Check DYTC is enabled and supports mode setting */ 784 if (!(output & BIT(DYTC_QUERY_ENABLE_BIT))) 785 return -ENODEV; 786 787 dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF; 788 if (dytc_version < 5) 789 return -ENODEV; 790 791 priv->dytc = kzalloc(sizeof(struct ideapad_dytc_priv), GFP_KERNEL); 792 if (!priv->dytc) 793 return -ENOMEM; 794 795 mutex_init(&priv->dytc->mutex); 796 797 priv->dytc->priv = priv; 798 priv->dytc->pprof.profile_get = dytc_profile_get; 799 priv->dytc->pprof.profile_set = dytc_profile_set; 800 801 /* Setup supported modes */ 802 set_bit(PLATFORM_PROFILE_LOW_POWER, priv->dytc->pprof.choices); 803 set_bit(PLATFORM_PROFILE_BALANCED, priv->dytc->pprof.choices); 804 set_bit(PLATFORM_PROFILE_PERFORMANCE, priv->dytc->pprof.choices); 805 806 /* Create platform_profile structure and register */ 807 err = platform_profile_register(&priv->dytc->pprof); 808 if (err) 809 goto mutex_destroy; 810 811 /* Ensure initial values are correct */ 812 dytc_profile_refresh(priv); 813 814 return 0; 815 816mutex_destroy: 817 mutex_destroy(&priv->dytc->mutex); 818 kfree(priv->dytc); 819 priv->dytc = NULL; 820 return err; 821} 822 823static void ideapad_dytc_profile_exit(struct ideapad_private *priv) 824{ 825 if (!priv->dytc) 826 return; 827 828 platform_profile_remove(); 829 mutex_destroy(&priv->dytc->mutex); 830 kfree(priv->dytc); 831 priv->dytc = NULL; 832} 833 834/* |
|
553 * Rfkill 554 */ 555struct ideapad_rfk_data { 556 char *name; 557 int cfgbit; 558 int opcode; 559 int type; 560}; --- 460 unchanged lines hidden (view full) --- 1021 1022 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) 1023 if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg)) 1024 ideapad_register_rfkill(priv, i); 1025 1026 ideapad_sync_rfk_state(priv); 1027 ideapad_sync_touchpad_state(priv); 1028 | 835 * Rfkill 836 */ 837struct ideapad_rfk_data { 838 char *name; 839 int cfgbit; 840 int opcode; 841 int type; 842}; --- 460 unchanged lines hidden (view full) --- 1303 1304 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) 1305 if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg)) 1306 ideapad_register_rfkill(priv, i); 1307 1308 ideapad_sync_rfk_state(priv); 1309 ideapad_sync_touchpad_state(priv); 1310 |
1311 ideapad_dytc_profile_init(priv); 1312 |
|
1029 if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { 1030 ret = ideapad_backlight_init(priv); 1031 if (ret && ret != -ENODEV) 1032 goto backlight_failed; 1033 } 1034 ret = acpi_install_notify_handler(adev->handle, 1035 ACPI_DEVICE_NOTIFY, ideapad_acpi_notify, priv); 1036 if (ret) --- 37 unchanged lines hidden (view full) --- 1074 1075#if IS_ENABLED(CONFIG_ACPI_WMI) 1076 if (priv->fnesc_guid) 1077 wmi_remove_notify_handler(priv->fnesc_guid); 1078#endif 1079 acpi_remove_notify_handler(priv->adev->handle, 1080 ACPI_DEVICE_NOTIFY, ideapad_acpi_notify); 1081 ideapad_backlight_exit(priv); | 1313 if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { 1314 ret = ideapad_backlight_init(priv); 1315 if (ret && ret != -ENODEV) 1316 goto backlight_failed; 1317 } 1318 ret = acpi_install_notify_handler(adev->handle, 1319 ACPI_DEVICE_NOTIFY, ideapad_acpi_notify, priv); 1320 if (ret) --- 37 unchanged lines hidden (view full) --- 1358 1359#if IS_ENABLED(CONFIG_ACPI_WMI) 1360 if (priv->fnesc_guid) 1361 wmi_remove_notify_handler(priv->fnesc_guid); 1362#endif 1363 acpi_remove_notify_handler(priv->adev->handle, 1364 ACPI_DEVICE_NOTIFY, ideapad_acpi_notify); 1365 ideapad_backlight_exit(priv); |
1366 ideapad_dytc_profile_exit(priv); |
|
1082 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) 1083 ideapad_unregister_rfkill(priv, i); 1084 ideapad_input_exit(priv); 1085 ideapad_debugfs_exit(priv); 1086 ideapad_sysfs_exit(priv); 1087 dev_set_drvdata(&pdev->dev, NULL); 1088 1089 return 0; --- 5 unchanged lines hidden (view full) --- 1095 struct ideapad_private *priv; 1096 1097 if (!device) 1098 return -EINVAL; 1099 priv = dev_get_drvdata(device); 1100 1101 ideapad_sync_rfk_state(priv); 1102 ideapad_sync_touchpad_state(priv); | 1367 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) 1368 ideapad_unregister_rfkill(priv, i); 1369 ideapad_input_exit(priv); 1370 ideapad_debugfs_exit(priv); 1371 ideapad_sysfs_exit(priv); 1372 dev_set_drvdata(&pdev->dev, NULL); 1373 1374 return 0; --- 5 unchanged lines hidden (view full) --- 1380 struct ideapad_private *priv; 1381 1382 if (!device) 1383 return -EINVAL; 1384 priv = dev_get_drvdata(device); 1385 1386 ideapad_sync_rfk_state(priv); 1387 ideapad_sync_touchpad_state(priv); |
1388 1389 if (priv->dytc) 1390 dytc_profile_refresh(priv); 1391 |
|
1103 return 0; 1104} 1105#endif 1106static SIMPLE_DEV_PM_OPS(ideapad_pm, NULL, ideapad_acpi_resume); 1107 1108static const struct acpi_device_id ideapad_device_ids[] = { 1109 { "VPC2004", 0}, 1110 { "", 0}, --- 18 unchanged lines hidden --- | 1392 return 0; 1393} 1394#endif 1395static SIMPLE_DEV_PM_OPS(ideapad_pm, NULL, ideapad_acpi_resume); 1396 1397static const struct acpi_device_id ideapad_device_ids[] = { 1398 { "VPC2004", 0}, 1399 { "", 0}, --- 18 unchanged lines hidden --- |