xref: /openbmc/linux/drivers/hwmon/pmbus/xdp710.c (revision b12f6749)
1b12f6749SPeter Yin // SPDX-License-Identifier: GPL-2.0-or-later
2b12f6749SPeter Yin /*
3b12f6749SPeter Yin  * Driver for Infineon XDP710 Hot-Swap Controller
4b12f6749SPeter Yin  */
5b12f6749SPeter Yin 
6b12f6749SPeter Yin #include <linux/bitops.h>
7b12f6749SPeter Yin #include <linux/i2c.h>
8b12f6749SPeter Yin #include <linux/module.h>
9b12f6749SPeter Yin #include <linux/of_device.h>
10b12f6749SPeter Yin #include "pmbus.h"
11b12f6749SPeter Yin 
12b12f6749SPeter Yin #define XDP710_REG_CFG		0xD3
13b12f6749SPeter Yin #define XDP710_V_SNS_CFG	0xD4
14b12f6749SPeter Yin #define XDP710_CS_RNG		0xD5
15b12f6749SPeter Yin 
16b12f6749SPeter Yin /*
17b12f6749SPeter Yin  * The table to map configuration register values
18b12f6749SPeter Yin  * to sense resistor values
19b12f6749SPeter Yin  */
20b12f6749SPeter Yin static const int micro_ohm_rsense[] = {
21b12f6749SPeter Yin 	200, 250, 300, 330, 400, 470, 500, 600,
22b12f6749SPeter Yin 	670, 700, 750, 800, 900, 1000, 1100, 1200,
23b12f6749SPeter Yin 	1250, 1300, 1400, 1500, 1600, 1700, 1800, 1900,
24b12f6749SPeter Yin 	2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700,
25b12f6749SPeter Yin 	2800, 3000, 3100, 3200, 3300, 3400, 3500, 3600,
26b12f6749SPeter Yin 	3700, 3800, 3900, 4000, 4100, 4200, 4300, 4400,
27b12f6749SPeter Yin 	4500, 4600, 4700, 4800, 4900, 5000, 5500, 6000,
28b12f6749SPeter Yin 	6500, 7000, 7500, 8000, 8500, 9000, 9500, 10000
29b12f6749SPeter Yin };
30b12f6749SPeter Yin 
31b12f6749SPeter Yin static struct pmbus_driver_info xdp710_info = {
32b12f6749SPeter Yin 	.pages = 1,
33b12f6749SPeter Yin 	.format[PSC_VOLTAGE_IN] = direct,
34b12f6749SPeter Yin 	.format[PSC_VOLTAGE_OUT] = direct,
35b12f6749SPeter Yin 	.format[PSC_CURRENT_OUT] = direct,
36b12f6749SPeter Yin 	.format[PSC_POWER] = direct,
37b12f6749SPeter Yin 	.format[PSC_TEMPERATURE] = direct,
38b12f6749SPeter Yin 	.m[PSC_VOLTAGE_IN] = 4653,
39b12f6749SPeter Yin 	.b[PSC_VOLTAGE_IN] = 0,
40b12f6749SPeter Yin 	.R[PSC_VOLTAGE_IN] = -2,
41b12f6749SPeter Yin 	.m[PSC_VOLTAGE_OUT] = 4653,
42b12f6749SPeter Yin 	.b[PSC_VOLTAGE_OUT] = 0,
43b12f6749SPeter Yin 	.R[PSC_VOLTAGE_OUT] = -2,
44b12f6749SPeter Yin 	.m[PSC_CURRENT_OUT] = 23165,
45b12f6749SPeter Yin 	.b[PSC_CURRENT_OUT] = 0,
46b12f6749SPeter Yin 	.R[PSC_CURRENT_OUT] = -2,
47b12f6749SPeter Yin 	.m[PSC_POWER] = 4211,
48b12f6749SPeter Yin 	.b[PSC_POWER] = 0,
49b12f6749SPeter Yin 	.R[PSC_POWER] = -2,
50b12f6749SPeter Yin 	.m[PSC_TEMPERATURE] = 52,
51b12f6749SPeter Yin 	.b[PSC_TEMPERATURE] = 14321,
52b12f6749SPeter Yin 	.R[PSC_TEMPERATURE] = -1,
53b12f6749SPeter Yin 	.func[0] =
54b12f6749SPeter Yin 		PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_PIN |
55b12f6749SPeter Yin 		PMBUS_HAVE_TEMP | PMBUS_HAVE_IOUT |
56b12f6749SPeter Yin 		PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
57b12f6749SPeter Yin };
58b12f6749SPeter Yin 
xdp710_probe(struct i2c_client * client)59b12f6749SPeter Yin static int xdp710_probe(struct i2c_client *client)
60b12f6749SPeter Yin {
61b12f6749SPeter Yin 	struct pmbus_driver_info *info;
62b12f6749SPeter Yin 	u8 cs_rng;
63b12f6749SPeter Yin 	u8 vtlm_rng;
64b12f6749SPeter Yin 	int rsense;
65b12f6749SPeter Yin 	int ret;
66b12f6749SPeter Yin 	int m = 0;
67b12f6749SPeter Yin 
68b12f6749SPeter Yin 	info = devm_kmemdup(&client->dev, &xdp710_info, sizeof(*info),
69b12f6749SPeter Yin 			    GFP_KERNEL);
70b12f6749SPeter Yin 	if (!info)
71b12f6749SPeter Yin 		return -ENOMEM;
72b12f6749SPeter Yin 
73b12f6749SPeter Yin 	ret = i2c_smbus_read_word_data(client, XDP710_CS_RNG);
74b12f6749SPeter Yin 	if (ret < 0) {
75b12f6749SPeter Yin 		dev_err(&client->dev, "Can't get CS_RNG");
76b12f6749SPeter Yin 		return ret;
77b12f6749SPeter Yin 	}
78b12f6749SPeter Yin 	cs_rng = (ret >> 6) & GENMASK(1, 0);
79b12f6749SPeter Yin 
80b12f6749SPeter Yin 	ret = i2c_smbus_read_word_data(client, XDP710_V_SNS_CFG);
81b12f6749SPeter Yin 	if (ret < 0) {
82b12f6749SPeter Yin 		dev_err(&client->dev, "Can't get V_SNS_CFG");
83b12f6749SPeter Yin 		return ret;
84b12f6749SPeter Yin 	}
85b12f6749SPeter Yin 	vtlm_rng = ret & GENMASK(1, 0);
86b12f6749SPeter Yin 
87b12f6749SPeter Yin 	ret = i2c_smbus_read_word_data(client, XDP710_REG_CFG);
88b12f6749SPeter Yin 	if (ret < 0) {
89b12f6749SPeter Yin 		dev_err(&client->dev, "Can't get REG_CFG");
90b12f6749SPeter Yin 		return ret;
91b12f6749SPeter Yin 	}
92b12f6749SPeter Yin 	ret &= GENMASK(5, 0);
93b12f6749SPeter Yin 	rsense = micro_ohm_rsense[ret];
94b12f6749SPeter Yin 
95b12f6749SPeter Yin 	info->m[PSC_VOLTAGE_IN] <<= vtlm_rng;
96b12f6749SPeter Yin 	info->m[PSC_VOLTAGE_OUT] <<= vtlm_rng;
97b12f6749SPeter Yin 
98b12f6749SPeter Yin 	m = info->m[PSC_CURRENT_OUT];
99b12f6749SPeter Yin 	info->m[PSC_CURRENT_OUT] = DIV_ROUND_CLOSEST(m * rsense >> cs_rng, 1000);
100b12f6749SPeter Yin 
101b12f6749SPeter Yin 	m = info->m[PSC_POWER];
102b12f6749SPeter Yin 	info->m[PSC_POWER] = DIV_ROUND_CLOSEST(m * rsense >> cs_rng, 1000);
103b12f6749SPeter Yin 
104b12f6749SPeter Yin 	return pmbus_do_probe(client, info);
105b12f6749SPeter Yin }
106b12f6749SPeter Yin 
107b12f6749SPeter Yin static const struct of_device_id xdp710_of_match[] = {
108b12f6749SPeter Yin 	{ .compatible = "infineon,xdp710" },
109b12f6749SPeter Yin 	{}
110b12f6749SPeter Yin };
111b12f6749SPeter Yin 
112b12f6749SPeter Yin static const struct i2c_device_id xdp710_id[] = {
113b12f6749SPeter Yin 	{"xdp710", 0},
114b12f6749SPeter Yin 	{ }
115b12f6749SPeter Yin };
116b12f6749SPeter Yin MODULE_DEVICE_TABLE(i2c, xdp710_id);
117b12f6749SPeter Yin 
118b12f6749SPeter Yin static struct i2c_driver xdp710_driver = {
119b12f6749SPeter Yin 	.driver = {
120b12f6749SPeter Yin 		   .name = "xdp710",
121b12f6749SPeter Yin 		   .of_match_table = xdp710_of_match,
122b12f6749SPeter Yin 	},
123b12f6749SPeter Yin 	.probe = xdp710_probe,
124b12f6749SPeter Yin 	.id_table = xdp710_id,
125b12f6749SPeter Yin };
126b12f6749SPeter Yin module_i2c_driver(xdp710_driver);
127b12f6749SPeter Yin 
128b12f6749SPeter Yin MODULE_AUTHOR("Peter Yin <peter.yin@quantatw.com>");
129b12f6749SPeter Yin MODULE_DESCRIPTION("PMBus driver for XDP710 HSC");
130b12f6749SPeter Yin MODULE_LICENSE("GPL");
131b12f6749SPeter Yin MODULE_IMPORT_NS(PMBUS);
132