linux/drivers/hwmon/pmbus/ir35221.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Hardware monitoring driver for IR35221
   4 *
   5 * Copyright (C) IBM Corporation 2017.
   6 */
   7
   8#include <linux/err.h>
   9#include <linux/i2c.h>
  10#include <linux/init.h>
  11#include <linux/kernel.h>
  12#include <linux/module.h>
  13#include "pmbus.h"
  14
  15#define IR35221_MFR_VIN_PEAK            0xc5
  16#define IR35221_MFR_VOUT_PEAK           0xc6
  17#define IR35221_MFR_IOUT_PEAK           0xc7
  18#define IR35221_MFR_TEMP_PEAK           0xc8
  19#define IR35221_MFR_VIN_VALLEY          0xc9
  20#define IR35221_MFR_VOUT_VALLEY         0xca
  21#define IR35221_MFR_IOUT_VALLEY         0xcb
  22#define IR35221_MFR_TEMP_VALLEY         0xcc
  23
  24static int ir35221_read_word_data(struct i2c_client *client, int page, int reg)
  25{
  26        int ret;
  27
  28        switch (reg) {
  29        case PMBUS_VIRT_READ_VIN_MAX:
  30                ret = pmbus_read_word_data(client, page, IR35221_MFR_VIN_PEAK);
  31                break;
  32        case PMBUS_VIRT_READ_VOUT_MAX:
  33                ret = pmbus_read_word_data(client, page, IR35221_MFR_VOUT_PEAK);
  34                break;
  35        case PMBUS_VIRT_READ_IOUT_MAX:
  36                ret = pmbus_read_word_data(client, page, IR35221_MFR_IOUT_PEAK);
  37                break;
  38        case PMBUS_VIRT_READ_TEMP_MAX:
  39                ret = pmbus_read_word_data(client, page, IR35221_MFR_TEMP_PEAK);
  40                break;
  41        case PMBUS_VIRT_READ_VIN_MIN:
  42                ret = pmbus_read_word_data(client, page,
  43                                           IR35221_MFR_VIN_VALLEY);
  44                break;
  45        case PMBUS_VIRT_READ_VOUT_MIN:
  46                ret = pmbus_read_word_data(client, page,
  47                                           IR35221_MFR_VOUT_VALLEY);
  48                break;
  49        case PMBUS_VIRT_READ_IOUT_MIN:
  50                ret = pmbus_read_word_data(client, page,
  51                                           IR35221_MFR_IOUT_VALLEY);
  52                break;
  53        case PMBUS_VIRT_READ_TEMP_MIN:
  54                ret = pmbus_read_word_data(client, page,
  55                                           IR35221_MFR_TEMP_VALLEY);
  56                break;
  57        default:
  58                ret = -ENODATA;
  59                break;
  60        }
  61
  62        return ret;
  63}
  64
  65static int ir35221_probe(struct i2c_client *client,
  66                         const struct i2c_device_id *id)
  67{
  68        struct pmbus_driver_info *info;
  69        u8 buf[I2C_SMBUS_BLOCK_MAX];
  70        int ret;
  71
  72        if (!i2c_check_functionality(client->adapter,
  73                                     I2C_FUNC_SMBUS_READ_BYTE_DATA
  74                                | I2C_FUNC_SMBUS_READ_WORD_DATA
  75                                | I2C_FUNC_SMBUS_READ_BLOCK_DATA))
  76                return -ENODEV;
  77
  78        ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
  79        if (ret < 0) {
  80                dev_err(&client->dev, "Failed to read PMBUS_MFR_ID\n");
  81                return ret;
  82        }
  83        if (ret != 2 || strncmp(buf, "RI", strlen("RI"))) {
  84                dev_err(&client->dev, "MFR_ID unrecognised\n");
  85                return -ENODEV;
  86        }
  87
  88        ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
  89        if (ret < 0) {
  90                dev_err(&client->dev, "Failed to read PMBUS_MFR_MODEL\n");
  91                return ret;
  92        }
  93        if (ret != 2 || !(buf[0] == 0x6c && buf[1] == 0x00)) {
  94                dev_err(&client->dev, "MFR_MODEL unrecognised\n");
  95                return -ENODEV;
  96        }
  97
  98        info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info),
  99                            GFP_KERNEL);
 100        if (!info)
 101                return -ENOMEM;
 102
 103        info->read_word_data = ir35221_read_word_data;
 104
 105        info->pages = 2;
 106        info->format[PSC_VOLTAGE_IN] = linear;
 107        info->format[PSC_VOLTAGE_OUT] = linear;
 108        info->format[PSC_CURRENT_IN] = linear;
 109        info->format[PSC_CURRENT_OUT] = linear;
 110        info->format[PSC_POWER] = linear;
 111        info->format[PSC_TEMPERATURE] = linear;
 112
 113        info->func[0] = PMBUS_HAVE_VIN
 114                | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
 115                | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
 116                | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
 117                | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
 118                | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP;
 119        info->func[1] = info->func[0];
 120
 121        return pmbus_do_probe(client, id, info);
 122}
 123
 124static const struct i2c_device_id ir35221_id[] = {
 125        {"ir35221", 0},
 126        {}
 127};
 128
 129MODULE_DEVICE_TABLE(i2c, ir35221_id);
 130
 131static struct i2c_driver ir35221_driver = {
 132        .driver = {
 133                .name   = "ir35221",
 134        },
 135        .probe          = ir35221_probe,
 136        .remove         = pmbus_do_remove,
 137        .id_table       = ir35221_id,
 138};
 139
 140module_i2c_driver(ir35221_driver);
 141
 142MODULE_AUTHOR("Samuel Mendoza-Jonas <sam@mendozajonas.com");
 143MODULE_DESCRIPTION("PMBus driver for IR35221");
 144MODULE_LICENSE("GPL");
 145