// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for Analog Devices ADM1275 Hot-Swap Controller * and Digital Power Monitor * * Copyright (c) 2011 Ericsson AB. * Copyright (c) 2018 Guenter Roeck
*/
/* * The PMON configuration register is a 16-bit register only on chips * supporting power average sampling. On other chips it is an 8-bit * register.
*/ if (data->have_power_sampling) {
ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG);
mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK;
shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT;
} else {
ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
mask = ADM1275_VI_AVG_MASK;
shift = ADM1275_VI_AVG_SHIFT;
} if (ret < 0) return ret;
ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONTROL, 0); if (ret) return ret;
if (data->have_power_sampling)
ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG,
word); else
ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONFIG,
word);
/* * We still want to re-enable conversions if writing into * ADM1275_PMON_CONFIG failed.
*/
ret2 = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONTROL,
ADM1275_CONVERT_EN); if (!ret)
ret = ret2;
staticint adm1275_read_word_data(struct i2c_client *client, int page, int phase, int reg)
{ conststruct pmbus_driver_info *info = pmbus_get_driver_info(client); conststruct adm1275_data *data = to_adm1275_data(info); int ret = 0;
if (page > 0) return -ENXIO;
switch (reg) { case PMBUS_IOUT_UC_FAULT_LIMIT: if (!data->have_uc_fault) return -ENXIO;
ret = pmbus_read_word_data(client, 0, 0xff,
ADM1275_IOUT_WARN2_LIMIT); break; case PMBUS_IOUT_OC_FAULT_LIMIT: if (!data->have_oc_fault) return -ENXIO;
ret = pmbus_read_word_data(client, 0, 0xff,
ADM1275_IOUT_WARN2_LIMIT); break; case PMBUS_VOUT_OV_WARN_LIMIT: if (data->have_vout) return -ENODATA;
ret = pmbus_read_word_data(client, 0, 0xff,
ADM1075_VAUX_OV_WARN_LIMIT); break; case PMBUS_VOUT_UV_WARN_LIMIT: if (data->have_vout) return -ENODATA;
ret = pmbus_read_word_data(client, 0, 0xff,
ADM1075_VAUX_UV_WARN_LIMIT); break; case PMBUS_READ_VOUT: if (data->have_vout) return -ENODATA;
ret = pmbus_read_word_data(client, 0, 0xff,
ADM1075_READ_VAUX); break; case PMBUS_VIRT_READ_IOUT_MIN: if (!data->have_iout_min) return -ENXIO;
ret = pmbus_read_word_data(client, 0, 0xff,
ADM1293_IOUT_MIN); break; case PMBUS_VIRT_READ_IOUT_MAX:
ret = pmbus_read_word_data(client, 0, 0xff,
ADM1275_PEAK_IOUT); break; case PMBUS_VIRT_READ_VOUT_MAX:
ret = pmbus_read_word_data(client, 0, 0xff,
ADM1275_PEAK_VOUT); break; case PMBUS_VIRT_READ_VIN_MAX:
ret = pmbus_read_word_data(client, 0, 0xff,
ADM1275_PEAK_VIN); break; case PMBUS_VIRT_READ_PIN_MIN: if (!data->have_pin_min) return -ENXIO;
ret = pmbus_read_word_data(client, 0, 0xff,
ADM1293_PIN_MIN); break; case PMBUS_VIRT_READ_PIN_MAX: if (!data->have_pin_max) return -ENXIO;
ret = pmbus_read_word_data(client, 0, 0xff,
ADM1276_PEAK_PIN); break; case PMBUS_VIRT_READ_TEMP_MAX: if (!data->have_temp_max) return -ENXIO;
ret = pmbus_read_word_data(client, 0, 0xff,
ADM1278_PEAK_TEMP); break; case PMBUS_VIRT_RESET_IOUT_HISTORY: case PMBUS_VIRT_RESET_VOUT_HISTORY: case PMBUS_VIRT_RESET_VIN_HISTORY: break; case PMBUS_VIRT_RESET_PIN_HISTORY: if (!data->have_pin_max) return -ENXIO; break; case PMBUS_VIRT_RESET_TEMP_HISTORY: if (!data->have_temp_max) return -ENXIO; break; case PMBUS_VIRT_POWER_SAMPLES: if (!data->have_power_sampling) return -ENXIO;
ret = adm1275_read_samples(data, client, true); if (ret < 0) break;
ret = BIT(ret); break; case PMBUS_VIRT_IN_SAMPLES: case PMBUS_VIRT_CURR_SAMPLES:
ret = adm1275_read_samples(data, client, false); if (ret < 0) break;
ret = BIT(ret); break; default:
ret = -ENODATA; break;
} return ret;
}
staticint adm1275_write_word_data(struct i2c_client *client, int page, int reg,
u16 word)
{ conststruct pmbus_driver_info *info = pmbus_get_driver_info(client); conststruct adm1275_data *data = to_adm1275_data(info); int ret;
if (page > 0) return -ENXIO;
switch (reg) { case PMBUS_IOUT_UC_FAULT_LIMIT: case PMBUS_IOUT_OC_FAULT_LIMIT:
ret = pmbus_write_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT,
word); break; case PMBUS_VIRT_RESET_IOUT_HISTORY:
ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0); if (!ret && data->have_iout_min)
ret = pmbus_write_word_data(client, 0,
ADM1293_IOUT_MIN, 0); break; case PMBUS_VIRT_RESET_VOUT_HISTORY:
ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VOUT, 0); break; case PMBUS_VIRT_RESET_VIN_HISTORY:
ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VIN, 0); break; case PMBUS_VIRT_RESET_PIN_HISTORY:
ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0); if (!ret && data->have_pin_min)
ret = pmbus_write_word_data(client, 0,
ADM1293_PIN_MIN, 0); break; case PMBUS_VIRT_RESET_TEMP_HISTORY:
ret = pmbus_write_word_data(client, 0, ADM1278_PEAK_TEMP, 0); break; case PMBUS_VIRT_POWER_SAMPLES: if (!data->have_power_sampling) return -ENXIO;
word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX);
ret = adm1275_write_samples(data, client, true, ilog2(word)); break; case PMBUS_VIRT_IN_SAMPLES: case PMBUS_VIRT_CURR_SAMPLES:
word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX);
ret = adm1275_write_samples(data, client, false, ilog2(word)); break; default:
ret = -ENODATA; break;
} return ret;
}
staticint adm1275_read_byte_data(struct i2c_client *client, int page, int reg)
{ conststruct pmbus_driver_info *info = pmbus_get_driver_info(client); conststruct adm1275_data *data = to_adm1275_data(info); int mfr_status, ret;
if (page > 0) return -ENXIO;
switch (reg) { case PMBUS_STATUS_IOUT:
ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_IOUT); if (ret < 0) break; if (!data->have_oc_fault && !data->have_uc_fault) break;
mfr_status = pmbus_read_byte_data(client, page,
PMBUS_STATUS_MFR_SPECIFIC); if (mfr_status < 0) return mfr_status; if (mfr_status & ADM1275_MFR_STATUS_IOUT_WARN2) {
ret |= data->have_oc_fault ?
PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT;
} break; case PMBUS_STATUS_VOUT: if (data->have_vout) return -ENODATA;
ret = 0; if (data->have_vaux_status) {
mfr_status = pmbus_read_byte_data(client, 0,
ADM1075_VAUX_STATUS); if (mfr_status < 0) return mfr_status; if (mfr_status & ADM1075_VAUX_OV_WARN)
ret |= PB_VOLTAGE_OV_WARNING; if (mfr_status & ADM1075_VAUX_UV_WARN)
ret |= PB_VOLTAGE_UV_WARNING;
} elseif (data->have_mfr_vaux_status) {
mfr_status = pmbus_read_byte_data(client, page,
PMBUS_STATUS_MFR_SPECIFIC); if (mfr_status < 0) return mfr_status; if (mfr_status & ADM1293_MFR_STATUS_VAUX_OV_WARN)
ret |= PB_VOLTAGE_OV_WARNING; if (mfr_status & ADM1293_MFR_STATUS_VAUX_UV_WARN)
ret |= PB_VOLTAGE_UV_WARNING;
} break; default:
ret = -ENODATA; break;
} return ret;
}
/* Enable VOUT & TEMP1 if not enabled (disabled by default) */ staticint adm1275_enable_vout_temp(struct adm1275_data *data, struct i2c_client *client, int config)
{ int ret;
if ((config & ADM1278_PMON_DEFCONFIG) != ADM1278_PMON_DEFCONFIG) {
config |= ADM1278_PMON_DEFCONFIG;
ret = adm1275_write_pmon_config(data, client, config); if (ret < 0) {
dev_err(&client->dev, "Failed to enable VOUT/TEMP1 monitoring\n"); return ret;
}
} return 0;
}
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("PMBUS");
Messung V0.5
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
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.