xref: /linux/drivers/hwmon/pmbus/tps53679.c (revision 6f944004f873e3036fabc4b3f14a96899fefbff5)
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