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