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