ltc3815.c (5065B)
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 27static 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 48static 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 72static 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 112static 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 145static const struct i2c_device_id ltc3815_id[] = { 146 {"ltc3815", 0}, 147 { } 148}; 149MODULE_DEVICE_TABLE(i2c, ltc3815_id); 150 151static 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 181static int ltc3815_probe(struct i2c_client *client) 182{ 183 int chip_id; 184 185 if (!i2c_check_functionality(client->adapter, 186 I2C_FUNC_SMBUS_READ_WORD_DATA)) 187 return -ENODEV; 188 189 chip_id = i2c_smbus_read_word_data(client, LTC3815_MFR_SPECIAL_ID); 190 if (chip_id < 0) 191 return chip_id; 192 if ((chip_id & LTC3815_ID_MASK) != LTC3815_ID) 193 return -ENODEV; 194 195 return pmbus_do_probe(client, <c3815_info); 196} 197 198static struct i2c_driver ltc3815_driver = { 199 .driver = { 200 .name = "ltc3815", 201 }, 202 .probe_new = ltc3815_probe, 203 .id_table = ltc3815_id, 204}; 205 206module_i2c_driver(ltc3815_driver); 207 208MODULE_AUTHOR("Guenter Roeck"); 209MODULE_DESCRIPTION("PMBus driver for LTC3815"); 210MODULE_LICENSE("GPL"); 211MODULE_IMPORT_NS(PMBUS);