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, 0xff, 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, 73 int phase, int reg) 74 { 75 int ret; 76 77 switch (reg) { 78 case PMBUS_VIRT_READ_VIN_MAX: 79 ret = pmbus_read_word_data(client, page, phase, 80 LTC3815_MFR_VIN_PEAK); 81 break; 82 case PMBUS_VIRT_READ_VOUT_MAX: 83 ret = pmbus_read_word_data(client, page, phase, 84 LTC3815_MFR_VOUT_PEAK); 85 break; 86 case PMBUS_VIRT_READ_TEMP_MAX: 87 ret = pmbus_read_word_data(client, page, phase, 88 LTC3815_MFR_TEMP_PEAK); 89 break; 90 case PMBUS_VIRT_READ_IOUT_MAX: 91 ret = pmbus_read_word_data(client, page, phase, 92 LTC3815_MFR_IOUT_PEAK); 93 break; 94 case PMBUS_VIRT_READ_IIN_MAX: 95 ret = pmbus_read_word_data(client, page, phase, 96 LTC3815_MFR_IIN_PEAK); 97 break; 98 case PMBUS_VIRT_RESET_VOUT_HISTORY: 99 case PMBUS_VIRT_RESET_VIN_HISTORY: 100 case PMBUS_VIRT_RESET_TEMP_HISTORY: 101 case PMBUS_VIRT_RESET_IOUT_HISTORY: 102 case PMBUS_VIRT_RESET_IIN_HISTORY: 103 ret = 0; 104 break; 105 default: 106 ret = -ENODATA; 107 break; 108 } 109 return ret; 110 } 111 112 static int ltc3815_write_word_data(struct i2c_client *client, int page, 113 int reg, u16 word) 114 { 115 int ret; 116 117 switch (reg) { 118 case PMBUS_VIRT_RESET_IIN_HISTORY: 119 ret = pmbus_write_word_data(client, page, 120 LTC3815_MFR_IIN_PEAK, 0); 121 break; 122 case PMBUS_VIRT_RESET_IOUT_HISTORY: 123 ret = pmbus_write_word_data(client, page, 124 LTC3815_MFR_IOUT_PEAK, 0); 125 break; 126 case PMBUS_VIRT_RESET_VOUT_HISTORY: 127 ret = pmbus_write_word_data(client, page, 128 LTC3815_MFR_VOUT_PEAK, 0); 129 break; 130 case PMBUS_VIRT_RESET_VIN_HISTORY: 131 ret = pmbus_write_word_data(client, page, 132 LTC3815_MFR_VIN_PEAK, 0); 133 break; 134 case PMBUS_VIRT_RESET_TEMP_HISTORY: 135 ret = pmbus_write_word_data(client, page, 136 LTC3815_MFR_TEMP_PEAK, 0); 137 break; 138 default: 139 ret = -ENODATA; 140 break; 141 } 142 return ret; 143 } 144 145 static const struct i2c_device_id ltc3815_id[] = { 146 {"ltc3815", 0}, 147 { } 148 }; 149 MODULE_DEVICE_TABLE(i2c, ltc3815_id); 150 151 static struct pmbus_driver_info ltc3815_info = { 152 .pages = 1, 153 .format[PSC_VOLTAGE_IN] = direct, 154 .format[PSC_VOLTAGE_OUT] = direct, 155 .format[PSC_CURRENT_IN] = direct, 156 .format[PSC_CURRENT_OUT] = direct, 157 .format[PSC_TEMPERATURE] = direct, 158 .m[PSC_VOLTAGE_IN] = 250, 159 .b[PSC_VOLTAGE_IN] = 0, 160 .R[PSC_VOLTAGE_IN] = 0, 161 .m[PSC_VOLTAGE_OUT] = 2, 162 .b[PSC_VOLTAGE_OUT] = 0, 163 .R[PSC_VOLTAGE_OUT] = 3, 164 .m[PSC_CURRENT_IN] = 1, 165 .b[PSC_CURRENT_IN] = 0, 166 .R[PSC_CURRENT_IN] = 2, 167 .m[PSC_CURRENT_OUT] = 1, 168 .b[PSC_CURRENT_OUT] = 0, 169 .R[PSC_CURRENT_OUT] = 2, 170 .m[PSC_TEMPERATURE] = 1, 171 .b[PSC_TEMPERATURE] = 0, 172 .R[PSC_TEMPERATURE] = 0, 173 .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_VOUT | 174 PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP, 175 .read_byte_data = ltc3815_read_byte_data, 176 .read_word_data = ltc3815_read_word_data, 177 .write_byte = ltc3815_write_byte, 178 .write_word_data = ltc3815_write_word_data, 179 }; 180 181 static int ltc3815_probe(struct i2c_client *client, 182 const struct i2c_device_id *id) 183 { 184 int chip_id; 185 186 if (!i2c_check_functionality(client->adapter, 187 I2C_FUNC_SMBUS_READ_WORD_DATA)) 188 return -ENODEV; 189 190 chip_id = i2c_smbus_read_word_data(client, LTC3815_MFR_SPECIAL_ID); 191 if (chip_id < 0) 192 return chip_id; 193 if ((chip_id & LTC3815_ID_MASK) != LTC3815_ID) 194 return -ENODEV; 195 196 return pmbus_do_probe(client, id, <c3815_info); 197 } 198 199 static struct i2c_driver ltc3815_driver = { 200 .driver = { 201 .name = "ltc3815", 202 }, 203 .probe = ltc3815_probe, 204 .remove = pmbus_do_remove, 205 .id_table = ltc3815_id, 206 }; 207 208 module_i2c_driver(ltc3815_driver); 209 210 MODULE_AUTHOR("Guenter Roeck"); 211 MODULE_DESCRIPTION("PMBus driver for LTC3815"); 212 MODULE_LICENSE("GPL"); 213