linux/drivers/platform/x86/ideapad-laptop.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  ideapad-laptop.c - Lenovo IdeaPad ACPI Extras
   4 *
   5 *  Copyright © 2010 Intel Corporation
   6 *  Copyright © 2010 David Woodhouse <dwmw2@infradead.org>
   7 */
   8
   9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  10
  11#include <linux/acpi.h>
  12#include <linux/backlight.h>
  13#include <linux/bitops.h>
  14#include <linux/bug.h>
  15#include <linux/debugfs.h>
  16#include <linux/device.h>
  17#include <linux/dmi.h>
  18#include <linux/fb.h>
  19#include <linux/i8042.h>
  20#include <linux/init.h>
  21#include <linux/input.h>
  22#include <linux/input/sparse-keymap.h>
  23#include <linux/jiffies.h>
  24#include <linux/kernel.h>
  25#include <linux/leds.h>
  26#include <linux/module.h>
  27#include <linux/platform_device.h>
  28#include <linux/platform_profile.h>
  29#include <linux/rfkill.h>
  30#include <linux/seq_file.h>
  31#include <linux/sysfs.h>
  32#include <linux/types.h>
  33
  34#include <acpi/video.h>
  35
  36#include <dt-bindings/leds/common.h>
  37
  38#define IDEAPAD_RFKILL_DEV_NUM  3
  39
  40#if IS_ENABLED(CONFIG_ACPI_WMI)
  41static const char *const ideapad_wmi_fnesc_events[] = {
  42        "26CAB2E5-5CF1-46AE-AAC3-4A12B6BA50E6", /* Yoga 3 */
  43        "56322276-8493-4CE8-A783-98C991274F5E", /* Yoga 700 */
  44        "8FC0DE0C-B4E4-43FD-B0F3-8871711C1294", /* Legion 5 */
  45};
  46#endif
  47
  48enum {
  49        CFG_CAP_BT_BIT       = 16,
  50        CFG_CAP_3G_BIT       = 17,
  51        CFG_CAP_WIFI_BIT     = 18,
  52        CFG_CAP_CAM_BIT      = 19,
  53        CFG_CAP_TOUCHPAD_BIT = 30,
  54};
  55
  56enum {
  57        GBMD_CONSERVATION_STATE_BIT = 5,
  58};
  59
  60enum {
  61        SBMC_CONSERVATION_ON  = 3,
  62        SBMC_CONSERVATION_OFF = 5,
  63};
  64
  65enum {
  66        HALS_KBD_BL_SUPPORT_BIT       = 4,
  67        HALS_KBD_BL_STATE_BIT         = 5,
  68        HALS_USB_CHARGING_SUPPORT_BIT = 6,
  69        HALS_USB_CHARGING_STATE_BIT   = 7,
  70        HALS_FNLOCK_SUPPORT_BIT       = 9,
  71        HALS_FNLOCK_STATE_BIT         = 10,
  72        HALS_HOTKEYS_PRIMARY_BIT      = 11,
  73};
  74
  75enum {
  76        SALS_KBD_BL_ON        = 0x8,
  77        SALS_KBD_BL_OFF       = 0x9,
  78        SALS_USB_CHARGING_ON  = 0xa,
  79        SALS_USB_CHARGING_OFF = 0xb,
  80        SALS_FNLOCK_ON        = 0xe,
  81        SALS_FNLOCK_OFF       = 0xf,
  82};
  83
  84enum {
  85        VPCCMD_R_VPC1 = 0x10,
  86        VPCCMD_R_BL_MAX,
  87        VPCCMD_R_BL,
  88        VPCCMD_W_BL,
  89        VPCCMD_R_WIFI,
  90        VPCCMD_W_WIFI,
  91        VPCCMD_R_BT,
  92        VPCCMD_W_BT,
  93        VPCCMD_R_BL_POWER,
  94        VPCCMD_R_NOVO,
  95        VPCCMD_R_VPC2,
  96        VPCCMD_R_TOUCHPAD,
  97        VPCCMD_W_TOUCHPAD,
  98        VPCCMD_R_CAMERA,
  99        VPCCMD_W_CAMERA,
 100        VPCCMD_R_3G,
 101        VPCCMD_W_3G,
 102        VPCCMD_R_ODD, /* 0x21 */
 103        VPCCMD_W_FAN,
 104        VPCCMD_R_RF,
 105        VPCCMD_W_RF,
 106        VPCCMD_R_FAN = 0x2B,
 107        VPCCMD_R_SPECIAL_BUTTONS = 0x31,
 108        VPCCMD_W_BL_POWER = 0x33,
 109};
 110
 111struct ideapad_dytc_priv {
 112        enum platform_profile_option current_profile;
 113        struct platform_profile_handler pprof;
 114        struct mutex mutex; /* protects the DYTC interface */
 115        struct ideapad_private *priv;
 116};
 117
 118struct ideapad_rfk_priv {
 119        int dev;
 120        struct ideapad_private *priv;
 121};
 122
 123struct ideapad_private {
 124        struct acpi_device *adev;
 125        struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
 126        struct ideapad_rfk_priv rfk_priv[IDEAPAD_RFKILL_DEV_NUM];
 127        struct platform_device *platform_device;
 128        struct input_dev *inputdev;
 129        struct backlight_device *blightdev;
 130        struct ideapad_dytc_priv *dytc;
 131        struct dentry *debug;
 132        unsigned long cfg;
 133        const char *fnesc_guid;
 134        struct {
 135                bool conservation_mode    : 1;
 136                bool dytc                 : 1;
 137                bool fan_mode             : 1;
 138                bool fn_lock              : 1;
 139                bool hw_rfkill_switch     : 1;
 140                bool kbd_bl               : 1;
 141                bool touchpad_ctrl_via_ec : 1;
 142                bool usb_charging         : 1;
 143        } features;
 144        struct {
 145                bool initialized;
 146                struct led_classdev led;
 147                unsigned int last_brightness;
 148        } kbd_bl;
 149};
 150
 151static bool no_bt_rfkill;
 152module_param(no_bt_rfkill, bool, 0444);
 153MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
 154
 155/*
 156 * ACPI Helpers
 157 */
 158#define IDEAPAD_EC_TIMEOUT 200 /* in ms */
 159
 160static int eval_int(acpi_handle handle, const char *name, unsigned long *res)
 161{
 162        unsigned long long result;
 163        acpi_status status;
 164
 165        status = acpi_evaluate_integer(handle, (char *)name, NULL, &result);
 166        if (ACPI_FAILURE(status))
 167                return -EIO;
 168
 169        *res = result;
 170
 171        return 0;
 172}
 173
 174static int exec_simple_method(acpi_handle handle, const char *name, unsigned long arg)
 175{
 176        acpi_status status = acpi_execute_simple_method(handle, (char *)name, arg);
 177
 178        return ACPI_FAILURE(status) ? -EIO : 0;
 179}
 180
 181static int eval_gbmd(acpi_handle handle, unsigned long *res)
 182{
 183        return eval_int(handle, "GBMD", res);
 184}
 185
 186static int exec_sbmc(acpi_handle handle, unsigned long arg)
 187{
 188        return exec_simple_method(handle, "SBMC", arg);
 189}
 190
 191static int eval_hals(acpi_handle handle, unsigned long *res)
 192{
 193        return eval_int(handle, "HALS", res);
 194}
 195
 196static int exec_sals(acpi_handle handle, unsigned long arg)
 197{
 198        return exec_simple_method(handle, "SALS", arg);
 199}
 200
 201static int eval_int_with_arg(acpi_handle handle, const char *name, unsigned long arg, unsigned long *res)
 202{
 203        struct acpi_object_list params;
 204        unsigned long long result;
 205        union acpi_object in_obj;
 206        acpi_status status;
 207
 208        params.count = 1;
 209        params.pointer = &in_obj;
 210        in_obj.type = ACPI_TYPE_INTEGER;
 211        in_obj.integer.value = arg;
 212
 213        status = acpi_evaluate_integer(handle, (char *)name, &params, &result);
 214        if (ACPI_FAILURE(status))
 215                return -EIO;
 216
 217        if (res)
 218                *res = result;
 219
 220        return 0;
 221}
 222
 223static int eval_dytc(acpi_handle handle, unsigned long cmd, unsigned long *res)
 224{
 225        return eval_int_with_arg(handle, "DYTC", cmd, res);
 226}
 227
 228static int eval_vpcr(acpi_handle handle, unsigned long cmd, unsigned long *res)
 229{
 230        return eval_int_with_arg(handle, "VPCR", cmd, res);
 231}
 232
 233static int eval_vpcw(acpi_handle handle, unsigned long cmd, unsigned long data)
 234{
 235        struct acpi_object_list params;
 236        union acpi_object in_obj[2];
 237        acpi_status status;
 238
 239        params.count = 2;
 240        params.pointer = in_obj;
 241        in_obj[0].type = ACPI_TYPE_INTEGER;
 242        in_obj[0].integer.value = cmd;
 243        in_obj[1].type = ACPI_TYPE_INTEGER;
 244        in_obj[1].integer.value = data;
 245
 246        status = acpi_evaluate_object(handle, "VPCW", &params, NULL);
 247        if (ACPI_FAILURE(status))
 248                return -EIO;
 249
 250        return 0;
 251}
 252
 253static int read_ec_data(acpi_handle handle, unsigned long cmd, unsigned long *data)
 254{
 255        unsigned long end_jiffies, val;
 256        int err;
 257
 258        err = eval_vpcw(handle, 1, cmd);
 259        if (err)
 260                return err;
 261
 262        end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1;
 263
 264        while (time_before(jiffies, end_jiffies)) {
 265                schedule();
 266
 267                err = eval_vpcr(handle, 1, &val);
 268                if (err)
 269                        return err;
 270
 271                if (val == 0)
 272                        return eval_vpcr(handle, 0, data);
 273        }
 274
 275        acpi_handle_err(handle, "timeout in %s\n", __func__);
 276
 277        return -ETIMEDOUT;
 278}
 279
 280static int write_ec_cmd(acpi_handle handle, unsigned long cmd, unsigned long data)
 281{
 282        unsigned long end_jiffies, val;
 283        int err;
 284
 285        err = eval_vpcw(handle, 0, data);
 286        if (err)
 287                return err;
 288
 289        err = eval_vpcw(handle, 1, cmd);
 290        if (err)
 291                return err;
 292
 293        end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1;
 294
 295        while (time_before(jiffies, end_jiffies)) {
 296                schedule();
 297
 298                err = eval_vpcr(handle, 1, &val);
 299                if (err)
 300                        return err;
 301
 302                if (val == 0)
 303                        return 0;
 304        }
 305
 306        acpi_handle_err(handle, "timeout in %s\n", __func__);
 307
 308        return -ETIMEDOUT;
 309}
 310
 311/*
 312 * debugfs
 313 */
 314static int debugfs_status_show(struct seq_file *s, void *data)
 315{
 316        struct ideapad_private *priv = s->private;
 317        unsigned long value;
 318
 319        if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value))
 320                seq_printf(s, "Backlight max:  %lu\n", value);
 321        if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value))
 322                seq_printf(s, "Backlight now:  %lu\n", value);
 323        if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &value))
 324                seq_printf(s, "BL power value: %s (%lu)\n", value ? "on" : "off", value);
 325
 326        seq_puts(s, "=====================\n");
 327
 328        if (!read_ec_data(priv->adev->handle, VPCCMD_R_RF, &value))
 329                seq_printf(s, "Radio status: %s (%lu)\n", value ? "on" : "off", value);
 330        if (!read_ec_data(priv->adev->handle, VPCCMD_R_WIFI, &value))
 331                seq_printf(s, "Wifi status:  %s (%lu)\n", value ? "on" : "off", value);
 332        if (!read_ec_data(priv->adev->handle, VPCCMD_R_BT, &value))
 333                seq_printf(s, "BT status:    %s (%lu)\n", value ? "on" : "off", value);
 334        if (!read_ec_data(priv->adev->handle, VPCCMD_R_3G, &value))
 335                seq_printf(s, "3G status:    %s (%lu)\n", value ? "on" : "off", value);
 336
 337        seq_puts(s, "=====================\n");
 338
 339        if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value))
 340                seq_printf(s, "Touchpad status: %s (%lu)\n", value ? "on" : "off", value);
 341        if (!read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &value))
 342                seq_printf(s, "Camera status:   %s (%lu)\n", value ? "on" : "off", value);
 343
 344        seq_puts(s, "=====================\n");
 345
 346        if (!eval_gbmd(priv->adev->handle, &value))
 347                seq_printf(s, "GBMD: %#010lx\n", value);
 348        if (!eval_hals(priv->adev->handle, &value))
 349                seq_printf(s, "HALS: %#010lx\n", value);
 350
 351        return 0;
 352}
 353DEFINE_SHOW_ATTRIBUTE(debugfs_status);
 354
 355static int debugfs_cfg_show(struct seq_file *s, void *data)
 356{
 357        struct ideapad_private *priv = s->private;
 358
 359        seq_printf(s, "_CFG: %#010lx\n\n", priv->cfg);
 360
 361        seq_puts(s, "Capabilities:");
 362        if (test_bit(CFG_CAP_BT_BIT, &priv->cfg))
 363                seq_puts(s, " bluetooth");
 364        if (test_bit(CFG_CAP_3G_BIT, &priv->cfg))
 365                seq_puts(s, " 3G");
 366        if (test_bit(CFG_CAP_WIFI_BIT, &priv->cfg))
 367                seq_puts(s, " wifi");
 368        if (test_bit(CFG_CAP_CAM_BIT, &priv->cfg))
 369                seq_puts(s, " camera");
 370        if (test_bit(CFG_CAP_TOUCHPAD_BIT, &priv->cfg))
 371                seq_puts(s, " touchpad");
 372        seq_puts(s, "\n");
 373
 374        seq_puts(s, "Graphics: ");
 375        switch (priv->cfg & 0x700) {
 376        case 0x100:
 377                seq_puts(s, "Intel");
 378                break;
 379        case 0x200:
 380                seq_puts(s, "ATI");
 381                break;
 382        case 0x300:
 383                seq_puts(s, "Nvidia");
 384                break;
 385        case 0x400:
 386                seq_puts(s, "Intel and ATI");
 387                break;
 388        case 0x500:
 389                seq_puts(s, "Intel and Nvidia");
 390                break;
 391        }
 392        seq_puts(s, "\n");
 393
 394        return 0;
 395}
 396DEFINE_SHOW_ATTRIBUTE(debugfs_cfg);
 397
 398static void ideapad_debugfs_init(struct ideapad_private *priv)
 399{
 400        struct dentry *dir;
 401
 402        dir = debugfs_create_dir("ideapad", NULL);
 403        priv->debug = dir;
 404
 405        debugfs_create_file("cfg", 0444, dir, priv, &debugfs_cfg_fops);
 406        debugfs_create_file("status", 0444, dir, priv, &debugfs_status_fops);
 407}
 408
 409static void ideapad_debugfs_exit(struct ideapad_private *priv)
 410{
 411        debugfs_remove_recursive(priv->debug);
 412        priv->debug = NULL;
 413}
 414
 415/*
 416 * sysfs
 417 */
 418static ssize_t camera_power_show(struct device *dev,
 419                                 struct device_attribute *attr,
 420                                 char *buf)
 421{
 422        struct ideapad_private *priv = dev_get_drvdata(dev);
 423        unsigned long result;
 424        int err;
 425
 426        err = read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &result);
 427        if (err)
 428                return err;
 429
 430        return sysfs_emit(buf, "%d\n", !!result);
 431}
 432
 433static ssize_t camera_power_store(struct device *dev,
 434                                  struct device_attribute *attr,
 435                                  const char *buf, size_t count)
 436{
 437        struct ideapad_private *priv = dev_get_drvdata(dev);
 438        bool state;
 439        int err;
 440
 441        err = kstrtobool(buf, &state);
 442        if (err)
 443                return err;
 444
 445        err = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state);
 446        if (err)
 447                return err;
 448
 449        return count;
 450}
 451
 452static DEVICE_ATTR_RW(camera_power);
 453
 454static ssize_t conservation_mode_show(struct device *dev,
 455                                      struct device_attribute *attr,
 456                                      char *buf)
 457{
 458        struct ideapad_private *priv = dev_get_drvdata(dev);
 459        unsigned long result;
 460        int err;
 461
 462        err = eval_gbmd(priv->adev->handle, &result);
 463        if (err)
 464                return err;
 465
 466        return sysfs_emit(buf, "%d\n", !!test_bit(GBMD_CONSERVATION_STATE_BIT, &result));
 467}
 468
 469static ssize_t conservation_mode_store(struct device *dev,
 470                                       struct device_attribute *attr,
 471                                       const char *buf, size_t count)
 472{
 473        struct ideapad_private *priv = dev_get_drvdata(dev);
 474        bool state;
 475        int err;
 476
 477        err = kstrtobool(buf, &state);
 478        if (err)
 479                return err;
 480
 481        err = exec_sbmc(priv->adev->handle, state ? SBMC_CONSERVATION_ON : SBMC_CONSERVATION_OFF);
 482        if (err)
 483                return err;
 484
 485        return count;
 486}
 487
 488static DEVICE_ATTR_RW(conservation_mode);
 489
 490static ssize_t fan_mode_show(struct device *dev,
 491                             struct device_attribute *attr,
 492                             char *buf)
 493{
 494        struct ideapad_private *priv = dev_get_drvdata(dev);
 495        unsigned long result;
 496        int err;
 497
 498        err = read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &result);
 499        if (err)
 500                return err;
 501
 502        return sysfs_emit(buf, "%lu\n", result);
 503}
 504
 505static ssize_t fan_mode_store(struct device *dev,
 506                              struct device_attribute *attr,
 507                              const char *buf, size_t count)
 508{
 509        struct ideapad_private *priv = dev_get_drvdata(dev);
 510        unsigned int state;
 511        int err;
 512
 513        err = kstrtouint(buf, 0, &state);
 514        if (err)
 515                return err;
 516
 517        if (state > 4 || state == 3)
 518                return -EINVAL;
 519
 520        err = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state);
 521        if (err)
 522                return err;
 523
 524        return count;
 525}
 526
 527static DEVICE_ATTR_RW(fan_mode);
 528
 529static ssize_t fn_lock_show(struct device *dev,
 530                            struct device_attribute *attr,
 531                            char *buf)
 532{
 533        struct ideapad_private *priv = dev_get_drvdata(dev);
 534        unsigned long hals;
 535        int err;
 536
 537        err = eval_hals(priv->adev->handle, &hals);
 538        if (err)
 539                return err;
 540
 541        return sysfs_emit(buf, "%d\n", !!test_bit(HALS_FNLOCK_STATE_BIT, &hals));
 542}
 543
 544static ssize_t fn_lock_store(struct device *dev,
 545                             struct device_attribute *attr,
 546                             const char *buf, size_t count)
 547{
 548        struct ideapad_private *priv = dev_get_drvdata(dev);
 549        bool state;
 550        int err;
 551
 552        err = kstrtobool(buf, &state);
 553        if (err)
 554                return err;
 555
 556        err = exec_sals(priv->adev->handle, state ? SALS_FNLOCK_ON : SALS_FNLOCK_OFF);
 557        if (err)
 558                return err;
 559
 560        return count;
 561}
 562
 563static DEVICE_ATTR_RW(fn_lock);
 564
 565static ssize_t touchpad_show(struct device *dev,
 566                             struct device_attribute *attr,
 567                             char *buf)
 568{
 569        struct ideapad_private *priv = dev_get_drvdata(dev);
 570        unsigned long result;
 571        int err;
 572
 573        err = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result);
 574        if (err)
 575                return err;
 576
 577        return sysfs_emit(buf, "%d\n", !!result);
 578}
 579
 580static ssize_t touchpad_store(struct device *dev,
 581                              struct device_attribute *attr,
 582                              const char *buf, size_t count)
 583{
 584        struct ideapad_private *priv = dev_get_drvdata(dev);
 585        bool state;
 586        int err;
 587
 588        err = kstrtobool(buf, &state);
 589        if (err)
 590                return err;
 591
 592        err = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
 593        if (err)
 594                return err;
 595
 596        return count;
 597}
 598
 599static DEVICE_ATTR_RW(touchpad);
 600
 601static ssize_t usb_charging_show(struct device *dev,
 602                                 struct device_attribute *attr,
 603                                 char *buf)
 604{
 605        struct ideapad_private *priv = dev_get_drvdata(dev);
 606        unsigned long hals;
 607        int err;
 608
 609        err = eval_hals(priv->adev->handle, &hals);
 610        if (err)
 611                return err;
 612
 613        return sysfs_emit(buf, "%d\n", !!test_bit(HALS_USB_CHARGING_STATE_BIT, &hals));
 614}
 615
 616static ssize_t usb_charging_store(struct device *dev,
 617                                  struct device_attribute *attr,
 618                                  const char *buf, size_t count)
 619{
 620        struct ideapad_private *priv = dev_get_drvdata(dev);
 621        bool state;
 622        int err;
 623
 624        err = kstrtobool(buf, &state);
 625        if (err)
 626                return err;
 627
 628        err = exec_sals(priv->adev->handle, state ? SALS_USB_CHARGING_ON : SALS_USB_CHARGING_OFF);
 629        if (err)
 630                return err;
 631
 632        return count;
 633}
 634
 635static DEVICE_ATTR_RW(usb_charging);
 636
 637static struct attribute *ideapad_attributes[] = {
 638        &dev_attr_camera_power.attr,
 639        &dev_attr_conservation_mode.attr,
 640        &dev_attr_fan_mode.attr,
 641        &dev_attr_fn_lock.attr,
 642        &dev_attr_touchpad.attr,
 643        &dev_attr_usb_charging.attr,
 644        NULL
 645};
 646
 647static umode_t ideapad_is_visible(struct kobject *kobj,
 648                                  struct attribute *attr,
 649                                  int idx)
 650{
 651        struct device *dev = kobj_to_dev(kobj);
 652        struct ideapad_private *priv = dev_get_drvdata(dev);
 653        bool supported = true;
 654
 655        if (attr == &dev_attr_camera_power.attr)
 656                supported = test_bit(CFG_CAP_CAM_BIT, &priv->cfg);
 657        else if (attr == &dev_attr_conservation_mode.attr)
 658                supported = priv->features.conservation_mode;
 659        else if (attr == &dev_attr_fan_mode.attr)
 660                supported = priv->features.fan_mode;
 661        else if (attr == &dev_attr_fn_lock.attr)
 662                supported = priv->features.fn_lock;
 663        else if (attr == &dev_attr_touchpad.attr)
 664                supported = priv->features.touchpad_ctrl_via_ec &&
 665                            test_bit(CFG_CAP_TOUCHPAD_BIT, &priv->cfg);
 666        else if (attr == &dev_attr_usb_charging.attr)
 667                supported = priv->features.usb_charging;
 668
 669        return supported ? attr->mode : 0;
 670}
 671
 672static const struct attribute_group ideapad_attribute_group = {
 673        .is_visible = ideapad_is_visible,
 674        .attrs = ideapad_attributes
 675};
 676
 677/*
 678 * DYTC Platform profile
 679 */
 680#define DYTC_CMD_QUERY        0 /* To get DYTC status - enable/revision */
 681#define DYTC_CMD_SET          1 /* To enable/disable IC function mode */
 682#define DYTC_CMD_GET          2 /* To get current IC function and mode */
 683#define DYTC_CMD_RESET    0x1ff /* To reset back to default */
 684
 685#define DYTC_QUERY_ENABLE_BIT 8  /* Bit        8 - 0 = disabled, 1 = enabled */
 686#define DYTC_QUERY_SUBREV_BIT 16 /* Bits 16 - 27 - sub revision */
 687#define DYTC_QUERY_REV_BIT    28 /* Bits 28 - 31 - revision */
 688
 689#define DYTC_GET_FUNCTION_BIT 8  /* Bits  8-11 - function setting */
 690#define DYTC_GET_MODE_BIT     12 /* Bits 12-15 - mode setting */
 691
 692#define DYTC_SET_FUNCTION_BIT 12 /* Bits 12-15 - function setting */
 693#define DYTC_SET_MODE_BIT     16 /* Bits 16-19 - mode setting */
 694#define DYTC_SET_VALID_BIT    20 /* Bit     20 - 1 = on, 0 = off */
 695
 696#define DYTC_FUNCTION_STD     0  /* Function = 0, standard mode */
 697#define DYTC_FUNCTION_CQL     1  /* Function = 1, lap mode */
 698#define DYTC_FUNCTION_MMC     11 /* Function = 11, desk mode */
 699
 700#define DYTC_MODE_PERFORM     2  /* High power mode aka performance */
 701#define DYTC_MODE_LOW_POWER       3  /* Low power mode aka quiet */
 702#define DYTC_MODE_BALANCE   0xF  /* Default mode aka balanced */
 703
 704#define DYTC_SET_COMMAND(function, mode, on) \
 705        (DYTC_CMD_SET | (function) << DYTC_SET_FUNCTION_BIT | \
 706         (mode) << DYTC_SET_MODE_BIT | \
 707         (on) << DYTC_SET_VALID_BIT)
 708
 709#define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 0)
 710
 711#define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 1)
 712
 713static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile)
 714{
 715        switch (dytcmode) {
 716        case DYTC_MODE_LOW_POWER:
 717                *profile = PLATFORM_PROFILE_LOW_POWER;
 718                break;
 719        case DYTC_MODE_BALANCE:
 720                *profile =  PLATFORM_PROFILE_BALANCED;
 721                break;
 722        case DYTC_MODE_PERFORM:
 723                *profile =  PLATFORM_PROFILE_PERFORMANCE;
 724                break;
 725        default: /* Unknown mode */
 726                return -EINVAL;
 727        }
 728
 729        return 0;
 730}
 731
 732static int convert_profile_to_dytc(enum platform_profile_option profile, int *perfmode)
 733{
 734        switch (profile) {
 735        case PLATFORM_PROFILE_LOW_POWER:
 736                *perfmode = DYTC_MODE_LOW_POWER;
 737                break;
 738        case PLATFORM_PROFILE_BALANCED:
 739                *perfmode = DYTC_MODE_BALANCE;
 740                break;
 741        case PLATFORM_PROFILE_PERFORMANCE:
 742                *perfmode = DYTC_MODE_PERFORM;
 743                break;
 744        default: /* Unknown profile */
 745                return -EOPNOTSUPP;
 746        }
 747
 748        return 0;
 749}
 750
 751/*
 752 * dytc_profile_get: Function to register with platform_profile
 753 * handler. Returns current platform profile.
 754 */
 755static int dytc_profile_get(struct platform_profile_handler *pprof,
 756                            enum platform_profile_option *profile)
 757{
 758        struct ideapad_dytc_priv *dytc = container_of(pprof, struct ideapad_dytc_priv, pprof);
 759
 760        *profile = dytc->current_profile;
 761        return 0;
 762}
 763
 764/*
 765 * Helper function - check if we are in CQL mode and if we are
 766 *  - disable CQL,
 767 *  - run the command
 768 *  - enable CQL
 769 *  If not in CQL mode, just run the command
 770 */
 771static int dytc_cql_command(struct ideapad_private *priv, unsigned long cmd,
 772                            unsigned long *output)
 773{
 774        int err, cmd_err, cur_funcmode;
 775
 776        /* Determine if we are in CQL mode. This alters the commands we do */
 777        err = eval_dytc(priv->adev->handle, DYTC_CMD_GET, output);
 778        if (err)
 779                return err;
 780
 781        cur_funcmode = (*output >> DYTC_GET_FUNCTION_BIT) & 0xF;
 782        /* Check if we're OK to return immediately */
 783        if (cmd == DYTC_CMD_GET && cur_funcmode != DYTC_FUNCTION_CQL)
 784                return 0;
 785
 786        if (cur_funcmode == DYTC_FUNCTION_CQL) {
 787                err = eval_dytc(priv->adev->handle, DYTC_DISABLE_CQL, NULL);
 788                if (err)
 789                        return err;
 790        }
 791
 792        cmd_err = eval_dytc(priv->adev->handle, cmd, output);
 793        /* Check return condition after we've restored CQL state */
 794
 795        if (cur_funcmode == DYTC_FUNCTION_CQL) {
 796                err = eval_dytc(priv->adev->handle, DYTC_ENABLE_CQL, NULL);
 797                if (err)
 798                        return err;
 799        }
 800
 801        return cmd_err;
 802}
 803
 804/*
 805 * dytc_profile_set: Function to register with platform_profile
 806 * handler. Sets current platform profile.
 807 */
 808static int dytc_profile_set(struct platform_profile_handler *pprof,
 809                            enum platform_profile_option profile)
 810{
 811        struct ideapad_dytc_priv *dytc = container_of(pprof, struct ideapad_dytc_priv, pprof);
 812        struct ideapad_private *priv = dytc->priv;
 813        unsigned long output;
 814        int err;
 815
 816        err = mutex_lock_interruptible(&dytc->mutex);
 817        if (err)
 818                return err;
 819
 820        if (profile == PLATFORM_PROFILE_BALANCED) {
 821                /* To get back to balanced mode we just issue a reset command */
 822                err = eval_dytc(priv->adev->handle, DYTC_CMD_RESET, NULL);
 823                if (err)
 824                        goto unlock;
 825        } else {
 826                int perfmode;
 827
 828                err = convert_profile_to_dytc(profile, &perfmode);
 829                if (err)
 830                        goto unlock;
 831
 832                /* Determine if we are in CQL mode. This alters the commands we do */
 833                err = dytc_cql_command(priv, DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1),
 834                                       &output);
 835                if (err)
 836                        goto unlock;
 837        }
 838
 839        /* Success - update current profile */
 840        dytc->current_profile = profile;
 841
 842unlock:
 843        mutex_unlock(&dytc->mutex);
 844
 845        return err;
 846}
 847
 848static void dytc_profile_refresh(struct ideapad_private *priv)
 849{
 850        enum platform_profile_option profile;
 851        unsigned long output;
 852        int err, perfmode;
 853
 854        mutex_lock(&priv->dytc->mutex);
 855        err = dytc_cql_command(priv, DYTC_CMD_GET, &output);
 856        mutex_unlock(&priv->dytc->mutex);
 857        if (err)
 858                return;
 859
 860        perfmode = (output >> DYTC_GET_MODE_BIT) & 0xF;
 861
 862        if (convert_dytc_to_profile(perfmode, &profile))
 863                return;
 864
 865        if (profile != priv->dytc->current_profile) {
 866                priv->dytc->current_profile = profile;
 867                platform_profile_notify();
 868        }
 869}
 870
 871static int ideapad_dytc_profile_init(struct ideapad_private *priv)
 872{
 873        int err, dytc_version;
 874        unsigned long output;
 875
 876        if (!priv->features.dytc)
 877                return -ENODEV;
 878
 879        err = eval_dytc(priv->adev->handle, DYTC_CMD_QUERY, &output);
 880        /* For all other errors we can flag the failure */
 881        if (err)
 882                return err;
 883
 884        /* Check DYTC is enabled and supports mode setting */
 885        if (!test_bit(DYTC_QUERY_ENABLE_BIT, &output))
 886                return -ENODEV;
 887
 888        dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF;
 889        if (dytc_version < 5)
 890                return -ENODEV;
 891
 892        priv->dytc = kzalloc(sizeof(*priv->dytc), GFP_KERNEL);
 893        if (!priv->dytc)
 894                return -ENOMEM;
 895
 896        mutex_init(&priv->dytc->mutex);
 897
 898        priv->dytc->priv = priv;
 899        priv->dytc->pprof.profile_get = dytc_profile_get;
 900        priv->dytc->pprof.profile_set = dytc_profile_set;
 901
 902        /* Setup supported modes */
 903        set_bit(PLATFORM_PROFILE_LOW_POWER, priv->dytc->pprof.choices);
 904        set_bit(PLATFORM_PROFILE_BALANCED, priv->dytc->pprof.choices);
 905        set_bit(PLATFORM_PROFILE_PERFORMANCE, priv->dytc->pprof.choices);
 906
 907        /* Create platform_profile structure and register */
 908        err = platform_profile_register(&priv->dytc->pprof);
 909        if (err)
 910                goto pp_reg_failed;
 911
 912        /* Ensure initial values are correct */
 913        dytc_profile_refresh(priv);
 914
 915        return 0;
 916
 917pp_reg_failed:
 918        mutex_destroy(&priv->dytc->mutex);
 919        kfree(priv->dytc);
 920        priv->dytc = NULL;
 921
 922        return err;
 923}
 924
 925static void ideapad_dytc_profile_exit(struct ideapad_private *priv)
 926{
 927        if (!priv->dytc)
 928                return;
 929
 930        platform_profile_remove();
 931        mutex_destroy(&priv->dytc->mutex);
 932        kfree(priv->dytc);
 933
 934        priv->dytc = NULL;
 935}
 936
 937/*
 938 * Rfkill
 939 */
 940struct ideapad_rfk_data {
 941        char *name;
 942        int cfgbit;
 943        int opcode;
 944        int type;
 945};
 946
 947static const struct ideapad_rfk_data ideapad_rfk_data[] = {
 948        { "ideapad_wlan",      CFG_CAP_WIFI_BIT, VPCCMD_W_WIFI, RFKILL_TYPE_WLAN },
 949        { "ideapad_bluetooth", CFG_CAP_BT_BIT,   VPCCMD_W_BT,   RFKILL_TYPE_BLUETOOTH },
 950        { "ideapad_3g",        CFG_CAP_3G_BIT,   VPCCMD_W_3G,   RFKILL_TYPE_WWAN },
 951};
 952
 953static int ideapad_rfk_set(void *data, bool blocked)
 954{
 955        struct ideapad_rfk_priv *priv = data;
 956        int opcode = ideapad_rfk_data[priv->dev].opcode;
 957
 958        return write_ec_cmd(priv->priv->adev->handle, opcode, !blocked);
 959}
 960
 961static const struct rfkill_ops ideapad_rfk_ops = {
 962        .set_block = ideapad_rfk_set,
 963};
 964
 965static void ideapad_sync_rfk_state(struct ideapad_private *priv)
 966{
 967        unsigned long hw_blocked = 0;
 968        int i;
 969
 970        if (priv->features.hw_rfkill_switch) {
 971                if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked))
 972                        return;
 973                hw_blocked = !hw_blocked;
 974        }
 975
 976        for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
 977                if (priv->rfk[i])
 978                        rfkill_set_hw_state(priv->rfk[i], hw_blocked);
 979}
 980
 981static int ideapad_register_rfkill(struct ideapad_private *priv, int dev)
 982{
 983        unsigned long rf_enabled;
 984        int err;
 985
 986        if (no_bt_rfkill && ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH) {
 987                /* Force to enable bluetooth when no_bt_rfkill=1 */
 988                write_ec_cmd(priv->adev->handle, ideapad_rfk_data[dev].opcode, 1);
 989                return 0;
 990        }
 991
 992        priv->rfk_priv[dev].dev = dev;
 993        priv->rfk_priv[dev].priv = priv;
 994
 995        priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev].name,
 996                                      &priv->platform_device->dev,
 997                                      ideapad_rfk_data[dev].type,
 998                                      &ideapad_rfk_ops,
 999                                      &priv->rfk_priv[dev]);
