0001
0002
0003
0004
0005
0006
0007
0008
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010
0011 #include <linux/acpi.h>
0012 #include <linux/backlight.h>
0013 #include <linux/bitops.h>
0014 #include <linux/bug.h>
0015 #include <linux/debugfs.h>
0016 #include <linux/device.h>
0017 #include <linux/dmi.h>
0018 #include <linux/fb.h>
0019 #include <linux/i8042.h>
0020 #include <linux/init.h>
0021 #include <linux/input.h>
0022 #include <linux/input/sparse-keymap.h>
0023 #include <linux/jiffies.h>
0024 #include <linux/kernel.h>
0025 #include <linux/leds.h>
0026 #include <linux/module.h>
0027 #include <linux/platform_device.h>
0028 #include <linux/platform_profile.h>
0029 #include <linux/rfkill.h>
0030 #include <linux/seq_file.h>
0031 #include <linux/sysfs.h>
0032 #include <linux/types.h>
0033
0034 #include <acpi/video.h>
0035
0036 #include <dt-bindings/leds/common.h>
0037
0038 #define IDEAPAD_RFKILL_DEV_NUM 3
0039
0040 #if IS_ENABLED(CONFIG_ACPI_WMI)
0041 static const char *const ideapad_wmi_fnesc_events[] = {
0042 "26CAB2E5-5CF1-46AE-AAC3-4A12B6BA50E6",
0043 "56322276-8493-4CE8-A783-98C991274F5E",
0044 "8FC0DE0C-B4E4-43FD-B0F3-8871711C1294",
0045 };
0046 #endif
0047
0048 enum {
0049 CFG_CAP_BT_BIT = 16,
0050 CFG_CAP_3G_BIT = 17,
0051 CFG_CAP_WIFI_BIT = 18,
0052 CFG_CAP_CAM_BIT = 19,
0053 CFG_CAP_TOUCHPAD_BIT = 30,
0054 };
0055
0056 enum {
0057 GBMD_CONSERVATION_STATE_BIT = 5,
0058 };
0059
0060 enum {
0061 SBMC_CONSERVATION_ON = 3,
0062 SBMC_CONSERVATION_OFF = 5,
0063 };
0064
0065 enum {
0066 HALS_KBD_BL_SUPPORT_BIT = 4,
0067 HALS_KBD_BL_STATE_BIT = 5,
0068 HALS_USB_CHARGING_SUPPORT_BIT = 6,
0069 HALS_USB_CHARGING_STATE_BIT = 7,
0070 HALS_FNLOCK_SUPPORT_BIT = 9,
0071 HALS_FNLOCK_STATE_BIT = 10,
0072 HALS_HOTKEYS_PRIMARY_BIT = 11,
0073 };
0074
0075 enum {
0076 SALS_KBD_BL_ON = 0x8,
0077 SALS_KBD_BL_OFF = 0x9,
0078 SALS_USB_CHARGING_ON = 0xa,
0079 SALS_USB_CHARGING_OFF = 0xb,
0080 SALS_FNLOCK_ON = 0xe,
0081 SALS_FNLOCK_OFF = 0xf,
0082 };
0083
0084 enum {
0085 VPCCMD_R_VPC1 = 0x10,
0086 VPCCMD_R_BL_MAX,
0087 VPCCMD_R_BL,
0088 VPCCMD_W_BL,
0089 VPCCMD_R_WIFI,
0090 VPCCMD_W_WIFI,
0091 VPCCMD_R_BT,
0092 VPCCMD_W_BT,
0093 VPCCMD_R_BL_POWER,
0094 VPCCMD_R_NOVO,
0095 VPCCMD_R_VPC2,
0096 VPCCMD_R_TOUCHPAD,
0097 VPCCMD_W_TOUCHPAD,
0098 VPCCMD_R_CAMERA,
0099 VPCCMD_W_CAMERA,
0100 VPCCMD_R_3G,
0101 VPCCMD_W_3G,
0102 VPCCMD_R_ODD,
0103 VPCCMD_W_FAN,
0104 VPCCMD_R_RF,
0105 VPCCMD_W_RF,
0106 VPCCMD_R_FAN = 0x2B,
0107 VPCCMD_R_SPECIAL_BUTTONS = 0x31,
0108 VPCCMD_W_BL_POWER = 0x33,
0109 };
0110
0111 struct ideapad_dytc_priv {
0112 enum platform_profile_option current_profile;
0113 struct platform_profile_handler pprof;
0114 struct mutex mutex;
0115 struct ideapad_private *priv;
0116 };
0117
0118 struct ideapad_rfk_priv {
0119 int dev;
0120 struct ideapad_private *priv;
0121 };
0122
0123 struct ideapad_private {
0124 struct acpi_device *adev;
0125 struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
0126 struct ideapad_rfk_priv rfk_priv[IDEAPAD_RFKILL_DEV_NUM];
0127 struct platform_device *platform_device;
0128 struct input_dev *inputdev;
0129 struct backlight_device *blightdev;
0130 struct ideapad_dytc_priv *dytc;
0131 struct dentry *debug;
0132 unsigned long cfg;
0133 const char *fnesc_guid;
0134 struct {
0135 bool conservation_mode : 1;
0136 bool dytc : 1;
0137 bool fan_mode : 1;
0138 bool fn_lock : 1;
0139 bool hw_rfkill_switch : 1;
0140 bool kbd_bl : 1;
0141 bool touchpad_ctrl_via_ec : 1;
0142 bool usb_charging : 1;
0143 } features;
0144 struct {
0145 bool initialized;
0146 struct led_classdev led;
0147 unsigned int last_brightness;
0148 } kbd_bl;
0149 };
0150
0151 static bool no_bt_rfkill;
0152 module_param(no_bt_rfkill, bool, 0444);
0153 MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
0154
0155 static bool allow_v4_dytc;
0156 module_param(allow_v4_dytc, bool, 0444);
0157 MODULE_PARM_DESC(allow_v4_dytc, "Enable DYTC version 4 platform-profile support.");
0158
0159
0160
0161
0162 #define IDEAPAD_EC_TIMEOUT 200
0163
0164 static int eval_int(acpi_handle handle, const char *name, unsigned long *res)
0165 {
0166 unsigned long long result;
0167 acpi_status status;
0168
0169 status = acpi_evaluate_integer(handle, (char *)name, NULL, &result);
0170 if (ACPI_FAILURE(status))
0171 return -EIO;
0172
0173 *res = result;
0174
0175 return 0;
0176 }
0177
0178 static int exec_simple_method(acpi_handle handle, const char *name, unsigned long arg)
0179 {
0180 acpi_status status = acpi_execute_simple_method(handle, (char *)name, arg);
0181
0182 return ACPI_FAILURE(status) ? -EIO : 0;
0183 }
0184
0185 static int eval_gbmd(acpi_handle handle, unsigned long *res)
0186 {
0187 return eval_int(handle, "GBMD", res);
0188 }
0189
0190 static int exec_sbmc(acpi_handle handle, unsigned long arg)
0191 {
0192 return exec_simple_method(handle, "SBMC", arg);
0193 }
0194
0195 static int eval_hals(acpi_handle handle, unsigned long *res)
0196 {
0197 return eval_int(handle, "HALS", res);
0198 }
0199
0200 static int exec_sals(acpi_handle handle, unsigned long arg)
0201 {
0202 return exec_simple_method(handle, "SALS", arg);
0203 }
0204
0205 static int eval_int_with_arg(acpi_handle handle, const char *name, unsigned long arg, unsigned long *res)
0206 {
0207 struct acpi_object_list params;
0208 unsigned long long result;
0209 union acpi_object in_obj;
0210 acpi_status status;
0211
0212 params.count = 1;
0213 params.pointer = &in_obj;
0214 in_obj.type = ACPI_TYPE_INTEGER;
0215 in_obj.integer.value = arg;
0216
0217 status = acpi_evaluate_integer(handle, (char *)name, ¶ms, &result);
0218 if (ACPI_FAILURE(status))
0219 return -EIO;
0220
0221 if (res)
0222 *res = result;
0223
0224 return 0;
0225 }
0226
0227 static int eval_dytc(acpi_handle handle, unsigned long cmd, unsigned long *res)
0228 {
0229 return eval_int_with_arg(handle, "DYTC", cmd, res);
0230 }
0231
0232 static int eval_vpcr(acpi_handle handle, unsigned long cmd, unsigned long *res)
0233 {
0234 return eval_int_with_arg(handle, "VPCR", cmd, res);
0235 }
0236
0237 static int eval_vpcw(acpi_handle handle, unsigned long cmd, unsigned long data)
0238 {
0239 struct acpi_object_list params;
0240 union acpi_object in_obj[2];
0241 acpi_status status;
0242
0243 params.count = 2;
0244 params.pointer = in_obj;
0245 in_obj[0].type = ACPI_TYPE_INTEGER;
0246 in_obj[0].integer.value = cmd;
0247 in_obj[1].type = ACPI_TYPE_INTEGER;
0248 in_obj[1].integer.value = data;
0249
0250 status = acpi_evaluate_object(handle, "VPCW", ¶ms, NULL);
0251 if (ACPI_FAILURE(status))
0252 return -EIO;
0253
0254 return 0;
0255 }
0256
0257 static int read_ec_data(acpi_handle handle, unsigned long cmd, unsigned long *data)
0258 {
0259 unsigned long end_jiffies, val;
0260 int err;
0261
0262 err = eval_vpcw(handle, 1, cmd);
0263 if (err)
0264 return err;
0265
0266 end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1;
0267
0268 while (time_before(jiffies, end_jiffies)) {
0269 schedule();
0270
0271 err = eval_vpcr(handle, 1, &val);
0272 if (err)
0273 return err;
0274
0275 if (val == 0)
0276 return eval_vpcr(handle, 0, data);
0277 }
0278
0279 acpi_handle_err(handle, "timeout in %s\n", __func__);
0280
0281 return -ETIMEDOUT;
0282 }
0283
0284 static int write_ec_cmd(acpi_handle handle, unsigned long cmd, unsigned long data)
0285 {
0286 unsigned long end_jiffies, val;
0287 int err;
0288
0289 err = eval_vpcw(handle, 0, data);
0290 if (err)
0291 return err;
0292
0293 err = eval_vpcw(handle, 1, cmd);
0294 if (err)
0295 return err;
0296
0297 end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1;
0298
0299 while (time_before(jiffies, end_jiffies)) {
0300 schedule();
0301
0302 err = eval_vpcr(handle, 1, &val);
0303 if (err)
0304 return err;
0305
0306 if (val == 0)
0307 return 0;
0308 }
0309
0310 acpi_handle_err(handle, "timeout in %s\n", __func__);
0311
0312 return -ETIMEDOUT;
0313 }
0314
0315
0316
0317
0318 static int debugfs_status_show(struct seq_file *s, void *data)
0319 {
0320 struct ideapad_private *priv = s->private;
0321 unsigned long value;
0322
0323 if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value))
0324 seq_printf(s, "Backlight max: %lu\n", value);
0325 if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value))
0326 seq_printf(s, "Backlight now: %lu\n", value);
0327 if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &value))
0328 seq_printf(s, "BL power value: %s (%lu)\n", value ? "on" : "off", value);
0329
0330 seq_puts(s, "=====================\n");
0331
0332 if (!read_ec_data(priv->adev->handle, VPCCMD_R_RF, &value))
0333 seq_printf(s, "Radio status: %s (%lu)\n", value ? "on" : "off", value);
0334 if (!read_ec_data(priv->adev->handle, VPCCMD_R_WIFI, &value))
0335 seq_printf(s, "Wifi status: %s (%lu)\n", value ? "on" : "off", value);
0336 if (!read_ec_data(priv->adev->handle, VPCCMD_R_BT, &value))
0337 seq_printf(s, "BT status: %s (%lu)\n", value ? "on" : "off", value);
0338 if (!read_ec_data(priv->adev->handle, VPCCMD_R_3G, &value))
0339 seq_printf(s, "3G status: %s (%lu)\n", value ? "on" : "off", value);
0340
0341 seq_puts(s, "=====================\n");
0342
0343 if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value))
0344 seq_printf(s, "Touchpad status: %s (%lu)\n", value ? "on" : "off", value);
0345 if (!read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &value))
0346 seq_printf(s, "Camera status: %s (%lu)\n", value ? "on" : "off", value);
0347
0348 seq_puts(s, "=====================\n");
0349
0350 if (!eval_gbmd(priv->adev->handle, &value))
0351 seq_printf(s, "GBMD: %#010lx\n", value);
0352 if (!eval_hals(priv->adev->handle, &value))
0353 seq_printf(s, "HALS: %#010lx\n", value);
0354
0355 return 0;
0356 }
0357 DEFINE_SHOW_ATTRIBUTE(debugfs_status);
0358
0359 static int debugfs_cfg_show(struct seq_file *s, void *data)
0360 {
0361 struct ideapad_private *priv = s->private;
0362
0363 seq_printf(s, "_CFG: %#010lx\n\n", priv->cfg);
0364
0365 seq_puts(s, "Capabilities:");
0366 if (test_bit(CFG_CAP_BT_BIT, &priv->cfg))
0367 seq_puts(s, " bluetooth");
0368 if (test_bit(CFG_CAP_3G_BIT, &priv->cfg))
0369 seq_puts(s, " 3G");
0370 if (test_bit(CFG_CAP_WIFI_BIT, &priv->cfg))
0371 seq_puts(s, " wifi");
0372 if (test_bit(CFG_CAP_CAM_BIT, &priv->cfg))
0373 seq_puts(s, " camera");
0374 if (test_bit(CFG_CAP_TOUCHPAD_BIT, &priv->cfg))
0375 seq_puts(s, " touchpad");
0376 seq_puts(s, "\n");
0377
0378 seq_puts(s, "Graphics: ");
0379 switch (priv->cfg & 0x700) {
0380 case 0x100:
0381 seq_puts(s, "Intel");
0382 break;
0383 case 0x200:
0384 seq_puts(s, "ATI");
0385 break;
0386 case 0x300:
0387 seq_puts(s, "Nvidia");
0388 break;
0389 case 0x400:
0390 seq_puts(s, "Intel and ATI");
0391 break;
0392 case 0x500:
0393 seq_puts(s, "Intel and Nvidia");
0394 break;
0395 }
0396 seq_puts(s, "\n");
0397
0398 return 0;
0399 }
0400 DEFINE_SHOW_ATTRIBUTE(debugfs_cfg);
0401
0402 static void ideapad_debugfs_init(struct ideapad_private *priv)
0403 {
0404 struct dentry *dir;
0405
0406 dir = debugfs_create_dir("ideapad", NULL);
0407 priv->debug = dir;
0408
0409 debugfs_create_file("cfg", 0444, dir, priv, &debugfs_cfg_fops);
0410 debugfs_create_file("status", 0444, dir, priv, &debugfs_status_fops);
0411 }
0412
0413 static void ideapad_debugfs_exit(struct ideapad_private *priv)
0414 {
0415 debugfs_remove_recursive(priv->debug);
0416 priv->debug = NULL;
0417 }
0418
0419
0420
0421
0422 static ssize_t camera_power_show(struct device *dev,
0423 struct device_attribute *attr,
0424 char *buf)
0425 {
0426 struct ideapad_private *priv = dev_get_drvdata(dev);
0427 unsigned long result;
0428 int err;
0429
0430 err = read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &result);
0431 if (err)
0432 return err;
0433
0434 return sysfs_emit(buf, "%d\n", !!result);
0435 }
0436
0437 static ssize_t camera_power_store(struct device *dev,
0438 struct device_attribute *attr,
0439 const char *buf, size_t count)
0440 {
0441 struct ideapad_private *priv = dev_get_drvdata(dev);
0442 bool state;
0443 int err;
0444
0445 err = kstrtobool(buf, &state);
0446 if (err)
0447 return err;
0448
0449 err = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state);
0450 if (err)
0451 return err;
0452
0453 return count;
0454 }
0455
0456 static DEVICE_ATTR_RW(camera_power);
0457
0458 static ssize_t conservation_mode_show(struct device *dev,
0459 struct device_attribute *attr,
0460 char *buf)
0461 {
0462 struct ideapad_private *priv = dev_get_drvdata(dev);
0463 unsigned long result;
0464 int err;
0465
0466 err = eval_gbmd(priv->adev->handle, &result);
0467 if (err)
0468 return err;
0469
0470 return sysfs_emit(buf, "%d\n", !!test_bit(GBMD_CONSERVATION_STATE_BIT, &result));
0471 }
0472
0473 static ssize_t conservation_mode_store(struct device *dev,
0474 struct device_attribute *attr,
0475 const char *buf, size_t count)
0476 {
0477 struct ideapad_private *priv = dev_get_drvdata(dev);
0478 bool state;
0479 int err;
0480
0481 err = kstrtobool(buf, &state);
0482 if (err)
0483 return err;
0484
0485 err = exec_sbmc(priv->adev->handle, state ? SBMC_CONSERVATION_ON : SBMC_CONSERVATION_OFF);
0486 if (err)
0487 return err;
0488
0489 return count;
0490 }
0491
0492 static DEVICE_ATTR_RW(conservation_mode);
0493
0494 static ssize_t fan_mode_show(struct device *dev,
0495 struct device_attribute *attr,
0496 char *buf)
0497 {
0498 struct ideapad_private *priv = dev_get_drvdata(dev);
0499 unsigned long result;
0500 int err;
0501
0502 err = read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &result);
0503 if (err)
0504 return err;
0505
0506 return sysfs_emit(buf, "%lu\n", result);
0507 }
0508
0509 static ssize_t fan_mode_store(struct device *dev,
0510 struct device_attribute *attr,
0511 const char *buf, size_t count)
0512 {
0513 struct ideapad_private *priv = dev_get_drvdata(dev);
0514 unsigned int state;
0515 int err;
0516
0517 err = kstrtouint(buf, 0, &state);
0518 if (err)
0519 return err;
0520
0521 if (state > 4 || state == 3)
0522 return -EINVAL;
0523
0524 err = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state);
0525 if (err)
0526 return err;
0527
0528 return count;
0529 }
0530
0531 static DEVICE_ATTR_RW(fan_mode);
0532
0533 static ssize_t fn_lock_show(struct device *dev,
0534 struct device_attribute *attr,
0535 char *buf)
0536 {
0537 struct ideapad_private *priv = dev_get_drvdata(dev);
0538 unsigned long hals;
0539 int err;
0540
0541 err = eval_hals(priv->adev->handle, &hals);
0542 if (err)
0543 return err;
0544
0545 return sysfs_emit(buf, "%d\n", !!test_bit(HALS_FNLOCK_STATE_BIT, &hals));
0546 }
0547
0548 static ssize_t fn_lock_store(struct device *dev,
0549 struct device_attribute *attr,
0550 const char *buf, size_t count)
0551 {
0552 struct ideapad_private *priv = dev_get_drvdata(dev);
0553 bool state;
0554 int err;
0555
0556 err = kstrtobool(buf, &state);
0557 if (err)
0558 return err;
0559
0560 err = exec_sals(priv->adev->handle, state ? SALS_FNLOCK_ON : SALS_FNLOCK_OFF);
0561 if (err)
0562 return err;
0563
0564 return count;
0565 }
0566
0567 static DEVICE_ATTR_RW(fn_lock);
0568
0569 static ssize_t touchpad_show(struct device *dev,
0570 struct device_attribute *attr,
0571 char *buf)
0572 {
0573 struct ideapad_private *priv = dev_get_drvdata(dev);
0574 unsigned long result;
0575 int err;
0576
0577 err = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result);
0578 if (err)
0579 return err;
0580
0581 return sysfs_emit(buf, "%d\n", !!result);
0582 }
0583
0584 static ssize_t touchpad_store(struct device *dev,
0585 struct device_attribute *attr,
0586 const char *buf, size_t count)
0587 {
0588 struct ideapad_private *priv = dev_get_drvdata(dev);
0589 bool state;
0590 int err;
0591
0592 err = kstrtobool(buf, &state);
0593 if (err)
0594 return err;
0595
0596 err = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
0597 if (err)
0598 return err;
0599
0600 return count;
0601 }
0602
0603 static DEVICE_ATTR_RW(touchpad);
0604
0605 static ssize_t usb_charging_show(struct device *dev,
0606 struct device_attribute *attr,
0607 char *buf)
0608 {
0609 struct ideapad_private *priv = dev_get_drvdata(dev);
0610 unsigned long hals;
0611 int err;
0612
0613 err = eval_hals(priv->adev->handle, &hals);
0614 if (err)
0615 return err;
0616
0617 return sysfs_emit(buf, "%d\n", !!test_bit(HALS_USB_CHARGING_STATE_BIT, &hals));
0618 }
0619
0620 static ssize_t usb_charging_store(struct device *dev,
0621 struct device_attribute *attr,
0622 const char *buf, size_t count)
0623 {
0624 struct ideapad_private *priv = dev_get_drvdata(dev);
0625 bool state;
0626 int err;
0627
0628 err = kstrtobool(buf, &state);
0629 if (err)
0630 return err;
0631
0632 err = exec_sals(priv->adev->handle, state ? SALS_USB_CHARGING_ON : SALS_USB_CHARGING_OFF);
0633 if (err)
0634 return err;
0635
0636 return count;
0637 }
0638
0639 static DEVICE_ATTR_RW(usb_charging);
0640
0641 static struct attribute *ideapad_attributes[] = {
0642 &dev_attr_camera_power.attr,
0643 &dev_attr_conservation_mode.attr,
0644 &dev_attr_fan_mode.attr,
0645 &dev_attr_fn_lock.attr,
0646 &dev_attr_touchpad.attr,
0647 &dev_attr_usb_charging.attr,
0648 NULL
0649 };
0650
0651 static umode_t ideapad_is_visible(struct kobject *kobj,
0652 struct attribute *attr,
0653 int idx)
0654 {
0655 struct device *dev = kobj_to_dev(kobj);
0656 struct ideapad_private *priv = dev_get_drvdata(dev);
0657 bool supported = true;
0658
0659 if (attr == &dev_attr_camera_power.attr)
0660 supported = test_bit(CFG_CAP_CAM_BIT, &priv->cfg);
0661 else if (attr == &dev_attr_conservation_mode.attr)
0662 supported = priv->features.conservation_mode;
0663 else if (attr == &dev_attr_fan_mode.attr)
0664 supported = priv->features.fan_mode;
0665 else if (attr == &dev_attr_fn_lock.attr)
0666 supported = priv->features.fn_lock;
0667 else if (attr == &dev_attr_touchpad.attr)
0668 supported = priv->features.touchpad_ctrl_via_ec &&
0669 test_bit(CFG_CAP_TOUCHPAD_BIT, &priv->cfg);
0670 else if (attr == &dev_attr_usb_charging.attr)
0671 supported = priv->features.usb_charging;
0672
0673 return supported ? attr->mode : 0;
0674 }
0675
0676 static const struct attribute_group ideapad_attribute_group = {
0677 .is_visible = ideapad_is_visible,
0678 .attrs = ideapad_attributes
0679 };
0680
0681
0682
0683
0684 #define DYTC_CMD_QUERY 0
0685 #define DYTC_CMD_SET 1
0686 #define DYTC_CMD_GET 2
0687 #define DYTC_CMD_RESET 0x1ff
0688
0689 #define DYTC_QUERY_ENABLE_BIT 8
0690 #define DYTC_QUERY_SUBREV_BIT 16
0691 #define DYTC_QUERY_REV_BIT 28
0692
0693 #define DYTC_GET_FUNCTION_BIT 8
0694 #define DYTC_GET_MODE_BIT 12
0695
0696 #define DYTC_SET_FUNCTION_BIT 12
0697 #define DYTC_SET_MODE_BIT 16
0698 #define DYTC_SET_VALID_BIT 20
0699
0700 #define DYTC_FUNCTION_STD 0
0701 #define DYTC_FUNCTION_CQL 1
0702 #define DYTC_FUNCTION_MMC 11
0703
0704 #define DYTC_MODE_PERFORM 2
0705 #define DYTC_MODE_LOW_POWER 3
0706 #define DYTC_MODE_BALANCE 0xF
0707
0708 #define DYTC_SET_COMMAND(function, mode, on) \
0709 (DYTC_CMD_SET | (function) << DYTC_SET_FUNCTION_BIT | \
0710 (mode) << DYTC_SET_MODE_BIT | \
0711 (on) << DYTC_SET_VALID_BIT)
0712
0713 #define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 0)
0714
0715 #define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 1)
0716
0717 static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile)
0718 {
0719 switch (dytcmode) {
0720 case DYTC_MODE_LOW_POWER:
0721 *profile = PLATFORM_PROFILE_LOW_POWER;
0722 break;
0723 case DYTC_MODE_BALANCE:
0724 *profile = PLATFORM_PROFILE_BALANCED;
0725 break;
0726 case DYTC_MODE_PERFORM:
0727 *profile = PLATFORM_PROFILE_PERFORMANCE;
0728 break;
0729 default:
0730 return -EINVAL;
0731 }
0732
0733 return 0;
0734 }
0735
0736 static int convert_profile_to_dytc(enum platform_profile_option profile, int *perfmode)
0737 {
0738 switch (profile) {
0739 case PLATFORM_PROFILE_LOW_POWER:
0740 *perfmode = DYTC_MODE_LOW_POWER;
0741 break;
0742 case PLATFORM_PROFILE_BALANCED:
0743 *perfmode = DYTC_MODE_BALANCE;
0744 break;
0745 case PLATFORM_PROFILE_PERFORMANCE:
0746 *perfmode = DYTC_MODE_PERFORM;
0747 break;
0748 default:
0749 return -EOPNOTSUPP;
0750 }
0751
0752 return 0;
0753 }
0754
0755
0756
0757
0758
0759 static int dytc_profile_get(struct platform_profile_handler *pprof,
0760 enum platform_profile_option *profile)
0761 {
0762 struct ideapad_dytc_priv *dytc = container_of(pprof, struct ideapad_dytc_priv, pprof);
0763
0764 *profile = dytc->current_profile;
0765 return 0;
0766 }
0767
0768
0769
0770
0771
0772
0773
0774
0775 static int dytc_cql_command(struct ideapad_private *priv, unsigned long cmd,
0776 unsigned long *output)
0777 {
0778 int err, cmd_err, cur_funcmode;
0779
0780
0781 err = eval_dytc(priv->adev->handle, DYTC_CMD_GET, output);
0782 if (err)
0783 return err;
0784
0785 cur_funcmode = (*output >> DYTC_GET_FUNCTION_BIT) & 0xF;
0786
0787 if (cmd == DYTC_CMD_GET && cur_funcmode != DYTC_FUNCTION_CQL)
0788 return 0;
0789
0790 if (cur_funcmode == DYTC_FUNCTION_CQL) {
0791 err = eval_dytc(priv->adev->handle, DYTC_DISABLE_CQL, NULL);
0792 if (err)
0793 return err;
0794 }
0795
0796 cmd_err = eval_dytc(priv->adev->handle, cmd, output);
0797
0798
0799 if (cur_funcmode == DYTC_FUNCTION_CQL) {
0800 err = eval_dytc(priv->adev->handle, DYTC_ENABLE_CQL, NULL);
0801 if (err)
0802 return err;
0803 }
0804
0805 return cmd_err;
0806 }
0807
0808
0809
0810
0811
0812 static int dytc_profile_set(struct platform_profile_handler *pprof,
0813 enum platform_profile_option profile)
0814 {
0815 struct ideapad_dytc_priv *dytc = container_of(pprof, struct ideapad_dytc_priv, pprof);
0816 struct ideapad_private *priv = dytc->priv;
0817 unsigned long output;
0818 int err;
0819
0820 err = mutex_lock_interruptible(&dytc->mutex);
0821 if (err)
0822 return err;
0823
0824 if (profile == PLATFORM_PROFILE_BALANCED) {
0825
0826 err = eval_dytc(priv->adev->handle, DYTC_CMD_RESET, NULL);
0827 if (err)
0828 goto unlock;
0829 } else {
0830 int perfmode;
0831
0832 err = convert_profile_to_dytc(profile, &perfmode);
0833 if (err)
0834 goto unlock;
0835
0836
0837 err = dytc_cql_command(priv, DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1),
0838 &output);
0839 if (err)
0840 goto unlock;
0841 }
0842
0843
0844 dytc->current_profile = profile;
0845
0846 unlock:
0847 mutex_unlock(&dytc->mutex);
0848
0849 return err;
0850 }
0851
0852 static void dytc_profile_refresh(struct ideapad_private *priv)
0853 {
0854 enum platform_profile_option profile;
0855 unsigned long output;
0856 int err, perfmode;
0857
0858 mutex_lock(&priv->dytc->mutex);
0859 err = dytc_cql_command(priv, DYTC_CMD_GET, &output);
0860 mutex_unlock(&priv->dytc->mutex);
0861 if (err)
0862 return;
0863
0864 perfmode = (output >> DYTC_GET_MODE_BIT) & 0xF;
0865
0866 if (convert_dytc_to_profile(perfmode, &profile))
0867 return;
0868
0869 if (profile != priv->dytc->current_profile) {
0870 priv->dytc->current_profile = profile;
0871 platform_profile_notify();
0872 }
0873 }
0874
0875 static const struct dmi_system_id ideapad_dytc_v4_allow_table[] = {
0876 {
0877
0878 .matches = {
0879 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
0880 DMI_MATCH(DMI_PRODUCT_NAME, "82L5")
0881 }
0882 },
0883 {
0884
0885 .matches = {
0886 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
0887 DMI_MATCH(DMI_PRODUCT_VERSION, "IdeaPad 5 15ITL05")
0888 }
0889 },
0890 {}
0891 };
0892
0893 static int ideapad_dytc_profile_init(struct ideapad_private *priv)
0894 {
0895 int err, dytc_version;
0896 unsigned long output;
0897
0898 if (!priv->features.dytc)
0899 return -ENODEV;
0900
0901 err = eval_dytc(priv->adev->handle, DYTC_CMD_QUERY, &output);
0902
0903 if (err)
0904 return err;
0905
0906
0907 if (!test_bit(DYTC_QUERY_ENABLE_BIT, &output)) {
0908 dev_info(&priv->platform_device->dev, "DYTC_QUERY_ENABLE_BIT returned false\n");
0909 return -ENODEV;
0910 }
0911
0912 dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF;
0913
0914 if (dytc_version < 4) {
0915 dev_info(&priv->platform_device->dev, "DYTC_VERSION < 4 is not supported\n");
0916 return -ENODEV;
0917 }
0918
0919 if (dytc_version < 5 &&
0920 !(allow_v4_dytc || dmi_check_system(ideapad_dytc_v4_allow_table))) {
0921 dev_info(&priv->platform_device->dev,
0922 "DYTC_VERSION 4 support may not work. Pass ideapad_laptop.allow_v4_dytc=Y on the kernel commandline to enable\n");
0923 return -ENODEV;
0924 }
0925
0926 priv->dytc = kzalloc(sizeof(*priv->dytc), GFP_KERNEL);
0927 if (!priv->dytc)
0928 return -ENOMEM;
0929
0930 mutex_init(&priv->dytc->mutex);
0931
0932 priv->dytc->priv = priv;
0933 priv->dytc->pprof.profile_get = dytc_profile_get;
0934 priv->dytc->pprof.profile_set = dytc_profile_set;
0935
0936
0937 set_bit(PLATFORM_PROFILE_LOW_POWER, priv->dytc->pprof.choices);
0938 set_bit(PLATFORM_PROFILE_BALANCED, priv->dytc->pprof.choices);
0939 set_bit(PLATFORM_PROFILE_PERFORMANCE, priv->dytc->pprof.choices);
0940
0941
0942 err = platform_profile_register(&priv->dytc->pprof);
0943 if (err)
0944 goto pp_reg_failed;
0945
0946
0947 dytc_profile_refresh(priv);
0948
0949 return 0;
0950
0951 pp_reg_failed:
0952 mutex_destroy(&priv->dytc->mutex);
0953 kfree(priv->dytc);
0954 priv->dytc = NULL;
0955
0956 return err;
0957 }
0958
0959 static void ideapad_dytc_profile_exit(struct ideapad_private *priv)
0960 {
0961 if (!priv->dytc)
0962 return;
0963
0964 platform_profile_remove();
0965 mutex_destroy(&priv->dytc->mutex);
0966 kfree(priv->dytc);
0967
0968 priv->dytc = NULL;
0969 }
0970
0971
0972
0973
0974 struct ideapad_rfk_data {
0975 char *name;
0976 int cfgbit;
0977 int opcode;
0978 int type;
0979 };
0980
0981 static const struct ideapad_rfk_data ideapad_rfk_data[] = {
0982 { "ideapad_wlan", CFG_CAP_WIFI_BIT, VPCCMD_W_WIFI, RFKILL_TYPE_WLAN },
0983 { "ideapad_bluetooth", CFG_CAP_BT_BIT, VPCCMD_W_BT, RFKILL_TYPE_BLUETOOTH },
0984 { "ideapad_3g", CFG_CAP_3G_BIT, VPCCMD_W_3G, RFKILL_TYPE_WWAN },
0985 };
0986
0987 static int ideapad_rfk_set(void *data, bool blocked)
0988 {
0989 struct ideapad_rfk_priv *priv = data;
0990 int opcode = ideapad_rfk_data[priv->dev].opcode;
0991
0992 return write_ec_cmd(priv->priv->adev->handle, opcode, !blocked);
0993 }
0994
0995 static const struct rfkill_ops ideapad_rfk_ops = {
0996 .set_block = ideapad_rfk_set,
0997 };
0998
0999 static void ideapad_sync_rfk_state(struct ideapad_private *priv)
1000 {
1001 unsigned long hw_blocked = 0;
1002 int i;
1003
1004 if (priv->features.hw_rfkill_switch) {
1005 if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked))
1006 return;
1007 hw_blocked = !hw_blocked;
1008 }
1009
1010 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
1011 if (priv->rfk[i])
1012 rfkill_set_hw_state(priv->rfk[i], hw_blocked);
1013 }
1014
1015 static int ideapad_register_rfkill(struct ideapad_private *priv, int dev)
1016 {
1017 unsigned long rf_enabled;
1018 int err;
1019
1020 if (no_bt_rfkill && ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH) {
1021
1022 write_ec_cmd(priv->adev->handle, ideapad_rfk_data[dev].opcode, 1);
1023 return 0;
1024 }
1025
1026 priv->rfk_priv[dev].dev = dev;
1027 priv->rfk_priv[dev].priv = priv;
1028
1029 priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev].name,
1030 &priv->platform_device->dev,
1031 ideapad_rfk_data[dev].type,
1032 &ideapad_rfk_ops,
1033 &priv->rfk_priv[dev]);
1034 if (!priv->rfk[dev])
1035 return -ENOMEM;
1036
1037 err = read_ec_data(priv->adev->handle, ideapad_rfk_data[dev].opcode - 1, &rf_enabled);
1038 if (err)
1039 rf_enabled = 1;
1040
1041 rfkill_init_sw_state(priv->rfk[dev], !rf_enabled);
1042
1043 err = rfkill_register(priv->rfk[dev]);
1044 if (err)
1045 rfkill_destroy(priv->rfk[dev]);
1046
1047 return err;
1048 }
1049
1050 static void ideapad_unregister_rfkill(struct ideapad_private *priv, int dev)
1051 {
1052 if (!priv->rfk[dev])
1053 return;
1054
1055 rfkill_unregister(priv->rfk[dev]);
1056 rfkill_destroy(priv->rfk[dev]);
1057 }
1058
1059
1060
1061
1062 static int ideapad_sysfs_init(struct ideapad_private *priv)
1063 {
1064 return device_add_group(&priv->platform_device->dev,
1065 &ideapad_attribute_group);
1066 }
1067
1068 static void ideapad_sysfs_exit(struct ideapad_private *priv)
1069 {
1070 device_remove_group(&priv->platform_device->dev,
1071 &ideapad_attribute_group);
1072 }
1073
1074
1075
1076
1077 static const struct key_entry ideapad_keymap[] = {
1078 { KE_KEY, 6, { KEY_SWITCHVIDEOMODE } },
1079 { KE_KEY, 7, { KEY_CAMERA } },
1080 { KE_KEY, 8, { KEY_MICMUTE } },
1081 { KE_KEY, 11, { KEY_F16 } },
1082 { KE_KEY, 13, { KEY_WLAN } },
1083 { KE_KEY, 16, { KEY_PROG1 } },
1084 { KE_KEY, 17, { KEY_PROG2 } },
1085 { KE_KEY, 64, { KEY_PROG3 } },
1086 { KE_KEY, 65, { KEY_PROG4 } },
1087 { KE_KEY, 66, { KEY_TOUCHPAD_OFF } },
1088 { KE_KEY, 67, { KEY_TOUCHPAD_ON } },
1089 { KE_KEY, 128, { KEY_ESC } },
1090 { KE_END },
1091 };
1092
1093 static int ideapad_input_init(struct ideapad_private *priv)
1094 {
1095 struct input_dev *inputdev;
1096 int err;
1097
1098 inputdev = input_allocate_device();
1099 if (!inputdev)
1100 return -ENOMEM;
1101
1102 inputdev->name = "Ideapad extra buttons";
1103 inputdev->phys = "ideapad/input0";
1104 inputdev->id.bustype = BUS_HOST;
1105 inputdev->dev.parent = &priv->platform_device->dev;
1106
1107 err = sparse_keymap_setup(inputdev, ideapad_keymap, NULL);
1108 if (err) {
1109 dev_err(&priv->platform_device->dev,
1110 "Could not set up input device keymap: %d\n", err);
1111 goto err_free_dev;
1112 }
1113
1114 err = input_register_device(inputdev);
1115 if (err) {
1116 dev_err(&priv->platform_device->dev,
1117 "Could not register input device: %d\n", err);
1118 goto err_free_dev;
1119 }
1120
1121 priv->inputdev = inputdev;
1122
1123 return 0;
1124
1125 err_free_dev:
1126 input_free_device(inputdev);
1127
1128 return err;
1129 }
1130
1131 static void ideapad_input_exit(struct ideapad_private *priv)
1132 {
1133 input_unregister_device(priv->inputdev);
1134 priv->inputdev = NULL;
1135 }
1136
1137 static void ideapad_input_report(struct ideapad_private *priv,
1138 unsigned long scancode)
1139 {
1140 sparse_keymap_report_event(priv->inputdev, scancode, 1, true);
1141 }
1142
1143 static void ideapad_input_novokey(struct ideapad_private *priv)
1144 {
1145 unsigned long long_pressed;
1146
1147 if (read_ec_data(priv->adev->handle, VPCCMD_R_NOVO, &long_pressed))
1148 return;
1149
1150 if (long_pressed)
1151 ideapad_input_report(priv, 17);
1152 else
1153 ideapad_input_report(priv, 16);
1154 }
1155
1156 static void ideapad_check_special_buttons(struct ideapad_private *priv)
1157 {
1158 unsigned long bit, value;
1159
1160 if (read_ec_data(priv->adev->handle, VPCCMD_R_SPECIAL_BUTTONS, &value))
1161 return;
1162
1163 for_each_set_bit (bit, &value, 16) {
1164 switch (bit) {
1165 case 6:
1166 case 0:
1167
1168 ideapad_input_report(priv, 65);
1169 break;
1170 case 1:
1171
1172 ideapad_input_report(priv, 64);
1173 break;
1174 default:
1175 dev_info(&priv->platform_device->dev,
1176 "Unknown special button: %lu\n", bit);
1177 break;
1178 }
1179 }
1180 }
1181
1182
1183
1184
1185 static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
1186 {
1187 struct ideapad_private *priv = bl_get_data(blightdev);
1188 unsigned long now;
1189 int err;
1190
1191 err = read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
1192 if (err)
1193 return err;
1194
1195 return now;
1196 }
1197
1198 static int ideapad_backlight_update_status(struct backlight_device *blightdev)
1199 {
1200 struct ideapad_private *priv = bl_get_data(blightdev);
1201 int err;
1202
1203 err = write_ec_cmd(priv->adev->handle, VPCCMD_W_BL,
1204 blightdev->props.brightness);
1205 if (err)
1206 return err;
1207
1208 err = write_ec_cmd(priv->adev->handle, VPCCMD_W_BL_POWER,
1209 blightdev->props.power != FB_BLANK_POWERDOWN);
1210 if (err)
1211 return err;
1212
1213 return 0;
1214 }
1215
1216 static const struct backlight_ops ideapad_backlight_ops = {
1217 .get_brightness = ideapad_backlight_get_brightness,
1218 .update_status = ideapad_backlight_update_status,
1219 };
1220
1221 static int ideapad_backlight_init(struct ideapad_private *priv)
1222 {
1223 struct backlight_device *blightdev;
1224 struct backlight_properties props;
1225 unsigned long max, now, power;
1226 int err;
1227
1228 err = read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &max);
1229 if (err)
1230 return err;
1231
1232 err = read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
1233 if (err)
1234 return err;
1235
1236 err = read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power);
1237 if (err)
1238 return err;
1239
1240 memset(&props, 0, sizeof(props));
1241
1242 props.max_brightness = max;
1243 props.type = BACKLIGHT_PLATFORM;
1244
1245 blightdev = backlight_device_register("ideapad",
1246 &priv->platform_device->dev,
1247 priv,
1248 &ideapad_backlight_ops,
1249 &props);
1250 if (IS_ERR(blightdev)) {
1251 err = PTR_ERR(blightdev);
1252 dev_err(&priv->platform_device->dev,
1253 "Could not register backlight device: %d\n", err);
1254 return err;
1255 }
1256
1257 priv->blightdev = blightdev;
1258 blightdev->props.brightness = now;
1259 blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
1260
1261 backlight_update_status(blightdev);
1262
1263 return 0;
1264 }
1265
1266 static void ideapad_backlight_exit(struct ideapad_private *priv)
1267 {
1268 backlight_device_unregister(priv->blightdev);
1269 priv->blightdev = NULL;
1270 }
1271
1272 static void ideapad_backlight_notify_power(struct ideapad_private *priv)
1273 {
1274 struct backlight_device *blightdev = priv->blightdev;
1275 unsigned long power;
1276
1277 if (!blightdev)
1278 return;
1279
1280 if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power))
1281 return;
1282
1283 blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
1284 }
1285
1286 static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
1287 {
1288 unsigned long now;
1289
1290
1291 if (!priv->blightdev)
1292 read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
1293 else
1294 backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY);
1295 }
1296
1297
1298
1299
1300 static int ideapad_kbd_bl_brightness_get(struct ideapad_private *priv)
1301 {
1302 unsigned long hals;
1303 int err;
1304
1305 err = eval_hals(priv->adev->handle, &hals);
1306 if (err)
1307 return err;
1308
1309 return !!test_bit(HALS_KBD_BL_STATE_BIT, &hals);
1310 }
1311
1312 static enum led_brightness ideapad_kbd_bl_led_cdev_brightness_get(struct led_classdev *led_cdev)
1313 {
1314 struct ideapad_private *priv = container_of(led_cdev, struct ideapad_private, kbd_bl.led);
1315
1316 return ideapad_kbd_bl_brightness_get(priv);
1317 }
1318
1319 static int ideapad_kbd_bl_brightness_set(struct ideapad_private *priv, unsigned int brightness)
1320 {
1321 int err = exec_sals(priv->adev->handle, brightness ? SALS_KBD_BL_ON : SALS_KBD_BL_OFF);
1322
1323 if (err)
1324 return err;
1325
1326 priv->kbd_bl.last_brightness = brightness;
1327
1328 return 0;
1329 }
1330
1331 static int ideapad_kbd_bl_led_cdev_brightness_set(struct led_classdev *led_cdev,
1332 enum led_brightness brightness)
1333 {
1334 struct ideapad_private *priv = container_of(led_cdev, struct ideapad_private, kbd_bl.led);
1335
1336 return ideapad_kbd_bl_brightness_set(priv, brightness);
1337 }
1338
1339 static void ideapad_kbd_bl_notify(struct ideapad_private *priv)
1340 {
1341 int brightness;
1342
1343 if (!priv->kbd_bl.initialized)
1344 return;
1345
1346 brightness = ideapad_kbd_bl_brightness_get(priv);
1347 if (brightness < 0)
1348 return;
1349
1350 if (brightness == priv->kbd_bl.last_brightness)
1351 return;
1352
1353 priv->kbd_bl.last_brightness = brightness;
1354
1355 led_classdev_notify_brightness_hw_changed(&priv->kbd_bl.led, brightness);
1356 }
1357
1358 static int ideapad_kbd_bl_init(struct ideapad_private *priv)
1359 {
1360 int brightness, err;
1361
1362 if (!priv->features.kbd_bl)
1363 return -ENODEV;
1364
1365 if (WARN_ON(priv->kbd_bl.initialized))
1366 return -EEXIST;
1367
1368 brightness = ideapad_kbd_bl_brightness_get(priv);
1369 if (brightness < 0)
1370 return brightness;
1371
1372 priv->kbd_bl.last_brightness = brightness;
1373
1374 priv->kbd_bl.led.name = "platform::" LED_FUNCTION_KBD_BACKLIGHT;
1375 priv->kbd_bl.led.max_brightness = 1;
1376 priv->kbd_bl.led.brightness_get = ideapad_kbd_bl_led_cdev_brightness_get;
1377 priv->kbd_bl.led.brightness_set_blocking = ideapad_kbd_bl_led_cdev_brightness_set;
1378 priv->kbd_bl.led.flags = LED_BRIGHT_HW_CHANGED;
1379
1380 err = led_classdev_register(&priv->platform_device->dev, &priv->kbd_bl.led);
1381 if (err)
1382 return err;
1383
1384 priv->kbd_bl.initialized = true;
1385
1386 return 0;
1387 }
1388
1389 static void ideapad_kbd_bl_exit(struct ideapad_private *priv)
1390 {
1391 if (!priv->kbd_bl.initialized)
1392 return;
1393
1394 priv->kbd_bl.initialized = false;
1395
1396 led_classdev_unregister(&priv->kbd_bl.led);
1397 }
1398
1399
1400
1401
1402 static void ideapad_sync_touchpad_state(struct ideapad_private *priv)
1403 {
1404 unsigned long value;
1405
1406 if (!priv->features.touchpad_ctrl_via_ec)
1407 return;
1408
1409
1410 if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value)) {
1411 unsigned char param;
1412
1413
1414
1415
1416
1417
1418 i8042_command(¶m, value ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE);
1419 ideapad_input_report(priv, value ? 67 : 66);
1420 sysfs_notify(&priv->platform_device->dev.kobj, NULL, "touchpad");
1421 }
1422 }
1423
1424 static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
1425 {
1426 struct ideapad_private *priv = data;
1427 unsigned long vpc1, vpc2, bit;
1428
1429 if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
1430 return;
1431
1432 if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
1433 return;
1434
1435 vpc1 = (vpc2 << 8) | vpc1;
1436
1437 for_each_set_bit (bit, &vpc1, 16) {
1438 switch (bit) {
1439 case 13:
1440 case 11:
1441 case 8:
1442 case 7:
1443 case 6:
1444 ideapad_input_report(priv, bit);
1445 break;
1446 case 10:
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457 break;
1458 case 9:
1459 ideapad_sync_rfk_state(priv);
1460 break;
1461 case 5:
1462 ideapad_sync_touchpad_state(priv);
1463 break;
1464 case 4:
1465 ideapad_backlight_notify_brightness(priv);
1466 break;
1467 case 3:
1468 ideapad_input_novokey(priv);
1469 break;
1470 case 2:
1471 ideapad_backlight_notify_power(priv);
1472 break;
1473 case 1:
1474
1475
1476
1477
1478
1479
1480
1481 ideapad_kbd_bl_notify(priv);
1482 break;
1483 case 0:
1484 ideapad_check_special_buttons(priv);
1485 break;
1486 default:
1487 dev_info(&priv->platform_device->dev,
1488 "Unknown event: %lu\n", bit);
1489 }
1490 }
1491 }
1492
1493 #if IS_ENABLED(CONFIG_ACPI_WMI)
1494 static void ideapad_wmi_notify(u32 value, void *context)
1495 {
1496 struct ideapad_private *priv = context;
1497 unsigned long result;
1498
1499 switch (value) {
1500 case 128:
1501 ideapad_input_report(priv, value);
1502 break;
1503 case 208:
1504 if (!eval_hals(priv->adev->handle, &result)) {
1505 bool state = test_bit(HALS_FNLOCK_STATE_BIT, &result);
1506
1507 exec_sals(priv->adev->handle, state ? SALS_FNLOCK_ON : SALS_FNLOCK_OFF);
1508 }
1509 break;
1510 default:
1511 dev_info(&priv->platform_device->dev,
1512 "Unknown WMI event: %u\n", value);
1513 }
1514 }
1515 #endif
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532 static const struct dmi_system_id hw_rfkill_list[] = {
1533 {}
1534 };
1535
1536 static void ideapad_check_features(struct ideapad_private *priv)
1537 {
1538 acpi_handle handle = priv->adev->handle;
1539 unsigned long val;
1540
1541 priv->features.hw_rfkill_switch = dmi_check_system(hw_rfkill_list);
1542
1543
1544 priv->features.touchpad_ctrl_via_ec = !acpi_dev_present("ELAN0634", NULL, -1);
1545
1546 if (!read_ec_data(handle, VPCCMD_R_FAN, &val))
1547 priv->features.fan_mode = true;
1548
1549 if (acpi_has_method(handle, "GBMD") && acpi_has_method(handle, "SBMC"))
1550 priv->features.conservation_mode = true;
1551
1552 if (acpi_has_method(handle, "DYTC"))
1553 priv->features.dytc = true;
1554
1555 if (acpi_has_method(handle, "HALS") && acpi_has_method(handle, "SALS")) {
1556 if (!eval_hals(handle, &val)) {
1557 if (test_bit(HALS_FNLOCK_SUPPORT_BIT, &val))
1558 priv->features.fn_lock = true;
1559
1560 if (test_bit(HALS_KBD_BL_SUPPORT_BIT, &val))
1561 priv->features.kbd_bl = true;
1562
1563 if (test_bit(HALS_USB_CHARGING_SUPPORT_BIT, &val))
1564 priv->features.usb_charging = true;
1565 }
1566 }
1567 }
1568
1569 static int ideapad_acpi_add(struct platform_device *pdev)
1570 {
1571 struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
1572 struct ideapad_private *priv;
1573 acpi_status status;
1574 unsigned long cfg;
1575 int err, i;
1576
1577 if (!adev || eval_int(adev->handle, "_CFG", &cfg))
1578 return -ENODEV;
1579
1580 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
1581 if (!priv)
1582 return -ENOMEM;
1583
1584 dev_set_drvdata(&pdev->dev, priv);
1585
1586 priv->cfg = cfg;
1587 priv->adev = adev;
1588 priv->platform_device = pdev;
1589
1590 ideapad_check_features(priv);
1591
1592 err = ideapad_sysfs_init(priv);
1593 if (err)
1594 return err;
1595
1596 ideapad_debugfs_init(priv);
1597
1598 err = ideapad_input_init(priv);
1599 if (err)
1600 goto input_failed;
1601
1602 err = ideapad_kbd_bl_init(priv);
1603 if (err) {
1604 if (err != -ENODEV)
1605 dev_warn(&pdev->dev, "Could not set up keyboard backlight LED: %d\n", err);
1606 else
1607 dev_info(&pdev->dev, "Keyboard backlight control not available\n");
1608 }
1609
1610
1611
1612
1613
1614 if (!priv->features.hw_rfkill_switch)
1615 write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1);
1616
1617
1618 if (!priv->features.touchpad_ctrl_via_ec)
1619 write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, 1);
1620
1621 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
1622 if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
1623 ideapad_register_rfkill(priv, i);
1624
1625 ideapad_sync_rfk_state(priv);
1626 ideapad_sync_touchpad_state(priv);
1627
1628 err = ideapad_dytc_profile_init(priv);
1629 if (err) {
1630 if (err != -ENODEV)
1631 dev_warn(&pdev->dev, "Could not set up DYTC interface: %d\n", err);
1632 else
1633 dev_info(&pdev->dev, "DYTC interface is not available\n");
1634 }
1635
1636 if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
1637 err = ideapad_backlight_init(priv);
1638 if (err && err != -ENODEV)
1639 goto backlight_failed;
1640 }
1641
1642 status = acpi_install_notify_handler(adev->handle,
1643 ACPI_DEVICE_NOTIFY,
1644 ideapad_acpi_notify, priv);
1645 if (ACPI_FAILURE(status)) {
1646 err = -EIO;
1647 goto notification_failed;
1648 }
1649
1650 #if IS_ENABLED(CONFIG_ACPI_WMI)
1651 for (i = 0; i < ARRAY_SIZE(ideapad_wmi_fnesc_events); i++) {
1652 status = wmi_install_notify_handler(ideapad_wmi_fnesc_events[i],
1653 ideapad_wmi_notify, priv);
1654 if (ACPI_SUCCESS(status)) {
1655 priv->fnesc_guid = ideapad_wmi_fnesc_events[i];
1656 break;
1657 }
1658 }
1659
1660 if (ACPI_FAILURE(status) && status != AE_NOT_EXIST) {
1661 err = -EIO;
1662 goto notification_failed_wmi;
1663 }
1664 #endif
1665
1666 return 0;
1667
1668 #if IS_ENABLED(CONFIG_ACPI_WMI)
1669 notification_failed_wmi:
1670 acpi_remove_notify_handler(priv->adev->handle,
1671 ACPI_DEVICE_NOTIFY,
1672 ideapad_acpi_notify);
1673 #endif
1674
1675 notification_failed:
1676 ideapad_backlight_exit(priv);
1677
1678 backlight_failed:
1679 ideapad_dytc_profile_exit(priv);
1680
1681 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
1682 ideapad_unregister_rfkill(priv, i);
1683
1684 ideapad_kbd_bl_exit(priv);
1685 ideapad_input_exit(priv);
1686
1687 input_failed:
1688 ideapad_debugfs_exit(priv);
1689 ideapad_sysfs_exit(priv);
1690
1691 return err;
1692 }
1693
1694 static int ideapad_acpi_remove(struct platform_device *pdev)
1695 {
1696 struct ideapad_private *priv = dev_get_drvdata(&pdev->dev);
1697 int i;
1698
1699 #if IS_ENABLED(CONFIG_ACPI_WMI)
1700 if (priv->fnesc_guid)
1701 wmi_remove_notify_handler(priv->fnesc_guid);
1702 #endif
1703
1704 acpi_remove_notify_handler(priv->adev->handle,
1705 ACPI_DEVICE_NOTIFY,
1706 ideapad_acpi_notify);
1707
1708 ideapad_backlight_exit(priv);
1709 ideapad_dytc_profile_exit(priv);
1710
1711 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
1712 ideapad_unregister_rfkill(priv, i);
1713
1714 ideapad_kbd_bl_exit(priv);
1715 ideapad_input_exit(priv);
1716 ideapad_debugfs_exit(priv);
1717 ideapad_sysfs_exit(priv);
1718
1719 return 0;
1720 }
1721
1722 #ifdef CONFIG_PM_SLEEP
1723 static int ideapad_acpi_resume(struct device *dev)
1724 {
1725 struct ideapad_private *priv = dev_get_drvdata(dev);
1726
1727 ideapad_sync_rfk_state(priv);
1728 ideapad_sync_touchpad_state(priv);
1729
1730 if (priv->dytc)
1731 dytc_profile_refresh(priv);
1732
1733 return 0;
1734 }
1735 #endif
1736 static SIMPLE_DEV_PM_OPS(ideapad_pm, NULL, ideapad_acpi_resume);
1737
1738 static const struct acpi_device_id ideapad_device_ids[] = {
1739 {"VPC2004", 0},
1740 {"", 0},
1741 };
1742 MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
1743
1744 static struct platform_driver ideapad_acpi_driver = {
1745 .probe = ideapad_acpi_add,
1746 .remove = ideapad_acpi_remove,
1747 .driver = {
1748 .name = "ideapad_acpi",
1749 .pm = &ideapad_pm,
1750 .acpi_match_table = ACPI_PTR(ideapad_device_ids),
1751 },
1752 };
1753
1754 module_platform_driver(ideapad_acpi_driver);
1755
1756 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
1757 MODULE_DESCRIPTION("IdeaPad ACPI Extras");
1758 MODULE_LICENSE("GPL");