162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ideapad-laptop.h - Lenovo IdeaPad ACPI Extras 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright © 2010 Intel Corporation 662306a36Sopenharmony_ci * Copyright © 2010 David Woodhouse <dwmw2@infradead.org> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#ifndef _IDEAPAD_LAPTOP_H_ 1062306a36Sopenharmony_ci#define _IDEAPAD_LAPTOP_H_ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/acpi.h> 1362306a36Sopenharmony_ci#include <linux/jiffies.h> 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cienum { 1762306a36Sopenharmony_ci VPCCMD_R_VPC1 = 0x10, 1862306a36Sopenharmony_ci VPCCMD_R_BL_MAX, 1962306a36Sopenharmony_ci VPCCMD_R_BL, 2062306a36Sopenharmony_ci VPCCMD_W_BL, 2162306a36Sopenharmony_ci VPCCMD_R_WIFI, 2262306a36Sopenharmony_ci VPCCMD_W_WIFI, 2362306a36Sopenharmony_ci VPCCMD_R_BT, 2462306a36Sopenharmony_ci VPCCMD_W_BT, 2562306a36Sopenharmony_ci VPCCMD_R_BL_POWER, 2662306a36Sopenharmony_ci VPCCMD_R_NOVO, 2762306a36Sopenharmony_ci VPCCMD_R_VPC2, 2862306a36Sopenharmony_ci VPCCMD_R_TOUCHPAD, 2962306a36Sopenharmony_ci VPCCMD_W_TOUCHPAD, 3062306a36Sopenharmony_ci VPCCMD_R_CAMERA, 3162306a36Sopenharmony_ci VPCCMD_W_CAMERA, 3262306a36Sopenharmony_ci VPCCMD_R_3G, 3362306a36Sopenharmony_ci VPCCMD_W_3G, 3462306a36Sopenharmony_ci VPCCMD_R_ODD, /* 0x21 */ 3562306a36Sopenharmony_ci VPCCMD_W_FAN, 3662306a36Sopenharmony_ci VPCCMD_R_RF, 3762306a36Sopenharmony_ci VPCCMD_W_RF, 3862306a36Sopenharmony_ci VPCCMD_W_YMC = 0x2A, 3962306a36Sopenharmony_ci VPCCMD_R_FAN = 0x2B, 4062306a36Sopenharmony_ci VPCCMD_R_SPECIAL_BUTTONS = 0x31, 4162306a36Sopenharmony_ci VPCCMD_W_BL_POWER = 0x33, 4262306a36Sopenharmony_ci}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic inline int eval_int_with_arg(acpi_handle handle, const char *name, unsigned long arg, unsigned long *res) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct acpi_object_list params; 4762306a36Sopenharmony_ci unsigned long long result; 4862306a36Sopenharmony_ci union acpi_object in_obj; 4962306a36Sopenharmony_ci acpi_status status; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci params.count = 1; 5262306a36Sopenharmony_ci params.pointer = &in_obj; 5362306a36Sopenharmony_ci in_obj.type = ACPI_TYPE_INTEGER; 5462306a36Sopenharmony_ci in_obj.integer.value = arg; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci status = acpi_evaluate_integer(handle, (char *)name, ¶ms, &result); 5762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) 5862306a36Sopenharmony_ci return -EIO; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (res) 6162306a36Sopenharmony_ci *res = result; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return 0; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic inline int eval_vpcr(acpi_handle handle, unsigned long cmd, unsigned long *res) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci return eval_int_with_arg(handle, "VPCR", cmd, res); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic inline int eval_vpcw(acpi_handle handle, unsigned long cmd, unsigned long data) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct acpi_object_list params; 7462306a36Sopenharmony_ci union acpi_object in_obj[2]; 7562306a36Sopenharmony_ci acpi_status status; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci params.count = 2; 7862306a36Sopenharmony_ci params.pointer = in_obj; 7962306a36Sopenharmony_ci in_obj[0].type = ACPI_TYPE_INTEGER; 8062306a36Sopenharmony_ci in_obj[0].integer.value = cmd; 8162306a36Sopenharmony_ci in_obj[1].type = ACPI_TYPE_INTEGER; 8262306a36Sopenharmony_ci in_obj[1].integer.value = data; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci status = acpi_evaluate_object(handle, "VPCW", ¶ms, NULL); 8562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) 8662306a36Sopenharmony_ci return -EIO; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define IDEAPAD_EC_TIMEOUT 200 /* in ms */ 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic inline int read_ec_data(acpi_handle handle, unsigned long cmd, unsigned long *data) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci unsigned long end_jiffies, val; 9662306a36Sopenharmony_ci int err; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci err = eval_vpcw(handle, 1, cmd); 9962306a36Sopenharmony_ci if (err) 10062306a36Sopenharmony_ci return err; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci while (time_before(jiffies, end_jiffies)) { 10562306a36Sopenharmony_ci schedule(); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci err = eval_vpcr(handle, 1, &val); 10862306a36Sopenharmony_ci if (err) 10962306a36Sopenharmony_ci return err; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (val == 0) 11262306a36Sopenharmony_ci return eval_vpcr(handle, 0, data); 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci acpi_handle_err(handle, "timeout in %s\n", __func__); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return -ETIMEDOUT; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic inline int write_ec_cmd(acpi_handle handle, unsigned long cmd, unsigned long data) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci unsigned long end_jiffies, val; 12362306a36Sopenharmony_ci int err; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci err = eval_vpcw(handle, 0, data); 12662306a36Sopenharmony_ci if (err) 12762306a36Sopenharmony_ci return err; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci err = eval_vpcw(handle, 1, cmd); 13062306a36Sopenharmony_ci if (err) 13162306a36Sopenharmony_ci return err; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci while (time_before(jiffies, end_jiffies)) { 13662306a36Sopenharmony_ci schedule(); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci err = eval_vpcr(handle, 1, &val); 13962306a36Sopenharmony_ci if (err) 14062306a36Sopenharmony_ci return err; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (val == 0) 14362306a36Sopenharmony_ci return 0; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci acpi_handle_err(handle, "timeout in %s\n", __func__); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci return -ETIMEDOUT; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci#undef IDEAPAD_EC_TIMEOUT 15262306a36Sopenharmony_ci#endif /* !_IDEAPAD_LAPTOP_H_ */ 153