xref: /linux/drivers/hwmon/pmbus/vt7505.c (revision 7acf90feab8b009fde7def08ff2c622d0f10e99f)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Hardware monitoring driver for Analog Devices MAX16545/MAX16550 and
4  * Volterra VT7505 PMBus controllers.
5  *
6  * Copyright 2026 Hewlett Packard Enterprise Development LP
7  */
8 
9 #include <linux/bitfield.h>
10 #include <linux/i2c.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/of.h>
14 #include <linux/pmbus.h>
15 
16 #include "pmbus.h"
17 
18 #define VT7505_MFR_CONFIG		0xd0
19 #define VT7505_CFG_OCP_S_FILT_MASK	GENMASK(15, 14)
20 
21 #define VT7505_MFR_PEAK_VIN		0xd1
22 #define VT7505_MFR_PEAK_IOUT		0xd2
23 #define VT7505_MFR_PEAK_PIN		0xd3
24 #define VT7505_MFR_PEAK_TEMP		0xd4
25 #define VT7505_MFR_CLEAR_PEAKS		0xd5
26 #define VT7505_MFR_PEAK_VOUT		0xfd
27 
28 #define VT7505_RLOAD_DEFAULT		4750
29 /* Largest RLOAD for which coeff * rload / 1000 still fits in s32. */
30 #define VT7505_RLOAD_MAX		283383959U
31 
32 struct vt7505_chip_data {
33 	int temp_m;
34 	int temp_b;
35 	bool has_ocp_filter;
36 };
37 
38 static const struct vt7505_chip_data max16545_data = {
39 	.temp_m = 205,
40 	.temp_b = 6545,
41 };
42 
43 static const struct vt7505_chip_data max16550_data = {
44 	.temp_m = 199,
45 	.temp_b = 7046,
46 	.has_ocp_filter = true,
47 };
48 
49 static const struct vt7505_chip_data vt7505_data = {
50 	.temp_m = 205,
51 	.temp_b = 6545,
52 	.has_ocp_filter = true,
53 };
54 
55 static int vt7505_read_word_data(struct i2c_client *client, int page,
56 				 int phase, int reg)
57 {
58 	switch (reg) {
59 	case PMBUS_VIRT_READ_VIN_MAX:
60 		return pmbus_read_word_data(client, page, phase,
61 					    VT7505_MFR_PEAK_VIN);
62 	case PMBUS_VIRT_READ_IOUT_MAX:
63 		return pmbus_read_word_data(client, page, phase,
64 					    VT7505_MFR_PEAK_IOUT);
65 	case PMBUS_VIRT_READ_PIN_MAX:
66 		return pmbus_read_word_data(client, page, phase,
67 					    VT7505_MFR_PEAK_PIN);
68 	case PMBUS_VIRT_READ_TEMP_MAX:
69 		return pmbus_read_word_data(client, page, phase,
70 					    VT7505_MFR_PEAK_TEMP);
71 	case PMBUS_VIRT_READ_VOUT_MAX:
72 		return pmbus_read_word_data(client, page, phase,
73 					    VT7505_MFR_PEAK_VOUT);
74 	case PMBUS_VIRT_RESET_VIN_HISTORY:
75 	case PMBUS_VIRT_RESET_IOUT_HISTORY:
76 	case PMBUS_VIRT_RESET_PIN_HISTORY:
77 	case PMBUS_VIRT_RESET_TEMP_HISTORY:
78 	case PMBUS_VIRT_RESET_VOUT_HISTORY:
79 		return 0;
80 	default:
81 		return -ENODATA;
82 	}
83 }
84 
85 static int vt7505_write_word_data(struct i2c_client *client, int page,
86 				  int reg, u16 word)
87 {
88 	switch (reg) {
89 	/*
90 	 * A single reset command clears all peak values. CLEAR_PEAKS is a
91 	 * send-byte command; the device NAKs a word or byte-data write to it.
92 	 */
93 	case PMBUS_VIRT_RESET_VIN_HISTORY:
94 	case PMBUS_VIRT_RESET_IOUT_HISTORY:
95 	case PMBUS_VIRT_RESET_PIN_HISTORY:
96 	case PMBUS_VIRT_RESET_TEMP_HISTORY:
97 	case PMBUS_VIRT_RESET_VOUT_HISTORY:
98 		return pmbus_write_byte(client, page,
99 					VT7505_MFR_CLEAR_PEAKS);
100 	default:
101 		return -ENODATA;
102 	}
103 }
104 
105 /*
106  * None of these controllers implement the standard PMBus WRITE_PROTECT
107  * (0x10) register, so tell the core not to access it.
108  */
109 static struct pmbus_platform_data vt7505_pdata = {
110 	.flags = PMBUS_NO_WRITE_PROTECT,
111 };
112 
113 static int vt7505_set_ocp_filter(struct i2c_client *client)
114 {
115 	u32 ocp_us;
116 	u8 field;
117 	int ret;
118 	u16 word;
119 
120 	if (of_property_read_u32(client->dev.of_node, "adi,ocp-severe-filter-us",
121 				 &ocp_us))
122 		return 0;
123 
124 	switch (ocp_us) {
125 	case 0:
126 		field = 0;
127 		break;
128 	case 1:
129 		field = 1;
130 		break;
131 	case 2:
132 		field = 2;
133 		break;
134 	case 10:
135 		field = 3;
136 		break;
137 	default:
138 		return dev_err_probe(&client->dev, -EINVAL,
139 				     "invalid adi,ocp-severe-filter-us value %u\n",
140 				     ocp_us);
141 	}
142 
143 	ret = i2c_smbus_read_word_data(client, VT7505_MFR_CONFIG);
144 	if (ret < 0)
145 		return dev_err_probe(&client->dev, ret,
146 				     "failed to read MFR_CONFIG\n");
147 
148 	word = ret & ~VT7505_CFG_OCP_S_FILT_MASK;
149 	word |= FIELD_PREP(VT7505_CFG_OCP_S_FILT_MASK, field);
150 
151 	ret = i2c_smbus_write_word_data(client, VT7505_MFR_CONFIG, word);
152 	if (ret < 0)
153 		return dev_err_probe(&client->dev, ret,
154 				     "failed to write MFR_CONFIG\n");
155 
156 	return 0;
157 }
158 
159 static void vt7505_set_m(int *m, u32 rload)
160 {
161 	u64 val = (u64)*m * rload;
162 
163 	/* rload is range-checked in probe, so the result fits in int. */
164 	*m = DIV_ROUND_CLOSEST_ULL(val, 1000);
165 }
166 
167 static int vt7505_probe(struct i2c_client *client)
168 {
169 	struct device *dev = &client->dev;
170 	const struct vt7505_chip_data *chip;
171 	struct pmbus_driver_info *info;
172 	u32 rload;
173 	int ret;
174 
175 	chip = i2c_get_match_data(client);
176 	if (!chip)
177 		return -ENODEV;
178 
179 	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
180 	if (!info)
181 		return -ENOMEM;
182 
183 	dev->platform_data = &vt7505_pdata;
184 
185 	/*
186 	 * The m coefficient used in the direct-format current and power
187 	 * calculations depends on RLOAD, the external current-report resistor
188 	 * connected between the ILOAD pin and ground. Use the default value if
189 	 * none is specified.
190 	 */
191 	if (of_property_read_u32(dev->of_node, "adi,rload-ohms", &rload))
192 		rload = VT7505_RLOAD_DEFAULT;
193 
194 	if (!rload || rload > VT7505_RLOAD_MAX)
195 		return dev_err_probe(dev, -EINVAL,
196 				     "adi,rload-ohms must be 1-%u\n",
197 				     VT7505_RLOAD_MAX);
198 
199 	info->pages = 1;
200 	info->read_word_data = vt7505_read_word_data;
201 	info->write_word_data = vt7505_write_word_data;
202 
203 	info->format[PSC_VOLTAGE_IN] = direct;
204 	info->format[PSC_VOLTAGE_OUT] = direct;
205 	info->format[PSC_CURRENT_IN] = direct;
206 	info->format[PSC_CURRENT_OUT] = direct;
207 	info->format[PSC_POWER] = direct;
208 	info->format[PSC_TEMPERATURE] = direct;
209 
210 	/*
211 	 * Direct data format coefficients from the device datasheet ("PMBus
212 	 * Equation Parameters"). The current and power m coefficients scale
213 	 * with RLOAD; vt7505_set_m() applies the 1/1000 factor below, giving
214 	 * m = 3.824 * RLOAD for current and 0.895 * RLOAD for power. The
215 	 * temperature coefficients are chip specific (see the chip data).
216 	 */
217 	info->m[PSC_VOLTAGE_IN] = 7578;
218 	info->R[PSC_VOLTAGE_IN] = -2;
219 	info->m[PSC_VOLTAGE_OUT] = 7578;
220 	info->R[PSC_VOLTAGE_OUT] = -2;
221 	info->m[PSC_CURRENT_IN] = 3824;
222 	info->b[PSC_CURRENT_IN] = -4300;
223 	info->R[PSC_CURRENT_IN] = -3;
224 	info->m[PSC_CURRENT_OUT] = 3824;
225 	info->b[PSC_CURRENT_OUT] = -4300;
226 	info->R[PSC_CURRENT_OUT] = -3;
227 	info->m[PSC_POWER] = 895;
228 	info->b[PSC_POWER] = -9100;
229 	info->R[PSC_POWER] = -2;
230 
231 	vt7505_set_m(&info->m[PSC_CURRENT_IN], rload);
232 	vt7505_set_m(&info->m[PSC_CURRENT_OUT], rload);
233 	vt7505_set_m(&info->m[PSC_POWER], rload);
234 
235 	info->m[PSC_TEMPERATURE] = chip->temp_m;
236 	info->b[PSC_TEMPERATURE] = chip->temp_b;
237 	info->R[PSC_TEMPERATURE] = -2;
238 
239 	info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT |
240 			PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
241 			PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
242 			PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
243 			PMBUS_HAVE_IIN | PMBUS_HAVE_PIN;
244 
245 	/*
246 	 * The severe OCP deglitch filter is programmable on the MAX16550 and
247 	 * the VT7505, but fixed on the MAX16545.
248 	 */
249 	if (chip->has_ocp_filter) {
250 		ret = vt7505_set_ocp_filter(client);
251 		if (ret)
252 			return ret;
253 	}
254 
255 	return pmbus_do_probe(client, info);
256 }
257 
258 static const struct i2c_device_id vt7505_id[] = {
259 	{ .name = "max16545", .driver_data = (kernel_ulong_t)&max16545_data },
260 	{ .name = "max16550", .driver_data = (kernel_ulong_t)&max16550_data },
261 	{ .name = "vt7505", .driver_data = (kernel_ulong_t)&vt7505_data },
262 	{ }
263 };
264 MODULE_DEVICE_TABLE(i2c, vt7505_id);
265 
266 static const struct of_device_id vt7505_of_match[] = {
267 	{ .compatible = "adi,max16545", .data = &max16545_data },
268 	{ .compatible = "adi,max16550", .data = &max16550_data },
269 	{ .compatible = "adi,vt7505", .data = &vt7505_data },
270 	{ }
271 };
272 MODULE_DEVICE_TABLE(of, vt7505_of_match);
273 
274 static struct i2c_driver vt7505_driver = {
275 	.driver = {
276 		.name = "vt7505",
277 		.of_match_table = vt7505_of_match,
278 	},
279 	.probe = vt7505_probe,
280 	.id_table = vt7505_id,
281 };
282 module_i2c_driver(vt7505_driver);
283 
284 MODULE_AUTHOR("Georgi Vlaev <gvlaev@juniper.net>");
285 MODULE_DESCRIPTION("PMBus driver for Analog Devices MAX16545/MAX16550 and Volterra VT7505");
286 MODULE_LICENSE("GPL");
287 MODULE_IMPORT_NS("PMBUS");
288