1000        if (!priv->rfk[dev])
1001                return -ENOMEM;
1002
1003        err = read_ec_data(priv->adev->handle, ideapad_rfk_data[dev].opcode - 1, &rf_enabled);
1004        if (err)
1005                rf_enabled = 1;
1006
1007        rfkill_init_sw_state(priv->rfk[dev], !rf_enabled);
1008
1009        err = rfkill_register(priv->rfk[dev]);
1010        if (err)
1011                rfkill_destroy(priv->rfk[dev]);
1012
1013        return err;
1014}
1015
1016static void ideapad_unregister_rfkill(struct ideapad_private *priv, int dev)
1017{
1018        if (!priv->rfk[dev])
1019                return;
1020
1021        rfkill_unregister(priv->rfk[dev]);
1022        rfkill_destroy(priv->rfk[dev]);
1023}
1024
1025/*
1026 * Platform device
1027 */
1028static int ideapad_sysfs_init(struct ideapad_private *priv)
1029{
1030        return device_add_group(&priv->platform_device->dev,
1031                                &ideapad_attribute_group);
1032}
1033
1034static void ideapad_sysfs_exit(struct ideapad_private *priv)
1035{
1036        device_remove_group(&priv->platform_device->dev,
1037                            &ideapad_attribute_group);
1038}
1039
1040/*
1041 * input device
1042 */
1043static const struct key_entry ideapad_keymap[] = {
1044        { KE_KEY,   6, { KEY_SWITCHVIDEOMODE } },
1045        { KE_KEY,   7, { KEY_CAMERA } },
1046        { KE_KEY,   8, { KEY_MICMUTE } },
1047        { KE_KEY,  11, { KEY_F16 } },
1048        { KE_KEY,  13, { KEY_WLAN } },
1049        { KE_KEY,  16, { KEY_PROG1 } },
1050        { KE_KEY,  17, { KEY_PROG2 } },
1051        { KE_KEY,  64, { KEY_PROG3 } },
1052        { KE_KEY,  65, { KEY_PROG4 } },
1053        { KE_KEY,  66, { KEY_TOUCHPAD_OFF } },
1054        { KE_KEY,  67, { KEY_TOUCHPAD_ON } },
1055        { KE_KEY, 128, { KEY_ESC } },
1056        { KE_END },
1057};
1058
1059static int ideapad_input_init(struct ideapad_private *priv)
1060{
1061        struct input_dev *inputdev;
1062        int err;
1063
1064        inputdev = input_allocate_device();
1065        if (!inputdev)
1066                return -ENOMEM;
1067
1068        inputdev->name = "Ideapad extra buttons";
1069        inputdev->phys = "ideapad/input0";
1070        inputdev->id.bustype = BUS_HOST;
1071        inputdev->dev.parent = &priv->platform_device->dev;
1072
1073        err = sparse_keymap_setup(inputdev, ideapad_keymap, NULL);
1074        if (err) {
1075                dev_err(&priv->platform_device->dev,
1076                        "Could not set up input device keymap: %d\n", err);
1077                goto err_free_dev;
1078        }
1079
1080        err = input_register_device(inputdev);
1081        if (err) {
1082                dev_err(&priv->platform_device->dev,
1083                        "Could not register input device: %d\n", err);
1084                goto err_free_dev;
1085        }
1086
1087        priv->inputdev = inputdev;
1088
1089        return 0;
1090
1091err_free_dev:
1092        input_free_device(inputdev);
1093
1094        return err;
1095}
1096
1097static void ideapad_input_exit(struct ideapad_private *priv)
1098{
1099        input_unregister_device(priv->inputdev);
1100        priv->inputdev = NULL;
1101}
1102
1103static void ideapad_input_report(struct ideapad_private *priv,
1104                                 unsigned long scancode)
1105{
1106        sparse_keymap_report_event(priv->inputdev, scancode, 1, true);
1107}
1108
1109static void ideapad_input_novokey(struct ideapad_private *priv)
1110{
1111        unsigned long long_pressed;
1112
1113        if (read_ec_data(priv->adev->handle, VPCCMD_R_NOVO, &long_pressed))
1114                return;
1115
1116        if (long_pressed)
1117                ideapad_input_report(priv, 17);
1118        else
1119                ideapad_input_report(priv, 16);
1120}
1121
1122static void ideapad_check_special_buttons(struct ideapad_private *priv)
1123{
1124        unsigned long bit, value;
1125
1126        if (read_ec_data(priv->adev->handle, VPCCMD_R_SPECIAL_BUTTONS, &value))
1127                return;
1128
1129        for_each_set_bit (bit, &value, 16) {
1130                switch (bit) {
1131                case 6: /* Z570 */
1132                case 0: /* Z580 */
1133                        /* Thermal Management button */
1134                        ideapad_input_report(priv, 65);
1135                        break;
1136                case 1:
1137                        /* OneKey Theater button */
1138                        ideapad_input_report(priv, 64);
1139                        break;
1140                default:
1141                        dev_info(&priv->platform_device->dev,
1142                                 "Unknown special button: %lu\n", bit);
1143                        break;
1144                }
1145        }
1146}
1147
1148/*
1149 * backlight
1150 */
1151static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
1152{
1153        struct ideapad_private *priv = bl_get_data(blightdev);
1154        unsigned long now;
1155        int err;
1156
1157        err = read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
1158        if (err)
1159                return err;
1160
1161        return now;
1162}
1163
1164static int ideapad_backlight_update_status(struct backlight_device *blightdev)
1165{
1166        struct ideapad_private *priv = bl_get_data(blightdev);
1167        int err;
1168
1169        err = write_ec_cmd(priv->adev->handle, VPCCMD_W_BL,
1170                           blightdev->props.brightness);
1171        if (err)
1172                return err;
1173
1174        err = write_ec_cmd(priv->adev->handle, VPCCMD_W_BL_POWER,
1175                           blightdev->props.power != FB_BLANK_POWERDOWN);
1176        if (err)
1177                return err;
1178
1179        return 0;
1180}
1181
1182static const struct backlight_ops ideapad_backlight_ops = {
1183        .get_brightness = ideapad_backlight_get_brightness,
1184        .update_status = ideapad_backlight_update_status,
1185};
1186
1187static int ideapad_backlight_init(struct ideapad_private *priv)
1188{
1189        struct backlight_device *blightdev;
1190        struct backlight_properties props;
1191        unsigned long max, now, power;
1192        int err;
1193
1194        err = read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &max);
1195        if (err)
1196                return err;
1197
1198        err = read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
1199        if (err)
1200                return err;
1201
1202        err = read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power);
1203        if (err)
1204                return err;
1205
1206        memset(&props, 0, sizeof(props));
1207
1208        props.max_brightness = max;
1209        props.type = BACKLIGHT_PLATFORM;
1210
1211        blightdev = backlight_device_register("ideapad",
1212                                              &priv->platform_device->dev,
1213                                              priv,
1214                                              &ideapad_backlight_ops,
1215                                              &props);
1216        if (IS_ERR(blightdev)) {
1217                err = PTR_ERR(blightdev);
1218                dev_err(&priv->platform_device->dev,
1219                        "Could not register backlight device: %d\n", err);
1220                return err;
1221        }
1222
1223        priv->blightdev = blightdev;
1224        blightdev->props.brightness = now;
1225        blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
1226
1227        backlight_update_status(blightdev);
1228
1229        return 0;
1230}
1231
1232static void ideapad_backlight_exit(struct ideapad_private *priv)
1233{
1234        backlight_device_unregister(priv->blightdev);
1235        priv->blightdev = NULL;
1236}
1237
1238static void ideapad_backlight_notify_power(struct ideapad_private *priv)
1239{
1240        struct backlight_device *blightdev = priv->blightdev;
1241        unsigned long power;
1242
1243        if (!blightdev)
1244                return;
1245
1246        if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power))
1247                return;
1248
1249        blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
1250}
1251
1252static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
1253{
1254        unsigned long now;
1255
1256        /* if we control brightness via acpi video driver */
1257        if (!priv->blightdev)
1258                read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
1259        else
1260                backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY);
1261}
1262
1263/*
1264 * keyboard backlight
1265 */
1266static int ideapad_kbd_bl_brightness_get(struct ideapad_private *priv)
1267{
1268        unsigned long hals;
1269        int err;
1270
1271        err = eval_hals(priv->adev->handle, &hals);
1272        if (err)
1273                return err;
1274
1275        return !!test_bit(HALS_KBD_BL_STATE_BIT, &hals);
1276}
1277
1278static enum led_brightness ideapad_kbd_bl_led_cdev_brightness_get(struct led_classdev *led_cdev)
1279{
1280        struct ideapad_private *priv = container_of(led_cdev, struct ideapad_private, kbd_bl.led);
1281
1282        return ideapad_kbd_bl_brightness_get(priv);
1283}
1284
1285static int ideapad_kbd_bl_brightness_set(struct ideapad_private *priv, unsigned int brightness)
1286{
1287        int err = exec_sals(priv->adev->handle, brightness ? SALS_KBD_BL_ON : SALS_KBD_BL_OFF);
1288
1289        if (err)
1290                return err;
1291
1292        priv->kbd_bl.last_brightness = brightness;
1293
1294        return 0;
1295}
1296
1297static int ideapad_kbd_bl_led_cdev_brightness_set(struct led_classdev *led_cdev,
1298                                                  enum led_brightness brightness)
1299{
1300        struct ideapad_private *priv = container_of(led_cdev, struct ideapad_private, kbd_bl.led);
1301
1302        return ideapad_kbd_bl_brightness_set(priv, brightness);
1303}
1304
1305static void ideapad_kbd_bl_notify(struct ideapad_private *priv)
1306{
1307        int brightness;
1308
1309        if (!priv->kbd_bl.initialized)
1310                return;
1311
1312        brightness = ideapad_kbd_bl_brightness_get(priv);
1313        if (brightness < 0)
1314                return;
1315
1316        if (brightness == priv->kbd_bl.last_brightness)
1317                return;
1318
1319        priv->kbd_bl.last_brightness = brightness;
1320
1321        led_classdev_notify_brightness_hw_changed(&priv->kbd_bl.led, brightness);
1322}
1323
1324static int ideapad_kbd_bl_init(struct ideapad_private *priv)
1325{
1326        int brightness, err;
1327
1328        if (!priv->features.kbd_bl)
1329                return -ENODEV;
1330
1331        if (WARN_ON(priv->kbd_bl.initialized))
1332                return -EEXIST;
1333
1334        brightness = ideapad_kbd_bl_brightness_get(priv);
1335        if (brightness < 0)
1336                return brightness;
1337
1338        priv->kbd_bl.last_brightness = brightness;
1339
1340        priv->kbd_bl.led.name                    = "platform::" LED_FUNCTION_KBD_BACKLIGHT;
1341        priv->kbd_bl.led.max_brightness          = 1;
1342        priv->kbd_bl.led.brightness_get          = ideapad_kbd_bl_led_cdev_brightness_get;
1343        priv->kbd_bl.led.brightness_set_blocking = ideapad_kbd_bl_led_cdev_brightness_set;
1344        priv->kbd_bl.led.flags                   = LED_BRIGHT_HW_CHANGED;
1345
1346        err = led_classdev_register(&priv->platform_device->dev, &priv->kbd_bl.led);
1347        if (err)
1348                return err;
1349
1350        priv->kbd_bl.initialized = true;
1351
1352        return 0;
1353}
1354
1355static void ideapad_kbd_bl_exit(struct ideapad_private *priv)
1356{
1357        if (!priv->kbd_bl.initialized)
1358                return;
1359
1360        priv->kbd_bl.initialized = false;
1361
1362        led_classdev_unregister(&priv->kbd_bl.led);
1363}
1364
1365/*
1366 * module init/exit
1367 */
1368static void ideapad_sync_touchpad_state(struct ideapad_private *priv)
1369{
1370        unsigned long value;
1371
1372        if (!priv->features.touchpad_ctrl_via_ec)
1373                return;
1374
1375        /* Without reading from EC touchpad LED doesn't switch state */
1376        if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value)) {
1377                unsigned char param;
1378                /*
1379                 * Some IdeaPads don't really turn off touchpad - they only
1380                 * switch the LED state. We (de)activate KBC AUX port to turn
1381                 * touchpad off and on. We send KEY_TOUCHPAD_OFF and
1382                 * KEY_TOUCHPAD_ON to not to get out of sync with LED
1383                 */
1384                i8042_command(&param, value ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE);
1385                ideapad_input_report(priv, value ? 67 : 66);
1386                sysfs_notify(&priv->platform_device->dev.kobj, NULL, "touchpad");
1387        }
1388}
1389
1390static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
1391{
1392        struct ideapad_private *priv = data;
1393        unsigned long vpc1, vpc2, bit;
1394
1395        if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
1396                return;
1397
1398        if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
1399                return;
1400
1401        vpc1 = (vpc2 << 8) | vpc1;
1402
1403        for_each_set_bit (bit, &vpc1, 16) {
1404                switch (bit) {
1405                case 13:
1406                case 11:
1407                case 8:
1408                case 7:
1409                case 6:
1410                        ideapad_input_report(priv, bit);
1411                        break;
1412                case 10:
1413                        /*
1414                         * This event gets send on a Yoga 300-11IBR when the EC
1415                         * believes that the device has changed between laptop/
1416                         * tent/stand/tablet mode. The EC relies on getting
1417                         * angle info from 2 accelerometers through a special
1418                         * windows service calling a DSM on the DUAL250E ACPI-
1419                         * device. Linux does not do this, making the laptop/
1420                         * tent/stand/tablet mode info unreliable, so we simply
1421                         * ignore these events.
1422                         */
1423                        break;
1424                case 9:
1425                        ideapad_sync_rfk_state(priv);
1426                        break;
1427                case 5:
1428                        ideapad_sync_touchpad_state(priv);
1429                        break;
1430                case 4:
1431                        ideapad_backlight_notify_brightness(priv);
1432                        break;
1433                case 3:
1434                        ideapad_input_novokey(priv);
1435                        break;
1436                case 2:
1437                        ideapad_backlight_notify_power(priv);
1438                        break;
1439                case 1:
1440                        /*
1441                         * Some IdeaPads report event 1 every ~20
1442                         * seconds while on battery power; some
1443                         * report this when changing to/from tablet
1444                         * mode; some report this when the keyboard
1445                         * backlight has changed.
1446                         */
1447                        ideapad_kbd_bl_notify(priv);
1448                        break;
1449                case 0:
1450                        ideapad_check_special_buttons(priv);
1451                        break;
1452                default:
1453                        dev_info(&priv->platform_device->dev,
1454                                 "Unknown event: %lu\n", bit);
1455                }
1456        }
1457}
1458
1459#if IS_ENABLED(CONFIG_ACPI_WMI)
1460static void ideapad_wmi_notify(u32 value, void *context)
1461{
1462        struct ideapad_private *priv = context;
1463        unsigned long result;
1464
1465        switch (value) {
1466        case 128:
1467                ideapad_input_report(priv, value);
1468                break;
1469        case 208:
1470                if (!eval_hals(priv->adev->handle, &result)) {
1471                        bool state = test_bit(HALS_FNLOCK_STATE_BIT, &result);
1472
1473                        exec_sals(priv->adev->handle, state ? SALS_FNLOCK_ON : SALS_FNLOCK_OFF);
1474                }
1475                break;
1476        default:
1477                dev_info(&priv->platform_device->dev,
1478                         "Unknown WMI event: %u\n", value);
1479        }
1480}
1481#endif
1482
1483/*
1484 * Some ideapads have a hardware rfkill switch, but most do not have one.
1485 * Reading VPCCMD_R_RF always results in 0 on models without a hardware rfkill,
1486 * switch causing ideapad_laptop to wrongly report all radios as hw-blocked.
1487 * There used to be a long list of DMI ids for models without a hw rfkill
1488 * switch here, but that resulted in playing whack a mole.
1489 * More importantly wrongly reporting the wifi radio as hw-blocked, results in
1490 * non working wifi. Whereas not reporting it hw-blocked, when it actually is
1491 * hw-blocked results in an empty SSID list, which is a much more benign
1492 * failure mode.
1493 * So the default now is the much safer option of assuming there is no
1494 * hardware rfkill switch. This default also actually matches most hardware,
1495 * since having a hw rfkill switch is quite rare on modern hardware, so this
1496 * also leads to a much shorter list.
1497 */
1498static const struct dmi_system_id hw_rfkill_list[] = {
1499        {}
1500};
1501
1502static void ideapad_check_features(struct ideapad_private *priv)
1503{
1504        acpi_handle handle = priv->adev->handle;
1505        unsigned long val;
1506
1507        priv->features.hw_rfkill_switch = dmi_check_system(hw_rfkill_list);
1508
1509        /* Most ideapads with ELAN0634 touchpad don't use EC touchpad switch */
1510        priv->features.touchpad_ctrl_via_ec = !acpi_dev_present("ELAN0634", NULL, -1);
1511
1512        if (!read_ec_data(handle, VPCCMD_R_FAN, &val))
1513                priv->features.fan_mode = true;
1514
1515        if (acpi_has_method(handle, "GBMD") && acpi_has_method(handle, "SBMC"))
1516                priv->features.conservation_mode = true;
1517
1518        if (acpi_has_method(handle, "DYTC"))
1519                priv->features.dytc = true;
1520
1521        if (acpi_has_method(handle, "HALS") && acpi_has_method(handle, "SALS")) {
1522                if (!eval_hals(handle, &val)) {
1523                        if (test_bit(HALS_FNLOCK_SUPPORT_BIT, &val))
1524                                priv->features.fn_lock = true;
1525
1526                        if (test_bit(HALS_KBD_BL_SUPPORT_BIT, &val))
1527                                priv->features.kbd_bl = true;
1528
1529                        if (test_bit(HALS_USB_CHARGING_SUPPORT_BIT, &val))
1530                                priv->features.usb_charging = true;
1531                }
1532        }
1533}
1534
1535static int ideapad_acpi_add(struct platform_device *pdev)
1536{
1537        struct ideapad_private *priv;
1538        struct acpi_device *adev;
1539        acpi_status status;
1540        unsigned long cfg;
1541        int err, i;
1542
1543        err = acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev);
1544        if (err)
1545                return -ENODEV;
1546
1547        if (eval_int(adev->handle, "_CFG", &cfg))
1548                return -ENODEV;
1549
1550        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
1551        if (!priv)
1552                return -ENOMEM;
1553
1554        dev_set_drvdata(&pdev->dev, priv);
1555
1556        priv->cfg = cfg;
1557        priv->adev = adev;
1558        priv->platform_device = pdev;
1559
1560        ideapad_check_features(priv);
1561
1562        err = ideapad_sysfs_init(priv);
1563        if (err)
1564                return err;
1565
1566        ideapad_debugfs_init(priv);
1567
1568        err = ideapad_input_init(priv);
1569        if (err)
1570                goto input_failed;
1571
1572        err = ideapad_kbd_bl_init(priv);
1573        if (err) {
1574                if (err != -ENODEV)
1575                        dev_warn(&pdev->dev, "Could not set up keyboard backlight LED: %d\n", err);
1576                else
1577                        dev_info(&pdev->dev, "Keyboard backlight control not available\n");
1578        }
1579
1580        /*
1581         * On some models without a hw-switch (the yoga 2 13 at least)
1582         * VPCCMD_W_RF must be explicitly set to 1 for the wifi to work.
1583         */
1584        if (!priv->features.hw_rfkill_switch)
1585                write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1);
1586
1587        /* The same for Touchpad */
1588        if (!priv->features.touchpad_ctrl_via_ec)
1589                write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, 1);
1590
1591        for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
1592                if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
1593                        ideapad_register_rfkill(priv, i);
1594
1595        ideapad_sync_rfk_state(priv);
1596        ideapad_sync_touchpad_state(priv);
1597
1598        err = ideapad_dytc_profile_init(priv);
1599        if (err) {
1600                if (err != -ENODEV)
1601                        dev_warn(&pdev->dev, "Could not set up DYTC interface: %d\n", err);
1602                else
1603                        dev_info(&pdev->dev, "DYTC interface is not available\n");
1604        }
1605
1606        if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
1607                err = ideapad_backlight_init(priv);
1608                if (err && err != -ENODEV)
1609                        goto backlight_failed;
1610        }
1611
1612        status = acpi_install_notify_handler(adev->handle,
1613                                             ACPI_DEVICE_NOTIFY,
1614                                             ideapad_acpi_notify, priv);
1615        if (ACPI_FAILURE(status)) {
1616                err = -EIO;
1617                goto notification_failed;
1618        }
1619
1620#if IS_ENABLED(CONFIG_ACPI_WMI)
1621        for (i = 0; i < ARRAY_SIZE(ideapad_wmi_fnesc_events); i++) {
1622                status = wmi_install_notify_handler(ideapad_wmi_fnesc_events[i],
1623                                                    ideapad_wmi_notify, priv);
1624                if (ACPI_SUCCESS(status)) {
1625                        priv->fnesc_guid = ideapad_wmi_fnesc_events[i];
1626                        break;
1627                }
1628        }
1629
1630        if (ACPI_FAILURE(status) && status != AE_NOT_EXIST) {
1631                err = -EIO;
1632                goto notification_failed_wmi;
1633        }
1634#endif
1635
1636        return 0;
1637
1638#if IS_ENABLED(CONFIG_ACPI_WMI)
1639notification_failed_wmi:
1640        acpi_remove_notify_handler(priv->adev->handle,
1641                                   ACPI_DEVICE_NOTIFY,
1642                                   ideapad_acpi_notify);
1643#endif
1644
1645notification_failed:
1646        ideapad_backlight_exit(priv);
1647
1648backlight_failed:
1649        ideapad_dytc_profile_exit(priv);
1650
1651        for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
1652                ideapad_unregister_rfkill(priv, i);
1653
1654        ideapad_kbd_bl_exit(priv);
1655        ideapad_input_exit(priv);
1656
1657input_failed:
1658        ideapad_debugfs_exit(priv);
1659        ideapad_sysfs_exit(priv);
1660
1661        return err;
1662}
1663
1664static int ideapad_acpi_remove(struct platform_device *pdev)
1665{
1666        struct ideapad_private *priv = dev_get_drvdata(&pdev->dev);
1667        int i;
1668
1669#if IS_ENABLED(CONFIG_ACPI_WMI)
1670        if (priv->fnesc_guid)
1671                wmi_remove_notify_handler(priv->fnesc_guid);
1672#endif
1673
1674        acpi_remove_notify_handler(priv->adev->handle,
1675                                   ACPI_DEVICE_NOTIFY,
1676                                   ideapad_acpi_notify);
1677
1678        ideapad_backlight_exit(priv);
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        ideapad_debugfs_exit(priv);
1687        ideapad_sysfs_exit(priv);
1688
1689        return 0;
1690}
1691
1692#ifdef CONFIG_PM_SLEEP
1693static int ideapad_acpi_resume(struct device *dev)
1694{
1695        struct ideapad_private *priv = dev_get_drvdata(dev);
1696
1697        ideapad_sync_rfk_state(priv);
1698        ideapad_sync_touchpad_state(priv);
1699
1700        if (priv->dytc)
1701                dytc_profile_refresh(priv);
1702
1703        return 0;
1704}
1705#endif
1706static SIMPLE_DEV_PM_OPS(ideapad_pm, NULL, ideapad_acpi_resume);
1707
1708static const struct acpi_device_id ideapad_device_ids[] = {
1709        {"VPC2004", 0},
1710        {"", 0},
1711};
1712MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
1713
1714static struct platform_driver ideapad_acpi_driver = {
1715        .probe = ideapad_acpi_add,
1716        .remove = ideapad_acpi_remove,
1717        .driver = {
1718                .name   = "ideapad_acpi",
1719                .pm     = &ideapad_pm,
1720                .acpi_match_table = ACPI_PTR(ideapad_device_ids),
1721        },
1722};
1723
1724module_platform_driver(ideapad_acpi_driver);
1725
1726MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
1727MODULE_DESCRIPTION("IdeaPad ACPI Extras");
1728MODULE_LICENSE("GPL");
1729