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, pathname: (char *)name, arguments: ¶ms, data: &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, name: "VPCR" , arg: 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(object: handle, pathname: "VPCW" , parameter_objects: ¶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, cmd: 1, data: 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, cmd: 1, res: &val); |
108 | if (err) |
109 | return err; |
110 | |
111 | if (val == 0) |
112 | return eval_vpcr(handle, cmd: 0, res: 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, cmd: 0, data); |
126 | if (err) |
127 | return err; |
128 | |
129 | err = eval_vpcw(handle, cmd: 1, data: 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, cmd: 1, res: &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 | |