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