1 /*
2  * power/home/volume button support for
3  * Microsoft Surface Pro 3/4 tablet.
4  *
5  * Copyright (c) 2015 Intel Corporation.
6  * All rights reserved.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; version 2
11  * of the License.
12  */
13 
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/init.h>
17 #include <linux/types.h>
18 #include <linux/input.h>
19 #include <linux/acpi.h>
20 #include <acpi/button.h>
21 
22 #define SURFACE_PRO3_BUTTON_HID		"MSHW0028"
23 #define SURFACE_PRO4_BUTTON_HID		"MSHW0040"
24 #define SURFACE_BUTTON_OBJ_NAME		"VGBI"
25 #define SURFACE_BUTTON_DEVICE_NAME	"Surface Pro 3/4 Buttons"
26 
27 #define SURFACE_BUTTON_NOTIFY_TABLET_MODE	0xc8
28 
29 #define SURFACE_BUTTON_NOTIFY_PRESS_POWER	0xc6
30 #define SURFACE_BUTTON_NOTIFY_RELEASE_POWER	0xc7
31 
32 #define SURFACE_BUTTON_NOTIFY_PRESS_HOME	0xc4
33 #define SURFACE_BUTTON_NOTIFY_RELEASE_HOME	0xc5
34 
35 #define SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_UP	0xc0
36 #define SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_UP	0xc1
37 
38 #define SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_DOWN		0xc2
39 #define SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_DOWN	0xc3
40 
41 ACPI_MODULE_NAME("surface pro 3 button");
42 
43 MODULE_AUTHOR("Chen Yu");
44 MODULE_DESCRIPTION("Surface Pro3 Button Driver");
45 MODULE_LICENSE("GPL v2");
46 
47 /*
48  * Power button, Home button, Volume buttons support is supposed to
49  * be covered by drivers/input/misc/soc_button_array.c, which is implemented
50  * according to "Windows ACPI Design Guide for SoC Platforms".
51  * However surface pro3 seems not to obey the specs, instead it uses
52  * device VGBI(MSHW0028) for dispatching the events.
53  * We choose acpi_driver rather than platform_driver/i2c_driver because
54  * although VGBI has an i2c resource connected to i2c controller, it
55  * is not embedded in any i2c controller's scope, thus neither platform_device
56  * will be created, nor i2c_client will be enumerated, we have to use
57  * acpi_driver.
58  */
59 static const struct acpi_device_id surface_button_device_ids[] = {
60 	{SURFACE_PRO3_BUTTON_HID,    0},
61 	{SURFACE_PRO4_BUTTON_HID,    0},
62 	{"", 0},
63 };
64 MODULE_DEVICE_TABLE(acpi, surface_button_device_ids);
65 
66 struct surface_button {
67 	unsigned int type;
68 	struct input_dev *input;
69 	char phys[32];			/* for input device */
70 	unsigned long pushed;
71 	bool suspended;
72 };
73 
surface_button_notify(struct acpi_device * device,u32 event)74 static void surface_button_notify(struct acpi_device *device, u32 event)
75 {
76 	struct surface_button *button = acpi_driver_data(device);
77 	struct input_dev *input;
78 	int key_code = KEY_RESERVED;
79 	bool pressed = false;
80 
81 	switch (event) {
82 	/* Power button press,release handle */
83 	case SURFACE_BUTTON_NOTIFY_PRESS_POWER:
84 		pressed = true;
85 		/*fall through*/
86 	case SURFACE_BUTTON_NOTIFY_RELEASE_POWER:
87 		key_code = KEY_POWER;
88 		break;
89 	/* Home button press,release handle */
90 	case SURFACE_BUTTON_NOTIFY_PRESS_HOME:
91 		pressed = true;
92 		/*fall through*/
93 	case SURFACE_BUTTON_NOTIFY_RELEASE_HOME:
94 		key_code = KEY_LEFTMETA;
95 		break;
96 	/* Volume up button press,release handle */
97 	case SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_UP:
98 		pressed = true;
99 		/*fall through*/
100 	case SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_UP:
101 		key_code = KEY_VOLUMEUP;
102 		break;
103 	/* Volume down button press,release handle */
104 	case SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_DOWN:
105 		pressed = true;
106 		/*fall through*/
107 	case SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_DOWN:
108 		key_code = KEY_VOLUMEDOWN;
109 		break;
110 	case SURFACE_BUTTON_NOTIFY_TABLET_MODE:
111 		dev_warn_once(&device->dev, "Tablet mode is not supported\n");
112 		break;
113 	default:
114 		dev_info_ratelimited(&device->dev,
115 				     "Unsupported event [0x%x]\n", event);
116 		break;
117 	}
118 	input = button->input;
119 	if (key_code == KEY_RESERVED)
120 		return;
121 	if (pressed)
122 		pm_wakeup_dev_event(&device->dev, 0, button->suspended);
123 	if (button->suspended)
124 		return;
125 	input_report_key(input, key_code, pressed?1:0);
126 	input_sync(input);
127 }
128 
129 #ifdef CONFIG_PM_SLEEP
surface_button_suspend(struct device * dev)130 static int surface_button_suspend(struct device *dev)
131 {
132 	struct acpi_device *device = to_acpi_device(dev);
133 	struct surface_button *button = acpi_driver_data(device);
134 
135 	button->suspended = true;
136 	return 0;
137 }
138 
surface_button_resume(struct device * dev)139 static int surface_button_resume(struct device *dev)
140 {
141 	struct acpi_device *device = to_acpi_device(dev);
142 	struct surface_button *button = acpi_driver_data(device);
143 
144 	button->suspended = false;
145 	return 0;
146 }
147 #endif
148 
surface_button_add(struct acpi_device * device)149 static int surface_button_add(struct acpi_device *device)
150 {
151 	struct surface_button *button;
152 	struct input_dev *input;
153 	const char *hid = acpi_device_hid(device);
154 	char *name;
155 	int error;
156 
157 	if (strncmp(acpi_device_bid(device), SURFACE_BUTTON_OBJ_NAME,
158 	    strlen(SURFACE_BUTTON_OBJ_NAME)))
159 		return -ENODEV;
160 
161 	button = kzalloc(sizeof(struct surface_button), GFP_KERNEL);
162 	if (!button)
163 		return -ENOMEM;
164 
165 	device->driver_data = button;
166 	button->input = input = input_allocate_device();
167 	if (!input) {
168 		error = -ENOMEM;
169 		goto err_free_button;
170 	}
171 
172 	name = acpi_device_name(device);
173 	strcpy(name, SURFACE_BUTTON_DEVICE_NAME);
174 	snprintf(button->phys, sizeof(button->phys), "%s/buttons", hid);
175 
176 	input->name = name;
177 	input->phys = button->phys;
178 	input->id.bustype = BUS_HOST;
179 	input->dev.parent = &device->dev;
180 	input_set_capability(input, EV_KEY, KEY_POWER);
181 	input_set_capability(input, EV_KEY, KEY_LEFTMETA);
182 	input_set_capability(input, EV_KEY, KEY_VOLUMEUP);
183 	input_set_capability(input, EV_KEY, KEY_VOLUMEDOWN);
184 
185 	error = input_register_device(input);
186 	if (error)
187 		goto err_free_input;
188 
189 	device_init_wakeup(&device->dev, true);
190 	dev_info(&device->dev,
191 			"%s [%s]\n", name, acpi_device_bid(device));
192 	return 0;
193 
194  err_free_input:
195 	input_free_device(input);
196  err_free_button:
197 	kfree(button);
198 	return error;
199 }
200 
surface_button_remove(struct acpi_device * device)201 static int surface_button_remove(struct acpi_device *device)
202 {
203 	struct surface_button *button = acpi_driver_data(device);
204 
205 	input_unregister_device(button->input);
206 	kfree(button);
207 	return 0;
208 }
209 
210 static SIMPLE_DEV_PM_OPS(surface_button_pm,
211 		surface_button_suspend, surface_button_resume);
212 
213 static struct acpi_driver surface_button_driver = {
214 	.name = "surface_pro3_button",
215 	.class = "SurfacePro3",
216 	.ids = surface_button_device_ids,
217 	.ops = {
218 		.add = surface_button_add,
219 		.remove = surface_button_remove,
220 		.notify = surface_button_notify,
221 	},
222 	.drv.pm = &surface_button_pm,
223 };
224 
225 module_acpi_driver(surface_button_driver);
226