Quellcode-Bibliothek max8997-regulator.c
Sprache: C
// SPDX-License-Identifier: GPL-2.0+ // // max8997.c - Regulator driver for the Maxim 8997/8966 // // Copyright (C) 2011 Samsung Electronics // MyungJoo Ham <myungjoo.ham@samsung.com> // // This driver is based on max8998.c
if (lb < 0xf)
val = lb; else { if (ub >= 0xf)
val = 0xf; else return -EINVAL;
}
}
*selector = val;
ret = max8997_update_reg(i2c, reg, val << shift, mask);
return ret;
}
/* * For LDO1 ~ LDO21, BUCK1~5, BUCK7, CHARGER, CHARGER_TOPOFF * BUCK1, 2, and 5 are available if they are not controlled by gpio
*/ staticint max8997_set_voltage_ldobuck(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector)
{ struct max8997_data *max8997 = rdev_get_drvdata(rdev); struct i2c_client *i2c = max8997->iodev->i2c; conststruct voltage_map_desc *desc; int rid = rdev_get_id(rdev); int i, reg, shift, mask, ret;
switch (rid) { case MAX8997_LDO1 ... MAX8997_LDO21: break; case MAX8997_BUCK1 ... MAX8997_BUCK5: break; case MAX8997_BUCK6: return -EINVAL; case MAX8997_BUCK7: break; case MAX8997_CHARGER: break; case MAX8997_CHARGER_TOPOFF: break; default: return -EINVAL;
}
desc = reg_voltage_map[rid];
i = max8997_get_voltage_proper_val(desc, min_uV, max_uV); if (i < 0) return i;
ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); if (ret) return ret;
ret = max8997_update_reg(i2c, reg, i << shift, mask << shift);
*selector = i;
/* Delay is required only if the voltage is increasing */ if (old_selector >= new_selector) return 0;
/* No need to delay if gpio_dvs_mode */ switch (rid) { case MAX8997_BUCK1: if (max8997->buck1_gpiodvs) return 0; break; case MAX8997_BUCK2: if (max8997->buck2_gpiodvs) return 0; break; case MAX8997_BUCK5: if (max8997->buck5_gpiodvs) return 0; break;
}
switch (rid) { case MAX8997_BUCK1: case MAX8997_BUCK2: case MAX8997_BUCK4: case MAX8997_BUCK5: return DIV_ROUND_UP(desc->step * (new_selector - old_selector),
max8997->ramp_delay * 1000);
}
return 0;
}
/* * Assess the damage on the voltage setting of BUCK1,2,5 by the change. * * When GPIO-DVS mode is used for multiple bucks, changing the voltage value * of one of the bucks may affect that of another buck, which is the side * effect of the change (set_voltage). This function examines the GPIO-DVS * configurations and checks whether such side-effect exists.
*/ staticint max8997_assess_side_effect(struct regulator_dev *rdev,
u8 new_val, int *best)
{ struct max8997_data *max8997 = rdev_get_drvdata(rdev); int rid = rdev_get_id(rdev);
u8 *buckx_val[3]; bool buckx_gpiodvs[3]; int side_effect[8]; int min_side_effect = INT_MAX; int i;
*best = -1;
switch (rid) { case MAX8997_BUCK1:
rid = 0; break; case MAX8997_BUCK2:
rid = 1; break; case MAX8997_BUCK5:
rid = 2; break; default: return -EINVAL;
}
if (new_val != (buckx_val[rid])[i]) {
side_effect[i] = -1; continue;
}
side_effect[i] = 0; for (others = 0; others < 3; others++) { int diff;
if (others == rid) continue; if (buckx_gpiodvs[others] == false) continue; /* Not affected */
diff = (buckx_val[others])[i] -
(buckx_val[others])[max8997->buck125_gpioindex]; if (diff > 0)
side_effect[i] += diff; elseif (diff < 0)
side_effect[i] -= diff;
} if (side_effect[i] == 0) {
*best = i; return 0; /* NO SIDE EFFECT! Use This! */
} if (side_effect[i] < min_side_effect) {
min_side_effect = side_effect[i];
*best = i;
}
}
if (*best == -1) return -EINVAL;
return side_effect[*best];
}
/* * For Buck 1 ~ 5 and 7. If it is not controlled by GPIO, this calls * max8997_set_voltage_ldobuck to do the job.
*/ staticint max8997_set_voltage_buck(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector)
{ struct max8997_data *max8997 = rdev_get_drvdata(rdev); int rid = rdev_get_id(rdev); conststruct voltage_map_desc *desc; int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg; bool gpio_dvs_mode = false;
if (rid < MAX8997_BUCK1 || rid > MAX8997_BUCK7) return -EINVAL;
switch (rid) { case MAX8997_BUCK1: if (max8997->buck1_gpiodvs)
gpio_dvs_mode = true; break; case MAX8997_BUCK2: if (max8997->buck2_gpiodvs)
gpio_dvs_mode = true; break; case MAX8997_BUCK5: if (max8997->buck5_gpiodvs)
gpio_dvs_mode = true; break;
}
if (!gpio_dvs_mode) return max8997_set_voltage_ldobuck(rdev, min_uV, max_uV,
selector);
pmic_np = iodev->dev->of_node; if (!pmic_np) {
dev_err(&pdev->dev, "could not find pmic sub-node\n"); return -ENODEV;
}
struct device_node *regulators_np __free(device_node) = of_get_child_by_name(pmic_np, "regulators"); if (!regulators_np) {
dev_err(&pdev->dev, "could not find regulators sub-node\n"); return -EINVAL;
}
/* count the number of regulators to be supported in pmic */
pdata->num_regulators = of_get_child_count(regulators_np);
rdata = devm_kcalloc(&pdev->dev,
pdata->num_regulators, sizeof(*rdata),
GFP_KERNEL); if (!rdata) return -ENOMEM;
pdata->regulators = rdata;
for_each_child_of_node(regulators_np, reg_np) { for (i = 0; i < ARRAY_SIZE(regulators); i++) if (of_node_name_eq(reg_np, regulators[i].name)) break;
if (i == ARRAY_SIZE(regulators)) {
dev_warn(&pdev->dev, "don't know how to configure regulator %pOFn\n",
reg_np); continue;
}
for (i = 0; i < nr_dvs; i++) {
max8997->buck1_vol[i] = ret =
max8997_get_voltage_proper_val(
&buck1245_voltage_map_desc,
pdata->buck1_voltage[i],
pdata->buck1_voltage[i] +
buck1245_voltage_map_desc.step); if (ret < 0) return ret;
max8997->buck2_vol[i] = ret =
max8997_get_voltage_proper_val(
&buck1245_voltage_map_desc,
pdata->buck2_voltage[i],
pdata->buck2_voltage[i] +
buck1245_voltage_map_desc.step); if (ret < 0) return ret;
max8997->buck5_vol[i] = ret =
max8997_get_voltage_proper_val(
&buck1245_voltage_map_desc,
pdata->buck5_voltage[i],
pdata->buck5_voltage[i] +
buck1245_voltage_map_desc.step); if (ret < 0) return ret;
if (max_buck1 < max8997->buck1_vol[i])
max_buck1 = max8997->buck1_vol[i]; if (max_buck2 < max8997->buck2_vol[i])
max_buck2 = max8997->buck2_vol[i]; if (max_buck5 < max8997->buck5_vol[i])
max_buck5 = max8997->buck5_vol[i];
}
/* For the safety, set max voltage before setting up */ for (i = 0; i < 8; i++) {
max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i,
max_buck1, 0x3f);
max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i,
max_buck2, 0x3f);
max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i,
max_buck5, 0x3f);
}
/* Initialize all the DVS related BUCK registers */ for (i = 0; i < nr_dvs; i++) {
max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i,
max8997->buck1_vol[i],
0x3f);
max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i,
max8997->buck2_vol[i],
0x3f);
max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i,
max8997->buck5_vol[i],
0x3f);
}
/* * If buck 1, 2, and 5 do not care DVS GPIO settings, ignore them. * If at least one of them cares, set gpios.
*/ if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs ||
pdata->buck5_gpiodvs) { constchar *gpio_names[3] = {"MAX8997 SET1", "MAX8997 SET2", "MAX8997 SET3"};
MODULE_DESCRIPTION("MAXIM 8997/8966 Regulator Driver");
MODULE_AUTHOR("MyungJoo Ham ");
MODULE_LICENSE("GPL");
Messung V0.5
¤ 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.0.9Bemerkung:
¤
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.