linux/drivers/hwmon/pmbus/ibm-cffps.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright 2017 IBM Corp.
   4 */
   5
   6#include <linux/bitfield.h>
   7#include <linux/bitops.h>
   8#include <linux/debugfs.h>
   9#include <linux/device.h>
  10#include <linux/fs.h>
  11#include <linux/i2c.h>
  12#include <linux/jiffies.h>
  13#include <linux/leds.h>
  14#include <linux/module.h>
  15#include <linux/mutex.h>
  16#include <linux/of_device.h>
  17#include <linux/pmbus.h>
  18
  19#include "pmbus.h"
  20
  21#define CFFPS_FRU_CMD                           0x9A
  22#define CFFPS_PN_CMD                            0x9B
  23#define CFFPS_HEADER_CMD                        0x9C
  24#define CFFPS_SN_CMD                            0x9E
  25#define CFFPS_MAX_POWER_OUT_CMD                 0xA7
  26#define CFFPS_CCIN_CMD                          0xBD
  27#define CFFPS_FW_CMD                            0xFA
  28#define CFFPS1_FW_NUM_BYTES                     4
  29#define CFFPS2_FW_NUM_WORDS                     3
  30#define CFFPS_SYS_CONFIG_CMD                    0xDA
  31#define CFFPS_12VCS_VOUT_CMD                    0xDE
  32
  33#define CFFPS_INPUT_HISTORY_CMD                 0xD6
  34#define CFFPS_INPUT_HISTORY_SIZE                100
  35
  36#define CFFPS_CCIN_VERSION                      GENMASK(15, 8)
  37#define CFFPS_CCIN_VERSION_1                     0x2b
  38#define CFFPS_CCIN_VERSION_2                     0x2e
  39
  40/* STATUS_MFR_SPECIFIC bits */
  41#define CFFPS_MFR_FAN_FAULT                     BIT(0)
  42#define CFFPS_MFR_THERMAL_FAULT                 BIT(1)
  43#define CFFPS_MFR_OV_FAULT                      BIT(2)
  44#define CFFPS_MFR_UV_FAULT                      BIT(3)
  45#define CFFPS_MFR_PS_KILL                       BIT(4)
  46#define CFFPS_MFR_OC_FAULT                      BIT(5)
  47#define CFFPS_MFR_VAUX_FAULT                    BIT(6)
  48#define CFFPS_MFR_CURRENT_SHARE_WARNING         BIT(7)
  49
  50#define CFFPS_LED_BLINK                         BIT(0)
  51#define CFFPS_LED_ON                            BIT(1)
  52#define CFFPS_LED_OFF                           BIT(2)
  53#define CFFPS_BLINK_RATE_MS                     250
  54
  55enum {
  56        CFFPS_DEBUGFS_INPUT_HISTORY = 0,
  57        CFFPS_DEBUGFS_FRU,
  58        CFFPS_DEBUGFS_PN,
  59        CFFPS_DEBUGFS_HEADER,
  60        CFFPS_DEBUGFS_SN,
  61        CFFPS_DEBUGFS_MAX_POWER_OUT,
  62        CFFPS_DEBUGFS_CCIN,
  63        CFFPS_DEBUGFS_FW,
  64        CFFPS_DEBUGFS_ON_OFF_CONFIG,
  65        CFFPS_DEBUGFS_NUM_ENTRIES
  66};
  67
  68enum versions { cffps1, cffps2, cffps_unknown };
  69
  70struct ibm_cffps_input_history {
  71        struct mutex update_lock;
  72        unsigned long last_update;
  73
  74        u8 byte_count;
  75        u8 data[CFFPS_INPUT_HISTORY_SIZE];
  76};
  77
  78struct ibm_cffps {
  79        enum versions version;
  80        struct i2c_client *client;
  81
  82        struct ibm_cffps_input_history input_history;
  83
  84        int debugfs_entries[CFFPS_DEBUGFS_NUM_ENTRIES];
  85
  86        char led_name[32];
  87        u8 led_state;
  88        struct led_classdev led;
  89};
  90
  91#define to_psu(x, y) container_of((x), struct ibm_cffps, debugfs_entries[(y)])
  92
  93static ssize_t ibm_cffps_read_input_history(struct ibm_cffps *psu,
  94                                            char __user *buf, size_t count,
  95                                            loff_t *ppos)
  96{
  97        int rc;
  98        u8 msgbuf0[1] = { CFFPS_INPUT_HISTORY_CMD };
  99        u8 msgbuf1[CFFPS_INPUT_HISTORY_SIZE + 1] = { 0 };
 100        struct i2c_msg msg[2] = {
 101                {
 102                        .addr = psu->client->addr,
 103                        .flags = psu->client->flags,
 104                        .len = 1,
 105                        .buf = msgbuf0,
 106                }, {
 107                        .addr = psu->client->addr,
 108                        .flags = psu->client->flags | I2C_M_RD,
 109                        .len = CFFPS_INPUT_HISTORY_SIZE + 1,
 110                        .buf = msgbuf1,
 111                },
 112        };
 113
 114        if (!*ppos) {
 115                mutex_lock(&psu->input_history.update_lock);
 116                if (time_after(jiffies, psu->input_history.last_update + HZ)) {
 117                        /*
 118                         * Use a raw i2c transfer, since we need more bytes
 119                         * than Linux I2C supports through smbus xfr (only 32).
 120                         */
 121                        rc = i2c_transfer(psu->client->adapter, msg, 2);
 122                        if (rc < 0) {
 123                                mutex_unlock(&psu->input_history.update_lock);
 124                                return rc;
 125                        }
 126
 127                        psu->input_history.byte_count = msgbuf1[0];
 128                        memcpy(psu->input_history.data, &msgbuf1[1],
 129                               CFFPS_INPUT_HISTORY_SIZE);
 130                        psu->input_history.last_update = jiffies;
 131                }
 132
 133                mutex_unlock(&psu->input_history.update_lock);
 134        }
 135
 136        return simple_read_from_buffer(buf, count, ppos,
 137                                       psu->input_history.data,
 138                                       psu->input_history.byte_count);
 139}
 140
 141static ssize_t ibm_cffps_debugfs_read(struct file *file, char __user *buf,
 142                                      size_t count, loff_t *ppos)
 143{
 144        u8 cmd;
 145        int i, rc;
 146        int *idxp = file->private_data;
 147        int idx = *idxp;
 148        struct ibm_cffps *psu = to_psu(idxp, idx);
 149        char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
 150
 151        pmbus_set_page(psu->client, 0);
 152
 153        switch (idx) {
 154        case CFFPS_DEBUGFS_INPUT_HISTORY:
 155                return ibm_cffps_read_input_history(psu, buf, count, ppos);
 156        case CFFPS_DEBUGFS_FRU:
 157                cmd = CFFPS_FRU_CMD;
 158                break;
 159        case CFFPS_DEBUGFS_PN:
 160                cmd = CFFPS_PN_CMD;
 161                break;
 162        case CFFPS_DEBUGFS_HEADER:
 163                cmd = CFFPS_HEADER_CMD;
 164                break;
 165        case CFFPS_DEBUGFS_SN:
 166                cmd = CFFPS_SN_CMD;
 167                break;
 168        case CFFPS_DEBUGFS_MAX_POWER_OUT:
 169                rc = i2c_smbus_read_word_swapped(psu->client,
 170                                                 CFFPS_MAX_POWER_OUT_CMD);
 171                if (rc < 0)
 172                        return rc;
 173
 174                rc = snprintf(data, I2C_SMBUS_BLOCK_MAX, "%d", rc);
 175                goto done;
 176        case CFFPS_DEBUGFS_CCIN:
 177                rc = i2c_smbus_read_word_swapped(psu->client, CFFPS_CCIN_CMD);
 178                if (rc < 0)
 179                        return rc;
 180
 181                rc = snprintf(data, 5, "%04X", rc);
 182                goto done;
 183        case CFFPS_DEBUGFS_FW:
 184                switch (psu->version) {
 185                case cffps1:
 186                        for (i = 0; i < CFFPS1_FW_NUM_BYTES; ++i) {
 187                                rc = i2c_smbus_read_byte_data(psu->client,
 188                                                              CFFPS_FW_CMD +
 189                                                                i);
 190                                if (rc < 0)
 191                                        return rc;
 192
 193                                snprintf(&data[i * 2], 3, "%02X", rc);
 194                        }
 195
 196                        rc = i * 2;
 197                        break;
 198                case cffps2:
 199                        for (i = 0; i < CFFPS2_FW_NUM_WORDS; ++i) {
 200                                rc = i2c_smbus_read_word_data(psu->client,
 201                                                              CFFPS_FW_CMD +
 202                                                                i);
 203                                if (rc < 0)
 204                                        return rc;
 205
 206                                snprintf(&data[i * 4], 5, "%04X", rc);
 207                        }
 208
 209                        rc = i * 4;
 210                        break;
 211                default:
 212                        return -EOPNOTSUPP;
 213                }
 214                goto done;
 215        case CFFPS_DEBUGFS_ON_OFF_CONFIG:
 216                rc = i2c_smbus_read_byte_data(psu->client,
 217                                              PMBUS_ON_OFF_CONFIG);
 218                if (rc < 0)
 219                        return rc;
 220
 221                rc = snprintf(data, 3, "%02x", rc);
 222                goto done;
 223        default:
 224                return -EINVAL;
 225        }
 226
 227        rc = i2c_smbus_read_block_data(psu->client, cmd, data);
 228        if (rc < 0)
 229                return rc;
 230
 231done:
 232        data[rc] = '\n';
 233        rc += 2;
 234
 235        return simple_read_from_buffer(buf, count, ppos, data, rc);
 236}
 237
 238static ssize_t ibm_cffps_debugfs_write(struct file *file,
 239                                       const char __user *buf, size_t count,
 240                                       loff_t *ppos)
 241{
 242        u8 data;
 243        ssize_t rc;
 244        int *idxp = file->private_data;
 245        int idx = *idxp;
 246        struct ibm_cffps *psu = to_psu(idxp, idx);
 247
 248        switch (idx) {
 249        case CFFPS_DEBUGFS_ON_OFF_CONFIG:
 250                pmbus_set_page(psu->client, 0);
 251
 252                rc = simple_write_to_buffer(&data, 1, ppos, buf, count);
 253                if (rc <= 0)
 254                        return rc;
 255
 256                rc = i2c_smbus_write_byte_data(psu->client,
 257                                               PMBUS_ON_OFF_CONFIG, data);
 258                if (rc)
 259                        return rc;
 260
 261                rc = 1;
 262                break;
 263        default:
 264                return -EINVAL;
 265        }
 266
 267        return rc;
 268}
 269
 270static const struct file_operations ibm_cffps_fops = {
 271        .llseek = noop_llseek,
 272        .read = ibm_cffps_debugfs_read,
 273        .write = ibm_cffps_debugfs_write,
 274        .open = simple_open,
 275};
 276
 277static int ibm_cffps_read_byte_data(struct i2c_client *client, int page,
 278                                    int reg)
 279{
 280        int rc, mfr;
 281
 282        switch (reg) {
 283        case PMBUS_STATUS_VOUT:
 284        case PMBUS_STATUS_IOUT:
 285        case PMBUS_STATUS_TEMPERATURE:
 286        case PMBUS_STATUS_FAN_12:
 287                rc = pmbus_read_byte_data(client, page, reg);
 288                if (rc < 0)
 289                        return rc;
 290
 291                mfr = pmbus_read_byte_data(client, page,
 292                                           PMBUS_STATUS_MFR_SPECIFIC);
 293                if (mfr < 0)
 294                        /*
 295                         * Return the status register instead of an error,
 296                         * since we successfully read status.
 297                         */
 298                        return rc;
 299
 300                /* Add MFR_SPECIFIC bits to the standard pmbus status regs. */
 301                if (reg == PMBUS_STATUS_FAN_12) {
 302                        if (mfr & CFFPS_MFR_FAN_FAULT)
 303                                rc |= PB_FAN_FAN1_FAULT;
 304                } else if (reg == PMBUS_STATUS_TEMPERATURE) {
 305                        if (mfr & CFFPS_MFR_THERMAL_FAULT)
 306                                rc |= PB_TEMP_OT_FAULT;
 307                } else if (reg == PMBUS_STATUS_VOUT) {
 308                        if (mfr & (CFFPS_MFR_OV_FAULT | CFFPS_MFR_VAUX_FAULT))
 309                                rc |= PB_VOLTAGE_OV_FAULT;
 310                        if (mfr & CFFPS_MFR_UV_FAULT)
 311                                rc |= PB_VOLTAGE_UV_FAULT;
 312                } else if (reg == PMBUS_STATUS_IOUT) {
 313                        if (mfr & CFFPS_MFR_OC_FAULT)
 314                                rc |= PB_IOUT_OC_FAULT;
 315                        if (mfr & CFFPS_MFR_CURRENT_SHARE_WARNING)
 316                                rc |= PB_CURRENT_SHARE_FAULT;
 317                }
 318                break;
 319        default:
 320                rc = -ENODATA;
 321                break;
 322        }
 323
 324        return rc;
 325}
 326
 327static int ibm_cffps_read_word_data(struct i2c_client *client, int page,
 328                                    int reg)
 329{
 330        int rc, mfr;
 331
 332        switch (reg) {
 333        case PMBUS_STATUS_WORD:
 334                rc = pmbus_read_word_data(client, page, reg);
 335                if (rc < 0)
 336                        return rc;
 337
 338                mfr = pmbus_read_byte_data(client, page,
 339                                           PMBUS_STATUS_MFR_SPECIFIC);
 340                if (mfr < 0)
 341                        /*
 342                         * Return the status register instead of an error,
 343                         * since we successfully read status.
 344                         */
 345                        return rc;
 346
 347                if (mfr & CFFPS_MFR_PS_KILL)
 348                        rc |= PB_STATUS_OFF;
 349                break;
 350        case PMBUS_VIRT_READ_VMON:
 351                rc = pmbus_read_word_data(client, page, CFFPS_12VCS_VOUT_CMD);
 352                break;
 353        default:
 354                rc = -ENODATA;
 355                break;
 356        }
 357
 358        return rc;
 359}
 360
 361static int ibm_cffps_led_brightness_set(struct led_classdev *led_cdev,
 362                                        enum led_brightness brightness)
 363{
 364        int rc;
 365        u8 next_led_state;
 366        struct ibm_cffps *psu = container_of(led_cdev, struct ibm_cffps, led);
 367
 368        if (brightness == LED_OFF) {
 369                next_led_state = CFFPS_LED_OFF;
 370        } else {
 371                brightness = LED_FULL;
 372
 373                if (psu->led_state != CFFPS_LED_BLINK)
 374                        next_led_state = CFFPS_LED_ON;
 375                else
 376                        next_led_state = CFFPS_LED_BLINK;
 377        }
 378
 379        dev_dbg(&psu->client->dev, "LED brightness set: %d. Command: %d.\n",
 380                brightness, next_led_state);
 381
 382        pmbus_set_page(psu->client, 0);
 383
 384        rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
 385                                       next_led_state);
 386        if (rc < 0)
 387                return rc;
 388
 389        psu->led_state = next_led_state;
 390        led_cdev->brightness = brightness;
 391
 392        return 0;
 393}
 394
 395static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev,
 396                                   unsigned long *delay_on,
 397                                   unsigned long *delay_off)
 398{
 399        int rc;
 400        struct ibm_cffps *psu = container_of(led_cdev, struct ibm_cffps, led);
 401
 402        dev_dbg(&psu->client->dev, "LED blink set.\n");
 403
 404        pmbus_set_page(psu->client, 0);
 405
 406        rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
 407                                       CFFPS_LED_BLINK);
 408        if (rc < 0)
 409                return rc;
 410
 411        psu->led_state = CFFPS_LED_BLINK;
 412        led_cdev->brightness = LED_FULL;
 413        *delay_on = CFFPS_BLINK_RATE_MS;
 414        *delay_off = CFFPS_BLINK_RATE_MS;
 415
 416        return 0;
 417}
 418
 419static void ibm_cffps_create_led_class(struct ibm_cffps *psu)
 420{
 421        int rc;
 422        struct i2c_client *client = psu->client;
 423        struct device *dev = &client->dev;
 424
 425        snprintf(psu->led_name, sizeof(psu->led_name), "%s-%02x", client->name,
 426                 client->addr);
 427        psu->led.name = psu->led_name;
 428        psu->led.max_brightness = LED_FULL;
 429        psu->led.brightness_set_blocking = ibm_cffps_led_brightness_set;
 430        psu->led.blink_set = ibm_cffps_led_blink_set;
 431
 432        rc = devm_led_classdev_register(dev, &psu->led);
 433        if (rc)
 434                dev_warn(dev, "failed to register led class: %d\n", rc);
 435        else
 436                i2c_smbus_write_byte_data(client, CFFPS_SYS_CONFIG_CMD,
 437                                          CFFPS_LED_OFF);
 438}
 439
 440static struct pmbus_driver_info ibm_cffps_info[] = {
 441        [cffps1] = {
 442                .pages = 1,
 443                .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
 444                        PMBUS_HAVE_PIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP |
 445                        PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
 446                        PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
 447                        PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP |
 448                        PMBUS_HAVE_STATUS_FAN12,
 449                .read_byte_data = ibm_cffps_read_byte_data,
 450                .read_word_data = ibm_cffps_read_word_data,
 451        },
 452        [cffps2] = {
 453                .pages = 2,
 454                .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
 455                        PMBUS_HAVE_PIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP |
 456                        PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
 457                        PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
 458                        PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP |
 459                        PMBUS_HAVE_STATUS_FAN12 | PMBUS_HAVE_VMON,
 460                .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
 461                        PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
 462                        PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT,
 463                .read_byte_data = ibm_cffps_read_byte_data,
 464                .read_word_data = ibm_cffps_read_word_data,
 465        },
 466};
 467
 468static struct pmbus_platform_data ibm_cffps_pdata = {
 469        .flags = PMBUS_SKIP_STATUS_CHECK,
 470};
 471
 472static int ibm_cffps_probe(struct i2c_client *client,
 473                           const struct i2c_device_id *id)
 474{
 475        int i, rc;
 476        enum versions vs = cffps_unknown;
 477        struct dentry *debugfs;
 478        struct dentry *ibm_cffps_dir;
 479        struct ibm_cffps *psu;
 480        const void *md = of_device_get_match_data(&client->dev);
 481
 482        if (md)
 483                vs = (enum versions)md;
 484        else if (id)
 485                vs = (enum versions)id->driver_data;
 486
 487        if (vs == cffps_unknown) {
 488                u16 ccin_version = CFFPS_CCIN_VERSION_1;
 489                int ccin = i2c_smbus_read_word_swapped(client, CFFPS_CCIN_CMD);
 490
 491                if (ccin > 0)
 492                        ccin_version = FIELD_GET(CFFPS_CCIN_VERSION, ccin);
 493
 494                switch (ccin_version) {
 495                default:
 496                case CFFPS_CCIN_VERSION_1:
 497                        vs = cffps1;
 498                        break;
 499                case CFFPS_CCIN_VERSION_2:
 500                        vs = cffps2;
 501                        break;
 502                }
 503
 504                /* Set the client name to include the version number. */
 505                snprintf(client->name, I2C_NAME_SIZE, "cffps%d", vs + 1);
 506        }
 507
 508        client->dev.platform_data = &ibm_cffps_pdata;
 509        rc = pmbus_do_probe(client, id, &ibm_cffps_info[vs]);
 510        if (rc)
 511                return rc;
 512
 513        /*
 514         * Don't fail the probe if there isn't enough memory for leds and
 515         * debugfs.
 516         */
 517        psu = devm_kzalloc(&client->dev, sizeof(*psu), GFP_KERNEL);
 518        if (!psu)
 519                return 0;
 520
 521        psu->version = vs;
 522        psu->client = client;
 523        mutex_init(&psu->input_history.update_lock);
 524        psu->input_history.last_update = jiffies - HZ;
 525
 526        ibm_cffps_create_led_class(psu);
 527
 528        /* Don't fail the probe if we can't create debugfs */
 529        debugfs = pmbus_get_debugfs_dir(client);
 530        if (!debugfs)
 531                return 0;
 532
 533        ibm_cffps_dir = debugfs_create_dir(client->name, debugfs);
 534        if (!ibm_cffps_dir)
 535                return 0;
 536
 537        for (i = 0; i < CFFPS_DEBUGFS_NUM_ENTRIES; ++i)
 538                psu->debugfs_entries[i] = i;
 539
 540        debugfs_create_file("input_history", 0444, ibm_cffps_dir,
 541                            &psu->debugfs_entries[CFFPS_DEBUGFS_INPUT_HISTORY],
 542                            &ibm_cffps_fops);
 543        debugfs_create_file("fru", 0444, ibm_cffps_dir,
 544                            &psu->debugfs_entries[CFFPS_DEBUGFS_FRU],
 545                            &ibm_cffps_fops);
 546        debugfs_create_file("part_number", 0444, ibm_cffps_dir,
 547                            &psu->debugfs_entries[CFFPS_DEBUGFS_PN],
 548                            &ibm_cffps_fops);
 549        debugfs_create_file("header", 0444, ibm_cffps_dir,
 550                            &psu->debugfs_entries[CFFPS_DEBUGFS_HEADER],
 551                            &ibm_cffps_fops);
 552        debugfs_create_file("serial_number", 0444, ibm_cffps_dir,
 553                            &psu->debugfs_entries[CFFPS_DEBUGFS_SN],
 554                            &ibm_cffps_fops);
 555        debugfs_create_file("max_power_out", 0444, ibm_cffps_dir,
 556                            &psu->debugfs_entries[CFFPS_DEBUGFS_MAX_POWER_OUT],
 557                            &ibm_cffps_fops);
 558        debugfs_create_file("ccin", 0444, ibm_cffps_dir,
 559                            &psu->debugfs_entries[CFFPS_DEBUGFS_CCIN],
 560                            &ibm_cffps_fops);
 561        debugfs_create_file("fw_version", 0444, ibm_cffps_dir,
 562                            &psu->debugfs_entries[CFFPS_DEBUGFS_FW],
 563                            &ibm_cffps_fops);
 564        debugfs_create_file("on_off_config", 0644, ibm_cffps_dir,
 565                            &psu->debugfs_entries[CFFPS_DEBUGFS_ON_OFF_CONFIG],
 566                            &ibm_cffps_fops);
 567
 568        return 0;
 569}
 570
 571static const struct i2c_device_id ibm_cffps_id[] = {
 572        { "ibm_cffps1", cffps1 },
 573        { "ibm_cffps2", cffps2 },
 574        { "ibm_cffps", cffps_unknown },
 575        {}
 576};
 577MODULE_DEVICE_TABLE(i2c, ibm_cffps_id);
 578
 579static const struct of_device_id ibm_cffps_of_match[] = {
 580        {
 581                .compatible = "ibm,cffps1",
 582                .data = (void *)cffps1
 583        },
 584        {
 585                .compatible = "ibm,cffps2",
 586                .data = (void *)cffps2
 587        },
 588        {
 589                .compatible = "ibm,cffps",
 590                .data = (void *)cffps_unknown
 591        },
 592        {}
 593};
 594MODULE_DEVICE_TABLE(of, ibm_cffps_of_match);
 595
 596static struct i2c_driver ibm_cffps_driver = {
 597        .driver = {
 598                .name = "ibm-cffps",
 599                .of_match_table = ibm_cffps_of_match,
 600        },
 601        .probe = ibm_cffps_probe,
 602        .remove = pmbus_do_remove,
 603        .id_table = ibm_cffps_id,
 604};
 605
 606module_i2c_driver(ibm_cffps_driver);
 607
 608MODULE_AUTHOR("Eddie James");
 609MODULE_DESCRIPTION("PMBus driver for IBM Common Form Factor power supplies");
 610MODULE_LICENSE("GPL");
 611