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