Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Hardware monitoring driver for IR35221
0004  *
0005  * Copyright (C) IBM Corporation 2017.
0006  */
0007 
0008 #include <linux/err.h>
0009 #include <linux/i2c.h>
0010 #include <linux/init.h>
0011 #include <linux/kernel.h>
0012 #include <linux/module.h>
0013 #include "pmbus.h"
0014 
0015 #define IR35221_MFR_VIN_PEAK        0xc5
0016 #define IR35221_MFR_VOUT_PEAK       0xc6
0017 #define IR35221_MFR_IOUT_PEAK       0xc7
0018 #define IR35221_MFR_TEMP_PEAK       0xc8
0019 #define IR35221_MFR_VIN_VALLEY      0xc9
0020 #define IR35221_MFR_VOUT_VALLEY     0xca
0021 #define IR35221_MFR_IOUT_VALLEY     0xcb
0022 #define IR35221_MFR_TEMP_VALLEY     0xcc
0023 
0024 static int ir35221_read_word_data(struct i2c_client *client, int page,
0025                   int phase, int reg)
0026 {
0027     int ret;
0028 
0029     switch (reg) {
0030     case PMBUS_VIRT_READ_VIN_MAX:
0031         ret = pmbus_read_word_data(client, page, phase,
0032                        IR35221_MFR_VIN_PEAK);
0033         break;
0034     case PMBUS_VIRT_READ_VOUT_MAX:
0035         ret = pmbus_read_word_data(client, page, phase,
0036                        IR35221_MFR_VOUT_PEAK);
0037         break;
0038     case PMBUS_VIRT_READ_IOUT_MAX:
0039         ret = pmbus_read_word_data(client, page, phase,
0040                        IR35221_MFR_IOUT_PEAK);
0041         break;
0042     case PMBUS_VIRT_READ_TEMP_MAX:
0043         ret = pmbus_read_word_data(client, page, phase,
0044                        IR35221_MFR_TEMP_PEAK);
0045         break;
0046     case PMBUS_VIRT_READ_VIN_MIN:
0047         ret = pmbus_read_word_data(client, page, phase,
0048                        IR35221_MFR_VIN_VALLEY);
0049         break;
0050     case PMBUS_VIRT_READ_VOUT_MIN:
0051         ret = pmbus_read_word_data(client, page, phase,
0052                        IR35221_MFR_VOUT_VALLEY);
0053         break;
0054     case PMBUS_VIRT_READ_IOUT_MIN:
0055         ret = pmbus_read_word_data(client, page, phase,
0056                        IR35221_MFR_IOUT_VALLEY);
0057         break;
0058     case PMBUS_VIRT_READ_TEMP_MIN:
0059         ret = pmbus_read_word_data(client, page, phase,
0060                        IR35221_MFR_TEMP_VALLEY);
0061         break;
0062     default:
0063         ret = -ENODATA;
0064         break;
0065     }
0066 
0067     return ret;
0068 }
0069 
0070 static int ir35221_probe(struct i2c_client *client)
0071 {
0072     struct pmbus_driver_info *info;
0073     u8 buf[I2C_SMBUS_BLOCK_MAX];
0074     int ret;
0075 
0076     if (!i2c_check_functionality(client->adapter,
0077                      I2C_FUNC_SMBUS_READ_BYTE_DATA
0078                 | I2C_FUNC_SMBUS_READ_WORD_DATA
0079                 | I2C_FUNC_SMBUS_READ_BLOCK_DATA))
0080         return -ENODEV;
0081 
0082     ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
0083     if (ret < 0) {
0084         dev_err(&client->dev, "Failed to read PMBUS_MFR_ID\n");
0085         return ret;
0086     }
0087     if (ret != 2 || strncmp(buf, "RI", strlen("RI"))) {
0088         dev_err(&client->dev, "MFR_ID unrecognised\n");
0089         return -ENODEV;
0090     }
0091 
0092     ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
0093     if (ret < 0) {
0094         dev_err(&client->dev, "Failed to read PMBUS_MFR_MODEL\n");
0095         return ret;
0096     }
0097     if (ret != 2 || !(buf[0] == 0x6c && buf[1] == 0x00)) {
0098         dev_err(&client->dev, "MFR_MODEL unrecognised\n");
0099         return -ENODEV;
0100     }
0101 
0102     info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info),
0103                 GFP_KERNEL);
0104     if (!info)
0105         return -ENOMEM;
0106 
0107     info->read_word_data = ir35221_read_word_data;
0108 
0109     info->pages = 2;
0110     info->format[PSC_VOLTAGE_IN] = linear;
0111     info->format[PSC_VOLTAGE_OUT] = linear;
0112     info->format[PSC_CURRENT_IN] = linear;
0113     info->format[PSC_CURRENT_OUT] = linear;
0114     info->format[PSC_POWER] = linear;
0115     info->format[PSC_TEMPERATURE] = linear;
0116 
0117     info->func[0] = PMBUS_HAVE_VIN
0118         | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
0119         | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
0120         | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
0121         | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
0122         | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP;
0123     info->func[1] = info->func[0];
0124 
0125     return pmbus_do_probe(client, info);
0126 }
0127 
0128 static const struct i2c_device_id ir35221_id[] = {
0129     {"ir35221", 0},
0130     {}
0131 };
0132 
0133 MODULE_DEVICE_TABLE(i2c, ir35221_id);
0134 
0135 static struct i2c_driver ir35221_driver = {
0136     .driver = {
0137         .name   = "ir35221",
0138     },
0139     .probe_new  = ir35221_probe,
0140     .id_table   = ir35221_id,
0141 };
0142 
0143 module_i2c_driver(ir35221_driver);
0144 
0145 MODULE_AUTHOR("Samuel Mendoza-Jonas <sam@mendozajonas.com");
0146 MODULE_DESCRIPTION("PMBus driver for IR35221");
0147 MODULE_LICENSE("GPL");
0148 MODULE_IMPORT_NS(PMBUS);