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