]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/platform/x86/ideapad-laptop.c
sparc,leon: Select USB_UHCI_BIG_ENDIAN_{MMIO,DESC}
[linux.git] / drivers / platform / x86 / ideapad-laptop.c
1 /*
2  *  ideapad-laptop.c - Lenovo IdeaPad ACPI Extras
3  *
4  *  Copyright © 2010 Intel Corporation
5  *  Copyright © 2010 David Woodhouse <dwmw2@infradead.org>
6  *
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.
11  *
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.
16  *
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
20  *  02110-1301, USA.
21  */
22
23 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24
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>
35 #include <linux/fb.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>
42
43 #define IDEAPAD_RFKILL_DEV_NUM  (3)
44
45 #define BM_CONSERVATION_BIT (5)
46
47 #define CFG_BT_BIT      (16)
48 #define CFG_3G_BIT      (17)
49 #define CFG_WIFI_BIT    (18)
50 #define CFG_CAMERA_BIT  (19)
51
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 */
56 };
57 #endif
58
59 enum {
60         BMCMD_CONSERVATION_ON = 3,
61         BMCMD_CONSERVATION_OFF = 5,
62 };
63
64 enum {
65         VPCCMD_R_VPC1 = 0x10,
66         VPCCMD_R_BL_MAX,
67         VPCCMD_R_BL,
68         VPCCMD_W_BL,
69         VPCCMD_R_WIFI,
70         VPCCMD_W_WIFI,
71         VPCCMD_R_BT,
72         VPCCMD_W_BT,
73         VPCCMD_R_BL_POWER,
74         VPCCMD_R_NOVO,
75         VPCCMD_R_VPC2,
76         VPCCMD_R_TOUCHPAD,
77         VPCCMD_W_TOUCHPAD,
78         VPCCMD_R_CAMERA,
79         VPCCMD_W_CAMERA,
80         VPCCMD_R_3G,
81         VPCCMD_W_3G,
82         VPCCMD_R_ODD, /* 0x21 */
83         VPCCMD_W_FAN,
84         VPCCMD_R_RF,
85         VPCCMD_W_RF,
86         VPCCMD_R_FAN = 0x2B,
87         VPCCMD_R_SPECIAL_BUTTONS = 0x31,
88         VPCCMD_W_BL_POWER = 0x33,
89 };
90
91 struct ideapad_rfk_priv {
92         int dev;
93         struct ideapad_private *priv;
94 };
95
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;
104         unsigned long cfg;
105         bool has_hw_rfkill_switch;
106         const char *fnesc_guid;
107 };
108
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.");
112
113 /*
114  * ACPI Helpers
115  */
116 #define IDEAPAD_EC_TIMEOUT (100) /* in ms */
117
118 static int read_method_int(acpi_handle handle, const char *method, int *val)
119 {
120         acpi_status status;
121         unsigned long long result;
122
123         status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
124         if (ACPI_FAILURE(status)) {
125                 *val = -1;
126                 return -1;
127         }
128         *val = result;
129         return 0;
130
131 }
132
133 static int method_gbmd(acpi_handle handle, unsigned long *ret)
134 {
135         int result, val;
136
137         result = read_method_int(handle, "GBMD", &val);
138         *ret = val;
139         return result;
140 }
141
142 static int method_sbmc(acpi_handle handle, int cmd)
143 {
144         acpi_status status;
145
146         status = acpi_execute_simple_method(handle, "SBMC", cmd);
147         return ACPI_FAILURE(status) ? -1 : 0;
148 }
149
150 static int method_vpcr(acpi_handle handle, int cmd, int *ret)
151 {
152         acpi_status status;
153         unsigned long long result;
154         struct acpi_object_list params;
155         union acpi_object in_obj;
156
157         params.count = 1;
158         params.pointer = &in_obj;
159         in_obj.type = ACPI_TYPE_INTEGER;
160         in_obj.integer.value = cmd;
161
162         status = acpi_evaluate_integer(handle, "VPCR", &params, &result);
163
164         if (ACPI_FAILURE(status)) {
165                 *ret = -1;
166                 return -1;
167         }
168         *ret = result;
169         return 0;
170
171 }
172
173 static int method_vpcw(acpi_handle handle, int cmd, int data)
174 {
175         struct acpi_object_list params;
176         union acpi_object in_obj[2];
177         acpi_status status;
178
179         params.count = 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;
185
186         status = acpi_evaluate_object(handle, "VPCW", &params, NULL);
187         if (status != AE_OK)
188                 return -1;
189         return 0;
190 }
191
192 static int read_ec_data(acpi_handle handle, int cmd, unsigned long *data)
193 {
194         int val;
195         unsigned long int end_jiffies;
196
197         if (method_vpcw(handle, 1, cmd))
198                 return -1;
199
200         for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
201              time_before(jiffies, end_jiffies);) {
202                 schedule();
203                 if (method_vpcr(handle, 1, &val))
204                         return -1;
205                 if (val == 0) {
206                         if (method_vpcr(handle, 0, &val))
207                                 return -1;
208                         *data = val;
209                         return 0;
210                 }
211         }
212         pr_err("timeout in read_ec_cmd\n");
213         return -1;
214 }
215
216 static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
217 {
218         int val;
219         unsigned long int end_jiffies;
220
221         if (method_vpcw(handle, 0, data))
222                 return -1;
223         if (method_vpcw(handle, 1, cmd))
224                 return -1;
225
226         for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
227              time_before(jiffies, end_jiffies);) {
228                 schedule();
229                 if (method_vpcr(handle, 1, &val))
230                         return -1;
231                 if (val == 0)
232                         return 0;
233         }
234         pr_err("timeout in %s\n", __func__);
235         return -1;
236 }
237
238 /*
239  * debugfs
240  */
241 static int debugfs_status_show(struct seq_file *s, void *data)
242 {
243         struct ideapad_private *priv = s->private;
244         unsigned long value;
245
246         if (!priv)
247                 return -EINVAL;
248
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");
256
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");
270
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");
278
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",
282                            value);
283         }
284
285         return 0;
286 }
287 DEFINE_SHOW_ATTRIBUTE(debugfs_status);
288
289 static int debugfs_cfg_show(struct seq_file *s, void *data)
290 {
291         struct ideapad_private *priv = s->private;
292
293         if (!priv) {
294                 seq_printf(s, "cfg: N/A\n");
295         } else {
296                 seq_printf(s, "cfg: 0x%.8lX\n\nCapability: ",
297                            priv->cfg);
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) {
308                 case 0x100:
309                         seq_printf(s, "Intel");
310                         break;
311                 case 0x200:
312                         seq_printf(s, "ATI");
313                         break;
314                 case 0x300:
315                         seq_printf(s, "Nvidia");
316                         break;
317                 case 0x400:
318                         seq_printf(s, "Intel and ATI");
319                         break;
320                 case 0x500:
321                         seq_printf(s, "Intel and Nvidia");
322                         break;
323                 }
324                 seq_printf(s, "\n");
325         }
326         return 0;
327 }
328 DEFINE_SHOW_ATTRIBUTE(debugfs_cfg);
329
330 static int ideapad_debugfs_init(struct ideapad_private *priv)
331 {
332         struct dentry *node;
333
334         priv->debug = debugfs_create_dir("ideapad", NULL);
335         if (priv->debug == NULL) {
336                 pr_err("failed to create debugfs directory");
337                 goto errout;
338         }
339
340         node = debugfs_create_file("cfg", S_IRUGO, priv->debug, priv,
341                                    &debugfs_cfg_fops);
342         if (!node) {
343                 pr_err("failed to create cfg in debugfs");
344                 goto errout;
345         }
346
347         node = debugfs_create_file("status", S_IRUGO, priv->debug, priv,
348                                    &debugfs_status_fops);
349         if (!node) {
350                 pr_err("failed to create status in debugfs");
351                 goto errout;
352         }
353
354         return 0;
355
356 errout:
357         return -ENOMEM;
358 }
359
360 static void ideapad_debugfs_exit(struct ideapad_private *priv)
361 {
362         debugfs_remove_recursive(priv->debug);
363         priv->debug = NULL;
364 }
365
366 /*
367  * sysfs
368  */
369 static ssize_t show_ideapad_cam(struct device *dev,
370                                 struct device_attribute *attr,
371                                 char *buf)
372 {
373         unsigned long result;
374         struct ideapad_private *priv = dev_get_drvdata(dev);
375
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);
379 }
380
381 static ssize_t store_ideapad_cam(struct device *dev,
382                                  struct device_attribute *attr,
383                                  const char *buf, size_t count)
384 {
385         int ret, state;
386         struct ideapad_private *priv = dev_get_drvdata(dev);
387
388         if (!count)
389                 return 0;
390         if (sscanf(buf, "%i", &state) != 1)
391                 return -EINVAL;
392         ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state);
393         if (ret < 0)
394                 return -EIO;
395         return count;
396 }
397
398 static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
399
400 static ssize_t show_ideapad_fan(struct device *dev,
401                                 struct device_attribute *attr,
402                                 char *buf)
403 {
404         unsigned long result;
405         struct ideapad_private *priv = dev_get_drvdata(dev);
406
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);
410 }
411
412 static ssize_t store_ideapad_fan(struct device *dev,
413                                  struct device_attribute *attr,
414                                  const char *buf, size_t count)
415 {
416         int ret, state;
417         struct ideapad_private *priv = dev_get_drvdata(dev);
418
419         if (!count)
420                 return 0;
421         if (sscanf(buf, "%i", &state) != 1)
422                 return -EINVAL;
423         if (state < 0 || state > 4 || state == 3)
424                 return -EINVAL;
425         ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state);
426         if (ret < 0)
427                 return -EIO;
428         return count;
429 }
430
431 static DEVICE_ATTR(fan_mode, 0644, show_ideapad_fan, store_ideapad_fan);
432
433 static ssize_t touchpad_show(struct device *dev,
434                              struct device_attribute *attr,
435                              char *buf)
436 {
437         struct ideapad_private *priv = dev_get_drvdata(dev);
438         unsigned long result;
439
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);
443 }
444
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)
449 {
450         struct ideapad_private *priv = dev_get_drvdata(dev);
451         bool state;
452         int ret;
453
454         ret = kstrtobool(buf, &state);
455         if (ret)
456                 return ret;
457
458         ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
459         if (ret < 0)
460                 return -EIO;
461         return count;
462 }
463
464 static DEVICE_ATTR_RO(touchpad);
465
466 static ssize_t conservation_mode_show(struct device *dev,
467                                 struct device_attribute *attr,
468                                 char *buf)
469 {
470         struct ideapad_private *priv = dev_get_drvdata(dev);
471         unsigned long result;
472
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));
476 }
477
478 static ssize_t conservation_mode_store(struct device *dev,
479                                  struct device_attribute *attr,
480                                  const char *buf, size_t count)
481 {
482         struct ideapad_private *priv = dev_get_drvdata(dev);
483         bool state;
484         int ret;
485
486         ret = kstrtobool(buf, &state);
487         if (ret)
488                 return ret;
489
490         ret = method_sbmc(priv->adev->handle, state ?
491                                               BMCMD_CONSERVATION_ON :
492                                               BMCMD_CONSERVATION_OFF);
493         if (ret < 0)
494                 return -EIO;
495         return count;
496 }
497
498 static DEVICE_ATTR_RW(conservation_mode);
499
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,
505         NULL
506 };
507
508 static umode_t ideapad_is_visible(struct kobject *kobj,
509                                  struct attribute *attr,
510                                  int idx)
511 {
512         struct device *dev = container_of(kobj, struct device, kobj);
513         struct ideapad_private *priv = dev_get_drvdata(dev);
514         bool supported;
515
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) {
519                 unsigned long value;
520                 supported = !read_ec_data(priv->adev->handle, VPCCMD_R_FAN,
521                                           &value);
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");
525         } else
526                 supported = true;
527
528         return supported ? attr->mode : 0;
529 }
530
531 static const struct attribute_group ideapad_attribute_group = {
532         .is_visible = ideapad_is_visible,
533         .attrs = ideapad_attributes
534 };
535
536 /*
537  * Rfkill
538  */
539 struct ideapad_rfk_data {
540         char *name;
541         int cfgbit;
542         int opcode;
543         int type;
544 };
545
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 },
550 };
551
552 static int ideapad_rfk_set(void *data, bool blocked)
553 {
554         struct ideapad_rfk_priv *priv = data;
555         int opcode = ideapad_rfk_data[priv->dev].opcode;
556
557         return write_ec_cmd(priv->priv->adev->handle, opcode, !blocked);
558 }
559
560 static const struct rfkill_ops ideapad_rfk_ops = {
561         .set_block = ideapad_rfk_set,
562 };
563
564 static void ideapad_sync_rfk_state(struct ideapad_private *priv)
565 {
566         unsigned long hw_blocked = 0;
567         int i;
568
569         if (priv->has_hw_rfkill_switch) {
570                 if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked))
571                         return;
572                 hw_blocked = !hw_blocked;
573         }
574
575         for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
576                 if (priv->rfk[i])
577                         rfkill_set_hw_state(priv->rfk[i], hw_blocked);
578 }
579
580 static int ideapad_register_rfkill(struct ideapad_private *priv, int dev)
581 {
582         int ret;
583         unsigned long sw_blocked;
584
585         if (no_bt_rfkill &&
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);
590                 return 0;
591         }
592         priv->rfk_priv[dev].dev = dev;
593         priv->rfk_priv[dev].priv = priv;
594
595         priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev].name,
596                                       &priv->platform_device->dev,
597                                       ideapad_rfk_data[dev].type,
598                                       &ideapad_rfk_ops,
599                                       &priv->rfk_priv[dev]);
600         if (!priv->rfk[dev])
601                 return -ENOMEM;
602
603         if (read_ec_data(priv->adev->handle, ideapad_rfk_data[dev].opcode-1,
604                          &sw_blocked)) {
605                 rfkill_init_sw_state(priv->rfk[dev], 0);
606         } else {
607                 sw_blocked = !sw_blocked;
608                 rfkill_init_sw_state(priv->rfk[dev], sw_blocked);
609         }
610
611         ret = rfkill_register(priv->rfk[dev]);
612         if (ret) {
613                 rfkill_destroy(priv->rfk[dev]);
614                 return ret;
615         }
616         return 0;
617 }
618
619 static void ideapad_unregister_rfkill(struct ideapad_private *priv, int dev)
620 {
621         if (!priv->rfk[dev])
622                 return;
623
624         rfkill_unregister(priv->rfk[dev]);
625         rfkill_destroy(priv->rfk[dev]);
626 }
627
628 /*
629  * Platform device
630  */
631 static int ideapad_sysfs_init(struct ideapad_private *priv)
632 {
633         return sysfs_create_group(&priv->platform_device->dev.kobj,
634                                     &ideapad_attribute_group);
635 }
636
637 static void ideapad_sysfs_exit(struct ideapad_private *priv)
638 {
639         sysfs_remove_group(&priv->platform_device->dev.kobj,
640                            &ideapad_attribute_group);
641 }
642
643 /*
644  * input device
645  */
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 } },
659
660         { KE_END, 0 },
661 };
662
663 static int ideapad_input_init(struct ideapad_private *priv)
664 {
665         struct input_dev *inputdev;
666         int error;
667
668         inputdev = input_allocate_device();
669         if (!inputdev)
670                 return -ENOMEM;
671
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;
676
677         error = sparse_keymap_setup(inputdev, ideapad_keymap, NULL);
678         if (error) {
679                 pr_err("Unable to setup input device keymap\n");
680                 goto err_free_dev;
681         }
682
683         error = input_register_device(inputdev);
684         if (error) {
685                 pr_err("Unable to register input device\n");
686                 goto err_free_dev;
687         }
688
689         priv->inputdev = inputdev;
690         return 0;
691
692 err_free_dev:
693         input_free_device(inputdev);
694         return error;
695 }
696
697 static void ideapad_input_exit(struct ideapad_private *priv)
698 {
699         input_unregister_device(priv->inputdev);
700         priv->inputdev = NULL;
701 }
702
703 static void ideapad_input_report(struct ideapad_private *priv,
704                                  unsigned long scancode)
705 {
706         sparse_keymap_report_event(priv->inputdev, scancode, 1, true);
707 }
708
709 static void ideapad_input_novokey(struct ideapad_private *priv)
710 {
711         unsigned long long_pressed;
712
713         if (read_ec_data(priv->adev->handle, VPCCMD_R_NOVO, &long_pressed))
714                 return;
715         if (long_pressed)
716                 ideapad_input_report(priv, 17);
717         else
718                 ideapad_input_report(priv, 16);
719 }
720
721 static void ideapad_check_special_buttons(struct ideapad_private *priv)
722 {
723         unsigned long bit, value;
724
725         read_ec_data(priv->adev->handle, VPCCMD_R_SPECIAL_BUTTONS, &value);
726
727         for (bit = 0; bit < 16; bit++) {
728                 if (test_bit(bit, &value)) {
729                         switch (bit) {
730                         case 0: /* Z580 */
731                         case 6: /* Z570 */
732                                 /* Thermal Management button */
733                                 ideapad_input_report(priv, 65);
734                                 break;
735                         case 1:
736                                 /* OneKey Theater button */
737                                 ideapad_input_report(priv, 64);
738                                 break;
739                         default:
740                                 pr_info("Unknown special button: %lu\n", bit);
741                                 break;
742                         }
743                 }
744         }
745 }
746
747 /*
748  * backlight
749  */
750 static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
751 {
752         struct ideapad_private *priv = bl_get_data(blightdev);
753         unsigned long now;
754
755         if (!priv)
756                 return -EINVAL;
757
758         if (read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now))
759                 return -EIO;
760         return now;
761 }
762
763 static int ideapad_backlight_update_status(struct backlight_device *blightdev)
764 {
765         struct ideapad_private *priv = bl_get_data(blightdev);
766
767         if (!priv)
768                 return -EINVAL;
769
770         if (write_ec_cmd(priv->adev->handle, VPCCMD_W_BL,
771                          blightdev->props.brightness))
772                 return -EIO;
773         if (write_ec_cmd(priv->adev->handle, VPCCMD_W_BL_POWER,
774                          blightdev->props.power == FB_BLANK_POWERDOWN ? 0 : 1))
775                 return -EIO;
776
777         return 0;
778 }
779
780 static const struct backlight_ops ideapad_backlight_ops = {
781         .get_brightness = ideapad_backlight_get_brightness,
782         .update_status = ideapad_backlight_update_status,
783 };
784
785 static int ideapad_backlight_init(struct ideapad_private *priv)
786 {
787         struct backlight_device *blightdev;
788         struct backlight_properties props;
789         unsigned long max, now, power;
790
791         if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &max))
792                 return -EIO;
793         if (read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now))
794                 return -EIO;
795         if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power))
796                 return -EIO;
797
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,
803                                               priv,
804                                               &ideapad_backlight_ops,
805                                               &props);
806         if (IS_ERR(blightdev)) {
807                 pr_err("Could not register backlight device\n");
808                 return PTR_ERR(blightdev);
809         }
810
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);
815
816         return 0;
817 }
818
819 static void ideapad_backlight_exit(struct ideapad_private *priv)
820 {
821         backlight_device_unregister(priv->blightdev);
822         priv->blightdev = NULL;
823 }
824
825 static void ideapad_backlight_notify_power(struct ideapad_private *priv)
826 {
827         unsigned long power;
828         struct backlight_device *blightdev = priv->blightdev;
829
830         if (!blightdev)
831                 return;
832         if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power))
833                 return;
834         blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
835 }
836
837 static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
838 {
839         unsigned long now;
840
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);
844                 return;
845         }
846
847         backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY);
848 }
849
850 /*
851  * module init/exit
852  */
853 static void ideapad_sync_touchpad_state(struct ideapad_private *priv)
854 {
855         unsigned long value;
856
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 */
863                 unsigned char param;
864                 i8042_command(&param, value ? I8042_CMD_AUX_ENABLE :
865                               I8042_CMD_AUX_DISABLE);
866                 ideapad_input_report(priv, value ? 67 : 66);
867         }
868 }
869
870 static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
871 {
872         struct ideapad_private *priv = data;
873         unsigned long vpc1, vpc2, vpc_bit;
874
875         if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
876                 return;
877         if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
878                 return;
879
880         vpc1 = (vpc2 << 8) | vpc1;
881         for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) {
882                 if (test_bit(vpc_bit, &vpc1)) {
883                         switch (vpc_bit) {
884                         case 9:
885                                 ideapad_sync_rfk_state(priv);
886                                 break;
887                         case 13:
888                         case 11:
889                         case 8:
890                         case 7:
891                         case 6:
892                                 ideapad_input_report(priv, vpc_bit);
893                                 break;
894                         case 5:
895                                 ideapad_sync_touchpad_state(priv);
896                                 break;
897                         case 4:
898                                 ideapad_backlight_notify_brightness(priv);
899                                 break;
900                         case 3:
901                                 ideapad_input_novokey(priv);
902                                 break;
903                         case 2:
904                                 ideapad_backlight_notify_power(priv);
905                                 break;
906                         case 0:
907                                 ideapad_check_special_buttons(priv);
908                                 break;
909                         case 1:
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.
914                                  */
915                                 break;
916                         default:
917                                 pr_info("Unknown event: %lu\n", vpc_bit);
918                         }
919                 }
920         }
921 }
922
923 #if IS_ENABLED(CONFIG_ACPI_WMI)
924 static void ideapad_wmi_notify(u32 value, void *context)
925 {
926         switch (value) {
927         case 128:
928                 ideapad_input_report(context, value);
929                 break;
930         default:
931                 pr_info("Unknown WMI event %u\n", value);
932         }
933 }
934 #endif
935
936 /*
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.
940  */
941 static const struct dmi_system_id no_hw_rfkill_list[] = {
942         {
943                 .ident = "Lenovo RESCUER R720-15IKBN",
944                 .matches = {
945                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
946                         DMI_MATCH(DMI_BOARD_NAME, "80WW"),
947                 },
948         },
949         {
950                 .ident = "Lenovo G40-30",
951                 .matches = {
952                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
953                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G40-30"),
954                 },
955         },
956         {
957                 .ident = "Lenovo G50-30",
958                 .matches = {
959                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
960                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G50-30"),
961                 },
962         },
963         {
964                 .ident = "Lenovo V310-14IKB",
965                 .matches = {
966                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
967                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-14IKB"),
968                 },
969         },
970         {
971                 .ident = "Lenovo V310-14ISK",
972                 .matches = {
973                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
974                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-14ISK"),
975                 },
976         },
977         {
978                 .ident = "Lenovo V310-15IKB",
979                 .matches = {
980                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
981                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-15IKB"),
982                 },
983         },
984         {
985                 .ident = "Lenovo V310-15ISK",
986                 .matches = {
987                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
988                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-15ISK"),
989                 },
990         },
991         {
992                 .ident = "Lenovo V510-15IKB",
993                 .matches = {
994                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
995                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V510-15IKB"),
996                 },
997         },
998         {
999                 .ident = "Lenovo ideapad 300-15IBR",
1000                 .matches = {
1001                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1002                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300-15IBR"),
1003                 },
1004         },
1005         {
1006                 .ident = "Lenovo ideapad 300-15IKB",
1007                 .matches = {
1008                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1009                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300-15IKB"),
1010                 },
1011         },
1012         {
1013                 .ident = "Lenovo ideapad 300S-11IBR",
1014                 .matches = {
1015                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1016                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 300S-11BR"),
1017                 },
1018         },
1019         {
1020                 .ident = "Lenovo ideapad 310-15ABR",
1021                 .matches = {
1022                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1023                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15ABR"),
1024                 },
1025         },
1026         {
1027                 .ident = "Lenovo ideapad 310-15IAP",
1028                 .matches = {
1029                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1030                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15IAP"),
1031                 },
1032         },
1033         {
1034                 .ident = "Lenovo ideapad 310-15IKB",
1035                 .matches = {
1036                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1037                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15IKB"),
1038                 },
1039         },
1040         {
1041                 .ident = "Lenovo ideapad 310-15ISK",
1042                 .matches = {
1043                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1044                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15ISK"),
1045                 },
1046         },
1047         {
1048                 .ident = "Lenovo ideapad Y700-14ISK",
1049                 .matches = {
1050                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1051                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-14ISK"),
1052                 },
1053         },
1054         {
1055                 .ident = "Lenovo ideapad Y700-15ACZ",
1056                 .matches = {
1057                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1058                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ACZ"),
1059                 },
1060         },
1061         {
1062                 .ident = "Lenovo ideapad Y700-15ISK",
1063                 .matches = {
1064                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1065                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ISK"),
1066                 },
1067         },
1068         {
1069                 .ident = "Lenovo ideapad Y700 Touch-15ISK",
1070                 .matches = {
1071                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1072                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700 Touch-15ISK"),
1073                 },
1074         },
1075         {
1076                 .ident = "Lenovo ideapad Y700-17ISK",
1077                 .matches = {
1078                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1079                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-17ISK"),
1080                 },
1081         },
1082         {
1083                 .ident = "Lenovo Legion Y520-15IKBN",
1084                 .matches = {
1085                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1086                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBN"),
1087                 },
1088         },
1089         {
1090                 .ident = "Lenovo Legion Y720-15IKB",
1091                 .matches = {
1092                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1093                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKB"),
1094                 },
1095         },
1096         {
1097                 .ident = "Lenovo Legion Y720-15IKBN",
1098                 .matches = {
1099                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1100                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKBN"),
1101                 },
1102         },
1103         {
1104                 .ident = "Lenovo Yoga 2 11 / 13 / Pro",
1105                 .matches = {
1106                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1107                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2"),
1108                 },
1109         },
1110         {
1111                 .ident = "Lenovo Yoga 2 11 / 13 / Pro",
1112                 .matches = {
1113                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1114                         DMI_MATCH(DMI_BOARD_NAME, "Yoga2"),
1115                 },
1116         },
1117         {
1118                 .ident = "Lenovo Yoga 3 1170 / 1470",
1119                 .matches = {
1120                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1121                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 3"),
1122                 },
1123         },
1124         {
1125                 .ident = "Lenovo Yoga 3 Pro 1370",
1126                 .matches = {
1127                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1128                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 3"),
1129                 },
1130         },
1131         {
1132                 .ident = "Lenovo Yoga 700",
1133                 .matches = {
1134                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1135                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 700"),
1136                 },
1137         },
1138         {
1139                 .ident = "Lenovo Yoga 900",
1140                 .matches = {
1141                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1142                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 900"),
1143                 },
1144         },
1145         {
1146                 .ident = "Lenovo Yoga 900",
1147                 .matches = {
1148                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1149                         DMI_MATCH(DMI_BOARD_NAME, "VIUU4"),
1150                 },
1151         },
1152         {
1153                 .ident = "Lenovo YOGA 910-13IKB",
1154                 .matches = {
1155                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1156                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 910-13IKB"),
1157                 },
1158         },
1159         {
1160                 .ident = "Lenovo YOGA 920-13IKB",
1161                 .matches = {
1162                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1163                         DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 920-13IKB"),
1164                 },
1165         },
1166         {}
1167 };
1168
1169 static int ideapad_acpi_add(struct platform_device *pdev)
1170 {
1171         int ret, i;
1172         int cfg;
1173         struct ideapad_private *priv;
1174         struct acpi_device *adev;
1175
1176         ret = acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev);
1177         if (ret)
1178                 return -ENODEV;
1179
1180         if (read_method_int(adev->handle, "_CFG", &cfg))
1181                 return -ENODEV;
1182
1183         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
1184         if (!priv)
1185                 return -ENOMEM;
1186
1187         dev_set_drvdata(&pdev->dev, priv);
1188         priv->cfg = cfg;
1189         priv->adev = adev;
1190         priv->platform_device = pdev;
1191         priv->has_hw_rfkill_switch = !dmi_check_system(no_hw_rfkill_list);
1192
1193         ret = ideapad_sysfs_init(priv);
1194         if (ret)
1195                 return ret;
1196
1197         ret = ideapad_debugfs_init(priv);
1198         if (ret)
1199                 goto debugfs_failed;
1200
1201         ret = ideapad_input_init(priv);
1202         if (ret)
1203                 goto input_failed;
1204
1205         /*
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.
1208          */
1209         if (!priv->has_hw_rfkill_switch)
1210                 write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1);
1211
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);
1215
1216         ideapad_sync_rfk_state(priv);
1217         ideapad_sync_touchpad_state(priv);
1218
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;
1223         }
1224         ret = acpi_install_notify_handler(adev->handle,
1225                 ACPI_DEVICE_NOTIFY, ideapad_acpi_notify, priv);
1226         if (ret)
1227                 goto notification_failed;
1228
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);
1233                 if (ret == AE_OK) {
1234                         priv->fnesc_guid = ideapad_wmi_fnesc_events[i];
1235                         break;
1236                 }
1237         }
1238         if (ret != AE_OK && ret != AE_NOT_EXIST)
1239                 goto notification_failed_wmi;
1240 #endif
1241
1242         return 0;
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);
1247 #endif
1248 notification_failed:
1249         ideapad_backlight_exit(priv);
1250 backlight_failed:
1251         for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
1252                 ideapad_unregister_rfkill(priv, i);
1253         ideapad_input_exit(priv);
1254 input_failed:
1255         ideapad_debugfs_exit(priv);
1256 debugfs_failed:
1257         ideapad_sysfs_exit(priv);
1258         return ret;
1259 }
1260
1261 static int ideapad_acpi_remove(struct platform_device *pdev)
1262 {
1263         struct ideapad_private *priv = dev_get_drvdata(&pdev->dev);
1264         int i;
1265
1266 #if IS_ENABLED(CONFIG_ACPI_WMI)
1267         if (priv->fnesc_guid)
1268                 wmi_remove_notify_handler(priv->fnesc_guid);
1269 #endif
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);
1279
1280         return 0;
1281 }
1282
1283 #ifdef CONFIG_PM_SLEEP
1284 static int ideapad_acpi_resume(struct device *device)
1285 {
1286         struct ideapad_private *priv;
1287
1288         if (!device)
1289                 return -EINVAL;
1290         priv = dev_get_drvdata(device);
1291
1292         ideapad_sync_rfk_state(priv);
1293         ideapad_sync_touchpad_state(priv);
1294         return 0;
1295 }
1296 #endif
1297 static SIMPLE_DEV_PM_OPS(ideapad_pm, NULL, ideapad_acpi_resume);
1298
1299 static const struct acpi_device_id ideapad_device_ids[] = {
1300         { "VPC2004", 0},
1301         { "", 0},
1302 };
1303 MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
1304
1305 static struct platform_driver ideapad_acpi_driver = {
1306         .probe = ideapad_acpi_add,
1307         .remove = ideapad_acpi_remove,
1308         .driver = {
1309                 .name   = "ideapad_acpi",
1310                 .pm     = &ideapad_pm,
1311                 .acpi_match_table = ACPI_PTR(ideapad_device_ids),
1312         },
1313 };
1314
1315 module_platform_driver(ideapad_acpi_driver);
1316
1317 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
1318 MODULE_DESCRIPTION("IdeaPad ACPI Extras");
1319 MODULE_LICENSE("GPL");