/* * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which * happens pretty much each time chip data is updated. Raw peak data therefore * does not provide much value. To be able to provide useful peak data, keep an * internal cache of measured peak data, which is only cleared if an explicit * "clear peak" command is executed for the sensor in question.
*/
/* * LTC3883 does not support LTC_NOT_PENDING, even though * the datasheet claims that it does.
*/
mask = LTC_NOT_BUSY; if (data->id != ltc3883)
mask |= LTC_NOT_PENDING;
do {
status = pmbus_read_byte_data(client, 0, LTC2978_MFR_COMMON); if (status == -EBADMSG || status == -ENXIO) { /* PEC error or NACK: chip may be busy, try again */
usleep_range(50, 100); continue;
} if (status < 0) return status;
if ((status & mask) == mask) return 0;
usleep_range(50, 100);
} while (time_before(jiffies, timeout));
return -ETIMEDOUT;
}
staticint ltc_read_word_data(struct i2c_client *client, int page, int phase, int reg)
{ int ret;
ret = ltc_wait_ready(client); if (ret < 0) return ret;
staticint ltc_write_byte(struct i2c_client *client, int page, u8 byte)
{ int ret;
ret = ltc_wait_ready(client); if (ret < 0) return ret;
return pmbus_write_byte(client, page, byte);
}
staticinlineint lin11_to_val(int data)
{
s16 e = ((s16)data) >> 11;
s32 m = (((s16)(data << 5)) >> 5);
/* * mantissa is 10 bit + sign, exponent adds up to 15 bit. * Add 6 bit to exponent for maximum accuracy (10 + 15 + 6 = 31).
*/
e += 6; return (e < 0 ? m >> -e : m << e);
}
staticint ltc_get_max(struct ltc2978_data *data, struct i2c_client *client, int page, int reg, u16 *pmax)
{ int ret;
ret = ltc_read_word_data(client, page, 0xff, reg); if (ret >= 0) { if (lin11_to_val(ret) > lin11_to_val(*pmax))
*pmax = ret;
ret = *pmax;
} return ret;
}
staticint ltc_get_min(struct ltc2978_data *data, struct i2c_client *client, int page, int reg, u16 *pmin)
{ int ret;
ret = ltc_read_word_data(client, page, 0xff, reg); if (ret >= 0) { if (lin11_to_val(ret) < lin11_to_val(*pmin))
*pmin = ret;
ret = *pmin;
} return ret;
}
staticint ltc2978_read_word_data_common(struct i2c_client *client, int page, int reg)
{ conststruct pmbus_driver_info *info = pmbus_get_driver_info(client); struct ltc2978_data *data = to_ltc2978_data(info); int ret;
switch (reg) { case PMBUS_VIRT_READ_VIN_MAX:
ret = ltc_get_max(data, client, page, LTC2978_MFR_VIN_PEAK,
&data->vin_max); break; case PMBUS_VIRT_READ_VOUT_MAX:
ret = ltc_read_word_data(client, page, 0xff,
LTC2978_MFR_VOUT_PEAK); if (ret >= 0) { /* * VOUT is 16 bit unsigned with fixed exponent, * so we can compare it directly
*/ if (ret > data->vout_max[page])
data->vout_max[page] = ret;
ret = data->vout_max[page];
} break; case PMBUS_VIRT_READ_TEMP_MAX:
ret = ltc_get_max(data, client, page,
LTC2978_MFR_TEMPERATURE_PEAK,
&data->temp_max[page]); break; case PMBUS_VIRT_RESET_VOUT_HISTORY: case PMBUS_VIRT_RESET_VIN_HISTORY: case PMBUS_VIRT_RESET_TEMP_HISTORY:
ret = 0; break; default:
ret = ltc_wait_ready(client); if (ret < 0) return ret;
ret = -ENODATA; break;
} return ret;
}
staticint ltc2978_read_word_data(struct i2c_client *client, int page, int phase, int reg)
{ conststruct pmbus_driver_info *info = pmbus_get_driver_info(client); struct ltc2978_data *data = to_ltc2978_data(info); int ret;
switch (reg) { case PMBUS_VIRT_READ_VIN_MIN:
ret = ltc_get_min(data, client, page, LTC2978_MFR_VIN_MIN,
&data->vin_min); break; case PMBUS_VIRT_READ_VOUT_MIN:
ret = ltc_read_word_data(client, page, phase,
LTC2978_MFR_VOUT_MIN); if (ret >= 0) { /* * VOUT_MIN is known to not be supported on some lots * of LTC2978 revision 1, and will return the maximum * possible voltage if read. If VOUT_MAX is valid and * lower than the reading of VOUT_MIN, use it instead.
*/ if (data->vout_max[page] && ret > data->vout_max[page])
ret = data->vout_max[page]; if (ret < data->vout_min[page])
data->vout_min[page] = ret;
ret = data->vout_min[page];
} break; case PMBUS_VIRT_READ_TEMP_MIN:
ret = ltc_get_min(data, client, page,
LTC2978_MFR_TEMPERATURE_MIN,
&data->temp_min[page]); break; case PMBUS_VIRT_READ_IOUT_MAX: case PMBUS_VIRT_RESET_IOUT_HISTORY: case PMBUS_VIRT_READ_TEMP2_MAX: case PMBUS_VIRT_RESET_TEMP2_HISTORY:
ret = -ENXIO; break; default:
ret = ltc2978_read_word_data_common(client, page, reg); break;
} return ret;
}
staticint ltc2974_read_word_data(struct i2c_client *client, int page, int phase, int reg)
{ conststruct pmbus_driver_info *info = pmbus_get_driver_info(client); struct ltc2978_data *data = to_ltc2978_data(info); int ret;
switch (reg) { case PMBUS_VIRT_READ_IOUT_MAX:
ret = ltc_get_max(data, client, page, LTC2974_MFR_IOUT_PEAK,
&data->iout_max[page]); break; case PMBUS_VIRT_READ_IOUT_MIN:
ret = ltc_get_min(data, client, page, LTC2974_MFR_IOUT_MIN,
&data->iout_min[page]); break; case PMBUS_VIRT_RESET_IOUT_HISTORY:
ret = 0; break; default:
ret = ltc2978_read_word_data(client, page, phase, reg); break;
} return ret;
}
staticint ltc2975_read_word_data(struct i2c_client *client, int page, int phase, int reg)
{ conststruct pmbus_driver_info *info = pmbus_get_driver_info(client); struct ltc2978_data *data = to_ltc2978_data(info); int ret;
switch (reg) { case PMBUS_VIRT_READ_IIN_MAX:
ret = ltc_get_max(data, client, page, LTC2975_MFR_IIN_PEAK,
&data->iin_max); break; case PMBUS_VIRT_READ_IIN_MIN:
ret = ltc_get_min(data, client, page, LTC2975_MFR_IIN_MIN,
&data->iin_min); break; case PMBUS_VIRT_READ_PIN_MAX:
ret = ltc_get_max(data, client, page, LTC2975_MFR_PIN_PEAK,
&data->pin_max); break; case PMBUS_VIRT_READ_PIN_MIN:
ret = ltc_get_min(data, client, page, LTC2975_MFR_PIN_MIN,
&data->pin_min); break; case PMBUS_VIRT_RESET_IIN_HISTORY: case PMBUS_VIRT_RESET_PIN_HISTORY:
ret = 0; break; default:
ret = ltc2978_read_word_data(client, page, phase, reg); break;
} return ret;
}
staticint ltc3880_read_word_data(struct i2c_client *client, int page, int phase, int reg)
{ conststruct pmbus_driver_info *info = pmbus_get_driver_info(client); struct ltc2978_data *data = to_ltc2978_data(info); int ret;
switch (reg) { case PMBUS_VIRT_READ_IOUT_MAX:
ret = ltc_get_max(data, client, page, LTC3880_MFR_IOUT_PEAK,
&data->iout_max[page]); break; case PMBUS_VIRT_READ_TEMP2_MAX:
ret = ltc_get_max(data, client, page,
LTC3880_MFR_TEMPERATURE2_PEAK,
&data->temp2_max); break; case PMBUS_VIRT_READ_VIN_MIN: case PMBUS_VIRT_READ_VOUT_MIN: case PMBUS_VIRT_READ_TEMP_MIN:
ret = -ENXIO; break; case PMBUS_VIRT_RESET_IOUT_HISTORY: case PMBUS_VIRT_RESET_TEMP2_HISTORY:
ret = 0; break; default:
ret = ltc2978_read_word_data_common(client, page, reg); break;
} return ret;
}
staticint ltc3883_read_word_data(struct i2c_client *client, int page, int phase, int reg)
{ conststruct pmbus_driver_info *info = pmbus_get_driver_info(client); struct ltc2978_data *data = to_ltc2978_data(info); int ret;
switch (reg) { case PMBUS_VIRT_READ_IIN_MAX:
ret = ltc_get_max(data, client, page, LTC3883_MFR_IIN_PEAK,
&data->iin_max); break; case PMBUS_VIRT_RESET_IIN_HISTORY:
ret = 0; break; default:
ret = ltc3880_read_word_data(client, page, phase, reg); break;
} return ret;
}
staticint ltc2978_clear_peaks(struct ltc2978_data *data, struct i2c_client *client, int page)
{ int ret;
if (has_clear_peaks(data))
ret = ltc_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); else
ret = ltc_write_byte(client, page, PMBUS_CLEAR_FAULTS);
return ret;
}
staticint ltc2978_write_word_data(struct i2c_client *client, int page, int reg, u16 word)
{ conststruct pmbus_driver_info *info = pmbus_get_driver_info(client); struct ltc2978_data *data = to_ltc2978_data(info); int ret;
switch (reg) { case PMBUS_VIRT_RESET_IIN_HISTORY:
data->iin_max = 0x7c00;
data->iin_min = 0x7bff;
ret = ltc2978_clear_peaks(data, client, 0); break; case PMBUS_VIRT_RESET_PIN_HISTORY:
data->pin_max = 0x7c00;
data->pin_min = 0x7bff;
ret = ltc2978_clear_peaks(data, client, 0); break; case PMBUS_VIRT_RESET_IOUT_HISTORY:
data->iout_max[page] = 0x7c00;
data->iout_min[page] = 0xfbff;
ret = ltc2978_clear_peaks(data, client, page); break; case PMBUS_VIRT_RESET_TEMP2_HISTORY:
data->temp2_max = 0x7c00;
ret = ltc2978_clear_peaks(data, client, page); break; case PMBUS_VIRT_RESET_VOUT_HISTORY:
data->vout_min[page] = 0xffff;
data->vout_max[page] = 0;
ret = ltc2978_clear_peaks(data, client, page); break; case PMBUS_VIRT_RESET_VIN_HISTORY:
data->vin_min = 0x7bff;
data->vin_max = 0x7c00;
ret = ltc2978_clear_peaks(data, client, page); break; case PMBUS_VIRT_RESET_TEMP_HISTORY:
data->temp_min[page] = 0x7bff;
data->temp_max[page] = 0x7c00;
ret = ltc2978_clear_peaks(data, client, page); break; default:
ret = ltc_wait_ready(client); if (ret < 0) return ret;
ret = -ENODATA; break;
} return ret;
}
data->vin_min = 0x7bff;
data->vin_max = 0x7c00; for (i = 0; i < ARRAY_SIZE(data->vout_min); i++)
data->vout_min[i] = 0xffff; for (i = 0; i < ARRAY_SIZE(data->iout_min); i++)
data->iout_min[i] = 0xfbff; for (i = 0; i < ARRAY_SIZE(data->iout_max); i++)
data->iout_max[i] = 0x7c00; for (i = 0; i < ARRAY_SIZE(data->temp_min); i++)
data->temp_min[i] = 0x7bff; for (i = 0; i < ARRAY_SIZE(data->temp_max); i++)
data->temp_max[i] = 0x7c00;
data->temp2_max = 0x7c00;
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.