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 = ACPI_COMPANION(&pdev->dev);
534 struct fujitsu_bl *priv;
535 int ret;
536
537 if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
538 return -ENODEV;
539
540 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
541 if (!priv)
542 return -ENOMEM;
543
544 fujitsu_bl = priv;
545 strscpy(acpi_device_name(device), ACPI_FUJITSU_BL_DEVICE_NAME);
546 strscpy(acpi_device_class(device), ACPI_FUJITSU_CLASS);
547
548 platform_set_drvdata(pdev, priv);
549
550 pr_info("ACPI: %s [%s]\n",
551 acpi_device_name(device), acpi_device_bid(device));
552
553 if (get_max_brightness(&pdev->dev) <= 0)
554 priv->max_brightness = FUJITSU_LCD_N_LEVELS;
555 get_lcd_level(&pdev->dev);
556
557 ret = acpi_fujitsu_bl_input_setup(&pdev->dev);
558 if (ret)
559 return ret;
560
561 ret = fujitsu_backlight_register(&pdev->dev);
562 if (ret)
563 return ret;
564
565 return acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
566 acpi_fujitsu_bl_notify, &pdev->dev);
567 }
568
acpi_fujitsu_bl_remove(struct platform_device * pdev)569 static void acpi_fujitsu_bl_remove(struct platform_device *pdev)
570 {
571 acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev),
572 ACPI_DEVICE_NOTIFY, acpi_fujitsu_bl_notify);
573 }
574
575 /* ACPI device for hotkey handling */
576
577 static const struct key_entry keymap_default[] = {
578 { KE_KEY, KEY1_CODE, { KEY_PROG1 } },
579 { KE_KEY, KEY2_CODE, { KEY_PROG2 } },
580 { KE_KEY, KEY3_CODE, { KEY_PROG3 } },
581 { KE_KEY, KEY4_CODE, { KEY_PROG4 } },
582 { KE_KEY, KEY9_CODE, { KEY_RFKILL } },
583 /* Soft keys read from status flags */
584 { KE_KEY, FLAG_RFKILL, { KEY_RFKILL } },
585 { KE_KEY, FLAG_TOUCHPAD_TOGGLE, { KEY_TOUCHPAD_TOGGLE } },
586 { KE_KEY, FLAG_MICMUTE, { KEY_MICMUTE } },
587 { KE_END, 0 }
588 };
589
590 static const struct key_entry keymap_s64x0[] = {
591 { KE_KEY, KEY1_CODE, { KEY_SCREENLOCK } }, /* "Lock" */
592 { KE_KEY, KEY2_CODE, { KEY_HELP } }, /* "Mobility Center */
593 { KE_KEY, KEY3_CODE, { KEY_PROG3 } },
594 { KE_KEY, KEY4_CODE, { KEY_PROG4 } },
595 { KE_END, 0 }
596 };
597
598 static const struct key_entry keymap_p8010[] = {
599 { KE_KEY, KEY1_CODE, { KEY_HELP } }, /* "Support" */
600 { KE_KEY, KEY2_CODE, { KEY_PROG2 } },
601 { KE_KEY, KEY3_CODE, { KEY_SWITCHVIDEOMODE } }, /* "Presentation" */
602 { KE_KEY, KEY4_CODE, { KEY_WWW } }, /* "WWW" */
603 { KE_END, 0 }
604 };
605
606 static const struct key_entry keymap_s2110[] = {
607 { KE_KEY, KEY1_CODE, { KEY_PROG1 } }, /* "A" */
608 { KE_KEY, KEY2_CODE, { KEY_PROG2 } }, /* "B" */
609 { KE_KEY, KEY3_CODE, { KEY_WWW } }, /* "Internet" */
610 { KE_KEY, KEY4_CODE, { KEY_EMAIL } }, /* "E-mail" */
611 { KE_KEY, KEY5_CODE, { KEY_STOPCD } },
612 { KE_KEY, KEY6_CODE, { KEY_PLAYPAUSE } },
613 { KE_KEY, KEY7_CODE, { KEY_PREVIOUSSONG } },
614 { KE_KEY, KEY8_CODE, { KEY_NEXTSONG } },
615 { KE_END, 0 }
616 };
617
618 static const struct key_entry *keymap = keymap_default;
619
fujitsu_laptop_dmi_keymap_override(const struct dmi_system_id * id)620 static int fujitsu_laptop_dmi_keymap_override(const struct dmi_system_id *id)
621 {
622 pr_info("Identified laptop model '%s'\n", id->ident);
623 keymap = id->driver_data;
624 return 1;
625 }
626
627 static const struct dmi_system_id fujitsu_laptop_dmi_table[] = {
628 {
629 .callback = fujitsu_laptop_dmi_keymap_override,
630 .ident = "Fujitsu Siemens S6410",
631 .matches = {
632 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
633 DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
634 },
635 .driver_data = (void *)keymap_s64x0
636 },
637 {
638 .callback = fujitsu_laptop_dmi_keymap_override,
639 .ident = "Fujitsu Siemens S6420",
640 .matches = {
641 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
642 DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6420"),
643 },
644 .driver_data = (void *)keymap_s64x0
645 },
646 {
647 .callback = fujitsu_laptop_dmi_keymap_override,
648 .ident = "Fujitsu LifeBook P8010",
649 .matches = {
650 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
651 DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"),
652 },
653 .driver_data = (void *)keymap_p8010
654 },
655 {
656 .callback = fujitsu_laptop_dmi_keymap_override,
657 .ident = "Fujitsu LifeBook S2110",
658 .matches = {
659 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
660 DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S2110"),
661 },
662 .driver_data = (void *)keymap_s2110
663 },
664 {}
665 };
666
acpi_fujitsu_laptop_input_setup(struct device * dev)667 static int acpi_fujitsu_laptop_input_setup(struct device *dev)
668 {
669 struct fujitsu_laptop *priv = dev_get_drvdata(dev);
670 struct acpi_device *device = ACPI_COMPANION(dev);
671 int ret;
672
673 priv->input = devm_input_allocate_device(dev);
674 if (!priv->input)
675 return -ENOMEM;
676
677 snprintf(priv->phys, sizeof(priv->phys), "%s/input0",
678 acpi_device_hid(device));
679
680 priv->input->name = acpi_device_name(device);
681 priv->input->phys = priv->phys;
682 priv->input->id.bustype = BUS_HOST;
683
684 dmi_check_system(fujitsu_laptop_dmi_table);
685 ret = sparse_keymap_setup(priv->input, keymap, NULL);
686 if (ret)
687 return ret;
688
689 return input_register_device(priv->input);
690 }
691
fujitsu_laptop_platform_add(struct device * dev)692 static int fujitsu_laptop_platform_add(struct device *dev)
693 {
694 struct fujitsu_laptop *priv = dev_get_drvdata(dev);
695 int ret;
696
697 priv->pf_device = platform_device_alloc("fujitsu-laptop", PLATFORM_DEVID_NONE);
698 if (!priv->pf_device)
699 return -ENOMEM;
700
701 platform_set_drvdata(priv->pf_device, priv);
702
703 ret = platform_device_add(priv->pf_device);
704 if (ret)
705 goto err_put_platform_device;
706
707 ret = sysfs_create_group(&priv->pf_device->dev.kobj,
708 &fujitsu_pf_attribute_group);
709 if (ret)
710 goto err_del_platform_device;
711
712 return 0;
713
714 err_del_platform_device:
715 platform_device_del(priv->pf_device);
716 err_put_platform_device:
717 platform_device_put(priv->pf_device);
718
719 return ret;
720 }
721
fujitsu_laptop_platform_remove(struct device * dev)722 static void fujitsu_laptop_platform_remove(struct device *dev)
723 {
724 struct fujitsu_laptop *priv = dev_get_drvdata(dev);
725
726 sysfs_remove_group(&priv->pf_device->dev.kobj,
727 &fujitsu_pf_attribute_group);
728 platform_device_unregister(priv->pf_device);
729 }
730
logolamp_set(struct led_classdev * cdev,enum led_brightness brightness)731 static int logolamp_set(struct led_classdev *cdev,
732 enum led_brightness brightness)
733 {
734 struct device *parent = cdev->dev->parent;
735 int poweron = FUNC_LED_ON, always = FUNC_LED_ON;
736 int ret;
737
738 if (brightness < LED_HALF)
739 poweron = FUNC_LED_OFF;
740
741 if (brightness < LED_FULL)
742 always = FUNC_LED_OFF;
743
744 ret = call_fext_func(parent, FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron);
745 if (ret < 0)
746 return ret;
747
748 return call_fext_func(parent, FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always);
749 }
750
logolamp_get(struct led_classdev * cdev)751 static enum led_brightness logolamp_get(struct led_classdev *cdev)
752 {
753 struct device *parent = cdev->dev->parent;
754 int ret;
755
756 ret = call_fext_func(parent, FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
757 if (ret == FUNC_LED_ON)
758 return LED_FULL;
759
760 ret = call_fext_func(parent, FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
761 if (ret == FUNC_LED_ON)
762 return LED_HALF;
763
764 return LED_OFF;
765 }
766
kblamps_set(struct led_classdev * cdev,enum led_brightness brightness)767 static int kblamps_set(struct led_classdev *cdev,
768 enum led_brightness brightness)
769 {
770 struct device *parent = cdev->dev->parent;
771
772 if (brightness >= LED_FULL)
773 return call_fext_func(parent, FUNC_LEDS, 0x1, KEYBOARD_LAMPS,
774 FUNC_LED_ON);
775 else
776 return call_fext_func(parent, FUNC_LEDS, 0x1, KEYBOARD_LAMPS,
777 FUNC_LED_OFF);
778 }
779
kblamps_get(struct led_classdev * cdev)780 static enum led_brightness kblamps_get(struct led_classdev *cdev)
781 {
782 enum led_brightness brightness = LED_OFF;
783
784 if (call_fext_func(cdev->dev->parent,
785 FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON)
786 brightness = LED_FULL;
787
788 return brightness;
789 }
790
radio_led_set(struct led_classdev * cdev,enum led_brightness brightness)791 static int radio_led_set(struct led_classdev *cdev,
792 enum led_brightness brightness)
793 {
794 struct device *parent = cdev->dev->parent;
795
796 if (brightness >= LED_FULL)
797 return call_fext_func(parent, FUNC_FLAGS, 0x5, RADIO_LED_ON,
798 RADIO_LED_ON);
799 else
800 return call_fext_func(parent, FUNC_FLAGS, 0x5, RADIO_LED_ON,
801 0x0);
802 }
803
radio_led_get(struct led_classdev * cdev)804 static enum led_brightness radio_led_get(struct led_classdev *cdev)
805 {
806 struct device *parent = cdev->dev->parent;
807 enum led_brightness brightness = LED_OFF;
808
809 if (call_fext_func(parent, FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON)
810 brightness = LED_FULL;
811
812 return brightness;
813 }
814
eco_led_set(struct led_classdev * cdev,enum led_brightness brightness)815 static int eco_led_set(struct led_classdev *cdev,
816 enum led_brightness brightness)
817 {
818 struct device *parent = cdev->dev->parent;
819 int curr;
820
821 curr = call_fext_func(parent, FUNC_LEDS, 0x2, ECO_LED, 0x0);
822 if (brightness >= LED_FULL)
823 return call_fext_func(parent, FUNC_LEDS, 0x1, ECO_LED,
824 curr | ECO_LED_ON);
825 else
826 return call_fext_func(parent, FUNC_LEDS, 0x1, ECO_LED,
827 curr & ~ECO_LED_ON);
828 }
829
eco_led_get(struct led_classdev * cdev)830 static enum led_brightness eco_led_get(struct led_classdev *cdev)
831 {
832 struct device *parent = cdev->dev->parent;
833 enum led_brightness brightness = LED_OFF;
834
835 if (call_fext_func(parent, FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON)
836 brightness = LED_FULL;
837
838 return brightness;
839 }
840
acpi_fujitsu_laptop_leds_register(struct device * dev)841 static int acpi_fujitsu_laptop_leds_register(struct device *dev)
842 {
843 struct fujitsu_laptop *priv = dev_get_drvdata(dev);
844 struct led_classdev *led;
845 int ret;
846
847 if (call_fext_func(dev, FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
848 led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
849 if (!led)
850 return -ENOMEM;
851
852 led->name = "fujitsu::logolamp";
853 led->brightness_set_blocking = logolamp_set;
854 led->brightness_get = logolamp_get;
855 ret = devm_led_classdev_register(dev, led);
856 if (ret)
857 return ret;
858 }
859
860 if ((call_fext_func(dev, FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
861 (call_fext_func(dev, FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) {
862 led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
863 if (!led)
864 return -ENOMEM;
865
866 led->name = "fujitsu::kblamps";
867 led->brightness_set_blocking = kblamps_set;
868 led->brightness_get = kblamps_get;
869 ret = devm_led_classdev_register(dev, led);
870 if (ret)
871 return ret;
872 }
873
874 /*
875 * Some Fujitsu laptops have a radio toggle button in place of a slide
876 * switch and all such machines appear to also have an RF LED. Based on
877 * comparing DSDT tables of four Fujitsu Lifebook models (E744, E751,
878 * S7110, S8420; the first one has a radio toggle button, the other
879 * three have slide switches), bit 17 of flags_supported (the value
880 * returned by method S000 of ACPI device FUJ02E3) seems to indicate
881 * whether given model has a radio toggle button.
882 */
883 if (priv->flags_supported & BIT(17)) {
884 led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
885 if (!led)
886 return -ENOMEM;
887
888 led->name = "fujitsu::radio_led";
889 led->brightness_set_blocking = radio_led_set;
890 led->brightness_get = radio_led_get;
891 led->default_trigger = "rfkill-any";
892 ret = devm_led_classdev_register(dev, led);
893 if (ret)
894 return ret;
895 }
896
897 /* Support for eco led is not always signaled in bit corresponding
898 * to the bit used to control the led. According to the DSDT table,
899 * bit 14 seems to indicate presence of said led as well.
900 * Confirm by testing the status.
901 */
902 if ((call_fext_func(dev, FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) &&
903 (call_fext_func(dev, FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) {
904 led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
905 if (!led)
906 return -ENOMEM;
907
908 led->name = "fujitsu::eco_led";
909 led->brightness_set_blocking = eco_led_set;
910 led->brightness_get = eco_led_get;
911 ret = devm_led_classdev_register(dev, led);
912 if (ret)
913 return ret;
914 }
915
916 return 0;
917 }
918
acpi_fujitsu_laptop_press(struct device * dev,int scancode)919 static void acpi_fujitsu_laptop_press(struct device *dev, int scancode)
920 {
921 struct fujitsu_laptop *priv = dev_get_drvdata(dev);
922 int ret;
923
924 ret = kfifo_in_locked(&priv->fifo, (unsigned char *)&scancode,
925 sizeof(scancode), &priv->fifo_lock);
926 if (ret != sizeof(scancode)) {
927 dev_info(&priv->input->dev, "Could not push scancode [0x%x]\n",
928 scancode);
929 return;
930 }
931 sparse_keymap_report_event(priv->input, scancode, 1, false);
932 dev_dbg(&priv->input->dev, "Push scancode into ringbuffer [0x%x]\n",
933 scancode);
934 }
935
acpi_fujitsu_laptop_release(struct device * dev)936 static void acpi_fujitsu_laptop_release(struct device *dev)
937 {
938 struct fujitsu_laptop *priv = dev_get_drvdata(dev);
939 int scancode, ret;
940
941 while (true) {
942 ret = kfifo_out_locked(&priv->fifo, (unsigned char *)&scancode,
943 sizeof(scancode), &priv->fifo_lock);
944 if (ret != sizeof(scancode))
945 return;
946 sparse_keymap_report_event(priv->input, scancode, 0, false);
947 dev_dbg(&priv->input->dev,
948 "Pop scancode from ringbuffer [0x%x]\n", scancode);
949 }
950 }
951
acpi_fujitsu_laptop_notify(acpi_handle handle,u32 event,void * data)952 static void acpi_fujitsu_laptop_notify(acpi_handle handle, u32 event, void *data)
953 {
954 struct device *dev = data;
955 struct fujitsu_laptop *priv = dev_get_drvdata(dev);
956 unsigned long flags;
957 int scancode, i = 0;
958 unsigned int irb;
959
960 if (event != ACPI_FUJITSU_NOTIFY_CODE) {
961 acpi_handle_info(handle, "Unsupported event [0x%x]\n", event);
962 sparse_keymap_report_event(priv->input, -1, 1, true);
963 return;
964 }
965
966 if (priv->flags_supported)
967 priv->flags_state = call_fext_func(dev, FUNC_FLAGS, 0x4, 0x0, 0x0);
968
969 while ((irb = call_fext_func(dev, FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 &&
970 i++ < MAX_HOTKEY_RINGBUFFER_SIZE) {
971 scancode = irb & 0x4ff;
972 if (sparse_keymap_entry_from_scancode(priv->input, scancode))
973 acpi_fujitsu_laptop_press(dev, scancode);
974 else if (scancode == 0)
975 acpi_fujitsu_laptop_release(dev);
976 else
977 acpi_handle_info(handle, "Unknown GIRB result [%x]\n", irb);
978 }
979
980 /*
981 * First seen on the Skylake-based Lifebook E736/E746/E756), the
982 * touchpad toggle hotkey (Fn+F4) is handled in software. Other models
983 * have since added additional "soft keys". These are reported in the
984 * status flags queried using FUNC_FLAGS.
985 */
986 if (priv->flags_supported & (FLAG_SOFTKEYS)) {
987 flags = call_fext_func(dev, FUNC_FLAGS, 0x1, 0x0, 0x0);
988 flags &= (FLAG_SOFTKEYS);
989 for_each_set_bit(i, &flags, BITS_PER_LONG)
990 sparse_keymap_report_event(priv->input, BIT(i), 1, true);
991 }
992 }
993
acpi_fujitsu_laptop_probe(struct platform_device * pdev)994 static int acpi_fujitsu_laptop_probe(struct platform_device *pdev)
995 {
996 struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
997 struct fujitsu_laptop *priv;
998 int ret, i = 0;
999
1000 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
1001 if (!priv)
1002 return -ENOMEM;
1003
1004 WARN_ONCE(fext, "More than one FUJ02E3 ACPI device was found. Driver may not work as intended.");
1005 fext = &pdev->dev;
1006
1007 strscpy(acpi_device_name(device), ACPI_FUJITSU_LAPTOP_DEVICE_NAME);
1008 strscpy(acpi_device_class(device), ACPI_FUJITSU_CLASS);
1009
1010 platform_set_drvdata(pdev, priv);
1011
1012 /* kfifo */
1013 spin_lock_init(&priv->fifo_lock);
1014 ret = kfifo_alloc(&priv->fifo, RINGBUFFERSIZE * sizeof(int),
1015 GFP_KERNEL);
1016 if (ret)
1017 return ret;
1018
1019 pr_info("ACPI: %s [%s]\n",
1020 acpi_device_name(device), acpi_device_bid(device));
1021
1022 while (call_fext_func(fext, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 &&
1023 i++ < MAX_HOTKEY_RINGBUFFER_SIZE)
1024 ; /* No action, result is discarded */
1025 acpi_handle_debug(device->handle, "Discarded %i ringbuffer entries\n",
1026 i);
1027
1028 priv->flags_supported = call_fext_func(fext, FUNC_FLAGS, 0x0, 0x0, 0x0);
1029
1030 /* Make sure our bitmask of supported functions is cleared if the
1031 RFKILL function block is not implemented, like on the S7020. */
1032 if (priv->flags_supported == UNSUPPORTED_CMD)
1033 priv->flags_supported = 0;
1034
1035 if (priv->flags_supported)
1036 priv->flags_state = call_fext_func(fext, FUNC_FLAGS, 0x4, 0x0,
1037 0x0);
1038
1039 /* Suspect this is a keymap of the application panel, print it */
1040 acpi_handle_info(device->handle, "BTNI: [0x%x]\n",
1041 call_fext_func(fext, FUNC_BUTTONS, 0x0, 0x0, 0x0));
1042
1043 /* Sync backlight power status */
1044 if (fujitsu_bl && fujitsu_bl->bl_device &&
1045 acpi_video_get_backlight_type() == acpi_backlight_vendor) {
1046 if (call_fext_func(fext, FUNC_BACKLIGHT, 0x2,
1047 BACKLIGHT_PARAM_POWER, 0x0) == BACKLIGHT_OFF)
1048 fujitsu_bl->bl_device->props.power = BACKLIGHT_POWER_OFF;
1049 else
1050 fujitsu_bl->bl_device->props.power = BACKLIGHT_POWER_ON;
1051 }
1052
1053 ret = acpi_fujitsu_laptop_input_setup(fext);
1054 if (ret)
1055 goto err_free_fifo;
1056
1057 ret = acpi_fujitsu_laptop_leds_register(fext);
1058 if (ret)
1059 goto err_free_fifo;
1060
1061 ret = fujitsu_laptop_platform_add(fext);
1062 if (ret)
1063 goto err_free_fifo;
1064
1065 ret = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
1066 acpi_fujitsu_laptop_notify, fext);
1067 if (ret)
1068 goto err_platform_remove;
1069
1070 ret = fujitsu_battery_charge_control_add(fext);
1071 if (ret < 0)
1072 pr_warn("Unable to register battery charge control: %d\n", ret);
1073
1074 return 0;
1075
1076 err_platform_remove:
1077 fujitsu_laptop_platform_remove(fext);
1078 err_free_fifo:
1079 kfifo_free(&priv->fifo);
1080
1081 return ret;
1082 }
1083
acpi_fujitsu_laptop_remove(struct platform_device * pdev)1084 static void acpi_fujitsu_laptop_remove(struct platform_device *pdev)
1085 {
1086 struct fujitsu_laptop *priv = platform_get_drvdata(pdev);
1087
1088 fujitsu_battery_charge_control_remove(&pdev->dev);
1089
1090 acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev), ACPI_DEVICE_NOTIFY,
1091 acpi_fujitsu_laptop_notify);
1092
1093 fujitsu_laptop_platform_remove(&pdev->dev);
1094
1095 kfifo_free(&priv->fifo);
1096 }
1097
1098 /* Initialization */
1099
1100 static const struct acpi_device_id fujitsu_bl_device_ids[] = {
1101 {ACPI_FUJITSU_BL_HID, 0},
1102 {"", 0},
1103 };
1104
1105 static struct platform_driver acpi_fujitsu_bl_driver = {
1106 .probe = acpi_fujitsu_bl_probe,
1107 .remove = acpi_fujitsu_bl_remove,
1108 .driver = {
1109 .name = ACPI_FUJITSU_BL_DRIVER_NAME,
1110 .acpi_match_table = fujitsu_bl_device_ids,
1111 },
1112 };
1113
1114 static const struct acpi_device_id fujitsu_laptop_device_ids[] = {
1115 {ACPI_FUJITSU_LAPTOP_HID, 0},
1116 {"", 0},
1117 };
1118
1119 static struct platform_driver acpi_fujitsu_laptop_driver = {
1120 .probe = acpi_fujitsu_laptop_probe,
1121 .remove = acpi_fujitsu_laptop_remove,
1122 .driver = {
1123 .name = ACPI_FUJITSU_LAPTOP_DRIVER_NAME,
1124 .acpi_match_table = fujitsu_laptop_device_ids,
1125 },
1126 };
1127
1128 static const struct acpi_device_id fujitsu_ids[] __used = {
1129 {ACPI_FUJITSU_BL_HID, 0},
1130 {ACPI_FUJITSU_LAPTOP_HID, 0},
1131 {"", 0}
1132 };
1133 MODULE_DEVICE_TABLE(acpi, fujitsu_ids);
1134
fujitsu_init(void)1135 static int __init fujitsu_init(void)
1136 {
1137 int ret;
1138
1139 ret = platform_driver_register(&acpi_fujitsu_bl_driver);
1140 if (ret)
1141 return ret;
1142
1143 /* Register platform stuff */
1144
1145 ret = platform_driver_register(&fujitsu_pf_driver);
1146 if (ret)
1147 goto err_unregister_acpi;
1148
1149 /* Register laptop driver */
1150
1151 ret = platform_driver_register(&acpi_fujitsu_laptop_driver);
1152 if (ret)
1153 goto err_unregister_platform_driver;
1154
1155 pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n");
1156
1157 return 0;
1158
1159 err_unregister_platform_driver:
1160 platform_driver_unregister(&fujitsu_pf_driver);
1161 err_unregister_acpi:
1162 platform_driver_unregister(&acpi_fujitsu_bl_driver);
1163
1164 return ret;
1165 }
1166
fujitsu_cleanup(void)1167 static void __exit fujitsu_cleanup(void)
1168 {
1169 platform_driver_unregister(&acpi_fujitsu_laptop_driver);
1170
1171 platform_driver_unregister(&fujitsu_pf_driver);
1172
1173 platform_driver_unregister(&acpi_fujitsu_bl_driver);
1174
1175 pr_info("driver unloaded\n");
1176 }
1177
1178 module_init(fujitsu_init);
1179 module_exit(fujitsu_cleanup);
1180
1181 module_param(use_alt_lcd_levels, int, 0644);
1182 MODULE_PARM_DESC(use_alt_lcd_levels, "Interface used for setting LCD brightness level (-1 = auto, 0 = force SBLL, 1 = force SBL2)");
1183 module_param(disable_brightness_adjust, bool, 0644);
1184 MODULE_PARM_DESC(disable_brightness_adjust, "Disable LCD brightness adjustment");
1185
1186 MODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon");
1187 MODULE_DESCRIPTION("Fujitsu laptop extras support");
1188 MODULE_VERSION(FUJITSU_DRIVER_VERSION);
1189 MODULE_LICENSE("GPL");
1190