Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

hwmon: add MP29502 driver

Add support for MPS VR controller mp29502. This driver exposes
telemetry and limits value readings and writtings.

Signed-off-by: Wensheng Wang <wenswang@yeah.net>
Link: https://lore.kernel.org/r/20250805102020.749850-3-wenswang@yeah.net
[groeck: Fixed document formatting]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>

authored by

Wensheng Wang and committed by
Guenter Roeck
90bad684 a3a2923a

+781
+1
Documentation/hwmon/index.rst
··· 176 176 mp2869 177 177 mp2888 178 178 mp2891 179 + mp29502 179 180 mp2975 180 181 mp2993 181 182 mp5023
+93
Documentation/hwmon/mp29502.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + Kernel driver mp29502 4 + ===================== 5 + 6 + Supported chips: 7 + 8 + * MPS mp29502 9 + 10 + Prefix: 'mp29502' 11 + 12 + Author: 13 + 14 + Wensheng Wang <wenswang@yeah.net> 15 + 16 + Description 17 + ----------- 18 + 19 + This driver implements support for Monolithic Power Systems, Inc. (MPS) 20 + MP29502 Digital Multi-phase Controller. 21 + 22 + Device compliant with: 23 + 24 + - PMBus rev 1.3 interface. 25 + 26 + The driver exports the following attributes via the 'sysfs' files 27 + for input voltage: 28 + 29 + **in1_input** 30 + 31 + **in1_label** 32 + 33 + **in1_crit** 34 + 35 + **in1_crit_alarm** 36 + 37 + The driver provides the following attributes for output voltage: 38 + 39 + **in2_input** 40 + 41 + **in2_label** 42 + 43 + **in2_crit** 44 + 45 + **in2_crit_alarm** 46 + 47 + **in2_lcrit** 48 + 49 + **in2_lcrit_alarm** 50 + 51 + The driver provides the following attributes for input current: 52 + 53 + **curr1_input** 54 + 55 + **curr1_label** 56 + 57 + The driver provides the following attributes for output current: 58 + 59 + **curr2_input** 60 + 61 + **curr2_label** 62 + 63 + **curr2_crit** 64 + 65 + **curr2_crit_alarm** 66 + 67 + **curr2_max** 68 + 69 + **curr2_max_alarm** 70 + 71 + The driver provides the following attributes for input power: 72 + 73 + **power1_input** 74 + 75 + **power1_label** 76 + 77 + The driver provides the following attributes for output power: 78 + 79 + **power2_input** 80 + 81 + **power2_label** 82 + 83 + The driver provides the following attributes for temperature: 84 + 85 + **temp1_input** 86 + 87 + **temp1_crit** 88 + 89 + **temp1_crit_alarm** 90 + 91 + **temp1_max** 92 + 93 + **temp1_max_alarm**
+7
MAINTAINERS
··· 17189 17189 F: Documentation/hwmon/mp2891.rst 17190 17190 F: drivers/hwmon/pmbus/mp2891.c 17191 17191 17192 + MPS MP29502 DRIVER 17193 + M: Wensheng Wang <wenswang@yeah.net> 17194 + L: linux-hwmon@vger.kernel.org 17195 + S: Maintained 17196 + F: Documentation/hwmon/mp29502.rst 17197 + F: drivers/hwmon/pmbus/mp29502.c 17198 + 17192 17199 MPS MP2993 DRIVER 17193 17200 M: Noah Wang <noahwang.wang@outlook.com> 17194 17201 L: linux-hwmon@vger.kernel.org
+9
drivers/hwmon/pmbus/Kconfig
··· 401 401 This driver can also be built as a module. If so, the module will 402 402 be called mp2891. 403 403 404 + config SENSORS_MP29502 405 + tristate "MPS MP29502" 406 + help 407 + If you say yes here you get hardware monitoring support for MPS 408 + MP29502 Dual Loop Digital Multi-Phase Controller. 409 + 410 + This driver can also be built as a module. If so, the module will 411 + be called mp29502. 412 + 404 413 config SENSORS_MP2975 405 414 tristate "MPS MP2975" 406 415 help
+1
drivers/hwmon/pmbus/Makefile
··· 40 40 obj-$(CONFIG_SENSORS_MP2869) += mp2869.o 41 41 obj-$(CONFIG_SENSORS_MP2888) += mp2888.o 42 42 obj-$(CONFIG_SENSORS_MP2891) += mp2891.o 43 + obj-$(CONFIG_SENSORS_MP29502) += mp29502.o 43 44 obj-$(CONFIG_SENSORS_MP2975) += mp2975.o 44 45 obj-$(CONFIG_SENSORS_MP2993) += mp2993.o 45 46 obj-$(CONFIG_SENSORS_MP5023) += mp5023.o
+670
drivers/hwmon/pmbus/mp29502.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers(MP29502) 4 + */ 5 + 6 + #include <linux/bitfield.h> 7 + #include <linux/i2c.h> 8 + #include <linux/module.h> 9 + #include <linux/of_device.h> 10 + #include "pmbus.h" 11 + 12 + #define MFR_VOUT_SCALE_LOOP 0x29 13 + #define MFR_SVI3_IOUT_PRT 0x67 14 + #define MFR_READ_PIN_EST 0x94 15 + #define MFR_READ_IIN_EST 0x95 16 + #define MFR_VOUT_PROT1 0x3D 17 + #define MFR_VOUT_PROT2 0x51 18 + #define MFR_SLOPE_CNT_SET 0xA8 19 + #define MFR_TSNS_FLT_SET 0xBB 20 + 21 + #define MP29502_VIN_OV_GAIN 4 22 + #define MP29502_TEMP_LIMIT_OFFSET 40 23 + #define MP29502_READ_VOUT_DIV 1024 24 + #define MP29502_READ_IOUT_DIV 32 25 + #define MP29502_IOUT_LIMIT_UINT 8 26 + #define MP29502_OVUV_LIMIT_SCALE 10 27 + #define MP28502_VOUT_OV_GAIN 512 28 + #define MP28502_VOUT_OV_SCALE 40 29 + #define MP29502_VOUT_UV_OFFSET 36 30 + #define MP29502_PIN_GAIN 2 31 + #define MP29502_IIN_DIV 2 32 + 33 + #define MP29502_PAGE_NUM 1 34 + 35 + #define MP29502_RAIL_FUNC (PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | \ 36 + PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT | \ 37 + PMBUS_HAVE_TEMP | PMBUS_HAVE_PIN | \ 38 + PMBUS_HAVE_IIN | \ 39 + PMBUS_HAVE_STATUS_VOUT | \ 40 + PMBUS_HAVE_STATUS_IOUT | \ 41 + PMBUS_HAVE_STATUS_TEMP | \ 42 + PMBUS_HAVE_STATUS_INPUT) 43 + 44 + struct mp29502_data { 45 + struct pmbus_driver_info info; 46 + int vout_scale; 47 + int vout_bottom_div; 48 + int vout_top_div; 49 + int ovp_div; 50 + int iout_scale; 51 + }; 52 + 53 + #define to_mp29502_data(x) container_of(x, struct mp29502_data, info) 54 + 55 + static u16 mp29502_reg2data_linear11(u16 word) 56 + { 57 + s16 exponent; 58 + s32 mantissa; 59 + s64 val; 60 + 61 + exponent = ((s16)word) >> 11; 62 + mantissa = ((s16)((word & 0x7ff) << 5)) >> 5; 63 + val = mantissa; 64 + 65 + if (exponent >= 0) 66 + val <<= exponent; 67 + else 68 + val >>= -exponent; 69 + 70 + return val; 71 + } 72 + 73 + static int 74 + mp29502_identify_vout_scale(struct i2c_client *client, struct pmbus_driver_info *info, 75 + int page) 76 + { 77 + struct mp29502_data *data = to_mp29502_data(info); 78 + int ret; 79 + 80 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); 81 + if (ret < 0) 82 + return ret; 83 + 84 + ret = i2c_smbus_read_word_data(client, MFR_VOUT_SCALE_LOOP); 85 + if (ret < 0) 86 + return ret; 87 + 88 + switch (FIELD_GET(GENMASK(12, 10), ret)) { 89 + case 0: 90 + data->vout_scale = 6400; 91 + break; 92 + case 1: 93 + data->vout_scale = 5120; 94 + break; 95 + case 2: 96 + data->vout_scale = 2560; 97 + break; 98 + case 3: 99 + data->vout_scale = 2048; 100 + break; 101 + case 4: 102 + data->vout_scale = 1024; 103 + break; 104 + case 5: 105 + data->vout_scale = 4; 106 + break; 107 + case 6: 108 + data->vout_scale = 2; 109 + break; 110 + case 7: 111 + data->vout_scale = 1; 112 + break; 113 + default: 114 + data->vout_scale = 1; 115 + break; 116 + } 117 + 118 + return 0; 119 + } 120 + 121 + static int 122 + mp29502_identify_vout_divider(struct i2c_client *client, struct pmbus_driver_info *info, 123 + int page) 124 + { 125 + struct mp29502_data *data = to_mp29502_data(info); 126 + int ret; 127 + 128 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); 129 + if (ret < 0) 130 + return ret; 131 + 132 + ret = i2c_smbus_read_word_data(client, MFR_VOUT_PROT1); 133 + if (ret < 0) 134 + return ret; 135 + 136 + data->vout_bottom_div = FIELD_GET(GENMASK(11, 0), ret); 137 + 138 + ret = i2c_smbus_read_word_data(client, MFR_VOUT_PROT2); 139 + if (ret < 0) 140 + return ret; 141 + 142 + data->vout_top_div = FIELD_GET(GENMASK(14, 0), ret); 143 + 144 + return 0; 145 + } 146 + 147 + static int 148 + mp29502_identify_ovp_divider(struct i2c_client *client, struct pmbus_driver_info *info, 149 + int page) 150 + { 151 + struct mp29502_data *data = to_mp29502_data(info); 152 + int ret; 153 + 154 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); 155 + if (ret < 0) 156 + return ret; 157 + 158 + ret = i2c_smbus_read_word_data(client, MFR_SLOPE_CNT_SET); 159 + if (ret < 0) 160 + return ret; 161 + 162 + data->ovp_div = FIELD_GET(GENMASK(9, 0), ret); 163 + 164 + return 0; 165 + } 166 + 167 + static int 168 + mp29502_identify_iout_scale(struct i2c_client *client, struct pmbus_driver_info *info, 169 + int page) 170 + { 171 + struct mp29502_data *data = to_mp29502_data(info); 172 + int ret; 173 + 174 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); 175 + if (ret < 0) 176 + return ret; 177 + 178 + ret = i2c_smbus_read_word_data(client, MFR_SVI3_IOUT_PRT); 179 + if (ret < 0) 180 + return ret; 181 + 182 + switch (ret & GENMASK(2, 0)) { 183 + case 0: 184 + case 6: 185 + data->iout_scale = 32; 186 + break; 187 + case 1: 188 + data->iout_scale = 1; 189 + break; 190 + case 2: 191 + data->iout_scale = 2; 192 + break; 193 + case 3: 194 + data->iout_scale = 4; 195 + break; 196 + case 4: 197 + data->iout_scale = 8; 198 + break; 199 + case 5: 200 + data->iout_scale = 16; 201 + break; 202 + default: 203 + data->iout_scale = 64; 204 + break; 205 + } 206 + 207 + return 0; 208 + } 209 + 210 + static int mp29502_read_vout_ov_limit(struct i2c_client *client, struct mp29502_data *data) 211 + { 212 + int ret; 213 + int ov_value; 214 + 215 + /* 216 + * This is because the vout ov fault limit value comes from 217 + * page1 MFR_TSNS_FLT_SET reg, and other telemetry and limit 218 + * value comes from page0 reg. So the page should be set to 219 + * 0 after the reading of vout ov limit. 220 + */ 221 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 1); 222 + if (ret < 0) 223 + return ret; 224 + 225 + ret = i2c_smbus_read_word_data(client, MFR_TSNS_FLT_SET); 226 + if (ret < 0) 227 + return ret; 228 + 229 + ov_value = DIV_ROUND_CLOSEST(FIELD_GET(GENMASK(12, 7), ret) * 230 + MP28502_VOUT_OV_GAIN * MP28502_VOUT_OV_SCALE, 231 + data->ovp_div); 232 + 233 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); 234 + if (ret < 0) 235 + return ret; 236 + 237 + return ov_value; 238 + } 239 + 240 + static int mp29502_write_vout_ov_limit(struct i2c_client *client, u16 word, 241 + struct mp29502_data *data) 242 + { 243 + int ret; 244 + 245 + /* 246 + * This is because the vout ov fault limit value comes from 247 + * page1 MFR_TSNS_FLT_SET reg, and other telemetry and limit 248 + * value comes from page0 reg. So the page should be set to 249 + * 0 after the writing of vout ov limit. 250 + */ 251 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 1); 252 + if (ret < 0) 253 + return ret; 254 + 255 + ret = i2c_smbus_read_word_data(client, MFR_TSNS_FLT_SET); 256 + if (ret < 0) 257 + return ret; 258 + 259 + ret = i2c_smbus_write_word_data(client, MFR_TSNS_FLT_SET, 260 + (ret & ~GENMASK(12, 7)) | 261 + FIELD_PREP(GENMASK(12, 7), 262 + DIV_ROUND_CLOSEST(word * data->ovp_div, 263 + MP28502_VOUT_OV_GAIN * MP28502_VOUT_OV_SCALE))); 264 + 265 + return i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); 266 + } 267 + 268 + static int mp29502_read_byte_data(struct i2c_client *client, int page, int reg) 269 + { 270 + int ret; 271 + 272 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); 273 + if (ret < 0) 274 + return ret; 275 + 276 + switch (reg) { 277 + case PMBUS_VOUT_MODE: 278 + ret = PB_VOUT_MODE_DIRECT; 279 + break; 280 + default: 281 + ret = -ENODATA; 282 + break; 283 + } 284 + 285 + return ret; 286 + } 287 + 288 + static int mp29502_read_word_data(struct i2c_client *client, int page, 289 + int phase, int reg) 290 + { 291 + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 292 + struct mp29502_data *data = to_mp29502_data(info); 293 + int ret; 294 + 295 + switch (reg) { 296 + case PMBUS_STATUS_WORD: 297 + ret = -ENODATA; 298 + break; 299 + case PMBUS_READ_VIN: 300 + /* 301 + * The MP29502 PMBUS_READ_VIN[10:0] is the vin value, the vin scale is 302 + * 125mV/LSB. And the vin scale is set to 125mV/Lsb(using r/m/b scale) 303 + * in MP29502 pmbus_driver_info struct, so the word data bit0-bit10 can 304 + * be returned to pmbus core directly. 305 + */ 306 + ret = pmbus_read_word_data(client, page, phase, reg); 307 + if (ret < 0) 308 + return ret; 309 + 310 + ret = FIELD_GET(GENMASK(10, 0), ret); 311 + break; 312 + case PMBUS_READ_VOUT: 313 + /* 314 + * The MP29502 PMBUS_READ_VOUT[11:0] is the vout value, and vout 315 + * value is calculated based on vout scale and vout divider. 316 + */ 317 + ret = pmbus_read_word_data(client, page, phase, reg); 318 + if (ret < 0) 319 + return ret; 320 + 321 + ret = DIV_ROUND_CLOSEST((ret & GENMASK(11, 0)) * 322 + data->vout_scale * 323 + (data->vout_bottom_div + 324 + 4 * data->vout_top_div), 325 + MP29502_READ_VOUT_DIV * 326 + data->vout_bottom_div); 327 + break; 328 + case PMBUS_READ_IIN: 329 + /* 330 + * The MP29502 MFR_READ_IIN_EST register is linear11 format, and the 331 + * exponent is not a constant value. But the iin scale is set to 332 + * 1A/Lsb(using r/m/b scale). As a result, the iin read from MP29502 333 + * should be calculated to A, then return the result to pmbus core. 334 + */ 335 + ret = pmbus_read_word_data(client, page, phase, MFR_READ_IIN_EST); 336 + if (ret < 0) 337 + return ret; 338 + 339 + ret = DIV_ROUND_CLOSEST(mp29502_reg2data_linear11(ret), 340 + MP29502_IIN_DIV); 341 + break; 342 + case PMBUS_READ_PIN: 343 + /* 344 + * The MP29502 MFR_READ_PIN_EST register is linear11 format, and the 345 + * exponent is not a constant value. But the pin scale is set to 346 + * 1W/Lsb(using r/m/b scale). As a result, the pout read from MP29502 347 + * should be calculated to W, then return the result to pmbus core. 348 + */ 349 + ret = pmbus_read_word_data(client, page, phase, MFR_READ_PIN_EST); 350 + if (ret < 0) 351 + return ret; 352 + 353 + ret = mp29502_reg2data_linear11(ret) * MP29502_PIN_GAIN; 354 + break; 355 + case PMBUS_READ_POUT: 356 + /* 357 + * The MP29502 PMBUS_READ_POUT register is linear11 format, and the 358 + * exponent is not a constant value. But the pout scale is set to 359 + * 1W/Lsb(using r/m/b scale). As a result, the pout read from MP29502 360 + * should be calculated to W, then return the result to pmbus core. 361 + * And the pout is calculated based on vout divider. 362 + */ 363 + ret = pmbus_read_word_data(client, page, phase, reg); 364 + if (ret < 0) 365 + return ret; 366 + 367 + ret = DIV_ROUND_CLOSEST(mp29502_reg2data_linear11(ret) * 368 + (data->vout_bottom_div + 369 + 4 * data->vout_top_div), 370 + data->vout_bottom_div); 371 + break; 372 + case PMBUS_READ_IOUT: 373 + ret = pmbus_read_word_data(client, page, phase, reg); 374 + if (ret < 0) 375 + return ret; 376 + 377 + ret = DIV_ROUND_CLOSEST((ret & GENMASK(10, 0)) * data->iout_scale, 378 + MP29502_READ_IOUT_DIV); 379 + break; 380 + case PMBUS_READ_TEMPERATURE_1: 381 + ret = pmbus_read_word_data(client, page, phase, reg); 382 + if (ret < 0) 383 + return ret; 384 + 385 + ret = FIELD_GET(GENMASK(10, 0), ret); 386 + break; 387 + case PMBUS_VIN_OV_FAULT_LIMIT: 388 + /* 389 + * The MP29502 PMBUS_VIN_OV_FAULT_LIMIT is 500mV/Lsb, but 390 + * the vin scale is set to 125mV/Lsb(using r/m/b scale), 391 + * so the word data should multiply by 4. 392 + */ 393 + ret = pmbus_read_word_data(client, page, phase, reg); 394 + if (ret < 0) 395 + return ret; 396 + 397 + ret = FIELD_GET(GENMASK(7, 0), ret) * MP29502_VIN_OV_GAIN; 398 + break; 399 + case PMBUS_VIN_UV_WARN_LIMIT: 400 + case PMBUS_VIN_UV_FAULT_LIMIT: 401 + /* 402 + * The MP29502 PMBUS_VIN_UV_WARN_LIMIT and PMBUS_VIN_UV_FAULT_LIMIT 403 + * scale is 125mV/Lsb, but the vin scale is set to 125mV/Lsb(using 404 + * r/m/b scale), so the word data bit0-bit9 can be returned to pmbus 405 + * core directly. 406 + */ 407 + ret = pmbus_read_word_data(client, page, phase, reg); 408 + if (ret < 0) 409 + return ret; 410 + 411 + ret = FIELD_GET(GENMASK(9, 0), ret); 412 + break; 413 + case PMBUS_VOUT_OV_FAULT_LIMIT: 414 + /* 415 + * The MP29502 vout ov fault limit value comes from 416 + * page1 MFR_TSNS_FLT_SET[12:7]. 417 + */ 418 + ret = mp29502_read_vout_ov_limit(client, data); 419 + if (ret < 0) 420 + return ret; 421 + 422 + break; 423 + case PMBUS_VOUT_UV_FAULT_LIMIT: 424 + ret = pmbus_read_word_data(client, page, phase, reg); 425 + if (ret < 0) 426 + return ret; 427 + 428 + ret = DIV_ROUND_CLOSEST((FIELD_GET(GENMASK(8, 0), ret) * 429 + MP29502_OVUV_LIMIT_SCALE - 430 + MP29502_VOUT_UV_OFFSET) * 431 + (data->vout_bottom_div + 432 + 4 * data->vout_top_div), 433 + data->vout_bottom_div); 434 + break; 435 + case PMBUS_IOUT_OC_FAULT_LIMIT: 436 + case PMBUS_IOUT_OC_WARN_LIMIT: 437 + ret = pmbus_read_word_data(client, page, phase, reg); 438 + if (ret < 0) 439 + return ret; 440 + 441 + ret = DIV_ROUND_CLOSEST((ret & GENMASK(7, 0)) * 442 + data->iout_scale * 443 + MP29502_IOUT_LIMIT_UINT, 444 + MP29502_READ_IOUT_DIV); 445 + break; 446 + case PMBUS_OT_FAULT_LIMIT: 447 + case PMBUS_OT_WARN_LIMIT: 448 + /* 449 + * The scale of MP29502 PMBUS_OT_FAULT_LIMIT and PMBUS_OT_WARN_LIMIT 450 + * is 1°C/LSB and they have 40°C offset. 451 + */ 452 + ret = pmbus_read_word_data(client, page, phase, reg); 453 + if (ret < 0) 454 + return ret; 455 + 456 + ret = (ret & GENMASK(7, 0)) - MP29502_TEMP_LIMIT_OFFSET; 457 + break; 458 + default: 459 + ret = -EINVAL; 460 + break; 461 + } 462 + 463 + return ret; 464 + } 465 + 466 + static int mp29502_write_word_data(struct i2c_client *client, int page, int reg, 467 + u16 word) 468 + { 469 + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 470 + struct mp29502_data *data = to_mp29502_data(info); 471 + int ret; 472 + 473 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); 474 + if (ret < 0) 475 + return ret; 476 + 477 + switch (reg) { 478 + case PMBUS_VIN_OV_FAULT_LIMIT: 479 + /* 480 + * The PMBUS_VIN_OV_FAULT_LIMIT[7:0] is the limit value, 481 + * and bit8-bit15 should not be changed. The scale of 482 + * PMBUS_VIN_OV_FAULT_LIMIT is 500mV/Lsb, but the vin 483 + * scale is set to 125mV/Lsb(using r/m/b scale), so 484 + * the word data should divide by 4. 485 + */ 486 + ret = pmbus_read_word_data(client, page, 0xff, reg); 487 + if (ret < 0) 488 + return ret; 489 + 490 + ret = pmbus_write_word_data(client, page, reg, 491 + (ret & ~GENMASK(7, 0)) | 492 + FIELD_PREP(GENMASK(7, 0), 493 + DIV_ROUND_CLOSEST(word, 494 + MP29502_VIN_OV_GAIN))); 495 + break; 496 + case PMBUS_VIN_UV_WARN_LIMIT: 497 + case PMBUS_VIN_UV_FAULT_LIMIT: 498 + /* 499 + * The PMBUS_VIN_UV_WARN_LIMIT[9:0] and PMBUS_VIN_UV_FAULT_LIMIT[9:0] 500 + * are the limit value, and bit10-bit15 should not be changed. 501 + */ 502 + ret = pmbus_read_word_data(client, page, 0xff, reg); 503 + if (ret < 0) 504 + return ret; 505 + 506 + ret = pmbus_write_word_data(client, page, reg, 507 + (ret & ~GENMASK(9, 0)) | 508 + FIELD_PREP(GENMASK(9, 0), 509 + word)); 510 + break; 511 + case PMBUS_VOUT_OV_FAULT_LIMIT: 512 + ret = mp29502_write_vout_ov_limit(client, word, data); 513 + if (ret < 0) 514 + return ret; 515 + 516 + break; 517 + case PMBUS_VOUT_UV_FAULT_LIMIT: 518 + ret = pmbus_read_word_data(client, page, 0xff, reg); 519 + if (ret < 0) 520 + return ret; 521 + 522 + ret = pmbus_write_word_data(client, page, reg, 523 + (ret & ~GENMASK(8, 0)) | 524 + FIELD_PREP(GENMASK(8, 0), 525 + DIV_ROUND_CLOSEST(word * 526 + data->vout_bottom_div + 527 + MP29502_VOUT_UV_OFFSET * 528 + (data->vout_bottom_div + 529 + 4 * data->vout_top_div), 530 + MP29502_OVUV_LIMIT_SCALE * 531 + (data->vout_bottom_div + 532 + 4 * data->vout_top_div)))); 533 + break; 534 + case PMBUS_IOUT_OC_FAULT_LIMIT: 535 + case PMBUS_IOUT_OC_WARN_LIMIT: 536 + ret = pmbus_write_word_data(client, page, reg, 537 + DIV_ROUND_CLOSEST(word * 538 + MP29502_READ_IOUT_DIV, 539 + MP29502_IOUT_LIMIT_UINT * 540 + data->iout_scale)); 541 + break; 542 + case PMBUS_OT_FAULT_LIMIT: 543 + case PMBUS_OT_WARN_LIMIT: 544 + /* 545 + * The PMBUS_OT_FAULT_LIMIT[7:0] and PMBUS_OT_WARN_LIMIT[7:0] 546 + * are the limit value, and bit8-bit15 should not be changed. 547 + */ 548 + ret = pmbus_read_word_data(client, page, 0xff, reg); 549 + if (ret < 0) 550 + return ret; 551 + 552 + ret = pmbus_write_word_data(client, page, reg, 553 + (ret & ~GENMASK(7, 0)) | 554 + FIELD_PREP(GENMASK(7, 0), 555 + word + MP29502_TEMP_LIMIT_OFFSET)); 556 + break; 557 + default: 558 + ret = -EINVAL; 559 + break; 560 + } 561 + 562 + return ret; 563 + } 564 + 565 + static int mp29502_identify(struct i2c_client *client, struct pmbus_driver_info *info) 566 + { 567 + int ret; 568 + 569 + /* Identify vout scale */ 570 + ret = mp29502_identify_vout_scale(client, info, 0); 571 + if (ret < 0) 572 + return ret; 573 + 574 + /* Identify vout divider. */ 575 + ret = mp29502_identify_vout_divider(client, info, 1); 576 + if (ret < 0) 577 + return ret; 578 + 579 + /* Identify ovp divider. */ 580 + ret = mp29502_identify_ovp_divider(client, info, 1); 581 + if (ret < 0) 582 + return ret; 583 + 584 + /* Identify iout scale */ 585 + return mp29502_identify_iout_scale(client, info, 0); 586 + } 587 + 588 + static const struct pmbus_driver_info mp29502_info = { 589 + .pages = MP29502_PAGE_NUM, 590 + .format[PSC_VOLTAGE_IN] = direct, 591 + .format[PSC_TEMPERATURE] = direct, 592 + .format[PSC_CURRENT_IN] = direct, 593 + .format[PSC_CURRENT_OUT] = direct, 594 + .format[PSC_VOLTAGE_OUT] = direct, 595 + .format[PSC_POWER] = direct, 596 + 597 + .m[PSC_VOLTAGE_IN] = 8, 598 + .R[PSC_VOLTAGE_IN] = 0, 599 + .b[PSC_VOLTAGE_IN] = 0, 600 + 601 + .m[PSC_VOLTAGE_OUT] = 1, 602 + .R[PSC_VOLTAGE_OUT] = 3, 603 + .b[PSC_VOLTAGE_OUT] = 0, 604 + 605 + .m[PSC_TEMPERATURE] = 1, 606 + .R[PSC_TEMPERATURE] = 0, 607 + .b[PSC_TEMPERATURE] = 0, 608 + 609 + .m[PSC_CURRENT_IN] = 1, 610 + .R[PSC_CURRENT_IN] = 0, 611 + .b[PSC_CURRENT_IN] = 0, 612 + 613 + .m[PSC_CURRENT_OUT] = 1, 614 + .R[PSC_CURRENT_OUT] = 0, 615 + .b[PSC_CURRENT_OUT] = 0, 616 + 617 + .m[PSC_POWER] = 1, 618 + .R[PSC_POWER] = 0, 619 + .b[PSC_POWER] = 0, 620 + 621 + .func[0] = MP29502_RAIL_FUNC, 622 + .read_word_data = mp29502_read_word_data, 623 + .read_byte_data = mp29502_read_byte_data, 624 + .write_word_data = mp29502_write_word_data, 625 + .identify = mp29502_identify, 626 + }; 627 + 628 + static int mp29502_probe(struct i2c_client *client) 629 + { 630 + struct pmbus_driver_info *info; 631 + struct mp29502_data *data; 632 + 633 + data = devm_kzalloc(&client->dev, sizeof(struct mp29502_data), 634 + GFP_KERNEL); 635 + if (!data) 636 + return -ENOMEM; 637 + 638 + memcpy(&data->info, &mp29502_info, sizeof(*info)); 639 + info = &data->info; 640 + 641 + return pmbus_do_probe(client, info); 642 + } 643 + 644 + static const struct i2c_device_id mp29502_id[] = { 645 + {"mp29502", 0}, 646 + {} 647 + }; 648 + MODULE_DEVICE_TABLE(i2c, mp29502_id); 649 + 650 + static const struct of_device_id __maybe_unused mp29502_of_match[] = { 651 + {.compatible = "mps,mp29502"}, 652 + {} 653 + }; 654 + MODULE_DEVICE_TABLE(of, mp29502_of_match); 655 + 656 + static struct i2c_driver mp29502_driver = { 657 + .driver = { 658 + .name = "mp29502", 659 + .of_match_table = mp29502_of_match, 660 + }, 661 + .probe = mp29502_probe, 662 + .id_table = mp29502_id, 663 + }; 664 + 665 + module_i2c_driver(mp29502_driver); 666 + 667 + MODULE_AUTHOR("Wensheng Wang <wenswang@yeah.net"); 668 + MODULE_DESCRIPTION("PMBus driver for MPS MP29502"); 669 + MODULE_LICENSE("GPL"); 670 + MODULE_IMPORT_NS("PMBUS");