xref: /linux/drivers/platform/x86/classmate-laptop.c (revision 7f71507851fc7764b36a3221839607d3a45c2025)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  Copyright (C) 2009  Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
4  */
5 
6 
7 #include <linux/init.h>
8 #include <linux/module.h>
9 #include <linux/slab.h>
10 #include <linux/workqueue.h>
11 #include <linux/acpi.h>
12 #include <linux/backlight.h>
13 #include <linux/input.h>
14 #include <linux/rfkill.h>
15 #include <linux/sysfs.h>
16 
17 struct cmpc_accel {
18 	int sensitivity;
19 	int g_select;
20 	int inputdev_state;
21 };
22 
23 #define CMPC_ACCEL_DEV_STATE_CLOSED	0
24 #define CMPC_ACCEL_DEV_STATE_OPEN	1
25 
26 #define CMPC_ACCEL_SENSITIVITY_DEFAULT		5
27 #define CMPC_ACCEL_G_SELECT_DEFAULT		0
28 
29 #define CMPC_ACCEL_HID		"ACCE0000"
30 #define CMPC_ACCEL_HID_V4	"ACCE0001"
31 #define CMPC_TABLET_HID		"TBLT0000"
32 #define CMPC_IPML_HID	"IPML200"
33 #define CMPC_KEYS_HID		"FNBT0000"
34 
35 /*
36  * Generic input device code.
37  */
38 
39 typedef void (*input_device_init)(struct input_dev *dev);
40 
41 static int cmpc_add_acpi_notify_device(struct acpi_device *acpi, char *name,
42 				       input_device_init idev_init)
43 {
44 	struct input_dev *inputdev;
45 	int error;
46 
47 	inputdev = input_allocate_device();
48 	if (!inputdev)
49 		return -ENOMEM;
50 	inputdev->name = name;
51 	inputdev->dev.parent = &acpi->dev;
52 	idev_init(inputdev);
53 	error = input_register_device(inputdev);
54 	if (error) {
55 		input_free_device(inputdev);
56 		return error;
57 	}
58 	dev_set_drvdata(&acpi->dev, inputdev);
59 	return 0;
60 }
61 
62 static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi)
63 {
64 	struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
65 	input_unregister_device(inputdev);
66 	return 0;
67 }
68 
69 /*
70  * Accelerometer code for Classmate V4
71  */
72 static acpi_status cmpc_start_accel_v4(acpi_handle handle)
73 {
74 	union acpi_object param[4];
75 	struct acpi_object_list input;
76 	acpi_status status;
77 
78 	param[0].type = ACPI_TYPE_INTEGER;
79 	param[0].integer.value = 0x3;
80 	param[1].type = ACPI_TYPE_INTEGER;
81 	param[1].integer.value = 0;
82 	param[2].type = ACPI_TYPE_INTEGER;
83 	param[2].integer.value = 0;
84 	param[3].type = ACPI_TYPE_INTEGER;
85 	param[3].integer.value = 0;
86 	input.count = 4;
87 	input.pointer = param;
88 	status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
89 	return status;
90 }
91 
92 static acpi_status cmpc_stop_accel_v4(acpi_handle handle)
93 {
94 	union acpi_object param[4];
95 	struct acpi_object_list input;
96 	acpi_status status;
97 
98 	param[0].type = ACPI_TYPE_INTEGER;
99 	param[0].integer.value = 0x4;
100 	param[1].type = ACPI_TYPE_INTEGER;
101 	param[1].integer.value = 0;
102 	param[2].type = ACPI_TYPE_INTEGER;
103 	param[2].integer.value = 0;
104 	param[3].type = ACPI_TYPE_INTEGER;
105 	param[3].integer.value = 0;
106 	input.count = 4;
107 	input.pointer = param;
108 	status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
109 	return status;
110 }
111 
112 static acpi_status cmpc_accel_set_sensitivity_v4(acpi_handle handle, int val)
113 {
114 	union acpi_object param[4];
115 	struct acpi_object_list input;
116 
117 	param[0].type = ACPI_TYPE_INTEGER;
118 	param[0].integer.value = 0x02;
119 	param[1].type = ACPI_TYPE_INTEGER;
120 	param[1].integer.value = val;
121 	param[2].type = ACPI_TYPE_INTEGER;
122 	param[2].integer.value = 0;
123 	param[3].type = ACPI_TYPE_INTEGER;
124 	param[3].integer.value = 0;
125 	input.count = 4;
126 	input.pointer = param;
127 	return acpi_evaluate_object(handle, "ACMD", &input, NULL);
128 }
129 
130 static acpi_status cmpc_accel_set_g_select_v4(acpi_handle handle, int val)
131 {
132 	union acpi_object param[4];
133 	struct acpi_object_list input;
134 
135 	param[0].type = ACPI_TYPE_INTEGER;
136 	param[0].integer.value = 0x05;
137 	param[1].type = ACPI_TYPE_INTEGER;
138 	param[1].integer.value = val;
139 	param[2].type = ACPI_TYPE_INTEGER;
140 	param[2].integer.value = 0;
141 	param[3].type = ACPI_TYPE_INTEGER;
142 	param[3].integer.value = 0;
143 	input.count = 4;
144 	input.pointer = param;
145 	return acpi_evaluate_object(handle, "ACMD", &input, NULL);
146 }
147 
148 static acpi_status cmpc_get_accel_v4(acpi_handle handle,
149 				     int16_t *x,
150 				     int16_t *y,
151 				     int16_t *z)
152 {
153 	union acpi_object param[4];
154 	struct acpi_object_list input;
155 	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
156 	int16_t *locs;
157 	acpi_status status;
158 
159 	param[0].type = ACPI_TYPE_INTEGER;
160 	param[0].integer.value = 0x01;
161 	param[1].type = ACPI_TYPE_INTEGER;
162 	param[1].integer.value = 0;
163 	param[2].type = ACPI_TYPE_INTEGER;
164 	param[2].integer.value = 0;
165 	param[3].type = ACPI_TYPE_INTEGER;
166 	param[3].integer.value = 0;
167 	input.count = 4;
168 	input.pointer = param;
169 	status = acpi_evaluate_object(handle, "ACMD", &input, &output);
170 	if (ACPI_SUCCESS(status)) {
171 		union acpi_object *obj;
172 		obj = output.pointer;
173 		locs = (int16_t *) obj->buffer.pointer;
174 		*x = locs[0];
175 		*y = locs[1];
176 		*z = locs[2];
177 		kfree(output.pointer);
178 	}
179 	return status;
180 }
181 
182 static void cmpc_accel_handler_v4(struct acpi_device *dev, u32 event)
183 {
184 	if (event == 0x81) {
185 		int16_t x, y, z;
186 		acpi_status status;
187 
188 		status = cmpc_get_accel_v4(dev->handle, &x, &y, &z);
189 		if (ACPI_SUCCESS(status)) {
190 			struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
191 
192 			input_report_abs(inputdev, ABS_X, x);
193 			input_report_abs(inputdev, ABS_Y, y);
194 			input_report_abs(inputdev, ABS_Z, z);
195 			input_sync(inputdev);
196 		}
197 	}
198 }
199 
200 static ssize_t cmpc_accel_sensitivity_show_v4(struct device *dev,
201 					      struct device_attribute *attr,
202 					      char *buf)
203 {
204 	struct acpi_device *acpi;
205 	struct input_dev *inputdev;
206 	struct cmpc_accel *accel;
207 
208 	acpi = to_acpi_device(dev);
209 	inputdev = dev_get_drvdata(&acpi->dev);
210 	accel = dev_get_drvdata(&inputdev->dev);
211 
212 	return sysfs_emit(buf, "%d\n", accel->sensitivity);
213 }
214 
215 static ssize_t cmpc_accel_sensitivity_store_v4(struct device *dev,
216 					       struct device_attribute *attr,
217 					       const char *buf, size_t count)
218 {
219 	struct acpi_device *acpi;
220 	struct input_dev *inputdev;
221 	struct cmpc_accel *accel;
222 	unsigned long sensitivity;
223 	int r;
224 
225 	acpi = to_acpi_device(dev);
226 	inputdev = dev_get_drvdata(&acpi->dev);
227 	accel = dev_get_drvdata(&inputdev->dev);
228 
229 	r = kstrtoul(buf, 0, &sensitivity);
230 	if (r)
231 		return r;
232 
233 	/* sensitivity must be between 1 and 127 */
234 	if (sensitivity < 1 || sensitivity > 127)
235 		return -EINVAL;
236 
237 	accel->sensitivity = sensitivity;
238 	cmpc_accel_set_sensitivity_v4(acpi->handle, sensitivity);
239 
240 	return strnlen(buf, count);
241 }
242 
243 static struct device_attribute cmpc_accel_sensitivity_attr_v4 = {
244 	.attr = { .name = "sensitivity", .mode = 0660 },
245 	.show = cmpc_accel_sensitivity_show_v4,
246 	.store = cmpc_accel_sensitivity_store_v4
247 };
248 
249 static ssize_t cmpc_accel_g_select_show_v4(struct device *dev,
250 					   struct device_attribute *attr,
251 					   char *buf)
252 {
253 	struct acpi_device *acpi;
254 	struct input_dev *inputdev;
255 	struct cmpc_accel *accel;
256 
257 	acpi = to_acpi_device(dev);
258 	inputdev = dev_get_drvdata(&acpi->dev);
259 	accel = dev_get_drvdata(&inputdev->dev);
260 
261 	return sysfs_emit(buf, "%d\n", accel->g_select);
262 }
263 
264 static ssize_t cmpc_accel_g_select_store_v4(struct device *dev,
265 					    struct device_attribute *attr,
266 					    const char *buf, size_t count)
267 {
268 	struct acpi_device *acpi;
269 	struct input_dev *inputdev;
270 	struct cmpc_accel *accel;
271 	unsigned long g_select;
272 	int r;
273 
274 	acpi = to_acpi_device(dev);
275 	inputdev = dev_get_drvdata(&acpi->dev);
276 	accel = dev_get_drvdata(&inputdev->dev);
277 
278 	r = kstrtoul(buf, 0, &g_select);
279 	if (r)
280 		return r;
281 
282 	/* 0 means 1.5g, 1 means 6g, everything else is wrong */
283 	if (g_select != 0 && g_select != 1)
284 		return -EINVAL;
285 
286 	accel->g_select = g_select;
287 	cmpc_accel_set_g_select_v4(acpi->handle, g_select);
288 
289 	return strnlen(buf, count);
290 }
291 
292 static struct device_attribute cmpc_accel_g_select_attr_v4 = {
293 	.attr = { .name = "g_select", .mode = 0660 },
294 	.show = cmpc_accel_g_select_show_v4,
295 	.store = cmpc_accel_g_select_store_v4
296 };
297 
298 static int cmpc_accel_open_v4(struct input_dev *input)
299 {
300 	struct acpi_device *acpi;
301 	struct cmpc_accel *accel;
302 
303 	acpi = to_acpi_device(input->dev.parent);
304 	accel = dev_get_drvdata(&input->dev);
305 
306 	cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
307 	cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
308 
309 	if (ACPI_SUCCESS(cmpc_start_accel_v4(acpi->handle))) {
310 		accel->inputdev_state = CMPC_ACCEL_DEV_STATE_OPEN;
311 		return 0;
312 	}
313 	return -EIO;
314 }
315 
316 static void cmpc_accel_close_v4(struct input_dev *input)
317 {
318 	struct acpi_device *acpi;
319 	struct cmpc_accel *accel;
320 
321 	acpi = to_acpi_device(input->dev.parent);
322 	accel = dev_get_drvdata(&input->dev);
323 
324 	cmpc_stop_accel_v4(acpi->handle);
325 	accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
326 }
327 
328 static void cmpc_accel_idev_init_v4(struct input_dev *inputdev)
329 {
330 	set_bit(EV_ABS, inputdev->evbit);
331 	input_set_abs_params(inputdev, ABS_X, -255, 255, 16, 0);
332 	input_set_abs_params(inputdev, ABS_Y, -255, 255, 16, 0);
333 	input_set_abs_params(inputdev, ABS_Z, -255, 255, 16, 0);
334 	inputdev->open = cmpc_accel_open_v4;
335 	inputdev->close = cmpc_accel_close_v4;
336 }
337 
338 #ifdef CONFIG_PM_SLEEP
339 static int cmpc_accel_suspend_v4(struct device *dev)
340 {
341 	struct input_dev *inputdev;
342 	struct cmpc_accel *accel;
343 
344 	inputdev = dev_get_drvdata(dev);
345 	accel = dev_get_drvdata(&inputdev->dev);
346 
347 	if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN)
348 		return cmpc_stop_accel_v4(to_acpi_device(dev)->handle);
349 
350 	return 0;
351 }
352 
353 static int cmpc_accel_resume_v4(struct device *dev)
354 {
355 	struct input_dev *inputdev;
356 	struct cmpc_accel *accel;
357 
358 	inputdev = dev_get_drvdata(dev);
359 	accel = dev_get_drvdata(&inputdev->dev);
360 
361 	if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN) {
362 		cmpc_accel_set_sensitivity_v4(to_acpi_device(dev)->handle,
363 					      accel->sensitivity);
364 		cmpc_accel_set_g_select_v4(to_acpi_device(dev)->handle,
365 					   accel->g_select);
366 
367 		if (ACPI_FAILURE(cmpc_start_accel_v4(to_acpi_device(dev)->handle)))
368 			return -EIO;
369 	}
370 
371 	return 0;
372 }
373 #endif
374 
375 static int cmpc_accel_add_v4(struct acpi_device *acpi)
376 {
377 	int error;
378 	struct input_dev *inputdev;
379 	struct cmpc_accel *accel;
380 
381 	accel = kmalloc(sizeof(*accel), GFP_KERNEL);
382 	if (!accel)
383 		return -ENOMEM;
384 
385 	accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
386 
387 	accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
388 	cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
389 
390 	error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
391 	if (error)
392 		goto failed_sensitivity;
393 
394 	accel->g_select = CMPC_ACCEL_G_SELECT_DEFAULT;
395 	cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
396 
397 	error = device_create_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
398 	if (error)
399 		goto failed_g_select;
400 
401 	error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel_v4",
402 					    cmpc_accel_idev_init_v4);
403 	if (error)
404 		goto failed_input;
405 
406 	inputdev = dev_get_drvdata(&acpi->dev);
407 	dev_set_drvdata(&inputdev->dev, accel);
408 
409 	return 0;
410 
411 failed_input:
412 	device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
413 failed_g_select:
414 	device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
415 failed_sensitivity:
416 	kfree(accel);
417 	return error;
418 }
419 
420 static void cmpc_accel_remove_v4(struct acpi_device *acpi)
421 {
422 	device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
423 	device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
424 	cmpc_remove_acpi_notify_device(acpi);
425 }
426 
427 static SIMPLE_DEV_PM_OPS(cmpc_accel_pm, cmpc_accel_suspend_v4,
428 			 cmpc_accel_resume_v4);
429 
430 static const struct acpi_device_id cmpc_accel_device_ids_v4[] = {
431 	{CMPC_ACCEL_HID_V4, 0},
432 	{"", 0}
433 };
434 
435 static struct acpi_driver cmpc_accel_acpi_driver_v4 = {
436 	.name = "cmpc_accel_v4",
437 	.class = "cmpc_accel_v4",
438 	.ids = cmpc_accel_device_ids_v4,
439 	.ops = {
440 		.add = cmpc_accel_add_v4,
441 		.remove = cmpc_accel_remove_v4,
442 		.notify = cmpc_accel_handler_v4,
443 	},
444 	.drv.pm = &cmpc_accel_pm,
445 };
446 
447 
448 /*
449  * Accelerometer code for Classmate versions prior to V4
450  */
451 static acpi_status cmpc_start_accel(acpi_handle handle)
452 {
453 	union acpi_object param[2];
454 	struct acpi_object_list input;
455 	acpi_status status;
456 
457 	param[0].type = ACPI_TYPE_INTEGER;
458 	param[0].integer.value = 0x3;
459 	param[1].type = ACPI_TYPE_INTEGER;
460 	input.count = 2;
461 	input.pointer = param;
462 	status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
463 	return status;
464 }
465 
466 static acpi_status cmpc_stop_accel(acpi_handle handle)
467 {
468 	union acpi_object param[2];
469 	struct acpi_object_list input;
470 	acpi_status status;
471 
472 	param[0].type = ACPI_TYPE_INTEGER;
473 	param[0].integer.value = 0x4;
474 	param[1].type = ACPI_TYPE_INTEGER;
475 	input.count = 2;
476 	input.pointer = param;
477 	status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
478 	return status;
479 }
480 
481 static acpi_status cmpc_accel_set_sensitivity(acpi_handle handle, int val)
482 {
483 	union acpi_object param[2];
484 	struct acpi_object_list input;
485 
486 	param[0].type = ACPI_TYPE_INTEGER;
487 	param[0].integer.value = 0x02;
488 	param[1].type = ACPI_TYPE_INTEGER;
489 	param[1].integer.value = val;
490 	input.count = 2;
491 	input.pointer = param;
492 	return acpi_evaluate_object(handle, "ACMD", &input, NULL);
493 }
494 
495 static acpi_status cmpc_get_accel(acpi_handle handle,
496 				  unsigned char *x,
497 				  unsigned char *y,
498 				  unsigned char *z)
499 {
500 	union acpi_object param[2];
501 	struct acpi_object_list input;
502 	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
503 	unsigned char *locs;
504 	acpi_status status;
505 
506 	param[0].type = ACPI_TYPE_INTEGER;
507 	param[0].integer.value = 0x01;
508 	param[1].type = ACPI_TYPE_INTEGER;
509 	input.count = 2;
510 	input.pointer = param;
511 	status = acpi_evaluate_object(handle, "ACMD", &input, &output);
512 	if (ACPI_SUCCESS(status)) {
513 		union acpi_object *obj;
514 		obj = output.pointer;
515 		locs = obj->buffer.pointer;
516 		*x = locs[0];
517 		*y = locs[1];
518 		*z = locs[2];
519 		kfree(output.pointer);
520 	}
521 	return status;
522 }
523 
524 static void cmpc_accel_handler(struct acpi_device *dev, u32 event)
525 {
526 	if (event == 0x81) {
527 		unsigned char x, y, z;
528 		acpi_status status;
529 
530 		status = cmpc_get_accel(dev->handle, &x, &y, &z);
531 		if (ACPI_SUCCESS(status)) {
532 			struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
533 
534 			input_report_abs(inputdev, ABS_X, x);
535 			input_report_abs(inputdev, ABS_Y, y);
536 			input_report_abs(inputdev, ABS_Z, z);
537 			input_sync(inputdev);
538 		}
539 	}
540 }
541 
542 static ssize_t cmpc_accel_sensitivity_show(struct device *dev,
543 					   struct device_attribute *attr,
544 					   char *buf)
545 {
546 	struct acpi_device *acpi;
547 	struct input_dev *inputdev;
548 	struct cmpc_accel *accel;
549 
550 	acpi = to_acpi_device(dev);
551 	inputdev = dev_get_drvdata(&acpi->dev);
552 	accel = dev_get_drvdata(&inputdev->dev);
553 
554 	return sysfs_emit(buf, "%d\n", accel->sensitivity);
555 }
556 
557 static ssize_t cmpc_accel_sensitivity_store(struct device *dev,
558 					    struct device_attribute *attr,
559 					    const char *buf, size_t count)
560 {
561 	struct acpi_device *acpi;
562 	struct input_dev *inputdev;
563 	struct cmpc_accel *accel;
564 	unsigned long sensitivity;
565 	int r;
566 
567 	acpi = to_acpi_device(dev);
568 	inputdev = dev_get_drvdata(&acpi->dev);
569 	accel = dev_get_drvdata(&inputdev->dev);
570 
571 	r = kstrtoul(buf, 0, &sensitivity);
572 	if (r)
573 		return r;
574 
575 	accel->sensitivity = sensitivity;
576 	cmpc_accel_set_sensitivity(acpi->handle, sensitivity);
577 
578 	return strnlen(buf, count);
579 }
580 
581 static struct device_attribute cmpc_accel_sensitivity_attr = {
582 	.attr = { .name = "sensitivity", .mode = 0660 },
583 	.show = cmpc_accel_sensitivity_show,
584 	.store = cmpc_accel_sensitivity_store
585 };
586 
587 static int cmpc_accel_open(struct input_dev *input)
588 {
589 	struct acpi_device *acpi;
590 
591 	acpi = to_acpi_device(input->dev.parent);
592 	if (ACPI_SUCCESS(cmpc_start_accel(acpi->handle)))
593 		return 0;
594 	return -EIO;
595 }
596 
597 static void cmpc_accel_close(struct input_dev *input)
598 {
599 	struct acpi_device *acpi;
600 
601 	acpi = to_acpi_device(input->dev.parent);
602 	cmpc_stop_accel(acpi->handle);
603 }
604 
605 static void cmpc_accel_idev_init(struct input_dev *inputdev)
606 {
607 	set_bit(EV_ABS, inputdev->evbit);
608 	input_set_abs_params(inputdev, ABS_X, 0, 255, 8, 0);
609 	input_set_abs_params(inputdev, ABS_Y, 0, 255, 8, 0);
610 	input_set_abs_params(inputdev, ABS_Z, 0, 255, 8, 0);
611 	inputdev->open = cmpc_accel_open;
612 	inputdev->close = cmpc_accel_close;
613 }
614 
615 static int cmpc_accel_add(struct acpi_device *acpi)
616 {
617 	int error;
618 	struct input_dev *inputdev;
619 	struct cmpc_accel *accel;
620 
621 	accel = kmalloc(sizeof(*accel), GFP_KERNEL);
622 	if (!accel)
623 		return -ENOMEM;
624 
625 	accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
626 	cmpc_accel_set_sensitivity(acpi->handle, accel->sensitivity);
627 
628 	error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
629 	if (error)
630 		goto failed_file;
631 
632 	error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel",
633 					    cmpc_accel_idev_init);
634 	if (error)
635 		goto failed_input;
636 
637 	inputdev = dev_get_drvdata(&acpi->dev);
638 	dev_set_drvdata(&inputdev->dev, accel);
639 
640 	return 0;
641 
642 failed_input:
643 	device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
644 failed_file:
645 	kfree(accel);
646 	return error;
647 }
648 
649 static void cmpc_accel_remove(struct acpi_device *acpi)
650 {
651 	device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
652 	cmpc_remove_acpi_notify_device(acpi);
653 }
654 
655 static const struct acpi_device_id cmpc_accel_device_ids[] = {
656 	{CMPC_ACCEL_HID, 0},
657 	{"", 0}
658 };
659 
660 static struct acpi_driver cmpc_accel_acpi_driver = {
661 	.name = "cmpc_accel",
662 	.class = "cmpc_accel",
663 	.ids = cmpc_accel_device_ids,
664 	.ops = {
665 		.add = cmpc_accel_add,
666 		.remove = cmpc_accel_remove,
667 		.notify = cmpc_accel_handler,
668 	}
669 };
670 
671 
672 /*
673  * Tablet mode code.
674  */
675 static acpi_status cmpc_get_tablet(acpi_handle handle,
676 				   unsigned long long *value)
677 {
678 	union acpi_object param;
679 	struct acpi_object_list input;
680 	unsigned long long output;
681 	acpi_status status;
682 
683 	param.type = ACPI_TYPE_INTEGER;
684 	param.integer.value = 0x01;
685 	input.count = 1;
686 	input.pointer = &param;
687 	status = acpi_evaluate_integer(handle, "TCMD", &input, &output);
688 	if (ACPI_SUCCESS(status))
689 		*value = output;
690 	return status;
691 }
692 
693 static void cmpc_tablet_handler(struct acpi_device *dev, u32 event)
694 {
695 	unsigned long long val = 0;
696 	struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
697 
698 	if (event == 0x81) {
699 		if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val))) {
700 			input_report_switch(inputdev, SW_TABLET_MODE, !val);
701 			input_sync(inputdev);
702 		}
703 	}
704 }
705 
706 static void cmpc_tablet_idev_init(struct input_dev *inputdev)
707 {
708 	unsigned long long val = 0;
709 	struct acpi_device *acpi;
710 
711 	set_bit(EV_SW, inputdev->evbit);
712 	set_bit(SW_TABLET_MODE, inputdev->swbit);
713 
714 	acpi = to_acpi_device(inputdev->dev.parent);
715 	if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val))) {
716 		input_report_switch(inputdev, SW_TABLET_MODE, !val);
717 		input_sync(inputdev);
718 	}
719 }
720 
721 static int cmpc_tablet_add(struct acpi_device *acpi)
722 {
723 	return cmpc_add_acpi_notify_device(acpi, "cmpc_tablet",
724 					   cmpc_tablet_idev_init);
725 }
726 
727 static void cmpc_tablet_remove(struct acpi_device *acpi)
728 {
729 	cmpc_remove_acpi_notify_device(acpi);
730 }
731 
732 #ifdef CONFIG_PM_SLEEP
733 static int cmpc_tablet_resume(struct device *dev)
734 {
735 	struct input_dev *inputdev = dev_get_drvdata(dev);
736 
737 	unsigned long long val = 0;
738 	if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val))) {
739 		input_report_switch(inputdev, SW_TABLET_MODE, !val);
740 		input_sync(inputdev);
741 	}
742 	return 0;
743 }
744 #endif
745 
746 static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume);
747 
748 static const struct acpi_device_id cmpc_tablet_device_ids[] = {
749 	{CMPC_TABLET_HID, 0},
750 	{"", 0}
751 };
752 
753 static struct acpi_driver cmpc_tablet_acpi_driver = {
754 	.name = "cmpc_tablet",
755 	.class = "cmpc_tablet",
756 	.ids = cmpc_tablet_device_ids,
757 	.ops = {
758 		.add = cmpc_tablet_add,
759 		.remove = cmpc_tablet_remove,
760 		.notify = cmpc_tablet_handler,
761 	},
762 	.drv.pm = &cmpc_tablet_pm,
763 };
764 
765 
766 /*
767  * Backlight code.
768  */
769 
770 static acpi_status cmpc_get_brightness(acpi_handle handle,
771 				       unsigned long long *value)
772 {
773 	union acpi_object param;
774 	struct acpi_object_list input;
775 	unsigned long long output;
776 	acpi_status status;
777 
778 	param.type = ACPI_TYPE_INTEGER;
779 	param.integer.value = 0xC0;
780 	input.count = 1;
781 	input.pointer = &param;
782 	status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
783 	if (ACPI_SUCCESS(status))
784 		*value = output;
785 	return status;
786 }
787 
788 static acpi_status cmpc_set_brightness(acpi_handle handle,
789 				       unsigned long long value)
790 {
791 	union acpi_object param[2];
792 	struct acpi_object_list input;
793 	acpi_status status;
794 	unsigned long long output;
795 
796 	param[0].type = ACPI_TYPE_INTEGER;
797 	param[0].integer.value = 0xC0;
798 	param[1].type = ACPI_TYPE_INTEGER;
799 	param[1].integer.value = value;
800 	input.count = 2;
801 	input.pointer = param;
802 	status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
803 	return status;
804 }
805 
806 static int cmpc_bl_get_brightness(struct backlight_device *bd)
807 {
808 	acpi_status status;
809 	acpi_handle handle;
810 	unsigned long long brightness;
811 
812 	handle = bl_get_data(bd);
813 	status = cmpc_get_brightness(handle, &brightness);
814 	if (ACPI_SUCCESS(status))
815 		return brightness;
816 	else
817 		return -1;
818 }
819 
820 static int cmpc_bl_update_status(struct backlight_device *bd)
821 {
822 	acpi_status status;
823 	acpi_handle handle;
824 
825 	handle = bl_get_data(bd);
826 	status = cmpc_set_brightness(handle, bd->props.brightness);
827 	if (ACPI_SUCCESS(status))
828 		return 0;
829 	else
830 		return -1;
831 }
832 
833 static const struct backlight_ops cmpc_bl_ops = {
834 	.get_brightness = cmpc_bl_get_brightness,
835 	.update_status = cmpc_bl_update_status
836 };
837 
838 /*
839  * RFKILL code.
840  */
841 
842 static acpi_status cmpc_get_rfkill_wlan(acpi_handle handle,
843 					unsigned long long *value)
844 {
845 	union acpi_object param;
846 	struct acpi_object_list input;
847 	unsigned long long output;
848 	acpi_status status;
849 
850 	param.type = ACPI_TYPE_INTEGER;
851 	param.integer.value = 0xC1;
852 	input.count = 1;
853 	input.pointer = &param;
854 	status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
855 	if (ACPI_SUCCESS(status))
856 		*value = output;
857 	return status;
858 }
859 
860 static acpi_status cmpc_set_rfkill_wlan(acpi_handle handle,
861 					unsigned long long value)
862 {
863 	union acpi_object param[2];
864 	struct acpi_object_list input;
865 	acpi_status status;
866 	unsigned long long output;
867 
868 	param[0].type = ACPI_TYPE_INTEGER;
869 	param[0].integer.value = 0xC1;
870 	param[1].type = ACPI_TYPE_INTEGER;
871 	param[1].integer.value = value;
872 	input.count = 2;
873 	input.pointer = param;
874 	status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
875 	return status;
876 }
877 
878 static void cmpc_rfkill_query(struct rfkill *rfkill, void *data)
879 {
880 	acpi_status status;
881 	acpi_handle handle;
882 	unsigned long long state;
883 	bool blocked;
884 
885 	handle = data;
886 	status = cmpc_get_rfkill_wlan(handle, &state);
887 	if (ACPI_SUCCESS(status)) {
888 		blocked = state & 1 ? false : true;
889 		rfkill_set_sw_state(rfkill, blocked);
890 	}
891 }
892 
893 static int cmpc_rfkill_block(void *data, bool blocked)
894 {
895 	acpi_status status;
896 	acpi_handle handle;
897 	unsigned long long state;
898 	bool is_blocked;
899 
900 	handle = data;
901 	status = cmpc_get_rfkill_wlan(handle, &state);
902 	if (ACPI_FAILURE(status))
903 		return -ENODEV;
904 	/* Check if we really need to call cmpc_set_rfkill_wlan */
905 	is_blocked = state & 1 ? false : true;
906 	if (is_blocked != blocked) {
907 		state = blocked ? 0 : 1;
908 		status = cmpc_set_rfkill_wlan(handle, state);
909 		if (ACPI_FAILURE(status))
910 			return -ENODEV;
911 	}
912 	return 0;
913 }
914 
915 static const struct rfkill_ops cmpc_rfkill_ops = {
916 	.query = cmpc_rfkill_query,
917 	.set_block = cmpc_rfkill_block,
918 };
919 
920 /*
921  * Common backlight and rfkill code.
922  */
923 
924 struct ipml200_dev {
925 	struct backlight_device *bd;
926 	struct rfkill *rf;
927 };
928 
929 static int cmpc_ipml_add(struct acpi_device *acpi)
930 {
931 	int retval;
932 	struct ipml200_dev *ipml;
933 	struct backlight_properties props;
934 
935 	ipml = kmalloc(sizeof(*ipml), GFP_KERNEL);
936 	if (ipml == NULL)
937 		return -ENOMEM;
938 
939 	memset(&props, 0, sizeof(struct backlight_properties));
940 	props.type = BACKLIGHT_PLATFORM;
941 	props.max_brightness = 7;
942 	ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
943 					     acpi->handle, &cmpc_bl_ops,
944 					     &props);
945 	if (IS_ERR(ipml->bd)) {
946 		retval = PTR_ERR(ipml->bd);
947 		goto out_bd;
948 	}
949 
950 	ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
951 				&cmpc_rfkill_ops, acpi->handle);
952 	/*
953 	 * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV).
954 	 * This is OK, however, since all other uses of the device will not
955 	 * dereference it.
956 	 */
957 	if (ipml->rf) {
958 		retval = rfkill_register(ipml->rf);
959 		if (retval) {
960 			rfkill_destroy(ipml->rf);
961 			ipml->rf = NULL;
962 		}
963 	}
964 
965 	dev_set_drvdata(&acpi->dev, ipml);
966 	return 0;
967 
968 out_bd:
969 	kfree(ipml);
970 	return retval;
971 }
972 
973 static void cmpc_ipml_remove(struct acpi_device *acpi)
974 {
975 	struct ipml200_dev *ipml;
976 
977 	ipml = dev_get_drvdata(&acpi->dev);
978 
979 	backlight_device_unregister(ipml->bd);
980 
981 	if (ipml->rf) {
982 		rfkill_unregister(ipml->rf);
983 		rfkill_destroy(ipml->rf);
984 	}
985 
986 	kfree(ipml);
987 }
988 
989 static const struct acpi_device_id cmpc_ipml_device_ids[] = {
990 	{CMPC_IPML_HID, 0},
991 	{"", 0}
992 };
993 
994 static struct acpi_driver cmpc_ipml_acpi_driver = {
995 	.name = "cmpc",
996 	.class = "cmpc",
997 	.ids = cmpc_ipml_device_ids,
998 	.ops = {
999 		.add = cmpc_ipml_add,
1000 		.remove = cmpc_ipml_remove
1001 	}
1002 };
1003 
1004 
1005 /*
1006  * Extra keys code.
1007  */
1008 static int cmpc_keys_codes[] = {
1009 	KEY_UNKNOWN,
1010 	KEY_WLAN,
1011 	KEY_SWITCHVIDEOMODE,
1012 	KEY_BRIGHTNESSDOWN,
1013 	KEY_BRIGHTNESSUP,
1014 	KEY_VENDOR,
1015 	KEY_UNKNOWN,
1016 	KEY_CAMERA,
1017 	KEY_BACK,
1018 	KEY_FORWARD,
1019 	KEY_UNKNOWN,
1020 	KEY_WLAN, /* NL3: 0x8b (press), 0x9b (release) */
1021 	KEY_MAX
1022 };
1023 
1024 static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
1025 {
1026 	struct input_dev *inputdev;
1027 	int code = KEY_MAX;
1028 
1029 	if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
1030 		code = cmpc_keys_codes[event & 0x0F];
1031 	inputdev = dev_get_drvdata(&dev->dev);
1032 	input_report_key(inputdev, code, !(event & 0x10));
1033 	input_sync(inputdev);
1034 }
1035 
1036 static void cmpc_keys_idev_init(struct input_dev *inputdev)
1037 {
1038 	int i;
1039 
1040 	set_bit(EV_KEY, inputdev->evbit);
1041 	for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++)
1042 		set_bit(cmpc_keys_codes[i], inputdev->keybit);
1043 }
1044 
1045 static int cmpc_keys_add(struct acpi_device *acpi)
1046 {
1047 	return cmpc_add_acpi_notify_device(acpi, "cmpc_keys",
1048 					   cmpc_keys_idev_init);
1049 }
1050 
1051 static void cmpc_keys_remove(struct acpi_device *acpi)
1052 {
1053 	cmpc_remove_acpi_notify_device(acpi);
1054 }
1055 
1056 static const struct acpi_device_id cmpc_keys_device_ids[] = {
1057 	{CMPC_KEYS_HID, 0},
1058 	{"", 0}
1059 };
1060 
1061 static struct acpi_driver cmpc_keys_acpi_driver = {
1062 	.name = "cmpc_keys",
1063 	.class = "cmpc_keys",
1064 	.ids = cmpc_keys_device_ids,
1065 	.ops = {
1066 		.add = cmpc_keys_add,
1067 		.remove = cmpc_keys_remove,
1068 		.notify = cmpc_keys_handler,
1069 	}
1070 };
1071 
1072 
1073 /*
1074  * General init/exit code.
1075  */
1076 
1077 static int cmpc_init(void)
1078 {
1079 	int r;
1080 
1081 	r = acpi_bus_register_driver(&cmpc_keys_acpi_driver);
1082 	if (r)
1083 		goto failed_keys;
1084 
1085 	r = acpi_bus_register_driver(&cmpc_ipml_acpi_driver);
1086 	if (r)
1087 		goto failed_bl;
1088 
1089 	r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver);
1090 	if (r)
1091 		goto failed_tablet;
1092 
1093 	r = acpi_bus_register_driver(&cmpc_accel_acpi_driver);
1094 	if (r)
1095 		goto failed_accel;
1096 
1097 	r = acpi_bus_register_driver(&cmpc_accel_acpi_driver_v4);
1098 	if (r)
1099 		goto failed_accel_v4;
1100 
1101 	return r;
1102 
1103 failed_accel_v4:
1104 	acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
1105 
1106 failed_accel:
1107 	acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
1108 
1109 failed_tablet:
1110 	acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
1111 
1112 failed_bl:
1113 	acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
1114 
1115 failed_keys:
1116 	return r;
1117 }
1118 
1119 static void cmpc_exit(void)
1120 {
1121 	acpi_bus_unregister_driver(&cmpc_accel_acpi_driver_v4);
1122 	acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
1123 	acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
1124 	acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
1125 	acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
1126 }
1127 
1128 module_init(cmpc_init);
1129 module_exit(cmpc_exit);
1130 
1131 static const struct acpi_device_id cmpc_device_ids[] __maybe_unused = {
1132 	{CMPC_ACCEL_HID, 0},
1133 	{CMPC_ACCEL_HID_V4, 0},
1134 	{CMPC_TABLET_HID, 0},
1135 	{CMPC_IPML_HID, 0},
1136 	{CMPC_KEYS_HID, 0},
1137 	{"", 0}
1138 };
1139 
1140 MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);
1141 MODULE_DESCRIPTION("Support for Intel Classmate PC ACPI devices");
1142 MODULE_LICENSE("GPL");
1143