xref: /linux/drivers/platform/x86/fujitsu-laptop.c (revision 5b05bb3f6c5716fab6911e12d60dd1f43ad9806a)
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