linux/drivers/platform/surface/surface3_power.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Supports for the power IC on the Surface 3 tablet.
   4 *
   5 * (C) Copyright 2016-2018 Red Hat, Inc
   6 * (C) Copyright 2016-2018 Benjamin Tissoires <benjamin.tissoires@gmail.com>
   7 * (C) Copyright 2016 Stephen Just <stephenjust@gmail.com>
   8 *
   9 * This driver has been reverse-engineered by parsing the DSDT of the Surface 3
  10 * and looking at the registers of the chips.
  11 *
  12 * The DSDT allowed to find out that:
  13 * - the driver is required for the ACPI BAT0 device to communicate to the chip
  14 *   through an operation region.
  15 * - the various defines for the operation region functions to communicate with
  16 *   this driver
  17 * - the DSM 3f99e367-6220-4955-8b0f-06ef2ae79412 allows to trigger ACPI
  18 *   events to BAT0 (the code is all available in the DSDT).
  19 *
  20 * Further findings regarding the 2 chips declared in the MSHW0011 are:
  21 * - there are 2 chips declared:
  22 *   . 0x22 seems to control the ADP1 line status (and probably the charger)
  23 *   . 0x55 controls the battery directly
  24 * - the battery chip uses a SMBus protocol (using plain SMBus allows non
  25 *   destructive commands):
  26 *   . the commands/registers used are in the range 0x00..0x7F
  27 *   . if bit 8 (0x80) is set in the SMBus command, the returned value is the
  28 *     same as when it is not set. There is a high chance this bit is the
  29 *     read/write
  30 *   . the various registers semantic as been deduced by observing the register
  31 *     dumps.
  32 */
  33
  34#include <linux/acpi.h>
  35#include <linux/bits.h>
  36#include <linux/freezer.h>
  37#include <linux/i2c.h>
  38#include <linux/kernel.h>
  39#include <linux/kthread.h>
  40#include <linux/slab.h>
  41#include <linux/types.h>
  42#include <linux/uuid.h>
  43#include <asm/unaligned.h>
  44
  45#define SURFACE_3_POLL_INTERVAL         (2 * HZ)
  46#define SURFACE_3_STRLEN                10
  47
  48struct mshw0011_data {
  49        struct i2c_client       *adp1;
  50        struct i2c_client       *bat0;
  51        unsigned short          notify_mask;
  52        struct task_struct      *poll_task;
  53        bool                    kthread_running;
  54
  55        bool                    charging;
  56        bool                    bat_charging;
  57        u8                      trip_point;
  58        s32                     full_capacity;
  59};
  60
  61struct mshw0011_handler_data {
  62        struct acpi_connection_info     info;
  63        struct i2c_client               *client;
  64};
  65
  66struct bix {
  67        u32     revision;
  68        u32     power_unit;
  69        u32     design_capacity;
  70        u32     last_full_charg_capacity;
  71        u32     battery_technology;
  72        u32     design_voltage;
  73        u32     design_capacity_of_warning;
  74        u32     design_capacity_of_low;
  75        u32     cycle_count;
  76        u32     measurement_accuracy;
  77        u32     max_sampling_time;
  78        u32     min_sampling_time;
  79        u32     max_average_interval;
  80        u32     min_average_interval;
  81        u32     battery_capacity_granularity_1;
  82        u32     battery_capacity_granularity_2;
  83        char    model[SURFACE_3_STRLEN];
  84        char    serial[SURFACE_3_STRLEN];
  85        char    type[SURFACE_3_STRLEN];
  86        char    OEM[SURFACE_3_STRLEN];
  87} __packed;
  88
  89struct bst {
  90        u32     battery_state;
  91        s32     battery_present_rate;
  92        u32     battery_remaining_capacity;
  93        u32     battery_present_voltage;
  94} __packed;
  95
  96struct gsb_command {
  97        u8      arg0;
  98        u8      arg1;
  99        u8      arg2;
 100} __packed;
 101
 102struct gsb_buffer {
 103        u8      status;
 104        u8      len;
 105        u8      ret;
 106        union {
 107                struct gsb_command      cmd;
 108                struct bst              bst;
 109                struct bix              bix;
 110        } __packed;
 111} __packed;
 112
 113#define ACPI_BATTERY_STATE_DISCHARGING  BIT(0)
 114#define ACPI_BATTERY_STATE_CHARGING     BIT(1)
 115#define ACPI_BATTERY_STATE_CRITICAL     BIT(2)
 116
 117#define MSHW0011_CMD_DEST_BAT0          0x01
 118#define MSHW0011_CMD_DEST_ADP1          0x03
 119
 120#define MSHW0011_CMD_BAT0_STA           0x01
 121#define MSHW0011_CMD_BAT0_BIX           0x02
 122#define MSHW0011_CMD_BAT0_BCT           0x03
 123#define MSHW0011_CMD_BAT0_BTM           0x04
 124#define MSHW0011_CMD_BAT0_BST           0x05
 125#define MSHW0011_CMD_BAT0_BTP           0x06
 126#define MSHW0011_CMD_ADP1_PSR           0x07
 127#define MSHW0011_CMD_BAT0_PSOC          0x09
 128#define MSHW0011_CMD_BAT0_PMAX          0x0a
 129#define MSHW0011_CMD_BAT0_PSRC          0x0b
 130#define MSHW0011_CMD_BAT0_CHGI          0x0c
 131#define MSHW0011_CMD_BAT0_ARTG          0x0d
 132
 133#define MSHW0011_NOTIFY_GET_VERSION     0x00
 134#define MSHW0011_NOTIFY_ADP1            0x01
 135#define MSHW0011_NOTIFY_BAT0_BST        0x02
 136#define MSHW0011_NOTIFY_BAT0_BIX        0x05
 137
 138#define MSHW0011_ADP1_REG_PSR           0x04
 139
 140#define MSHW0011_BAT0_REG_CAPACITY              0x0c
 141#define MSHW0011_BAT0_REG_FULL_CHG_CAPACITY     0x0e
 142#define MSHW0011_BAT0_REG_DESIGN_CAPACITY       0x40
 143#define MSHW0011_BAT0_REG_VOLTAGE       0x08
 144#define MSHW0011_BAT0_REG_RATE          0x14
 145#define MSHW0011_BAT0_REG_OEM           0x45
 146#define MSHW0011_BAT0_REG_TYPE          0x4e
 147#define MSHW0011_BAT0_REG_SERIAL_NO     0x56
 148#define MSHW0011_BAT0_REG_CYCLE_CNT     0x6e
 149
 150#define MSHW0011_EV_2_5_MASK            GENMASK(8, 0)
 151
 152/* 3f99e367-6220-4955-8b0f-06ef2ae79412 */
 153static const guid_t mshw0011_guid =
 154        GUID_INIT(0x3F99E367, 0x6220, 0x4955, 0x8B, 0x0F, 0x06, 0xEF,
 155                  0x2A, 0xE7, 0x94, 0x12);
 156
 157static int
 158mshw0011_notify(struct mshw0011_data *cdata, u8 arg1, u8 arg2,
 159                unsigned int *ret_value)
 160{
 161        union acpi_object *obj;
 162        acpi_handle handle;
 163        unsigned int i;
 164
 165        handle = ACPI_HANDLE(&cdata->adp1->dev);
 166        if (!handle)
 167                return -ENODEV;
 168
 169        obj = acpi_evaluate_dsm_typed(handle, &mshw0011_guid, arg1, arg2, NULL,
 170                                      ACPI_TYPE_BUFFER);
 171        if (!obj) {
 172                dev_err(&cdata->adp1->dev, "device _DSM execution failed\n");
 173                return -ENODEV;
 174        }
 175
 176        *ret_value = 0;
 177        for (i = 0; i < obj->buffer.length; i++)
 178                *ret_value |= obj->buffer.pointer[i] << (i * 8);
 179
 180        ACPI_FREE(obj);
 181        return 0;
 182}
 183
 184static const struct bix default_bix = {
 185        .revision = 0x00,
 186        .power_unit = 0x01,
 187        .design_capacity = 0x1dca,
 188        .last_full_charg_capacity = 0x1dca,
 189        .battery_technology = 0x01,
 190        .design_voltage = 0x10df,
 191        .design_capacity_of_warning = 0x8f,
 192        .design_capacity_of_low = 0x47,
 193        .cycle_count = 0xffffffff,
 194        .measurement_accuracy = 0x00015f90,
 195        .max_sampling_time = 0x03e8,
 196        .min_sampling_time = 0x03e8,
 197        .max_average_interval = 0x03e8,
 198        .min_average_interval = 0x03e8,
 199        .battery_capacity_granularity_1 = 0x45,
 200        .battery_capacity_granularity_2 = 0x11,
 201        .model = "P11G8M",
 202        .serial = "",
 203        .type = "LION",
 204        .OEM = "",
 205};
 206
 207static int mshw0011_bix(struct mshw0011_data *cdata, struct bix *bix)
 208{
 209        struct i2c_client *client = cdata->bat0;
 210        char buf[SURFACE_3_STRLEN];
 211        int ret;
 212
 213        *bix = default_bix;
 214
 215        /* get design capacity */
 216        ret = i2c_smbus_read_word_data(client,
 217                                       MSHW0011_BAT0_REG_DESIGN_CAPACITY);
 218        if (ret < 0) {
 219                dev_err(&client->dev, "Error reading design capacity: %d\n",
 220                        ret);
 221                return ret;
 222        }
 223        bix->design_capacity = ret;
 224
 225        /* get last full charge capacity */
 226        ret = i2c_smbus_read_word_data(client,
 227                                       MSHW0011_BAT0_REG_FULL_CHG_CAPACITY);
 228        if (ret < 0) {
 229                dev_err(&client->dev,
 230                        "Error reading last full charge capacity: %d\n", ret);
 231                return ret;
 232        }
 233        bix->last_full_charg_capacity = ret;
 234
 235        /* get serial number */
 236        ret = i2c_smbus_read_i2c_block_data(client, MSHW0011_BAT0_REG_SERIAL_NO,
 237                                            sizeof(buf), buf);
 238        if (ret != sizeof(buf)) {
 239                dev_err(&client->dev, "Error reading serial no: %d\n", ret);
 240                return ret;
 241        }
 242        snprintf(bix->serial, ARRAY_SIZE(bix->serial), "%3pE%6pE", buf + 7, buf);
 243
 244        /* get cycle count */
 245        ret = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_CYCLE_CNT);
 246        if (ret < 0) {
 247                dev_err(&client->dev, "Error reading cycle count: %d\n", ret);
 248                return ret;
 249        }
 250        bix->cycle_count = ret;
 251
 252        /* get OEM name */
 253        ret = i2c_smbus_read_i2c_block_data(client, MSHW0011_BAT0_REG_OEM,
 254                                            4, buf);
 255        if (ret != 4) {
 256                dev_err(&client->dev, "Error reading cycle count: %d\n", ret);
 257                return ret;
 258        }
 259        snprintf(bix->OEM, ARRAY_SIZE(bix->OEM), "%3pE", buf);
 260
 261        return 0;
 262}
 263
 264static int mshw0011_bst(struct mshw0011_data *cdata, struct bst *bst)
 265{
 266        struct i2c_client *client = cdata->bat0;
 267        int rate, capacity, voltage, state;
 268        s16 tmp;
 269
 270        rate = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_RATE);
 271        if (rate < 0)
 272                return rate;
 273
 274        capacity = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_CAPACITY);
 275        if (capacity < 0)
 276                return capacity;
 277
 278        voltage = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_VOLTAGE);
 279        if (voltage < 0)
 280                return voltage;
 281
 282        tmp = rate;
 283        bst->battery_present_rate = abs((s32)tmp);
 284
 285        state = 0;
 286        if ((s32) tmp > 0)
 287                state |= ACPI_BATTERY_STATE_CHARGING;
 288        else if ((s32) tmp < 0)
 289                state |= ACPI_BATTERY_STATE_DISCHARGING;
 290        bst->battery_state = state;
 291
 292        bst->battery_remaining_capacity = capacity;
 293        bst->battery_present_voltage = voltage;
 294
 295        return 0;
 296}
 297
 298static int mshw0011_adp_psr(struct mshw0011_data *cdata)
 299{
 300        return i2c_smbus_read_byte_data(cdata->adp1, MSHW0011_ADP1_REG_PSR);
 301}
 302
 303static int mshw0011_isr(struct mshw0011_data *cdata)
 304{
 305        struct bst bst;
 306        struct bix bix;
 307        int ret;
 308        bool status, bat_status;
 309
 310        ret = mshw0011_adp_psr(cdata);
 311        if (ret < 0)
 312                return ret;
 313
 314        status = ret;
 315        if (status != cdata->charging)
 316                mshw0011_notify(cdata, cdata->notify_mask,
 317                                MSHW0011_NOTIFY_ADP1, &ret);
 318
 319        cdata->charging = status;
 320
 321        ret = mshw0011_bst(cdata, &bst);
 322        if (ret < 0)
 323                return ret;
 324
 325        bat_status = bst.battery_state;
 326        if (bat_status != cdata->bat_charging)
 327                mshw0011_notify(cdata, cdata->notify_mask,
 328                                MSHW0011_NOTIFY_BAT0_BST, &ret);
 329
 330        cdata->bat_charging = bat_status;
 331
 332        ret = mshw0011_bix(cdata, &bix);
 333        if (ret < 0)
 334                return ret;
 335
 336        if (bix.last_full_charg_capacity != cdata->full_capacity)
 337                mshw0011_notify(cdata, cdata->notify_mask,
 338                                MSHW0011_NOTIFY_BAT0_BIX, &ret);
 339
 340        cdata->full_capacity = bix.last_full_charg_capacity;
 341
 342        return 0;
 343}
 344
 345static int mshw0011_poll_task(void *data)
 346{
 347        struct mshw0011_data *cdata = data;
 348        int ret = 0;
 349
 350        cdata->kthread_running = true;
 351
 352        set_freezable();
 353
 354        while (!kthread_should_stop()) {
 355                schedule_timeout_interruptible(SURFACE_3_POLL_INTERVAL);
 356                try_to_freeze();
 357                ret = mshw0011_isr(data);
 358                if (ret)
 359                        break;
 360        }
 361
 362        cdata->kthread_running = false;
 363        return ret;
 364}
 365
 366static acpi_status
 367mshw0011_space_handler(u32 function, acpi_physical_address command,
 368                        u32 bits, u64 *value64,
 369                        void *handler_context, void *region_context)
 370{
 371        struct gsb_buffer *gsb = (struct gsb_buffer *)value64;
 372        struct mshw0011_handler_data *data = handler_context;
 373        struct acpi_connection_info *info = &data->info;
 374        struct acpi_resource_i2c_serialbus *sb;
 375        struct i2c_client *client = data->client;
 376        struct mshw0011_data *cdata = i2c_get_clientdata(client);
 377        struct acpi_resource *ares;
 378        u32 accessor_type = function >> 16;
 379        acpi_status ret;
 380        int status = 1;
 381
 382        ret = acpi_buffer_to_resource(info->connection, info->length, &ares);
 383        if (ACPI_FAILURE(ret))
 384                return ret;
 385
 386        if (!value64 || !i2c_acpi_get_i2c_resource(ares, &sb)) {
 387                ret = AE_BAD_PARAMETER;
 388                goto err;
 389        }
 390
 391        if (accessor_type != ACPI_GSB_ACCESS_ATTRIB_RAW_PROCESS) {
 392                ret = AE_BAD_PARAMETER;
 393                goto err;
 394        }
 395
 396        if (gsb->cmd.arg0 == MSHW0011_CMD_DEST_ADP1 &&
 397            gsb->cmd.arg1 == MSHW0011_CMD_ADP1_PSR) {
 398                status = mshw0011_adp_psr(cdata);
 399                if (status >= 0) {
 400                        ret = AE_OK;
 401                        goto out;
 402                } else {
 403                        ret = AE_ERROR;
 404                        goto err;
 405                }
 406        }
 407
 408        if (gsb->cmd.arg0 != MSHW0011_CMD_DEST_BAT0) {
 409                ret = AE_BAD_PARAMETER;
 410                goto err;
 411        }
 412
 413        switch (gsb->cmd.arg1) {
 414        case MSHW0011_CMD_BAT0_STA:
 415                break;
 416        case MSHW0011_CMD_BAT0_BIX:
 417                ret = mshw0011_bix(cdata, &gsb->bix);
 418                break;
 419        case MSHW0011_CMD_BAT0_BTP:
 420                cdata->trip_point = gsb->cmd.arg2;
 421                break;
 422        case MSHW0011_CMD_BAT0_BST:
 423                ret = mshw0011_bst(cdata, &gsb->bst);
 424                break;
 425        default:
 426                dev_info(&cdata->bat0->dev, "command(0x%02x) is not supported.\n", gsb->cmd.arg1);
 427                ret = AE_BAD_PARAMETER;
 428                goto err;
 429        }
 430
 431 out:
 432        gsb->ret = status;
 433        gsb->status = 0;
 434
 435 err:
 436        ACPI_FREE(ares);
 437        return ret;
 438}
 439
 440static int mshw0011_install_space_handler(struct i2c_client *client)
 441{
 442        struct acpi_device *adev;
 443        struct mshw0011_handler_data *data;
 444        acpi_status status;
 445
 446        adev = ACPI_COMPANION(&client->dev);
 447        if (!adev)
 448                return -ENODEV;
 449
 450        data = kzalloc(sizeof(struct mshw0011_handler_data),
 451                            GFP_KERNEL);
 452        if (!data)
 453                return -ENOMEM;
 454
 455        data->client = client;
 456        status = acpi_bus_attach_private_data(adev->handle, (void *)data);
 457        if (ACPI_FAILURE(status)) {
 458                kfree(data);
 459                return -ENOMEM;
 460        }
 461
 462        status = acpi_install_address_space_handler(adev->handle,
 463                                                    ACPI_ADR_SPACE_GSBUS,
 464                                                    &mshw0011_space_handler,
 465                                                    NULL,
 466                                                    data);
 467        if (ACPI_FAILURE(status)) {
 468                dev_err(&client->dev, "Error installing i2c space handler\n");
 469                acpi_bus_detach_private_data(adev->handle);
 470                kfree(data);
 471                return -ENOMEM;
 472        }
 473
 474        acpi_dev_clear_dependencies(adev);
 475        return 0;
 476}
 477
 478static void mshw0011_remove_space_handler(struct i2c_client *client)
 479{
 480        struct mshw0011_handler_data *data;
 481        acpi_handle handle;
 482        acpi_status status;
 483
 484        handle = ACPI_HANDLE(&client->dev);
 485        if (!handle)
 486                return;
 487
 488        acpi_remove_address_space_handler(handle,
 489                                ACPI_ADR_SPACE_GSBUS,
 490                                &mshw0011_space_handler);
 491
 492        status = acpi_bus_get_private_data(handle, (void **)&data);
 493        if (ACPI_SUCCESS(status))
 494                kfree(data);
 495
 496        acpi_bus_detach_private_data(handle);
 497}
 498
 499static int mshw0011_probe(struct i2c_client *client)
 500{
 501        struct i2c_board_info board_info;
 502        struct device *dev = &client->dev;
 503        struct i2c_client *bat0;
 504        struct mshw0011_data *data;
 505        int error, mask;
 506
 507        data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
 508        if (!data)
 509                return -ENOMEM;
 510
 511        data->adp1 = client;
 512        i2c_set_clientdata(client, data);
 513
 514        memset(&board_info, 0, sizeof(board_info));
 515        strlcpy(board_info.type, "MSHW0011-bat0", I2C_NAME_SIZE);
 516
 517        bat0 = i2c_acpi_new_device(dev, 1, &board_info);
 518        if (IS_ERR(bat0))
 519                return PTR_ERR(bat0);
 520
 521        data->bat0 = bat0;
 522        i2c_set_clientdata(bat0, data);
 523
 524        error = mshw0011_notify(data, 1, MSHW0011_NOTIFY_GET_VERSION, &mask);
 525        if (error)
 526                goto out_err;
 527
 528        data->notify_mask = mask == MSHW0011_EV_2_5_MASK;
 529
 530        data->poll_task = kthread_run(mshw0011_poll_task, data, "mshw0011_adp");
 531        if (IS_ERR(data->poll_task)) {
 532                error = PTR_ERR(data->poll_task);
 533                dev_err(&client->dev, "Unable to run kthread err %d\n", error);
 534                goto out_err;
 535        }
 536
 537        error = mshw0011_install_space_handler(client);
 538        if (error)
 539                goto out_err;
 540
 541        return 0;
 542
 543out_err:
 544        if (data->kthread_running)
 545                kthread_stop(data->poll_task);
 546        i2c_unregister_device(data->bat0);
 547        return error;
 548}
 549
 550static int mshw0011_remove(struct i2c_client *client)
 551{
 552        struct mshw0011_data *cdata = i2c_get_clientdata(client);
 553
 554        mshw0011_remove_space_handler(client);
 555
 556        if (cdata->kthread_running)
 557                kthread_stop(cdata->poll_task);
 558
 559        i2c_unregister_device(cdata->bat0);
 560
 561        return 0;
 562}
 563
 564static const struct acpi_device_id mshw0011_acpi_match[] = {
 565        { "MSHW0011", 0 },
 566        { }
 567};
 568MODULE_DEVICE_TABLE(acpi, mshw0011_acpi_match);
 569
 570static struct i2c_driver mshw0011_driver = {
 571        .probe_new = mshw0011_probe,
 572        .remove = mshw0011_remove,
 573        .driver = {
 574                .name = "mshw0011",
 575                .acpi_match_table = mshw0011_acpi_match,
 576        },
 577};
 578module_i2c_driver(mshw0011_driver);
 579
 580MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
 581MODULE_DESCRIPTION("mshw0011 driver");
 582MODULE_LICENSE("GPL v2");
 583