/* Pin control high power mode input pins. */ #define SPMI_REGULATOR_PIN_CTRL_HPM_NONE 0x00 #define SPMI_REGULATOR_PIN_CTRL_HPM_EN0 0x01 #define SPMI_REGULATOR_PIN_CTRL_HPM_EN1 0x02 #define SPMI_REGULATOR_PIN_CTRL_HPM_EN2 0x04 #define SPMI_REGULATOR_PIN_CTRL_HPM_EN3 0x08 #define SPMI_REGULATOR_PIN_CTRL_HPM_SLEEP_B 0x10 #define SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT 0x20
/* * Used with enable parameters to specify that hardware default register values * should be left unaltered.
*/ #define SPMI_REGULATOR_USE_HW_DEFAULT 2
/* Soft start strength of a voltage switch type regulator */ enum spmi_vs_soft_start_str {
SPMI_VS_SOFT_START_STR_0P05_UA = 0,
SPMI_VS_SOFT_START_STR_0P25_UA,
SPMI_VS_SOFT_START_STR_0P55_UA,
SPMI_VS_SOFT_START_STR_0P75_UA,
SPMI_VS_SOFT_START_STR_HW_DEFAULT,
};
/** * struct spmi_regulator_init_data - spmi-regulator initialization data * @pin_ctrl_enable: Bit mask specifying which hardware pins should be * used to enable the regulator, if any * Value should be an ORing of * SPMI_REGULATOR_PIN_CTRL_ENABLE_* constants. If * the bit specified by * SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT is * set, then pin control enable hardware registers * will not be modified. * @pin_ctrl_hpm: Bit mask specifying which hardware pins should be * used to force the regulator into high power * mode, if any * Value should be an ORing of * SPMI_REGULATOR_PIN_CTRL_HPM_* constants. If * the bit specified by * SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT is * set, then pin control mode hardware registers * will not be modified. * @vs_soft_start_strength: This parameter sets the soft start strength for * voltage switch type regulators. Its value * should be one of SPMI_VS_SOFT_START_STR_*. If * its value is SPMI_VS_SOFT_START_STR_HW_DEFAULT, * then the soft start strength will be left at its * default hardware value.
*/ struct spmi_regulator_init_data { unsigned pin_ctrl_enable; unsigned pin_ctrl_hpm; enum spmi_vs_soft_start_str vs_soft_start_strength;
};
/* * Second common register layout used by newer devices starting with ftsmps426 * Note that some of the registers from the first common layout remain * unchanged and their definition is not duplicated.
*/ enum spmi_ftsmps426_regulator_registers {
SPMI_FTSMPS426_REG_VOLTAGE_LSB = 0x40,
SPMI_FTSMPS426_REG_VOLTAGE_MSB = 0x41,
SPMI_FTSMPS426_REG_VOLTAGE_ULS_LSB = 0x68,
SPMI_FTSMPS426_REG_VOLTAGE_ULS_MSB = 0x69,
};
/* * Third common register layout
*/ enum spmi_hfsmps_regulator_registers {
SPMI_HFSMPS_REG_STEP_CTRL = 0x3c,
SPMI_HFSMPS_REG_PULL_DOWN = 0xa0,
};
/* Used for indexing into ctrl_reg. These are offsets from 0x40 */ enum spmi_common_control_register_index {
SPMI_COMMON_IDX_VOLTAGE_RANGE = 0,
SPMI_COMMON_IDX_VOLTAGE_SET = 1,
SPMI_COMMON_IDX_MODE = 5,
SPMI_COMMON_IDX_ENABLE = 6,
};
/* Clock rate in kHz of the FTSMPS regulator reference clock. */ #define SPMI_FTSMPS_CLOCK_RATE 19200
/* Minimum voltage stepper delay for each step. */ #define SPMI_FTSMPS_STEP_DELAY 8 #define SPMI_DEFAULT_STEP_DELAY 20
/* * The ratio SPMI_FTSMPS_STEP_MARGIN_NUM/SPMI_FTSMPS_STEP_MARGIN_DEN is used to * adjust the step rate in order to account for oscillator variance.
*/ #define SPMI_FTSMPS_STEP_MARGIN_NUM 4 #define SPMI_FTSMPS_STEP_MARGIN_DEN 5
/* slew_rate has units of uV/us. */ #define SPMI_HFSMPS_SLEW_RATE_38p4 38400
/* Clock rate in kHz of the FTSMPS426 regulator reference clock. */ #define SPMI_FTSMPS426_CLOCK_RATE 4800
#define SPMI_HFS430_CLOCK_RATE 1600
/* Minimum voltage stepper delay for each step. */ #define SPMI_FTSMPS426_STEP_DELAY 2
/* * The ratio SPMI_FTSMPS426_STEP_MARGIN_NUM/SPMI_FTSMPS426_STEP_MARGIN_DEN is * used to adjust the step rate in order to account for oscillator variance.
*/ #define SPMI_FTSMPS426_STEP_MARGIN_NUM 10 #define SPMI_FTSMPS426_STEP_MARGIN_DEN 11
/* VSET value to decide the range of ULT SMPS */ #define ULT_SMPS_RANGE_SPLIT 0x60
/** * struct spmi_voltage_range - regulator set point voltage mapping description * @min_uV: Minimum programmable output voltage resulting from * set point register value 0x00 * @max_uV: Maximum programmable output voltage * @step_uV: Output voltage increase resulting from the set point * register value increasing by 1 * @set_point_min_uV: Minimum allowed voltage * @set_point_max_uV: Maximum allowed voltage. This may be tweaked in order * to pick which range should be used in the case of * overlapping set points. * @n_voltages: Number of preferred voltage set points present in this * range * @range_sel: Voltage range register value corresponding to this range * * The following relationships must be true for the values used in this struct: * (max_uV - min_uV) % step_uV == 0 * (set_point_min_uV - min_uV) % step_uV == 0* * (set_point_max_uV - min_uV) % step_uV == 0* * n_voltages = (set_point_max_uV - set_point_min_uV) / step_uV + 1 * * *Note, set_point_min_uV == set_point_max_uV == 0 is allowed in order to * specify that the voltage range has meaning, but is not preferred.
*/ struct spmi_voltage_range { int min_uV; int max_uV; int step_uV; int set_point_min_uV; int set_point_max_uV; unsigned n_voltages;
u8 range_sel;
};
/* * The ranges specified in the spmi_voltage_set_points struct must be listed * so that range[i].set_point_max_uV < range[i+1].set_point_min_uV.
*/ struct spmi_voltage_set_points { conststruct spmi_voltage_range *range; int count; unsigned n_voltages;
};
struct spmi_regulator { struct regulator_desc desc; struct device *dev; struct delayed_work ocp_work; struct regmap *regmap; struct spmi_voltage_set_points *set_points; enum spmi_regulator_logical_type logical_type; int ocp_irq; int ocp_count; int ocp_max_retries; int ocp_retry_delay_ms; int hpm_min_load; int slew_rate;
ktime_t vs_enable_time;
u16 base; struct list_head node;
};
/* * These tables contain the physically available PMIC regulator voltage setpoint * ranges. Where two ranges overlap in hardware, one of the ranges is trimmed * to ensure that the setpoints available to software are monotonically * increasing and unique. The set_voltage callback functions expect these * properties to hold.
*/ staticconststruct spmi_voltage_range pldo_ranges[] = {
SPMI_VOLTAGE_RANGE(2, 750000, 750000, 1537500, 1537500, 12500),
SPMI_VOLTAGE_RANGE(3, 1500000, 1550000, 3075000, 3075000, 25000),
SPMI_VOLTAGE_RANGE(4, 1750000, 3100000, 4900000, 4900000, 50000),
};
staticint spmi_regulator_select_voltage(struct spmi_regulator *vreg, int min_uV, int max_uV)
{ conststruct spmi_voltage_range *range; int uV = min_uV; int lim_min_uV, lim_max_uV, i, range_id, range_max_uV; int selector, voltage_sel;
/* Check if request voltage is outside of physically settable range. */
lim_min_uV = vreg->set_points->range[0].set_point_min_uV;
lim_max_uV =
vreg->set_points->range[vreg->set_points->count - 1].set_point_max_uV;
if (uV < lim_min_uV || uV > lim_max_uV) {
dev_err(vreg->dev, "request v=[%d, %d] is outside possible v=[%d, %d]\n",
min_uV, max_uV, lim_min_uV, lim_max_uV); return -EINVAL;
}
/* Find the range which uV is inside of. */ for (i = vreg->set_points->count - 1; i > 0; i--) {
range_max_uV = vreg->set_points->range[i - 1].set_point_max_uV; if (uV > range_max_uV && range_max_uV > 0) break;
}
range_id = i;
range = &vreg->set_points->range[range_id];
/* * Force uV to be an allowed set point by applying a ceiling function to * the uV value.
*/
voltage_sel = DIV_ROUND_UP(uV - range->min_uV, range->step_uV);
uV = voltage_sel * range->step_uV + range->min_uV;
if (uV > max_uV) {
dev_err(vreg->dev, "request v=[%d, %d] cannot be met by any set point; " "next set point: %d\n",
min_uV, max_uV, uV); return -EINVAL;
}
selector = 0; for (i = 0; i < range_id; i++)
selector += vreg->set_points->range[i].n_voltages;
selector += (uV - range->set_point_min_uV) / range->step_uV;
range = vreg->set_points->range;
end = range + vreg->set_points->count;
for (; range < end; range++) { if (selector < range->n_voltages) { /* * hardware selectors between set point min and real * min are invalid so we ignore them
*/
offset = range->set_point_min_uV - range->min_uV;
offset /= range->step_uV;
*voltage_sel = selector + offset;
*range_sel = range->range_sel; return 0;
}
for (; r < end; r++) { if (r == range && range->n_voltages) { /* * hardware selectors between set point min and real * min and between set point max and real max are * invalid so we return an error if they're * programmed into the hardware
*/
offset = range->set_point_min_uV - range->min_uV;
offset /= range->step_uV; if (hw_sel < offset) return -EINVAL;
for (; range < end; range++) if (range->range_sel == range_sel) return range;
return NULL;
}
staticint spmi_regulator_select_voltage_same_range(struct spmi_regulator *vreg, int min_uV, int max_uV)
{ conststruct spmi_voltage_range *range; int uV = min_uV; int i, selector;
range = spmi_regulator_find_range(vreg); if (!range) goto different_range;
if (uV < range->min_uV || uV > range->max_uV) { /* Current range doesn't support the requested voltage. */ goto different_range;
}
/* * Force uV to be an allowed set point by applying a ceiling function to * the uV value.
*/
uV = DIV_ROUND_UP(uV - range->min_uV, range->step_uV);
uV = uV * range->step_uV + range->min_uV;
if (uV > max_uV) { /* * No set point in the current voltage range is within the * requested min_uV to max_uV range.
*/ goto different_range;
}
selector = 0; for (i = 0; i < vreg->set_points->count; i++) { if (uV >= vreg->set_points->range[i].set_point_min_uV
&& uV <= vreg->set_points->range[i].set_point_max_uV) {
selector +=
(uV - vreg->set_points->range[i].set_point_min_uV)
/ vreg->set_points->range[i].step_uV; break;
}
staticint spmi_regulator_common_map_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
{ struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
/* * Favor staying in the current voltage range if possible. This avoids * voltage spikes that occur when changing the voltage range.
*/ return spmi_regulator_select_voltage_same_range(vreg, min_uV, max_uV);
}
/* * Certain types of regulators do not have a range select register so * only voltage set register needs to be written.
*/ return spmi_vreg_write(vreg, SPMI_COMMON_REG_VOLTAGE_SET, &sel, 1);
}
ret = spmi_sw_selector_to_hw(vreg, selector, &range_sel, &voltage_sel); if (ret) return ret;
/* * Calculate VSET based on range * In case of range 0: voltage_sel is a 7 bit value, can be written * witout any modification. * In case of range 1: voltage_sel is a 5 bit value, bits[7-5] set to * [011].
*/ if (range_sel == 1)
voltage_sel |= ULT_SMPS_RANGE_SPLIT;
switch (mode) { case REGULATOR_MODE_NORMAL:
val = SPMI_COMMON_MODE_HPM_MASK; break; case REGULATOR_MODE_FAST:
val = SPMI_COMMON_MODE_AUTO_MASK; break; default:
val = 0; break;
}
switch (mode) { case REGULATOR_MODE_NORMAL:
val = SPMI_FTSMPS426_MODE_HPM_MASK; break; case REGULATOR_MODE_FAST:
val = SPMI_FTSMPS426_MODE_AUTO_MASK; break; case REGULATOR_MODE_IDLE:
val = SPMI_FTSMPS426_MODE_LPM_MASK; break; default: return -EINVAL;
}
/* * Reset the OCP count if there is a large delay between switch enable * and when OCP triggers. This is indicative of a hotplug event as * opposed to a fault.
*/ if (ocp_trigger_delay_us > SPMI_VS_OCP_FAULT_DELAY_US)
vreg->ocp_count = 0;
/* Wait for switch output to settle back to 0 V after OCP triggered. */
udelay(SPMI_VS_OCP_FALL_DELAY_US);
vreg->ocp_count++;
if (vreg->ocp_count == 1) { /* Immediately clear the over current condition. */
spmi_regulator_vs_clear_ocp(vreg);
} elseif (vreg->ocp_count <= vreg->ocp_max_retries) { /* Schedule the over current clear task to run later. */
schedule_delayed_work(&vreg->ocp_work,
msecs_to_jiffies(vreg->ocp_retry_delay_ms) + 1);
} else {
dev_err(vreg->dev, "OCP triggered %d times; no further retries\n",
vreg->ocp_count);
}
/* If AVS is enabled, switch it off during the voltage change */
avs_enabled = SAW3_AVS_CTL_EN_MASK & avs_ctl; if (avs_enabled) {
avs_ctl &= ~SAW3_AVS_CTL_TGGL_MASK;
regmap_write(saw_regmap, SAW3_AVS_CTL, avs_ctl);
}
if (mapping->set_points) { if (!mapping->set_points->n_voltages)
spmi_calculate_num_voltages(mapping->set_points);
vreg->desc.n_voltages = mapping->set_points->n_voltages;
}
return 0;
}
staticint spmi_regulator_init_slew_rate(struct spmi_regulator *vreg)
{ int ret;
u8 reg = 0; int step, delay, slew_rate, step_delay; conststruct spmi_voltage_range *range;
ret = spmi_vreg_read(vreg, SPMI_COMMON_REG_STEP_CTRL, ®, 1); if (ret) {
dev_err(vreg->dev, "spmi read failed, ret=%d\n", ret); return ret;
}
range = spmi_regulator_find_range(vreg); if (!range) return -EINVAL;
ret = spmi_vreg_read(vreg, SPMI_COMMON_REG_VOLTAGE_RANGE, ctrl_reg, 8); if (ret) return ret;
/* Set up enable pin control. */ if (!(data->pin_ctrl_enable & SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT)) { switch (type) { case SPMI_REGULATOR_LOGICAL_TYPE_SMPS: case SPMI_REGULATOR_LOGICAL_TYPE_LDO: case SPMI_REGULATOR_LOGICAL_TYPE_VS:
ctrl_reg[SPMI_COMMON_IDX_ENABLE] &=
~SPMI_COMMON_ENABLE_FOLLOW_ALL_MASK;
ctrl_reg[SPMI_COMMON_IDX_ENABLE] |=
data->pin_ctrl_enable & SPMI_COMMON_ENABLE_FOLLOW_ALL_MASK; break; default: break;
}
}
/* Set up mode pin control. */ if (!(data->pin_ctrl_hpm & SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT)) { switch (type) { case SPMI_REGULATOR_LOGICAL_TYPE_SMPS: case SPMI_REGULATOR_LOGICAL_TYPE_LDO:
ctrl_reg[SPMI_COMMON_IDX_MODE] &=
~SPMI_COMMON_MODE_FOLLOW_ALL_MASK;
ctrl_reg[SPMI_COMMON_IDX_MODE] |=
data->pin_ctrl_hpm & SPMI_COMMON_MODE_FOLLOW_ALL_MASK; break; case SPMI_REGULATOR_LOGICAL_TYPE_VS: case SPMI_REGULATOR_LOGICAL_TYPE_ULT_LO_SMPS: case SPMI_REGULATOR_LOGICAL_TYPE_ULT_HO_SMPS: case SPMI_REGULATOR_LOGICAL_TYPE_ULT_LDO:
ctrl_reg[SPMI_COMMON_IDX_MODE] &=
~SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK;
ctrl_reg[SPMI_COMMON_IDX_MODE] |=
data->pin_ctrl_hpm & SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK; break; default: break;
}
}
/* Write back any control register values that were modified. */
ret = spmi_vreg_write(vreg, SPMI_COMMON_REG_VOLTAGE_RANGE, ctrl_reg, 8); if (ret) return ret;
/* Set soft start strength and over current protection for VS. */ if (type == SPMI_REGULATOR_LOGICAL_TYPE_VS) { if (data->vs_soft_start_strength
!= SPMI_VS_SOFT_START_STR_HW_DEFAULT) {
reg = data->vs_soft_start_strength
& SPMI_VS_SOFT_START_SEL_MASK;
mask = SPMI_VS_SOFT_START_SEL_MASK; return spmi_vreg_update_bits(vreg,
SPMI_VS_REG_SOFT_START,
reg, mask);
}
}
return 0;
}
staticvoid spmi_regulator_get_dt_config(struct spmi_regulator *vreg, struct device_node *node, struct spmi_regulator_init_data *data)
{ /* * Initialize configuration parameters to use hardware default in case * no value is specified via device tree.
*/
data->pin_ctrl_enable = SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT;
data->pin_ctrl_hpm = SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT;
data->vs_soft_start_strength = SPMI_VS_SOFT_START_STR_HW_DEFAULT;
/* These bindings are optional, so it is okay if they aren't found. */
of_property_read_u32(node, "qcom,ocp-max-retries",
&vreg->ocp_max_retries);
of_property_read_u32(node, "qcom,ocp-retry-delay",
&vreg->ocp_retry_delay_ms);
of_property_read_u32(node, "qcom,pin-ctrl-enable",
&data->pin_ctrl_enable);
of_property_read_u32(node, "qcom,pin-ctrl-hpm", &data->pin_ctrl_hpm);
of_property_read_u32(node, "qcom,vs-soft-start-strength",
&data->vs_soft_start_strength);
}
staticunsignedint spmi_regulator_of_map_mode(unsignedint mode)
{ if (mode == 1) return REGULATOR_MODE_NORMAL; if (mode == 2) return REGULATOR_MODE_FAST;
if (!vreg->ocp_max_retries)
vreg->ocp_max_retries = SPMI_VS_OCP_DEFAULT_MAX_RETRIES; if (!vreg->ocp_retry_delay_ms)
vreg->ocp_retry_delay_ms = SPMI_VS_OCP_DEFAULT_RETRY_DELAY_MS;
ret = spmi_regulator_init_registers(vreg, &data); if (ret) {
dev_err(dev, "common initialization failed, ret=%d\n", ret); return ret;
}
switch (vreg->logical_type) { case SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS: case SPMI_REGULATOR_LOGICAL_TYPE_ULT_LO_SMPS: case SPMI_REGULATOR_LOGICAL_TYPE_ULT_HO_SMPS: case SPMI_REGULATOR_LOGICAL_TYPE_SMPS:
ret = spmi_regulator_init_slew_rate(vreg); if (ret) return ret; break; case SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS426:
ret = spmi_regulator_init_slew_rate_ftsmps426(vreg,
SPMI_FTSMPS426_CLOCK_RATE); if (ret) return ret; break; case SPMI_REGULATOR_LOGICAL_TYPE_HFS430:
ret = spmi_regulator_init_slew_rate_ftsmps426(vreg,
SPMI_HFS430_CLOCK_RATE); if (ret) return ret; break; case SPMI_REGULATOR_LOGICAL_TYPE_HFSMPS: case SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS3:
ret = spmi_regulator_init_slew_rate_hfsmps(vreg); if (ret) return ret; break; default: break;
}
if (vreg->logical_type != SPMI_REGULATOR_LOGICAL_TYPE_VS)
vreg->ocp_irq = 0;
if (vreg->ocp_irq) {
ret = devm_request_irq(dev, vreg->ocp_irq,
spmi_regulator_vs_ocp_isr, IRQF_TRIGGER_RISING, "ocp",
vreg); if (ret < 0) {
dev_err(dev, "failed to request irq %d, ret=%d\n",
vreg->ocp_irq, ret); return ret;
}
ret = devm_delayed_work_autocancel(dev, &vreg->ocp_work,
spmi_regulator_vs_ocp_work); if (ret) 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.