2 * ideapad-laptop.c - Lenovo IdeaPad ACPI Extras
4 * Copyright © 2010 Intel Corporation
5 * Copyright © 2010 David Woodhouse <dwmw2@infradead.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/init.h>
28 #include <linux/types.h>
29 #include <linux/acpi.h>
30 #include <linux/rfkill.h>
31 #include <linux/platform_device.h>
32 #include <linux/input.h>
33 #include <linux/input/sparse-keymap.h>
34 #include <linux/backlight.h>
36 #include <linux/debugfs.h>
37 #include <linux/seq_file.h>
38 #include <linux/i8042.h>
39 #include <linux/dmi.h>
40 #include <linux/device.h>
41 #include <acpi/video.h>
43 #define IDEAPAD_RFKILL_DEV_NUM (3)
45 #define BM_CONSERVATION_BIT (5)
47 #define CFG_BT_BIT (16)
48 #define CFG_3G_BIT (17)
49 #define CFG_WIFI_BIT (18)
50 #define CFG_CAMERA_BIT (19)
52 #if IS_ENABLED(CONFIG_ACPI_WMI)
53 static const char *const ideapad_wmi_fnesc_events
[] = {
54 "26CAB2E5-5CF1-46AE-AAC3-4A12B6BA50E6", /* Yoga 3 */
55 "56322276-8493-4CE8-A783-98C991274F5E", /* Yoga 700 */
60 BMCMD_CONSERVATION_ON
= 3,
61 BMCMD_CONSERVATION_OFF
= 5,
82 VPCCMD_R_ODD
, /* 0x21 */
87 VPCCMD_R_SPECIAL_BUTTONS
= 0x31,
88 VPCCMD_W_BL_POWER
= 0x33,
91 struct ideapad_rfk_priv
{
93 struct ideapad_private
*priv
;
96 struct ideapad_private
{
97 struct acpi_device
*adev
;
98 struct rfkill
*rfk
[IDEAPAD_RFKILL_DEV_NUM
];
99 struct ideapad_rfk_priv rfk_priv
[IDEAPAD_RFKILL_DEV_NUM
];
100 struct platform_device
*platform_device
;
101 struct input_dev
*inputdev
;
102 struct backlight_device
*blightdev
;
103 struct dentry
*debug
;
105 bool has_hw_rfkill_switch
;
106 const char *fnesc_guid
;
109 static bool no_bt_rfkill
;
110 module_param(no_bt_rfkill
, bool, 0444);
111 MODULE_PARM_DESC(no_bt_rfkill
, "No rfkill for bluetooth.");
116 #define IDEAPAD_EC_TIMEOUT (100) /* in ms */
118 static int read_method_int(acpi_handle handle
, const char *method
, int *val
)
121 unsigned long long result
;
123 status
= acpi_evaluate_integer(handle
, (char *)method
, NULL
, &result
);
124 if (ACPI_FAILURE(status
)) {
133 static int method_gbmd(acpi_handle handle
, unsigned long *ret
)
137 result
= read_method_int(handle
, "GBMD", &val
);
142 static int method_sbmc(acpi_handle handle
, int cmd
)
146 status
= acpi_execute_simple_method(handle
, "SBMC", cmd
);
147 return ACPI_FAILURE(status
) ? -1 : 0;
150 static int method_vpcr(acpi_handle handle
, int cmd
, int *ret
)
153 unsigned long long result
;
154 struct acpi_object_list params
;
155 union acpi_object in_obj
;
158 params
.pointer
= &in_obj
;
159 in_obj
.type
= ACPI_TYPE_INTEGER
;
160 in_obj
.integer
.value
= cmd
;
162 status
= acpi_evaluate_integer(handle
, "VPCR", ¶ms
, &result
);
164 if (ACPI_FAILURE(status
)) {
173 static int method_vpcw(acpi_handle handle
, int cmd
, int data
)
175 struct acpi_object_list params
;
176 union acpi_object in_obj
[2];
180 params
.pointer
= in_obj
;
181 in_obj
[0].type
= ACPI_TYPE_INTEGER
;
182 in_obj
[0].integer
.value
= cmd
;
183 in_obj
[1].type
= ACPI_TYPE_INTEGER
;
184 in_obj
[1].integer
.value
= data
;
186 status
= acpi_evaluate_object(handle
, "VPCW", ¶ms
, NULL
);
192 static int read_ec_data(acpi_handle handle
, int cmd
, unsigned long *data
)
195 unsigned long int end_jiffies
;
197 if (method_vpcw(handle
, 1, cmd
))
200 for (end_jiffies
= jiffies
+(HZ
)*IDEAPAD_EC_TIMEOUT
/1000+1;
201 time_before(jiffies
, end_jiffies
);) {
203 if (method_vpcr(handle
, 1, &val
))
206 if (method_vpcr(handle
, 0, &val
))
212 pr_err("timeout in read_ec_cmd\n");
216 static int write_ec_cmd(acpi_handle handle
, int cmd
, unsigned long data
)
219 unsigned long int end_jiffies
;
221 if (method_vpcw(handle
, 0, data
))
223 if (method_vpcw(handle
, 1, cmd
))
226 for (end_jiffies
= jiffies
+(HZ
)*IDEAPAD_EC_TIMEOUT
/1000+1;
227 time_before(jiffies
, end_jiffies
);) {
229 if (method_vpcr(handle
, 1, &val
))
234 pr_err("timeout in %s\n", __func__
);
241 static int debugfs_status_show(struct seq_file
*s
, void *data
)
243 struct ideapad_private
*priv
= s
->private;
249 if (!read_ec_data(priv
->adev
->handle
, VPCCMD_R_BL_MAX
, &value
))
250 seq_printf(s
, "Backlight max:\t%lu\n", value
);
251 if (!read_ec_data(priv
->adev
->handle
, VPCCMD_R_BL
, &value
))
252 seq_printf(s
, "Backlight now:\t%lu\n", value
);
253 if (!read_ec_data(priv
->adev
->handle
, VPCCMD_R_BL_POWER
, &value
))
254 seq_printf(s
, "BL power value:\t%s\n", value
? "On" : "Off");
255 seq_printf(s
, "=====================\n");
257 if (!read_ec_data(priv
->adev
->handle
, VPCCMD_R_RF
, &value
))
258 seq_printf(s
, "Radio status:\t%s(%lu)\n",
259 value
? "On" : "Off", value
);
260 if (!read_ec_data(priv
->adev
->handle
, VPCCMD_R_WIFI
, &value
))
261 seq_printf(s
, "Wifi status:\t%s(%lu)\n",
262 value
? "On" : "Off", value
);
263 if (!read_ec_data(priv
->adev
->handle
, VPCCMD_R_BT
, &value
))
264 seq_printf(s
, "BT status:\t%s(%lu)\n",
265 value
? "On" : "Off", value
);
266 if (!read_ec_data(priv
->adev
->handle
, VPCCMD_R_3G
, &value
))
267 seq_printf(s
, "3G status:\t%s(%lu)\n",
268 value
? "On" : "Off", value
);
269 seq_printf(s
, "=====================\n");
271 if (!read_ec_data(priv
->adev
->handle
, VPCCMD_R_TOUCHPAD
, &value
))
272 seq_printf(s
, "Touchpad status:%s(%lu)\n",
273 value
? "On" : "Off", value
);
274 if (!read_ec_data(priv
->adev
->handle
, VPCCMD_R_CAMERA
, &value
))
275 seq_printf(s
, "Camera status:\t%s(%lu)\n",
276 value
? "On" : "Off", value
);
277 seq_puts(s
, "=====================\n");
279 if (!method_gbmd(priv
->adev
->handle
, &value
)) {
280 seq_printf(s
, "Conservation mode:\t%s(%lu)\n",
281 test_bit(BM_CONSERVATION_BIT
, &value
) ? "On" : "Off",
287 DEFINE_SHOW_ATTRIBUTE(debugfs_status
);
289 static int debugfs_cfg_show(struct seq_file
*s
, void *data
)
291 struct ideapad_private
*priv
= s
->private;
294 seq_printf(s
, "cfg: N/A\n");
296 seq_printf(s
, "cfg: 0x%.8lX\n\nCapability: ",
298 if (test_bit(CFG_BT_BIT
, &priv
->cfg
))
299 seq_printf(s
, "Bluetooth ");
300 if (test_bit(CFG_3G_BIT
, &priv
->cfg
))
301 seq_printf(s
, "3G ");
302 if (test_bit(CFG_WIFI_BIT
, &priv
->cfg
))
303 seq_printf(s
, "Wireless ");
304 if (test_bit(CFG_CAMERA_BIT
, &priv
->cfg
))
305 seq_printf(s
, "Camera ");
306 seq_printf(s
, "\nGraphic: ");
307 switch ((priv
->cfg
)&0x700) {
309 seq_printf(s
, "Intel");
312 seq_printf(s
, "ATI");
315 seq_printf(s
, "Nvidia");
318 seq_printf(s
, "Intel and ATI");
321 seq_printf(s
, "Intel and Nvidia");
328 DEFINE_SHOW_ATTRIBUTE(debugfs_cfg
);
330 static int ideapad_debugfs_init(struct ideapad_private
*priv
)
334 priv
->debug
= debugfs_create_dir("ideapad", NULL
);
335 if (priv
->debug
== NULL
) {
336 pr_err("failed to create debugfs directory");
340 node
= debugfs_create_file("cfg", S_IRUGO
, priv
->debug
, priv
,
343 pr_err("failed to create cfg in debugfs");
347 node
= debugfs_create_file("status", S_IRUGO
, priv
->debug
, priv
,
348 &debugfs_status_fops
);
350 pr_err("failed to create status in debugfs");
360 static void ideapad_debugfs_exit(struct ideapad_private
*priv
)
362 debugfs_remove_recursive(priv
->debug
);
369 static ssize_t
show_ideapad_cam(struct device
*dev
,
370 struct device_attribute
*attr
,
373 unsigned long result
;
374 struct ideapad_private
*priv
= dev_get_drvdata(dev
);
376 if (read_ec_data(priv
->adev
->handle
, VPCCMD_R_CAMERA
, &result
))
377 return sprintf(buf
, "-1\n");
378 return sprintf(buf
, "%lu\n", result
);
381 static ssize_t
store_ideapad_cam(struct device
*dev
,
382 struct device_attribute
*attr
,
383 const char *buf
, size_t count
)
386 struct ideapad_private
*priv
= dev_get_drvdata(dev
);
390 if (sscanf(buf
, "%i", &state
) != 1)
392 ret
= write_ec_cmd(priv
->adev
->handle
, VPCCMD_W_CAMERA
, state
);
398 static DEVICE_ATTR(camera_power
, 0644, show_ideapad_cam
, store_ideapad_cam
);
400 static ssize_t
show_ideapad_fan(struct device
*dev
,
401 struct device_attribute
*attr
,
404 unsigned long result
;
405 struct ideapad_private
*priv
= dev_get_drvdata(dev
);
407 if (read_ec_data(priv
->adev
->handle
, VPCCMD_R_FAN
, &result
))
408 return sprintf(buf
, "-1\n");
409 return sprintf(buf
, "%lu\n", result
);
412 static ssize_t
store_ideapad_fan(struct device
*dev
,
413 struct device_attribute
*attr
,
414 const char *buf
, size_t count
)
417 struct ideapad_private
*priv
= dev_get_drvdata(dev
);
421 if (sscanf(buf
, "%i", &state
) != 1)
423 if (state
< 0 || state
> 4 || state
== 3)
425 ret
= write_ec_cmd(priv
->adev
->handle
, VPCCMD_W_FAN
, state
);
431 static DEVICE_ATTR(fan_mode
, 0644, show_ideapad_fan
, store_ideapad_fan
);
433 static ssize_t
touchpad_show(struct device
*dev
,
434 struct device_attribute
*attr
,
437 struct ideapad_private
*priv
= dev_get_drvdata(dev
);
438 unsigned long result
;
440 if (read_ec_data(priv
->adev
->handle
, VPCCMD_R_TOUCHPAD
, &result
))
441 return sprintf(buf
, "-1\n");
442 return sprintf(buf
, "%lu\n", result
);
445 /* Switch to RO for now: It might be revisited in the future */
446 static ssize_t __maybe_unused
touchpad_store(struct device
*dev
,
447 struct device_attribute
*attr
,
448 const char *buf
, size_t count
)
450 struct ideapad_private
*priv
= dev_get_drvdata(dev
);
454 ret
= kstrtobool(buf
, &state
);
458 ret
= write_ec_cmd(priv
->adev
->handle
, VPCCMD_W_TOUCHPAD
, state
);
464 static DEVICE_ATTR_RO(touchpad
);
466 static ssize_t
conservation_mode_show(struct device
*dev
,
467 struct device_attribute
*attr
,
470 struct ideapad_private
*priv
= dev_get_drvdata(dev
);
471 unsigned long result
;
473 if (method_gbmd(priv
->adev
->handle
, &result
))
474 return sprintf(buf
, "-1\n");
475 return sprintf(buf
, "%u\n", test_bit(BM_CONSERVATION_BIT
, &result
));
478 static ssize_t
conservation_mode_store(struct device
*dev
,
479 struct device_attribute
*attr
,
480 const char *buf
, size_t count
)
482 struct ideapad_private
*priv
= dev_get_drvdata(dev
);
486 ret
= kstrtobool(buf
, &state
);
490 ret
= method_sbmc(priv
->adev
->handle
, state
?
491 BMCMD_CONSERVATION_ON
:
492 BMCMD_CONSERVATION_OFF
);
498 static DEVICE_ATTR_RW(conservation_mode
);
500 static struct attribute
*ideapad_attributes
[] = {
501 &dev_attr_camera_power
.attr
,
502 &dev_attr_fan_mode
.attr
,
503 &dev_attr_touchpad
.attr
,
504 &dev_attr_conservation_mode
.attr
,
508 static umode_t
ideapad_is_visible(struct kobject
*kobj
,
509 struct attribute
*attr
,
512 struct device
*dev
= container_of(kobj
, struct device
, kobj
);
513 struct ideapad_private
*priv
= dev_get_drvdata(dev
);
516 if (attr
== &dev_attr_camera_power
.attr
)
517 supported
= test_bit(CFG_CAMERA_BIT
, &(priv
->cfg
));
518 else if (attr
== &dev_attr_fan_mode
.attr
) {
520 supported
= !read_ec_data(priv
->adev
->handle
, VPCCMD_R_FAN
,
522 } else if (attr
== &dev_attr_conservation_mode
.attr
) {
523 supported
= acpi_has_method(priv
->adev
->handle
, "GBMD") &&
524 acpi_has_method(priv
->adev
->handle
, "SBMC");
528 return supported
? attr
->mode
: 0;
531 static const struct attribute_group ideapad_attribute_group
= {
532 .is_visible
= ideapad_is_visible
,
533 .attrs
= ideapad_attributes
539 struct ideapad_rfk_data
{
546 static const struct ideapad_rfk_data ideapad_rfk_data
[] = {
547 { "ideapad_wlan", CFG_WIFI_BIT
, VPCCMD_W_WIFI
, RFKILL_TYPE_WLAN
},
548 { "ideapad_bluetooth", CFG_BT_BIT
, VPCCMD_W_BT
, RFKILL_TYPE_BLUETOOTH
},
549 { "ideapad_3g", CFG_3G_BIT
, VPCCMD_W_3G
, RFKILL_TYPE_WWAN
},
552 static int ideapad_rfk_set(void *data
, bool blocked
)
554 struct ideapad_rfk_priv
*priv
= data
;
555 int opcode
= ideapad_rfk_data
[priv
->dev
].opcode
;
557 return write_ec_cmd(priv
->priv
->adev
->handle
, opcode
, !blocked
);
560 static const struct rfkill_ops ideapad_rfk_ops
= {
561 .set_block
= ideapad_rfk_set
,
564 static void ideapad_sync_rfk_state(struct ideapad_private
*priv
)
566 unsigned long hw_blocked
= 0;
569 if (priv
->has_hw_rfkill_switch
) {
570 if (read_ec_data(priv
->adev
->handle
, VPCCMD_R_RF
, &hw_blocked
))
572 hw_blocked
= !hw_blocked
;
575 for (i
= 0; i
< IDEAPAD_RFKILL_DEV_NUM
; i
++)
577 rfkill_set_hw_state(priv
->rfk
[i
], hw_blocked
);
580 static int ideapad_register_rfkill(struct ideapad_private
*priv
, int dev
)
583 unsigned long sw_blocked
;
586 (ideapad_rfk_data
[dev
].type
== RFKILL_TYPE_BLUETOOTH
)) {
587 /* Force to enable bluetooth when no_bt_rfkill=1 */
588 write_ec_cmd(priv
->adev
->handle
,
589 ideapad_rfk_data
[dev
].opcode
, 1);
592 priv
->rfk_priv
[dev
].dev
= dev
;
593 priv
->rfk_priv
[dev
].priv
= priv
;
595 priv
->rfk
[dev
] = rfkill_alloc(ideapad_rfk_data
[dev
].name
,
596 &priv
->platform_device
->dev
,
597 ideapad_rfk_data
[dev
].type
,
599 &priv
->rfk_priv
[dev
]);
603 if (read_ec_data(priv
->adev
->handle
, ideapad_rfk_data
[dev
].opcode
-1,
605 rfkill_init_sw_state(priv
->rfk
[dev
], 0);
607 sw_blocked
= !sw_blocked
;
608 rfkill_init_sw_state(priv
->rfk
[dev
], sw_blocked
);
611 ret
= rfkill_register(priv
->rfk
[dev
]);
613 rfkill_destroy(priv
->rfk
[dev
]);
619 static void ideapad_unregister_rfkill(struct ideapad_private
*priv
, int dev
)
624 rfkill_unregister(priv
->rfk
[dev
]);
625 rfkill_destroy(priv
->rfk
[dev
]);
631 static int ideapad_sysfs_init(struct ideapad_private
*priv
)
633 return sysfs_create_group(&priv
->platform_device
->dev
.kobj
,
634 &ideapad_attribute_group
);
637 static void ideapad_sysfs_exit(struct ideapad_private
*priv
)
639 sysfs_remove_group(&priv
->platform_device
->dev
.kobj
,
640 &ideapad_attribute_group
);
646 static const struct key_entry ideapad_keymap
[] = {
647 { KE_KEY
, 6, { KEY_SWITCHVIDEOMODE
} },
648 { KE_KEY
, 7, { KEY_CAMERA
} },
649 { KE_KEY
, 8, { KEY_MICMUTE
} },
650 { KE_KEY
, 11, { KEY_F16
} },
651 { KE_KEY
, 13, { KEY_WLAN
} },
652 { KE_KEY
, 16, { KEY_PROG1
} },
653 { KE_KEY
, 17, { KEY_PROG2
} },
654 { KE_KEY
, 64, { KEY_PROG3
} },
655 { KE_KEY
, 65, { KEY_PROG4
} },
656 { KE_KEY
, 66, { KEY_TOUCHPAD_OFF
} },
657 { KE_KEY
, 67, { KEY_TOUCHPAD_ON
} },
658 { KE_KEY
, 128, { KEY_ESC
} },
663 static int ideapad_input_init(struct ideapad_private
*priv
)
665 struct input_dev
*inputdev
;
668 inputdev
= input_allocate_device();
672 inputdev
->name
= "Ideapad extra buttons";
673 inputdev
->phys
= "ideapad/input0";
674 inputdev
->id
.bustype
= BUS_HOST
;
675 inputdev
->dev
.parent
= &priv
->platform_device
->dev
;
677 error
= sparse_keymap_setup(inputdev
, ideapad_keymap
, NULL
);
679 pr_err("Unable to setup input device keymap\n");
683 error
= input_register_device(inputdev
);
685 pr_err("Unable to register input device\n");
689 priv
->inputdev
= inputdev
;
693 input_free_device(inputdev
);
697 static void ideapad_input_exit(struct ideapad_private
*priv
)
699 input_unregister_device(priv
->inputdev
);
700 priv
->inputdev
= NULL
;
703 static void ideapad_input_report(struct ideapad_private
*priv
,
704 unsigned long scancode
)
706 sparse_keymap_report_event(priv
->inputdev
, scancode
, 1, true);
709 static void ideapad_input_novokey(struct ideapad_private
*priv
)
711 unsigned long long_pressed
;
713 if (read_ec_data(priv
->adev
->handle
, VPCCMD_R_NOVO
, &long_pressed
))
716 ideapad_input_report(priv
, 17);
718 ideapad_input_report(priv
, 16);
721 static void ideapad_check_special_buttons(struct ideapad_private
*priv
)
723 unsigned long bit
, value
;
725 read_ec_data(priv
->adev
->handle
, VPCCMD_R_SPECIAL_BUTTONS
, &value
);
727 for (bit
= 0; bit
< 16; bit
++) {
728 if (test_bit(bit
, &value
)) {
732 /* Thermal Management button */
733 ideapad_input_report(priv
, 65);
736 /* OneKey Theater button */
737 ideapad_input_report(priv
, 64);
740 pr_info("Unknown special button: %lu\n", bit
);
750 static int ideapad_backlight_get_brightness(struct backlight_device
*blightdev
)
752 struct ideapad_private
*priv
= bl_get_data(blightdev
);
758 if (read_ec_data(priv
->adev
->handle
, VPCCMD_R_BL
, &now
))
763 static int ideapad_backlight_update_status(struct backlight_device
*blightdev
)
765 struct ideapad_private
*priv
= bl_get_data(blightdev
);
770 if (write_ec_cmd(priv
->adev
->handle
, VPCCMD_W_BL
,
771 blightdev
->props
.brightness
))
773 if (write_ec_cmd(priv
->adev
->handle
, VPCCMD_W_BL_POWER
,
774 blightdev
->props
.power
== FB_BLANK_POWERDOWN
? 0 : 1))
780 static const struct backlight_ops ideapad_backlight_ops
= {
781 .get_brightness
= ideapad_backlight_get_brightness
,
782 .update_status
= ideapad_backlight_update_status
,
785 static int ideapad_backlight_init(struct ideapad_private
*priv
)
787 struct backlight_device
*blightdev
;
788 struct backlight_properties props
;
789 unsigned long max
, now
, power
;
791 if (read_ec_data(priv
->adev
->handle
, VPCCMD_R_BL_MAX
, &max
))
793 if (read_ec_data(priv
->adev
->handle
, VPCCMD_R_BL
, &now
))
795 if (read_ec_data(priv
->adev
->handle
, VPCCMD_R_BL_POWER
, &power
))
798 memset(&props
, 0, sizeof(struct backlight_properties
));
799 props
.max_brightness
= max
;
800 props
.type
= BACKLIGHT_PLATFORM
;
801 blightdev
= backlight_device_register("ideapad",
802 &priv
->platform_device
->dev
,
804 &ideapad_backlight_ops
,
806 if (IS_ERR(blightdev
)) {
807 pr_err("Could not register backlight device\n");
808 return PTR_ERR(blightdev
);
811 priv
->blightdev
= blightdev
;
812 blightdev
->props
.brightness
= now
;
813 blightdev
->props
.power
= power
? FB_BLANK_UNBLANK
: FB_BLANK_POWERDOWN
;
814 backlight_update_status(blightdev
);
819 static void ideapad_backlight_exit(struct ideapad_private
*priv
)
821 backlight_device_unregister(priv
->blightdev
);
822 priv
->blightdev
= NULL
;
825 static void ideapad_backlight_notify_power(struct ideapad_private
*priv
)
828 struct backlight_device
*blightdev
= priv
->blightdev
;
832 if (read_ec_data(priv
->adev
->handle
, VPCCMD_R_BL_POWER
, &power
))
834 blightdev
->props
.power
= power
? FB_BLANK_UNBLANK
: FB_BLANK_POWERDOWN
;
837 static void ideapad_backlight_notify_brightness(struct ideapad_private
*priv
)
841 /* if we control brightness via acpi video driver */
842 if (priv
->blightdev
== NULL
) {
843 read_ec_data(priv
->adev
->handle
, VPCCMD_R_BL
, &now
);
847 backlight_force_update(priv
->blightdev
, BACKLIGHT_UPDATE_HOTKEY
);
853 static void ideapad_sync_touchpad_state(struct ideapad_private
*priv
)
857 /* Without reading from EC touchpad LED doesn't switch state */
858 if (!read_ec_data(priv
->adev
->handle
, VPCCMD_R_TOUCHPAD
, &value
)) {
859 /* Some IdeaPads don't really turn off touchpad - they only
860 * switch the LED state. We (de)activate KBC AUX port to turn
861 * touchpad off and on. We send KEY_TOUCHPAD_OFF and
862 * KEY_TOUCHPAD_ON to not to get out of sync with LED */
864 i8042_command(¶m
, value
? I8042_CMD_AUX_ENABLE
:
865 I8042_CMD_AUX_DISABLE
);
866 ideapad_input_report(priv
, value
? 67 : 66);
870 static void ideapad_acpi_notify(acpi_handle handle
, u32 event
, void *data
)
872 struct ideapad_private
*priv
= data
;
873 unsigned long vpc1
, vpc2
, vpc_bit
;
875 if (read_ec_data(handle
, VPCCMD_R_VPC1
, &vpc1
))
877 if (read_ec_data(handle
, VPCCMD_R_VPC2
, &vpc2
))
880 vpc1
= (vpc2
<< 8) | vpc1
;
881 for (vpc_bit
= 0; vpc_bit
< 16; vpc_bit
++) {
882 if (test_bit(vpc_bit
, &vpc1
)) {
885 ideapad_sync_rfk_state(priv
);
892 ideapad_input_report(priv
, vpc_bit
);
895 ideapad_sync_touchpad_state(priv
);
898 ideapad_backlight_notify_brightness(priv
);
901 ideapad_input_novokey(priv
);
904 ideapad_backlight_notify_power(priv
);
907 ideapad_check_special_buttons(priv
);
910 /* Some IdeaPads report event 1 every ~20
911 * seconds while on battery power; some
912 * report this when changing to/from tablet
913 * mode. Squelch this event.
917 pr_info("Unknown event: %lu\n", vpc_bit
);
923 #if IS_ENABLED(CONFIG_ACPI_WMI)
924 static void ideapad_wmi_notify(u32 value
, void *context
)
928 ideapad_input_report(context
, value
);
931 pr_info("Unknown WMI event %u\n", value
);
937 * Some ideapads don't have a hardware rfkill switch, reading VPCCMD_R_RF
938 * always results in 0 on these models, causing ideapad_laptop to wrongly
939 * report all radios as hardware-blocked.
941 static const struct dmi_system_id no_hw_rfkill_list
[] = {
943 .ident
= "Lenovo RESCUER R720-15IKBN",
945 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
946 DMI_MATCH(DMI_BOARD_NAME
, "80WW"),
950 .ident
= "Lenovo G40-30",
952 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
953 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo G40-30"),
957 .ident
= "Lenovo G50-30",
959 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
960 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo G50-30"),
964 .ident
= "Lenovo V310-14IKB",
966 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
967 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo V310-14IKB"),
971 .ident
= "Lenovo V310-14ISK",
973 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
974 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo V310-14ISK"),
978 .ident
= "Lenovo V310-15IKB",
980 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
981 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo V310-15IKB"),
985 .ident
= "Lenovo V310-15ISK",
987 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
988 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo V310-15ISK"),
992 .ident
= "Lenovo V510-15IKB",
994 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
995 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo V510-15IKB"),
999 .ident
= "Lenovo ideapad 300-15IBR",
1001 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1002 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo ideapad 300-15IBR"),
1006 .ident
= "Lenovo ideapad 300-15IKB",
1008 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1009 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo ideapad 300-15IKB"),
1013 .ident
= "Lenovo ideapad 300S-11IBR",
1015 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1016 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo ideapad 300S-11BR"),
1020 .ident
= "Lenovo ideapad 310-15ABR",
1022 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1023 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo ideapad 310-15ABR"),
1027 .ident
= "Lenovo ideapad 310-15IAP",
1029 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1030 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo ideapad 310-15IAP"),
1034 .ident
= "Lenovo ideapad 310-15IKB",
1036 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1037 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo ideapad 310-15IKB"),
1041 .ident
= "Lenovo ideapad 310-15ISK",
1043 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1044 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo ideapad 310-15ISK"),
1048 .ident
= "Lenovo ideapad Y700-14ISK",
1050 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1051 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo ideapad Y700-14ISK"),
1055 .ident
= "Lenovo ideapad Y700-15ACZ",
1057 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1058 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo ideapad Y700-15ACZ"),
1062 .ident
= "Lenovo ideapad Y700-15ISK",
1064 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1065 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo ideapad Y700-15ISK"),
1069 .ident
= "Lenovo ideapad Y700 Touch-15ISK",
1071 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1072 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo ideapad Y700 Touch-15ISK"),
1076 .ident
= "Lenovo ideapad Y700-17ISK",
1078 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1079 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo ideapad Y700-17ISK"),
1083 .ident
= "Lenovo Legion Y520-15IKBN",
1085 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1086 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo Y520-15IKBN"),
1090 .ident
= "Lenovo Legion Y720-15IKB",
1092 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1093 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo Y720-15IKB"),
1097 .ident
= "Lenovo Legion Y720-15IKBN",
1099 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1100 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo Y720-15IKBN"),
1104 .ident
= "Lenovo Yoga 2 11 / 13 / Pro",
1106 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1107 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo Yoga 2"),
1111 .ident
= "Lenovo Yoga 2 11 / 13 / Pro",
1113 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1114 DMI_MATCH(DMI_BOARD_NAME
, "Yoga2"),
1118 .ident
= "Lenovo Yoga 3 1170 / 1470",
1120 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1121 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo Yoga 3"),
1125 .ident
= "Lenovo Yoga 3 Pro 1370",
1127 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1128 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo YOGA 3"),
1132 .ident
= "Lenovo Yoga 700",
1134 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1135 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo YOGA 700"),
1139 .ident
= "Lenovo Yoga 900",
1141 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1142 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo YOGA 900"),
1146 .ident
= "Lenovo Yoga 900",
1148 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1149 DMI_MATCH(DMI_BOARD_NAME
, "VIUU4"),
1153 .ident
= "Lenovo YOGA 910-13IKB",
1155 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1156 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo YOGA 910-13IKB"),
1160 .ident
= "Lenovo YOGA 920-13IKB",
1162 DMI_MATCH(DMI_SYS_VENDOR
, "LENOVO"),
1163 DMI_MATCH(DMI_PRODUCT_VERSION
, "Lenovo YOGA 920-13IKB"),
1169 static int ideapad_acpi_add(struct platform_device
*pdev
)
1173 struct ideapad_private
*priv
;
1174 struct acpi_device
*adev
;
1176 ret
= acpi_bus_get_device(ACPI_HANDLE(&pdev
->dev
), &adev
);
1180 if (read_method_int(adev
->handle
, "_CFG", &cfg
))
1183 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
1187 dev_set_drvdata(&pdev
->dev
, priv
);
1190 priv
->platform_device
= pdev
;
1191 priv
->has_hw_rfkill_switch
= !dmi_check_system(no_hw_rfkill_list
);
1193 ret
= ideapad_sysfs_init(priv
);
1197 ret
= ideapad_debugfs_init(priv
);
1199 goto debugfs_failed
;
1201 ret
= ideapad_input_init(priv
);
1206 * On some models without a hw-switch (the yoga 2 13 at least)
1207 * VPCCMD_W_RF must be explicitly set to 1 for the wifi to work.
1209 if (!priv
->has_hw_rfkill_switch
)
1210 write_ec_cmd(priv
->adev
->handle
, VPCCMD_W_RF
, 1);
1212 for (i
= 0; i
< IDEAPAD_RFKILL_DEV_NUM
; i
++)
1213 if (test_bit(ideapad_rfk_data
[i
].cfgbit
, &priv
->cfg
))
1214 ideapad_register_rfkill(priv
, i
);
1216 ideapad_sync_rfk_state(priv
);
1217 ideapad_sync_touchpad_state(priv
);
1219 if (acpi_video_get_backlight_type() == acpi_backlight_vendor
) {
1220 ret
= ideapad_backlight_init(priv
);
1221 if (ret
&& ret
!= -ENODEV
)
1222 goto backlight_failed
;
1224 ret
= acpi_install_notify_handler(adev
->handle
,
1225 ACPI_DEVICE_NOTIFY
, ideapad_acpi_notify
, priv
);
1227 goto notification_failed
;
1229 #if IS_ENABLED(CONFIG_ACPI_WMI)
1230 for (i
= 0; i
< ARRAY_SIZE(ideapad_wmi_fnesc_events
); i
++) {
1231 ret
= wmi_install_notify_handler(ideapad_wmi_fnesc_events
[i
],
1232 ideapad_wmi_notify
, priv
);
1234 priv
->fnesc_guid
= ideapad_wmi_fnesc_events
[i
];
1238 if (ret
!= AE_OK
&& ret
!= AE_NOT_EXIST
)
1239 goto notification_failed_wmi
;
1243 #if IS_ENABLED(CONFIG_ACPI_WMI)
1244 notification_failed_wmi
:
1245 acpi_remove_notify_handler(priv
->adev
->handle
,
1246 ACPI_DEVICE_NOTIFY
, ideapad_acpi_notify
);
1248 notification_failed
:
1249 ideapad_backlight_exit(priv
);
1251 for (i
= 0; i
< IDEAPAD_RFKILL_DEV_NUM
; i
++)
1252 ideapad_unregister_rfkill(priv
, i
);
1253 ideapad_input_exit(priv
);
1255 ideapad_debugfs_exit(priv
);
1257 ideapad_sysfs_exit(priv
);
1261 static int ideapad_acpi_remove(struct platform_device
*pdev
)
1263 struct ideapad_private
*priv
= dev_get_drvdata(&pdev
->dev
);
1266 #if IS_ENABLED(CONFIG_ACPI_WMI)
1267 if (priv
->fnesc_guid
)
1268 wmi_remove_notify_handler(priv
->fnesc_guid
);
1270 acpi_remove_notify_handler(priv
->adev
->handle
,
1271 ACPI_DEVICE_NOTIFY
, ideapad_acpi_notify
);
1272 ideapad_backlight_exit(priv
);
1273 for (i
= 0; i
< IDEAPAD_RFKILL_DEV_NUM
; i
++)
1274 ideapad_unregister_rfkill(priv
, i
);
1275 ideapad_input_exit(priv
);
1276 ideapad_debugfs_exit(priv
);
1277 ideapad_sysfs_exit(priv
);
1278 dev_set_drvdata(&pdev
->dev
, NULL
);
1283 #ifdef CONFIG_PM_SLEEP
1284 static int ideapad_acpi_resume(struct device
*device
)
1286 struct ideapad_private
*priv
;
1290 priv
= dev_get_drvdata(device
);
1292 ideapad_sync_rfk_state(priv
);
1293 ideapad_sync_touchpad_state(priv
);
1297 static SIMPLE_DEV_PM_OPS(ideapad_pm
, NULL
, ideapad_acpi_resume
);
1299 static const struct acpi_device_id ideapad_device_ids
[] = {
1303 MODULE_DEVICE_TABLE(acpi
, ideapad_device_ids
);
1305 static struct platform_driver ideapad_acpi_driver
= {
1306 .probe
= ideapad_acpi_add
,
1307 .remove
= ideapad_acpi_remove
,
1309 .name
= "ideapad_acpi",
1311 .acpi_match_table
= ACPI_PTR(ideapad_device_ids
),
1315 module_platform_driver(ideapad_acpi_driver
);
1317 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
1318 MODULE_DESCRIPTION("IdeaPad ACPI Extras");
1319 MODULE_LICENSE("GPL");