xref: /linux/drivers/platform/x86/ideapad-laptop.h (revision a3a02a52bcfcbcc4a637d4b68bf1bc391c9fad02)
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, &params, &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", &params, 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