1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 261052652SVadim Pasternak /* 361052652SVadim Pasternak * Hardware monitoring driver for Texas Instruments TPS53679 461052652SVadim Pasternak * 561052652SVadim Pasternak * Copyright (c) 2017 Mellanox Technologies. All rights reserved. 661052652SVadim Pasternak * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com> 761052652SVadim Pasternak */ 861052652SVadim Pasternak 953030bccSGuenter Roeck #include <linux/bits.h> 1061052652SVadim Pasternak #include <linux/err.h> 1161052652SVadim Pasternak #include <linux/i2c.h> 1261052652SVadim Pasternak #include <linux/init.h> 1361052652SVadim Pasternak #include <linux/kernel.h> 1461052652SVadim Pasternak #include <linux/module.h> 1563eb4587SGuenter Roeck #include <linux/of_device.h> 1661052652SVadim Pasternak #include "pmbus.h" 1761052652SVadim Pasternak 1863eb4587SGuenter Roeck enum chips { 19*6f944004SGuenter Roeck tps53647, tps53667, tps53679, tps53681, tps53688 2063eb4587SGuenter Roeck }; 2163eb4587SGuenter Roeck 22*6f944004SGuenter Roeck #define TPS53647_PAGE_NUM 1 23*6f944004SGuenter Roeck 2461052652SVadim Pasternak #define TPS53679_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */ 2561052652SVadim Pasternak #define TPS53679_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */ 2661052652SVadim Pasternak #define TPS53679_PROT_VR13_10MV 0x04 /* VR13.0 mode, 10-mV DAC */ 2761052652SVadim Pasternak #define TPS53679_PROT_IMVP8_5MV 0x05 /* IMVP8 mode, 5-mV DAC */ 2861052652SVadim Pasternak #define TPS53679_PROT_VR13_5MV 0x07 /* VR13.0 mode, 5-mV DAC */ 2961052652SVadim Pasternak #define TPS53679_PAGE_NUM 2 3061052652SVadim Pasternak 3153030bccSGuenter Roeck #define TPS53681_DEVICE_ID 0x81 3253030bccSGuenter Roeck 3353030bccSGuenter Roeck #define TPS53681_PMBUS_REVISION 0x33 3453030bccSGuenter Roeck 3553030bccSGuenter Roeck #define TPS53681_MFR_SPECIFIC_20 0xe4 /* Number of phases, per page */ 3653030bccSGuenter Roeck 3753030bccSGuenter Roeck static int tps53679_identify_mode(struct i2c_client *client, 3861052652SVadim Pasternak struct pmbus_driver_info *info) 3961052652SVadim Pasternak { 4061052652SVadim Pasternak u8 vout_params; 41b9fa0a3aSVadim Pasternak int i, ret; 4261052652SVadim Pasternak 43*6f944004SGuenter Roeck for (i = 0; i < info->pages; i++) { 4461052652SVadim Pasternak /* Read the register with VOUT scaling value.*/ 45b9fa0a3aSVadim Pasternak ret = pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); 4661052652SVadim Pasternak if (ret < 0) 4761052652SVadim Pasternak return ret; 4861052652SVadim Pasternak 4961052652SVadim Pasternak vout_params = ret & GENMASK(4, 0); 5061052652SVadim Pasternak 5161052652SVadim Pasternak switch (vout_params) { 5261052652SVadim Pasternak case TPS53679_PROT_VR13_10MV: 5361052652SVadim Pasternak case TPS53679_PROT_VR12_5_10MV: 54b9fa0a3aSVadim Pasternak info->vrm_version[i] = vr13; 5561052652SVadim Pasternak break; 5661052652SVadim Pasternak case TPS53679_PROT_VR13_5MV: 5761052652SVadim Pasternak case TPS53679_PROT_VR12_5MV: 5861052652SVadim Pasternak case TPS53679_PROT_IMVP8_5MV: 59b9fa0a3aSVadim Pasternak info->vrm_version[i] = vr12; 6061052652SVadim Pasternak break; 6161052652SVadim Pasternak default: 6261052652SVadim Pasternak return -EINVAL; 6361052652SVadim Pasternak } 64b9fa0a3aSVadim Pasternak } 6561052652SVadim Pasternak 6661052652SVadim Pasternak return 0; 6761052652SVadim Pasternak } 6861052652SVadim Pasternak 6953030bccSGuenter Roeck static int tps53679_identify_phases(struct i2c_client *client, 7053030bccSGuenter Roeck struct pmbus_driver_info *info) 7153030bccSGuenter Roeck { 7253030bccSGuenter Roeck int ret; 7353030bccSGuenter Roeck 7453030bccSGuenter Roeck /* On TPS53681, only channel A provides per-phase output current */ 7553030bccSGuenter Roeck ret = pmbus_read_byte_data(client, 0, TPS53681_MFR_SPECIFIC_20); 7653030bccSGuenter Roeck if (ret < 0) 7753030bccSGuenter Roeck return ret; 7853030bccSGuenter Roeck info->phases[0] = (ret & 0x07) + 1; 7953030bccSGuenter Roeck 8053030bccSGuenter Roeck return 0; 8153030bccSGuenter Roeck } 8253030bccSGuenter Roeck 8353030bccSGuenter Roeck static int tps53679_identify_chip(struct i2c_client *client, 8453030bccSGuenter Roeck u8 revision, u16 id) 8553030bccSGuenter Roeck { 8653030bccSGuenter Roeck u8 buf[I2C_SMBUS_BLOCK_MAX]; 8753030bccSGuenter Roeck int ret; 8853030bccSGuenter Roeck 8953030bccSGuenter Roeck ret = pmbus_read_byte_data(client, 0, PMBUS_REVISION); 9053030bccSGuenter Roeck if (ret < 0) 9153030bccSGuenter Roeck return ret; 9253030bccSGuenter Roeck if (ret != revision) { 9353030bccSGuenter Roeck dev_err(&client->dev, "Unexpected PMBus revision 0x%x\n", ret); 9453030bccSGuenter Roeck return -ENODEV; 9553030bccSGuenter Roeck } 9653030bccSGuenter Roeck 9753030bccSGuenter Roeck ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf); 9853030bccSGuenter Roeck if (ret < 0) 9953030bccSGuenter Roeck return ret; 10053030bccSGuenter Roeck if (ret != 1 || buf[0] != id) { 10153030bccSGuenter Roeck dev_err(&client->dev, "Unexpected device ID 0x%x\n", buf[0]); 10253030bccSGuenter Roeck return -ENODEV; 10353030bccSGuenter Roeck } 10453030bccSGuenter Roeck return 0; 10553030bccSGuenter Roeck } 10653030bccSGuenter Roeck 10753030bccSGuenter Roeck /* 10853030bccSGuenter Roeck * Common identification function for chips with multi-phase support. 10953030bccSGuenter Roeck * Since those chips have special configuration registers, we want to have 11053030bccSGuenter Roeck * some level of reassurance that we are really talking with the chip 11153030bccSGuenter Roeck * being probed. Check PMBus revision and chip ID. 11253030bccSGuenter Roeck */ 11353030bccSGuenter Roeck static int tps53679_identify_multiphase(struct i2c_client *client, 11453030bccSGuenter Roeck struct pmbus_driver_info *info, 11553030bccSGuenter Roeck int pmbus_rev, int device_id) 11653030bccSGuenter Roeck { 11753030bccSGuenter Roeck int ret; 11853030bccSGuenter Roeck 11953030bccSGuenter Roeck ret = tps53679_identify_chip(client, pmbus_rev, device_id); 12053030bccSGuenter Roeck if (ret < 0) 12153030bccSGuenter Roeck return ret; 12253030bccSGuenter Roeck 12353030bccSGuenter Roeck ret = tps53679_identify_mode(client, info); 12453030bccSGuenter Roeck if (ret < 0) 12553030bccSGuenter Roeck return ret; 12653030bccSGuenter Roeck 12753030bccSGuenter Roeck return tps53679_identify_phases(client, info); 12853030bccSGuenter Roeck } 12953030bccSGuenter Roeck 13053030bccSGuenter Roeck static int tps53679_identify(struct i2c_client *client, 13153030bccSGuenter Roeck struct pmbus_driver_info *info) 13253030bccSGuenter Roeck { 13353030bccSGuenter Roeck return tps53679_identify_mode(client, info); 13453030bccSGuenter Roeck } 13553030bccSGuenter Roeck 13653030bccSGuenter Roeck static int tps53681_identify(struct i2c_client *client, 13753030bccSGuenter Roeck struct pmbus_driver_info *info) 13853030bccSGuenter Roeck { 13953030bccSGuenter Roeck return tps53679_identify_multiphase(client, info, 14053030bccSGuenter Roeck TPS53681_PMBUS_REVISION, 14153030bccSGuenter Roeck TPS53681_DEVICE_ID); 14253030bccSGuenter Roeck } 14353030bccSGuenter Roeck 14453030bccSGuenter Roeck static int tps53681_read_word_data(struct i2c_client *client, int page, 14553030bccSGuenter Roeck int phase, int reg) 14653030bccSGuenter Roeck { 14753030bccSGuenter Roeck /* 14853030bccSGuenter Roeck * For reading the total output current (READ_IOUT) for all phases, 14953030bccSGuenter Roeck * the chip datasheet is a bit vague. It says "PHASE must be set to 15053030bccSGuenter Roeck * FFh to access all phases simultaneously. PHASE may also be set to 15153030bccSGuenter Roeck * 80h readack (!) the total phase current". 15253030bccSGuenter Roeck * Experiments show that the command does _not_ report the total 15353030bccSGuenter Roeck * current for all phases if the phase is set to 0xff. Instead, it 15453030bccSGuenter Roeck * appears to report the current of one of the phases. Override phase 15553030bccSGuenter Roeck * parameter with 0x80 when reading the total output current on page 0. 15653030bccSGuenter Roeck */ 15753030bccSGuenter Roeck if (reg == PMBUS_READ_IOUT && page == 0 && phase == 0xff) 15853030bccSGuenter Roeck return pmbus_read_word_data(client, page, 0x80, reg); 15953030bccSGuenter Roeck return -ENODATA; 16053030bccSGuenter Roeck } 16153030bccSGuenter Roeck 16261052652SVadim Pasternak static struct pmbus_driver_info tps53679_info = { 16361052652SVadim Pasternak .format[PSC_VOLTAGE_IN] = linear, 16461052652SVadim Pasternak .format[PSC_VOLTAGE_OUT] = vid, 16561052652SVadim Pasternak .format[PSC_TEMPERATURE] = linear, 16661052652SVadim Pasternak .format[PSC_CURRENT_OUT] = linear, 16761052652SVadim Pasternak .format[PSC_POWER] = linear, 16839c749acSGuenter Roeck .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | 16939c749acSGuenter Roeck PMBUS_HAVE_STATUS_INPUT | 17063eb4587SGuenter Roeck PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | 17161052652SVadim Pasternak PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | 17261052652SVadim Pasternak PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | 17361052652SVadim Pasternak PMBUS_HAVE_POUT, 17439c749acSGuenter Roeck .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | 17561052652SVadim Pasternak PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | 17661052652SVadim Pasternak PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | 17761052652SVadim Pasternak PMBUS_HAVE_POUT, 17853030bccSGuenter Roeck .pfunc[0] = PMBUS_HAVE_IOUT, 17953030bccSGuenter Roeck .pfunc[1] = PMBUS_HAVE_IOUT, 18053030bccSGuenter Roeck .pfunc[2] = PMBUS_HAVE_IOUT, 18153030bccSGuenter Roeck .pfunc[3] = PMBUS_HAVE_IOUT, 18253030bccSGuenter Roeck .pfunc[4] = PMBUS_HAVE_IOUT, 18353030bccSGuenter Roeck .pfunc[5] = PMBUS_HAVE_IOUT, 18461052652SVadim Pasternak }; 18561052652SVadim Pasternak 18661052652SVadim Pasternak static int tps53679_probe(struct i2c_client *client, 18761052652SVadim Pasternak const struct i2c_device_id *id) 18861052652SVadim Pasternak { 18963eb4587SGuenter Roeck struct device *dev = &client->dev; 190ff066653SVadim Pasternak struct pmbus_driver_info *info; 19163eb4587SGuenter Roeck enum chips chip_id; 192ff066653SVadim Pasternak 19363eb4587SGuenter Roeck if (dev->of_node) 19463eb4587SGuenter Roeck chip_id = (enum chips)of_device_get_match_data(dev); 19563eb4587SGuenter Roeck else 19663eb4587SGuenter Roeck chip_id = id->driver_data; 19763eb4587SGuenter Roeck 19863eb4587SGuenter Roeck info = devm_kmemdup(dev, &tps53679_info, sizeof(*info), GFP_KERNEL); 199ff066653SVadim Pasternak if (!info) 200ff066653SVadim Pasternak return -ENOMEM; 201ff066653SVadim Pasternak 20263eb4587SGuenter Roeck switch (chip_id) { 203*6f944004SGuenter Roeck case tps53647: 204*6f944004SGuenter Roeck case tps53667: 205*6f944004SGuenter Roeck info->pages = TPS53647_PAGE_NUM; 206*6f944004SGuenter Roeck info->identify = tps53679_identify; 207*6f944004SGuenter Roeck break; 20863eb4587SGuenter Roeck case tps53679: 20963eb4587SGuenter Roeck case tps53688: 21063eb4587SGuenter Roeck info->pages = TPS53679_PAGE_NUM; 21163eb4587SGuenter Roeck info->identify = tps53679_identify; 21263eb4587SGuenter Roeck break; 21353030bccSGuenter Roeck case tps53681: 21453030bccSGuenter Roeck info->pages = TPS53679_PAGE_NUM; 21553030bccSGuenter Roeck info->phases[0] = 6; 21653030bccSGuenter Roeck info->identify = tps53681_identify; 21753030bccSGuenter Roeck info->read_word_data = tps53681_read_word_data; 21853030bccSGuenter Roeck break; 21963eb4587SGuenter Roeck default: 22063eb4587SGuenter Roeck return -ENODEV; 22163eb4587SGuenter Roeck } 22263eb4587SGuenter Roeck 223ff066653SVadim Pasternak return pmbus_do_probe(client, id, info); 22461052652SVadim Pasternak } 22561052652SVadim Pasternak 22661052652SVadim Pasternak static const struct i2c_device_id tps53679_id[] = { 227*6f944004SGuenter Roeck {"tps53647", tps53647}, 228*6f944004SGuenter Roeck {"tps53667", tps53667}, 22963eb4587SGuenter Roeck {"tps53679", tps53679}, 23053030bccSGuenter Roeck {"tps53681", tps53681}, 23163eb4587SGuenter Roeck {"tps53688", tps53688}, 23261052652SVadim Pasternak {} 23361052652SVadim Pasternak }; 23461052652SVadim Pasternak 23561052652SVadim Pasternak MODULE_DEVICE_TABLE(i2c, tps53679_id); 23661052652SVadim Pasternak 237e91cb17bSGuenter Roeck static const struct of_device_id __maybe_unused tps53679_of_match[] = { 238*6f944004SGuenter Roeck {.compatible = "ti,tps53647", .data = (void *)tps53647}, 239*6f944004SGuenter Roeck {.compatible = "ti,tps53667", .data = (void *)tps53667}, 24063eb4587SGuenter Roeck {.compatible = "ti,tps53679", .data = (void *)tps53679}, 24153030bccSGuenter Roeck {.compatible = "ti,tps53681", .data = (void *)tps53681}, 24263eb4587SGuenter Roeck {.compatible = "ti,tps53688", .data = (void *)tps53688}, 24361052652SVadim Pasternak {} 24461052652SVadim Pasternak }; 24561052652SVadim Pasternak MODULE_DEVICE_TABLE(of, tps53679_of_match); 24661052652SVadim Pasternak 24761052652SVadim Pasternak static struct i2c_driver tps53679_driver = { 24861052652SVadim Pasternak .driver = { 24961052652SVadim Pasternak .name = "tps53679", 25061052652SVadim Pasternak .of_match_table = of_match_ptr(tps53679_of_match), 25161052652SVadim Pasternak }, 25261052652SVadim Pasternak .probe = tps53679_probe, 25361052652SVadim Pasternak .remove = pmbus_do_remove, 25461052652SVadim Pasternak .id_table = tps53679_id, 25561052652SVadim Pasternak }; 25661052652SVadim Pasternak 25761052652SVadim Pasternak module_i2c_driver(tps53679_driver); 25861052652SVadim Pasternak 25961052652SVadim Pasternak MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>"); 26061052652SVadim Pasternak MODULE_DESCRIPTION("PMBus driver for Texas Instruments TPS53679"); 26161052652SVadim Pasternak MODULE_LICENSE("GPL"); 262