/* * Vender specific registers, the register MFR_SVI3_IOUT_PRT(0x65), * MFR_VOUT_LOOP_CTRL(0xBD), READ_PIN_EST(0x94)and READ_IIN_EST(0x95) * redefine the standard PMBUS register. The MFR_SVI3_IOUT_PRT(0x65) * is used to identify the iout scale and the MFR_VOUT_LOOP_CTRL(0xBD) * is used to identify the vout scale. The READ_PIN_EST(0x94) is used * to read input power per rail. The MP2891 does not have standard * READ_IIN register(0x89), the iin telemetry can be obtained through * the vendor redefined register READ_IIN_EST(0x95).
*/ #define MFR_VOUT_LOOP_CTRL 0xBD #define READ_PIN_EST 0x94 #define READ_IIN_EST 0x95 #define MFR_SVI3_IOUT_PRT 0x65
staticint mp2891_read_byte_data(struct i2c_client *client, int page, int reg)
{ int ret;
switch (reg) { case PMBUS_VOUT_MODE: /* * The MP2891 does not follow standard PMBus protocol completely, the * PMBUS_VOUT_MODE(0x20) in MP2891 is reserved and 0x00 is always * returned when the register is read. But the calculation of vout in * this driver is based on direct format. As a result, the format of * vout is enforced to direct.
*/
ret = PB_VOUT_MODE_DIRECT; break; default:
ret = -ENODATA; break;
}
return ret;
}
staticint mp2891_read_word_data(struct i2c_client *client, int page, int phase, int reg)
{ conststruct pmbus_driver_info *info = pmbus_get_driver_info(client); struct mp2891_data *data = to_mp2891_data(info); int ret;
switch (reg) { case PMBUS_READ_VIN:
ret = pmbus_read_word_data(client, page, phase, reg); if (ret < 0) return ret;
ret = ret & GENMASK(9, 0); break; case PMBUS_READ_IIN: /* * The MP2891 does not have standard PMBUS_READ_IIN register(0x89), * the iin telemetry can be obtained through the vender redefined * register READ_IIN_EST(0x95). The MP2891 PMBUS_READ_IIN register * is linear11 format, But the pout scale is set to 1A/Lsb(using * r/m/b scale). As a result, the iin read from MP2891 should be * calculated to A, then return the result to pmbus core.
*/
ret = pmbus_read_word_data(client, page, phase, READ_IIN_EST); if (ret < 0) return ret;
ret = mp2891_reg2data_linear11(ret); break; case PMBUS_READ_PIN: /* * The MP2891 has standard PMBUS_READ_PIN register(0x97), but this * is not used to read the input power per rail. The input power * per rail is read through the vender redefined register * READ_PIN_EST(0x94). The MP2891 PMBUS_READ_PIN register is linear11 * format, But the pout scale is set to 1W/Lsb(using r/m/b scale). * As a result, the pin read from MP2891 should be calculated to W, * then return the result to pmbus core.
*/
ret = pmbus_read_word_data(client, page, phase, READ_PIN_EST); if (ret < 0) return ret;
ret = mp2891_reg2data_linear11(ret); break; case PMBUS_READ_POUT: /* * The MP2891 PMBUS_READ_POUT register is linear11 format, and the * exponent is not a constant value. But the pout scale is set to * 1W/Lsb(using r/m/b scale). As a result, the pout read from MP2891 * should be calculated to W, then return the result to pmbus core.
*/
ret = pmbus_read_word_data(client, page, phase, reg); if (ret < 0) return ret;
ret = mp2891_reg2data_linear11(ret); break; case PMBUS_READ_VOUT: case PMBUS_VOUT_UV_WARN_LIMIT:
ret = pmbus_read_word_data(client, page, phase, reg); if (ret < 0) return ret;
ret = DIV_ROUND_CLOSEST(ret * data->vout_scale[page], MP2891_VOUT_SCALE_DIV); break; case PMBUS_READ_IOUT:
ret = pmbus_read_word_data(client, page, phase, reg); if (ret < 0) return ret;
ret = DIV_ROUND_CLOSEST((ret & GENMASK(10, 0)) * data->iout_scale[page],
MP2891_IOUT_SCALE_DIV); break; case PMBUS_OT_FAULT_LIMIT: case PMBUS_OT_WARN_LIMIT: /* * The scale of MP2891 PMBUS_OT_FAULT_LIMIT and PMBUS_OT_WARN_LIMIT * is 1°C/LSB and they have 40°C offset.
*/
ret = pmbus_read_word_data(client, page, phase, reg); if (ret < 0) return ret;
ret = (ret & GENMASK(7, 0)) - MP2891_TEMP_LIMIT_OFFSET; break; case PMBUS_VIN_OV_FAULT_LIMIT: /* * The MP2891 PMBUS_VIN_OV_FAULT_LIMIT scale is 125mV/Lsb. * but the vin scale is set to 31.25mV/Lsb(using r/m/b scale). * As a result, the limit value should be multiplied by 4.
*/
ret = pmbus_read_word_data(client, page, phase, reg); if (ret < 0) return ret;
ret = (ret & GENMASK(7, 0)) * 4; break; case PMBUS_VOUT_UV_FAULT_LIMIT:
ret = pmbus_read_word_data(client, page, phase, reg); if (ret < 0) return ret;
if (FIELD_GET(GENMASK(11, 8), ret))
ret = FIELD_GET(GENMASK(7, 0), ret) * MP2891_UV_LIMIT_SCALE -
(FIELD_GET(GENMASK(11, 8), ret) + 1) * MP2891_OVUV_DELTA_SCALE; else
ret = FIELD_GET(GENMASK(7, 0), ret) * MP2891_UV_LIMIT_SCALE;
ret = ret < 0 ? 0 : ret; break; case PMBUS_VOUT_OV_FAULT_LIMIT:
ret = pmbus_read_word_data(client, page, phase, reg); if (ret < 0) return ret;
if (FIELD_GET(GENMASK(11, 8), ret))
ret = FIELD_GET(GENMASK(7, 0), ret) * MP2891_OV_LIMIT_SCALE +
(FIELD_GET(GENMASK(11, 8), ret) + 1) * MP2891_OVUV_DELTA_SCALE; else
ret = FIELD_GET(GENMASK(7, 0), ret) * MP2891_OV_LIMIT_SCALE; break; case PMBUS_IOUT_OC_WARN_LIMIT: case PMBUS_IOUT_OC_FAULT_LIMIT:
ret = pmbus_read_word_data(client, page, phase, reg); if (ret < 0) return ret;
ret = DIV_ROUND_CLOSEST((ret & GENMASK(7, 0)) * data->iout_scale[page] *
MP2891_IOUT_LIMIT_UINT, MP2891_IOUT_SCALE_DIV); break; case PMBUS_IIN_OC_WARN_LIMIT: /* * The scale of PMBUS_IIN_OC_WARN_LIMIT is 0.5A/Lsb, but the iin scale * is set to 1A/Lsb(using r/m/b scale), so the word data should be * divided by 2.
*/
ret = pmbus_read_word_data(client, 0, phase, reg); if (ret < 0) return ret;
ret = DIV_ROUND_CLOSEST((ret & GENMASK(9, 0)), 2); break; case PMBUS_PIN_OP_WARN_LIMIT: /* * The scale of PMBUS_PIN_OP_WARN_LIMIT is 2W/Lsb, but the pin scale * is set to 1W/Lsb(using r/m/b scale), so the word data should be * multiplied by 2.
*/
ret = pmbus_read_word_data(client, 0, phase, reg); if (ret < 0) return ret;
ret = (ret & GENMASK(9, 0)) * MP2891_PIN_LIMIT_UINT; break; case PMBUS_READ_TEMPERATURE_1: case PMBUS_VIN_UV_FAULT_LIMIT: case PMBUS_VIN_UV_WARN_LIMIT:
ret = -ENODATA; break; default:
ret = -EINVAL; break;
}
return ret;
}
staticint mp2891_write_word_data(struct i2c_client *client, int page, int reg,
u16 word)
{ conststruct pmbus_driver_info *info = pmbus_get_driver_info(client); struct mp2891_data *data = to_mp2891_data(info); int ret;
switch (reg) { case PMBUS_VOUT_UV_WARN_LIMIT:
ret = pmbus_write_word_data(client, page, reg,
DIV_ROUND_CLOSEST(word * MP2891_VOUT_SCALE_DIV,
data->vout_scale[page])); break; case PMBUS_VOUT_UV_FAULT_LIMIT: /* * The PMBUS_VOUT_UV_FAULT_LIMIT[7:0] is the limit value, and bit8-bit15 * should not be changed.
*/
ret = pmbus_read_word_data(client, page, 0xff, reg); if (ret < 0) return ret;
if (FIELD_GET(GENMASK(11, 8), ret))
ret = pmbus_write_word_data(client, page, reg,
(ret & ~GENMASK(7, 0)) |
FIELD_PREP(GENMASK(7, 0),
DIV_ROUND_CLOSEST(word +
(FIELD_GET(GENMASK(11, 8), ret) + 1) *
MP2891_OVUV_DELTA_SCALE,
MP2891_UV_LIMIT_SCALE))); else
ret = pmbus_write_word_data(client, page, reg,
(ret & ~GENMASK(7, 0)) |
FIELD_PREP(GENMASK(7, 0),
DIV_ROUND_CLOSEST(word,
MP2891_UV_LIMIT_SCALE))); break; case PMBUS_VOUT_OV_FAULT_LIMIT: /* * The PMBUS_VOUT_OV_FAULT_LIMIT[7:0] is the limit value, and bit8-bit15 * should not be changed.
*/
ret = pmbus_read_word_data(client, page, 0xff, reg); if (ret < 0) return ret;
if (FIELD_GET(GENMASK(11, 8), ret))
ret = pmbus_write_word_data(client, page, reg,
(ret & ~GENMASK(7, 0)) |
FIELD_PREP(GENMASK(7, 0),
DIV_ROUND_CLOSEST(word -
(FIELD_GET(GENMASK(11, 8), ret) + 1) *
MP2891_OVUV_DELTA_SCALE,
MP2891_OV_LIMIT_SCALE))); else
ret = pmbus_write_word_data(client, page, reg,
(ret & ~GENMASK(7, 0)) |
FIELD_PREP(GENMASK(7, 0),
DIV_ROUND_CLOSEST(word,
MP2891_OV_LIMIT_SCALE))); break; case PMBUS_VIN_OV_FAULT_LIMIT: /* * The PMBUS_VIN_OV_FAULT_LIMIT[7:0] is the limit value, and bit8-bit15 * should not be changed. The scale of PMBUS_VIN_OV_FAULT_LIMIT is 125mV/Lsb, * but the vin scale is set to 31.25mV/Lsb(using r/m/b scale), so the word data * should be divided by 4.
*/
ret = pmbus_read_word_data(client, page, 0xff, reg); if (ret < 0) return ret;
ret = pmbus_write_word_data(client, page, reg,
(ret & ~GENMASK(7, 0)) |
FIELD_PREP(GENMASK(7, 0),
DIV_ROUND_CLOSEST(word, 4))); break; case PMBUS_OT_FAULT_LIMIT: case PMBUS_OT_WARN_LIMIT: /* * The scale of MP2891 PMBUS_OT_FAULT_LIMIT and PMBUS_OT_WARN_LIMIT * have 40°C offset. The bit0-bit7 is the limit value, and bit8-bit15 * should not be changed.
*/
ret = pmbus_read_word_data(client, page, 0xff, reg); if (ret < 0) return ret;
ret = pmbus_write_word_data(client, page, reg,
(ret & ~GENMASK(7, 0)) |
FIELD_PREP(GENMASK(7, 0), word + MP2891_TEMP_LIMIT_OFFSET)); break; case PMBUS_IOUT_OC_WARN_LIMIT: case PMBUS_IOUT_OC_FAULT_LIMIT:
ret = pmbus_write_word_data(client, page, reg,
DIV_ROUND_CLOSEST(word * MP2891_IOUT_SCALE_DIV,
MP2891_IOUT_LIMIT_UINT *
data->iout_scale[page])); break; case PMBUS_IIN_OC_WARN_LIMIT: /* * The scale of PMBUS_IIN_OC_WARN_LIMIT is 0.5A/Lsb, but the iin scale * is set to 1A/Lsb(using r/m/b scale), so the word data should be * multiplied by 2.
*/
ret = pmbus_write_word_data(client, page, reg, word * 2); break; case PMBUS_PIN_OP_WARN_LIMIT: /* * The scale of PMBUS_PIN_OP_WARN_LIMIT is 2W/Lsb, but the pin scale * is set to 1W/Lsb(using r/m/b scale), so the word data should be * divided by 2.
*/
ret = pmbus_write_word_data(client, page, reg,
DIV_ROUND_CLOSEST(word, MP2891_PIN_LIMIT_UINT)); break; case PMBUS_VIN_UV_FAULT_LIMIT: case PMBUS_VIN_UV_WARN_LIMIT:
ret = -ENODATA; break; default:
ret = -EINVAL; break;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.