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