linux/drivers/i2c/busses/i2c-scmi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * SMBus driver for ACPI SMBus CMI
   4 *
   5 * Copyright (C) 2009 Crane Cai <crane.cai@amd.com>
   6 */
   7
   8#include <linux/module.h>
   9#include <linux/slab.h>
  10#include <linux/kernel.h>
  11#include <linux/stddef.h>
  12#include <linux/i2c.h>
  13#include <linux/acpi.h>
  14
  15#define ACPI_SMBUS_HC_CLASS             "smbus"
  16#define ACPI_SMBUS_HC_DEVICE_NAME       "cmi"
  17
  18/* SMBUS HID definition as supported by Microsoft Windows */
  19#define ACPI_SMBUS_MS_HID               "SMB0001"
  20
  21ACPI_MODULE_NAME("smbus_cmi");
  22
  23struct smbus_methods_t {
  24        char *mt_info;
  25        char *mt_sbr;
  26        char *mt_sbw;
  27};
  28
  29struct acpi_smbus_cmi {
  30        acpi_handle handle;
  31        struct i2c_adapter adapter;
  32        u8 cap_info:1;
  33        u8 cap_read:1;
  34        u8 cap_write:1;
  35        struct smbus_methods_t *methods;
  36};
  37
  38static const struct smbus_methods_t smbus_methods = {
  39        .mt_info = "_SBI",
  40        .mt_sbr  = "_SBR",
  41        .mt_sbw  = "_SBW",
  42};
  43
  44/* Some IBM BIOSes omit the leading underscore */
  45static const struct smbus_methods_t ibm_smbus_methods = {
  46        .mt_info = "SBI_",
  47        .mt_sbr  = "SBR_",
  48        .mt_sbw  = "SBW_",
  49};
  50
  51static const struct acpi_device_id acpi_smbus_cmi_ids[] = {
  52        {"SMBUS01", (kernel_ulong_t)&smbus_methods},
  53        {ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods},
  54        {ACPI_SMBUS_MS_HID, (kernel_ulong_t)&smbus_methods},
  55        {"", 0}
  56};
  57MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids);
  58
  59#define ACPI_SMBUS_STATUS_OK                    0x00
  60#define ACPI_SMBUS_STATUS_FAIL                  0x07
  61#define ACPI_SMBUS_STATUS_DNAK                  0x10
  62#define ACPI_SMBUS_STATUS_DERR                  0x11
  63#define ACPI_SMBUS_STATUS_CMD_DENY              0x12
  64#define ACPI_SMBUS_STATUS_UNKNOWN               0x13
  65#define ACPI_SMBUS_STATUS_ACC_DENY              0x17
  66#define ACPI_SMBUS_STATUS_TIMEOUT               0x18
  67#define ACPI_SMBUS_STATUS_NOTSUP                0x19
  68#define ACPI_SMBUS_STATUS_BUSY                  0x1a
  69#define ACPI_SMBUS_STATUS_PEC                   0x1f
  70
  71#define ACPI_SMBUS_PRTCL_WRITE                  0x00
  72#define ACPI_SMBUS_PRTCL_READ                   0x01
  73#define ACPI_SMBUS_PRTCL_QUICK                  0x02
  74#define ACPI_SMBUS_PRTCL_BYTE                   0x04
  75#define ACPI_SMBUS_PRTCL_BYTE_DATA              0x06
  76#define ACPI_SMBUS_PRTCL_WORD_DATA              0x08
  77#define ACPI_SMBUS_PRTCL_BLOCK_DATA             0x0a
  78
  79
  80static int
  81acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
  82                   char read_write, u8 command, int size,
  83                   union i2c_smbus_data *data)
  84{
  85        int result = 0;
  86        struct acpi_smbus_cmi *smbus_cmi = adap->algo_data;
  87        unsigned char protocol;
  88        acpi_status status = 0;
  89        struct acpi_object_list input;
  90        union acpi_object mt_params[5];
  91        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
  92        union acpi_object *obj;
  93        union acpi_object *pkg;
  94        char *method;
  95        int len = 0;
  96
  97        dev_dbg(&adap->dev, "access size: %d %s\n", size,
  98                (read_write) ? "READ" : "WRITE");
  99        switch (size) {
 100        case I2C_SMBUS_QUICK:
 101                protocol = ACPI_SMBUS_PRTCL_QUICK;
 102                command = 0;
 103                if (read_write == I2C_SMBUS_WRITE) {
 104                        mt_params[3].type = ACPI_TYPE_INTEGER;
 105                        mt_params[3].integer.value = 0;
 106                        mt_params[4].type = ACPI_TYPE_INTEGER;
 107                        mt_params[4].integer.value = 0;
 108                }
 109                break;
 110
 111        case I2C_SMBUS_BYTE:
 112                protocol = ACPI_SMBUS_PRTCL_BYTE;
 113                if (read_write == I2C_SMBUS_WRITE) {
 114                        mt_params[3].type = ACPI_TYPE_INTEGER;
 115                        mt_params[3].integer.value = 0;
 116                        mt_params[4].type = ACPI_TYPE_INTEGER;
 117                        mt_params[4].integer.value = 0;
 118                } else {
 119                        command = 0;
 120                }
 121                break;
 122
 123        case I2C_SMBUS_BYTE_DATA:
 124                protocol = ACPI_SMBUS_PRTCL_BYTE_DATA;
 125                if (read_write == I2C_SMBUS_WRITE) {
 126                        mt_params[3].type = ACPI_TYPE_INTEGER;
 127                        mt_params[3].integer.value = 1;
 128                        mt_params[4].type = ACPI_TYPE_INTEGER;
 129                        mt_params[4].integer.value = data->byte;
 130                }
 131                break;
 132
 133        case I2C_SMBUS_WORD_DATA:
 134                protocol = ACPI_SMBUS_PRTCL_WORD_DATA;
 135                if (read_write == I2C_SMBUS_WRITE) {
 136                        mt_params[3].type = ACPI_TYPE_INTEGER;
 137                        mt_params[3].integer.value = 2;
 138                        mt_params[4].type = ACPI_TYPE_INTEGER;
 139                        mt_params[4].integer.value = data->word;
 140                }
 141                break;
 142
 143        case I2C_SMBUS_BLOCK_DATA:
 144                protocol = ACPI_SMBUS_PRTCL_BLOCK_DATA;
 145                if (read_write == I2C_SMBUS_WRITE) {
 146                        len = data->block[0];
 147                        if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
 148                                return -EINVAL;
 149                        mt_params[3].type = ACPI_TYPE_INTEGER;
 150                        mt_params[3].integer.value = len;
 151                        mt_params[4].type = ACPI_TYPE_BUFFER;
 152                        mt_params[4].buffer.length = len;
 153                        mt_params[4].buffer.pointer = data->block + 1;
 154                }
 155                break;
 156
 157        default:
 158                dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
 159                return -EOPNOTSUPP;
 160        }
 161
 162        if (read_write == I2C_SMBUS_READ) {
 163                protocol |= ACPI_SMBUS_PRTCL_READ;
 164                method = smbus_cmi->methods->mt_sbr;
 165                input.count = 3;
 166        } else {
 167                protocol |= ACPI_SMBUS_PRTCL_WRITE;
 168                method = smbus_cmi->methods->mt_sbw;
 169                input.count = 5;
 170        }
 171
 172        input.pointer = mt_params;
 173        mt_params[0].type = ACPI_TYPE_INTEGER;
 174        mt_params[0].integer.value = protocol;
 175        mt_params[1].type = ACPI_TYPE_INTEGER;
 176        mt_params[1].integer.value = addr;
 177        mt_params[2].type = ACPI_TYPE_INTEGER;
 178        mt_params[2].integer.value = command;
 179
 180        status = acpi_evaluate_object(smbus_cmi->handle, method, &input,
 181                                      &buffer);
 182        if (ACPI_FAILURE(status)) {
 183                acpi_handle_err(smbus_cmi->handle,
 184                                "Failed to evaluate %s: %i\n", method, status);
 185                return -EIO;
 186        }
 187
 188        pkg = buffer.pointer;
 189        if (pkg && pkg->type == ACPI_TYPE_PACKAGE)
 190                obj = pkg->package.elements;
 191        else {
 192                acpi_handle_err(smbus_cmi->handle, "Invalid argument type\n");
 193                result = -EIO;
 194                goto out;
 195        }
 196        if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
 197                acpi_handle_err(smbus_cmi->handle, "Invalid argument type\n");
 198                result = -EIO;
 199                goto out;
 200        }
 201
 202        result = obj->integer.value;
 203        acpi_handle_debug(smbus_cmi->handle,  "%s return status: %i\n", method,
 204                          result);
 205
 206        switch (result) {
 207        case ACPI_SMBUS_STATUS_OK:
 208                result = 0;
 209                break;
 210        case ACPI_SMBUS_STATUS_BUSY:
 211                result = -EBUSY;
 212                goto out;
 213        case ACPI_SMBUS_STATUS_TIMEOUT:
 214                result = -ETIMEDOUT;
 215                goto out;
 216        case ACPI_SMBUS_STATUS_DNAK:
 217                result = -ENXIO;
 218                goto out;
 219        default:
 220                result = -EIO;
 221                goto out;
 222        }
 223
 224        if (read_write == I2C_SMBUS_WRITE || size == I2C_SMBUS_QUICK)
 225                goto out;
 226
 227        obj = pkg->package.elements + 1;
 228        if (obj->type != ACPI_TYPE_INTEGER) {
 229                acpi_handle_err(smbus_cmi->handle, "Invalid argument type\n");
 230                result = -EIO;
 231                goto out;
 232        }
 233
 234        len = obj->integer.value;
 235        obj = pkg->package.elements + 2;
 236        switch (size) {
 237        case I2C_SMBUS_BYTE:
 238        case I2C_SMBUS_BYTE_DATA:
 239        case I2C_SMBUS_WORD_DATA:
 240                if (obj->type != ACPI_TYPE_INTEGER) {
 241                        acpi_handle_err(smbus_cmi->handle,
 242                                        "Invalid argument type\n");
 243                        result = -EIO;
 244                        goto out;
 245                }
 246                if (len == 2)
 247                        data->word = obj->integer.value;
 248                else
 249                        data->byte = obj->integer.value;
 250                break;
 251        case I2C_SMBUS_BLOCK_DATA:
 252                if (obj->type != ACPI_TYPE_BUFFER) {
 253                        acpi_handle_err(smbus_cmi->handle,
 254                                        "Invalid argument type\n");
 255                        result = -EIO;
 256                        goto out;
 257                }
 258                if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
 259                        return -EPROTO;
 260                data->block[0] = len;
 261                memcpy(data->block + 1, obj->buffer.pointer, len);
 262                break;
 263        }
 264
 265out:
 266        kfree(buffer.pointer);
 267        dev_dbg(&adap->dev, "Transaction status: %i\n", result);
 268        return result;
 269}
 270
 271static u32 acpi_smbus_cmi_func(struct i2c_adapter *adapter)
 272{
 273        struct acpi_smbus_cmi *smbus_cmi = adapter->algo_data;
 274        u32 ret;
 275
 276        ret = smbus_cmi->cap_read | smbus_cmi->cap_write ?
 277                I2C_FUNC_SMBUS_QUICK : 0;
 278
 279        ret |= smbus_cmi->cap_read ?
 280                (I2C_FUNC_SMBUS_READ_BYTE |
 281                I2C_FUNC_SMBUS_READ_BYTE_DATA |
 282                I2C_FUNC_SMBUS_READ_WORD_DATA |
 283                I2C_FUNC_SMBUS_READ_BLOCK_DATA) : 0;
 284
 285        ret |= smbus_cmi->cap_write ?
 286                (I2C_FUNC_SMBUS_WRITE_BYTE |
 287                I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
 288                I2C_FUNC_SMBUS_WRITE_WORD_DATA |
 289                I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) : 0;
 290
 291        return ret;
 292}
 293
 294static const struct i2c_algorithm acpi_smbus_cmi_algorithm = {
 295        .smbus_xfer = acpi_smbus_cmi_access,
 296        .functionality = acpi_smbus_cmi_func,
 297};
 298
 299
 300static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
 301                                  const char *name)
 302{
 303        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 304        struct acpi_handle *handle = smbus_cmi->handle;
 305        union acpi_object *obj;
 306        acpi_status status;
 307
 308        if (!strcmp(name, smbus_cmi->methods->mt_info)) {
 309                status = acpi_evaluate_object(smbus_cmi->handle,
 310                                        smbus_cmi->methods->mt_info,
 311                                        NULL, &buffer);
 312                if (ACPI_FAILURE(status)) {
 313                        acpi_handle_err(handle, "Failed to evaluate %s: %i\n",
 314                                        smbus_cmi->methods->mt_info, status);
 315                        return -EIO;
 316                }
 317
 318                obj = buffer.pointer;
 319                if (obj && obj->type == ACPI_TYPE_PACKAGE)
 320                        obj = obj->package.elements;
 321                else {
 322                        acpi_handle_err(handle, "Invalid argument type\n");
 323                        kfree(buffer.pointer);
 324                        return -EIO;
 325                }
 326
 327                if (obj->type != ACPI_TYPE_INTEGER) {
 328                        acpi_handle_err(handle, "Invalid argument type\n");
 329                        kfree(buffer.pointer);
 330                        return -EIO;
 331                } else
 332                        acpi_handle_debug(handle, "SMBus CMI Version %x\n",
 333                                          (int)obj->integer.value);
 334
 335                kfree(buffer.pointer);
 336                smbus_cmi->cap_info = 1;
 337        } else if (!strcmp(name, smbus_cmi->methods->mt_sbr))
 338                smbus_cmi->cap_read = 1;
 339        else if (!strcmp(name, smbus_cmi->methods->mt_sbw))
 340                smbus_cmi->cap_write = 1;
 341        else
 342                acpi_handle_debug(handle, "Unsupported CMI method: %s\n", name);
 343
 344        return 0;
 345}
 346
 347static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level,
 348                        void *context, void **return_value)
 349{
 350        char node_name[5];
 351        struct acpi_buffer buffer = { sizeof(node_name), node_name };
 352        struct acpi_smbus_cmi *smbus_cmi = context;
 353        acpi_status status;
 354
 355        status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
 356
 357        if (ACPI_SUCCESS(status))
 358                acpi_smbus_cmi_add_cap(smbus_cmi, node_name);
 359
 360        return AE_OK;
 361}
 362
 363static int acpi_smbus_cmi_add(struct acpi_device *device)
 364{
 365        struct acpi_smbus_cmi *smbus_cmi;
 366        const struct acpi_device_id *id;
 367        int ret;
 368
 369        smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
 370        if (!smbus_cmi)
 371                return -ENOMEM;
 372
 373        smbus_cmi->handle = device->handle;
 374        strcpy(acpi_device_name(device), ACPI_SMBUS_HC_DEVICE_NAME);
 375        strcpy(acpi_device_class(device), ACPI_SMBUS_HC_CLASS);
 376        device->driver_data = smbus_cmi;
 377        smbus_cmi->cap_info = 0;
 378        smbus_cmi->cap_read = 0;
 379        smbus_cmi->cap_write = 0;
 380
 381        for (id = acpi_smbus_cmi_ids; id->id[0]; id++)
 382                if (!strcmp(id->id, acpi_device_hid(device)))
 383                        smbus_cmi->methods =
 384                                (struct smbus_methods_t *) id->driver_data;
 385
 386        acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
 387                            acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL);
 388
 389        if (smbus_cmi->cap_info == 0) {
 390                ret = -ENODEV;
 391                goto err;
 392        }
 393
 394        snprintf(smbus_cmi->adapter.name, sizeof(smbus_cmi->adapter.name),
 395                "SMBus CMI adapter %s",
 396                acpi_device_name(device));
 397        smbus_cmi->adapter.owner = THIS_MODULE;
 398        smbus_cmi->adapter.algo = &acpi_smbus_cmi_algorithm;
 399        smbus_cmi->adapter.algo_data = smbus_cmi;
 400        smbus_cmi->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
 401        smbus_cmi->adapter.dev.parent = &device->dev;
 402
 403        ret = i2c_add_adapter(&smbus_cmi->adapter);
 404        if (ret) {
 405                dev_err(&device->dev, "Couldn't register adapter!\n");
 406                goto err;
 407        }
 408
 409        return 0;
 410
 411err:
 412        kfree(smbus_cmi);
 413        device->driver_data = NULL;
 414        return ret;
 415}
 416
 417static int acpi_smbus_cmi_remove(struct acpi_device *device)
 418{
 419        struct acpi_smbus_cmi *smbus_cmi = acpi_driver_data(device);
 420
 421        i2c_del_adapter(&smbus_cmi->adapter);
 422        kfree(smbus_cmi);
 423        device->driver_data = NULL;
 424
 425        return 0;
 426}
 427
 428static struct acpi_driver acpi_smbus_cmi_driver = {
 429        .name = ACPI_SMBUS_HC_DEVICE_NAME,
 430        .class = ACPI_SMBUS_HC_CLASS,
 431        .ids = acpi_smbus_cmi_ids,
 432        .ops = {
 433                .add = acpi_smbus_cmi_add,
 434                .remove = acpi_smbus_cmi_remove,
 435        },
 436};
 437module_acpi_driver(acpi_smbus_cmi_driver);
 438
 439MODULE_LICENSE("GPL");
 440MODULE_AUTHOR("Crane Cai <crane.cai@amd.com>");
 441MODULE_DESCRIPTION("ACPI SMBus CMI driver");
 442