1c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck/* 2ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck * Hardware monitoring driver for LTC2978 and LTC3880 3c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * 4c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * Copyright (c) 2011 Ericsson AB. 5c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * 6c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * This program is free software; you can redistribute it and/or modify 7c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * it under the terms of the GNU General Public License as published by 8c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * the Free Software Foundation; either version 2 of the License, or 9c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * (at your option) any later version. 10c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * 11c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * This program is distributed in the hope that it will be useful, 12c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * but WITHOUT ANY WARRANTY; without even the implied warranty of 13c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * GNU General Public License for more details. 15c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * 16c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * You should have received a copy of the GNU General Public License 17c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * along with this program; if not, write to the Free Software 18c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck */ 20c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 21c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#include <linux/kernel.h> 22c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#include <linux/module.h> 23c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#include <linux/init.h> 24c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#include <linux/err.h> 25c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#include <linux/slab.h> 26c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#include <linux/i2c.h> 27c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#include "pmbus.h" 28c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 29ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeckenum chips { ltc2978, ltc3880 }; 30c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 31ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck/* LTC2978 and LTC3880 */ 32c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_MFR_VOUT_PEAK 0xdd 33c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_MFR_VIN_PEAK 0xde 34c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_MFR_TEMPERATURE_PEAK 0xdf 35c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_MFR_SPECIAL_ID 0xe7 36c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 37ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck/* LTC2978 only */ 38c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_MFR_VOUT_MIN 0xfb 39c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_MFR_VIN_MIN 0xfc 40c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_MFR_TEMPERATURE_MIN 0xfd 41c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 42ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck/* LTC3880 only */ 43ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck#define LTC3880_MFR_IOUT_PEAK 0xd7 44ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck#define LTC3880_MFR_CLEAR_PEAKS 0xe3 45ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck#define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 46ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck 47c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_ID_REV1 0x0121 48c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define LTC2978_ID_REV2 0x0122 49ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck#define LTC3880_ID 0x4000 50ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck#define LTC3880_ID_MASK 0xff00 51c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 52c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck/* 53c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which 54c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * happens pretty much each time chip data is updated. Raw peak data therefore 55c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * does not provide much value. To be able to provide useful peak data, keep an 56c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * internal cache of measured peak data, which is only cleared if an explicit 57c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * "clear peak" command is executed for the sensor in question. 58c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck */ 59c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeckstruct ltc2978_data { 60c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck enum chips id; 61c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck int vin_min, vin_max; 62c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck int temp_min, temp_max; 63c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck int vout_min[8], vout_max[8]; 64ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck int iout_max[2]; 65ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck int temp2_max[2]; 66c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck struct pmbus_driver_info info; 67c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck}; 68c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 69c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck#define to_ltc2978_data(x) container_of(x, struct ltc2978_data, info) 70c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 71c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeckstatic inline int lin11_to_val(int data) 72c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck{ 73c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck s16 e = ((s16)data) >> 11; 74c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck s32 m = (((s16)(data << 5)) >> 5); 75c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 76c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck /* 77c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * mantissa is 10 bit + sign, exponent adds up to 15 bit. 78c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * Add 6 bit to exponent for maximum accuracy (10 + 15 + 6 = 31). 79c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck */ 80c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck e += 6; 81c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck return (e < 0 ? m >> -e : m << e); 82c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck} 83c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 84ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeckstatic int ltc2978_read_word_data_common(struct i2c_client *client, int page, 85ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck int reg) 86c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck{ 87c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 88c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck struct ltc2978_data *data = to_ltc2978_data(info); 89c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck int ret; 90c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 91c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck switch (reg) { 92c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck case PMBUS_VIRT_READ_VIN_MAX: 93c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_PEAK); 94c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (ret >= 0) { 95c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (lin11_to_val(ret) > lin11_to_val(data->vin_max)) 96c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->vin_max = ret; 97c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck ret = data->vin_max; 98c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck } 99c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck break; 100c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck case PMBUS_VIRT_READ_VOUT_MAX: 101c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_PEAK); 102c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (ret >= 0) { 103c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck /* 104c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * VOUT is 16 bit unsigned with fixed exponent, 105c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * so we can compare it directly 106c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck */ 107c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (ret > data->vout_max[page]) 108c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->vout_max[page] = ret; 109c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck ret = data->vout_max[page]; 110c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck } 111c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck break; 112c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck case PMBUS_VIRT_READ_TEMP_MAX: 113c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck ret = pmbus_read_word_data(client, page, 114c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck LTC2978_MFR_TEMPERATURE_PEAK); 115c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (ret >= 0) { 116c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (lin11_to_val(ret) > lin11_to_val(data->temp_max)) 117c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->temp_max = ret; 118c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck ret = data->temp_max; 119c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck } 120c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck break; 121ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case PMBUS_VIRT_RESET_VOUT_HISTORY: 122ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case PMBUS_VIRT_RESET_VIN_HISTORY: 123ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case PMBUS_VIRT_RESET_TEMP_HISTORY: 124ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = 0; 125ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck break; 126ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck default: 127ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = -ENODATA; 128ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck break; 129ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck } 130ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck return ret; 131ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck} 132ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck 133ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeckstatic int ltc2978_read_word_data(struct i2c_client *client, int page, int reg) 134ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck{ 135ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 136ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck struct ltc2978_data *data = to_ltc2978_data(info); 137ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck int ret; 138ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck 139ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck switch (reg) { 140c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck case PMBUS_VIRT_READ_VIN_MIN: 141c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_MIN); 142c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (ret >= 0) { 143c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (lin11_to_val(ret) < lin11_to_val(data->vin_min)) 144c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->vin_min = ret; 145c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck ret = data->vin_min; 146c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck } 147c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck break; 148c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck case PMBUS_VIRT_READ_VOUT_MIN: 149c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_MIN); 150c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (ret >= 0) { 151c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck /* 152c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * VOUT_MIN is known to not be supported on some lots 153c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * of LTC2978 revision 1, and will return the maximum 154c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * possible voltage if read. If VOUT_MAX is valid and 155c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck * lower than the reading of VOUT_MIN, use it instead. 156c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck */ 157c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (data->vout_max[page] && ret > data->vout_max[page]) 158c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck ret = data->vout_max[page]; 159c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (ret < data->vout_min[page]) 160c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->vout_min[page] = ret; 161c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck ret = data->vout_min[page]; 162c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck } 163c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck break; 164c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck case PMBUS_VIRT_READ_TEMP_MIN: 165c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck ret = pmbus_read_word_data(client, page, 166c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck LTC2978_MFR_TEMPERATURE_MIN); 167c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (ret >= 0) { 168c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (lin11_to_val(ret) 169c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck < lin11_to_val(data->temp_min)) 170c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->temp_min = ret; 171c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck ret = data->temp_min; 172c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck } 173c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck break; 174ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case PMBUS_VIRT_READ_IOUT_MAX: 175ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case PMBUS_VIRT_RESET_IOUT_HISTORY: 176ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case PMBUS_VIRT_READ_TEMP2_MAX: 177ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case PMBUS_VIRT_RESET_TEMP2_HISTORY: 178ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = -ENXIO; 179ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck break; 180ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck default: 181ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = ltc2978_read_word_data_common(client, page, reg); 182ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck break; 183ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck } 184ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck return ret; 185ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck} 186ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck 187ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeckstatic int ltc3880_read_word_data(struct i2c_client *client, int page, int reg) 188ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck{ 189ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 190ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck struct ltc2978_data *data = to_ltc2978_data(info); 191ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck int ret; 192ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck 193ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck switch (reg) { 194ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case PMBUS_VIRT_READ_IOUT_MAX: 195ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = pmbus_read_word_data(client, page, LTC3880_MFR_IOUT_PEAK); 196ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck if (ret >= 0) { 197ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck if (lin11_to_val(ret) 198ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck > lin11_to_val(data->iout_max[page])) 199ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck data->iout_max[page] = ret; 200ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = data->iout_max[page]; 201ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck } 202ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck break; 203ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case PMBUS_VIRT_READ_TEMP2_MAX: 204ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = pmbus_read_word_data(client, page, 205ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck LTC3880_MFR_TEMPERATURE2_PEAK); 206ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck if (ret >= 0) { 207ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck if (lin11_to_val(ret) 208ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck > lin11_to_val(data->temp2_max[page])) 209ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck data->temp2_max[page] = ret; 210ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = data->temp2_max[page]; 211ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck } 212ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck break; 213ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case PMBUS_VIRT_READ_VIN_MIN: 214ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case PMBUS_VIRT_READ_VOUT_MIN: 215ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case PMBUS_VIRT_READ_TEMP_MIN: 216ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = -ENXIO; 217ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck break; 218ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case PMBUS_VIRT_RESET_IOUT_HISTORY: 219ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case PMBUS_VIRT_RESET_TEMP2_HISTORY: 220c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck ret = 0; 221c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck break; 222c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck default: 223ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = ltc2978_read_word_data_common(client, page, reg); 224c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck break; 225c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck } 226c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck return ret; 227c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck} 228c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 229ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeckstatic int ltc2978_clear_peaks(struct i2c_client *client, int page, 230ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck enum chips id) 231ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck{ 232ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck int ret; 233ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck 234ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck if (id == ltc2978) 235ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); 236ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck else 237ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); 238ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck 239ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck return ret; 240ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck} 241ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck 242c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeckstatic int ltc2978_write_word_data(struct i2c_client *client, int page, 243c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck int reg, u16 word) 244c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck{ 245c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 246c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck struct ltc2978_data *data = to_ltc2978_data(info); 247c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck int ret; 248c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 249c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck switch (reg) { 250ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case PMBUS_VIRT_RESET_IOUT_HISTORY: 251ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck data->iout_max[page] = 0x7fff; 252ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = ltc2978_clear_peaks(client, page, data->id); 253ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck break; 254ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case PMBUS_VIRT_RESET_TEMP2_HISTORY: 255ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck data->temp2_max[page] = 0x7fff; 256ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = ltc2978_clear_peaks(client, page, data->id); 257ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck break; 258c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck case PMBUS_VIRT_RESET_VOUT_HISTORY: 259c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->vout_min[page] = 0xffff; 260c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->vout_max[page] = 0; 261ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = ltc2978_clear_peaks(client, page, data->id); 262c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck break; 263c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck case PMBUS_VIRT_RESET_VIN_HISTORY: 264c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->vin_min = 0x7bff; 265c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->vin_max = 0; 266ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = ltc2978_clear_peaks(client, page, data->id); 267c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck break; 268c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck case PMBUS_VIRT_RESET_TEMP_HISTORY: 269c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->temp_min = 0x7bff; 270c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->temp_max = 0x7fff; 271ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck ret = ltc2978_clear_peaks(client, page, data->id); 272c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck break; 273c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck default: 274c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck ret = -ENODATA; 275c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck break; 276c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck } 277c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck return ret; 278c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck} 279c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 280c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeckstatic const struct i2c_device_id ltc2978_id[] = { 281c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck {"ltc2978", ltc2978}, 282ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck {"ltc3880", ltc3880}, 283c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck {} 284c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck}; 285c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter RoeckMODULE_DEVICE_TABLE(i2c, ltc2978_id); 286c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 287c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeckstatic int ltc2978_probe(struct i2c_client *client, 288c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck const struct i2c_device_id *id) 289c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck{ 2908b313ca7f1b98263ce22519b25a9c2a362eeb898Guenter Roeck int chip_id, i; 291c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck struct ltc2978_data *data; 292c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck struct pmbus_driver_info *info; 293c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 294c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (!i2c_check_functionality(client->adapter, 295c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck I2C_FUNC_SMBUS_READ_WORD_DATA)) 296c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck return -ENODEV; 297c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 2988b313ca7f1b98263ce22519b25a9c2a362eeb898Guenter Roeck data = devm_kzalloc(&client->dev, sizeof(struct ltc2978_data), 2998b313ca7f1b98263ce22519b25a9c2a362eeb898Guenter Roeck GFP_KERNEL); 300c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (!data) 301c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck return -ENOMEM; 302c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 303c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck chip_id = i2c_smbus_read_word_data(client, LTC2978_MFR_SPECIAL_ID); 3048b313ca7f1b98263ce22519b25a9c2a362eeb898Guenter Roeck if (chip_id < 0) 3058b313ca7f1b98263ce22519b25a9c2a362eeb898Guenter Roeck return chip_id; 306c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 307c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) { 308c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->id = ltc2978; 309ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck } else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) { 310ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck data->id = ltc3880; 311c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck } else { 312c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id); 3138b313ca7f1b98263ce22519b25a9c2a362eeb898Guenter Roeck return -ENODEV; 314c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck } 315c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck if (data->id != id->driver_data) 316c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck dev_warn(&client->dev, 317c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck "Device mismatch: Configured %s, detected %s\n", 318c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck id->name, 319c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck ltc2978_id[data->id].name); 320c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 321c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck info = &data->info; 322c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck info->write_word_data = ltc2978_write_word_data; 323c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 324c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->vout_min[0] = 0xffff; 325c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->vin_min = 0x7bff; 326c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->temp_min = 0x7bff; 327c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->temp_max = 0x7fff; 328c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 329c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck switch (id->driver_data) { 330c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck case ltc2978: 331ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck info->read_word_data = ltc2978_read_word_data; 332c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck info->pages = 8; 333c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT 334c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 335c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; 336c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck for (i = 1; i < 8; i++) { 337c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck info->func[i] = PMBUS_HAVE_VOUT 338c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck | PMBUS_HAVE_STATUS_VOUT; 339c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck data->vout_min[i] = 0xffff; 340c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck } 341c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck break; 342ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck case ltc3880: 343ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck info->read_word_data = ltc3880_read_word_data; 344ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck info->pages = 2; 345ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN 346ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck | PMBUS_HAVE_STATUS_INPUT 347ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 348ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT 349ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP 350ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; 351ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT 352ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT 353ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck | PMBUS_HAVE_POUT 354ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; 355ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck data->vout_min[1] = 0xffff; 356ddfb41ca2a33c9f5053126324597510974724a1fGuenter Roeck break; 357c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck default: 3588b313ca7f1b98263ce22519b25a9c2a362eeb898Guenter Roeck return -ENODEV; 359c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck } 360c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 3618b313ca7f1b98263ce22519b25a9c2a362eeb898Guenter Roeck return pmbus_do_probe(client, id, info); 362c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck} 363c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 364c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck/* This is the driver that will be inserted */ 365c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeckstatic struct i2c_driver ltc2978_driver = { 366c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck .driver = { 367c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck .name = "ltc2978", 368c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck }, 369c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck .probe = ltc2978_probe, 370dd285ad7373bf5d21cceacb3b7a5eb8b72d37085Guenter Roeck .remove = pmbus_do_remove, 371c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck .id_table = ltc2978_id, 372c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck}; 373c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 374f0967eea80ec2a19a4fe1ad27e3ff1b22c79a3c7Axel Linmodule_i2c_driver(ltc2978_driver); 375c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter Roeck 376c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter RoeckMODULE_AUTHOR("Guenter Roeck"); 377ddfb41ca2a33c9f5053126324597510974724a1fGuenter RoeckMODULE_DESCRIPTION("PMBus driver for LTC2978 and LTC3880"); 378c3ff9a674c2313d4f28e38d384b18b561b313eb7Guenter RoeckMODULE_LICENSE("GPL"); 379