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,
  25                                  int phase, int reg)
  26{
  27        int ret;
  28
  29        switch (reg) {
  30        case PMBUS_VIRT_READ_VIN_MAX:
  31                ret = pmbus_read_word_data(client, page, phase,
  32                                           IR35221_MFR_VIN_PEAK);
  33                break;
  34        case PMBUS_VIRT_READ_VOUT_MAX:
  35                ret = pmbus_read_word_data(client, page, phase,
  36                                           IR35221_MFR_VOUT_PEAK);
  37                break;
  38        case PMBUS_VIRT_READ_IOUT_MAX:
  39                ret = pmbus_read_word_data(client, page, phase,
  40                                           IR35221_MFR_IOUT_PEAK);
  41                break;
  42        case PMBUS_VIRT_READ_TEMP_MAX:
  43                ret = pmbus_read_word_data(client, page, phase,
  44                                           IR35221_MFR_TEMP_PEAK);
  45                break;
  46        case PMBUS_VIRT_READ_VIN_MIN:
  47                ret = pmbus_read_word_data(client, page, phase,
  48                                           IR35221_MFR_VIN_VALLEY);
  49                break;
  50        case PMBUS_VIRT_READ_VOUT_MIN:
  51                ret = pmbus_read_word_data(client, page, phase,
  52                                           IR35221_MFR_VOUT_VALLEY);
  53                break;
  54        case PMBUS_VIRT_READ_IOUT_MIN:
  55                ret = pmbus_read_word_data(client, page, phase,
  56                                           IR35221_MFR_IOUT_VALLEY);
  57                break;
  58        case PMBUS_VIRT_READ_TEMP_MIN:
  59                ret = pmbus_read_word_data(client, page, phase,
  60                                           IR35221_MFR_TEMP_VALLEY);
  61                break;
  62        default:
  63                ret = -ENODATA;
  64                break;
  65        }
  66
  67        return ret;
  68}
  69
  70static int ir35221_probe(struct i2c_client *client)
  71{
  72        struct pmbus_driver_info *info;
  73        u8 buf[I2C_SMBUS_BLOCK_MAX];
  74        int ret;
  75
  76        if (!i2c_check_functionality(client->adapter,
  77                                     I2C_FUNC_SMBUS_READ_BYTE_DATA
  78                                | I2C_FUNC_SMBUS_READ_WORD_DATA
  79                                | I2C_FUNC_SMBUS_READ_BLOCK_DATA))
  80                return -ENODEV;
  81
  82        ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
  83        if (ret < 0) {
  84                dev_err(&client->dev, "Failed to read PMBUS_MFR_ID\n");
  85                return ret;
  86        }
  87        if (ret != 2 || strncmp(buf, "RI", strlen("RI"))) {
  88                dev_err(&client->dev, "MFR_ID unrecognised\n");
  89                return -ENODEV;
  90        }
  91
  92        ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
  93        if (ret < 0) {
  94                dev_err(&client->dev, "Failed to read PMBUS_MFR_MODEL\n");
  95                return ret;
  96        }
  97        if (ret != 2 || !(buf[0] == 0x6c && buf[1] == 0x00)) {
  98                dev_err(&client->dev, "MFR_MODEL unrecognised\n");
  99                return -ENODEV;
 100        }
 101
 102        info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info),
 103                            GFP_KERNEL);
 104        if (!info)
 105                return -ENOMEM;
 106
 107        info->read_word_data = ir35221_read_word_data;
 108
 109        info->pages = 2;
 110        info->format[PSC_VOLTAGE_IN] = linear;
 111        info->format[PSC_VOLTAGE_OUT] = linear;
 112        info->format[PSC_CURRENT_IN] = linear;
 113        info->format[PSC_CURRENT_OUT] = linear;
 114        info->format[PSC_POWER] = linear;
 115        info->format[PSC_TEMPERATURE] = linear;
 116
 117        info->func[0] = PMBUS_HAVE_VIN
 118                | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
 119                | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
 120                | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
 121                | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
 122                | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP;
 123        info->func[1] = info->func[0];
 124
 125        return pmbus_do_probe(client, info);
 126}
 127
 128static const struct i2c_device_id ir35221_id[] = {
 129        {"ir35221", 0},
 130        {}
 131};
 132
 133MODULE_DEVICE_TABLE(i2c, ir35221_id);
 134
 135static struct i2c_driver ir35221_driver = {
 136        .driver = {
 137                .name   = "ir35221",
 138        },
 139        .probe_new      = ir35221_probe,
 140        .remove         = pmbus_do_remove,
 141        .id_table       = ir35221_id,
 142};
 143
 144module_i2c_driver(ir35221_driver);
 145
 146MODULE_AUTHOR("Samuel Mendoza-Jonas <sam@mendozajonas.com");
 147MODULE_DESCRIPTION("PMBus driver for IR35221");
 148MODULE_LICENSE("GPL");
 149