1*38b2b022SNoah Wang // SPDX-License-Identifier: GPL-2.0-or-later 2*38b2b022SNoah Wang /* 3*38b2b022SNoah Wang * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers(MP2891) 4*38b2b022SNoah Wang */ 5*38b2b022SNoah Wang 6*38b2b022SNoah Wang #include <linux/bitfield.h> 7*38b2b022SNoah Wang #include <linux/i2c.h> 8*38b2b022SNoah Wang #include <linux/module.h> 9*38b2b022SNoah Wang #include <linux/of_device.h> 10*38b2b022SNoah Wang #include "pmbus.h" 11*38b2b022SNoah Wang 12*38b2b022SNoah Wang /* 13*38b2b022SNoah Wang * Vender specific registers, the register MFR_SVI3_IOUT_PRT(0x65), 14*38b2b022SNoah Wang * MFR_VOUT_LOOP_CTRL(0xBD), READ_PIN_EST(0x94)and READ_IIN_EST(0x95) 15*38b2b022SNoah Wang * redefine the standard PMBUS register. The MFR_SVI3_IOUT_PRT(0x65) 16*38b2b022SNoah Wang * is used to identify the iout scale and the MFR_VOUT_LOOP_CTRL(0xBD) 17*38b2b022SNoah Wang * is used to identify the vout scale. The READ_PIN_EST(0x94) is used 18*38b2b022SNoah Wang * to read input power per rail. The MP2891 does not have standard 19*38b2b022SNoah Wang * READ_IIN register(0x89), the iin telemetry can be obtained through 20*38b2b022SNoah Wang * the vendor redefined register READ_IIN_EST(0x95). 21*38b2b022SNoah Wang */ 22*38b2b022SNoah Wang #define MFR_VOUT_LOOP_CTRL 0xBD 23*38b2b022SNoah Wang #define READ_PIN_EST 0x94 24*38b2b022SNoah Wang #define READ_IIN_EST 0x95 25*38b2b022SNoah Wang #define MFR_SVI3_IOUT_PRT 0x65 26*38b2b022SNoah Wang 27*38b2b022SNoah Wang #define MP2891_TEMP_LIMIT_OFFSET 40 28*38b2b022SNoah Wang #define MP2891_PIN_LIMIT_UINT 2 29*38b2b022SNoah Wang #define MP2891_IOUT_LIMIT_UINT 8 30*38b2b022SNoah Wang #define MP2891_IOUT_SCALE_DIV 32 31*38b2b022SNoah Wang #define MP2891_VOUT_SCALE_DIV 100 32*38b2b022SNoah Wang #define MP2891_OVUV_DELTA_SCALE 50 33*38b2b022SNoah Wang #define MP2891_OV_LIMIT_SCALE 20 34*38b2b022SNoah Wang #define MP2891_UV_LIMIT_SCALE 5 35*38b2b022SNoah Wang 36*38b2b022SNoah Wang #define MP2891_PAGE_NUM 2 37*38b2b022SNoah Wang 38*38b2b022SNoah Wang #define MP2891_RAIL1_FUNC (PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | \ 39*38b2b022SNoah Wang PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP | \ 40*38b2b022SNoah Wang PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | \ 41*38b2b022SNoah Wang PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_VOUT | \ 42*38b2b022SNoah Wang PMBUS_HAVE_STATUS_IOUT | \ 43*38b2b022SNoah Wang PMBUS_HAVE_STATUS_INPUT | \ 44*38b2b022SNoah Wang PMBUS_HAVE_STATUS_TEMP) 45*38b2b022SNoah Wang 46*38b2b022SNoah Wang #define MP2891_RAIL2_FUNC (PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | \ 47*38b2b022SNoah Wang PMBUS_HAVE_TEMP | PMBUS_HAVE_POUT | \ 48*38b2b022SNoah Wang PMBUS_HAVE_PIN | PMBUS_HAVE_IIN | \ 49*38b2b022SNoah Wang PMBUS_HAVE_STATUS_VOUT | \ 50*38b2b022SNoah Wang PMBUS_HAVE_STATUS_IOUT | \ 51*38b2b022SNoah Wang PMBUS_HAVE_STATUS_INPUT | \ 52*38b2b022SNoah Wang PMBUS_HAVE_STATUS_TEMP) 53*38b2b022SNoah Wang 54*38b2b022SNoah Wang struct mp2891_data { 55*38b2b022SNoah Wang struct pmbus_driver_info info; 56*38b2b022SNoah Wang int vout_scale[MP2891_PAGE_NUM]; 57*38b2b022SNoah Wang int iout_scale[MP2891_PAGE_NUM]; 58*38b2b022SNoah Wang }; 59*38b2b022SNoah Wang 60*38b2b022SNoah Wang #define to_mp2891_data(x) container_of(x, struct mp2891_data, info) 61*38b2b022SNoah Wang 62*38b2b022SNoah Wang /* Converts a LINEAR11 value to DIRECT format */ 63*38b2b022SNoah Wang static u16 mp2891_reg2data_linear11(u16 word) 64*38b2b022SNoah Wang { 65*38b2b022SNoah Wang s16 exponent; 66*38b2b022SNoah Wang s32 mantissa; 67*38b2b022SNoah Wang s64 val; 68*38b2b022SNoah Wang 69*38b2b022SNoah Wang exponent = ((s16)word) >> 11; 70*38b2b022SNoah Wang mantissa = ((s16)((word & 0x7ff) << 5)) >> 5; 71*38b2b022SNoah Wang val = mantissa; 72*38b2b022SNoah Wang 73*38b2b022SNoah Wang if (exponent >= 0) 74*38b2b022SNoah Wang val <<= exponent; 75*38b2b022SNoah Wang else 76*38b2b022SNoah Wang val >>= -exponent; 77*38b2b022SNoah Wang 78*38b2b022SNoah Wang return val; 79*38b2b022SNoah Wang } 80*38b2b022SNoah Wang 81*38b2b022SNoah Wang static int 82*38b2b022SNoah Wang mp2891_identify_vout_scale(struct i2c_client *client, struct pmbus_driver_info *info, 83*38b2b022SNoah Wang int page) 84*38b2b022SNoah Wang { 85*38b2b022SNoah Wang struct mp2891_data *data = to_mp2891_data(info); 86*38b2b022SNoah Wang int ret; 87*38b2b022SNoah Wang 88*38b2b022SNoah Wang ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); 89*38b2b022SNoah Wang if (ret < 0) 90*38b2b022SNoah Wang return ret; 91*38b2b022SNoah Wang 92*38b2b022SNoah Wang ret = i2c_smbus_read_word_data(client, MFR_VOUT_LOOP_CTRL); 93*38b2b022SNoah Wang if (ret < 0) 94*38b2b022SNoah Wang return ret; 95*38b2b022SNoah Wang 96*38b2b022SNoah Wang /* 97*38b2b022SNoah Wang * The output voltage is equal to the READ_VOUT(0x8B) register value multiplied 98*38b2b022SNoah Wang * by vout_scale. 99*38b2b022SNoah Wang * Obtain vout scale from the register MFR_VOUT_LOOP_CTRL, bits 15-14,bit 13. 100*38b2b022SNoah Wang * If MFR_VOUT_LOOP_CTRL[13] = 1, the vout scale is below: 101*38b2b022SNoah Wang * 2.5mV/LSB 102*38b2b022SNoah Wang * If MFR_VOUT_LOOP_CTRL[13] = 0, the vout scale is decided by 103*38b2b022SNoah Wang * MFR_VOUT_LOOP_CTRL[15:14]: 104*38b2b022SNoah Wang * 00b - 6.25mV/LSB, 01b - 5mV/LSB, 10b - 2mV/LSB, 11b - 1mV 105*38b2b022SNoah Wang */ 106*38b2b022SNoah Wang if (ret & GENMASK(13, 13)) { 107*38b2b022SNoah Wang data->vout_scale[page] = 250; 108*38b2b022SNoah Wang } else { 109*38b2b022SNoah Wang ret = FIELD_GET(GENMASK(15, 14), ret); 110*38b2b022SNoah Wang if (ret == 0) 111*38b2b022SNoah Wang data->vout_scale[page] = 625; 112*38b2b022SNoah Wang else if (ret == 1) 113*38b2b022SNoah Wang data->vout_scale[page] = 500; 114*38b2b022SNoah Wang else if (ret == 2) 115*38b2b022SNoah Wang data->vout_scale[page] = 200; 116*38b2b022SNoah Wang else 117*38b2b022SNoah Wang data->vout_scale[page] = 100; 118*38b2b022SNoah Wang } 119*38b2b022SNoah Wang 120*38b2b022SNoah Wang return 0; 121*38b2b022SNoah Wang } 122*38b2b022SNoah Wang 123*38b2b022SNoah Wang static int 124*38b2b022SNoah Wang mp2891_identify_iout_scale(struct i2c_client *client, struct pmbus_driver_info *info, 125*38b2b022SNoah Wang int page) 126*38b2b022SNoah Wang { 127*38b2b022SNoah Wang struct mp2891_data *data = to_mp2891_data(info); 128*38b2b022SNoah Wang int ret; 129*38b2b022SNoah Wang 130*38b2b022SNoah Wang ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); 131*38b2b022SNoah Wang if (ret < 0) 132*38b2b022SNoah Wang return ret; 133*38b2b022SNoah Wang 134*38b2b022SNoah Wang ret = i2c_smbus_read_word_data(client, MFR_SVI3_IOUT_PRT); 135*38b2b022SNoah Wang if (ret < 0) 136*38b2b022SNoah Wang return ret; 137*38b2b022SNoah Wang 138*38b2b022SNoah Wang /* 139*38b2b022SNoah Wang * The output current is equal to the READ_IOUT(0x8C) register value 140*38b2b022SNoah Wang * multiplied by iout_scale. 141*38b2b022SNoah Wang * Obtain iout_scale from the register MFR_SVI3_IOUT_PRT[2:0]. 142*38b2b022SNoah Wang * The value is selected as below: 143*38b2b022SNoah Wang * 000b - 1A/LSB, 001b - (1/32)A/LSB, 010b - (1/16)A/LSB, 144*38b2b022SNoah Wang * 011b - (1/8)A/LSB, 100b - (1/4)A/LSB, 101b - (1/2)A/LSB 145*38b2b022SNoah Wang * 110b - 1A/LSB, 111b - 2A/LSB 146*38b2b022SNoah Wang */ 147*38b2b022SNoah Wang switch (ret & GENMASK(2, 0)) { 148*38b2b022SNoah Wang case 0: 149*38b2b022SNoah Wang case 6: 150*38b2b022SNoah Wang data->iout_scale[page] = 32; 151*38b2b022SNoah Wang break; 152*38b2b022SNoah Wang case 1: 153*38b2b022SNoah Wang data->iout_scale[page] = 1; 154*38b2b022SNoah Wang break; 155*38b2b022SNoah Wang case 2: 156*38b2b022SNoah Wang data->iout_scale[page] = 2; 157*38b2b022SNoah Wang break; 158*38b2b022SNoah Wang case 3: 159*38b2b022SNoah Wang data->iout_scale[page] = 4; 160*38b2b022SNoah Wang break; 161*38b2b022SNoah Wang case 4: 162*38b2b022SNoah Wang data->iout_scale[page] = 8; 163*38b2b022SNoah Wang break; 164*38b2b022SNoah Wang case 5: 165*38b2b022SNoah Wang data->iout_scale[page] = 16; 166*38b2b022SNoah Wang break; 167*38b2b022SNoah Wang default: 168*38b2b022SNoah Wang data->iout_scale[page] = 64; 169*38b2b022SNoah Wang break; 170*38b2b022SNoah Wang } 171*38b2b022SNoah Wang 172*38b2b022SNoah Wang return 0; 173*38b2b022SNoah Wang } 174*38b2b022SNoah Wang 175*38b2b022SNoah Wang static int mp2891_identify(struct i2c_client *client, struct pmbus_driver_info *info) 176*38b2b022SNoah Wang { 177*38b2b022SNoah Wang int ret; 178*38b2b022SNoah Wang 179*38b2b022SNoah Wang /* Identify vout scale for rail 1. */ 180*38b2b022SNoah Wang ret = mp2891_identify_vout_scale(client, info, 0); 181*38b2b022SNoah Wang if (ret < 0) 182*38b2b022SNoah Wang return ret; 183*38b2b022SNoah Wang 184*38b2b022SNoah Wang /* Identify vout scale for rail 2. */ 185*38b2b022SNoah Wang ret = mp2891_identify_vout_scale(client, info, 1); 186*38b2b022SNoah Wang if (ret < 0) 187*38b2b022SNoah Wang return ret; 188*38b2b022SNoah Wang 189*38b2b022SNoah Wang /* Identify iout scale for rail 1. */ 190*38b2b022SNoah Wang ret = mp2891_identify_iout_scale(client, info, 0); 191*38b2b022SNoah Wang if (ret < 0) 192*38b2b022SNoah Wang return ret; 193*38b2b022SNoah Wang 194*38b2b022SNoah Wang /* Identify iout scale for rail 2. */ 195*38b2b022SNoah Wang return mp2891_identify_iout_scale(client, info, 1); 196*38b2b022SNoah Wang } 197*38b2b022SNoah Wang 198*38b2b022SNoah Wang static int mp2891_read_byte_data(struct i2c_client *client, int page, int reg) 199*38b2b022SNoah Wang { 200*38b2b022SNoah Wang int ret; 201*38b2b022SNoah Wang 202*38b2b022SNoah Wang switch (reg) { 203*38b2b022SNoah Wang case PMBUS_VOUT_MODE: 204*38b2b022SNoah Wang /* 205*38b2b022SNoah Wang * The MP2891 does not follow standard PMBus protocol completely, the 206*38b2b022SNoah Wang * PMBUS_VOUT_MODE(0x20) in MP2891 is reserved and 0x00 is always 207*38b2b022SNoah Wang * returned when the register is read. But the calculation of vout in 208*38b2b022SNoah Wang * this driver is based on direct format. As a result, the format of 209*38b2b022SNoah Wang * vout is enforced to direct. 210*38b2b022SNoah Wang */ 211*38b2b022SNoah Wang ret = PB_VOUT_MODE_DIRECT; 212*38b2b022SNoah Wang break; 213*38b2b022SNoah Wang default: 214*38b2b022SNoah Wang ret = -ENODATA; 215*38b2b022SNoah Wang break; 216*38b2b022SNoah Wang } 217*38b2b022SNoah Wang 218*38b2b022SNoah Wang return ret; 219*38b2b022SNoah Wang } 220*38b2b022SNoah Wang 221*38b2b022SNoah Wang static int mp2891_read_word_data(struct i2c_client *client, int page, 222*38b2b022SNoah Wang int phase, int reg) 223*38b2b022SNoah Wang { 224*38b2b022SNoah Wang const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 225*38b2b022SNoah Wang struct mp2891_data *data = to_mp2891_data(info); 226*38b2b022SNoah Wang int ret; 227*38b2b022SNoah Wang 228*38b2b022SNoah Wang switch (reg) { 229*38b2b022SNoah Wang case PMBUS_READ_VIN: 230*38b2b022SNoah Wang ret = pmbus_read_word_data(client, page, phase, reg); 231*38b2b022SNoah Wang if (ret < 0) 232*38b2b022SNoah Wang return ret; 233*38b2b022SNoah Wang 234*38b2b022SNoah Wang ret = ret & GENMASK(9, 0); 235*38b2b022SNoah Wang break; 236*38b2b022SNoah Wang case PMBUS_READ_IIN: 237*38b2b022SNoah Wang /* 238*38b2b022SNoah Wang * The MP2891 does not have standard PMBUS_READ_IIN register(0x89), 239*38b2b022SNoah Wang * the iin telemetry can be obtained through the vender redefined 240*38b2b022SNoah Wang * register READ_IIN_EST(0x95). The MP2891 PMBUS_READ_IIN register 241*38b2b022SNoah Wang * is linear11 format, But the pout scale is set to 1A/Lsb(using 242*38b2b022SNoah Wang * r/m/b scale). As a result, the iin read from MP2891 should be 243*38b2b022SNoah Wang * calculated to A, then return the result to pmbus core. 244*38b2b022SNoah Wang */ 245*38b2b022SNoah Wang ret = pmbus_read_word_data(client, page, phase, READ_IIN_EST); 246*38b2b022SNoah Wang if (ret < 0) 247*38b2b022SNoah Wang return ret; 248*38b2b022SNoah Wang 249*38b2b022SNoah Wang ret = mp2891_reg2data_linear11(ret); 250*38b2b022SNoah Wang break; 251*38b2b022SNoah Wang case PMBUS_READ_PIN: 252*38b2b022SNoah Wang /* 253*38b2b022SNoah Wang * The MP2891 has standard PMBUS_READ_PIN register(0x97), but this 254*38b2b022SNoah Wang * is not used to read the input power per rail. The input power 255*38b2b022SNoah Wang * per rail is read through the vender redefined register 256*38b2b022SNoah Wang * READ_PIN_EST(0x94). The MP2891 PMBUS_READ_PIN register is linear11 257*38b2b022SNoah Wang * format, But the pout scale is set to 1W/Lsb(using r/m/b scale). 258*38b2b022SNoah Wang * As a result, the pin read from MP2891 should be calculated to W, 259*38b2b022SNoah Wang * then return the result to pmbus core. 260*38b2b022SNoah Wang */ 261*38b2b022SNoah Wang ret = pmbus_read_word_data(client, page, phase, READ_PIN_EST); 262*38b2b022SNoah Wang if (ret < 0) 263*38b2b022SNoah Wang return ret; 264*38b2b022SNoah Wang 265*38b2b022SNoah Wang ret = mp2891_reg2data_linear11(ret); 266*38b2b022SNoah Wang break; 267*38b2b022SNoah Wang case PMBUS_READ_POUT: 268*38b2b022SNoah Wang /* 269*38b2b022SNoah Wang * The MP2891 PMBUS_READ_POUT register is linear11 format, and the 270*38b2b022SNoah Wang * exponent is not a constant value. But the pout scale is set to 271*38b2b022SNoah Wang * 1W/Lsb(using r/m/b scale). As a result, the pout read from MP2891 272*38b2b022SNoah Wang * should be calculated to W, then return the result to pmbus core. 273*38b2b022SNoah Wang */ 274*38b2b022SNoah Wang ret = pmbus_read_word_data(client, page, phase, reg); 275*38b2b022SNoah Wang if (ret < 0) 276*38b2b022SNoah Wang return ret; 277*38b2b022SNoah Wang 278*38b2b022SNoah Wang ret = mp2891_reg2data_linear11(ret); 279*38b2b022SNoah Wang break; 280*38b2b022SNoah Wang case PMBUS_READ_VOUT: 281*38b2b022SNoah Wang case PMBUS_VOUT_UV_WARN_LIMIT: 282*38b2b022SNoah Wang ret = pmbus_read_word_data(client, page, phase, reg); 283*38b2b022SNoah Wang if (ret < 0) 284*38b2b022SNoah Wang return ret; 285*38b2b022SNoah Wang 286*38b2b022SNoah Wang ret = DIV_ROUND_CLOSEST(ret * data->vout_scale[page], MP2891_VOUT_SCALE_DIV); 287*38b2b022SNoah Wang break; 288*38b2b022SNoah Wang case PMBUS_READ_IOUT: 289*38b2b022SNoah Wang ret = pmbus_read_word_data(client, page, phase, reg); 290*38b2b022SNoah Wang if (ret < 0) 291*38b2b022SNoah Wang return ret; 292*38b2b022SNoah Wang 293*38b2b022SNoah Wang ret = DIV_ROUND_CLOSEST((ret & GENMASK(10, 0)) * data->iout_scale[page], 294*38b2b022SNoah Wang MP2891_IOUT_SCALE_DIV); 295*38b2b022SNoah Wang break; 296*38b2b022SNoah Wang case PMBUS_OT_FAULT_LIMIT: 297*38b2b022SNoah Wang case PMBUS_OT_WARN_LIMIT: 298*38b2b022SNoah Wang /* 299*38b2b022SNoah Wang * The scale of MP2891 PMBUS_OT_FAULT_LIMIT and PMBUS_OT_WARN_LIMIT 300*38b2b022SNoah Wang * is 1°C/LSB and they have 40°C offset. 301*38b2b022SNoah Wang */ 302*38b2b022SNoah Wang ret = pmbus_read_word_data(client, page, phase, reg); 303*38b2b022SNoah Wang if (ret < 0) 304*38b2b022SNoah Wang return ret; 305*38b2b022SNoah Wang 306*38b2b022SNoah Wang ret = (ret & GENMASK(7, 0)) - MP2891_TEMP_LIMIT_OFFSET; 307*38b2b022SNoah Wang break; 308*38b2b022SNoah Wang case PMBUS_VIN_OV_FAULT_LIMIT: 309*38b2b022SNoah Wang /* 310*38b2b022SNoah Wang * The MP2891 PMBUS_VIN_OV_FAULT_LIMIT scale is 125mV/Lsb. 311*38b2b022SNoah Wang * but the vin scale is set to 31.25mV/Lsb(using r/m/b scale). 312*38b2b022SNoah Wang * As a result, the limit value should be multiplied by 4. 313*38b2b022SNoah Wang */ 314*38b2b022SNoah Wang ret = pmbus_read_word_data(client, page, phase, reg); 315*38b2b022SNoah Wang if (ret < 0) 316*38b2b022SNoah Wang return ret; 317*38b2b022SNoah Wang 318*38b2b022SNoah Wang ret = (ret & GENMASK(7, 0)) * 4; 319*38b2b022SNoah Wang break; 320*38b2b022SNoah Wang case PMBUS_VOUT_UV_FAULT_LIMIT: 321*38b2b022SNoah Wang ret = pmbus_read_word_data(client, page, phase, reg); 322*38b2b022SNoah Wang if (ret < 0) 323*38b2b022SNoah Wang return ret; 324*38b2b022SNoah Wang 325*38b2b022SNoah Wang if (FIELD_GET(GENMASK(11, 8), ret)) 326*38b2b022SNoah Wang ret = FIELD_GET(GENMASK(7, 0), ret) * MP2891_UV_LIMIT_SCALE - 327*38b2b022SNoah Wang (FIELD_GET(GENMASK(11, 8), ret) + 1) * MP2891_OVUV_DELTA_SCALE; 328*38b2b022SNoah Wang else 329*38b2b022SNoah Wang ret = FIELD_GET(GENMASK(7, 0), ret) * MP2891_UV_LIMIT_SCALE; 330*38b2b022SNoah Wang 331*38b2b022SNoah Wang ret = ret < 0 ? 0 : ret; 332*38b2b022SNoah Wang break; 333*38b2b022SNoah Wang case PMBUS_VOUT_OV_FAULT_LIMIT: 334*38b2b022SNoah Wang ret = pmbus_read_word_data(client, page, phase, reg); 335*38b2b022SNoah Wang if (ret < 0) 336*38b2b022SNoah Wang return ret; 337*38b2b022SNoah Wang 338*38b2b022SNoah Wang if (FIELD_GET(GENMASK(11, 8), ret)) 339*38b2b022SNoah Wang ret = FIELD_GET(GENMASK(7, 0), ret) * MP2891_OV_LIMIT_SCALE + 340*38b2b022SNoah Wang (FIELD_GET(GENMASK(11, 8), ret) + 1) * MP2891_OVUV_DELTA_SCALE; 341*38b2b022SNoah Wang else 342*38b2b022SNoah Wang ret = FIELD_GET(GENMASK(7, 0), ret) * MP2891_OV_LIMIT_SCALE; 343*38b2b022SNoah Wang break; 344*38b2b022SNoah Wang case PMBUS_IOUT_OC_WARN_LIMIT: 345*38b2b022SNoah Wang case PMBUS_IOUT_OC_FAULT_LIMIT: 346*38b2b022SNoah Wang ret = pmbus_read_word_data(client, page, phase, reg); 347*38b2b022SNoah Wang if (ret < 0) 348*38b2b022SNoah Wang return ret; 349*38b2b022SNoah Wang 350*38b2b022SNoah Wang ret = DIV_ROUND_CLOSEST((ret & GENMASK(7, 0)) * data->iout_scale[page] * 351*38b2b022SNoah Wang MP2891_IOUT_LIMIT_UINT, MP2891_IOUT_SCALE_DIV); 352*38b2b022SNoah Wang break; 353*38b2b022SNoah Wang case PMBUS_IIN_OC_WARN_LIMIT: 354*38b2b022SNoah Wang /* 355*38b2b022SNoah Wang * The scale of PMBUS_IIN_OC_WARN_LIMIT is 0.5A/Lsb, but the iin scale 356*38b2b022SNoah Wang * is set to 1A/Lsb(using r/m/b scale), so the word data should be 357*38b2b022SNoah Wang * divided by 2. 358*38b2b022SNoah Wang */ 359*38b2b022SNoah Wang ret = pmbus_read_word_data(client, 0, phase, reg); 360*38b2b022SNoah Wang if (ret < 0) 361*38b2b022SNoah Wang return ret; 362*38b2b022SNoah Wang 363*38b2b022SNoah Wang ret = DIV_ROUND_CLOSEST((ret & GENMASK(9, 0)), 2); 364*38b2b022SNoah Wang break; 365*38b2b022SNoah Wang case PMBUS_PIN_OP_WARN_LIMIT: 366*38b2b022SNoah Wang /* 367*38b2b022SNoah Wang * The scale of PMBUS_PIN_OP_WARN_LIMIT is 2W/Lsb, but the pin scale 368*38b2b022SNoah Wang * is set to 1W/Lsb(using r/m/b scale), so the word data should be 369*38b2b022SNoah Wang * multiplied by 2. 370*38b2b022SNoah Wang */ 371*38b2b022SNoah Wang ret = pmbus_read_word_data(client, 0, phase, reg); 372*38b2b022SNoah Wang if (ret < 0) 373*38b2b022SNoah Wang return ret; 374*38b2b022SNoah Wang 375*38b2b022SNoah Wang ret = (ret & GENMASK(9, 0)) * MP2891_PIN_LIMIT_UINT; 376*38b2b022SNoah Wang break; 377*38b2b022SNoah Wang case PMBUS_READ_TEMPERATURE_1: 378*38b2b022SNoah Wang case PMBUS_VIN_UV_FAULT_LIMIT: 379*38b2b022SNoah Wang case PMBUS_VIN_UV_WARN_LIMIT: 380*38b2b022SNoah Wang ret = -ENODATA; 381*38b2b022SNoah Wang break; 382*38b2b022SNoah Wang default: 383*38b2b022SNoah Wang ret = -EINVAL; 384*38b2b022SNoah Wang break; 385*38b2b022SNoah Wang } 386*38b2b022SNoah Wang 387*38b2b022SNoah Wang return ret; 388*38b2b022SNoah Wang } 389*38b2b022SNoah Wang 390*38b2b022SNoah Wang static int mp2891_write_word_data(struct i2c_client *client, int page, int reg, 391*38b2b022SNoah Wang u16 word) 392*38b2b022SNoah Wang { 393*38b2b022SNoah Wang const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 394*38b2b022SNoah Wang struct mp2891_data *data = to_mp2891_data(info); 395*38b2b022SNoah Wang int ret; 396*38b2b022SNoah Wang 397*38b2b022SNoah Wang switch (reg) { 398*38b2b022SNoah Wang case PMBUS_VOUT_UV_WARN_LIMIT: 399*38b2b022SNoah Wang ret = pmbus_write_word_data(client, page, reg, 400*38b2b022SNoah Wang DIV_ROUND_CLOSEST(word * MP2891_VOUT_SCALE_DIV, 401*38b2b022SNoah Wang data->vout_scale[page])); 402*38b2b022SNoah Wang break; 403*38b2b022SNoah Wang case PMBUS_VOUT_UV_FAULT_LIMIT: 404*38b2b022SNoah Wang /* 405*38b2b022SNoah Wang * The PMBUS_VOUT_UV_FAULT_LIMIT[7:0] is the limit value, and bit8-bit15 406*38b2b022SNoah Wang * should not be changed. 407*38b2b022SNoah Wang */ 408*38b2b022SNoah Wang ret = pmbus_read_word_data(client, page, 0xff, reg); 409*38b2b022SNoah Wang if (ret < 0) 410*38b2b022SNoah Wang return ret; 411*38b2b022SNoah Wang 412*38b2b022SNoah Wang if (FIELD_GET(GENMASK(11, 8), ret)) 413*38b2b022SNoah Wang ret = pmbus_write_word_data(client, page, reg, 414*38b2b022SNoah Wang (ret & ~GENMASK(7, 0)) | 415*38b2b022SNoah Wang FIELD_PREP(GENMASK(7, 0), 416*38b2b022SNoah Wang DIV_ROUND_CLOSEST(word + 417*38b2b022SNoah Wang (FIELD_GET(GENMASK(11, 8), ret) + 1) * 418*38b2b022SNoah Wang MP2891_OVUV_DELTA_SCALE, 419*38b2b022SNoah Wang MP2891_UV_LIMIT_SCALE))); 420*38b2b022SNoah Wang else 421*38b2b022SNoah Wang ret = pmbus_write_word_data(client, page, reg, 422*38b2b022SNoah Wang (ret & ~GENMASK(7, 0)) | 423*38b2b022SNoah Wang FIELD_PREP(GENMASK(7, 0), 424*38b2b022SNoah Wang DIV_ROUND_CLOSEST(word, 425*38b2b022SNoah Wang MP2891_UV_LIMIT_SCALE))); 426*38b2b022SNoah Wang break; 427*38b2b022SNoah Wang case PMBUS_VOUT_OV_FAULT_LIMIT: 428*38b2b022SNoah Wang /* 429*38b2b022SNoah Wang * The PMBUS_VOUT_OV_FAULT_LIMIT[7:0] is the limit value, and bit8-bit15 430*38b2b022SNoah Wang * should not be changed. 431*38b2b022SNoah Wang */ 432*38b2b022SNoah Wang ret = pmbus_read_word_data(client, page, 0xff, reg); 433*38b2b022SNoah Wang if (ret < 0) 434*38b2b022SNoah Wang return ret; 435*38b2b022SNoah Wang 436*38b2b022SNoah Wang if (FIELD_GET(GENMASK(11, 8), ret)) 437*38b2b022SNoah Wang ret = pmbus_write_word_data(client, page, reg, 438*38b2b022SNoah Wang (ret & ~GENMASK(7, 0)) | 439*38b2b022SNoah Wang FIELD_PREP(GENMASK(7, 0), 440*38b2b022SNoah Wang DIV_ROUND_CLOSEST(word - 441*38b2b022SNoah Wang (FIELD_GET(GENMASK(11, 8), ret) + 1) * 442*38b2b022SNoah Wang MP2891_OVUV_DELTA_SCALE, 443*38b2b022SNoah Wang MP2891_OV_LIMIT_SCALE))); 444*38b2b022SNoah Wang else 445*38b2b022SNoah Wang ret = pmbus_write_word_data(client, page, reg, 446*38b2b022SNoah Wang (ret & ~GENMASK(7, 0)) | 447*38b2b022SNoah Wang FIELD_PREP(GENMASK(7, 0), 448*38b2b022SNoah Wang DIV_ROUND_CLOSEST(word, 449*38b2b022SNoah Wang MP2891_OV_LIMIT_SCALE))); 450*38b2b022SNoah Wang break; 451*38b2b022SNoah Wang case PMBUS_VIN_OV_FAULT_LIMIT: 452*38b2b022SNoah Wang /* 453*38b2b022SNoah Wang * The PMBUS_VIN_OV_FAULT_LIMIT[7:0] is the limit value, and bit8-bit15 454*38b2b022SNoah Wang * should not be changed. The scale of PMBUS_VIN_OV_FAULT_LIMIT is 125mV/Lsb, 455*38b2b022SNoah Wang * but the vin scale is set to 31.25mV/Lsb(using r/m/b scale), so the word data 456*38b2b022SNoah Wang * should be divided by 4. 457*38b2b022SNoah Wang */ 458*38b2b022SNoah Wang ret = pmbus_read_word_data(client, page, 0xff, reg); 459*38b2b022SNoah Wang if (ret < 0) 460*38b2b022SNoah Wang return ret; 461*38b2b022SNoah Wang 462*38b2b022SNoah Wang ret = pmbus_write_word_data(client, page, reg, 463*38b2b022SNoah Wang (ret & ~GENMASK(7, 0)) | 464*38b2b022SNoah Wang FIELD_PREP(GENMASK(7, 0), 465*38b2b022SNoah Wang DIV_ROUND_CLOSEST(word, 4))); 466*38b2b022SNoah Wang break; 467*38b2b022SNoah Wang case PMBUS_OT_FAULT_LIMIT: 468*38b2b022SNoah Wang case PMBUS_OT_WARN_LIMIT: 469*38b2b022SNoah Wang /* 470*38b2b022SNoah Wang * The scale of MP2891 PMBUS_OT_FAULT_LIMIT and PMBUS_OT_WARN_LIMIT 471*38b2b022SNoah Wang * have 40°C offset. The bit0-bit7 is the limit value, and bit8-bit15 472*38b2b022SNoah Wang * should not be changed. 473*38b2b022SNoah Wang */ 474*38b2b022SNoah Wang ret = pmbus_read_word_data(client, page, 0xff, reg); 475*38b2b022SNoah Wang if (ret < 0) 476*38b2b022SNoah Wang return ret; 477*38b2b022SNoah Wang 478*38b2b022SNoah Wang ret = pmbus_write_word_data(client, page, reg, 479*38b2b022SNoah Wang (ret & ~GENMASK(7, 0)) | 480*38b2b022SNoah Wang FIELD_PREP(GENMASK(7, 0), word + MP2891_TEMP_LIMIT_OFFSET)); 481*38b2b022SNoah Wang break; 482*38b2b022SNoah Wang case PMBUS_IOUT_OC_WARN_LIMIT: 483*38b2b022SNoah Wang case PMBUS_IOUT_OC_FAULT_LIMIT: 484*38b2b022SNoah Wang ret = pmbus_write_word_data(client, page, reg, 485*38b2b022SNoah Wang DIV_ROUND_CLOSEST(word * MP2891_IOUT_SCALE_DIV, 486*38b2b022SNoah Wang MP2891_IOUT_LIMIT_UINT * 487*38b2b022SNoah Wang data->iout_scale[page])); 488*38b2b022SNoah Wang break; 489*38b2b022SNoah Wang case PMBUS_IIN_OC_WARN_LIMIT: 490*38b2b022SNoah Wang /* 491*38b2b022SNoah Wang * The scale of PMBUS_IIN_OC_WARN_LIMIT is 0.5A/Lsb, but the iin scale 492*38b2b022SNoah Wang * is set to 1A/Lsb(using r/m/b scale), so the word data should be 493*38b2b022SNoah Wang * multiplied by 2. 494*38b2b022SNoah Wang */ 495*38b2b022SNoah Wang ret = pmbus_write_word_data(client, page, reg, word * 2); 496*38b2b022SNoah Wang break; 497*38b2b022SNoah Wang case PMBUS_PIN_OP_WARN_LIMIT: 498*38b2b022SNoah Wang /* 499*38b2b022SNoah Wang * The scale of PMBUS_PIN_OP_WARN_LIMIT is 2W/Lsb, but the pin scale 500*38b2b022SNoah Wang * is set to 1W/Lsb(using r/m/b scale), so the word data should be 501*38b2b022SNoah Wang * divided by 2. 502*38b2b022SNoah Wang */ 503*38b2b022SNoah Wang ret = pmbus_write_word_data(client, page, reg, 504*38b2b022SNoah Wang DIV_ROUND_CLOSEST(word, MP2891_PIN_LIMIT_UINT)); 505*38b2b022SNoah Wang break; 506*38b2b022SNoah Wang case PMBUS_VIN_UV_FAULT_LIMIT: 507*38b2b022SNoah Wang case PMBUS_VIN_UV_WARN_LIMIT: 508*38b2b022SNoah Wang ret = -ENODATA; 509*38b2b022SNoah Wang break; 510*38b2b022SNoah Wang default: 511*38b2b022SNoah Wang ret = -EINVAL; 512*38b2b022SNoah Wang break; 513*38b2b022SNoah Wang } 514*38b2b022SNoah Wang 515*38b2b022SNoah Wang return ret; 516*38b2b022SNoah Wang } 517*38b2b022SNoah Wang 518*38b2b022SNoah Wang static const struct pmbus_driver_info mp2891_info = { 519*38b2b022SNoah Wang .pages = MP2891_PAGE_NUM, 520*38b2b022SNoah Wang .format[PSC_VOLTAGE_IN] = direct, 521*38b2b022SNoah Wang .format[PSC_CURRENT_IN] = direct, 522*38b2b022SNoah Wang .format[PSC_CURRENT_OUT] = direct, 523*38b2b022SNoah Wang .format[PSC_TEMPERATURE] = direct, 524*38b2b022SNoah Wang .format[PSC_POWER] = direct, 525*38b2b022SNoah Wang .format[PSC_VOLTAGE_OUT] = direct, 526*38b2b022SNoah Wang 527*38b2b022SNoah Wang /* set vin scale 31.25mV/Lsb */ 528*38b2b022SNoah Wang .m[PSC_VOLTAGE_IN] = 32, 529*38b2b022SNoah Wang .R[PSC_VOLTAGE_IN] = 0, 530*38b2b022SNoah Wang .b[PSC_VOLTAGE_IN] = 0, 531*38b2b022SNoah Wang 532*38b2b022SNoah Wang /* set temp scale 1000m°C/Lsb */ 533*38b2b022SNoah Wang .m[PSC_TEMPERATURE] = 1, 534*38b2b022SNoah Wang .R[PSC_TEMPERATURE] = 0, 535*38b2b022SNoah Wang .b[PSC_TEMPERATURE] = 0, 536*38b2b022SNoah Wang 537*38b2b022SNoah Wang .m[PSC_CURRENT_IN] = 1, 538*38b2b022SNoah Wang .R[PSC_CURRENT_IN] = 0, 539*38b2b022SNoah Wang .b[PSC_CURRENT_IN] = 0, 540*38b2b022SNoah Wang 541*38b2b022SNoah Wang .m[PSC_CURRENT_OUT] = 1, 542*38b2b022SNoah Wang .R[PSC_CURRENT_OUT] = 0, 543*38b2b022SNoah Wang .b[PSC_CURRENT_OUT] = 0, 544*38b2b022SNoah Wang 545*38b2b022SNoah Wang .m[PSC_POWER] = 1, 546*38b2b022SNoah Wang .R[PSC_POWER] = 0, 547*38b2b022SNoah Wang .b[PSC_POWER] = 0, 548*38b2b022SNoah Wang 549*38b2b022SNoah Wang .m[PSC_VOLTAGE_OUT] = 1, 550*38b2b022SNoah Wang .R[PSC_VOLTAGE_OUT] = 3, 551*38b2b022SNoah Wang .b[PSC_VOLTAGE_OUT] = 0, 552*38b2b022SNoah Wang 553*38b2b022SNoah Wang .func[0] = MP2891_RAIL1_FUNC, 554*38b2b022SNoah Wang .func[1] = MP2891_RAIL2_FUNC, 555*38b2b022SNoah Wang .read_word_data = mp2891_read_word_data, 556*38b2b022SNoah Wang .write_word_data = mp2891_write_word_data, 557*38b2b022SNoah Wang .read_byte_data = mp2891_read_byte_data, 558*38b2b022SNoah Wang .identify = mp2891_identify, 559*38b2b022SNoah Wang }; 560*38b2b022SNoah Wang 561*38b2b022SNoah Wang static int mp2891_probe(struct i2c_client *client) 562*38b2b022SNoah Wang { 563*38b2b022SNoah Wang struct mp2891_data *data; 564*38b2b022SNoah Wang 565*38b2b022SNoah Wang data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); 566*38b2b022SNoah Wang if (!data) 567*38b2b022SNoah Wang return -ENOMEM; 568*38b2b022SNoah Wang 569*38b2b022SNoah Wang memcpy(&data->info, &mp2891_info, sizeof(mp2891_info)); 570*38b2b022SNoah Wang 571*38b2b022SNoah Wang return pmbus_do_probe(client, &data->info); 572*38b2b022SNoah Wang } 573*38b2b022SNoah Wang 574*38b2b022SNoah Wang static const struct i2c_device_id mp2891_id[] = { 575*38b2b022SNoah Wang {"mp2891", 0}, 576*38b2b022SNoah Wang {} 577*38b2b022SNoah Wang }; 578*38b2b022SNoah Wang MODULE_DEVICE_TABLE(i2c, mp2891_id); 579*38b2b022SNoah Wang 580*38b2b022SNoah Wang static const struct of_device_id __maybe_unused mp2891_of_match[] = { 581*38b2b022SNoah Wang {.compatible = "mps,mp2891"}, 582*38b2b022SNoah Wang {} 583*38b2b022SNoah Wang }; 584*38b2b022SNoah Wang MODULE_DEVICE_TABLE(of, mp2891_of_match); 585*38b2b022SNoah Wang 586*38b2b022SNoah Wang static struct i2c_driver mp2891_driver = { 587*38b2b022SNoah Wang .driver = { 588*38b2b022SNoah Wang .name = "mp2891", 589*38b2b022SNoah Wang .of_match_table = mp2891_of_match, 590*38b2b022SNoah Wang }, 591*38b2b022SNoah Wang .probe = mp2891_probe, 592*38b2b022SNoah Wang .id_table = mp2891_id, 593*38b2b022SNoah Wang }; 594*38b2b022SNoah Wang 595*38b2b022SNoah Wang module_i2c_driver(mp2891_driver); 596*38b2b022SNoah Wang 597*38b2b022SNoah Wang MODULE_AUTHOR("Noah Wang <noahwang.wang@outlook.com>"); 598*38b2b022SNoah Wang MODULE_DESCRIPTION("PMBus driver for MPS MP2891"); 599*38b2b022SNoah Wang MODULE_LICENSE("GPL"); 600*38b2b022SNoah Wang MODULE_IMPORT_NS(PMBUS); 601