linux/drivers/platform/x86/panasonic-laptop.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  Panasonic HotKey and LCD brightness control driver
   4 *  (C) 2004 Hiroshi Miura <miura@da-cha.org>
   5 *  (C) 2004 NTT DATA Intellilink Co. http://www.intellilink.co.jp/
   6 *  (C) YOKOTA Hiroshi <yokota (at) netlab. is. tsukuba. ac. jp>
   7 *  (C) 2004 David Bronaugh <dbronaugh>
   8 *  (C) 2006-2008 Harald Welte <laforge@gnumonks.org>
   9 *
  10 *  derived from toshiba_acpi.c, Copyright (C) 2002-2004 John Belmonte
  11 *
  12 *---------------------------------------------------------------------------
  13 *
  14 * ChangeLog:
  15 *      Aug.18, 2020    Kenneth Chan <kenneth.t.chan@gmail.com>
  16 *              -v0.98  add platform devices for firmware brightness registers
  17 *                      add support for battery charging threshold (eco mode)
  18 *                      resolve hotkey double trigger
  19 *                      add write support to mute
  20 *                      fix sticky_key init bug
  21 *                      fix naming of platform files for consistency with other
  22 *                      modules
  23 *                      split MODULE_AUTHOR() by one author per macro call
  24 *                      replace ACPI prints with pr_*() macros
  25 *              -v0.97  add support for cdpower hardware switch
  26 *              -v0.96  merge Lucina's enhancement
  27 *                      Jan.13, 2009 Martin Lucina <mato@kotelna.sk>
  28 *                              - add support for optical driver power in
  29 *                                Y and W series
  30 *
  31 *      Sep.23, 2008    Harald Welte <laforge@gnumonks.org>
  32 *              -v0.95  rename driver from drivers/acpi/pcc_acpi.c to
  33 *                      drivers/misc/panasonic-laptop.c
  34 *
  35 *      Jul.04, 2008    Harald Welte <laforge@gnumonks.org>
  36 *              -v0.94  replace /proc interface with device attributes
  37 *                      support {set,get}keycode on th input device
  38 *
  39 *      Jun.27, 2008    Harald Welte <laforge@gnumonks.org>
  40 *              -v0.92  merge with 2.6.26-rc6 input API changes
  41 *                      remove broken <= 2.6.15 kernel support
  42 *                      resolve all compiler warnings
  43 *                      various coding style fixes (checkpatch.pl)
  44 *                      add support for backlight api
  45 *                      major code restructuring
  46 *
  47 *      Dac.28, 2007    Harald Welte <laforge@gnumonks.org>
  48 *              -v0.91  merge with 2.6.24-rc6 ACPI changes
  49 *
  50 *      Nov.04, 2006    Hiroshi Miura <miura@da-cha.org>
  51 *              -v0.9   remove warning about section reference.
  52 *                      remove acpi_os_free
  53 *                      add /proc/acpi/pcc/brightness interface for HAL access
  54 *                      merge dbronaugh's enhancement
  55 *                      Aug.17, 2004 David Bronaugh (dbronaugh)
  56 *                              - Added screen brightness setting interface
  57 *                                Thanks to FreeBSD crew (acpi_panasonic.c)
  58 *                                for the ideas I needed to accomplish it
  59 *
  60 *      May.29, 2006    Hiroshi Miura <miura@da-cha.org>
  61 *              -v0.8.4 follow to change keyinput structure
  62 *                      thanks Fabian Yamaguchi <fabs@cs.tu-berlin.de>,
  63 *                      Jacob Bower <jacob.bower@ic.ac.uk> and
  64 *                      Hiroshi Yokota for providing solutions.
  65 *
  66 *      Oct.02, 2004    Hiroshi Miura <miura@da-cha.org>
  67 *              -v0.8.2 merge code of YOKOTA Hiroshi
  68 *                                      <yokota@netlab.is.tsukuba.ac.jp>.
  69 *                      Add sticky key mode interface.
  70 *                      Refactoring acpi_pcc_generate_keyinput().
  71 *
  72 *      Sep.15, 2004    Hiroshi Miura <miura@da-cha.org>
  73 *              -v0.8   Generate key input event on input subsystem.
  74 *                      This is based on yet another driver written by
  75 *                                                      Ryuta Nakanishi.
  76 *
  77 *      Sep.10, 2004    Hiroshi Miura <miura@da-cha.org>
  78 *              -v0.7   Change proc interface functions using seq_file
  79 *                      facility as same as other ACPI drivers.
  80 *
  81 *      Aug.28, 2004    Hiroshi Miura <miura@da-cha.org>
  82 *              -v0.6.4 Fix a silly error with status checking
  83 *
  84 *      Aug.25, 2004    Hiroshi Miura <miura@da-cha.org>
  85 *              -v0.6.3 replace read_acpi_int by standard function
  86 *                                                      acpi_evaluate_integer
  87 *                      some clean up and make smart copyright notice.
  88 *                      fix return value of pcc_acpi_get_key()
  89 *                      fix checking return value of acpi_bus_register_driver()
  90 *
  91 *      Aug.22, 2004    David Bronaugh <dbronaugh@linuxboxen.org>
  92 *              -v0.6.2 Add check on ACPI data (num_sifr)
  93 *                      Coding style cleanups, better error messages/handling
  94 *                      Fixed an off-by-one error in memory allocation
  95 *
  96 *      Aug.21, 2004    David Bronaugh <dbronaugh@linuxboxen.org>
  97 *              -v0.6.1 Fix a silly error with status checking
  98 *
  99 *      Aug.20, 2004    David Bronaugh <dbronaugh@linuxboxen.org>
 100 *              - v0.6  Correct brightness controls to reflect reality
 101 *                      based on information gleaned by Hiroshi Miura
 102 *                      and discussions with Hiroshi Miura
 103 *
 104 *      Aug.10, 2004    Hiroshi Miura <miura@da-cha.org>
 105 *              - v0.5  support LCD brightness control
 106 *                      based on the disclosed information by MEI.
 107 *
 108 *      Jul.25, 2004    Hiroshi Miura <miura@da-cha.org>
 109 *              - v0.4  first post version
 110 *                      add function to retrive SIFR
 111 *
 112 *      Jul.24, 2004    Hiroshi Miura <miura@da-cha.org>
 113 *              - v0.3  get proper status of hotkey
 114 *
 115 *      Jul.22, 2004    Hiroshi Miura <miura@da-cha.org>
 116 *              - v0.2  add HotKey handler
 117 *
 118 *      Jul.17, 2004    Hiroshi Miura <miura@da-cha.org>
 119 *              - v0.1  start from toshiba_acpi driver written by John Belmonte
 120 */
 121
 122#include <linux/kernel.h>
 123#include <linux/module.h>
 124#include <linux/init.h>
 125#include <linux/types.h>
 126#include <linux/backlight.h>
 127#include <linux/ctype.h>
 128#include <linux/seq_file.h>
 129#include <linux/uaccess.h>
 130#include <linux/slab.h>
 131#include <linux/acpi.h>
 132#include <linux/input.h>
 133#include <linux/input/sparse-keymap.h>
 134#include <linux/platform_device.h>
 135
 136
 137MODULE_AUTHOR("Hiroshi Miura <miura@da-cha.org>");
 138MODULE_AUTHOR("David Bronaugh <dbronaugh@linuxboxen.org>");
 139MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
 140MODULE_AUTHOR("Martin Lucina <mato@kotelna.sk>");
 141MODULE_AUTHOR("Kenneth Chan <kenneth.t.chan@gmail.com>");
 142MODULE_DESCRIPTION("ACPI HotKey driver for Panasonic Let's Note laptops");
 143MODULE_LICENSE("GPL");
 144
 145#define LOGPREFIX "pcc_acpi: "
 146
 147/* Define ACPI PATHs */
 148/* Lets note hotkeys */
 149#define METHOD_HKEY_QUERY       "HINF"
 150#define METHOD_HKEY_SQTY        "SQTY"
 151#define METHOD_HKEY_SINF        "SINF"
 152#define METHOD_HKEY_SSET        "SSET"
 153#define METHOD_ECWR             "\\_SB.ECWR"
 154#define HKEY_NOTIFY             0x80
 155#define ECO_MODE_OFF            0x00
 156#define ECO_MODE_ON             0x80
 157
 158#define ACPI_PCC_DRIVER_NAME    "Panasonic Laptop Support"
 159#define ACPI_PCC_DEVICE_NAME    "Hotkey"
 160#define ACPI_PCC_CLASS          "pcc"
 161
 162#define ACPI_PCC_INPUT_PHYS     "panasonic/hkey0"
 163
 164/* LCD_TYPEs: 0 = Normal, 1 = Semi-transparent
 165   ECO_MODEs: 0x03 = off, 0x83 = on
 166*/
 167enum SINF_BITS { SINF_NUM_BATTERIES = 0,
 168                 SINF_LCD_TYPE,
 169                 SINF_AC_MAX_BRIGHT,
 170                 SINF_AC_MIN_BRIGHT,
 171                 SINF_AC_CUR_BRIGHT,
 172                 SINF_DC_MAX_BRIGHT,
 173                 SINF_DC_MIN_BRIGHT,
 174                 SINF_DC_CUR_BRIGHT,
 175                 SINF_MUTE,
 176                 SINF_RESERVED,
 177                 SINF_ECO_MODE = 0x0A,
 178                 SINF_CUR_BRIGHT = 0x0D,
 179                 SINF_STICKY_KEY = 0x80,
 180        };
 181/* R1 handles SINF_AC_CUR_BRIGHT as SINF_CUR_BRIGHT, doesn't know AC state */
 182
 183static int acpi_pcc_hotkey_add(struct acpi_device *device);
 184static int acpi_pcc_hotkey_remove(struct acpi_device *device);
 185static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event);
 186
 187static const struct acpi_device_id pcc_device_ids[] = {
 188        { "MAT0012", 0},
 189        { "MAT0013", 0},
 190        { "MAT0018", 0},
 191        { "MAT0019", 0},
 192        { "", 0},
 193};
 194MODULE_DEVICE_TABLE(acpi, pcc_device_ids);
 195
 196#ifdef CONFIG_PM_SLEEP
 197static int acpi_pcc_hotkey_resume(struct device *dev);
 198#endif
 199static SIMPLE_DEV_PM_OPS(acpi_pcc_hotkey_pm, NULL, acpi_pcc_hotkey_resume);
 200
 201static struct acpi_driver acpi_pcc_driver = {
 202        .name =         ACPI_PCC_DRIVER_NAME,
 203        .class =        ACPI_PCC_CLASS,
 204        .ids =          pcc_device_ids,
 205        .ops =          {
 206                                .add =          acpi_pcc_hotkey_add,
 207                                .remove =       acpi_pcc_hotkey_remove,
 208                                .notify =       acpi_pcc_hotkey_notify,
 209                        },
 210        .drv.pm =       &acpi_pcc_hotkey_pm,
 211};
 212
 213static const struct key_entry panasonic_keymap[] = {
 214        { KE_KEY, 0, { KEY_RESERVED } },
 215        { KE_KEY, 1, { KEY_BRIGHTNESSDOWN } },
 216        { KE_KEY, 2, { KEY_BRIGHTNESSUP } },
 217        { KE_KEY, 3, { KEY_DISPLAYTOGGLE } },
 218        { KE_KEY, 4, { KEY_MUTE } },
 219        { KE_KEY, 5, { KEY_VOLUMEDOWN } },
 220        { KE_KEY, 6, { KEY_VOLUMEUP } },
 221        { KE_KEY, 7, { KEY_SLEEP } },
 222        { KE_KEY, 8, { KEY_PROG1 } }, /* Change CPU boost */
 223        { KE_KEY, 9, { KEY_BATTERY } },
 224        { KE_KEY, 10, { KEY_SUSPEND } },
 225        { KE_END, 0 }
 226};
 227
 228struct pcc_acpi {
 229        acpi_handle             handle;
 230        unsigned long           num_sifr;
 231        int                     sticky_key;
 232        int                     eco_mode;
 233        int                     mute;
 234        int                     ac_brightness;
 235        int                     dc_brightness;
 236        int                     current_brightness;
 237        u32                     *sinf;
 238        struct acpi_device      *device;
 239        struct input_dev        *input_dev;
 240        struct backlight_device *backlight;
 241        struct platform_device  *platform;
 242};
 243
 244/* method access functions */
 245static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val)
 246{
 247        union acpi_object in_objs[] = {
 248                { .integer.type  = ACPI_TYPE_INTEGER,
 249                  .integer.value = func, },
 250                { .integer.type  = ACPI_TYPE_INTEGER,
 251                  .integer.value = val, },
 252        };
 253        struct acpi_object_list params = {
 254                .count   = ARRAY_SIZE(in_objs),
 255                .pointer = in_objs,
 256        };
 257        acpi_status status = AE_OK;
 258
 259        status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SSET,
 260                                      &params, NULL);
 261
 262        return (status == AE_OK) ? 0 : -EIO;
 263}
 264
 265static inline int acpi_pcc_get_sqty(struct acpi_device *device)
 266{
 267        unsigned long long s;
 268        acpi_status status;
 269
 270        status = acpi_evaluate_integer(device->handle, METHOD_HKEY_SQTY,
 271                                       NULL, &s);
 272        if (ACPI_SUCCESS(status))
 273                return s;
 274        else {
 275                pr_err("evaluation error HKEY.SQTY\n");
 276                return -EINVAL;
 277        }
 278}
 279
 280static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc)
 281{
 282        acpi_status status;
 283        struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
 284        union acpi_object *hkey = NULL;
 285        int i;
 286
 287        status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SINF, NULL,
 288                                      &buffer);
 289        if (ACPI_FAILURE(status)) {
 290                pr_err("evaluation error HKEY.SINF\n");
 291                return 0;
 292        }
 293
 294        hkey = buffer.pointer;
 295        if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) {
 296                pr_err("Invalid HKEY.SINF\n");
 297                status = AE_ERROR;
 298                goto end;
 299        }
 300
 301        if (pcc->num_sifr < hkey->package.count) {
 302                pr_err("SQTY reports bad SINF length\n");
 303                status = AE_ERROR;
 304                goto end;
 305        }
 306
 307        for (i = 0; i < hkey->package.count; i++) {
 308                union acpi_object *element = &(hkey->package.elements[i]);
 309                if (likely(element->type == ACPI_TYPE_INTEGER)) {
 310                        pcc->sinf[i] = element->integer.value;
 311                } else
 312                        pr_err("Invalid HKEY.SINF data\n");
 313        }
 314        pcc->sinf[hkey->package.count] = -1;
 315
 316end:
 317        kfree(buffer.pointer);
 318        return status == AE_OK;
 319}
 320
 321/* backlight API interface functions */
 322
 323/* This driver currently treats AC and DC brightness identical,
 324 * since we don't need to invent an interface to the core ACPI
 325 * logic to receive events in case a power supply is plugged in
 326 * or removed */
 327
 328static int bl_get(struct backlight_device *bd)
 329{
 330        struct pcc_acpi *pcc = bl_get_data(bd);
 331
 332        if (!acpi_pcc_retrieve_biosdata(pcc))
 333                return -EIO;
 334
 335        return pcc->sinf[SINF_AC_CUR_BRIGHT];
 336}
 337
 338static int bl_set_status(struct backlight_device *bd)
 339{
 340        struct pcc_acpi *pcc = bl_get_data(bd);
 341        int bright = bd->props.brightness;
 342        int rc;
 343
 344        if (!acpi_pcc_retrieve_biosdata(pcc))
 345                return -EIO;
 346
 347        if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT])
 348                bright = pcc->sinf[SINF_AC_MIN_BRIGHT];
 349
 350        if (bright < pcc->sinf[SINF_DC_MIN_BRIGHT])
 351                bright = pcc->sinf[SINF_DC_MIN_BRIGHT];
 352
 353        if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT] ||
 354            bright > pcc->sinf[SINF_AC_MAX_BRIGHT])
 355                return -EINVAL;
 356
 357        rc = acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, bright);
 358        if (rc < 0)
 359                return rc;
 360
 361        return acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, bright);
 362}
 363
 364static const struct backlight_ops pcc_backlight_ops = {
 365        .get_brightness = bl_get,
 366        .update_status  = bl_set_status,
 367};
 368
 369
 370/* returns ACPI_SUCCESS if methods to control optical drive are present */
 371
 372static acpi_status check_optd_present(void)
 373{
 374        acpi_status status = AE_OK;
 375        acpi_handle handle;
 376
 377        status = acpi_get_handle(NULL, "\\_SB.STAT", &handle);
 378        if (ACPI_FAILURE(status))
 379                goto out;
 380        status = acpi_get_handle(NULL, "\\_SB.FBAY", &handle);
 381        if (ACPI_FAILURE(status))
 382                goto out;
 383        status = acpi_get_handle(NULL, "\\_SB.CDDI", &handle);
 384        if (ACPI_FAILURE(status))
 385                goto out;
 386
 387out:
 388        return status;
 389}
 390
 391/* get optical driver power state */
 392
 393static int get_optd_power_state(void)
 394{
 395        acpi_status status;
 396        unsigned long long state;
 397        int result;
 398
 399        status = acpi_evaluate_integer(NULL, "\\_SB.STAT", NULL, &state);
 400        if (ACPI_FAILURE(status)) {
 401                pr_err("evaluation error _SB.STAT\n");
 402                result = -EIO;
 403                goto out;
 404        }
 405        switch (state) {
 406        case 0: /* power off */
 407                result = 0;
 408                break;
 409        case 0x0f: /* power on */
 410                result = 1;
 411                break;
 412        default:
 413                result = -EIO;
 414                break;
 415        }
 416
 417out:
 418        return result;
 419}
 420
 421/* set optical drive power state */
 422
 423static int set_optd_power_state(int new_state)
 424{
 425        int result;
 426        acpi_status status;
 427
 428        result = get_optd_power_state();
 429        if (result < 0)
 430                goto out;
 431        if (new_state == result)
 432                goto out;
 433
 434        switch (new_state) {
 435        case 0: /* power off */
 436                /* Call CDDR instead, since they both call the same method
 437                 * while CDDI takes 1 arg and we are not quite sure what it is.
 438                 */
 439                status = acpi_evaluate_object(NULL, "\\_SB.CDDR", NULL, NULL);
 440                if (ACPI_FAILURE(status)) {
 441                        pr_err("evaluation error _SB.CDDR\n");
 442                        result = -EIO;
 443                }
 444                break;
 445        case 1: /* power on */
 446                status = acpi_evaluate_object(NULL, "\\_SB.FBAY", NULL, NULL);
 447                if (ACPI_FAILURE(status)) {
 448                        pr_err("evaluation error _SB.FBAY\n");
 449                        result = -EIO;
 450                }
 451                break;
 452        default:
 453                result = -EINVAL;
 454                break;
 455        }
 456
 457out:
 458        return result;
 459}
 460
 461
 462/* sysfs user interface functions */
 463
 464static ssize_t numbatt_show(struct device *dev, struct device_attribute *attr,
 465                            char *buf)
 466{
 467        struct acpi_device *acpi = to_acpi_device(dev);
 468        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 469
 470        if (!acpi_pcc_retrieve_biosdata(pcc))
 471                return -EIO;
 472
 473        return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]);
 474}
 475
 476static ssize_t lcdtype_show(struct device *dev, struct device_attribute *attr,
 477                            char *buf)
 478{
 479        struct acpi_device *acpi = to_acpi_device(dev);
 480        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 481
 482        if (!acpi_pcc_retrieve_biosdata(pcc))
 483                return -EIO;
 484
 485        return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_LCD_TYPE]);
 486}
 487
 488static ssize_t mute_show(struct device *dev, struct device_attribute *attr,
 489                         char *buf)
 490{
 491        struct acpi_device *acpi = to_acpi_device(dev);
 492        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 493
 494        if (!acpi_pcc_retrieve_biosdata(pcc))
 495                return -EIO;
 496
 497        return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_MUTE]);
 498}
 499
 500static ssize_t mute_store(struct device *dev, struct device_attribute *attr,
 501                          const char *buf, size_t count)
 502{
 503        struct acpi_device *acpi = to_acpi_device(dev);
 504        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 505        int err, val;
 506
 507        err = kstrtoint(buf, 0, &val);
 508        if (err)
 509                return err;
 510        if (val == 0 || val == 1) {
 511                acpi_pcc_write_sset(pcc, SINF_MUTE, val);
 512                pcc->mute = val;
 513        }
 514
 515        return count;
 516}
 517
 518static ssize_t sticky_key_show(struct device *dev, struct device_attribute *attr,
 519                           char *buf)
 520{
 521        struct acpi_device *acpi = to_acpi_device(dev);
 522        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 523
 524        if (!acpi_pcc_retrieve_biosdata(pcc))
 525                return -EIO;
 526
 527        return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sticky_key);
 528}
 529
 530static ssize_t sticky_key_store(struct device *dev, struct device_attribute *attr,
 531                          const char *buf, size_t count)
 532{
 533        struct acpi_device *acpi = to_acpi_device(dev);
 534        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 535        int err, val;
 536
 537        err = kstrtoint(buf, 0, &val);
 538        if (err)
 539                return err;
 540        if (val == 0 || val == 1) {
 541                acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, val);
 542                pcc->sticky_key = val;
 543        }
 544
 545        return count;
 546}
 547
 548static ssize_t eco_mode_show(struct device *dev, struct device_attribute *attr,
 549                                char *buf)
 550{
 551        struct acpi_device *acpi = to_acpi_device(dev);
 552        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 553        int result;
 554
 555        if (!acpi_pcc_retrieve_biosdata(pcc))
 556                return -EIO;
 557
 558        switch (pcc->sinf[SINF_ECO_MODE]) {
 559        case (ECO_MODE_OFF + 3):
 560                result = 0;
 561                break;
 562        case (ECO_MODE_ON + 3):
 563                result = 1;
 564                break;
 565        default:
 566                result = -EIO;
 567                break;
 568        }
 569        return snprintf(buf, PAGE_SIZE, "%u\n", result);
 570}
 571
 572static ssize_t eco_mode_store(struct device *dev, struct device_attribute *attr,
 573                          const char *buf, size_t count)
 574{
 575        struct acpi_device *acpi = to_acpi_device(dev);
 576        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 577        int err, state;
 578
 579        union acpi_object param[2];
 580        struct acpi_object_list input;
 581        acpi_status status;
 582
 583        param[0].type = ACPI_TYPE_INTEGER;
 584        param[0].integer.value = 0x15;
 585        param[1].type = ACPI_TYPE_INTEGER;
 586        input.count = 2;
 587        input.pointer = param;
 588
 589        err = kstrtoint(buf, 0, &state);
 590        if (err)
 591                return err;
 592
 593        switch (state) {
 594        case 0:
 595                param[1].integer.value = ECO_MODE_OFF;
 596                pcc->sinf[SINF_ECO_MODE] = 0;
 597                pcc->eco_mode = 0;
 598                break;
 599        case 1:
 600                param[1].integer.value = ECO_MODE_ON;
 601                pcc->sinf[SINF_ECO_MODE] = 1;
 602                pcc->eco_mode = 1;
 603                break;
 604        default:
 605                /* nothing to do */
 606                return count;
 607        }
 608
 609        status = acpi_evaluate_object(NULL, METHOD_ECWR,
 610                                       &input, NULL);
 611        if (ACPI_FAILURE(status)) {
 612                pr_err("%s evaluation failed\n", METHOD_ECWR);
 613                return -EINVAL;
 614        }
 615
 616        return count;
 617}
 618
 619static ssize_t ac_brightness_show(struct device *dev, struct device_attribute *attr,
 620                                  char *buf)
 621{
 622        struct acpi_device *acpi = to_acpi_device(dev);
 623        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 624
 625        if (!acpi_pcc_retrieve_biosdata(pcc))
 626                return -EIO;
 627
 628        return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_AC_CUR_BRIGHT]);
 629}
 630
 631static ssize_t ac_brightness_store(struct device *dev, struct device_attribute *attr,
 632                                   const char *buf, size_t count)
 633{
 634        struct acpi_device *acpi = to_acpi_device(dev);
 635        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 636        int err, val;
 637
 638        err = kstrtoint(buf, 0, &val);
 639        if (err)
 640                return err;
 641        if (val >= 0 && val <= 255) {
 642                acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, val);
 643                pcc->ac_brightness = val;
 644        }
 645
 646        return count;
 647}
 648
 649static ssize_t dc_brightness_show(struct device *dev, struct device_attribute *attr,
 650                                  char *buf)
 651{
 652        struct acpi_device *acpi = to_acpi_device(dev);
 653        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 654
 655        if (!acpi_pcc_retrieve_biosdata(pcc))
 656                return -EIO;
 657
 658        return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_DC_CUR_BRIGHT]);
 659}
 660
 661static ssize_t dc_brightness_store(struct device *dev, struct device_attribute *attr,
 662                                   const char *buf, size_t count)
 663{
 664        struct acpi_device *acpi = to_acpi_device(dev);
 665        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 666        int err, val;
 667
 668        err = kstrtoint(buf, 0, &val);
 669        if (err)
 670                return err;
 671        if (val >= 0 && val <= 255) {
 672                acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, val);
 673                pcc->dc_brightness = val;
 674        }
 675
 676        return count;
 677}
 678
 679static ssize_t current_brightness_show(struct device *dev, struct device_attribute *attr,
 680                                       char *buf)
 681{
 682        struct acpi_device *acpi = to_acpi_device(dev);
 683        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 684
 685        if (!acpi_pcc_retrieve_biosdata(pcc))
 686                return -EIO;
 687
 688        return snprintf(buf, PAGE_SIZE, "%u\n", pcc->sinf[SINF_CUR_BRIGHT]);
 689}
 690
 691static ssize_t current_brightness_store(struct device *dev, struct device_attribute *attr,
 692                                        const char *buf, size_t count)
 693{
 694        struct acpi_device *acpi = to_acpi_device(dev);
 695        struct pcc_acpi *pcc = acpi_driver_data(acpi);
 696        int err, val;
 697
 698        err = kstrtoint(buf, 0, &val);
 699        if (err)
 700                return err;
 701
 702        if (val >= 0 && val <= 255) {
 703                err = acpi_pcc_write_sset(pcc, SINF_CUR_BRIGHT, val);
 704                pcc->current_brightness = val;
 705        }
 706
 707        return count;
 708}
 709
 710static ssize_t cdpower_show(struct device *dev, struct device_attribute *attr,
 711                            char *buf)
 712{
 713        return snprintf(buf, PAGE_SIZE, "%d\n", get_optd_power_state());
 714}
 715
 716static ssize_t cdpower_store(struct device *dev, struct device_attribute *attr,
 717                           const char *buf, size_t count)
 718{
 719        int err, val;
 720
 721        err = kstrtoint(buf, 10, &val);
 722        if (err)
 723                return err;
 724        set_optd_power_state(val);
 725        return count;
 726}
 727
 728static DEVICE_ATTR_RO(numbatt);
 729static DEVICE_ATTR_RO(lcdtype);
 730static DEVICE_ATTR_RW(mute);
 731static DEVICE_ATTR_RW(sticky_key);
 732static DEVICE_ATTR_RW(eco_mode);
 733static DEVICE_ATTR_RW(ac_brightness);
 734static DEVICE_ATTR_RW(dc_brightness);
 735static DEVICE_ATTR_RW(current_brightness);
 736static DEVICE_ATTR_RW(cdpower);
 737
 738static struct attribute *pcc_sysfs_entries[] = {
 739        &dev_attr_numbatt.attr,
 740        &dev_attr_lcdtype.attr,
 741        &dev_attr_mute.attr,
 742        &dev_attr_sticky_key.attr,
 743        &dev_attr_eco_mode.attr,
 744        &dev_attr_ac_brightness.attr,
 745        &dev_attr_dc_brightness.attr,
 746        &dev_attr_current_brightness.attr,
 747        &dev_attr_cdpower.attr,
 748        NULL,
 749};
 750
 751static const struct attribute_group pcc_attr_group = {
 752        .name   = NULL,         /* put in device directory */
 753        .attrs  = pcc_sysfs_entries,
 754};
 755
 756
 757/* hotkey input device driver */
 758
 759static int sleep_keydown_seen;
 760static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
 761{
 762        struct input_dev *hotk_input_dev = pcc->input_dev;
 763        int rc;
 764        unsigned long long result;
 765
 766        rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY,
 767                                   NULL, &result);
 768        if (ACPI_FAILURE(rc)) {
 769                pr_err("error getting hotkey status\n");
 770                return;
 771        }
 772
 773        /* hack: some firmware sends no key down for sleep / hibernate */
 774        if ((result & 0xf) == 0x7 || (result & 0xf) == 0xa) {
 775                if (result & 0x80)
 776                        sleep_keydown_seen = 1;
 777                if (!sleep_keydown_seen)
 778                        sparse_keymap_report_event(hotk_input_dev,
 779                                        result & 0xf, 0x80, false);
 780        }
 781
 782        if ((result & 0xf) == 0x7 || (result & 0xf) == 0x9 || (result & 0xf) == 0xa) {
 783                if (!sparse_keymap_report_event(hotk_input_dev,
 784                                                result & 0xf, result & 0x80, false))
 785                        pr_err("Unknown hotkey event: 0x%04llx\n", result);
 786        }
 787}
 788
 789static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event)
 790{
 791        struct pcc_acpi *pcc = acpi_driver_data(device);
 792
 793        switch (event) {
 794        case HKEY_NOTIFY:
 795                acpi_pcc_generate_keyinput(pcc);
 796                break;
 797        default:
 798                /* nothing to do */
 799                break;
 800        }
 801}
 802
 803static void pcc_optd_notify(acpi_handle handle, u32 event, void *data)
 804{
 805        if (event != ACPI_NOTIFY_EJECT_REQUEST)
 806                return;
 807
 808        set_optd_power_state(0);
 809}
 810
 811static int pcc_register_optd_notifier(struct pcc_acpi *pcc, char *node)
 812{
 813        acpi_status status;
 814        acpi_handle handle;
 815
 816        status = acpi_get_handle(NULL, node, &handle);
 817
 818        if (ACPI_SUCCESS(status)) {
 819                status = acpi_install_notify_handler(handle,
 820                                ACPI_SYSTEM_NOTIFY,
 821                                pcc_optd_notify, pcc);
 822                if (ACPI_FAILURE(status))
 823                        pr_err("Failed to register notify on %s\n", node);
 824        } else
 825                return -ENODEV;
 826
 827        return 0;
 828}
 829
 830static void pcc_unregister_optd_notifier(struct pcc_acpi *pcc, char *node)
 831{
 832        acpi_status status = AE_OK;
 833        acpi_handle handle;
 834
 835        status = acpi_get_handle(NULL, node, &handle);
 836
 837        if (ACPI_SUCCESS(status)) {
 838                status = acpi_remove_notify_handler(handle,
 839                                ACPI_SYSTEM_NOTIFY,
 840                                pcc_optd_notify);
 841                if (ACPI_FAILURE(status))
 842                        pr_err("Error removing optd notify handler %s\n",
 843                                        node);
 844        }
 845}
 846
 847static int acpi_pcc_init_input(struct pcc_acpi *pcc)
 848{
 849        struct input_dev *input_dev;
 850        int error;
 851
 852        input_dev = input_allocate_device();
 853        if (!input_dev)
 854                return -ENOMEM;
 855
 856        input_dev->name = ACPI_PCC_DRIVER_NAME;
 857        input_dev->phys = ACPI_PCC_INPUT_PHYS;
 858        input_dev->id.bustype = BUS_HOST;
 859        input_dev->id.vendor = 0x0001;
 860        input_dev->id.product = 0x0001;
 861        input_dev->id.version = 0x0100;
 862
 863        error = sparse_keymap_setup(input_dev, panasonic_keymap, NULL);
 864        if (error) {
 865                pr_err("Unable to setup input device keymap\n");
 866                goto err_free_dev;
 867        }
 868
 869        error = input_register_device(input_dev);
 870        if (error) {
 871                pr_err("Unable to register input device\n");
 872                goto err_free_dev;
 873        }
 874
 875        pcc->input_dev = input_dev;
 876        return 0;
 877
 878 err_free_dev:
 879        input_free_device(input_dev);
 880        return error;
 881}
 882
 883/* kernel module interface */
 884
 885#ifdef CONFIG_PM_SLEEP
 886static int acpi_pcc_hotkey_resume(struct device *dev)
 887{
 888        struct pcc_acpi *pcc;
 889
 890        if (!dev)
 891                return -EINVAL;
 892
 893        pcc = acpi_driver_data(to_acpi_device(dev));
 894        if (!pcc)
 895                return -EINVAL;
 896
 897        acpi_pcc_write_sset(pcc, SINF_MUTE, pcc->mute);
 898        acpi_pcc_write_sset(pcc, SINF_ECO_MODE, pcc->eco_mode);
 899        acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_key);
 900        acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, pcc->ac_brightness);
 901        acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, pcc->dc_brightness);
 902        acpi_pcc_write_sset(pcc, SINF_CUR_BRIGHT, pcc->current_brightness);
 903
 904        return 0;
 905}
 906#endif
 907
 908static int acpi_pcc_hotkey_add(struct acpi_device *device)
 909{
 910        struct backlight_properties props;
 911        struct pcc_acpi *pcc;
 912        int num_sifr, result;
 913
 914        if (!device)
 915                return -EINVAL;
 916
 917        num_sifr = acpi_pcc_get_sqty(device);
 918
 919        if (num_sifr < 0 || num_sifr > 255) {
 920                pr_err("num_sifr out of range");
 921                return -ENODEV;
 922        }
 923
 924        pcc = kzalloc(sizeof(struct pcc_acpi), GFP_KERNEL);
 925        if (!pcc) {
 926                pr_err("Couldn't allocate mem for pcc");
 927                return -ENOMEM;
 928        }
 929
 930        pcc->sinf = kcalloc(num_sifr + 1, sizeof(u32), GFP_KERNEL);
 931        if (!pcc->sinf) {
 932                result = -ENOMEM;
 933                goto out_hotkey;
 934        }
 935
 936        pcc->device = device;
 937        pcc->handle = device->handle;
 938        pcc->num_sifr = num_sifr;
 939        device->driver_data = pcc;
 940        strcpy(acpi_device_name(device), ACPI_PCC_DEVICE_NAME);
 941        strcpy(acpi_device_class(device), ACPI_PCC_CLASS);
 942
 943        result = acpi_pcc_init_input(pcc);
 944        if (result) {
 945                pr_err("Error installing keyinput handler\n");
 946                goto out_sinf;
 947        }
 948
 949        if (!acpi_pcc_retrieve_biosdata(pcc)) {
 950                result = -EIO;
 951                pr_err("Couldn't retrieve BIOS data\n");
 952                goto out_input;
 953        }
 954        /* initialize backlight */
 955        memset(&props, 0, sizeof(struct backlight_properties));
 956        props.type = BACKLIGHT_PLATFORM;
 957        props.max_brightness = pcc->sinf[SINF_AC_MAX_BRIGHT];
 958        pcc->backlight = backlight_device_register("panasonic", NULL, pcc,
 959                                                   &pcc_backlight_ops, &props);
 960        if (IS_ERR(pcc->backlight)) {
 961                result = PTR_ERR(pcc->backlight);
 962                goto out_input;
 963        }
 964
 965        /* read the initial brightness setting from the hardware */
 966        pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT];
 967
 968        /* Reset initial sticky key mode since the hardware register state is not consistent */
 969        acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, 0);
 970        pcc->sticky_key = 0;
 971
 972        pcc->eco_mode = pcc->sinf[SINF_ECO_MODE];
 973        pcc->mute = pcc->sinf[SINF_MUTE];
 974        pcc->ac_brightness = pcc->sinf[SINF_AC_CUR_BRIGHT];
 975        pcc->dc_brightness = pcc->sinf[SINF_DC_CUR_BRIGHT];
 976        pcc->current_brightness = pcc->sinf[SINF_CUR_BRIGHT];
 977
 978        /* add sysfs attributes */
 979        result = sysfs_create_group(&device->dev.kobj, &pcc_attr_group);
 980        if (result)
 981                goto out_backlight;
 982
 983        /* optical drive initialization */
 984        if (ACPI_SUCCESS(check_optd_present())) {
 985                pcc->platform = platform_device_register_simple("panasonic",
 986                        -1, NULL, 0);
 987                if (IS_ERR(pcc->platform)) {
 988                        result = PTR_ERR(pcc->platform);
 989                        goto out_backlight;
 990                }
 991                result = device_create_file(&pcc->platform->dev,
 992                        &dev_attr_cdpower);
 993                pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD");
 994                if (result)
 995                        goto out_platform;
 996        } else {
 997                pcc->platform = NULL;
 998        }
 999
1000        return 0;
1001
1002out_platform:
1003        platform_device_unregister(pcc->platform);
1004out_backlight:
1005        backlight_device_unregister(pcc->backlight);
1006out_input:
1007        input_unregister_device(pcc->input_dev);
1008out_sinf:
1009        kfree(pcc->sinf);
1010out_hotkey:
1011        kfree(pcc);
1012
1013        return result;
1014}
1015
1016static int acpi_pcc_hotkey_remove(struct acpi_device *device)
1017{
1018        struct pcc_acpi *pcc = acpi_driver_data(device);
1019
1020        if (!device || !pcc)
1021                return -EINVAL;
1022
1023        if (pcc->platform) {
1024                device_remove_file(&pcc->platform->dev, &dev_attr_cdpower);
1025                platform_device_unregister(pcc->platform);
1026        }
1027        pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD");
1028
1029        sysfs_remove_group(&device->dev.kobj, &pcc_attr_group);
1030
1031        backlight_device_unregister(pcc->backlight);
1032
1033        input_unregister_device(pcc->input_dev);
1034
1035        kfree(pcc->sinf);
1036        kfree(pcc);
1037
1038        return 0;
1039}
1040
1041module_acpi_driver(acpi_pcc_driver);
1042