^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*-*-linux-c-*-*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@just42.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) Copyright (C) 2008 Peter Gruber <nokos@gmx.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) Copyright (C) 2008 Tony Vroon <tony@linx.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) Based on earlier work:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) Copyright (C) 2003 Shane Spencer <shane@bogomip.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) Adrian Yee <brewt-fujitsu@brewt.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) Templated from msi-laptop.c and thinkpad_acpi.c which is copyright
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) by its respective authors.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * fujitsu-laptop.c - Fujitsu laptop support, providing access to additional
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * features made available on a range of Fujitsu laptops including the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * P2xxx/P5xxx/S6xxx/S7xxx series.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * This driver implements a vendor-specific backlight control interface for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * Fujitsu laptops and provides support for hotkeys present on certain Fujitsu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * laptops.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * This driver has been tested on a Fujitsu Lifebook S6410, S7020 and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * P8010. It should work on most P-series and S-series Lifebooks, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * YMMV.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * The module parameter use_alt_lcd_levels switches between different ACPI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * brightness controls which are used by different Fujitsu laptops. In most
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * cases the correct method is automatically detected. "use_alt_lcd_levels=1"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * is applicable for a Fujitsu Lifebook S6410 if autodetection fails.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <linux/dmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #include <linux/backlight.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #include <linux/input/sparse-keymap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #include <linux/kfifo.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #include <linux/leds.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #include <acpi/video.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define FUJITSU_DRIVER_VERSION "0.6.0"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define FUJITSU_LCD_N_LEVELS 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define ACPI_FUJITSU_CLASS "fujitsu"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define ACPI_FUJITSU_BL_HID "FUJ02B1"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define ACPI_FUJITSU_BL_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI brightness driver"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define ACPI_FUJITSU_BL_DEVICE_NAME "Fujitsu FUJ02B1"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define ACPI_FUJITSU_LAPTOP_HID "FUJ02E3"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define ACPI_FUJITSU_LAPTOP_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define ACPI_FUJITSU_LAPTOP_DEVICE_NAME "Fujitsu FUJ02E3"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define ACPI_FUJITSU_NOTIFY_CODE 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /* FUNC interface - command values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define FUNC_FLAGS BIT(12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define FUNC_LEDS (BIT(12) | BIT(0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define FUNC_BUTTONS (BIT(12) | BIT(1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define FUNC_BACKLIGHT (BIT(12) | BIT(2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) /* FUNC interface - responses */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define UNSUPPORTED_CMD 0x80000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /* FUNC interface - status flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) #define FLAG_RFKILL BIT(5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define FLAG_LID BIT(8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define FLAG_DOCK BIT(9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define FLAG_TOUCHPAD_TOGGLE BIT(26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #define FLAG_MICMUTE BIT(29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define FLAG_SOFTKEYS (FLAG_RFKILL | FLAG_TOUCHPAD_TOGGLE | FLAG_MICMUTE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /* FUNC interface - LED control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define FUNC_LED_OFF BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define FUNC_LED_ON (BIT(0) | BIT(16) | BIT(17))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #define LOGOLAMP_POWERON BIT(13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #define LOGOLAMP_ALWAYS BIT(14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define KEYBOARD_LAMPS BIT(8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #define RADIO_LED_ON BIT(5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) #define ECO_LED BIT(16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define ECO_LED_ON BIT(19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) /* FUNC interface - backlight power control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #define BACKLIGHT_PARAM_POWER BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) #define BACKLIGHT_OFF (BIT(0) | BIT(1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) #define BACKLIGHT_ON 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /* Scancodes read from the GIRB register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #define KEY1_CODE 0x410
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define KEY2_CODE 0x411
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) #define KEY3_CODE 0x412
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #define KEY4_CODE 0x413
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) #define KEY5_CODE 0x420
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /* Hotkey ringbuffer limits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) #define MAX_HOTKEY_RINGBUFFER_SIZE 100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define RINGBUFFERSIZE 40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /* Module parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static int use_alt_lcd_levels = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static bool disable_brightness_adjust;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) /* Device controlling the backlight and associated keys */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) struct fujitsu_bl {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct input_dev *input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) char phys[32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct backlight_device *bl_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) unsigned int max_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) unsigned int brightness_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static struct fujitsu_bl *fujitsu_bl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) /* Device used to access hotkeys and other features on the laptop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) struct fujitsu_laptop {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) struct input_dev *input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) char phys[32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) struct platform_device *pf_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct kfifo fifo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) spinlock_t fifo_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) int flags_supported;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) int flags_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static struct acpi_device *fext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /* Fujitsu ACPI interface function */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) static int call_fext_func(struct acpi_device *device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) int func, int op, int feature, int state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) union acpi_object params[4] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) { .integer.type = ACPI_TYPE_INTEGER, .integer.value = func },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) { .integer.type = ACPI_TYPE_INTEGER, .integer.value = op },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) { .integer.type = ACPI_TYPE_INTEGER, .integer.value = feature },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) { .integer.type = ACPI_TYPE_INTEGER, .integer.value = state }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) struct acpi_object_list arg_list = { 4, params };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) unsigned long long value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) status = acpi_evaluate_integer(device->handle, "FUNC", &arg_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) acpi_handle_err(device->handle, "Failed to evaluate FUNC\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) acpi_handle_debug(device->handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) func, op, feature, state, (int)value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) /* Hardware access for LCD brightness control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) static int set_lcd_level(struct acpi_device *device, int level)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) struct fujitsu_bl *priv = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) char *method;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) switch (use_alt_lcd_levels) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) case -1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (acpi_has_method(device->handle, "SBL2"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) method = "SBL2";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) method = "SBLL";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) method = "SBL2";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) method = "SBLL";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) acpi_handle_debug(device->handle, "set lcd level via %s [%d]\n", method,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if (level < 0 || level >= priv->max_brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) status = acpi_execute_simple_method(device->handle, method, level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) acpi_handle_err(device->handle, "Failed to evaluate %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) method);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) priv->brightness_level = level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) static int get_lcd_level(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) struct fujitsu_bl *priv = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) unsigned long long state = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) acpi_status status = AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) acpi_handle_debug(device->handle, "get lcd level via GBLL\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) status = acpi_evaluate_integer(device->handle, "GBLL", NULL, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) priv->brightness_level = state & 0x0fffffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return priv->brightness_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) static int get_max_brightness(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) struct fujitsu_bl *priv = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) unsigned long long state = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) acpi_status status = AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) acpi_handle_debug(device->handle, "get max lcd level via RBLL\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) status = acpi_evaluate_integer(device->handle, "RBLL", NULL, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) priv->max_brightness = state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) return priv->max_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) /* Backlight device stuff */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) static int bl_get_brightness(struct backlight_device *b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) struct acpi_device *device = bl_get_data(b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) return b->props.power == FB_BLANK_POWERDOWN ? 0 : get_lcd_level(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) static int bl_update_status(struct backlight_device *b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) struct acpi_device *device = bl_get_data(b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (fext) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) if (b->props.power == FB_BLANK_POWERDOWN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) call_fext_func(fext, FUNC_BACKLIGHT, 0x1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) BACKLIGHT_PARAM_POWER, BACKLIGHT_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) call_fext_func(fext, FUNC_BACKLIGHT, 0x1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) BACKLIGHT_PARAM_POWER, BACKLIGHT_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) return set_lcd_level(device, b->props.brightness);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) static const struct backlight_ops fujitsu_bl_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) .get_brightness = bl_get_brightness,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) .update_status = bl_update_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) static ssize_t lid_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) struct fujitsu_laptop *priv = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) if (!(priv->flags_supported & FLAG_LID))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) return sprintf(buf, "unknown\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) if (priv->flags_state & FLAG_LID)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) return sprintf(buf, "open\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) return sprintf(buf, "closed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) struct fujitsu_laptop *priv = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (!(priv->flags_supported & FLAG_DOCK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return sprintf(buf, "unknown\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (priv->flags_state & FLAG_DOCK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) return sprintf(buf, "docked\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) return sprintf(buf, "undocked\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) static ssize_t radios_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) struct fujitsu_laptop *priv = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) if (!(priv->flags_supported & FLAG_RFKILL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) return sprintf(buf, "unknown\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (priv->flags_state & FLAG_RFKILL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) return sprintf(buf, "on\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) return sprintf(buf, "killed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) static DEVICE_ATTR_RO(lid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) static DEVICE_ATTR_RO(dock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) static DEVICE_ATTR_RO(radios);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) static struct attribute *fujitsu_pf_attributes[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) &dev_attr_lid.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) &dev_attr_dock.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) &dev_attr_radios.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) static const struct attribute_group fujitsu_pf_attribute_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .attrs = fujitsu_pf_attributes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) static struct platform_driver fujitsu_pf_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) .name = "fujitsu-laptop",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) /* ACPI device for LCD brightness control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) static const struct key_entry keymap_backlight[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) { KE_KEY, true, { KEY_BRIGHTNESSUP } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) { KE_KEY, false, { KEY_BRIGHTNESSDOWN } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) { KE_END, 0 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) static int acpi_fujitsu_bl_input_setup(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) struct fujitsu_bl *priv = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) priv->input = devm_input_allocate_device(&device->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (!priv->input)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) snprintf(priv->phys, sizeof(priv->phys), "%s/video/input0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) acpi_device_hid(device));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) priv->input->name = acpi_device_name(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) priv->input->phys = priv->phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) priv->input->id.bustype = BUS_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) priv->input->id.product = 0x06;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) ret = sparse_keymap_setup(priv->input, keymap_backlight, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) return input_register_device(priv->input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) static int fujitsu_backlight_register(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) struct fujitsu_bl *priv = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) const struct backlight_properties props = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) .brightness = priv->brightness_level,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) .max_brightness = priv->max_brightness - 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) .type = BACKLIGHT_PLATFORM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) struct backlight_device *bd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) bd = devm_backlight_device_register(&device->dev, "fujitsu-laptop",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) &device->dev, device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) &fujitsu_bl_ops, &props);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) if (IS_ERR(bd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return PTR_ERR(bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) priv->bl_device = bd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) static int acpi_fujitsu_bl_add(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) struct fujitsu_bl *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) fujitsu_bl = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) strcpy(acpi_device_name(device), ACPI_FUJITSU_BL_DEVICE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) strcpy(acpi_device_class(device), ACPI_FUJITSU_CLASS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) device->driver_data = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) pr_info("ACPI: %s [%s]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) acpi_device_name(device), acpi_device_bid(device));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (get_max_brightness(device) <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) priv->max_brightness = FUJITSU_LCD_N_LEVELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) get_lcd_level(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) ret = acpi_fujitsu_bl_input_setup(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) return fujitsu_backlight_register(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) /* Brightness notify */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) struct fujitsu_bl *priv = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) int oldb, newb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) if (event != ACPI_FUJITSU_NOTIFY_CODE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) acpi_handle_info(device->handle, "unsupported event [0x%x]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) sparse_keymap_report_event(priv->input, -1, 1, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) oldb = priv->brightness_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) get_lcd_level(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) newb = priv->brightness_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) acpi_handle_debug(device->handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) "brightness button event [%i -> %i]\n", oldb, newb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) if (oldb == newb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) if (!disable_brightness_adjust)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) set_lcd_level(device, newb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) sparse_keymap_report_event(priv->input, oldb < newb, 1, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) /* ACPI device for hotkey handling */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) static const struct key_entry keymap_default[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) { KE_KEY, KEY1_CODE, { KEY_PROG1 } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) { KE_KEY, KEY2_CODE, { KEY_PROG2 } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) { KE_KEY, KEY3_CODE, { KEY_PROG3 } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) { KE_KEY, KEY4_CODE, { KEY_PROG4 } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) { KE_KEY, KEY5_CODE, { KEY_RFKILL } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) /* Soft keys read from status flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) { KE_KEY, FLAG_RFKILL, { KEY_RFKILL } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) { KE_KEY, FLAG_TOUCHPAD_TOGGLE, { KEY_TOUCHPAD_TOGGLE } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) { KE_KEY, FLAG_MICMUTE, { KEY_MICMUTE } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) { KE_END, 0 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) static const struct key_entry keymap_s64x0[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) { KE_KEY, KEY1_CODE, { KEY_SCREENLOCK } }, /* "Lock" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) { KE_KEY, KEY2_CODE, { KEY_HELP } }, /* "Mobility Center */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) { KE_KEY, KEY3_CODE, { KEY_PROG3 } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) { KE_KEY, KEY4_CODE, { KEY_PROG4 } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) { KE_END, 0 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) static const struct key_entry keymap_p8010[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) { KE_KEY, KEY1_CODE, { KEY_HELP } }, /* "Support" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) { KE_KEY, KEY2_CODE, { KEY_PROG2 } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) { KE_KEY, KEY3_CODE, { KEY_SWITCHVIDEOMODE } }, /* "Presentation" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) { KE_KEY, KEY4_CODE, { KEY_WWW } }, /* "WWW" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) { KE_END, 0 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) static const struct key_entry *keymap = keymap_default;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) static int fujitsu_laptop_dmi_keymap_override(const struct dmi_system_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) pr_info("Identified laptop model '%s'\n", id->ident);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) keymap = id->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) static const struct dmi_system_id fujitsu_laptop_dmi_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) .callback = fujitsu_laptop_dmi_keymap_override,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) .ident = "Fujitsu Siemens S6410",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) .driver_data = (void *)keymap_s64x0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) .callback = fujitsu_laptop_dmi_keymap_override,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) .ident = "Fujitsu Siemens S6420",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6420"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) .driver_data = (void *)keymap_s64x0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) .callback = fujitsu_laptop_dmi_keymap_override,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) .ident = "Fujitsu LifeBook P8010",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) .driver_data = (void *)keymap_p8010
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) struct fujitsu_laptop *priv = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) priv->input = devm_input_allocate_device(&device->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) if (!priv->input)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) snprintf(priv->phys, sizeof(priv->phys), "%s/input0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) acpi_device_hid(device));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) priv->input->name = acpi_device_name(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) priv->input->phys = priv->phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) priv->input->id.bustype = BUS_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) dmi_check_system(fujitsu_laptop_dmi_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) ret = sparse_keymap_setup(priv->input, keymap, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) return input_register_device(priv->input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) static int fujitsu_laptop_platform_add(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) struct fujitsu_laptop *priv = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) priv->pf_device = platform_device_alloc("fujitsu-laptop", -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) if (!priv->pf_device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) platform_set_drvdata(priv->pf_device, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) ret = platform_device_add(priv->pf_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) goto err_put_platform_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) ret = sysfs_create_group(&priv->pf_device->dev.kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) &fujitsu_pf_attribute_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) goto err_del_platform_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) err_del_platform_device:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) platform_device_del(priv->pf_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) err_put_platform_device:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) platform_device_put(priv->pf_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) static void fujitsu_laptop_platform_remove(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) struct fujitsu_laptop *priv = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) sysfs_remove_group(&priv->pf_device->dev.kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) &fujitsu_pf_attribute_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) platform_device_unregister(priv->pf_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) static int logolamp_set(struct led_classdev *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) enum led_brightness brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) struct acpi_device *device = to_acpi_device(cdev->dev->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) int poweron = FUNC_LED_ON, always = FUNC_LED_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (brightness < LED_HALF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) poweron = FUNC_LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) if (brightness < LED_FULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) always = FUNC_LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) ret = call_fext_func(device, FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) return call_fext_func(device, FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) static enum led_brightness logolamp_get(struct led_classdev *cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) struct acpi_device *device = to_acpi_device(cdev->dev->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) ret = call_fext_func(device, FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) if (ret == FUNC_LED_ON)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) return LED_FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) ret = call_fext_func(device, FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) if (ret == FUNC_LED_ON)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) return LED_HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) return LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) static int kblamps_set(struct led_classdev *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) enum led_brightness brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) struct acpi_device *device = to_acpi_device(cdev->dev->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) if (brightness >= LED_FULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) return call_fext_func(device, FUNC_LEDS, 0x1, KEYBOARD_LAMPS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) FUNC_LED_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) return call_fext_func(device, FUNC_LEDS, 0x1, KEYBOARD_LAMPS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) FUNC_LED_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) static enum led_brightness kblamps_get(struct led_classdev *cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) struct acpi_device *device = to_acpi_device(cdev->dev->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) enum led_brightness brightness = LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) if (call_fext_func(device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) brightness = LED_FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) return brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) static int radio_led_set(struct led_classdev *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) enum led_brightness brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) struct acpi_device *device = to_acpi_device(cdev->dev->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) if (brightness >= LED_FULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) return call_fext_func(device, FUNC_FLAGS, 0x5, RADIO_LED_ON,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) RADIO_LED_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) return call_fext_func(device, FUNC_FLAGS, 0x5, RADIO_LED_ON,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) static enum led_brightness radio_led_get(struct led_classdev *cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) struct acpi_device *device = to_acpi_device(cdev->dev->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) enum led_brightness brightness = LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) if (call_fext_func(device, FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) brightness = LED_FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) return brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) static int eco_led_set(struct led_classdev *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) enum led_brightness brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) struct acpi_device *device = to_acpi_device(cdev->dev->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) int curr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) curr = call_fext_func(device, FUNC_LEDS, 0x2, ECO_LED, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) if (brightness >= LED_FULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) return call_fext_func(device, FUNC_LEDS, 0x1, ECO_LED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) curr | ECO_LED_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) return call_fext_func(device, FUNC_LEDS, 0x1, ECO_LED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) curr & ~ECO_LED_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) static enum led_brightness eco_led_get(struct led_classdev *cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) struct acpi_device *device = to_acpi_device(cdev->dev->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) enum led_brightness brightness = LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) if (call_fext_func(device, FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) brightness = LED_FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) return brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) struct fujitsu_laptop *priv = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) struct led_classdev *led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) if (call_fext_func(device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) if (!led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) led->name = "fujitsu::logolamp";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) led->brightness_set_blocking = logolamp_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) led->brightness_get = logolamp_get;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) ret = devm_led_classdev_register(&device->dev, led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) if ((call_fext_func(device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) (call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) if (!led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) led->name = "fujitsu::kblamps";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) led->brightness_set_blocking = kblamps_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) led->brightness_get = kblamps_get;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) ret = devm_led_classdev_register(&device->dev, led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) * Some Fujitsu laptops have a radio toggle button in place of a slide
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) * switch and all such machines appear to also have an RF LED. Based on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) * comparing DSDT tables of four Fujitsu Lifebook models (E744, E751,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) * S7110, S8420; the first one has a radio toggle button, the other
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) * three have slide switches), bit 17 of flags_supported (the value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) * returned by method S000 of ACPI device FUJ02E3) seems to indicate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) * whether given model has a radio toggle button.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) if (priv->flags_supported & BIT(17)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) if (!led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) led->name = "fujitsu::radio_led";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) led->brightness_set_blocking = radio_led_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) led->brightness_get = radio_led_get;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) led->default_trigger = "rfkill-any";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) ret = devm_led_classdev_register(&device->dev, led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) /* Support for eco led is not always signaled in bit corresponding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) * to the bit used to control the led. According to the DSDT table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) * bit 14 seems to indicate presence of said led as well.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) * Confirm by testing the status.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) if ((call_fext_func(device, FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) (call_fext_func(device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) if (!led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) led->name = "fujitsu::eco_led";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) led->brightness_set_blocking = eco_led_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) led->brightness_get = eco_led_get;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) ret = devm_led_classdev_register(&device->dev, led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) static int acpi_fujitsu_laptop_add(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) struct fujitsu_laptop *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) int ret, i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) WARN_ONCE(fext, "More than one FUJ02E3 ACPI device was found. Driver may not work as intended.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) fext = device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) strcpy(acpi_device_name(device), ACPI_FUJITSU_LAPTOP_DEVICE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) strcpy(acpi_device_class(device), ACPI_FUJITSU_CLASS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) device->driver_data = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) /* kfifo */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) spin_lock_init(&priv->fifo_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) ret = kfifo_alloc(&priv->fifo, RINGBUFFERSIZE * sizeof(int),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) pr_info("ACPI: %s [%s]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) acpi_device_name(device), acpi_device_bid(device));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) while (call_fext_func(device, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) i++ < MAX_HOTKEY_RINGBUFFER_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) ; /* No action, result is discarded */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) acpi_handle_debug(device->handle, "Discarded %i ringbuffer entries\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) priv->flags_supported = call_fext_func(device, FUNC_FLAGS, 0x0, 0x0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) /* Make sure our bitmask of supported functions is cleared if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) RFKILL function block is not implemented, like on the S7020. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) if (priv->flags_supported == UNSUPPORTED_CMD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) priv->flags_supported = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) if (priv->flags_supported)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) priv->flags_state = call_fext_func(device, FUNC_FLAGS, 0x4, 0x0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) /* Suspect this is a keymap of the application panel, print it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) acpi_handle_info(device->handle, "BTNI: [0x%x]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) /* Sync backlight power status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) if (fujitsu_bl && fujitsu_bl->bl_device &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) acpi_video_get_backlight_type() == acpi_backlight_vendor) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) if (call_fext_func(fext, FUNC_BACKLIGHT, 0x2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) BACKLIGHT_PARAM_POWER, 0x0) == BACKLIGHT_OFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) fujitsu_bl->bl_device->props.power = FB_BLANK_POWERDOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) fujitsu_bl->bl_device->props.power = FB_BLANK_UNBLANK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) ret = acpi_fujitsu_laptop_input_setup(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) goto err_free_fifo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) ret = acpi_fujitsu_laptop_leds_register(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) goto err_free_fifo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) ret = fujitsu_laptop_platform_add(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) goto err_free_fifo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) err_free_fifo:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) kfifo_free(&priv->fifo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) static int acpi_fujitsu_laptop_remove(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) struct fujitsu_laptop *priv = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) fujitsu_laptop_platform_remove(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) kfifo_free(&priv->fifo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) static void acpi_fujitsu_laptop_press(struct acpi_device *device, int scancode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) struct fujitsu_laptop *priv = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) ret = kfifo_in_locked(&priv->fifo, (unsigned char *)&scancode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) sizeof(scancode), &priv->fifo_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) if (ret != sizeof(scancode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) dev_info(&priv->input->dev, "Could not push scancode [0x%x]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) scancode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) sparse_keymap_report_event(priv->input, scancode, 1, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) dev_dbg(&priv->input->dev, "Push scancode into ringbuffer [0x%x]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) scancode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) static void acpi_fujitsu_laptop_release(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) struct fujitsu_laptop *priv = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) int scancode, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) while (true) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) ret = kfifo_out_locked(&priv->fifo, (unsigned char *)&scancode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) sizeof(scancode), &priv->fifo_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) if (ret != sizeof(scancode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) sparse_keymap_report_event(priv->input, scancode, 0, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) dev_dbg(&priv->input->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) "Pop scancode from ringbuffer [0x%x]\n", scancode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) struct fujitsu_laptop *priv = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) int scancode, i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) unsigned int irb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) if (event != ACPI_FUJITSU_NOTIFY_CODE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) acpi_handle_info(device->handle, "Unsupported event [0x%x]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) sparse_keymap_report_event(priv->input, -1, 1, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) if (priv->flags_supported)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) priv->flags_state = call_fext_func(device, FUNC_FLAGS, 0x4, 0x0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) while ((irb = call_fext_func(device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) i++ < MAX_HOTKEY_RINGBUFFER_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) scancode = irb & 0x4ff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) if (sparse_keymap_entry_from_scancode(priv->input, scancode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) acpi_fujitsu_laptop_press(device, scancode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) else if (scancode == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) acpi_fujitsu_laptop_release(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) acpi_handle_info(device->handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) "Unknown GIRB result [%x]\n", irb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) * First seen on the Skylake-based Lifebook E736/E746/E756), the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) * touchpad toggle hotkey (Fn+F4) is handled in software. Other models
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) * have since added additional "soft keys". These are reported in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) * status flags queried using FUNC_FLAGS.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) if (priv->flags_supported & (FLAG_SOFTKEYS)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) flags = call_fext_func(device, FUNC_FLAGS, 0x1, 0x0, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) flags &= (FLAG_SOFTKEYS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) for_each_set_bit(i, &flags, BITS_PER_LONG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) sparse_keymap_report_event(priv->input, BIT(i), 1, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) /* Initialization */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) static const struct acpi_device_id fujitsu_bl_device_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) {ACPI_FUJITSU_BL_HID, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) {"", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) static struct acpi_driver acpi_fujitsu_bl_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) .name = ACPI_FUJITSU_BL_DRIVER_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) .class = ACPI_FUJITSU_CLASS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) .ids = fujitsu_bl_device_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) .ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) .add = acpi_fujitsu_bl_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) .notify = acpi_fujitsu_bl_notify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) static const struct acpi_device_id fujitsu_laptop_device_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) {ACPI_FUJITSU_LAPTOP_HID, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) {"", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) static struct acpi_driver acpi_fujitsu_laptop_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) .name = ACPI_FUJITSU_LAPTOP_DRIVER_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) .class = ACPI_FUJITSU_CLASS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) .ids = fujitsu_laptop_device_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) .ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) .add = acpi_fujitsu_laptop_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) .remove = acpi_fujitsu_laptop_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) .notify = acpi_fujitsu_laptop_notify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) static const struct acpi_device_id fujitsu_ids[] __used = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) {ACPI_FUJITSU_BL_HID, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) {ACPI_FUJITSU_LAPTOP_HID, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) {"", 0}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) MODULE_DEVICE_TABLE(acpi, fujitsu_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) static int __init fujitsu_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) ret = acpi_bus_register_driver(&acpi_fujitsu_bl_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) /* Register platform stuff */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) ret = platform_driver_register(&fujitsu_pf_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) goto err_unregister_acpi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) /* Register laptop driver */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) ret = acpi_bus_register_driver(&acpi_fujitsu_laptop_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) goto err_unregister_platform_driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) err_unregister_platform_driver:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) platform_driver_unregister(&fujitsu_pf_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) err_unregister_acpi:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) static void __exit fujitsu_cleanup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) acpi_bus_unregister_driver(&acpi_fujitsu_laptop_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) platform_driver_unregister(&fujitsu_pf_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) pr_info("driver unloaded\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) module_init(fujitsu_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) module_exit(fujitsu_cleanup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) module_param(use_alt_lcd_levels, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) MODULE_PARM_DESC(use_alt_lcd_levels, "Interface used for setting LCD brightness level (-1 = auto, 0 = force SBLL, 1 = force SBL2)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) module_param(disable_brightness_adjust, bool, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) MODULE_PARM_DESC(disable_brightness_adjust, "Disable LCD brightness adjustment");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) MODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) MODULE_DESCRIPTION("Fujitsu laptop extras support");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) MODULE_VERSION(FUJITSU_DRIVER_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) MODULE_LICENSE("GPL");