1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers |
4 | * |
5 | * Copyright (C) 2020 Nvidia Technologies Ltd. |
6 | */ |
7 | |
8 | #include <linux/err.h> |
9 | #include <linux/i2c.h> |
10 | #include <linux/init.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/module.h> |
13 | #include "pmbus.h" |
14 | |
15 | /* Vendor specific registers. */ |
16 | #define MP2888_MFR_SYS_CONFIG 0x44 |
17 | #define MP2888_MFR_READ_CS1_2 0x73 |
18 | #define MP2888_MFR_READ_CS3_4 0x74 |
19 | #define MP2888_MFR_READ_CS5_6 0x75 |
20 | #define MP2888_MFR_READ_CS7_8 0x76 |
21 | #define MP2888_MFR_READ_CS9_10 0x77 |
22 | #define MP2888_MFR_VR_CONFIG1 0xe1 |
23 | |
24 | #define MP2888_TOTAL_CURRENT_RESOLUTION BIT(3) |
25 | #define MP2888_PHASE_CURRENT_RESOLUTION BIT(4) |
26 | #define MP2888_DRMOS_KCS GENMASK(2, 0) |
27 | #define MP2888_TEMP_UNIT 10 |
28 | #define MP2888_MAX_PHASE 10 |
29 | |
30 | struct mp2888_data { |
31 | struct pmbus_driver_info info; |
32 | int total_curr_resolution; |
33 | int phase_curr_resolution; |
34 | int curr_sense_gain; |
35 | }; |
36 | |
37 | #define to_mp2888_data(x) container_of(x, struct mp2888_data, info) |
38 | |
39 | static int mp2888_read_byte_data(struct i2c_client *client, int page, int reg) |
40 | { |
41 | switch (reg) { |
42 | case PMBUS_VOUT_MODE: |
43 | /* Enforce VOUT direct format. */ |
44 | return PB_VOUT_MODE_DIRECT; |
45 | default: |
46 | return -ENODATA; |
47 | } |
48 | } |
49 | |
50 | static int |
51 | mp2888_current_sense_gain_and_resolution_get(struct i2c_client *client, struct mp2888_data *data) |
52 | { |
53 | int ret; |
54 | |
55 | /* |
56 | * Obtain DrMOS current sense gain of power stage from the register |
57 | * , bits 0-2. The value is selected as below: |
58 | * 00b - 5µA/A, 01b - 8.5µA/A, 10b - 9.7µA/A, 11b - 10µA/A. Other |
59 | * values are reserved. |
60 | */ |
61 | ret = i2c_smbus_read_word_data(client, MP2888_MFR_SYS_CONFIG); |
62 | if (ret < 0) |
63 | return ret; |
64 | |
65 | switch (ret & MP2888_DRMOS_KCS) { |
66 | case 0: |
67 | data->curr_sense_gain = 85; |
68 | break; |
69 | case 1: |
70 | data->curr_sense_gain = 97; |
71 | break; |
72 | case 2: |
73 | data->curr_sense_gain = 100; |
74 | break; |
75 | case 3: |
76 | data->curr_sense_gain = 50; |
77 | break; |
78 | default: |
79 | return -EINVAL; |
80 | } |
81 | |
82 | /* |
83 | * Obtain resolution selector for total and phase current report and protection. |
84 | * 0: original resolution; 1: half resolution (in such case phase current value should |
85 | * be doubled. |
86 | */ |
87 | data->total_curr_resolution = (ret & MP2888_TOTAL_CURRENT_RESOLUTION) >> 3; |
88 | data->phase_curr_resolution = (ret & MP2888_PHASE_CURRENT_RESOLUTION) >> 4; |
89 | |
90 | return 0; |
91 | } |
92 | |
93 | static int |
94 | mp2888_read_phase(struct i2c_client *client, struct mp2888_data *data, int page, int phase, u8 reg) |
95 | { |
96 | int ret; |
97 | |
98 | ret = pmbus_read_word_data(client, page, phase, reg); |
99 | if (ret < 0) |
100 | return ret; |
101 | |
102 | if (!((phase + 1) % 2)) |
103 | ret >>= 8; |
104 | ret &= 0xff; |
105 | |
106 | /* |
107 | * Output value is calculated as: (READ_CSx / 80 – 1.23) / (Kcs * Rcs) |
108 | * where: |
109 | * - Kcs is the DrMOS current sense gain of power stage, which is obtained from the |
110 | * register MP2888_MFR_VR_CONFIG1, bits 13-12 with the following selection of DrMOS |
111 | * (data->curr_sense_gain): |
112 | * 00b - 8.5µA/A, 01b - 9.7µA/A, 1b - 10µA/A, 11b - 5µA/A. |
113 | * - Rcs is the internal phase current sense resistor. This parameter depends on hardware |
114 | * assembly. By default it is set to 1kΩ. In case of different assembly, user should |
115 | * scale this parameter by dividing it by Rcs. |
116 | * If phase current resolution bit is set to 1, READ_CSx value should be doubled. |
117 | * Note, that current phase sensing, providing by the device is not accurate. This is |
118 | * because sampling of current occurrence of bit weight has a big deviation, especially for |
119 | * light load. |
120 | */ |
121 | ret = DIV_ROUND_CLOSEST(ret * 200 - 19600, data->curr_sense_gain); |
122 | /* Scale according to total current resolution. */ |
123 | ret = (data->total_curr_resolution) ? ret * 2 : ret; |
124 | return ret; |
125 | } |
126 | |
127 | static int |
128 | mp2888_read_phases(struct i2c_client *client, struct mp2888_data *data, int page, int phase) |
129 | { |
130 | int ret; |
131 | |
132 | switch (phase) { |
133 | case 0 ... 1: |
134 | ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS1_2); |
135 | break; |
136 | case 2 ... 3: |
137 | ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS3_4); |
138 | break; |
139 | case 4 ... 5: |
140 | ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS5_6); |
141 | break; |
142 | case 6 ... 7: |
143 | ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS7_8); |
144 | break; |
145 | case 8 ... 9: |
146 | ret = mp2888_read_phase(client, data, page, phase, MP2888_MFR_READ_CS9_10); |
147 | break; |
148 | default: |
149 | return -ENODATA; |
150 | } |
151 | return ret; |
152 | } |
153 | |
154 | static int mp2888_read_word_data(struct i2c_client *client, int page, int phase, int reg) |
155 | { |
156 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); |
157 | struct mp2888_data *data = to_mp2888_data(info); |
158 | int ret; |
159 | |
160 | switch (reg) { |
161 | case PMBUS_READ_VIN: |
162 | ret = pmbus_read_word_data(client, page, phase, reg); |
163 | if (ret <= 0) |
164 | return ret; |
165 | |
166 | /* |
167 | * READ_VIN requires fixup to scale it to linear11 format. Register data format |
168 | * provides 10 bits for mantissa and 6 bits for exponent. Bits 15:10 are set with |
169 | * the fixed value 111011b. |
170 | */ |
171 | ret = (ret & GENMASK(9, 0)) | ((ret & GENMASK(31, 10)) << 1); |
172 | break; |
173 | case PMBUS_OT_WARN_LIMIT: |
174 | ret = pmbus_read_word_data(client, page, phase, reg); |
175 | if (ret < 0) |
176 | return ret; |
177 | /* |
178 | * Chip reports limits in degrees C, but the actual temperature in 10th of |
179 | * degrees C - scaling is needed to match both. |
180 | */ |
181 | ret *= MP2888_TEMP_UNIT; |
182 | break; |
183 | case PMBUS_READ_IOUT: |
184 | if (phase != 0xff) |
185 | return mp2888_read_phases(client, data, page, phase); |
186 | |
187 | ret = pmbus_read_word_data(client, page, phase, reg); |
188 | if (ret < 0) |
189 | return ret; |
190 | /* |
191 | * READ_IOUT register has unused bits 15:12 with fixed value 1110b. Clear these |
192 | * bits and scale with total current resolution. Data is provided in direct format. |
193 | */ |
194 | ret &= GENMASK(11, 0); |
195 | ret = data->total_curr_resolution ? ret * 2 : ret; |
196 | break; |
197 | case PMBUS_IOUT_OC_WARN_LIMIT: |
198 | ret = pmbus_read_word_data(client, page, phase, reg); |
199 | if (ret < 0) |
200 | return ret; |
201 | ret &= GENMASK(9, 0); |
202 | /* |
203 | * Chip reports limits with resolution 1A or 2A, if total current resolution bit is |
204 | * set 1. Actual current is reported with 0.25A or respectively 0.5A resolution. |
205 | * Scaling is needed to match both. |
206 | */ |
207 | ret = data->total_curr_resolution ? ret * 8 : ret * 4; |
208 | break; |
209 | case PMBUS_READ_POUT: |
210 | case PMBUS_READ_PIN: |
211 | ret = pmbus_read_word_data(client, page, phase, reg); |
212 | if (ret < 0) |
213 | return ret; |
214 | ret = data->total_curr_resolution ? ret : DIV_ROUND_CLOSEST(ret, 2); |
215 | break; |
216 | case PMBUS_POUT_OP_WARN_LIMIT: |
217 | ret = pmbus_read_word_data(client, page, phase, reg); |
218 | if (ret < 0) |
219 | return ret; |
220 | /* |
221 | * Chip reports limits with resolution 1W or 2W, if total current resolution bit is |
222 | * set 1. Actual power is reported with 0.5W or 1W respectively resolution. Scaling |
223 | * is needed to match both. |
224 | */ |
225 | ret = data->total_curr_resolution ? ret * 2 : ret; |
226 | break; |
227 | /* |
228 | * The below registers are not implemented by device or implemented not according to the |
229 | * spec. Skip all of them to avoid exposing non-relevant inputs to sysfs. |
230 | */ |
231 | case PMBUS_OT_FAULT_LIMIT: |
232 | case PMBUS_UT_WARN_LIMIT: |
233 | case PMBUS_UT_FAULT_LIMIT: |
234 | case PMBUS_VIN_UV_FAULT_LIMIT: |
235 | case PMBUS_VOUT_UV_WARN_LIMIT: |
236 | case PMBUS_VOUT_OV_WARN_LIMIT: |
237 | case PMBUS_VOUT_UV_FAULT_LIMIT: |
238 | case PMBUS_VOUT_OV_FAULT_LIMIT: |
239 | case PMBUS_VIN_OV_WARN_LIMIT: |
240 | case PMBUS_IOUT_OC_LV_FAULT_LIMIT: |
241 | case PMBUS_IOUT_OC_FAULT_LIMIT: |
242 | case PMBUS_POUT_MAX: |
243 | case PMBUS_IOUT_UC_FAULT_LIMIT: |
244 | case PMBUS_POUT_OP_FAULT_LIMIT: |
245 | case PMBUS_PIN_OP_WARN_LIMIT: |
246 | case PMBUS_MFR_VIN_MIN: |
247 | case PMBUS_MFR_VOUT_MIN: |
248 | case PMBUS_MFR_VIN_MAX: |
249 | case PMBUS_MFR_VOUT_MAX: |
250 | case PMBUS_MFR_IIN_MAX: |
251 | case PMBUS_MFR_IOUT_MAX: |
252 | case PMBUS_MFR_PIN_MAX: |
253 | case PMBUS_MFR_POUT_MAX: |
254 | case PMBUS_MFR_MAX_TEMP_1: |
255 | return -ENXIO; |
256 | default: |
257 | return -ENODATA; |
258 | } |
259 | |
260 | return ret; |
261 | } |
262 | |
263 | static int mp2888_write_word_data(struct i2c_client *client, int page, int reg, u16 word) |
264 | { |
265 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); |
266 | struct mp2888_data *data = to_mp2888_data(info); |
267 | |
268 | switch (reg) { |
269 | case PMBUS_OT_WARN_LIMIT: |
270 | word = DIV_ROUND_CLOSEST(word, MP2888_TEMP_UNIT); |
271 | /* Drop unused bits 15:8. */ |
272 | word = clamp_val(word, 0, GENMASK(7, 0)); |
273 | break; |
274 | case PMBUS_IOUT_OC_WARN_LIMIT: |
275 | /* Fix limit according to total curent resolution. */ |
276 | word = data->total_curr_resolution ? DIV_ROUND_CLOSEST(word, 8) : |
277 | DIV_ROUND_CLOSEST(word, 4); |
278 | /* Drop unused bits 15:10. */ |
279 | word = clamp_val(word, 0, GENMASK(9, 0)); |
280 | break; |
281 | case PMBUS_POUT_OP_WARN_LIMIT: |
282 | /* Fix limit according to total curent resolution. */ |
283 | word = data->total_curr_resolution ? DIV_ROUND_CLOSEST(word, 4) : |
284 | DIV_ROUND_CLOSEST(word, 2); |
285 | /* Drop unused bits 15:10. */ |
286 | word = clamp_val(word, 0, GENMASK(9, 0)); |
287 | break; |
288 | default: |
289 | return -ENODATA; |
290 | } |
291 | return pmbus_write_word_data(client, page, reg, word); |
292 | } |
293 | |
294 | static int |
295 | mp2888_identify_multiphase(struct i2c_client *client, struct mp2888_data *data, |
296 | struct pmbus_driver_info *info) |
297 | { |
298 | int ret; |
299 | |
300 | ret = i2c_smbus_write_byte_data(client, command: PMBUS_PAGE, value: 0); |
301 | if (ret < 0) |
302 | return ret; |
303 | |
304 | /* Identify multiphase number - could be from 1 to 10. */ |
305 | ret = i2c_smbus_read_word_data(client, MP2888_MFR_VR_CONFIG1); |
306 | if (ret <= 0) |
307 | return ret; |
308 | |
309 | info->phases[0] = ret & GENMASK(3, 0); |
310 | |
311 | /* |
312 | * The device provides a total of 10 PWM pins, and can be configured to different phase |
313 | * count applications for rail. |
314 | */ |
315 | if (info->phases[0] > MP2888_MAX_PHASE) |
316 | return -EINVAL; |
317 | |
318 | return 0; |
319 | } |
320 | |
321 | static struct pmbus_driver_info mp2888_info = { |
322 | .pages = 1, |
323 | .format[PSC_VOLTAGE_IN] = linear, |
324 | .format[PSC_VOLTAGE_OUT] = direct, |
325 | .format[PSC_TEMPERATURE] = direct, |
326 | .format[PSC_CURRENT_IN] = linear, |
327 | .format[PSC_CURRENT_OUT] = direct, |
328 | .format[PSC_POWER] = direct, |
329 | .m[PSC_TEMPERATURE] = 1, |
330 | .R[PSC_TEMPERATURE] = 1, |
331 | .m[PSC_VOLTAGE_OUT] = 1, |
332 | .R[PSC_VOLTAGE_OUT] = 3, |
333 | .m[PSC_CURRENT_OUT] = 4, |
334 | .m[PSC_POWER] = 1, |
335 | .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT | |
336 | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | |
337 | PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | |
338 | PMBUS_PHASE_VIRTUAL, |
339 | .pfunc[0] = PMBUS_HAVE_IOUT, |
340 | .pfunc[1] = PMBUS_HAVE_IOUT, |
341 | .pfunc[2] = PMBUS_HAVE_IOUT, |
342 | .pfunc[3] = PMBUS_HAVE_IOUT, |
343 | .pfunc[4] = PMBUS_HAVE_IOUT, |
344 | .pfunc[5] = PMBUS_HAVE_IOUT, |
345 | .pfunc[6] = PMBUS_HAVE_IOUT, |
346 | .pfunc[7] = PMBUS_HAVE_IOUT, |
347 | .pfunc[8] = PMBUS_HAVE_IOUT, |
348 | .pfunc[9] = PMBUS_HAVE_IOUT, |
349 | .read_byte_data = mp2888_read_byte_data, |
350 | .read_word_data = mp2888_read_word_data, |
351 | .write_word_data = mp2888_write_word_data, |
352 | }; |
353 | |
354 | static int mp2888_probe(struct i2c_client *client) |
355 | { |
356 | struct pmbus_driver_info *info; |
357 | struct mp2888_data *data; |
358 | int ret; |
359 | |
360 | data = devm_kzalloc(dev: &client->dev, size: sizeof(struct mp2888_data), GFP_KERNEL); |
361 | if (!data) |
362 | return -ENOMEM; |
363 | |
364 | memcpy(&data->info, &mp2888_info, sizeof(*info)); |
365 | info = &data->info; |
366 | |
367 | /* Identify multiphase configuration. */ |
368 | ret = mp2888_identify_multiphase(client, data, info); |
369 | if (ret) |
370 | return ret; |
371 | |
372 | /* Obtain current sense gain of power stage and current resolution. */ |
373 | ret = mp2888_current_sense_gain_and_resolution_get(client, data); |
374 | if (ret) |
375 | return ret; |
376 | |
377 | return pmbus_do_probe(client, info); |
378 | } |
379 | |
380 | static const struct i2c_device_id mp2888_id[] = { |
381 | {"mp2888" , 0}, |
382 | {} |
383 | }; |
384 | |
385 | MODULE_DEVICE_TABLE(i2c, mp2888_id); |
386 | |
387 | static const struct of_device_id __maybe_unused mp2888_of_match[] = { |
388 | {.compatible = "mps,mp2888" }, |
389 | {} |
390 | }; |
391 | MODULE_DEVICE_TABLE(of, mp2888_of_match); |
392 | |
393 | static struct i2c_driver mp2888_driver = { |
394 | .driver = { |
395 | .name = "mp2888" , |
396 | .of_match_table = of_match_ptr(mp2888_of_match), |
397 | }, |
398 | .probe = mp2888_probe, |
399 | .id_table = mp2888_id, |
400 | }; |
401 | |
402 | module_i2c_driver(mp2888_driver); |
403 | |
404 | MODULE_AUTHOR("Vadim Pasternak <vadimp@nvidia.com>" ); |
405 | MODULE_DESCRIPTION("PMBus driver for MPS MP2888 device" ); |
406 | MODULE_LICENSE("GPL" ); |
407 | MODULE_IMPORT_NS(PMBUS); |
408 | |