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