/* pick up Efuse based voltages */
res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 0); if (!res) {
dev_err(dev, "Unable to get IO resource\n");
ret = -ENODEV; goto out_map;
}
base = ioremap(res->start, resource_size(res)); if (!base) {
dev_err(dev, "Unable to map Efuse registers\n");
ret = -ENOMEM; goto out_map;
}
/* Fetch efuse-settings. */
prop = of_find_property(dev->of_node, "ti,efuse-settings", NULL); if (!prop) {
dev_err(dev, "No 'ti,efuse-settings' property found\n");
ret = -EINVAL; goto out;
}
proplen = prop->length / sizeof(int);
data->num_vdd_table = proplen / 2; /* Verify for corrupted OPP entries in dt */ if (data->num_vdd_table * 2 * sizeof(int) != prop->length) {
dev_err(dev, "Invalid 'ti,efuse-settings'\n");
ret = -EINVAL; goto out;
}
ret = of_property_read_u32(dev->of_node, "ti,absolute-max-voltage-uv",
&data->vdd_absolute_max_voltage_uv); if (ret) {
dev_err(dev, "ti,absolute-max-voltage-uv is missing\n");
ret = -EINVAL; goto out;
}
table = kcalloc(data->num_vdd_table, sizeof(*data->vdd_table),
GFP_KERNEL); if (!table) {
ret = -ENOMEM; goto out;
}
data->vdd_table = table;
val = prop->value; for (i = 0; i < data->num_vdd_table; i++, table++) {
u32 efuse_offset;
u32 tmp;
table = data->vdd_table; if (!table) return -EINVAL;
/* Find a exact match - this list is usually very small */ for (i = 0; i < data->num_vdd_table; i++, table++) if (table->reference_uv == reference_uv) return table->optimized_uv;
/* IF things are screwed up, we'd make a mess on console.. ratelimit */
dev_err_ratelimited(dev, "%s: Failed optimized voltage match for %d\n",
__func__, reference_uv); return reference_uv;
}
staticint _opp_set_voltage(struct device *dev, struct dev_pm_opp_supply *supply, int new_target_uv, struct regulator *reg, char *reg_name)
{ int ret; unsignedlong vdd_uv, uv_max;
if (new_target_uv)
vdd_uv = new_target_uv; else
vdd_uv = supply->u_volt;
if (new_supply_vdd->u_volt_min < vdd_uv)
new_supply_vdd->u_volt_min = vdd_uv;
/* Scaling up? Scale voltage before frequency */ if (freq > old_freq) {
ret = _opp_set_voltage(dev, new_supply_vdd, vdd_uv, vdd_reg, "vdd"); if (ret) goto restore_voltage;
ret = _opp_set_voltage(dev, new_supply_vbb, 0, vbb_reg, "vbb"); if (ret) goto restore_voltage;
} else {
ret = _opp_set_voltage(dev, new_supply_vbb, 0, vbb_reg, "vbb"); if (ret) goto restore_voltage;
ret = _opp_set_voltage(dev, new_supply_vdd, vdd_uv, vdd_reg, "vdd"); if (ret) goto restore_voltage;
}
return0;
restore_voltage: /* Fetch old supplies information only if required */
ret = dev_pm_opp_get_supplies(old_opp, opp_data.old_supplies);
WARN_ON(ret);
/* This shouldn't harm even if the voltages weren't updated earlier */ if (old_supply_vdd->u_volt) {
ret = _opp_set_voltage(dev, old_supply_vbb, 0, vbb_reg, "vbb"); if (ret) return ret;
ret = _opp_set_voltage(dev, old_supply_vdd, 0, vdd_reg, "vdd"); if (ret) return ret;
}
of_data = device_get_match_data(dev); if (!of_data) { /* Again, unlikely.. but mistakes do happen */
dev_err(dev, "%s: Bad data in match\n", __func__); return -EINVAL;
}
dev_set_drvdata(dev, (void *)of_data);
/* If we need optimized voltage */ if (of_data->flags & OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE) {
ret = _store_optimized_voltages(dev, &opp_data); if (ret) return ret;
}
ret = dev_pm_opp_set_config_regulators(cpu_dev, ti_opp_config_regulators); if (ret < 0) {
_free_optimized_voltages(dev, &opp_data); return ret;
}
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.