18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2009 Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/init.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 118c2ecf20Sopenharmony_ci#include <linux/acpi.h> 128c2ecf20Sopenharmony_ci#include <linux/backlight.h> 138c2ecf20Sopenharmony_ci#include <linux/input.h> 148c2ecf20Sopenharmony_ci#include <linux/rfkill.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistruct cmpc_accel { 198c2ecf20Sopenharmony_ci int sensitivity; 208c2ecf20Sopenharmony_ci int g_select; 218c2ecf20Sopenharmony_ci int inputdev_state; 228c2ecf20Sopenharmony_ci}; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define CMPC_ACCEL_DEV_STATE_CLOSED 0 258c2ecf20Sopenharmony_ci#define CMPC_ACCEL_DEV_STATE_OPEN 1 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define CMPC_ACCEL_SENSITIVITY_DEFAULT 5 288c2ecf20Sopenharmony_ci#define CMPC_ACCEL_G_SELECT_DEFAULT 0 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define CMPC_ACCEL_HID "ACCE0000" 318c2ecf20Sopenharmony_ci#define CMPC_ACCEL_HID_V4 "ACCE0001" 328c2ecf20Sopenharmony_ci#define CMPC_TABLET_HID "TBLT0000" 338c2ecf20Sopenharmony_ci#define CMPC_IPML_HID "IPML200" 348c2ecf20Sopenharmony_ci#define CMPC_KEYS_HID "FNBT0000" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* 378c2ecf20Sopenharmony_ci * Generic input device code. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_citypedef void (*input_device_init)(struct input_dev *dev); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic int cmpc_add_acpi_notify_device(struct acpi_device *acpi, char *name, 438c2ecf20Sopenharmony_ci input_device_init idev_init) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct input_dev *inputdev; 468c2ecf20Sopenharmony_ci int error; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci inputdev = input_allocate_device(); 498c2ecf20Sopenharmony_ci if (!inputdev) 508c2ecf20Sopenharmony_ci return -ENOMEM; 518c2ecf20Sopenharmony_ci inputdev->name = name; 528c2ecf20Sopenharmony_ci inputdev->dev.parent = &acpi->dev; 538c2ecf20Sopenharmony_ci idev_init(inputdev); 548c2ecf20Sopenharmony_ci error = input_register_device(inputdev); 558c2ecf20Sopenharmony_ci if (error) { 568c2ecf20Sopenharmony_ci input_free_device(inputdev); 578c2ecf20Sopenharmony_ci return error; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci dev_set_drvdata(&acpi->dev, inputdev); 608c2ecf20Sopenharmony_ci return 0; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int cmpc_remove_acpi_notify_device(struct acpi_device *acpi) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci struct input_dev *inputdev = dev_get_drvdata(&acpi->dev); 668c2ecf20Sopenharmony_ci input_unregister_device(inputdev); 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* 718c2ecf20Sopenharmony_ci * Accelerometer code for Classmate V4 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_cistatic acpi_status cmpc_start_accel_v4(acpi_handle handle) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci union acpi_object param[4]; 768c2ecf20Sopenharmony_ci struct acpi_object_list input; 778c2ecf20Sopenharmony_ci acpi_status status; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci param[0].type = ACPI_TYPE_INTEGER; 808c2ecf20Sopenharmony_ci param[0].integer.value = 0x3; 818c2ecf20Sopenharmony_ci param[1].type = ACPI_TYPE_INTEGER; 828c2ecf20Sopenharmony_ci param[1].integer.value = 0; 838c2ecf20Sopenharmony_ci param[2].type = ACPI_TYPE_INTEGER; 848c2ecf20Sopenharmony_ci param[2].integer.value = 0; 858c2ecf20Sopenharmony_ci param[3].type = ACPI_TYPE_INTEGER; 868c2ecf20Sopenharmony_ci param[3].integer.value = 0; 878c2ecf20Sopenharmony_ci input.count = 4; 888c2ecf20Sopenharmony_ci input.pointer = param; 898c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, "ACMD", &input, NULL); 908c2ecf20Sopenharmony_ci return status; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic acpi_status cmpc_stop_accel_v4(acpi_handle handle) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci union acpi_object param[4]; 968c2ecf20Sopenharmony_ci struct acpi_object_list input; 978c2ecf20Sopenharmony_ci acpi_status status; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci param[0].type = ACPI_TYPE_INTEGER; 1008c2ecf20Sopenharmony_ci param[0].integer.value = 0x4; 1018c2ecf20Sopenharmony_ci param[1].type = ACPI_TYPE_INTEGER; 1028c2ecf20Sopenharmony_ci param[1].integer.value = 0; 1038c2ecf20Sopenharmony_ci param[2].type = ACPI_TYPE_INTEGER; 1048c2ecf20Sopenharmony_ci param[2].integer.value = 0; 1058c2ecf20Sopenharmony_ci param[3].type = ACPI_TYPE_INTEGER; 1068c2ecf20Sopenharmony_ci param[3].integer.value = 0; 1078c2ecf20Sopenharmony_ci input.count = 4; 1088c2ecf20Sopenharmony_ci input.pointer = param; 1098c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, "ACMD", &input, NULL); 1108c2ecf20Sopenharmony_ci return status; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic acpi_status cmpc_accel_set_sensitivity_v4(acpi_handle handle, int val) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci union acpi_object param[4]; 1168c2ecf20Sopenharmony_ci struct acpi_object_list input; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci param[0].type = ACPI_TYPE_INTEGER; 1198c2ecf20Sopenharmony_ci param[0].integer.value = 0x02; 1208c2ecf20Sopenharmony_ci param[1].type = ACPI_TYPE_INTEGER; 1218c2ecf20Sopenharmony_ci param[1].integer.value = val; 1228c2ecf20Sopenharmony_ci param[2].type = ACPI_TYPE_INTEGER; 1238c2ecf20Sopenharmony_ci param[2].integer.value = 0; 1248c2ecf20Sopenharmony_ci param[3].type = ACPI_TYPE_INTEGER; 1258c2ecf20Sopenharmony_ci param[3].integer.value = 0; 1268c2ecf20Sopenharmony_ci input.count = 4; 1278c2ecf20Sopenharmony_ci input.pointer = param; 1288c2ecf20Sopenharmony_ci return acpi_evaluate_object(handle, "ACMD", &input, NULL); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic acpi_status cmpc_accel_set_g_select_v4(acpi_handle handle, int val) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci union acpi_object param[4]; 1348c2ecf20Sopenharmony_ci struct acpi_object_list input; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci param[0].type = ACPI_TYPE_INTEGER; 1378c2ecf20Sopenharmony_ci param[0].integer.value = 0x05; 1388c2ecf20Sopenharmony_ci param[1].type = ACPI_TYPE_INTEGER; 1398c2ecf20Sopenharmony_ci param[1].integer.value = val; 1408c2ecf20Sopenharmony_ci param[2].type = ACPI_TYPE_INTEGER; 1418c2ecf20Sopenharmony_ci param[2].integer.value = 0; 1428c2ecf20Sopenharmony_ci param[3].type = ACPI_TYPE_INTEGER; 1438c2ecf20Sopenharmony_ci param[3].integer.value = 0; 1448c2ecf20Sopenharmony_ci input.count = 4; 1458c2ecf20Sopenharmony_ci input.pointer = param; 1468c2ecf20Sopenharmony_ci return acpi_evaluate_object(handle, "ACMD", &input, NULL); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic acpi_status cmpc_get_accel_v4(acpi_handle handle, 1508c2ecf20Sopenharmony_ci int16_t *x, 1518c2ecf20Sopenharmony_ci int16_t *y, 1528c2ecf20Sopenharmony_ci int16_t *z) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci union acpi_object param[4]; 1558c2ecf20Sopenharmony_ci struct acpi_object_list input; 1568c2ecf20Sopenharmony_ci struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 1578c2ecf20Sopenharmony_ci int16_t *locs; 1588c2ecf20Sopenharmony_ci acpi_status status; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci param[0].type = ACPI_TYPE_INTEGER; 1618c2ecf20Sopenharmony_ci param[0].integer.value = 0x01; 1628c2ecf20Sopenharmony_ci param[1].type = ACPI_TYPE_INTEGER; 1638c2ecf20Sopenharmony_ci param[1].integer.value = 0; 1648c2ecf20Sopenharmony_ci param[2].type = ACPI_TYPE_INTEGER; 1658c2ecf20Sopenharmony_ci param[2].integer.value = 0; 1668c2ecf20Sopenharmony_ci param[3].type = ACPI_TYPE_INTEGER; 1678c2ecf20Sopenharmony_ci param[3].integer.value = 0; 1688c2ecf20Sopenharmony_ci input.count = 4; 1698c2ecf20Sopenharmony_ci input.pointer = param; 1708c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, "ACMD", &input, &output); 1718c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) { 1728c2ecf20Sopenharmony_ci union acpi_object *obj; 1738c2ecf20Sopenharmony_ci obj = output.pointer; 1748c2ecf20Sopenharmony_ci locs = (int16_t *) obj->buffer.pointer; 1758c2ecf20Sopenharmony_ci *x = locs[0]; 1768c2ecf20Sopenharmony_ci *y = locs[1]; 1778c2ecf20Sopenharmony_ci *z = locs[2]; 1788c2ecf20Sopenharmony_ci kfree(output.pointer); 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci return status; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic void cmpc_accel_handler_v4(struct acpi_device *dev, u32 event) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci if (event == 0x81) { 1868c2ecf20Sopenharmony_ci int16_t x, y, z; 1878c2ecf20Sopenharmony_ci acpi_status status; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci status = cmpc_get_accel_v4(dev->handle, &x, &y, &z); 1908c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) { 1918c2ecf20Sopenharmony_ci struct input_dev *inputdev = dev_get_drvdata(&dev->dev); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_X, x); 1948c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_Y, y); 1958c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_Z, z); 1968c2ecf20Sopenharmony_ci input_sync(inputdev); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic ssize_t cmpc_accel_sensitivity_show_v4(struct device *dev, 2028c2ecf20Sopenharmony_ci struct device_attribute *attr, 2038c2ecf20Sopenharmony_ci char *buf) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct acpi_device *acpi; 2068c2ecf20Sopenharmony_ci struct input_dev *inputdev; 2078c2ecf20Sopenharmony_ci struct cmpc_accel *accel; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci acpi = to_acpi_device(dev); 2108c2ecf20Sopenharmony_ci inputdev = dev_get_drvdata(&acpi->dev); 2118c2ecf20Sopenharmony_ci accel = dev_get_drvdata(&inputdev->dev); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", accel->sensitivity); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic ssize_t cmpc_accel_sensitivity_store_v4(struct device *dev, 2178c2ecf20Sopenharmony_ci struct device_attribute *attr, 2188c2ecf20Sopenharmony_ci const char *buf, size_t count) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci struct acpi_device *acpi; 2218c2ecf20Sopenharmony_ci struct input_dev *inputdev; 2228c2ecf20Sopenharmony_ci struct cmpc_accel *accel; 2238c2ecf20Sopenharmony_ci unsigned long sensitivity; 2248c2ecf20Sopenharmony_ci int r; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci acpi = to_acpi_device(dev); 2278c2ecf20Sopenharmony_ci inputdev = dev_get_drvdata(&acpi->dev); 2288c2ecf20Sopenharmony_ci accel = dev_get_drvdata(&inputdev->dev); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci r = kstrtoul(buf, 0, &sensitivity); 2318c2ecf20Sopenharmony_ci if (r) 2328c2ecf20Sopenharmony_ci return r; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* sensitivity must be between 1 and 127 */ 2358c2ecf20Sopenharmony_ci if (sensitivity < 1 || sensitivity > 127) 2368c2ecf20Sopenharmony_ci return -EINVAL; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci accel->sensitivity = sensitivity; 2398c2ecf20Sopenharmony_ci cmpc_accel_set_sensitivity_v4(acpi->handle, sensitivity); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return strnlen(buf, count); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic struct device_attribute cmpc_accel_sensitivity_attr_v4 = { 2458c2ecf20Sopenharmony_ci .attr = { .name = "sensitivity", .mode = 0660 }, 2468c2ecf20Sopenharmony_ci .show = cmpc_accel_sensitivity_show_v4, 2478c2ecf20Sopenharmony_ci .store = cmpc_accel_sensitivity_store_v4 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic ssize_t cmpc_accel_g_select_show_v4(struct device *dev, 2518c2ecf20Sopenharmony_ci struct device_attribute *attr, 2528c2ecf20Sopenharmony_ci char *buf) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct acpi_device *acpi; 2558c2ecf20Sopenharmony_ci struct input_dev *inputdev; 2568c2ecf20Sopenharmony_ci struct cmpc_accel *accel; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci acpi = to_acpi_device(dev); 2598c2ecf20Sopenharmony_ci inputdev = dev_get_drvdata(&acpi->dev); 2608c2ecf20Sopenharmony_ci accel = dev_get_drvdata(&inputdev->dev); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", accel->g_select); 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic ssize_t cmpc_accel_g_select_store_v4(struct device *dev, 2668c2ecf20Sopenharmony_ci struct device_attribute *attr, 2678c2ecf20Sopenharmony_ci const char *buf, size_t count) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct acpi_device *acpi; 2708c2ecf20Sopenharmony_ci struct input_dev *inputdev; 2718c2ecf20Sopenharmony_ci struct cmpc_accel *accel; 2728c2ecf20Sopenharmony_ci unsigned long g_select; 2738c2ecf20Sopenharmony_ci int r; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci acpi = to_acpi_device(dev); 2768c2ecf20Sopenharmony_ci inputdev = dev_get_drvdata(&acpi->dev); 2778c2ecf20Sopenharmony_ci accel = dev_get_drvdata(&inputdev->dev); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci r = kstrtoul(buf, 0, &g_select); 2808c2ecf20Sopenharmony_ci if (r) 2818c2ecf20Sopenharmony_ci return r; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* 0 means 1.5g, 1 means 6g, everything else is wrong */ 2848c2ecf20Sopenharmony_ci if (g_select != 0 && g_select != 1) 2858c2ecf20Sopenharmony_ci return -EINVAL; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci accel->g_select = g_select; 2888c2ecf20Sopenharmony_ci cmpc_accel_set_g_select_v4(acpi->handle, g_select); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci return strnlen(buf, count); 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic struct device_attribute cmpc_accel_g_select_attr_v4 = { 2948c2ecf20Sopenharmony_ci .attr = { .name = "g_select", .mode = 0660 }, 2958c2ecf20Sopenharmony_ci .show = cmpc_accel_g_select_show_v4, 2968c2ecf20Sopenharmony_ci .store = cmpc_accel_g_select_store_v4 2978c2ecf20Sopenharmony_ci}; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic int cmpc_accel_open_v4(struct input_dev *input) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci struct acpi_device *acpi; 3028c2ecf20Sopenharmony_ci struct cmpc_accel *accel; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci acpi = to_acpi_device(input->dev.parent); 3058c2ecf20Sopenharmony_ci accel = dev_get_drvdata(&input->dev); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity); 3088c2ecf20Sopenharmony_ci cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(cmpc_start_accel_v4(acpi->handle))) { 3118c2ecf20Sopenharmony_ci accel->inputdev_state = CMPC_ACCEL_DEV_STATE_OPEN; 3128c2ecf20Sopenharmony_ci return 0; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci return -EIO; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic void cmpc_accel_close_v4(struct input_dev *input) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct acpi_device *acpi; 3208c2ecf20Sopenharmony_ci struct cmpc_accel *accel; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci acpi = to_acpi_device(input->dev.parent); 3238c2ecf20Sopenharmony_ci accel = dev_get_drvdata(&input->dev); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci cmpc_stop_accel_v4(acpi->handle); 3268c2ecf20Sopenharmony_ci accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic void cmpc_accel_idev_init_v4(struct input_dev *inputdev) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci set_bit(EV_ABS, inputdev->evbit); 3328c2ecf20Sopenharmony_ci input_set_abs_params(inputdev, ABS_X, -255, 255, 16, 0); 3338c2ecf20Sopenharmony_ci input_set_abs_params(inputdev, ABS_Y, -255, 255, 16, 0); 3348c2ecf20Sopenharmony_ci input_set_abs_params(inputdev, ABS_Z, -255, 255, 16, 0); 3358c2ecf20Sopenharmony_ci inputdev->open = cmpc_accel_open_v4; 3368c2ecf20Sopenharmony_ci inputdev->close = cmpc_accel_close_v4; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 3408c2ecf20Sopenharmony_cistatic int cmpc_accel_suspend_v4(struct device *dev) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct input_dev *inputdev; 3438c2ecf20Sopenharmony_ci struct cmpc_accel *accel; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci inputdev = dev_get_drvdata(dev); 3468c2ecf20Sopenharmony_ci accel = dev_get_drvdata(&inputdev->dev); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN) 3498c2ecf20Sopenharmony_ci return cmpc_stop_accel_v4(to_acpi_device(dev)->handle); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int cmpc_accel_resume_v4(struct device *dev) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct input_dev *inputdev; 3578c2ecf20Sopenharmony_ci struct cmpc_accel *accel; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci inputdev = dev_get_drvdata(dev); 3608c2ecf20Sopenharmony_ci accel = dev_get_drvdata(&inputdev->dev); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN) { 3638c2ecf20Sopenharmony_ci cmpc_accel_set_sensitivity_v4(to_acpi_device(dev)->handle, 3648c2ecf20Sopenharmony_ci accel->sensitivity); 3658c2ecf20Sopenharmony_ci cmpc_accel_set_g_select_v4(to_acpi_device(dev)->handle, 3668c2ecf20Sopenharmony_ci accel->g_select); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (ACPI_FAILURE(cmpc_start_accel_v4(to_acpi_device(dev)->handle))) 3698c2ecf20Sopenharmony_ci return -EIO; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci return 0; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci#endif 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic int cmpc_accel_add_v4(struct acpi_device *acpi) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci int error; 3798c2ecf20Sopenharmony_ci struct input_dev *inputdev; 3808c2ecf20Sopenharmony_ci struct cmpc_accel *accel; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci accel = kmalloc(sizeof(*accel), GFP_KERNEL); 3838c2ecf20Sopenharmony_ci if (!accel) 3848c2ecf20Sopenharmony_ci return -ENOMEM; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT; 3898c2ecf20Sopenharmony_ci cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4); 3928c2ecf20Sopenharmony_ci if (error) 3938c2ecf20Sopenharmony_ci goto failed_sensitivity; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci accel->g_select = CMPC_ACCEL_G_SELECT_DEFAULT; 3968c2ecf20Sopenharmony_ci cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci error = device_create_file(&acpi->dev, &cmpc_accel_g_select_attr_v4); 3998c2ecf20Sopenharmony_ci if (error) 4008c2ecf20Sopenharmony_ci goto failed_g_select; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel_v4", 4038c2ecf20Sopenharmony_ci cmpc_accel_idev_init_v4); 4048c2ecf20Sopenharmony_ci if (error) 4058c2ecf20Sopenharmony_ci goto failed_input; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci inputdev = dev_get_drvdata(&acpi->dev); 4088c2ecf20Sopenharmony_ci dev_set_drvdata(&inputdev->dev, accel); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci return 0; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cifailed_input: 4138c2ecf20Sopenharmony_ci device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4); 4148c2ecf20Sopenharmony_cifailed_g_select: 4158c2ecf20Sopenharmony_ci device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4); 4168c2ecf20Sopenharmony_cifailed_sensitivity: 4178c2ecf20Sopenharmony_ci kfree(accel); 4188c2ecf20Sopenharmony_ci return error; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic int cmpc_accel_remove_v4(struct acpi_device *acpi) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4); 4248c2ecf20Sopenharmony_ci device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4); 4258c2ecf20Sopenharmony_ci return cmpc_remove_acpi_notify_device(acpi); 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(cmpc_accel_pm, cmpc_accel_suspend_v4, 4298c2ecf20Sopenharmony_ci cmpc_accel_resume_v4); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic const struct acpi_device_id cmpc_accel_device_ids_v4[] = { 4328c2ecf20Sopenharmony_ci {CMPC_ACCEL_HID_V4, 0}, 4338c2ecf20Sopenharmony_ci {"", 0} 4348c2ecf20Sopenharmony_ci}; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic struct acpi_driver cmpc_accel_acpi_driver_v4 = { 4378c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4388c2ecf20Sopenharmony_ci .name = "cmpc_accel_v4", 4398c2ecf20Sopenharmony_ci .class = "cmpc_accel_v4", 4408c2ecf20Sopenharmony_ci .ids = cmpc_accel_device_ids_v4, 4418c2ecf20Sopenharmony_ci .ops = { 4428c2ecf20Sopenharmony_ci .add = cmpc_accel_add_v4, 4438c2ecf20Sopenharmony_ci .remove = cmpc_accel_remove_v4, 4448c2ecf20Sopenharmony_ci .notify = cmpc_accel_handler_v4, 4458c2ecf20Sopenharmony_ci }, 4468c2ecf20Sopenharmony_ci .drv.pm = &cmpc_accel_pm, 4478c2ecf20Sopenharmony_ci}; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci/* 4518c2ecf20Sopenharmony_ci * Accelerometer code for Classmate versions prior to V4 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_cistatic acpi_status cmpc_start_accel(acpi_handle handle) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci union acpi_object param[2]; 4568c2ecf20Sopenharmony_ci struct acpi_object_list input; 4578c2ecf20Sopenharmony_ci acpi_status status; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci param[0].type = ACPI_TYPE_INTEGER; 4608c2ecf20Sopenharmony_ci param[0].integer.value = 0x3; 4618c2ecf20Sopenharmony_ci param[1].type = ACPI_TYPE_INTEGER; 4628c2ecf20Sopenharmony_ci input.count = 2; 4638c2ecf20Sopenharmony_ci input.pointer = param; 4648c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, "ACMD", &input, NULL); 4658c2ecf20Sopenharmony_ci return status; 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic acpi_status cmpc_stop_accel(acpi_handle handle) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci union acpi_object param[2]; 4718c2ecf20Sopenharmony_ci struct acpi_object_list input; 4728c2ecf20Sopenharmony_ci acpi_status status; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci param[0].type = ACPI_TYPE_INTEGER; 4758c2ecf20Sopenharmony_ci param[0].integer.value = 0x4; 4768c2ecf20Sopenharmony_ci param[1].type = ACPI_TYPE_INTEGER; 4778c2ecf20Sopenharmony_ci input.count = 2; 4788c2ecf20Sopenharmony_ci input.pointer = param; 4798c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, "ACMD", &input, NULL); 4808c2ecf20Sopenharmony_ci return status; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic acpi_status cmpc_accel_set_sensitivity(acpi_handle handle, int val) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci union acpi_object param[2]; 4868c2ecf20Sopenharmony_ci struct acpi_object_list input; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci param[0].type = ACPI_TYPE_INTEGER; 4898c2ecf20Sopenharmony_ci param[0].integer.value = 0x02; 4908c2ecf20Sopenharmony_ci param[1].type = ACPI_TYPE_INTEGER; 4918c2ecf20Sopenharmony_ci param[1].integer.value = val; 4928c2ecf20Sopenharmony_ci input.count = 2; 4938c2ecf20Sopenharmony_ci input.pointer = param; 4948c2ecf20Sopenharmony_ci return acpi_evaluate_object(handle, "ACMD", &input, NULL); 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic acpi_status cmpc_get_accel(acpi_handle handle, 4988c2ecf20Sopenharmony_ci unsigned char *x, 4998c2ecf20Sopenharmony_ci unsigned char *y, 5008c2ecf20Sopenharmony_ci unsigned char *z) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci union acpi_object param[2]; 5038c2ecf20Sopenharmony_ci struct acpi_object_list input; 5048c2ecf20Sopenharmony_ci struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 5058c2ecf20Sopenharmony_ci unsigned char *locs; 5068c2ecf20Sopenharmony_ci acpi_status status; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci param[0].type = ACPI_TYPE_INTEGER; 5098c2ecf20Sopenharmony_ci param[0].integer.value = 0x01; 5108c2ecf20Sopenharmony_ci param[1].type = ACPI_TYPE_INTEGER; 5118c2ecf20Sopenharmony_ci input.count = 2; 5128c2ecf20Sopenharmony_ci input.pointer = param; 5138c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, "ACMD", &input, &output); 5148c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) { 5158c2ecf20Sopenharmony_ci union acpi_object *obj; 5168c2ecf20Sopenharmony_ci obj = output.pointer; 5178c2ecf20Sopenharmony_ci locs = obj->buffer.pointer; 5188c2ecf20Sopenharmony_ci *x = locs[0]; 5198c2ecf20Sopenharmony_ci *y = locs[1]; 5208c2ecf20Sopenharmony_ci *z = locs[2]; 5218c2ecf20Sopenharmony_ci kfree(output.pointer); 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci return status; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic void cmpc_accel_handler(struct acpi_device *dev, u32 event) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci if (event == 0x81) { 5298c2ecf20Sopenharmony_ci unsigned char x, y, z; 5308c2ecf20Sopenharmony_ci acpi_status status; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci status = cmpc_get_accel(dev->handle, &x, &y, &z); 5338c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) { 5348c2ecf20Sopenharmony_ci struct input_dev *inputdev = dev_get_drvdata(&dev->dev); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_X, x); 5378c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_Y, y); 5388c2ecf20Sopenharmony_ci input_report_abs(inputdev, ABS_Z, z); 5398c2ecf20Sopenharmony_ci input_sync(inputdev); 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic ssize_t cmpc_accel_sensitivity_show(struct device *dev, 5458c2ecf20Sopenharmony_ci struct device_attribute *attr, 5468c2ecf20Sopenharmony_ci char *buf) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct acpi_device *acpi; 5498c2ecf20Sopenharmony_ci struct input_dev *inputdev; 5508c2ecf20Sopenharmony_ci struct cmpc_accel *accel; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci acpi = to_acpi_device(dev); 5538c2ecf20Sopenharmony_ci inputdev = dev_get_drvdata(&acpi->dev); 5548c2ecf20Sopenharmony_ci accel = dev_get_drvdata(&inputdev->dev); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", accel->sensitivity); 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic ssize_t cmpc_accel_sensitivity_store(struct device *dev, 5608c2ecf20Sopenharmony_ci struct device_attribute *attr, 5618c2ecf20Sopenharmony_ci const char *buf, size_t count) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct acpi_device *acpi; 5648c2ecf20Sopenharmony_ci struct input_dev *inputdev; 5658c2ecf20Sopenharmony_ci struct cmpc_accel *accel; 5668c2ecf20Sopenharmony_ci unsigned long sensitivity; 5678c2ecf20Sopenharmony_ci int r; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci acpi = to_acpi_device(dev); 5708c2ecf20Sopenharmony_ci inputdev = dev_get_drvdata(&acpi->dev); 5718c2ecf20Sopenharmony_ci accel = dev_get_drvdata(&inputdev->dev); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci r = kstrtoul(buf, 0, &sensitivity); 5748c2ecf20Sopenharmony_ci if (r) 5758c2ecf20Sopenharmony_ci return r; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci accel->sensitivity = sensitivity; 5788c2ecf20Sopenharmony_ci cmpc_accel_set_sensitivity(acpi->handle, sensitivity); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci return strnlen(buf, count); 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic struct device_attribute cmpc_accel_sensitivity_attr = { 5848c2ecf20Sopenharmony_ci .attr = { .name = "sensitivity", .mode = 0660 }, 5858c2ecf20Sopenharmony_ci .show = cmpc_accel_sensitivity_show, 5868c2ecf20Sopenharmony_ci .store = cmpc_accel_sensitivity_store 5878c2ecf20Sopenharmony_ci}; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic int cmpc_accel_open(struct input_dev *input) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci struct acpi_device *acpi; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci acpi = to_acpi_device(input->dev.parent); 5948c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(cmpc_start_accel(acpi->handle))) 5958c2ecf20Sopenharmony_ci return 0; 5968c2ecf20Sopenharmony_ci return -EIO; 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic void cmpc_accel_close(struct input_dev *input) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci struct acpi_device *acpi; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci acpi = to_acpi_device(input->dev.parent); 6048c2ecf20Sopenharmony_ci cmpc_stop_accel(acpi->handle); 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic void cmpc_accel_idev_init(struct input_dev *inputdev) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci set_bit(EV_ABS, inputdev->evbit); 6108c2ecf20Sopenharmony_ci input_set_abs_params(inputdev, ABS_X, 0, 255, 8, 0); 6118c2ecf20Sopenharmony_ci input_set_abs_params(inputdev, ABS_Y, 0, 255, 8, 0); 6128c2ecf20Sopenharmony_ci input_set_abs_params(inputdev, ABS_Z, 0, 255, 8, 0); 6138c2ecf20Sopenharmony_ci inputdev->open = cmpc_accel_open; 6148c2ecf20Sopenharmony_ci inputdev->close = cmpc_accel_close; 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic int cmpc_accel_add(struct acpi_device *acpi) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci int error; 6208c2ecf20Sopenharmony_ci struct input_dev *inputdev; 6218c2ecf20Sopenharmony_ci struct cmpc_accel *accel; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci accel = kmalloc(sizeof(*accel), GFP_KERNEL); 6248c2ecf20Sopenharmony_ci if (!accel) 6258c2ecf20Sopenharmony_ci return -ENOMEM; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT; 6288c2ecf20Sopenharmony_ci cmpc_accel_set_sensitivity(acpi->handle, accel->sensitivity); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr); 6318c2ecf20Sopenharmony_ci if (error) 6328c2ecf20Sopenharmony_ci goto failed_file; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel", 6358c2ecf20Sopenharmony_ci cmpc_accel_idev_init); 6368c2ecf20Sopenharmony_ci if (error) 6378c2ecf20Sopenharmony_ci goto failed_input; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci inputdev = dev_get_drvdata(&acpi->dev); 6408c2ecf20Sopenharmony_ci dev_set_drvdata(&inputdev->dev, accel); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci return 0; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cifailed_input: 6458c2ecf20Sopenharmony_ci device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr); 6468c2ecf20Sopenharmony_cifailed_file: 6478c2ecf20Sopenharmony_ci kfree(accel); 6488c2ecf20Sopenharmony_ci return error; 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic int cmpc_accel_remove(struct acpi_device *acpi) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr); 6548c2ecf20Sopenharmony_ci return cmpc_remove_acpi_notify_device(acpi); 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cistatic const struct acpi_device_id cmpc_accel_device_ids[] = { 6588c2ecf20Sopenharmony_ci {CMPC_ACCEL_HID, 0}, 6598c2ecf20Sopenharmony_ci {"", 0} 6608c2ecf20Sopenharmony_ci}; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic struct acpi_driver cmpc_accel_acpi_driver = { 6638c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6648c2ecf20Sopenharmony_ci .name = "cmpc_accel", 6658c2ecf20Sopenharmony_ci .class = "cmpc_accel", 6668c2ecf20Sopenharmony_ci .ids = cmpc_accel_device_ids, 6678c2ecf20Sopenharmony_ci .ops = { 6688c2ecf20Sopenharmony_ci .add = cmpc_accel_add, 6698c2ecf20Sopenharmony_ci .remove = cmpc_accel_remove, 6708c2ecf20Sopenharmony_ci .notify = cmpc_accel_handler, 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci}; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci/* 6768c2ecf20Sopenharmony_ci * Tablet mode code. 6778c2ecf20Sopenharmony_ci */ 6788c2ecf20Sopenharmony_cistatic acpi_status cmpc_get_tablet(acpi_handle handle, 6798c2ecf20Sopenharmony_ci unsigned long long *value) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci union acpi_object param; 6828c2ecf20Sopenharmony_ci struct acpi_object_list input; 6838c2ecf20Sopenharmony_ci unsigned long long output; 6848c2ecf20Sopenharmony_ci acpi_status status; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci param.type = ACPI_TYPE_INTEGER; 6878c2ecf20Sopenharmony_ci param.integer.value = 0x01; 6888c2ecf20Sopenharmony_ci input.count = 1; 6898c2ecf20Sopenharmony_ci input.pointer = ¶m; 6908c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(handle, "TCMD", &input, &output); 6918c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) 6928c2ecf20Sopenharmony_ci *value = output; 6938c2ecf20Sopenharmony_ci return status; 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_cistatic void cmpc_tablet_handler(struct acpi_device *dev, u32 event) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci unsigned long long val = 0; 6998c2ecf20Sopenharmony_ci struct input_dev *inputdev = dev_get_drvdata(&dev->dev); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (event == 0x81) { 7028c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val))) { 7038c2ecf20Sopenharmony_ci input_report_switch(inputdev, SW_TABLET_MODE, !val); 7048c2ecf20Sopenharmony_ci input_sync(inputdev); 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cistatic void cmpc_tablet_idev_init(struct input_dev *inputdev) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci unsigned long long val = 0; 7128c2ecf20Sopenharmony_ci struct acpi_device *acpi; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci set_bit(EV_SW, inputdev->evbit); 7158c2ecf20Sopenharmony_ci set_bit(SW_TABLET_MODE, inputdev->swbit); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci acpi = to_acpi_device(inputdev->dev.parent); 7188c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val))) { 7198c2ecf20Sopenharmony_ci input_report_switch(inputdev, SW_TABLET_MODE, !val); 7208c2ecf20Sopenharmony_ci input_sync(inputdev); 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistatic int cmpc_tablet_add(struct acpi_device *acpi) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci return cmpc_add_acpi_notify_device(acpi, "cmpc_tablet", 7278c2ecf20Sopenharmony_ci cmpc_tablet_idev_init); 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic int cmpc_tablet_remove(struct acpi_device *acpi) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci return cmpc_remove_acpi_notify_device(acpi); 7338c2ecf20Sopenharmony_ci} 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 7368c2ecf20Sopenharmony_cistatic int cmpc_tablet_resume(struct device *dev) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci struct input_dev *inputdev = dev_get_drvdata(dev); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci unsigned long long val = 0; 7418c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val))) { 7428c2ecf20Sopenharmony_ci input_report_switch(inputdev, SW_TABLET_MODE, !val); 7438c2ecf20Sopenharmony_ci input_sync(inputdev); 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci return 0; 7468c2ecf20Sopenharmony_ci} 7478c2ecf20Sopenharmony_ci#endif 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic const struct acpi_device_id cmpc_tablet_device_ids[] = { 7528c2ecf20Sopenharmony_ci {CMPC_TABLET_HID, 0}, 7538c2ecf20Sopenharmony_ci {"", 0} 7548c2ecf20Sopenharmony_ci}; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic struct acpi_driver cmpc_tablet_acpi_driver = { 7578c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7588c2ecf20Sopenharmony_ci .name = "cmpc_tablet", 7598c2ecf20Sopenharmony_ci .class = "cmpc_tablet", 7608c2ecf20Sopenharmony_ci .ids = cmpc_tablet_device_ids, 7618c2ecf20Sopenharmony_ci .ops = { 7628c2ecf20Sopenharmony_ci .add = cmpc_tablet_add, 7638c2ecf20Sopenharmony_ci .remove = cmpc_tablet_remove, 7648c2ecf20Sopenharmony_ci .notify = cmpc_tablet_handler, 7658c2ecf20Sopenharmony_ci }, 7668c2ecf20Sopenharmony_ci .drv.pm = &cmpc_tablet_pm, 7678c2ecf20Sopenharmony_ci}; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci/* 7718c2ecf20Sopenharmony_ci * Backlight code. 7728c2ecf20Sopenharmony_ci */ 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic acpi_status cmpc_get_brightness(acpi_handle handle, 7758c2ecf20Sopenharmony_ci unsigned long long *value) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci union acpi_object param; 7788c2ecf20Sopenharmony_ci struct acpi_object_list input; 7798c2ecf20Sopenharmony_ci unsigned long long output; 7808c2ecf20Sopenharmony_ci acpi_status status; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci param.type = ACPI_TYPE_INTEGER; 7838c2ecf20Sopenharmony_ci param.integer.value = 0xC0; 7848c2ecf20Sopenharmony_ci input.count = 1; 7858c2ecf20Sopenharmony_ci input.pointer = ¶m; 7868c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(handle, "GRDI", &input, &output); 7878c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) 7888c2ecf20Sopenharmony_ci *value = output; 7898c2ecf20Sopenharmony_ci return status; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_cistatic acpi_status cmpc_set_brightness(acpi_handle handle, 7938c2ecf20Sopenharmony_ci unsigned long long value) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci union acpi_object param[2]; 7968c2ecf20Sopenharmony_ci struct acpi_object_list input; 7978c2ecf20Sopenharmony_ci acpi_status status; 7988c2ecf20Sopenharmony_ci unsigned long long output; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci param[0].type = ACPI_TYPE_INTEGER; 8018c2ecf20Sopenharmony_ci param[0].integer.value = 0xC0; 8028c2ecf20Sopenharmony_ci param[1].type = ACPI_TYPE_INTEGER; 8038c2ecf20Sopenharmony_ci param[1].integer.value = value; 8048c2ecf20Sopenharmony_ci input.count = 2; 8058c2ecf20Sopenharmony_ci input.pointer = param; 8068c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(handle, "GWRI", &input, &output); 8078c2ecf20Sopenharmony_ci return status; 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic int cmpc_bl_get_brightness(struct backlight_device *bd) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci acpi_status status; 8138c2ecf20Sopenharmony_ci acpi_handle handle; 8148c2ecf20Sopenharmony_ci unsigned long long brightness; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci handle = bl_get_data(bd); 8178c2ecf20Sopenharmony_ci status = cmpc_get_brightness(handle, &brightness); 8188c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) 8198c2ecf20Sopenharmony_ci return brightness; 8208c2ecf20Sopenharmony_ci else 8218c2ecf20Sopenharmony_ci return -1; 8228c2ecf20Sopenharmony_ci} 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic int cmpc_bl_update_status(struct backlight_device *bd) 8258c2ecf20Sopenharmony_ci{ 8268c2ecf20Sopenharmony_ci acpi_status status; 8278c2ecf20Sopenharmony_ci acpi_handle handle; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci handle = bl_get_data(bd); 8308c2ecf20Sopenharmony_ci status = cmpc_set_brightness(handle, bd->props.brightness); 8318c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) 8328c2ecf20Sopenharmony_ci return 0; 8338c2ecf20Sopenharmony_ci else 8348c2ecf20Sopenharmony_ci return -1; 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic const struct backlight_ops cmpc_bl_ops = { 8388c2ecf20Sopenharmony_ci .get_brightness = cmpc_bl_get_brightness, 8398c2ecf20Sopenharmony_ci .update_status = cmpc_bl_update_status 8408c2ecf20Sopenharmony_ci}; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci/* 8438c2ecf20Sopenharmony_ci * RFKILL code. 8448c2ecf20Sopenharmony_ci */ 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cistatic acpi_status cmpc_get_rfkill_wlan(acpi_handle handle, 8478c2ecf20Sopenharmony_ci unsigned long long *value) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci union acpi_object param; 8508c2ecf20Sopenharmony_ci struct acpi_object_list input; 8518c2ecf20Sopenharmony_ci unsigned long long output; 8528c2ecf20Sopenharmony_ci acpi_status status; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci param.type = ACPI_TYPE_INTEGER; 8558c2ecf20Sopenharmony_ci param.integer.value = 0xC1; 8568c2ecf20Sopenharmony_ci input.count = 1; 8578c2ecf20Sopenharmony_ci input.pointer = ¶m; 8588c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(handle, "GRDI", &input, &output); 8598c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) 8608c2ecf20Sopenharmony_ci *value = output; 8618c2ecf20Sopenharmony_ci return status; 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic acpi_status cmpc_set_rfkill_wlan(acpi_handle handle, 8658c2ecf20Sopenharmony_ci unsigned long long value) 8668c2ecf20Sopenharmony_ci{ 8678c2ecf20Sopenharmony_ci union acpi_object param[2]; 8688c2ecf20Sopenharmony_ci struct acpi_object_list input; 8698c2ecf20Sopenharmony_ci acpi_status status; 8708c2ecf20Sopenharmony_ci unsigned long long output; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci param[0].type = ACPI_TYPE_INTEGER; 8738c2ecf20Sopenharmony_ci param[0].integer.value = 0xC1; 8748c2ecf20Sopenharmony_ci param[1].type = ACPI_TYPE_INTEGER; 8758c2ecf20Sopenharmony_ci param[1].integer.value = value; 8768c2ecf20Sopenharmony_ci input.count = 2; 8778c2ecf20Sopenharmony_ci input.pointer = param; 8788c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(handle, "GWRI", &input, &output); 8798c2ecf20Sopenharmony_ci return status; 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistatic void cmpc_rfkill_query(struct rfkill *rfkill, void *data) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci acpi_status status; 8858c2ecf20Sopenharmony_ci acpi_handle handle; 8868c2ecf20Sopenharmony_ci unsigned long long state; 8878c2ecf20Sopenharmony_ci bool blocked; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci handle = data; 8908c2ecf20Sopenharmony_ci status = cmpc_get_rfkill_wlan(handle, &state); 8918c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) { 8928c2ecf20Sopenharmony_ci blocked = state & 1 ? false : true; 8938c2ecf20Sopenharmony_ci rfkill_set_sw_state(rfkill, blocked); 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic int cmpc_rfkill_block(void *data, bool blocked) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci acpi_status status; 9008c2ecf20Sopenharmony_ci acpi_handle handle; 9018c2ecf20Sopenharmony_ci unsigned long long state; 9028c2ecf20Sopenharmony_ci bool is_blocked; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci handle = data; 9058c2ecf20Sopenharmony_ci status = cmpc_get_rfkill_wlan(handle, &state); 9068c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 9078c2ecf20Sopenharmony_ci return -ENODEV; 9088c2ecf20Sopenharmony_ci /* Check if we really need to call cmpc_set_rfkill_wlan */ 9098c2ecf20Sopenharmony_ci is_blocked = state & 1 ? false : true; 9108c2ecf20Sopenharmony_ci if (is_blocked != blocked) { 9118c2ecf20Sopenharmony_ci state = blocked ? 0 : 1; 9128c2ecf20Sopenharmony_ci status = cmpc_set_rfkill_wlan(handle, state); 9138c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 9148c2ecf20Sopenharmony_ci return -ENODEV; 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci return 0; 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_cistatic const struct rfkill_ops cmpc_rfkill_ops = { 9208c2ecf20Sopenharmony_ci .query = cmpc_rfkill_query, 9218c2ecf20Sopenharmony_ci .set_block = cmpc_rfkill_block, 9228c2ecf20Sopenharmony_ci}; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci/* 9258c2ecf20Sopenharmony_ci * Common backlight and rfkill code. 9268c2ecf20Sopenharmony_ci */ 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistruct ipml200_dev { 9298c2ecf20Sopenharmony_ci struct backlight_device *bd; 9308c2ecf20Sopenharmony_ci struct rfkill *rf; 9318c2ecf20Sopenharmony_ci}; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_cistatic int cmpc_ipml_add(struct acpi_device *acpi) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci int retval; 9368c2ecf20Sopenharmony_ci struct ipml200_dev *ipml; 9378c2ecf20Sopenharmony_ci struct backlight_properties props; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci ipml = kmalloc(sizeof(*ipml), GFP_KERNEL); 9408c2ecf20Sopenharmony_ci if (ipml == NULL) 9418c2ecf20Sopenharmony_ci return -ENOMEM; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci memset(&props, 0, sizeof(struct backlight_properties)); 9448c2ecf20Sopenharmony_ci props.type = BACKLIGHT_PLATFORM; 9458c2ecf20Sopenharmony_ci props.max_brightness = 7; 9468c2ecf20Sopenharmony_ci ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev, 9478c2ecf20Sopenharmony_ci acpi->handle, &cmpc_bl_ops, 9488c2ecf20Sopenharmony_ci &props); 9498c2ecf20Sopenharmony_ci if (IS_ERR(ipml->bd)) { 9508c2ecf20Sopenharmony_ci retval = PTR_ERR(ipml->bd); 9518c2ecf20Sopenharmony_ci goto out_bd; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN, 9558c2ecf20Sopenharmony_ci &cmpc_rfkill_ops, acpi->handle); 9568c2ecf20Sopenharmony_ci /* 9578c2ecf20Sopenharmony_ci * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV). 9588c2ecf20Sopenharmony_ci * This is OK, however, since all other uses of the device will not 9598c2ecf20Sopenharmony_ci * derefence it. 9608c2ecf20Sopenharmony_ci */ 9618c2ecf20Sopenharmony_ci if (ipml->rf) { 9628c2ecf20Sopenharmony_ci retval = rfkill_register(ipml->rf); 9638c2ecf20Sopenharmony_ci if (retval) { 9648c2ecf20Sopenharmony_ci rfkill_destroy(ipml->rf); 9658c2ecf20Sopenharmony_ci ipml->rf = NULL; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci dev_set_drvdata(&acpi->dev, ipml); 9708c2ecf20Sopenharmony_ci return 0; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ciout_bd: 9738c2ecf20Sopenharmony_ci kfree(ipml); 9748c2ecf20Sopenharmony_ci return retval; 9758c2ecf20Sopenharmony_ci} 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_cistatic int cmpc_ipml_remove(struct acpi_device *acpi) 9788c2ecf20Sopenharmony_ci{ 9798c2ecf20Sopenharmony_ci struct ipml200_dev *ipml; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci ipml = dev_get_drvdata(&acpi->dev); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci backlight_device_unregister(ipml->bd); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci if (ipml->rf) { 9868c2ecf20Sopenharmony_ci rfkill_unregister(ipml->rf); 9878c2ecf20Sopenharmony_ci rfkill_destroy(ipml->rf); 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci kfree(ipml); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci return 0; 9938c2ecf20Sopenharmony_ci} 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_cistatic const struct acpi_device_id cmpc_ipml_device_ids[] = { 9968c2ecf20Sopenharmony_ci {CMPC_IPML_HID, 0}, 9978c2ecf20Sopenharmony_ci {"", 0} 9988c2ecf20Sopenharmony_ci}; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_cistatic struct acpi_driver cmpc_ipml_acpi_driver = { 10018c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 10028c2ecf20Sopenharmony_ci .name = "cmpc", 10038c2ecf20Sopenharmony_ci .class = "cmpc", 10048c2ecf20Sopenharmony_ci .ids = cmpc_ipml_device_ids, 10058c2ecf20Sopenharmony_ci .ops = { 10068c2ecf20Sopenharmony_ci .add = cmpc_ipml_add, 10078c2ecf20Sopenharmony_ci .remove = cmpc_ipml_remove 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci}; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci/* 10138c2ecf20Sopenharmony_ci * Extra keys code. 10148c2ecf20Sopenharmony_ci */ 10158c2ecf20Sopenharmony_cistatic int cmpc_keys_codes[] = { 10168c2ecf20Sopenharmony_ci KEY_UNKNOWN, 10178c2ecf20Sopenharmony_ci KEY_WLAN, 10188c2ecf20Sopenharmony_ci KEY_SWITCHVIDEOMODE, 10198c2ecf20Sopenharmony_ci KEY_BRIGHTNESSDOWN, 10208c2ecf20Sopenharmony_ci KEY_BRIGHTNESSUP, 10218c2ecf20Sopenharmony_ci KEY_VENDOR, 10228c2ecf20Sopenharmony_ci KEY_UNKNOWN, 10238c2ecf20Sopenharmony_ci KEY_CAMERA, 10248c2ecf20Sopenharmony_ci KEY_BACK, 10258c2ecf20Sopenharmony_ci KEY_FORWARD, 10268c2ecf20Sopenharmony_ci KEY_MAX 10278c2ecf20Sopenharmony_ci}; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_cistatic void cmpc_keys_handler(struct acpi_device *dev, u32 event) 10308c2ecf20Sopenharmony_ci{ 10318c2ecf20Sopenharmony_ci struct input_dev *inputdev; 10328c2ecf20Sopenharmony_ci int code = KEY_MAX; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes)) 10358c2ecf20Sopenharmony_ci code = cmpc_keys_codes[event & 0x0F]; 10368c2ecf20Sopenharmony_ci inputdev = dev_get_drvdata(&dev->dev); 10378c2ecf20Sopenharmony_ci input_report_key(inputdev, code, !(event & 0x10)); 10388c2ecf20Sopenharmony_ci input_sync(inputdev); 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_cistatic void cmpc_keys_idev_init(struct input_dev *inputdev) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci int i; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci set_bit(EV_KEY, inputdev->evbit); 10468c2ecf20Sopenharmony_ci for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++) 10478c2ecf20Sopenharmony_ci set_bit(cmpc_keys_codes[i], inputdev->keybit); 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_cistatic int cmpc_keys_add(struct acpi_device *acpi) 10518c2ecf20Sopenharmony_ci{ 10528c2ecf20Sopenharmony_ci return cmpc_add_acpi_notify_device(acpi, "cmpc_keys", 10538c2ecf20Sopenharmony_ci cmpc_keys_idev_init); 10548c2ecf20Sopenharmony_ci} 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_cistatic int cmpc_keys_remove(struct acpi_device *acpi) 10578c2ecf20Sopenharmony_ci{ 10588c2ecf20Sopenharmony_ci return cmpc_remove_acpi_notify_device(acpi); 10598c2ecf20Sopenharmony_ci} 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_cistatic const struct acpi_device_id cmpc_keys_device_ids[] = { 10628c2ecf20Sopenharmony_ci {CMPC_KEYS_HID, 0}, 10638c2ecf20Sopenharmony_ci {"", 0} 10648c2ecf20Sopenharmony_ci}; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_cistatic struct acpi_driver cmpc_keys_acpi_driver = { 10678c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 10688c2ecf20Sopenharmony_ci .name = "cmpc_keys", 10698c2ecf20Sopenharmony_ci .class = "cmpc_keys", 10708c2ecf20Sopenharmony_ci .ids = cmpc_keys_device_ids, 10718c2ecf20Sopenharmony_ci .ops = { 10728c2ecf20Sopenharmony_ci .add = cmpc_keys_add, 10738c2ecf20Sopenharmony_ci .remove = cmpc_keys_remove, 10748c2ecf20Sopenharmony_ci .notify = cmpc_keys_handler, 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci}; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci/* 10808c2ecf20Sopenharmony_ci * General init/exit code. 10818c2ecf20Sopenharmony_ci */ 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cistatic int cmpc_init(void) 10848c2ecf20Sopenharmony_ci{ 10858c2ecf20Sopenharmony_ci int r; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci r = acpi_bus_register_driver(&cmpc_keys_acpi_driver); 10888c2ecf20Sopenharmony_ci if (r) 10898c2ecf20Sopenharmony_ci goto failed_keys; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci r = acpi_bus_register_driver(&cmpc_ipml_acpi_driver); 10928c2ecf20Sopenharmony_ci if (r) 10938c2ecf20Sopenharmony_ci goto failed_bl; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver); 10968c2ecf20Sopenharmony_ci if (r) 10978c2ecf20Sopenharmony_ci goto failed_tablet; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci r = acpi_bus_register_driver(&cmpc_accel_acpi_driver); 11008c2ecf20Sopenharmony_ci if (r) 11018c2ecf20Sopenharmony_ci goto failed_accel; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci r = acpi_bus_register_driver(&cmpc_accel_acpi_driver_v4); 11048c2ecf20Sopenharmony_ci if (r) 11058c2ecf20Sopenharmony_ci goto failed_accel_v4; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci return r; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_cifailed_accel_v4: 11108c2ecf20Sopenharmony_ci acpi_bus_unregister_driver(&cmpc_accel_acpi_driver); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_cifailed_accel: 11138c2ecf20Sopenharmony_ci acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cifailed_tablet: 11168c2ecf20Sopenharmony_ci acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_cifailed_bl: 11198c2ecf20Sopenharmony_ci acpi_bus_unregister_driver(&cmpc_keys_acpi_driver); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_cifailed_keys: 11228c2ecf20Sopenharmony_ci return r; 11238c2ecf20Sopenharmony_ci} 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_cistatic void cmpc_exit(void) 11268c2ecf20Sopenharmony_ci{ 11278c2ecf20Sopenharmony_ci acpi_bus_unregister_driver(&cmpc_accel_acpi_driver_v4); 11288c2ecf20Sopenharmony_ci acpi_bus_unregister_driver(&cmpc_accel_acpi_driver); 11298c2ecf20Sopenharmony_ci acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver); 11308c2ecf20Sopenharmony_ci acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver); 11318c2ecf20Sopenharmony_ci acpi_bus_unregister_driver(&cmpc_keys_acpi_driver); 11328c2ecf20Sopenharmony_ci} 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_cimodule_init(cmpc_init); 11358c2ecf20Sopenharmony_cimodule_exit(cmpc_exit); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cistatic const struct acpi_device_id cmpc_device_ids[] = { 11388c2ecf20Sopenharmony_ci {CMPC_ACCEL_HID, 0}, 11398c2ecf20Sopenharmony_ci {CMPC_ACCEL_HID_V4, 0}, 11408c2ecf20Sopenharmony_ci {CMPC_TABLET_HID, 0}, 11418c2ecf20Sopenharmony_ci {CMPC_IPML_HID, 0}, 11428c2ecf20Sopenharmony_ci {CMPC_KEYS_HID, 0}, 11438c2ecf20Sopenharmony_ci {"", 0} 11448c2ecf20Sopenharmony_ci}; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, cmpc_device_ids); 1147