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