/** * rpm_vreg_set_frequency - sets the frequency of a switching regulator * @vreg: ID for regulator * @freq: enum corresponding to desired frequency * * Returns 0 on success or errno. */ int rpm_vreg_set_frequency(int vreg_id, enum rpm_vreg_freq freq) { unsigned int mask[2] = {0}, val[2] = {0}; struct vreg *vreg; int rc; /* * HACK: make this function a no-op for 8064 so that it can be called by * consumers on 8064 before RPM capabilities are present. */ if (cpu_is_apq8064()) return 0; if (!config) { pr_err("rpm-regulator driver has not probed yet.\n"); return -ENODEV; } if (vreg_id < config->vreg_id_min || vreg_id > config->vreg_id_max) { pr_err("invalid regulator id=%d\n", vreg_id); return -EINVAL; } vreg = &config->vregs[vreg_id]; if (freq < 0 || freq > RPM_VREG_FREQ_1p20) { vreg_err(vreg, "invalid frequency=%d\n", freq); return -EINVAL; } if (!vreg->pdata.sleep_selectable) { vreg_err(vreg, "regulator is not marked sleep selectable\n"); return -EINVAL; } if (!vreg->part->freq.mask) { vreg_err(vreg, "frequency not supported\n"); return -EINVAL; } val[vreg->part->freq.word] = freq << vreg->part->freq.shift; mask[vreg->part->freq.word] = vreg->part->freq.mask; rc = vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1, mask[0], val[0], mask[1], val[1], vreg->part->request_len, 0); if (rc) vreg_err(vreg, "vreg_set failed, rc=%d\n", rc); printk("rpm-regulator driver has probed .\n"); return rc; }
static int vreg_set(struct vreg *vreg, unsigned mask0, unsigned val0, unsigned mask1, unsigned val1, unsigned cnt) { unsigned prev0 = 0, prev1 = 0; int rc; /* * Bypass the normal route for regulators that can be called to change * just the active set values. */ if (vreg->pdata.sleep_selectable) return vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1, mask0, val0, mask1, val1, cnt, 1); prev0 = vreg->req[0].value; vreg->req[0].value &= ~mask0; vreg->req[0].value |= val0 & mask0; prev1 = vreg->req[1].value; vreg->req[1].value &= ~mask1; vreg->req[1].value |= val1 & mask1; /* Ignore duplicate requests */ if (vreg->req[0].value == vreg->prev_active_req[0].value && vreg->req[1].value == vreg->prev_active_req[1].value) { if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_DUPLICATE) rpm_regulator_duplicate(vreg, MSM_RPM_CTX_SET_0, cnt); return 0; } rc = msm_rpm_set(MSM_RPM_CTX_SET_0, vreg->req, cnt); if (rc) { vreg->req[0].value = prev0; vreg->req[1].value = prev1; vreg_err(vreg, "msm_rpm_set failed, set=active, id=%d, rc=%d\n", vreg->req[0].id, rc); } else { if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_REQUEST) rpm_regulator_req(vreg, MSM_RPM_CTX_SET_0); vreg->prev_active_req[0].value = vreg->req[0].value; vreg->prev_active_req[1].value = vreg->req[1].value; } return rc; }
/** * rpm_vreg_set_voltage - vote for a min_uV value of specified regualtor * @vreg: ID for regulator * @voter: ID for the voter * @min_uV: minimum acceptable voltage (in uV) that is voted for * @max_uV: maximum acceptable voltage (in uV) that is voted for * @sleep_also: 0 for active set only, non-0 for active set and sleep set * * Returns 0 on success or errno. * * This function is used to vote for the voltage of a regulator without * using the regulator framework. It is needed by consumers which hold spin * locks or have interrupts disabled because the regulator framework can sleep. * It is also needed by consumers which wish to only vote for active set * regulator voltage. * * If sleep_also == 0, then a sleep-set value of 0V will be voted for. * * This function may only be called for regulators which have the sleep flag * specified in their private data. * * Consumers can vote to disable a regulator with this function by passing * min_uV = 0 and max_uV = 0. */ int rpm_vreg_set_voltage(int vreg_id, enum rpm_vreg_voter voter, int min_uV, int max_uV, int sleep_also) { unsigned int mask[2] = {0}, val[2] = {0}; struct vreg_range *range; struct vreg *vreg; int uV = min_uV; int lim_min_uV, lim_max_uV, i, rc; /* * HACK: make this function a no-op for 8064 so that it can be called by * consumers on 8064 before RPM capabilities are present. (needed for * acpuclock driver) */ if (cpu_is_apq8064()) return 0; if (!config) { pr_err("rpm-regulator driver has not probed yet.\n"); return -ENODEV; } if (vreg_id < config->vreg_id_min || vreg_id > config->vreg_id_max) { pr_err("invalid regulator id=%d\n", vreg_id); return -EINVAL; } vreg = &config->vregs[vreg_id]; range = &vreg->set_points->range[0]; if (!vreg->pdata.sleep_selectable) { vreg_err(vreg, "regulator is not marked sleep selectable\n"); return -EINVAL; } /* Allow min_uV == max_uV == 0 to represent a disable request. */ if (min_uV != 0 || max_uV != 0) { /* * Check if request voltage is outside of allowed range. The * regulator core has already checked that constraint range * is inside of the physically allowed range. */ lim_min_uV = vreg->pdata.init_data.constraints.min_uV; lim_max_uV = vreg->pdata.init_data.constraints.max_uV; if (uV < lim_min_uV && max_uV >= lim_min_uV) uV = lim_min_uV; if (uV < lim_min_uV || uV > lim_max_uV) { vreg_err(vreg, "request v=[%d, %d] is outside allowed " "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--) { if (uV > vreg->set_points->range[i - 1].max_uV) { range = &vreg->set_points->range[i]; break; } } /* * Force uV to be an allowed set point and apply a ceiling * function to non-set point values. */ uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV; uV = uV * range->step_uV + range->min_uV; if (uV > max_uV) { vreg_err(vreg, "request v=[%d, %d] cannot be met by any set point; " "next set point: %d\n", min_uV, max_uV, uV); return -EINVAL; } } if (vreg->part->uV.mask) { val[vreg->part->uV.word] = uV << vreg->part->uV.shift; mask[vreg->part->uV.word] = vreg->part->uV.mask; } else { val[vreg->part->mV.word] = MICRO_TO_MILLI(uV) << vreg->part->mV.shift; mask[vreg->part->mV.word] = vreg->part->mV.mask; } rc = vreg_set_noirq(vreg, voter, sleep_also, mask[0], val[0], mask[1], val[1], vreg->part->request_len, 1); if (rc) vreg_err(vreg, "vreg_set_noirq failed, rc=%d\n", rc); return rc; }