drm/panfrost: Move gpu_{write, read}() macros to panfrost_regs.h
[linux/fpc-iii.git] / drivers / platform / x86 / classmate-laptop.c
blob86cc2cc68fb51b48d6f1308ff1dfff736e4eb2a5
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2009 Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
4 */
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>
16 MODULE_LICENSE("GPL");
18 struct cmpc_accel {
19 int sensitivity;
20 int g_select;
21 int inputdev_state;
24 #define CMPC_ACCEL_DEV_STATE_CLOSED 0
25 #define CMPC_ACCEL_DEV_STATE_OPEN 1
27 #define CMPC_ACCEL_SENSITIVITY_DEFAULT 5
28 #define CMPC_ACCEL_G_SELECT_DEFAULT 0
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"
37 * Generic input device code.
40 typedef void (*input_device_init)(struct input_dev *dev);
42 static int cmpc_add_acpi_notify_device(struct acpi_device *acpi, char *name,
43 input_device_init idev_init)
45 struct input_dev *inputdev;
46 int error;
48 inputdev = input_allocate_device();
49 if (!inputdev)
50 return -ENOMEM;
51 inputdev->name = name;
52 inputdev->dev.parent = &acpi->dev;
53 idev_init(inputdev);
54 error = input_register_device(inputdev);
55 if (error) {
56 input_free_device(inputdev);
57 return error;
59 dev_set_drvdata(&acpi->dev, inputdev);
60 return 0;
63 static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi)
65 struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
66 input_unregister_device(inputdev);
67 return 0;
71 * Accelerometer code for Classmate V4
73 static acpi_status cmpc_start_accel_v4(acpi_handle handle)
75 union acpi_object param[4];
76 struct acpi_object_list input;
77 acpi_status status;
79 param[0].type = ACPI_TYPE_INTEGER;
80 param[0].integer.value = 0x3;
81 param[1].type = ACPI_TYPE_INTEGER;
82 param[1].integer.value = 0;
83 param[2].type = ACPI_TYPE_INTEGER;
84 param[2].integer.value = 0;
85 param[3].type = ACPI_TYPE_INTEGER;
86 param[3].integer.value = 0;
87 input.count = 4;
88 input.pointer = param;
89 status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
90 return status;
93 static acpi_status cmpc_stop_accel_v4(acpi_handle handle)
95 union acpi_object param[4];
96 struct acpi_object_list input;
97 acpi_status status;
99 param[0].type = ACPI_TYPE_INTEGER;
100 param[0].integer.value = 0x4;
101 param[1].type = ACPI_TYPE_INTEGER;
102 param[1].integer.value = 0;
103 param[2].type = ACPI_TYPE_INTEGER;
104 param[2].integer.value = 0;
105 param[3].type = ACPI_TYPE_INTEGER;
106 param[3].integer.value = 0;
107 input.count = 4;
108 input.pointer = param;
109 status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
110 return status;
113 static acpi_status cmpc_accel_set_sensitivity_v4(acpi_handle handle, int val)
115 union acpi_object param[4];
116 struct acpi_object_list input;
118 param[0].type = ACPI_TYPE_INTEGER;
119 param[0].integer.value = 0x02;
120 param[1].type = ACPI_TYPE_INTEGER;
121 param[1].integer.value = val;
122 param[2].type = ACPI_TYPE_INTEGER;
123 param[2].integer.value = 0;
124 param[3].type = ACPI_TYPE_INTEGER;
125 param[3].integer.value = 0;
126 input.count = 4;
127 input.pointer = param;
128 return acpi_evaluate_object(handle, "ACMD", &input, NULL);
131 static acpi_status cmpc_accel_set_g_select_v4(acpi_handle handle, int val)
133 union acpi_object param[4];
134 struct acpi_object_list input;
136 param[0].type = ACPI_TYPE_INTEGER;
137 param[0].integer.value = 0x05;
138 param[1].type = ACPI_TYPE_INTEGER;
139 param[1].integer.value = val;
140 param[2].type = ACPI_TYPE_INTEGER;
141 param[2].integer.value = 0;
142 param[3].type = ACPI_TYPE_INTEGER;
143 param[3].integer.value = 0;
144 input.count = 4;
145 input.pointer = param;
146 return acpi_evaluate_object(handle, "ACMD", &input, NULL);
149 static acpi_status cmpc_get_accel_v4(acpi_handle handle,
150 int16_t *x,
151 int16_t *y,
152 int16_t *z)
154 union acpi_object param[4];
155 struct acpi_object_list input;
156 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
157 int16_t *locs;
158 acpi_status status;
160 param[0].type = ACPI_TYPE_INTEGER;
161 param[0].integer.value = 0x01;
162 param[1].type = ACPI_TYPE_INTEGER;
163 param[1].integer.value = 0;
164 param[2].type = ACPI_TYPE_INTEGER;
165 param[2].integer.value = 0;
166 param[3].type = ACPI_TYPE_INTEGER;
167 param[3].integer.value = 0;
168 input.count = 4;
169 input.pointer = param;
170 status = acpi_evaluate_object(handle, "ACMD", &input, &output);
171 if (ACPI_SUCCESS(status)) {
172 union acpi_object *obj;
173 obj = output.pointer;
174 locs = (int16_t *) obj->buffer.pointer;
175 *x = locs[0];
176 *y = locs[1];
177 *z = locs[2];
178 kfree(output.pointer);
180 return status;
183 static void cmpc_accel_handler_v4(struct acpi_device *dev, u32 event)
185 if (event == 0x81) {
186 int16_t x, y, z;
187 acpi_status status;
189 status = cmpc_get_accel_v4(dev->handle, &x, &y, &z);
190 if (ACPI_SUCCESS(status)) {
191 struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
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);
201 static ssize_t cmpc_accel_sensitivity_show_v4(struct device *dev,
202 struct device_attribute *attr,
203 char *buf)
205 struct acpi_device *acpi;
206 struct input_dev *inputdev;
207 struct cmpc_accel *accel;
209 acpi = to_acpi_device(dev);
210 inputdev = dev_get_drvdata(&acpi->dev);
211 accel = dev_get_drvdata(&inputdev->dev);
213 return sprintf(buf, "%d\n", accel->sensitivity);
216 static ssize_t cmpc_accel_sensitivity_store_v4(struct device *dev,
217 struct device_attribute *attr,
218 const char *buf, size_t count)
220 struct acpi_device *acpi;
221 struct input_dev *inputdev;
222 struct cmpc_accel *accel;
223 unsigned long sensitivity;
224 int r;
226 acpi = to_acpi_device(dev);
227 inputdev = dev_get_drvdata(&acpi->dev);
228 accel = dev_get_drvdata(&inputdev->dev);
230 r = kstrtoul(buf, 0, &sensitivity);
231 if (r)
232 return r;
234 /* sensitivity must be between 1 and 127 */
235 if (sensitivity < 1 || sensitivity > 127)
236 return -EINVAL;
238 accel->sensitivity = sensitivity;
239 cmpc_accel_set_sensitivity_v4(acpi->handle, sensitivity);
241 return strnlen(buf, count);
244 static struct device_attribute cmpc_accel_sensitivity_attr_v4 = {
245 .attr = { .name = "sensitivity", .mode = 0660 },
246 .show = cmpc_accel_sensitivity_show_v4,
247 .store = cmpc_accel_sensitivity_store_v4
250 static ssize_t cmpc_accel_g_select_show_v4(struct device *dev,
251 struct device_attribute *attr,
252 char *buf)
254 struct acpi_device *acpi;
255 struct input_dev *inputdev;
256 struct cmpc_accel *accel;
258 acpi = to_acpi_device(dev);
259 inputdev = dev_get_drvdata(&acpi->dev);
260 accel = dev_get_drvdata(&inputdev->dev);
262 return sprintf(buf, "%d\n", accel->g_select);
265 static ssize_t cmpc_accel_g_select_store_v4(struct device *dev,
266 struct device_attribute *attr,
267 const char *buf, size_t count)
269 struct acpi_device *acpi;
270 struct input_dev *inputdev;
271 struct cmpc_accel *accel;
272 unsigned long g_select;
273 int r;
275 acpi = to_acpi_device(dev);
276 inputdev = dev_get_drvdata(&acpi->dev);
277 accel = dev_get_drvdata(&inputdev->dev);
279 r = kstrtoul(buf, 0, &g_select);
280 if (r)
281 return r;
283 /* 0 means 1.5g, 1 means 6g, everything else is wrong */
284 if (g_select != 0 && g_select != 1)
285 return -EINVAL;
287 accel->g_select = g_select;
288 cmpc_accel_set_g_select_v4(acpi->handle, g_select);
290 return strnlen(buf, count);
293 static struct device_attribute cmpc_accel_g_select_attr_v4 = {
294 .attr = { .name = "g_select", .mode = 0660 },
295 .show = cmpc_accel_g_select_show_v4,
296 .store = cmpc_accel_g_select_store_v4
299 static int cmpc_accel_open_v4(struct input_dev *input)
301 struct acpi_device *acpi;
302 struct cmpc_accel *accel;
304 acpi = to_acpi_device(input->dev.parent);
305 accel = dev_get_drvdata(&input->dev);
307 cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
308 cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
310 if (ACPI_SUCCESS(cmpc_start_accel_v4(acpi->handle))) {
311 accel->inputdev_state = CMPC_ACCEL_DEV_STATE_OPEN;
312 return 0;
314 return -EIO;
317 static void cmpc_accel_close_v4(struct input_dev *input)
319 struct acpi_device *acpi;
320 struct cmpc_accel *accel;
322 acpi = to_acpi_device(input->dev.parent);
323 accel = dev_get_drvdata(&input->dev);
325 cmpc_stop_accel_v4(acpi->handle);
326 accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
329 static void cmpc_accel_idev_init_v4(struct input_dev *inputdev)
331 set_bit(EV_ABS, inputdev->evbit);
332 input_set_abs_params(inputdev, ABS_X, -255, 255, 16, 0);
333 input_set_abs_params(inputdev, ABS_Y, -255, 255, 16, 0);
334 input_set_abs_params(inputdev, ABS_Z, -255, 255, 16, 0);
335 inputdev->open = cmpc_accel_open_v4;
336 inputdev->close = cmpc_accel_close_v4;
339 #ifdef CONFIG_PM_SLEEP
340 static int cmpc_accel_suspend_v4(struct device *dev)
342 struct input_dev *inputdev;
343 struct cmpc_accel *accel;
345 inputdev = dev_get_drvdata(dev);
346 accel = dev_get_drvdata(&inputdev->dev);
348 if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN)
349 return cmpc_stop_accel_v4(to_acpi_device(dev)->handle);
351 return 0;
354 static int cmpc_accel_resume_v4(struct device *dev)
356 struct input_dev *inputdev;
357 struct cmpc_accel *accel;
359 inputdev = dev_get_drvdata(dev);
360 accel = dev_get_drvdata(&inputdev->dev);
362 if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN) {
363 cmpc_accel_set_sensitivity_v4(to_acpi_device(dev)->handle,
364 accel->sensitivity);
365 cmpc_accel_set_g_select_v4(to_acpi_device(dev)->handle,
366 accel->g_select);
368 if (ACPI_FAILURE(cmpc_start_accel_v4(to_acpi_device(dev)->handle)))
369 return -EIO;
372 return 0;
374 #endif
376 static int cmpc_accel_add_v4(struct acpi_device *acpi)
378 int error;
379 struct input_dev *inputdev;
380 struct cmpc_accel *accel;
382 accel = kmalloc(sizeof(*accel), GFP_KERNEL);
383 if (!accel)
384 return -ENOMEM;
386 accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED;
388 accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
389 cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity);
391 error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
392 if (error)
393 goto failed_sensitivity;
395 accel->g_select = CMPC_ACCEL_G_SELECT_DEFAULT;
396 cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select);
398 error = device_create_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
399 if (error)
400 goto failed_g_select;
402 error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel_v4",
403 cmpc_accel_idev_init_v4);
404 if (error)
405 goto failed_input;
407 inputdev = dev_get_drvdata(&acpi->dev);
408 dev_set_drvdata(&inputdev->dev, accel);
410 return 0;
412 failed_input:
413 device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
414 failed_g_select:
415 device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
416 failed_sensitivity:
417 kfree(accel);
418 return error;
421 static int cmpc_accel_remove_v4(struct acpi_device *acpi)
423 struct input_dev *inputdev;
424 struct cmpc_accel *accel;
426 inputdev = dev_get_drvdata(&acpi->dev);
427 accel = dev_get_drvdata(&inputdev->dev);
429 device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4);
430 device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4);
431 return cmpc_remove_acpi_notify_device(acpi);
434 static SIMPLE_DEV_PM_OPS(cmpc_accel_pm, cmpc_accel_suspend_v4,
435 cmpc_accel_resume_v4);
437 static const struct acpi_device_id cmpc_accel_device_ids_v4[] = {
438 {CMPC_ACCEL_HID_V4, 0},
439 {"", 0}
442 static struct acpi_driver cmpc_accel_acpi_driver_v4 = {
443 .owner = THIS_MODULE,
444 .name = "cmpc_accel_v4",
445 .class = "cmpc_accel_v4",
446 .ids = cmpc_accel_device_ids_v4,
447 .ops = {
448 .add = cmpc_accel_add_v4,
449 .remove = cmpc_accel_remove_v4,
450 .notify = cmpc_accel_handler_v4,
452 .drv.pm = &cmpc_accel_pm,
457 * Accelerometer code for Classmate versions prior to V4
459 static acpi_status cmpc_start_accel(acpi_handle handle)
461 union acpi_object param[2];
462 struct acpi_object_list input;
463 acpi_status status;
465 param[0].type = ACPI_TYPE_INTEGER;
466 param[0].integer.value = 0x3;
467 param[1].type = ACPI_TYPE_INTEGER;
468 input.count = 2;
469 input.pointer = param;
470 status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
471 return status;
474 static acpi_status cmpc_stop_accel(acpi_handle handle)
476 union acpi_object param[2];
477 struct acpi_object_list input;
478 acpi_status status;
480 param[0].type = ACPI_TYPE_INTEGER;
481 param[0].integer.value = 0x4;
482 param[1].type = ACPI_TYPE_INTEGER;
483 input.count = 2;
484 input.pointer = param;
485 status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
486 return status;
489 static acpi_status cmpc_accel_set_sensitivity(acpi_handle handle, int val)
491 union acpi_object param[2];
492 struct acpi_object_list input;
494 param[0].type = ACPI_TYPE_INTEGER;
495 param[0].integer.value = 0x02;
496 param[1].type = ACPI_TYPE_INTEGER;
497 param[1].integer.value = val;
498 input.count = 2;
499 input.pointer = param;
500 return acpi_evaluate_object(handle, "ACMD", &input, NULL);
503 static acpi_status cmpc_get_accel(acpi_handle handle,
504 unsigned char *x,
505 unsigned char *y,
506 unsigned char *z)
508 union acpi_object param[2];
509 struct acpi_object_list input;
510 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
511 unsigned char *locs;
512 acpi_status status;
514 param[0].type = ACPI_TYPE_INTEGER;
515 param[0].integer.value = 0x01;
516 param[1].type = ACPI_TYPE_INTEGER;
517 input.count = 2;
518 input.pointer = param;
519 status = acpi_evaluate_object(handle, "ACMD", &input, &output);
520 if (ACPI_SUCCESS(status)) {
521 union acpi_object *obj;
522 obj = output.pointer;
523 locs = obj->buffer.pointer;
524 *x = locs[0];
525 *y = locs[1];
526 *z = locs[2];
527 kfree(output.pointer);
529 return status;
532 static void cmpc_accel_handler(struct acpi_device *dev, u32 event)
534 if (event == 0x81) {
535 unsigned char x, y, z;
536 acpi_status status;
538 status = cmpc_get_accel(dev->handle, &x, &y, &z);
539 if (ACPI_SUCCESS(status)) {
540 struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
542 input_report_abs(inputdev, ABS_X, x);
543 input_report_abs(inputdev, ABS_Y, y);
544 input_report_abs(inputdev, ABS_Z, z);
545 input_sync(inputdev);
550 static ssize_t cmpc_accel_sensitivity_show(struct device *dev,
551 struct device_attribute *attr,
552 char *buf)
554 struct acpi_device *acpi;
555 struct input_dev *inputdev;
556 struct cmpc_accel *accel;
558 acpi = to_acpi_device(dev);
559 inputdev = dev_get_drvdata(&acpi->dev);
560 accel = dev_get_drvdata(&inputdev->dev);
562 return sprintf(buf, "%d\n", accel->sensitivity);
565 static ssize_t cmpc_accel_sensitivity_store(struct device *dev,
566 struct device_attribute *attr,
567 const char *buf, size_t count)
569 struct acpi_device *acpi;
570 struct input_dev *inputdev;
571 struct cmpc_accel *accel;
572 unsigned long sensitivity;
573 int r;
575 acpi = to_acpi_device(dev);
576 inputdev = dev_get_drvdata(&acpi->dev);
577 accel = dev_get_drvdata(&inputdev->dev);
579 r = kstrtoul(buf, 0, &sensitivity);
580 if (r)
581 return r;
583 accel->sensitivity = sensitivity;
584 cmpc_accel_set_sensitivity(acpi->handle, sensitivity);
586 return strnlen(buf, count);
589 static struct device_attribute cmpc_accel_sensitivity_attr = {
590 .attr = { .name = "sensitivity", .mode = 0660 },
591 .show = cmpc_accel_sensitivity_show,
592 .store = cmpc_accel_sensitivity_store
595 static int cmpc_accel_open(struct input_dev *input)
597 struct acpi_device *acpi;
599 acpi = to_acpi_device(input->dev.parent);
600 if (ACPI_SUCCESS(cmpc_start_accel(acpi->handle)))
601 return 0;
602 return -EIO;
605 static void cmpc_accel_close(struct input_dev *input)
607 struct acpi_device *acpi;
609 acpi = to_acpi_device(input->dev.parent);
610 cmpc_stop_accel(acpi->handle);
613 static void cmpc_accel_idev_init(struct input_dev *inputdev)
615 set_bit(EV_ABS, inputdev->evbit);
616 input_set_abs_params(inputdev, ABS_X, 0, 255, 8, 0);
617 input_set_abs_params(inputdev, ABS_Y, 0, 255, 8, 0);
618 input_set_abs_params(inputdev, ABS_Z, 0, 255, 8, 0);
619 inputdev->open = cmpc_accel_open;
620 inputdev->close = cmpc_accel_close;
623 static int cmpc_accel_add(struct acpi_device *acpi)
625 int error;
626 struct input_dev *inputdev;
627 struct cmpc_accel *accel;
629 accel = kmalloc(sizeof(*accel), GFP_KERNEL);
630 if (!accel)
631 return -ENOMEM;
633 accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
634 cmpc_accel_set_sensitivity(acpi->handle, accel->sensitivity);
636 error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
637 if (error)
638 goto failed_file;
640 error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel",
641 cmpc_accel_idev_init);
642 if (error)
643 goto failed_input;
645 inputdev = dev_get_drvdata(&acpi->dev);
646 dev_set_drvdata(&inputdev->dev, accel);
648 return 0;
650 failed_input:
651 device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
652 failed_file:
653 kfree(accel);
654 return error;
657 static int cmpc_accel_remove(struct acpi_device *acpi)
659 struct input_dev *inputdev;
660 struct cmpc_accel *accel;
662 inputdev = dev_get_drvdata(&acpi->dev);
663 accel = dev_get_drvdata(&inputdev->dev);
665 device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
666 return cmpc_remove_acpi_notify_device(acpi);
669 static const struct acpi_device_id cmpc_accel_device_ids[] = {
670 {CMPC_ACCEL_HID, 0},
671 {"", 0}
674 static struct acpi_driver cmpc_accel_acpi_driver = {
675 .owner = THIS_MODULE,
676 .name = "cmpc_accel",
677 .class = "cmpc_accel",
678 .ids = cmpc_accel_device_ids,
679 .ops = {
680 .add = cmpc_accel_add,
681 .remove = cmpc_accel_remove,
682 .notify = cmpc_accel_handler,
688 * Tablet mode code.
690 static acpi_status cmpc_get_tablet(acpi_handle handle,
691 unsigned long long *value)
693 union acpi_object param;
694 struct acpi_object_list input;
695 unsigned long long output;
696 acpi_status status;
698 param.type = ACPI_TYPE_INTEGER;
699 param.integer.value = 0x01;
700 input.count = 1;
701 input.pointer = &param;
702 status = acpi_evaluate_integer(handle, "TCMD", &input, &output);
703 if (ACPI_SUCCESS(status))
704 *value = output;
705 return status;
708 static void cmpc_tablet_handler(struct acpi_device *dev, u32 event)
710 unsigned long long val = 0;
711 struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
713 if (event == 0x81) {
714 if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val))) {
715 input_report_switch(inputdev, SW_TABLET_MODE, !val);
716 input_sync(inputdev);
721 static void cmpc_tablet_idev_init(struct input_dev *inputdev)
723 unsigned long long val = 0;
724 struct acpi_device *acpi;
726 set_bit(EV_SW, inputdev->evbit);
727 set_bit(SW_TABLET_MODE, inputdev->swbit);
729 acpi = to_acpi_device(inputdev->dev.parent);
730 if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val))) {
731 input_report_switch(inputdev, SW_TABLET_MODE, !val);
732 input_sync(inputdev);
736 static int cmpc_tablet_add(struct acpi_device *acpi)
738 return cmpc_add_acpi_notify_device(acpi, "cmpc_tablet",
739 cmpc_tablet_idev_init);
742 static int cmpc_tablet_remove(struct acpi_device *acpi)
744 return cmpc_remove_acpi_notify_device(acpi);
747 #ifdef CONFIG_PM_SLEEP
748 static int cmpc_tablet_resume(struct device *dev)
750 struct input_dev *inputdev = dev_get_drvdata(dev);
752 unsigned long long val = 0;
753 if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val))) {
754 input_report_switch(inputdev, SW_TABLET_MODE, !val);
755 input_sync(inputdev);
757 return 0;
759 #endif
761 static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume);
763 static const struct acpi_device_id cmpc_tablet_device_ids[] = {
764 {CMPC_TABLET_HID, 0},
765 {"", 0}
768 static struct acpi_driver cmpc_tablet_acpi_driver = {
769 .owner = THIS_MODULE,
770 .name = "cmpc_tablet",
771 .class = "cmpc_tablet",
772 .ids = cmpc_tablet_device_ids,
773 .ops = {
774 .add = cmpc_tablet_add,
775 .remove = cmpc_tablet_remove,
776 .notify = cmpc_tablet_handler,
778 .drv.pm = &cmpc_tablet_pm,
783 * Backlight code.
786 static acpi_status cmpc_get_brightness(acpi_handle handle,
787 unsigned long long *value)
789 union acpi_object param;
790 struct acpi_object_list input;
791 unsigned long long output;
792 acpi_status status;
794 param.type = ACPI_TYPE_INTEGER;
795 param.integer.value = 0xC0;
796 input.count = 1;
797 input.pointer = &param;
798 status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
799 if (ACPI_SUCCESS(status))
800 *value = output;
801 return status;
804 static acpi_status cmpc_set_brightness(acpi_handle handle,
805 unsigned long long value)
807 union acpi_object param[2];
808 struct acpi_object_list input;
809 acpi_status status;
810 unsigned long long output;
812 param[0].type = ACPI_TYPE_INTEGER;
813 param[0].integer.value = 0xC0;
814 param[1].type = ACPI_TYPE_INTEGER;
815 param[1].integer.value = value;
816 input.count = 2;
817 input.pointer = param;
818 status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
819 return status;
822 static int cmpc_bl_get_brightness(struct backlight_device *bd)
824 acpi_status status;
825 acpi_handle handle;
826 unsigned long long brightness;
828 handle = bl_get_data(bd);
829 status = cmpc_get_brightness(handle, &brightness);
830 if (ACPI_SUCCESS(status))
831 return brightness;
832 else
833 return -1;
836 static int cmpc_bl_update_status(struct backlight_device *bd)
838 acpi_status status;
839 acpi_handle handle;
841 handle = bl_get_data(bd);
842 status = cmpc_set_brightness(handle, bd->props.brightness);
843 if (ACPI_SUCCESS(status))
844 return 0;
845 else
846 return -1;
849 static const struct backlight_ops cmpc_bl_ops = {
850 .get_brightness = cmpc_bl_get_brightness,
851 .update_status = cmpc_bl_update_status
855 * RFKILL code.
858 static acpi_status cmpc_get_rfkill_wlan(acpi_handle handle,
859 unsigned long long *value)
861 union acpi_object param;
862 struct acpi_object_list input;
863 unsigned long long output;
864 acpi_status status;
866 param.type = ACPI_TYPE_INTEGER;
867 param.integer.value = 0xC1;
868 input.count = 1;
869 input.pointer = &param;
870 status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
871 if (ACPI_SUCCESS(status))
872 *value = output;
873 return status;
876 static acpi_status cmpc_set_rfkill_wlan(acpi_handle handle,
877 unsigned long long value)
879 union acpi_object param[2];
880 struct acpi_object_list input;
881 acpi_status status;
882 unsigned long long output;
884 param[0].type = ACPI_TYPE_INTEGER;
885 param[0].integer.value = 0xC1;
886 param[1].type = ACPI_TYPE_INTEGER;
887 param[1].integer.value = value;
888 input.count = 2;
889 input.pointer = param;
890 status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
891 return status;
894 static void cmpc_rfkill_query(struct rfkill *rfkill, void *data)
896 acpi_status status;
897 acpi_handle handle;
898 unsigned long long state;
899 bool blocked;
901 handle = data;
902 status = cmpc_get_rfkill_wlan(handle, &state);
903 if (ACPI_SUCCESS(status)) {
904 blocked = state & 1 ? false : true;
905 rfkill_set_sw_state(rfkill, blocked);
909 static int cmpc_rfkill_block(void *data, bool blocked)
911 acpi_status status;
912 acpi_handle handle;
913 unsigned long long state;
914 bool is_blocked;
916 handle = data;
917 status = cmpc_get_rfkill_wlan(handle, &state);
918 if (ACPI_FAILURE(status))
919 return -ENODEV;
920 /* Check if we really need to call cmpc_set_rfkill_wlan */
921 is_blocked = state & 1 ? false : true;
922 if (is_blocked != blocked) {
923 state = blocked ? 0 : 1;
924 status = cmpc_set_rfkill_wlan(handle, state);
925 if (ACPI_FAILURE(status))
926 return -ENODEV;
928 return 0;
931 static const struct rfkill_ops cmpc_rfkill_ops = {
932 .query = cmpc_rfkill_query,
933 .set_block = cmpc_rfkill_block,
937 * Common backlight and rfkill code.
940 struct ipml200_dev {
941 struct backlight_device *bd;
942 struct rfkill *rf;
945 static int cmpc_ipml_add(struct acpi_device *acpi)
947 int retval;
948 struct ipml200_dev *ipml;
949 struct backlight_properties props;
951 ipml = kmalloc(sizeof(*ipml), GFP_KERNEL);
952 if (ipml == NULL)
953 return -ENOMEM;
955 memset(&props, 0, sizeof(struct backlight_properties));
956 props.type = BACKLIGHT_PLATFORM;
957 props.max_brightness = 7;
958 ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
959 acpi->handle, &cmpc_bl_ops,
960 &props);
961 if (IS_ERR(ipml->bd)) {
962 retval = PTR_ERR(ipml->bd);
963 goto out_bd;
966 ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
967 &cmpc_rfkill_ops, acpi->handle);
969 * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV).
970 * This is OK, however, since all other uses of the device will not
971 * derefence it.
973 if (ipml->rf) {
974 retval = rfkill_register(ipml->rf);
975 if (retval) {
976 rfkill_destroy(ipml->rf);
977 ipml->rf = NULL;
981 dev_set_drvdata(&acpi->dev, ipml);
982 return 0;
984 out_bd:
985 kfree(ipml);
986 return retval;
989 static int cmpc_ipml_remove(struct acpi_device *acpi)
991 struct ipml200_dev *ipml;
993 ipml = dev_get_drvdata(&acpi->dev);
995 backlight_device_unregister(ipml->bd);
997 if (ipml->rf) {
998 rfkill_unregister(ipml->rf);
999 rfkill_destroy(ipml->rf);
1002 kfree(ipml);
1004 return 0;
1007 static const struct acpi_device_id cmpc_ipml_device_ids[] = {
1008 {CMPC_IPML_HID, 0},
1009 {"", 0}
1012 static struct acpi_driver cmpc_ipml_acpi_driver = {
1013 .owner = THIS_MODULE,
1014 .name = "cmpc",
1015 .class = "cmpc",
1016 .ids = cmpc_ipml_device_ids,
1017 .ops = {
1018 .add = cmpc_ipml_add,
1019 .remove = cmpc_ipml_remove
1025 * Extra keys code.
1027 static int cmpc_keys_codes[] = {
1028 KEY_UNKNOWN,
1029 KEY_WLAN,
1030 KEY_SWITCHVIDEOMODE,
1031 KEY_BRIGHTNESSDOWN,
1032 KEY_BRIGHTNESSUP,
1033 KEY_VENDOR,
1034 KEY_UNKNOWN,
1035 KEY_CAMERA,
1036 KEY_BACK,
1037 KEY_FORWARD,
1038 KEY_MAX
1041 static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
1043 struct input_dev *inputdev;
1044 int code = KEY_MAX;
1046 if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
1047 code = cmpc_keys_codes[event & 0x0F];
1048 inputdev = dev_get_drvdata(&dev->dev);
1049 input_report_key(inputdev, code, !(event & 0x10));
1050 input_sync(inputdev);
1053 static void cmpc_keys_idev_init(struct input_dev *inputdev)
1055 int i;
1057 set_bit(EV_KEY, inputdev->evbit);
1058 for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++)
1059 set_bit(cmpc_keys_codes[i], inputdev->keybit);
1062 static int cmpc_keys_add(struct acpi_device *acpi)
1064 return cmpc_add_acpi_notify_device(acpi, "cmpc_keys",
1065 cmpc_keys_idev_init);
1068 static int cmpc_keys_remove(struct acpi_device *acpi)
1070 return cmpc_remove_acpi_notify_device(acpi);
1073 static const struct acpi_device_id cmpc_keys_device_ids[] = {
1074 {CMPC_KEYS_HID, 0},
1075 {"", 0}
1078 static struct acpi_driver cmpc_keys_acpi_driver = {
1079 .owner = THIS_MODULE,
1080 .name = "cmpc_keys",
1081 .class = "cmpc_keys",
1082 .ids = cmpc_keys_device_ids,
1083 .ops = {
1084 .add = cmpc_keys_add,
1085 .remove = cmpc_keys_remove,
1086 .notify = cmpc_keys_handler,
1092 * General init/exit code.
1095 static int cmpc_init(void)
1097 int r;
1099 r = acpi_bus_register_driver(&cmpc_keys_acpi_driver);
1100 if (r)
1101 goto failed_keys;
1103 r = acpi_bus_register_driver(&cmpc_ipml_acpi_driver);
1104 if (r)
1105 goto failed_bl;
1107 r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver);
1108 if (r)
1109 goto failed_tablet;
1111 r = acpi_bus_register_driver(&cmpc_accel_acpi_driver);
1112 if (r)
1113 goto failed_accel;
1115 r = acpi_bus_register_driver(&cmpc_accel_acpi_driver_v4);
1116 if (r)
1117 goto failed_accel_v4;
1119 return r;
1121 failed_accel_v4:
1122 acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
1124 failed_accel:
1125 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
1127 failed_tablet:
1128 acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
1130 failed_bl:
1131 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
1133 failed_keys:
1134 return r;
1137 static void cmpc_exit(void)
1139 acpi_bus_unregister_driver(&cmpc_accel_acpi_driver_v4);
1140 acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
1141 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
1142 acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
1143 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
1146 module_init(cmpc_init);
1147 module_exit(cmpc_exit);
1149 static const struct acpi_device_id cmpc_device_ids[] = {
1150 {CMPC_ACCEL_HID, 0},
1151 {CMPC_ACCEL_HID_V4, 0},
1152 {CMPC_TABLET_HID, 0},
1153 {CMPC_IPML_HID, 0},
1154 {CMPC_KEYS_HID, 0},
1155 {"", 0}
1158 MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);