103e9bd8dSGuenter Roeck /* 203e9bd8dSGuenter Roeck * Hardware monitoring driver for LM25066 / LM5064 / LM5066 303e9bd8dSGuenter Roeck * 403e9bd8dSGuenter Roeck * Copyright (c) 2011 Ericsson AB. 5a7c69118SGuenter Roeck * Copyright (c) 2013 Guenter Roeck 603e9bd8dSGuenter Roeck * 703e9bd8dSGuenter Roeck * This program is free software; you can redistribute it and/or modify 803e9bd8dSGuenter Roeck * it under the terms of the GNU General Public License as published by 903e9bd8dSGuenter Roeck * the Free Software Foundation; either version 2 of the License, or 1003e9bd8dSGuenter Roeck * (at your option) any later version. 1103e9bd8dSGuenter Roeck * 1203e9bd8dSGuenter Roeck * This program is distributed in the hope that it will be useful, 1303e9bd8dSGuenter Roeck * but WITHOUT ANY WARRANTY; without even the implied warranty of 1403e9bd8dSGuenter Roeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1503e9bd8dSGuenter Roeck * GNU General Public License for more details. 1603e9bd8dSGuenter Roeck * 1703e9bd8dSGuenter Roeck * You should have received a copy of the GNU General Public License 1803e9bd8dSGuenter Roeck * along with this program; if not, write to the Free Software 1903e9bd8dSGuenter Roeck * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 2003e9bd8dSGuenter Roeck */ 2103e9bd8dSGuenter Roeck 2203e9bd8dSGuenter Roeck #include <linux/kernel.h> 2303e9bd8dSGuenter Roeck #include <linux/module.h> 2403e9bd8dSGuenter Roeck #include <linux/init.h> 2503e9bd8dSGuenter Roeck #include <linux/err.h> 2603e9bd8dSGuenter Roeck #include <linux/slab.h> 2703e9bd8dSGuenter Roeck #include <linux/i2c.h> 2803e9bd8dSGuenter Roeck #include "pmbus.h" 2903e9bd8dSGuenter Roeck 3003e9bd8dSGuenter Roeck enum chips { lm25066, lm5064, lm5066 }; 3103e9bd8dSGuenter Roeck 3203e9bd8dSGuenter Roeck #define LM25066_READ_VAUX 0xd0 3303e9bd8dSGuenter Roeck #define LM25066_MFR_READ_IIN 0xd1 3403e9bd8dSGuenter Roeck #define LM25066_MFR_READ_PIN 0xd2 3503e9bd8dSGuenter Roeck #define LM25066_MFR_IIN_OC_WARN_LIMIT 0xd3 3603e9bd8dSGuenter Roeck #define LM25066_MFR_PIN_OP_WARN_LIMIT 0xd4 3703e9bd8dSGuenter Roeck #define LM25066_READ_PIN_PEAK 0xd5 3803e9bd8dSGuenter Roeck #define LM25066_CLEAR_PIN_PEAK 0xd6 3903e9bd8dSGuenter Roeck #define LM25066_DEVICE_SETUP 0xd9 4003e9bd8dSGuenter Roeck #define LM25066_READ_AVG_VIN 0xdc 4103e9bd8dSGuenter Roeck #define LM25066_READ_AVG_VOUT 0xdd 4203e9bd8dSGuenter Roeck #define LM25066_READ_AVG_IIN 0xde 4303e9bd8dSGuenter Roeck #define LM25066_READ_AVG_PIN 0xdf 4403e9bd8dSGuenter Roeck 4503e9bd8dSGuenter Roeck #define LM25066_DEV_SETUP_CL (1 << 4) /* Current limit */ 4603e9bd8dSGuenter Roeck 4703e9bd8dSGuenter Roeck struct lm25066_data { 4803e9bd8dSGuenter Roeck int id; 4903e9bd8dSGuenter Roeck struct pmbus_driver_info info; 5003e9bd8dSGuenter Roeck }; 5103e9bd8dSGuenter Roeck 5203e9bd8dSGuenter Roeck #define to_lm25066_data(x) container_of(x, struct lm25066_data, info) 5303e9bd8dSGuenter Roeck 5403e9bd8dSGuenter Roeck static int lm25066_read_word_data(struct i2c_client *client, int page, int reg) 5503e9bd8dSGuenter Roeck { 5603e9bd8dSGuenter Roeck const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 5703e9bd8dSGuenter Roeck const struct lm25066_data *data = to_lm25066_data(info); 5803e9bd8dSGuenter Roeck int ret; 5903e9bd8dSGuenter Roeck 6003e9bd8dSGuenter Roeck switch (reg) { 61a7c69118SGuenter Roeck case PMBUS_VIRT_READ_VMON: 62a7c69118SGuenter Roeck ret = pmbus_read_word_data(client, 0, LM25066_READ_VAUX); 6303e9bd8dSGuenter Roeck if (ret < 0) 6403e9bd8dSGuenter Roeck break; 65a7c69118SGuenter Roeck /* Adjust returned value to match VIN coefficients */ 6603e9bd8dSGuenter Roeck switch (data->id) { 6703e9bd8dSGuenter Roeck case lm25066: 68a7c69118SGuenter Roeck /* VIN: 4.54 mV VAUX: 283.2 uV LSB */ 6903e9bd8dSGuenter Roeck ret = DIV_ROUND_CLOSEST(ret * 2832, 45400); 7003e9bd8dSGuenter Roeck break; 7103e9bd8dSGuenter Roeck case lm5064: 72a7c69118SGuenter Roeck /* VIN: 4.53 mV VAUX: 700 uV LSB */ 7303e9bd8dSGuenter Roeck ret = DIV_ROUND_CLOSEST(ret * 70, 453); 7403e9bd8dSGuenter Roeck break; 7503e9bd8dSGuenter Roeck case lm5066: 76a7c69118SGuenter Roeck /* VIN: 2.18 mV VAUX: 725 uV LSB */ 7703e9bd8dSGuenter Roeck ret = DIV_ROUND_CLOSEST(ret * 725, 2180); 7803e9bd8dSGuenter Roeck break; 7903e9bd8dSGuenter Roeck } 8003e9bd8dSGuenter Roeck break; 8103e9bd8dSGuenter Roeck case PMBUS_READ_IIN: 8203e9bd8dSGuenter Roeck ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_IIN); 8303e9bd8dSGuenter Roeck break; 8403e9bd8dSGuenter Roeck case PMBUS_READ_PIN: 8503e9bd8dSGuenter Roeck ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_PIN); 8603e9bd8dSGuenter Roeck break; 8703e9bd8dSGuenter Roeck case PMBUS_IIN_OC_WARN_LIMIT: 8803e9bd8dSGuenter Roeck ret = pmbus_read_word_data(client, 0, 8903e9bd8dSGuenter Roeck LM25066_MFR_IIN_OC_WARN_LIMIT); 9003e9bd8dSGuenter Roeck break; 9103e9bd8dSGuenter Roeck case PMBUS_PIN_OP_WARN_LIMIT: 9203e9bd8dSGuenter Roeck ret = pmbus_read_word_data(client, 0, 9303e9bd8dSGuenter Roeck LM25066_MFR_PIN_OP_WARN_LIMIT); 9403e9bd8dSGuenter Roeck break; 9503e9bd8dSGuenter Roeck case PMBUS_VIRT_READ_VIN_AVG: 9603e9bd8dSGuenter Roeck ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VIN); 9703e9bd8dSGuenter Roeck break; 9803e9bd8dSGuenter Roeck case PMBUS_VIRT_READ_VOUT_AVG: 9903e9bd8dSGuenter Roeck ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VOUT); 10003e9bd8dSGuenter Roeck break; 10103e9bd8dSGuenter Roeck case PMBUS_VIRT_READ_IIN_AVG: 10203e9bd8dSGuenter Roeck ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_IIN); 10303e9bd8dSGuenter Roeck break; 10403e9bd8dSGuenter Roeck case PMBUS_VIRT_READ_PIN_AVG: 10503e9bd8dSGuenter Roeck ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_PIN); 10603e9bd8dSGuenter Roeck break; 10703e9bd8dSGuenter Roeck case PMBUS_VIRT_READ_PIN_MAX: 10803e9bd8dSGuenter Roeck ret = pmbus_read_word_data(client, 0, LM25066_READ_PIN_PEAK); 10903e9bd8dSGuenter Roeck break; 11003e9bd8dSGuenter Roeck case PMBUS_VIRT_RESET_PIN_HISTORY: 11103e9bd8dSGuenter Roeck ret = 0; 11203e9bd8dSGuenter Roeck break; 11303e9bd8dSGuenter Roeck default: 11403e9bd8dSGuenter Roeck ret = -ENODATA; 11503e9bd8dSGuenter Roeck break; 11603e9bd8dSGuenter Roeck } 11703e9bd8dSGuenter Roeck return ret; 11803e9bd8dSGuenter Roeck } 11903e9bd8dSGuenter Roeck 12003e9bd8dSGuenter Roeck static int lm25066_write_word_data(struct i2c_client *client, int page, int reg, 12103e9bd8dSGuenter Roeck u16 word) 12203e9bd8dSGuenter Roeck { 12303e9bd8dSGuenter Roeck int ret; 12403e9bd8dSGuenter Roeck 12503e9bd8dSGuenter Roeck switch (reg) { 126*2507abb3SGuenter Roeck case PMBUS_VOUT_UV_WARN_LIMIT: 127*2507abb3SGuenter Roeck case PMBUS_OT_FAULT_LIMIT: 128*2507abb3SGuenter Roeck case PMBUS_OT_WARN_LIMIT: 129*2507abb3SGuenter Roeck case PMBUS_VIN_UV_WARN_LIMIT: 130*2507abb3SGuenter Roeck case PMBUS_VIN_OV_WARN_LIMIT: 131*2507abb3SGuenter Roeck word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff); 132*2507abb3SGuenter Roeck ret = pmbus_write_word_data(client, 0, reg, word); 133*2507abb3SGuenter Roeck pmbus_clear_cache(client); 134*2507abb3SGuenter Roeck break; 13503e9bd8dSGuenter Roeck case PMBUS_IIN_OC_WARN_LIMIT: 136*2507abb3SGuenter Roeck word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff); 13703e9bd8dSGuenter Roeck ret = pmbus_write_word_data(client, 0, 13803e9bd8dSGuenter Roeck LM25066_MFR_IIN_OC_WARN_LIMIT, 13903e9bd8dSGuenter Roeck word); 140*2507abb3SGuenter Roeck pmbus_clear_cache(client); 14103e9bd8dSGuenter Roeck break; 14203e9bd8dSGuenter Roeck case PMBUS_PIN_OP_WARN_LIMIT: 143*2507abb3SGuenter Roeck word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff); 14403e9bd8dSGuenter Roeck ret = pmbus_write_word_data(client, 0, 14503e9bd8dSGuenter Roeck LM25066_MFR_PIN_OP_WARN_LIMIT, 14603e9bd8dSGuenter Roeck word); 147*2507abb3SGuenter Roeck pmbus_clear_cache(client); 14803e9bd8dSGuenter Roeck break; 14903e9bd8dSGuenter Roeck case PMBUS_VIRT_RESET_PIN_HISTORY: 15003e9bd8dSGuenter Roeck ret = pmbus_write_byte(client, 0, LM25066_CLEAR_PIN_PEAK); 15103e9bd8dSGuenter Roeck break; 15203e9bd8dSGuenter Roeck default: 15303e9bd8dSGuenter Roeck ret = -ENODATA; 15403e9bd8dSGuenter Roeck break; 15503e9bd8dSGuenter Roeck } 15603e9bd8dSGuenter Roeck return ret; 15703e9bd8dSGuenter Roeck } 15803e9bd8dSGuenter Roeck 15903e9bd8dSGuenter Roeck static int lm25066_probe(struct i2c_client *client, 16003e9bd8dSGuenter Roeck const struct i2c_device_id *id) 16103e9bd8dSGuenter Roeck { 16203e9bd8dSGuenter Roeck int config; 16303e9bd8dSGuenter Roeck struct lm25066_data *data; 16403e9bd8dSGuenter Roeck struct pmbus_driver_info *info; 16503e9bd8dSGuenter Roeck 16603e9bd8dSGuenter Roeck if (!i2c_check_functionality(client->adapter, 16703e9bd8dSGuenter Roeck I2C_FUNC_SMBUS_READ_BYTE_DATA)) 16803e9bd8dSGuenter Roeck return -ENODEV; 16903e9bd8dSGuenter Roeck 1708b313ca7SGuenter Roeck data = devm_kzalloc(&client->dev, sizeof(struct lm25066_data), 1718b313ca7SGuenter Roeck GFP_KERNEL); 17203e9bd8dSGuenter Roeck if (!data) 17303e9bd8dSGuenter Roeck return -ENOMEM; 17403e9bd8dSGuenter Roeck 17503e9bd8dSGuenter Roeck config = i2c_smbus_read_byte_data(client, LM25066_DEVICE_SETUP); 1768b313ca7SGuenter Roeck if (config < 0) 1778b313ca7SGuenter Roeck return config; 17803e9bd8dSGuenter Roeck 17903e9bd8dSGuenter Roeck data->id = id->driver_data; 18003e9bd8dSGuenter Roeck info = &data->info; 18103e9bd8dSGuenter Roeck 182a7c69118SGuenter Roeck info->pages = 1; 18303e9bd8dSGuenter Roeck info->format[PSC_VOLTAGE_IN] = direct; 18403e9bd8dSGuenter Roeck info->format[PSC_VOLTAGE_OUT] = direct; 18503e9bd8dSGuenter Roeck info->format[PSC_CURRENT_IN] = direct; 18603e9bd8dSGuenter Roeck info->format[PSC_TEMPERATURE] = direct; 18703e9bd8dSGuenter Roeck info->format[PSC_POWER] = direct; 18803e9bd8dSGuenter Roeck 18903e9bd8dSGuenter Roeck info->m[PSC_TEMPERATURE] = 16; 19003e9bd8dSGuenter Roeck info->b[PSC_TEMPERATURE] = 0; 19103e9bd8dSGuenter Roeck info->R[PSC_TEMPERATURE] = 0; 19203e9bd8dSGuenter Roeck 193a7c69118SGuenter Roeck info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VMON | PMBUS_HAVE_VOUT 19403e9bd8dSGuenter Roeck | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_PIN | PMBUS_HAVE_IIN 19503e9bd8dSGuenter Roeck | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; 19603e9bd8dSGuenter Roeck 19703e9bd8dSGuenter Roeck info->read_word_data = lm25066_read_word_data; 19803e9bd8dSGuenter Roeck info->write_word_data = lm25066_write_word_data; 19903e9bd8dSGuenter Roeck 20003e9bd8dSGuenter Roeck switch (id->driver_data) { 20103e9bd8dSGuenter Roeck case lm25066: 20203e9bd8dSGuenter Roeck info->m[PSC_VOLTAGE_IN] = 22070; 20303e9bd8dSGuenter Roeck info->b[PSC_VOLTAGE_IN] = 0; 20403e9bd8dSGuenter Roeck info->R[PSC_VOLTAGE_IN] = -2; 20503e9bd8dSGuenter Roeck info->m[PSC_VOLTAGE_OUT] = 22070; 20603e9bd8dSGuenter Roeck info->b[PSC_VOLTAGE_OUT] = 0; 20703e9bd8dSGuenter Roeck info->R[PSC_VOLTAGE_OUT] = -2; 20803e9bd8dSGuenter Roeck 20903e9bd8dSGuenter Roeck if (config & LM25066_DEV_SETUP_CL) { 21003e9bd8dSGuenter Roeck info->m[PSC_CURRENT_IN] = 6852; 21103e9bd8dSGuenter Roeck info->b[PSC_CURRENT_IN] = 0; 21203e9bd8dSGuenter Roeck info->R[PSC_CURRENT_IN] = -2; 21303e9bd8dSGuenter Roeck info->m[PSC_POWER] = 369; 21403e9bd8dSGuenter Roeck info->b[PSC_POWER] = 0; 21503e9bd8dSGuenter Roeck info->R[PSC_POWER] = -2; 21603e9bd8dSGuenter Roeck } else { 21703e9bd8dSGuenter Roeck info->m[PSC_CURRENT_IN] = 13661; 21803e9bd8dSGuenter Roeck info->b[PSC_CURRENT_IN] = 0; 21903e9bd8dSGuenter Roeck info->R[PSC_CURRENT_IN] = -2; 22003e9bd8dSGuenter Roeck info->m[PSC_POWER] = 736; 22103e9bd8dSGuenter Roeck info->b[PSC_POWER] = 0; 22203e9bd8dSGuenter Roeck info->R[PSC_POWER] = -2; 22303e9bd8dSGuenter Roeck } 22403e9bd8dSGuenter Roeck break; 22503e9bd8dSGuenter Roeck case lm5064: 22603e9bd8dSGuenter Roeck info->m[PSC_VOLTAGE_IN] = 22075; 22703e9bd8dSGuenter Roeck info->b[PSC_VOLTAGE_IN] = 0; 22803e9bd8dSGuenter Roeck info->R[PSC_VOLTAGE_IN] = -2; 22903e9bd8dSGuenter Roeck info->m[PSC_VOLTAGE_OUT] = 22075; 23003e9bd8dSGuenter Roeck info->b[PSC_VOLTAGE_OUT] = 0; 23103e9bd8dSGuenter Roeck info->R[PSC_VOLTAGE_OUT] = -2; 23203e9bd8dSGuenter Roeck 23303e9bd8dSGuenter Roeck if (config & LM25066_DEV_SETUP_CL) { 23403e9bd8dSGuenter Roeck info->m[PSC_CURRENT_IN] = 6713; 23503e9bd8dSGuenter Roeck info->b[PSC_CURRENT_IN] = 0; 23603e9bd8dSGuenter Roeck info->R[PSC_CURRENT_IN] = -2; 23703e9bd8dSGuenter Roeck info->m[PSC_POWER] = 3619; 23803e9bd8dSGuenter Roeck info->b[PSC_POWER] = 0; 23903e9bd8dSGuenter Roeck info->R[PSC_POWER] = -3; 24003e9bd8dSGuenter Roeck } else { 24103e9bd8dSGuenter Roeck info->m[PSC_CURRENT_IN] = 13426; 24203e9bd8dSGuenter Roeck info->b[PSC_CURRENT_IN] = 0; 24303e9bd8dSGuenter Roeck info->R[PSC_CURRENT_IN] = -2; 24403e9bd8dSGuenter Roeck info->m[PSC_POWER] = 7238; 24503e9bd8dSGuenter Roeck info->b[PSC_POWER] = 0; 24603e9bd8dSGuenter Roeck info->R[PSC_POWER] = -3; 24703e9bd8dSGuenter Roeck } 24803e9bd8dSGuenter Roeck break; 24903e9bd8dSGuenter Roeck case lm5066: 25003e9bd8dSGuenter Roeck info->m[PSC_VOLTAGE_IN] = 4587; 25103e9bd8dSGuenter Roeck info->b[PSC_VOLTAGE_IN] = 0; 25203e9bd8dSGuenter Roeck info->R[PSC_VOLTAGE_IN] = -2; 25303e9bd8dSGuenter Roeck info->m[PSC_VOLTAGE_OUT] = 4587; 25403e9bd8dSGuenter Roeck info->b[PSC_VOLTAGE_OUT] = 0; 25503e9bd8dSGuenter Roeck info->R[PSC_VOLTAGE_OUT] = -2; 25603e9bd8dSGuenter Roeck 25703e9bd8dSGuenter Roeck if (config & LM25066_DEV_SETUP_CL) { 25803e9bd8dSGuenter Roeck info->m[PSC_CURRENT_IN] = 10753; 25903e9bd8dSGuenter Roeck info->b[PSC_CURRENT_IN] = 0; 26003e9bd8dSGuenter Roeck info->R[PSC_CURRENT_IN] = -2; 26103e9bd8dSGuenter Roeck info->m[PSC_POWER] = 1204; 26203e9bd8dSGuenter Roeck info->b[PSC_POWER] = 0; 26303e9bd8dSGuenter Roeck info->R[PSC_POWER] = -3; 26403e9bd8dSGuenter Roeck } else { 26503e9bd8dSGuenter Roeck info->m[PSC_CURRENT_IN] = 5405; 26603e9bd8dSGuenter Roeck info->b[PSC_CURRENT_IN] = 0; 26703e9bd8dSGuenter Roeck info->R[PSC_CURRENT_IN] = -2; 26803e9bd8dSGuenter Roeck info->m[PSC_POWER] = 605; 26903e9bd8dSGuenter Roeck info->b[PSC_POWER] = 0; 27003e9bd8dSGuenter Roeck info->R[PSC_POWER] = -3; 27103e9bd8dSGuenter Roeck } 27203e9bd8dSGuenter Roeck break; 27303e9bd8dSGuenter Roeck default: 2748b313ca7SGuenter Roeck return -ENODEV; 27503e9bd8dSGuenter Roeck } 27603e9bd8dSGuenter Roeck 2778b313ca7SGuenter Roeck return pmbus_do_probe(client, id, info); 27803e9bd8dSGuenter Roeck } 27903e9bd8dSGuenter Roeck 28003e9bd8dSGuenter Roeck static const struct i2c_device_id lm25066_id[] = { 28103e9bd8dSGuenter Roeck {"lm25066", lm25066}, 28203e9bd8dSGuenter Roeck {"lm5064", lm5064}, 28303e9bd8dSGuenter Roeck {"lm5066", lm5066}, 28403e9bd8dSGuenter Roeck { } 28503e9bd8dSGuenter Roeck }; 28603e9bd8dSGuenter Roeck 28703e9bd8dSGuenter Roeck MODULE_DEVICE_TABLE(i2c, lm25066_id); 28803e9bd8dSGuenter Roeck 28903e9bd8dSGuenter Roeck /* This is the driver that will be inserted */ 29003e9bd8dSGuenter Roeck static struct i2c_driver lm25066_driver = { 29103e9bd8dSGuenter Roeck .driver = { 29203e9bd8dSGuenter Roeck .name = "lm25066", 29303e9bd8dSGuenter Roeck }, 29403e9bd8dSGuenter Roeck .probe = lm25066_probe, 295dd285ad7SGuenter Roeck .remove = pmbus_do_remove, 29603e9bd8dSGuenter Roeck .id_table = lm25066_id, 29703e9bd8dSGuenter Roeck }; 29803e9bd8dSGuenter Roeck 299f0967eeaSAxel Lin module_i2c_driver(lm25066_driver); 30003e9bd8dSGuenter Roeck 30103e9bd8dSGuenter Roeck MODULE_AUTHOR("Guenter Roeck"); 30203e9bd8dSGuenter Roeck MODULE_DESCRIPTION("PMBus driver for LM25066/LM5064/LM5066"); 30303e9bd8dSGuenter Roeck MODULE_LICENSE("GPL"); 304