static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client, int page, constchar *buf, size_t count)
{ int rc, op_val; bool result;
rc = kstrtobool(buf, &result); if (rc) return rc;
op_val = result ? ISL68137_VOUT_AVS : 0;
/* * Writes to VOUT setpoint over AVSBus will persist after the VRM is * switched to PMBus control. Switching back to AVSBus control * restores this persisted setpoint rather than re-initializing to * PMBus VOUT_COMMAND. Writing VOUT_COMMAND first over PMBus before * enabling AVS control is the workaround.
*/ if (op_val == ISL68137_VOUT_AVS) {
rc = pmbus_read_word_data(client, page, 0xff,
PMBUS_VOUT_COMMAND); if (rc < 0) return rc;
staticint raa_dmpvr2_read_word_data(struct i2c_client *client, int page, int phase, int reg)
{ conststruct pmbus_driver_info *info = pmbus_get_driver_info(client); conststruct isl68137_data *data = to_isl68137_data(info); int ret;
u64 temp;
switch (reg) { case PMBUS_VIRT_READ_VMON:
ret = pmbus_read_word_data(client, page, phase,
RAA_DMPVR2_READ_VMON); break; case PMBUS_READ_POUT: case PMBUS_READ_VOUT: /* * In cases where a voltage divider is attached to the target * rail between Vout and the Vsense pin, both Vout and Pout * should be scaled by the voltage divider scaling factor. * I.e. Vout = Vsense * Rtotal / Rout
*/
ret = pmbus_read_word_data(client, page, phase, reg); if (ret > 0) {
temp = DIV_U64_ROUND_CLOSEST((u64)ret *
data->channel[page].vout_voltage_divider[1],
data->channel[page].vout_voltage_divider[0]);
ret = clamp_val(temp, 0, 0xffff);
} break; default:
ret = -ENODATA; break;
}
return ret;
}
staticint raa_dmpvr2_write_word_data(struct i2c_client *client, int page, int reg, u16 word)
{ conststruct pmbus_driver_info *info = pmbus_get_driver_info(client); conststruct isl68137_data *data = to_isl68137_data(info); int ret;
u64 temp;
switch (reg) { case PMBUS_VOUT_MAX: case PMBUS_VOUT_MARGIN_HIGH: case PMBUS_VOUT_MARGIN_LOW: case PMBUS_VOUT_OV_FAULT_LIMIT: case PMBUS_VOUT_UV_FAULT_LIMIT: case PMBUS_VOUT_COMMAND: /* * In cases where a voltage divider is attached to the target * rail between Vout and the Vsense pin, Vout related PMBus * commands should be scaled based on the expected voltage * at the Vsense pin. * I.e. Vsense = Vout * Rout / Rtotal
*/
temp = DIV_U64_ROUND_CLOSEST((u64)word *
data->channel[page].vout_voltage_divider[0],
data->channel[page].vout_voltage_divider[1]);
ret = clamp_val(temp, 0, 0xffff); break; default:
ret = -ENODATA; break;
} return ret;
}
err = of_property_read_u32(child, "reg", &channel); if (err) {
dev_err(dev, "missing reg property of %pOFn\n", child); return err;
} if (channel >= data->info.pages) {
dev_err(dev, "invalid reg %d of %pOFn\n", channel, child); return -EINVAL;
}
err = of_property_read_u32_array(child, "vout-voltage-divider",
data->channel[channel].vout_voltage_divider,
ARRAY_SIZE(data->channel[channel].vout_voltage_divider)); if (err && err != -EINVAL) {
dev_err(dev, "malformed vout-voltage-divider value for channel %d\n",
channel); return err;
}
rout = data->channel[channel].vout_voltage_divider[0];
rtotal = data->channel[channel].vout_voltage_divider[1]; if (rout == 0) {
dev_err(dev, "Voltage divider output resistance must be greater than 0\n"); return -EINVAL;
} if (rtotal < rout) {
dev_err(dev, "Voltage divider total resistance is less than output resistance\n"); return -EINVAL;
}
for_each_child_of_node_scoped(np, child) { if (strcmp(child->name, "channel")) continue;
err = isl68137_probe_child_from_dt(dev, child, data); if (err) return err;
}
return 0;
}
staticint isl68137_probe(struct i2c_client *client)
{ struct device *dev = &client->dev; struct pmbus_driver_info *info; struct isl68137_data *data; int i, err;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM;
/* * Initialize all voltage dividers to Rout=1 and Rtotal=1 to simplify * logic in PMBus word read/write functions
*/ for (i = 0; i < MAX_CHANNELS; i++)
memset(data->channel[i].vout_voltage_divider,
1, sizeof(data->channel[i].vout_voltage_divider));
memcpy(&data->info, &raa_dmpvr_info, sizeof(data->info));
info = &data->info;
/* This is the driver that will be inserted */ staticstruct i2c_driver isl68137_driver = {
.driver = {
.name = "isl68137",
.of_match_table = isl68137_of_match,
},
.probe = isl68137_probe,
.id_table = raa_dmpvr_id,
};
module_i2c_driver(isl68137_driver);
MODULE_AUTHOR("Maxim Sloyko ");
MODULE_DESCRIPTION("PMBus driver for Renesas digital multiphase voltage regulators");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("PMBUS");
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.