1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * ideapad-laptop.h - Lenovo IdeaPad ACPI Extras 4 * 5 * Copyright © 2010 Intel Corporation 6 * Copyright © 2010 David Woodhouse <dwmw2@infradead.org> 7 */ 8 9 #ifndef _IDEAPAD_LAPTOP_H_ 10 #define _IDEAPAD_LAPTOP_H_ 11 12 #include <linux/acpi.h> 13 #include <linux/jiffies.h> 14 #include <linux/errno.h> 15 16 enum { 17 VPCCMD_R_VPC1 = 0x10, 18 VPCCMD_R_BL_MAX, 19 VPCCMD_R_BL, 20 VPCCMD_W_BL, 21 VPCCMD_R_WIFI, 22 VPCCMD_W_WIFI, 23 VPCCMD_R_BT, 24 VPCCMD_W_BT, 25 VPCCMD_R_BL_POWER, 26 VPCCMD_R_NOVO, 27 VPCCMD_R_VPC2, 28 VPCCMD_R_TOUCHPAD, 29 VPCCMD_W_TOUCHPAD, 30 VPCCMD_R_CAMERA, 31 VPCCMD_W_CAMERA, 32 VPCCMD_R_3G, 33 VPCCMD_W_3G, 34 VPCCMD_R_ODD, /* 0x21 */ 35 VPCCMD_W_FAN, 36 VPCCMD_R_RF, 37 VPCCMD_W_RF, 38 VPCCMD_W_YMC = 0x2A, 39 VPCCMD_R_FAN = 0x2B, 40 VPCCMD_R_SPECIAL_BUTTONS = 0x31, 41 VPCCMD_W_BL_POWER = 0x33, 42 }; 43 44 static inline int eval_int_with_arg(acpi_handle handle, const char *name, unsigned long arg, unsigned long *res) 45 { 46 struct acpi_object_list params; 47 unsigned long long result; 48 union acpi_object in_obj; 49 acpi_status status; 50 51 params.count = 1; 52 params.pointer = &in_obj; 53 in_obj.type = ACPI_TYPE_INTEGER; 54 in_obj.integer.value = arg; 55 56 status = acpi_evaluate_integer(handle, (char *)name, ¶ms, &result); 57 if (ACPI_FAILURE(status)) 58 return -EIO; 59 60 if (res) 61 *res = result; 62 63 return 0; 64 } 65 66 static inline int eval_vpcr(acpi_handle handle, unsigned long cmd, unsigned long *res) 67 { 68 return eval_int_with_arg(handle, "VPCR", cmd, res); 69 } 70 71 static inline int eval_vpcw(acpi_handle handle, unsigned long cmd, unsigned long data) 72 { 73 struct acpi_object_list params; 74 union acpi_object in_obj[2]; 75 acpi_status status; 76 77 params.count = 2; 78 params.pointer = in_obj; 79 in_obj[0].type = ACPI_TYPE_INTEGER; 80 in_obj[0].integer.value = cmd; 81 in_obj[1].type = ACPI_TYPE_INTEGER; 82 in_obj[1].integer.value = data; 83 84 status = acpi_evaluate_object(handle, "VPCW", ¶ms, NULL); 85 if (ACPI_FAILURE(status)) 86 return -EIO; 87 88 return 0; 89 } 90 91 #define IDEAPAD_EC_TIMEOUT 200 /* in ms */ 92 93 static inline int read_ec_data(acpi_handle handle, unsigned long cmd, unsigned long *data) 94 { 95 unsigned long end_jiffies, val; 96 int err; 97 98 err = eval_vpcw(handle, 1, cmd); 99 if (err) 100 return err; 101 102 end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1; 103 104 while (time_before(jiffies, end_jiffies)) { 105 schedule(); 106 107 err = eval_vpcr(handle, 1, &val); 108 if (err) 109 return err; 110 111 if (val == 0) 112 return eval_vpcr(handle, 0, data); 113 } 114 115 acpi_handle_err(handle, "timeout in %s\n", __func__); 116 117 return -ETIMEDOUT; 118 } 119 120 static inline int write_ec_cmd(acpi_handle handle, unsigned long cmd, unsigned long data) 121 { 122 unsigned long end_jiffies, val; 123 int err; 124 125 err = eval_vpcw(handle, 0, data); 126 if (err) 127 return err; 128 129 err = eval_vpcw(handle, 1, cmd); 130 if (err) 131 return err; 132 133 end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1; 134 135 while (time_before(jiffies, end_jiffies)) { 136 schedule(); 137 138 err = eval_vpcr(handle, 1, &val); 139 if (err) 140 return err; 141 142 if (val == 0) 143 return 0; 144 } 145 146 acpi_handle_err(handle, "timeout in %s\n", __func__); 147 148 return -ETIMEDOUT; 149 } 150 151 #undef IDEAPAD_EC_TIMEOUT 152 #endif /* !_IDEAPAD_LAPTOP_H_ */ 153