xref: /linux/drivers/hwmon/pmbus/mp2985.c (revision 805185b7c7a1069e407b6f7b3bc98e44d415f484)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers(MP2985)
4  *
5  * Copyright (C) 2026 MPS
6  */
7 
8 #include <linux/bitfield.h>
9 #include <linux/i2c.h>
10 #include <linux/module.h>
11 #include <linux/of_device.h>
12 #include "pmbus.h"
13 
14 /*
15  * Vender specific register READ_PIN_EST(0x93), READ_IIN_EST(0x8E),
16  * MFR_VR_MULTI_CONFIG_R1(0x0D) and MFR_VR_MULTI_CONFIG_R2(0x1D).
17  * The READ_PIN_EST is used to read pin telemetry, the READ_IIN_EST
18  * is used to read iin telemetry and the MFR_VR_MULTI_CONFIG_R1,
19  * MFR_VR_MULTI_CONFIG_R2 are used to obtain vid scale.
20  */
21 #define READ_PIN_EST	0x93
22 #define READ_IIN_EST	0x8E
23 #define MFR_VR_MULTI_CONFIG_R1	0x0D
24 #define MFR_VR_MULTI_CONFIG_R2	0x1D
25 
26 #define MP2985_VOUT_DIV	64
27 #define MP2985_VOUT_OVUV_UINT	125
28 #define MP2985_VOUT_OVUV_DIV	64
29 
30 #define MP2985_PAGE_NUM	2
31 
32 #define MP2985_RAIL1_FUNC	(PMBUS_HAVE_VIN | PMBUS_HAVE_PIN | \
33 							 PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | \
34 							 PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP | \
35 							 PMBUS_HAVE_STATUS_VOUT | \
36 							 PMBUS_HAVE_STATUS_IOUT | \
37 							 PMBUS_HAVE_STATUS_TEMP | \
38 							 PMBUS_HAVE_STATUS_INPUT)
39 
40 #define MP2985_RAIL2_FUNC	(PMBUS_HAVE_PIN | PMBUS_HAVE_VOUT | \
41 							 PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT | \
42 							 PMBUS_HAVE_TEMP | PMBUS_HAVE_IIN | \
43 							 PMBUS_HAVE_STATUS_VOUT | \
44 							 PMBUS_HAVE_STATUS_IOUT | \
45 							 PMBUS_HAVE_STATUS_TEMP | \
46 							 PMBUS_HAVE_STATUS_INPUT)
47 
48 struct mp2985_data {
49 	struct pmbus_driver_info info;
50 	int vout_scale[MP2985_PAGE_NUM];
51 	int vid_offset[MP2985_PAGE_NUM];
52 };
53 
54 #define to_mp2985_data(x) container_of(x, struct mp2985_data, info)
55 
56 static u16 mp2985_linear_exp_transfer(u16 word, u16 expect_exponent)
57 {
58 	s16 exponent, mantissa, target_exponent;
59 
60 	exponent = ((s16)word) >> 11;
61 	mantissa = ((s16)((word & 0x7ff) << 5)) >> 5;
62 	target_exponent = (s16)((expect_exponent & 0x1f) << 11) >> 11;
63 
64 	/*
65 	 * The MP2985 does not support negtive limit value, if a negtive
66 	 * limit value is written, the limit value will become to 0. And
67 	 * the maximum positive limit value is limitted to 0x3FF.
68 	 */
69 	if (mantissa < 0) {
70 		mantissa = 0;
71 	} else {
72 		if (exponent > target_exponent) {
73 			mantissa = (1023 >> (exponent - target_exponent)) >= mantissa ?
74 						mantissa << (exponent - target_exponent) :
75 						0x3FF;
76 		} else {
77 			mantissa = clamp_val(mantissa >> (target_exponent - exponent),
78 					     0, 0x3FF);
79 		}
80 	}
81 
82 	return mantissa | ((expect_exponent << 11) & 0xf800);
83 }
84 
85 static int mp2985_read_byte_data(struct i2c_client *client, int page, int reg)
86 {
87 	int ret;
88 
89 	switch (reg) {
90 	case PMBUS_VOUT_MODE:
91 		/*
92 		 * The MP2985 does not follow standard PMBus protocol completely,
93 		 * and the calculation of vout in this driver is based on direct
94 		 * format. As a result, the format of vout is enforced to direct.
95 		 */
96 		ret = PB_VOUT_MODE_DIRECT;
97 		break;
98 	default:
99 		ret = -ENODATA;
100 		break;
101 	}
102 
103 	return ret;
104 }
105 
106 static int mp2985_read_word_data(struct i2c_client *client, int page, int phase,
107 				 int reg)
108 {
109 	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
110 	struct mp2985_data *data = to_mp2985_data(info);
111 	int ret;
112 
113 	switch (reg) {
114 	case PMBUS_READ_VOUT:
115 		ret = pmbus_read_word_data(client, page, phase, reg);
116 		if (ret < 0)
117 			return ret;
118 
119 		/*
120 		 * The MP2985 supports three vout mode, direct, linear11 and vid mode.
121 		 * In vid mode, the MP2985 vout telemetry has 49 vid step offset, but
122 		 * PMBUS_VOUT_OV_FAULT_LIMIT and PMBUS_VOUT_UV_FAULT_LIMIT do not take
123 		 * this into consideration, their resolution are 1.953125mV/LSB, as a
124 		 * result, format[PSC_VOLTAGE_OUT] can not be set to vid mode directly.
125 		 * Adding extra vid_offset variable for vout telemetry.
126 		 */
127 		ret = clamp_val(DIV_ROUND_CLOSEST(((ret & GENMASK(11, 0)) +
128 									data->vid_offset[page]) *
129 							data->vout_scale[page], MP2985_VOUT_DIV),
130 							0, 0x7FFF);
131 		break;
132 	case PMBUS_READ_IIN:
133 		/*
134 		 * The MP2985 has standard PMBUS_READ_IIN register(0x89), but this is
135 		 * not used to read the input current of per rail. The input current
136 		 * is read through the vender redefined register READ_IIN_EST(0x8E).
137 		 */
138 		ret = pmbus_read_word_data(client, page, phase, READ_IIN_EST);
139 		break;
140 	case PMBUS_READ_PIN:
141 		/*
142 		 * The MP2985 has standard PMBUS_READ_PIN register(0x97), but this
143 		 * is not used to read the input power of per rail. The input power
144 		 * of per rail is read through the vender redefined register
145 		 * READ_PIN_EST(0x93).
146 		 */
147 		ret = pmbus_read_word_data(client, page, phase, READ_PIN_EST);
148 		break;
149 	case PMBUS_VOUT_OV_FAULT_LIMIT:
150 	case PMBUS_VOUT_UV_FAULT_LIMIT:
151 		ret = pmbus_read_word_data(client, page, phase, reg);
152 		if (ret < 0)
153 			return ret;
154 
155 		ret = DIV_ROUND_CLOSEST((ret & GENMASK(11, 0)) * MP2985_VOUT_OVUV_UINT,
156 					MP2985_VOUT_OVUV_DIV);
157 		break;
158 	case PMBUS_STATUS_WORD:
159 	case PMBUS_READ_VIN:
160 	case PMBUS_READ_IOUT:
161 	case PMBUS_READ_POUT:
162 	case PMBUS_READ_TEMPERATURE_1:
163 	case PMBUS_VIN_OV_FAULT_LIMIT:
164 	case PMBUS_VIN_OV_WARN_LIMIT:
165 	case PMBUS_VIN_UV_WARN_LIMIT:
166 	case PMBUS_VIN_UV_FAULT_LIMIT:
167 	case PMBUS_IOUT_OC_FAULT_LIMIT:
168 	case PMBUS_IOUT_OC_WARN_LIMIT:
169 	case PMBUS_OT_FAULT_LIMIT:
170 	case PMBUS_OT_WARN_LIMIT:
171 		/*
172 		 * These register is not explicitly handled by the driver,
173 		 * as a result, return -ENODATA directly.
174 		 */
175 		ret = -ENODATA;
176 		break;
177 	default:
178 		/*
179 		 * The MP2985 do not support other telemetry and limit value
180 		 * reading, so, return -EINVAL directly.
181 		 */
182 		ret = -EINVAL;
183 		break;
184 	}
185 
186 	return ret;
187 }
188 
189 static int mp2985_write_word_data(struct i2c_client *client, int page, int reg,
190 				  u16 word)
191 {
192 	int ret;
193 
194 	switch (reg) {
195 	case PMBUS_VIN_OV_FAULT_LIMIT:
196 	case PMBUS_VIN_OV_WARN_LIMIT:
197 	case PMBUS_VIN_UV_WARN_LIMIT:
198 	case PMBUS_VIN_UV_FAULT_LIMIT:
199 		/*
200 		 * The PMBUS_VIN_OV_FAULT_LIMIT, PMBUS_VIN_OV_WARN_LIMIT,
201 		 * PMBUS_VIN_UV_WARN_LIMIT and PMBUS_VIN_UV_FAULT_LIMIT
202 		 * of MP2985 is linear11 format, and the exponent is a
203 		 * constant value(5'b11101), so the exponent of word
204 		 * parameter should be converted to 5'b11101(0x1D).
205 		 */
206 		ret = pmbus_write_word_data(client, page, reg,
207 					    mp2985_linear_exp_transfer(word, 0x1D));
208 		break;
209 	case PMBUS_VOUT_OV_FAULT_LIMIT:
210 	case PMBUS_VOUT_UV_FAULT_LIMIT:
211 		/*
212 		 * The bit0-bit11 is the limit value, and bit12-bit15
213 		 * should not be changed.
214 		 */
215 		ret = pmbus_read_word_data(client, page, 0xff, reg);
216 		if (ret < 0)
217 			return ret;
218 
219 		ret = pmbus_write_word_data(client, page, reg,
220 					    (ret & ~GENMASK(11, 0)) |
221 				clamp_val(DIV_ROUND_CLOSEST(word * MP2985_VOUT_OVUV_DIV,
222 							    MP2985_VOUT_OVUV_UINT), 0, 0xFFF));
223 		break;
224 	case PMBUS_OT_FAULT_LIMIT:
225 	case PMBUS_OT_WARN_LIMIT:
226 		/*
227 		 * The PMBUS_OT_FAULT_LIMIT and PMBUS_OT_WARN_LIMIT of
228 		 * MP2985 is linear11 format, and the exponent is a
229 		 * constant value(5'b00000), so the exponent of word
230 		 * parameter should be converted to 5'b00000.
231 		 */
232 		ret = pmbus_write_word_data(client, page, reg,
233 					    mp2985_linear_exp_transfer(word, 0x00));
234 		break;
235 	case PMBUS_IOUT_OC_FAULT_LIMIT:
236 	case PMBUS_IOUT_OC_WARN_LIMIT:
237 		/*
238 		 * The PMBUS_IOUT_OC_FAULT_LIMIT and PMBUS_IOUT_OC_WARN_LIMIT
239 		 * of MP2985 is linear11 format, and the exponent can not be
240 		 * changed.
241 		 */
242 		ret = pmbus_read_word_data(client, page, 0xff, reg);
243 		if (ret < 0)
244 			return ret;
245 
246 		ret = pmbus_write_word_data(client, page, reg,
247 					    mp2985_linear_exp_transfer(word,
248 								       FIELD_GET(GENMASK(15, 11),
249 										 ret)));
250 		break;
251 	default:
252 		/*
253 		 * The MP2985 do not support other limit value configuration,
254 		 * so, return -EINVAL directly.
255 		 */
256 		ret = -EINVAL;
257 		break;
258 	}
259 
260 	return ret;
261 }
262 
263 static int
264 mp2985_identify_vout_scale(struct i2c_client *client, struct pmbus_driver_info *info,
265 			   int page)
266 {
267 	struct mp2985_data *data = to_mp2985_data(info);
268 	int ret;
269 
270 	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
271 	if (ret < 0)
272 		return ret;
273 
274 	ret = i2c_smbus_read_byte_data(client, PMBUS_VOUT_MODE);
275 	if (ret < 0)
276 		return ret;
277 
278 	/*
279 	 * The MP2985 supports three vout mode. If PMBUS_VOUT_MODE
280 	 * bit5 is 1, it is vid mode. If PMBUS PMBUS_VOUT_MODE bit4
281 	 * is 1, it is linear11 mode, the vout scale is 1.953125mv/LSB.
282 	 * If PMBUS PMBUS_VOUT_MODE bit6 is 1, it is direct mode, the
283 	 * vout scale is 1mv/LSB. In vid mode, the MP2985 vout telemetry
284 	 * has 49 vid step offset.
285 	 */
286 	if (FIELD_GET(BIT(5), ret)) {
287 		ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2);
288 		if (ret < 0)
289 			return ret;
290 
291 		ret = i2c_smbus_read_word_data(client, page == 0 ?
292 						MFR_VR_MULTI_CONFIG_R1 :
293 						MFR_VR_MULTI_CONFIG_R2);
294 		if (ret < 0)
295 			return ret;
296 
297 		if (page == 0) {
298 			if (FIELD_GET(BIT(4), ret))
299 				data->vout_scale[page] = 320;
300 			else
301 				data->vout_scale[page] = 640;
302 		} else {
303 			if (FIELD_GET(BIT(3), ret))
304 				data->vout_scale[page] = 320;
305 			else
306 				data->vout_scale[page] = 640;
307 		}
308 
309 		data->vid_offset[page] = 49;
310 
311 		/*
312 		 * For vid mode, the MP2985 should be changed to page 2
313 		 * to obtain vout scale value, this may confuse the PMBus
314 		 * core. To avoid this, switch back to the previous page
315 		 * again.
316 		 */
317 		ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
318 		if (ret < 0)
319 			return ret;
320 	} else if (FIELD_GET(BIT(4), ret)) {
321 		data->vout_scale[page] = 125;
322 		data->vid_offset[page] = 0;
323 	} else {
324 		data->vout_scale[page] = 64;
325 		data->vid_offset[page] = 0;
326 	}
327 
328 	return 0;
329 }
330 
331 static int mp2985_identify(struct i2c_client *client, struct pmbus_driver_info *info)
332 {
333 	int ret;
334 
335 	ret = mp2985_identify_vout_scale(client, info, 0);
336 	if (ret < 0)
337 		return ret;
338 
339 	return mp2985_identify_vout_scale(client, info, 1);
340 }
341 
342 static struct pmbus_driver_info mp2985_info = {
343 	.pages = MP2985_PAGE_NUM,
344 	.format[PSC_VOLTAGE_IN] = linear,
345 	.format[PSC_CURRENT_IN] = linear,
346 	.format[PSC_CURRENT_OUT] = linear,
347 	.format[PSC_POWER] = linear,
348 	.format[PSC_TEMPERATURE] = linear,
349 	.format[PSC_VOLTAGE_OUT] = direct,
350 
351 	.m[PSC_VOLTAGE_OUT] = 1,
352 	.R[PSC_VOLTAGE_OUT] = 3,
353 	.b[PSC_VOLTAGE_OUT] = 0,
354 
355 	.func[0] = MP2985_RAIL1_FUNC,
356 	.func[1] = MP2985_RAIL2_FUNC,
357 	.read_word_data = mp2985_read_word_data,
358 	.read_byte_data = mp2985_read_byte_data,
359 	.write_word_data = mp2985_write_word_data,
360 	.identify = mp2985_identify,
361 };
362 
363 static int mp2985_probe(struct i2c_client *client)
364 {
365 	struct mp2985_data *data;
366 
367 	data = devm_kzalloc(&client->dev, sizeof(struct mp2985_data), GFP_KERNEL);
368 	if (!data)
369 		return -ENOMEM;
370 
371 	memcpy(&data->info, &mp2985_info, sizeof(mp2985_info));
372 
373 	return pmbus_do_probe(client, &data->info);
374 }
375 
376 static const struct i2c_device_id mp2985_id[] = {
377 	{"mp2985", 0},
378 	{}
379 };
380 MODULE_DEVICE_TABLE(i2c, mp2985_id);
381 
382 static const struct of_device_id __maybe_unused mp2985_of_match[] = {
383 	{.compatible = "mps,mp2985"},
384 	{}
385 };
386 MODULE_DEVICE_TABLE(of, mp2985_of_match);
387 
388 static struct i2c_driver mp2985_driver = {
389 	.driver = {
390 		.name = "mp2985",
391 		.of_match_table = mp2985_of_match,
392 	},
393 	.probe = mp2985_probe,
394 	.id_table = mp2985_id,
395 };
396 
397 module_i2c_driver(mp2985_driver);
398 
399 MODULE_AUTHOR("Wensheng Wang <wenswang@yeah.net>");
400 MODULE_DESCRIPTION("PMBus driver for MPS MP2985 device");
401 MODULE_LICENSE("GPL");
402 MODULE_IMPORT_NS("PMBUS");
403