^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 LTC3815
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2015 Linear Technology
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (c) 2015 Guenter Roeck
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/jiffies.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "pmbus.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define LTC3815_MFR_IOUT_PEAK 0xd7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define LTC3815_MFR_VOUT_PEAK 0xdd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define LTC3815_MFR_VIN_PEAK 0xde
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define LTC3815_MFR_TEMP_PEAK 0xdf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define LTC3815_MFR_IIN_PEAK 0xe1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define LTC3815_MFR_SPECIAL_ID 0xe7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define LTC3815_ID 0x8000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define LTC3815_ID_MASK 0xff00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static int ltc3815_read_byte_data(struct i2c_client *client, int page, int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) case PMBUS_VOUT_MODE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * The chip returns 0x3e, suggesting VID mode with manufacturer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * specific VID codes. Since the output voltage is reported
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * with a LSB of 0.5mV, override and report direct mode with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * appropriate coefficients.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) ret = 0x40;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) ret = -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static int ltc3815_write_byte(struct i2c_client *client, int page, u8 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) case PMBUS_CLEAR_FAULTS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * LTC3815 does not support the CLEAR_FAULTS command.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * Emulate it by clearing the status register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) ret = pmbus_read_word_data(client, 0, 0xff, PMBUS_STATUS_WORD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (ret > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) pmbus_write_word_data(client, 0, PMBUS_STATUS_WORD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) ret = -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static int ltc3815_read_word_data(struct i2c_client *client, int page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) int phase, int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) case PMBUS_VIRT_READ_VIN_MAX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) ret = pmbus_read_word_data(client, page, phase,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) LTC3815_MFR_VIN_PEAK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) case PMBUS_VIRT_READ_VOUT_MAX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) ret = pmbus_read_word_data(client, page, phase,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) LTC3815_MFR_VOUT_PEAK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) case PMBUS_VIRT_READ_TEMP_MAX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) ret = pmbus_read_word_data(client, page, phase,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) LTC3815_MFR_TEMP_PEAK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) case PMBUS_VIRT_READ_IOUT_MAX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) ret = pmbus_read_word_data(client, page, phase,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) LTC3815_MFR_IOUT_PEAK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) case PMBUS_VIRT_READ_IIN_MAX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ret = pmbus_read_word_data(client, page, phase,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) LTC3815_MFR_IIN_PEAK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) case PMBUS_VIRT_RESET_VOUT_HISTORY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) case PMBUS_VIRT_RESET_VIN_HISTORY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) case PMBUS_VIRT_RESET_TEMP_HISTORY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) case PMBUS_VIRT_RESET_IOUT_HISTORY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) case PMBUS_VIRT_RESET_IIN_HISTORY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) ret = -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static int ltc3815_write_word_data(struct i2c_client *client, int page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) int reg, u16 word)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) switch (reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) case PMBUS_VIRT_RESET_IIN_HISTORY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) ret = pmbus_write_word_data(client, page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) LTC3815_MFR_IIN_PEAK, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) case PMBUS_VIRT_RESET_IOUT_HISTORY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) ret = pmbus_write_word_data(client, page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) LTC3815_MFR_IOUT_PEAK, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) case PMBUS_VIRT_RESET_VOUT_HISTORY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) ret = pmbus_write_word_data(client, page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) LTC3815_MFR_VOUT_PEAK, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) case PMBUS_VIRT_RESET_VIN_HISTORY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) ret = pmbus_write_word_data(client, page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) LTC3815_MFR_VIN_PEAK, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) case PMBUS_VIRT_RESET_TEMP_HISTORY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) ret = pmbus_write_word_data(client, page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) LTC3815_MFR_TEMP_PEAK, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) ret = -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static const struct i2c_device_id ltc3815_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {"ltc3815", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) MODULE_DEVICE_TABLE(i2c, ltc3815_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) static struct pmbus_driver_info ltc3815_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) .pages = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) .format[PSC_VOLTAGE_IN] = direct,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) .format[PSC_VOLTAGE_OUT] = direct,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) .format[PSC_CURRENT_IN] = direct,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) .format[PSC_CURRENT_OUT] = direct,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) .format[PSC_TEMPERATURE] = direct,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) .m[PSC_VOLTAGE_IN] = 250,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) .b[PSC_VOLTAGE_IN] = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .R[PSC_VOLTAGE_IN] = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) .m[PSC_VOLTAGE_OUT] = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) .b[PSC_VOLTAGE_OUT] = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) .R[PSC_VOLTAGE_OUT] = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) .m[PSC_CURRENT_IN] = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) .b[PSC_CURRENT_IN] = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) .R[PSC_CURRENT_IN] = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) .m[PSC_CURRENT_OUT] = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .b[PSC_CURRENT_OUT] = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) .R[PSC_CURRENT_OUT] = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) .m[PSC_TEMPERATURE] = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) .b[PSC_TEMPERATURE] = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) .R[PSC_TEMPERATURE] = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_VOUT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .read_byte_data = ltc3815_read_byte_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .read_word_data = ltc3815_read_word_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) .write_byte = ltc3815_write_byte,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) .write_word_data = ltc3815_write_word_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static int ltc3815_probe(struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) int chip_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) if (!i2c_check_functionality(client->adapter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) I2C_FUNC_SMBUS_READ_WORD_DATA))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) chip_id = i2c_smbus_read_word_data(client, LTC3815_MFR_SPECIAL_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (chip_id < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return chip_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if ((chip_id & LTC3815_ID_MASK) != LTC3815_ID)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return pmbus_do_probe(client, <c3815_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) static struct i2c_driver ltc3815_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) .name = "ltc3815",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) .probe_new = ltc3815_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) .remove = pmbus_do_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) .id_table = ltc3815_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) module_i2c_driver(ltc3815_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) MODULE_AUTHOR("Guenter Roeck");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) MODULE_DESCRIPTION("PMBus driver for LTC3815");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) MODULE_LICENSE("GPL");