/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #define pr_fmt(fmt) "%s: " fmt, __func__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Debug Definitions */ enum { RPM_VREG_DEBUG_REQUEST = BIT(0), RPM_VREG_DEBUG_FULL_REQUEST = BIT(1), RPM_VREG_DEBUG_DUPLICATE = BIT(2), }; static int rpm_vreg_debug_mask; module_param_named( debug_mask, rpm_vreg_debug_mask, int, S_IRUSR | S_IWUSR ); #define vreg_err(req, fmt, ...) \ pr_err("%s: " fmt, req->rdesc.name, ##__VA_ARGS__) /* RPM regulator request types */ enum rpm_regulator_type { RPM_REGULATOR_TYPE_LDO, RPM_REGULATOR_TYPE_SMPS, RPM_REGULATOR_TYPE_VS, RPM_REGULATOR_TYPE_NCP, RPM_REGULATOR_TYPE_BOB, RPM_REGULATOR_TYPE_MAX, }; /* RPM resource parameters */ enum rpm_regulator_param_index { RPM_REGULATOR_PARAM_ENABLE, RPM_REGULATOR_PARAM_VOLTAGE, RPM_REGULATOR_PARAM_CURRENT, RPM_REGULATOR_PARAM_MODE_LDO, RPM_REGULATOR_PARAM_MODE_SMPS, RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE, RPM_REGULATOR_PARAM_PIN_CTRL_MODE, RPM_REGULATOR_PARAM_FREQUENCY, RPM_REGULATOR_PARAM_HEAD_ROOM, RPM_REGULATOR_PARAM_QUIET_MODE, RPM_REGULATOR_PARAM_FREQ_REASON, RPM_REGULATOR_PARAM_CORNER, RPM_REGULATOR_PARAM_BYPASS, RPM_REGULATOR_PARAM_FLOOR_CORNER, RPM_REGULATOR_PARAM_LEVEL, RPM_REGULATOR_PARAM_FLOOR_LEVEL, RPM_REGULATOR_PARAM_MODE_BOB, RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE1, RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE2, RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE3, RPM_REGULATOR_PARAM_MAX, }; enum rpm_regulator_smps_mode { RPM_REGULATOR_SMPS_MODE_AUTO = 0, RPM_REGULATOR_SMPS_MODE_IPEAK = 1, RPM_REGULATOR_SMPS_MODE_PWM = 2, }; enum rpm_regulator_ldo_mode { RPM_REGULATOR_LDO_MODE_IPEAK = 0, RPM_REGULATOR_LDO_MODE_HPM = 1, }; enum rpm_regulator_bob_mode { RPM_REGULATOR_BOB_MODE_PASS = 0, RPM_REGULATOR_BOB_MODE_PFM = 1, RPM_REGULATOR_BOB_MODE_AUTO = 2, RPM_REGULATOR_BOB_MODE_PWM = 3, }; #define RPM_SET_CONFIG_ACTIVE BIT(0) #define RPM_SET_CONFIG_SLEEP BIT(1) #define RPM_SET_CONFIG_BOTH (RPM_SET_CONFIG_ACTIVE \ | RPM_SET_CONFIG_SLEEP) struct rpm_regulator_param { char *name; char *property_name; u32 key; u32 min; u32 max; u32 supported_regulator_types; }; #define PARAM(_idx, _support_ldo, _support_smps, _support_vs, _support_ncp, \ _support_bob, _name, _min, _max, _property_name) \ [RPM_REGULATOR_PARAM_##_idx] = { \ .name = _name, \ .property_name = _property_name, \ .min = _min, \ .max = _max, \ .supported_regulator_types = \ _support_ldo << RPM_REGULATOR_TYPE_LDO | \ _support_smps << RPM_REGULATOR_TYPE_SMPS | \ _support_vs << RPM_REGULATOR_TYPE_VS | \ _support_ncp << RPM_REGULATOR_TYPE_NCP | \ _support_bob << RPM_REGULATOR_TYPE_BOB, \ } static struct rpm_regulator_param params[RPM_REGULATOR_PARAM_MAX] = { /* ID LDO SMPS VS NCP BOB name min max property-name */ PARAM(ENABLE, 1, 1, 1, 1, 1, "swen", 0, 1, "qcom,init-enable"), PARAM(VOLTAGE, 1, 1, 0, 1, 1, "uv", 0, 0x7FFFFFF, "qcom,init-voltage"), PARAM(CURRENT, 1, 1, 0, 0, 0, "ma", 0, 0x1FFF, "qcom,init-current"), PARAM(MODE_LDO, 1, 0, 0, 0, 0, "lsmd", 0, 1, "qcom,init-ldo-mode"), PARAM(MODE_SMPS, 0, 1, 0, 0, 0, "ssmd", 0, 2, "qcom,init-smps-mode"), PARAM(PIN_CTRL_ENABLE, 1, 1, 1, 0, 0, "pcen", 0, 0xF, "qcom,init-pin-ctrl-enable"), PARAM(PIN_CTRL_MODE, 1, 1, 1, 0, 0, "pcmd", 0, 0x1F, "qcom,init-pin-ctrl-mode"), PARAM(FREQUENCY, 0, 1, 0, 1, 0, "freq", 0, 31, "qcom,init-frequency"), PARAM(HEAD_ROOM, 1, 0, 0, 1, 0, "hr", 0, 0x7FFFFFFF, "qcom,init-head-room"), PARAM(QUIET_MODE, 0, 1, 0, 0, 0, "qm", 0, 2, "qcom,init-quiet-mode"), PARAM(FREQ_REASON, 0, 1, 0, 1, 0, "resn", 0, 8, "qcom,init-freq-reason"), PARAM(CORNER, 1, 1, 0, 0, 0, "corn", 0, 6, "qcom,init-voltage-corner"), PARAM(BYPASS, 1, 0, 0, 0, 0, "bypa", 0, 1, "qcom,init-disallow-bypass"), PARAM(FLOOR_CORNER, 1, 1, 0, 0, 0, "vfc", 0, 6, "qcom,init-voltage-floor-corner"), PARAM(LEVEL, 1, 1, 0, 0, 0, "vlvl", 0, 0xFFFF, "qcom,init-voltage-level"), PARAM(FLOOR_LEVEL, 1, 1, 0, 0, 0, "vfl", 0, 0xFFFF, "qcom,init-voltage-floor-level"), PARAM(MODE_BOB, 0, 0, 0, 0, 1, "bobm", 0, 3, "qcom,init-bob-mode"), PARAM(PIN_CTRL_VOLTAGE1, 0, 0, 0, 0, 1, "pcv1", 0, 0x7FFFFFF, "qcom,init-pin-ctrl-voltage1"), PARAM(PIN_CTRL_VOLTAGE2, 0, 0, 0, 0, 1, "pcv2", 0, 0x7FFFFFF, "qcom,init-pin-ctrl-voltage2"), PARAM(PIN_CTRL_VOLTAGE3, 0, 0, 0, 0, 1, "pcv3", 0, 0x7FFFFFF, "qcom,init-pin-ctrl-voltage3"), }; struct rpm_regulator_mode_map { int ldo_mode; int smps_mode; }; static struct rpm_regulator_mode_map mode_mapping[] = { [RPM_REGULATOR_MODE_AUTO] = {-1, RPM_REGULATOR_SMPS_MODE_AUTO}, [RPM_REGULATOR_MODE_IPEAK] = {RPM_REGULATOR_LDO_MODE_IPEAK, RPM_REGULATOR_SMPS_MODE_IPEAK}, [RPM_REGULATOR_MODE_HPM] = {RPM_REGULATOR_LDO_MODE_HPM, RPM_REGULATOR_SMPS_MODE_PWM}, }; /* Indices for use with pin control enable via enable/disable feature. */ #define RPM_VREG_PIN_CTRL_STATE_DISABLE 0 #define RPM_VREG_PIN_CTRL_STATE_ENABLE 1 #define RPM_VREG_PIN_CTRL_STATE_COUNT 2 struct rpm_vreg_request { u32 param[RPM_REGULATOR_PARAM_MAX]; u32 valid; u32 modified; }; struct rpm_vreg { struct rpm_vreg_request aggr_req_active; struct rpm_vreg_request aggr_req_sleep; struct list_head reg_list; const char *resource_name; u32 resource_id; bool allow_atomic; int regulator_type; int hpm_min_load; int enable_time; spinlock_t slock; struct mutex mlock; unsigned long flags; bool sleep_request_sent; bool wait_for_ack_active; bool wait_for_ack_sleep; bool always_wait_for_ack; bool apps_only; struct msm_rpm_request *handle_active; struct msm_rpm_request *handle_sleep; }; struct rpm_regulator { struct regulator_desc rdesc; struct regulator_dev *rdev; struct rpm_vreg *rpm_vreg; struct list_head list; bool set_active; bool set_sleep; bool always_send_voltage; bool always_send_current; bool use_pin_ctrl_for_enable; struct rpm_vreg_request req; int system_load; int min_uV; int max_uV; u32 pin_ctrl_mask[RPM_VREG_PIN_CTRL_STATE_COUNT]; enum rpm_regulator_param_index voltage_index; int voltage_offset; }; /* * This voltage in uV is returned by get_voltage functions when there is no way * to determine the current voltage level. It is needed because the regulator * framework treats a 0 uV voltage as an error. */ #define VOLTAGE_UNKNOWN 1 /* * Regulator requests sent in the active set take effect immediately. Requests * sent in the sleep set take effect when the Apps processor transitions into * RPM assisted power collapse. For any given regulator, if an active set * request is present, but not a sleep set request, then the active set request * is used at all times, even when the Apps processor is power collapsed. * * The rpm-regulator-smd takes advantage of this default usage of the active set * request by only sending a sleep set request if it differs from the * corresponding active set request. */ #define RPM_SET_ACTIVE MSM_RPM_CTX_ACTIVE_SET #define RPM_SET_SLEEP MSM_RPM_CTX_SLEEP_SET static u32 rpm_vreg_string_to_int(const u8 *str) { int i, len; u32 output = 0; len = strnlen(str, sizeof(u32)); for (i = 0; i < len; i++) output |= str[i] << (i * 8); return output; } static inline void rpm_vreg_lock(struct rpm_vreg *rpm_vreg) { if (rpm_vreg->allow_atomic) spin_lock_irqsave(&rpm_vreg->slock, rpm_vreg->flags); else mutex_lock(&rpm_vreg->mlock); } static inline void rpm_vreg_unlock(struct rpm_vreg *rpm_vreg) { if (rpm_vreg->allow_atomic) spin_unlock_irqrestore(&rpm_vreg->slock, rpm_vreg->flags); else mutex_unlock(&rpm_vreg->mlock); } static inline bool rpm_vreg_active_or_sleep_enabled(struct rpm_vreg *rpm_vreg) { return (rpm_vreg->aggr_req_active.param[RPM_REGULATOR_PARAM_ENABLE] && (rpm_vreg->aggr_req_active.valid & BIT(RPM_REGULATOR_PARAM_ENABLE))) || ((rpm_vreg->aggr_req_sleep.param[RPM_REGULATOR_PARAM_ENABLE]) && (rpm_vreg->aggr_req_sleep.valid & BIT(RPM_REGULATOR_PARAM_ENABLE))); } static inline bool rpm_vreg_shared_active_or_sleep_enabled_valid (struct rpm_vreg *rpm_vreg) { return !rpm_vreg->apps_only && ((rpm_vreg->aggr_req_active.valid & BIT(RPM_REGULATOR_PARAM_ENABLE)) || (rpm_vreg->aggr_req_sleep.valid & BIT(RPM_REGULATOR_PARAM_ENABLE))); } static const u32 power_level_params = BIT(RPM_REGULATOR_PARAM_ENABLE) | BIT(RPM_REGULATOR_PARAM_VOLTAGE) | BIT(RPM_REGULATOR_PARAM_CURRENT) | BIT(RPM_REGULATOR_PARAM_CORNER) | BIT(RPM_REGULATOR_PARAM_BYPASS) | BIT(RPM_REGULATOR_PARAM_FLOOR_CORNER) | BIT(RPM_REGULATOR_PARAM_LEVEL) | BIT(RPM_REGULATOR_PARAM_FLOOR_LEVEL); static bool rpm_vreg_ack_required(struct rpm_vreg *rpm_vreg, u32 set, const u32 *prev_param, const u32 *param, u32 prev_valid, u32 modified) { u32 mask; int i; if (rpm_vreg->always_wait_for_ack || (set == RPM_SET_ACTIVE && rpm_vreg->wait_for_ack_active) || (set == RPM_SET_SLEEP && rpm_vreg->wait_for_ack_sleep)) return true; for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) { mask = BIT(i); if (modified & mask) { if ((prev_valid & mask) && (power_level_params & mask) && (param[i] <= prev_param[i])) continue; else return true; } } return false; } static void rpm_vreg_check_param_max(struct rpm_regulator *regulator, int index, u32 new_max) { struct rpm_vreg *rpm_vreg = regulator->rpm_vreg; if (regulator->set_active && (rpm_vreg->aggr_req_active.valid & BIT(index)) && rpm_vreg->aggr_req_active.param[index] > new_max) rpm_vreg->wait_for_ack_active = true; if (regulator->set_sleep && (rpm_vreg->aggr_req_sleep.valid & BIT(index)) && rpm_vreg->aggr_req_sleep.param[index] > new_max) rpm_vreg->wait_for_ack_sleep = true; } /* * This is used when voting for LPM or HPM by subtracting or adding to the * hpm_min_load of a regulator. It has units of uA. */ #define LOAD_THRESHOLD_STEP 1000 static inline int rpm_vreg_hpm_min_uA(struct rpm_vreg *rpm_vreg) { return rpm_vreg->hpm_min_load; } static inline int rpm_vreg_lpm_max_uA(struct rpm_vreg *rpm_vreg) { return rpm_vreg->hpm_min_load - LOAD_THRESHOLD_STEP; } #define MICRO_TO_MILLI(uV) ((uV) / 1000) #define MILLI_TO_MICRO(uV) ((uV) * 1000) #define DEBUG_PRINT_BUFFER_SIZE 512 #define REQ_SENT 0 #define REQ_PREV 1 #define REQ_CACHED 2 #define REQ_TYPES 3 static void rpm_regulator_req(struct rpm_regulator *regulator, int set, bool sent) { char buf[DEBUG_PRINT_BUFFER_SIZE]; size_t buflen = DEBUG_PRINT_BUFFER_SIZE; struct rpm_vreg *rpm_vreg = regulator->rpm_vreg; struct rpm_vreg_request *aggr; bool first; u32 mask[REQ_TYPES] = {0, 0, 0}; const char *req_names[REQ_TYPES] = {"sent", "prev", "cached"}; int pos = 0; int i, j; aggr = (set == RPM_SET_ACTIVE) ? &rpm_vreg->aggr_req_active : &rpm_vreg->aggr_req_sleep; if (rpm_vreg_debug_mask & RPM_VREG_DEBUG_DUPLICATE) { mask[REQ_SENT] = aggr->modified; mask[REQ_PREV] = aggr->valid & ~aggr->modified; } else if (sent && (rpm_vreg_debug_mask & RPM_VREG_DEBUG_FULL_REQUEST)) { mask[REQ_SENT] = aggr->modified; mask[REQ_PREV] = aggr->valid & ~aggr->modified; } else if (sent && (rpm_vreg_debug_mask & RPM_VREG_DEBUG_REQUEST)) { mask[REQ_SENT] = aggr->modified; } if (!(mask[REQ_SENT] | mask[REQ_PREV])) return; if (set == RPM_SET_SLEEP && !rpm_vreg->sleep_request_sent) { mask[REQ_CACHED] = mask[REQ_SENT] | mask[REQ_PREV]; mask[REQ_SENT] = 0; mask[REQ_PREV] = 0; } pos += scnprintf(buf + pos, buflen - pos, "%s%s: ", KERN_INFO, __func__); pos += scnprintf(buf + pos, buflen - pos, "%s %u (%s): s=%s", rpm_vreg->resource_name, rpm_vreg->resource_id, regulator->rdesc.name, (set == RPM_SET_ACTIVE ? "act" : "slp")); for (i = 0; i < REQ_TYPES; i++) { if (mask[i]) pos += scnprintf(buf + pos, buflen - pos, "; %s: ", req_names[i]); first = true; for (j = 0; j < RPM_REGULATOR_PARAM_MAX; j++) { if (mask[i] & BIT(j)) { pos += scnprintf(buf + pos, buflen - pos, "%s%s=%u", (first ? "" : ", "), params[j].name, aggr->param[j]); first = false; } } } pos += scnprintf(buf + pos, buflen - pos, "\n"); printk(buf); } #define RPM_VREG_SET_PARAM(_regulator, _param, _val) \ { \ (_regulator)->req.param[RPM_REGULATOR_PARAM_##_param] = _val; \ (_regulator)->req.modified |= BIT(RPM_REGULATOR_PARAM_##_param); \ } \ static int rpm_vreg_add_kvp_to_request(struct rpm_vreg *rpm_vreg, const u32 *param, int idx, u32 set) { struct msm_rpm_request *handle; handle = (set == RPM_SET_ACTIVE ? rpm_vreg->handle_active : rpm_vreg->handle_sleep); if (rpm_vreg->allow_atomic) return msm_rpm_add_kvp_data_noirq(handle, params[idx].key, (u8 *)¶m[idx], 4); else return msm_rpm_add_kvp_data(handle, params[idx].key, (u8 *)¶m[idx], 4); } static void rpm_vreg_check_modified_requests(const u32 *prev_param, const u32 *param, u32 prev_valid, u32 *modified) { u32 value_changed = 0; int i; for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) { if (param[i] != prev_param[i]) value_changed |= BIT(i); } /* * Only keep bits that are for changed parameters or previously * invalid parameters. */ *modified &= value_changed | ~prev_valid; } static int rpm_vreg_add_modified_requests(struct rpm_regulator *regulator, u32 set, const u32 *param, u32 modified) { struct rpm_vreg *rpm_vreg = regulator->rpm_vreg; int rc = 0; int i; for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) { /* Only send requests for modified parameters. */ if (modified & BIT(i)) { rc = rpm_vreg_add_kvp_to_request(rpm_vreg, param, i, set); if (rc) { vreg_err(regulator, "add KVP failed: %s %u; %s, rc=%d\n", rpm_vreg->resource_name, rpm_vreg->resource_id, params[i].name, rc); return rc; } } } return rc; } static int rpm_vreg_send_request(struct rpm_regulator *regulator, u32 set, bool wait_for_ack) { struct rpm_vreg *rpm_vreg = regulator->rpm_vreg; struct msm_rpm_request *handle = (set == RPM_SET_ACTIVE ? rpm_vreg->handle_active : rpm_vreg->handle_sleep); int rc = 0; void *temp; if (unlikely(rpm_vreg->allow_atomic)) { rc = msm_rpm_wait_for_ack_noirq(msm_rpm_send_request_noirq( handle)); } else if (wait_for_ack) { rc = msm_rpm_wait_for_ack(msm_rpm_send_request(handle)); } else { temp = msm_rpm_send_request_noack(handle); if (IS_ERR(temp)) rc = PTR_ERR(temp); } if (rc) vreg_err(regulator, "msm rpm send failed: %s %u; set=%s, rc=%d\n", rpm_vreg->resource_name, rpm_vreg->resource_id, (set == RPM_SET_ACTIVE ? "act" : "slp"), rc); return rc; } #define RPM_VREG_AGGR_MIN(_idx, _param_aggr, _param_reg) \ { \ _param_aggr[RPM_REGULATOR_PARAM_##_idx] \ = min(_param_aggr[RPM_REGULATOR_PARAM_##_idx], \ _param_reg[RPM_REGULATOR_PARAM_##_idx]); \ } #define RPM_VREG_AGGR_MAX(_idx, _param_aggr, _param_reg) \ { \ _param_aggr[RPM_REGULATOR_PARAM_##_idx] \ = max(_param_aggr[RPM_REGULATOR_PARAM_##_idx], \ _param_reg[RPM_REGULATOR_PARAM_##_idx]); \ } #define RPM_VREG_AGGR_SUM(_idx, _param_aggr, _param_reg) \ { \ _param_aggr[RPM_REGULATOR_PARAM_##_idx] \ += _param_reg[RPM_REGULATOR_PARAM_##_idx]; \ } #define RPM_VREG_AGGR_OR(_idx, _param_aggr, _param_reg) \ { \ _param_aggr[RPM_REGULATOR_PARAM_##_idx] \ |= _param_reg[RPM_REGULATOR_PARAM_##_idx]; \ } /* * Aggregation is performed on each parameter based on the way that the RPM * aggregates that type internally between RPM masters. */ static void rpm_vreg_aggregate_params(u32 *param_aggr, const u32 *param_reg) { RPM_VREG_AGGR_MAX(ENABLE, param_aggr, param_reg); RPM_VREG_AGGR_MAX(VOLTAGE, param_aggr, param_reg); RPM_VREG_AGGR_SUM(CURRENT, param_aggr, param_reg); RPM_VREG_AGGR_MAX(MODE_LDO, param_aggr, param_reg); RPM_VREG_AGGR_MAX(MODE_SMPS, param_aggr, param_reg); RPM_VREG_AGGR_OR(PIN_CTRL_ENABLE, param_aggr, param_reg); RPM_VREG_AGGR_OR(PIN_CTRL_MODE, param_aggr, param_reg); RPM_VREG_AGGR_MIN(FREQUENCY, param_aggr, param_reg); RPM_VREG_AGGR_MAX(HEAD_ROOM, param_aggr, param_reg); RPM_VREG_AGGR_MAX(QUIET_MODE, param_aggr, param_reg); RPM_VREG_AGGR_MAX(FREQ_REASON, param_aggr, param_reg); RPM_VREG_AGGR_MAX(CORNER, param_aggr, param_reg); RPM_VREG_AGGR_MAX(BYPASS, param_aggr, param_reg); RPM_VREG_AGGR_MAX(FLOOR_CORNER, param_aggr, param_reg); RPM_VREG_AGGR_MAX(LEVEL, param_aggr, param_reg); RPM_VREG_AGGR_MAX(FLOOR_LEVEL, param_aggr, param_reg); RPM_VREG_AGGR_MAX(MODE_BOB, param_aggr, param_reg); RPM_VREG_AGGR_MAX(PIN_CTRL_VOLTAGE1, param_aggr, param_reg); RPM_VREG_AGGR_MAX(PIN_CTRL_VOLTAGE2, param_aggr, param_reg); RPM_VREG_AGGR_MAX(PIN_CTRL_VOLTAGE3, param_aggr, param_reg); } static int rpm_vreg_aggregate_requests(struct rpm_regulator *regulator) { struct rpm_vreg *rpm_vreg = regulator->rpm_vreg; u32 param_active[RPM_REGULATOR_PARAM_MAX]; u32 param_sleep[RPM_REGULATOR_PARAM_MAX]; u32 modified_active, modified_sleep; struct rpm_regulator *reg; bool sleep_set_differs = false; bool send_active = false; bool send_sleep = false; bool wait_for_ack; int rc = 0; int i; memset(param_active, 0, sizeof(param_active)); memset(param_sleep, 0, sizeof(param_sleep)); modified_active = rpm_vreg->aggr_req_active.modified; modified_sleep = rpm_vreg->aggr_req_sleep.modified; /* * Aggregate all of the requests for this regulator in both active * and sleep sets. */ list_for_each_entry(reg, &rpm_vreg->reg_list, list) { if (reg->set_active) { rpm_vreg_aggregate_params(param_active, reg->req.param); modified_active |= reg->req.modified; } if (reg->set_sleep) { rpm_vreg_aggregate_params(param_sleep, reg->req.param); modified_sleep |= reg->req.modified; } } /* * Check if the aggregated sleep set parameter values differ from the * aggregated active set parameter values. */ if (!rpm_vreg->sleep_request_sent) { for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) { if ((param_active[i] != param_sleep[i]) && (modified_sleep & BIT(i))) { sleep_set_differs = true; break; } } } /* Add KVPs to the active set RPM request if they have new values. */ rpm_vreg_check_modified_requests(rpm_vreg->aggr_req_active.param, param_active, rpm_vreg->aggr_req_active.valid, &modified_active); rc = rpm_vreg_add_modified_requests(regulator, RPM_SET_ACTIVE, param_active, modified_active); if (rc) return rc; send_active = modified_active; /* * Sleep set configurations are only sent if they differ from the * active set values. This is because the active set values will take * effect during rpm assisted power collapse in the absence of sleep set * values. * * However, once a sleep set request is sent for a given regulator, * additional sleep set requests must be sent in the future even if they * match the corresponding active set requests. */ if (rpm_vreg->sleep_request_sent || sleep_set_differs) { /* Add KVPs to the sleep set RPM request if they are new. */ rpm_vreg_check_modified_requests(rpm_vreg->aggr_req_sleep.param, param_sleep, rpm_vreg->aggr_req_sleep.valid, &modified_sleep); rc = rpm_vreg_add_modified_requests(regulator, RPM_SET_SLEEP, param_sleep, modified_sleep); if (rc) return rc; send_sleep = modified_sleep; } /* Send active set request to the RPM if it contains new KVPs. */ if (send_active) { wait_for_ack = rpm_vreg_ack_required(rpm_vreg, RPM_SET_ACTIVE, rpm_vreg->aggr_req_active.param, param_active, rpm_vreg->aggr_req_active.valid, modified_active); rc = rpm_vreg_send_request(regulator, RPM_SET_ACTIVE, wait_for_ack); if (rc) return rc; rpm_vreg->aggr_req_active.valid |= modified_active; rpm_vreg->wait_for_ack_active = false; } /* Store the results of the aggregation. */ rpm_vreg->aggr_req_active.modified = modified_active; memcpy(rpm_vreg->aggr_req_active.param, param_active, sizeof(param_active)); /* Handle debug printing of the active set request. */ rpm_regulator_req(regulator, RPM_SET_ACTIVE, send_active); if (send_active) rpm_vreg->aggr_req_active.modified = 0; /* Send sleep set request to the RPM if it contains new KVPs. */ if (send_sleep) { wait_for_ack = rpm_vreg_ack_required(rpm_vreg, RPM_SET_SLEEP, rpm_vreg->aggr_req_sleep.param, param_sleep, rpm_vreg->aggr_req_sleep.valid, modified_sleep); rc = rpm_vreg_send_request(regulator, RPM_SET_SLEEP, wait_for_ack); if (rc) return rc; else rpm_vreg->sleep_request_sent = true; rpm_vreg->aggr_req_sleep.valid |= modified_sleep; rpm_vreg->wait_for_ack_sleep = false; } /* Store the results of the aggregation. */ rpm_vreg->aggr_req_sleep.modified = modified_sleep; memcpy(rpm_vreg->aggr_req_sleep.param, param_sleep, sizeof(param_sleep)); /* Handle debug printing of the sleep set request. */ rpm_regulator_req(regulator, RPM_SET_SLEEP, send_sleep); if (send_sleep) rpm_vreg->aggr_req_sleep.modified = 0; /* * Loop over all requests for this regulator to update the valid and * modified values for use in future aggregation. */ list_for_each_entry(reg, &rpm_vreg->reg_list, list) { reg->req.valid |= reg->req.modified; reg->req.modified = 0; } return rc; } static int rpm_vreg_is_enabled(struct regulator_dev *rdev) { struct rpm_regulator *reg = rdev_get_drvdata(rdev); if (likely(!reg->use_pin_ctrl_for_enable)) return reg->req.param[RPM_REGULATOR_PARAM_ENABLE]; else return reg->req.param[RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE] == reg->pin_ctrl_mask[RPM_VREG_PIN_CTRL_STATE_ENABLE]; } static int rpm_vreg_enable(struct regulator_dev *rdev) { struct rpm_regulator *reg = rdev_get_drvdata(rdev); int rc; u32 prev_enable; rpm_vreg_lock(reg->rpm_vreg); if (likely(!reg->use_pin_ctrl_for_enable)) { /* Enable using swen KVP. */ prev_enable = reg->req.param[RPM_REGULATOR_PARAM_ENABLE]; RPM_VREG_SET_PARAM(reg, ENABLE, 1); rc = rpm_vreg_aggregate_requests(reg); if (rc) { vreg_err(reg, "enable failed, rc=%d", rc); RPM_VREG_SET_PARAM(reg, ENABLE, prev_enable); } } else { /* Enable using pcen KVP. */ prev_enable = reg->req.param[RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE]; RPM_VREG_SET_PARAM(reg, PIN_CTRL_ENABLE, reg->pin_ctrl_mask[RPM_VREG_PIN_CTRL_STATE_ENABLE]); rc = rpm_vreg_aggregate_requests(reg); if (rc) { vreg_err(reg, "enable failed, rc=%d", rc); RPM_VREG_SET_PARAM(reg, PIN_CTRL_ENABLE, prev_enable); } } rpm_vreg_unlock(reg->rpm_vreg); return rc; } static int rpm_vreg_disable(struct regulator_dev *rdev) { struct rpm_regulator *reg = rdev_get_drvdata(rdev); int rc; u32 prev_enable; rpm_vreg_lock(reg->rpm_vreg); if (likely(!reg->use_pin_ctrl_for_enable)) { /* Disable using swen KVP. */ prev_enable = reg->req.param[RPM_REGULATOR_PARAM_ENABLE]; RPM_VREG_SET_PARAM(reg, ENABLE, 0); rc = rpm_vreg_aggregate_requests(reg); if (rc) { vreg_err(reg, "disable failed, rc=%d", rc); RPM_VREG_SET_PARAM(reg, ENABLE, prev_enable); } } else { /* Disable using pcen KVP. */ prev_enable = reg->req.param[RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE]; RPM_VREG_SET_PARAM(reg, PIN_CTRL_ENABLE, reg->pin_ctrl_mask[RPM_VREG_PIN_CTRL_STATE_DISABLE]); rc = rpm_vreg_aggregate_requests(reg); if (rc) { vreg_err(reg, "disable failed, rc=%d", rc); RPM_VREG_SET_PARAM(reg, PIN_CTRL_ENABLE, prev_enable); } } rpm_vreg_unlock(reg->rpm_vreg); return rc; } #define RPM_VREG_SET_VOLTAGE(_regulator, _val) \ { \ (_regulator)->req.param[(_regulator)->voltage_index] = _val; \ (_regulator)->req.modified |= BIT((_regulator)->voltage_index); \ } \ static int rpm_vreg_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) { struct rpm_regulator *reg = rdev_get_drvdata(rdev); int rc = 0; int voltage; u32 prev_voltage; voltage = min_uV - reg->voltage_offset; if (voltage < params[reg->voltage_index].min || voltage > params[reg->voltage_index].max) { vreg_err(reg, "voltage=%d for key=%s is not within allowed range: [%u, %u]\n", voltage, params[reg->voltage_index].name, params[reg->voltage_index].min, params[reg->voltage_index].max); return -EINVAL; } rpm_vreg_lock(reg->rpm_vreg); prev_voltage = reg->req.param[reg->voltage_index]; RPM_VREG_SET_VOLTAGE(reg, voltage); rpm_vreg_check_param_max(reg, reg->voltage_index, max_uV - reg->voltage_offset); /* * Only send a new voltage if the regulator is currently enabled or * if the regulator has been configured to always send voltage updates. */ if (reg->always_send_voltage || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg) || rpm_vreg_shared_active_or_sleep_enabled_valid(reg->rpm_vreg)) rc = rpm_vreg_aggregate_requests(reg); if (rc) { vreg_err(reg, "set voltage for key=%s failed, rc=%d", params[reg->voltage_index].name, rc); RPM_VREG_SET_VOLTAGE(reg, prev_voltage); } rpm_vreg_unlock(reg->rpm_vreg); return rc; } static int rpm_vreg_get_voltage(struct regulator_dev *rdev) { struct rpm_regulator *reg = rdev_get_drvdata(rdev); int uV; uV = reg->req.param[reg->voltage_index] + reg->voltage_offset; if (uV == 0) uV = VOLTAGE_UNKNOWN; return uV; } static int rpm_vreg_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct rpm_regulator *reg = rdev_get_drvdata(rdev); int rc = 0; u32 prev_current; int prev_uA; rpm_vreg_lock(reg->rpm_vreg); prev_current = reg->req.param[RPM_REGULATOR_PARAM_CURRENT]; prev_uA = MILLI_TO_MICRO(prev_current); if (mode == REGULATOR_MODE_NORMAL) { /* Make sure that request current is in HPM range. */ if (prev_uA < rpm_vreg_hpm_min_uA(reg->rpm_vreg)) RPM_VREG_SET_PARAM(reg, CURRENT, MICRO_TO_MILLI(rpm_vreg_hpm_min_uA(reg->rpm_vreg))); } else if (REGULATOR_MODE_IDLE) { /* Make sure that request current is in LPM range. */ if (prev_uA > rpm_vreg_lpm_max_uA(reg->rpm_vreg)) RPM_VREG_SET_PARAM(reg, CURRENT, MICRO_TO_MILLI(rpm_vreg_lpm_max_uA(reg->rpm_vreg))); } else { vreg_err(reg, "invalid mode: %u\n", mode); rpm_vreg_unlock(reg->rpm_vreg); return -EINVAL; } /* * Only send a new load current value if the regulator is currently * enabled or if the regulator has been configured to always send * current updates. */ if (reg->always_send_current || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg) || rpm_vreg_shared_active_or_sleep_enabled_valid(reg->rpm_vreg)) rc = rpm_vreg_aggregate_requests(reg); if (rc) { vreg_err(reg, "set mode failed, rc=%d\n", rc); RPM_VREG_SET_PARAM(reg, CURRENT, prev_current); } rpm_vreg_unlock(reg->rpm_vreg); return rc; } static unsigned int rpm_vreg_get_mode(struct regulator_dev *rdev) { struct rpm_regulator *reg = rdev_get_drvdata(rdev); return (reg->req.param[RPM_REGULATOR_PARAM_CURRENT] >= MICRO_TO_MILLI(reg->rpm_vreg->hpm_min_load)) ? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE; } static unsigned int rpm_vreg_get_optimum_mode(struct regulator_dev *rdev, int input_uV, int output_uV, int load_uA) { struct rpm_regulator *reg = rdev_get_drvdata(rdev); u32 load_mA; load_uA += reg->system_load; load_mA = MICRO_TO_MILLI(load_uA); if (load_mA > params[RPM_REGULATOR_PARAM_CURRENT].max) load_mA = params[RPM_REGULATOR_PARAM_CURRENT].max; rpm_vreg_lock(reg->rpm_vreg); RPM_VREG_SET_PARAM(reg, CURRENT, load_mA); rpm_vreg_unlock(reg->rpm_vreg); return (load_uA >= reg->rpm_vreg->hpm_min_load) ? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE; } static int rpm_vreg_set_bob_mode(struct regulator_dev *rdev, unsigned int mode) { struct rpm_regulator *reg = rdev_get_drvdata(rdev); int rc; u32 prev_mode; rpm_vreg_lock(reg->rpm_vreg); prev_mode = reg->req.param[RPM_REGULATOR_PARAM_MODE_BOB]; switch (mode) { case REGULATOR_MODE_FAST: RPM_VREG_SET_PARAM(reg, MODE_BOB, RPM_REGULATOR_BOB_MODE_PWM); break; case REGULATOR_MODE_NORMAL: RPM_VREG_SET_PARAM(reg, MODE_BOB, RPM_REGULATOR_BOB_MODE_AUTO); break; case REGULATOR_MODE_IDLE: RPM_VREG_SET_PARAM(reg, MODE_BOB, RPM_REGULATOR_BOB_MODE_PFM); break; case REGULATOR_MODE_STANDBY: RPM_VREG_SET_PARAM(reg, MODE_BOB, RPM_REGULATOR_BOB_MODE_PASS); break; default: vreg_err(reg, "invalid mode: %u\n", mode); rpm_vreg_unlock(reg->rpm_vreg); return -EINVAL; } rc = rpm_vreg_aggregate_requests(reg); if (rc) { vreg_err(reg, "set BoB mode failed, rc=%d\n", rc); RPM_VREG_SET_PARAM(reg, MODE_BOB, prev_mode); } rpm_vreg_unlock(reg->rpm_vreg); return rc; } static unsigned int rpm_vreg_get_bob_mode(struct regulator_dev *rdev) { struct rpm_regulator *reg = rdev_get_drvdata(rdev); unsigned int mode; switch (reg->req.param[RPM_REGULATOR_PARAM_MODE_BOB]) { case RPM_REGULATOR_BOB_MODE_PWM: mode = REGULATOR_MODE_FAST; break; case RPM_REGULATOR_BOB_MODE_AUTO: mode = REGULATOR_MODE_NORMAL; break; case RPM_REGULATOR_BOB_MODE_PFM: mode = REGULATOR_MODE_IDLE; break; case RPM_REGULATOR_BOB_MODE_PASS: mode = REGULATOR_MODE_STANDBY; break; default: vreg_err(reg, "BoB mode unknown\n"); mode = REGULATOR_MODE_NORMAL; } return mode; } static int rpm_vreg_enable_time(struct regulator_dev *rdev) { struct rpm_regulator *reg = rdev_get_drvdata(rdev); return reg->rpm_vreg->enable_time; } static int rpm_vreg_send_defaults(struct rpm_regulator *reg) { int rc; rpm_vreg_lock(reg->rpm_vreg); rc = rpm_vreg_aggregate_requests(reg); if (rc) vreg_err(reg, "RPM request failed, rc=%d", rc); rpm_vreg_unlock(reg->rpm_vreg); return rc; } static int rpm_vreg_configure_pin_control_enable(struct rpm_regulator *reg, struct device_node *node) { struct rpm_regulator_param *pcen_param = ¶ms[RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE]; int rc, i; if (!of_find_property(node, "qcom,enable-with-pin-ctrl", NULL)) return 0; if (pcen_param->supported_regulator_types & BIT(reg->rpm_vreg->regulator_type)) { rc = of_property_read_u32_array(node, "qcom,enable-with-pin-ctrl", reg->pin_ctrl_mask, RPM_VREG_PIN_CTRL_STATE_COUNT); if (rc) { vreg_err(reg, "could not read qcom,enable-with-pin-ctrl, rc=%d\n", rc); return rc; } /* Verify that the mask values are valid. */ for (i = 0; i < RPM_VREG_PIN_CTRL_STATE_COUNT; i++) { if (reg->pin_ctrl_mask[i] < pcen_param->min || reg->pin_ctrl_mask[i] > pcen_param->max) { vreg_err(reg, "device tree property: qcom,enable-with-pin-ctrl[%d]=%u is outside allowed range [%u, %u]\n", i, reg->pin_ctrl_mask[i], pcen_param->min, pcen_param->max); return -EINVAL; } } reg->use_pin_ctrl_for_enable = true; } else { pr_warn("%s: regulator type=%d does not support device tree property: qcom,enable-with-pin-ctrl\n", reg->rdesc.name, reg->rpm_vreg->regulator_type); } return 0; } /** * rpm_regulator_get() - lookup and obtain a handle to an RPM regulator * @dev: device for regulator consumer * @supply: supply name * * Returns a struct rpm_regulator corresponding to the regulator producer, * or ERR_PTR() containing errno. * * This function may only be called from nonatomic context. */ struct rpm_regulator *rpm_regulator_get(struct device *dev, const char *supply) { struct rpm_regulator *framework_reg; struct rpm_regulator *priv_reg = NULL; struct regulator *regulator; struct rpm_vreg *rpm_vreg; regulator = regulator_get(dev, supply); if (IS_ERR(regulator)) { pr_err("could not find regulator for: dev=%s, supply=%s, rc=%ld\n", (dev ? dev_name(dev) : ""), (supply ? supply : ""), PTR_ERR(regulator)); return ERR_CAST(regulator); } framework_reg = regulator_get_drvdata(regulator); if (framework_reg == NULL) { pr_err("regulator structure not found.\n"); regulator_put(regulator); return ERR_PTR(-ENODEV); } regulator_put(regulator); rpm_vreg = framework_reg->rpm_vreg; priv_reg = kzalloc(sizeof(struct rpm_regulator), GFP_KERNEL); if (priv_reg == NULL) { vreg_err(framework_reg, "could not allocate memory for regulator\n"); return ERR_PTR(-ENOMEM); } /* * Allocate a regulator_dev struct so that framework callback functions * can be called from the private API functions. */ priv_reg->rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); if (priv_reg->rdev == NULL) { vreg_err(framework_reg, "could not allocate memory for regulator_dev\n"); kfree(priv_reg); return ERR_PTR(-ENOMEM); } priv_reg->rdev->reg_data = priv_reg; priv_reg->rpm_vreg = rpm_vreg; priv_reg->rdesc.name = framework_reg->rdesc.name; priv_reg->rdesc.ops = framework_reg->rdesc.ops; priv_reg->set_active = framework_reg->set_active; priv_reg->set_sleep = framework_reg->set_sleep; priv_reg->min_uV = framework_reg->min_uV; priv_reg->max_uV = framework_reg->max_uV; priv_reg->system_load = framework_reg->system_load; might_sleep_if(!rpm_vreg->allow_atomic); rpm_vreg_lock(rpm_vreg); list_add(&priv_reg->list, &rpm_vreg->reg_list); rpm_vreg_unlock(rpm_vreg); return priv_reg; } EXPORT_SYMBOL(rpm_regulator_get); static int rpm_regulator_check_input(struct rpm_regulator *regulator) { if (IS_ERR_OR_NULL(regulator) || regulator->rpm_vreg == NULL) { pr_err("invalid rpm_regulator pointer\n"); return -EINVAL; } might_sleep_if(!regulator->rpm_vreg->allow_atomic); return 0; } /** * rpm_regulator_put() - free the RPM regulator handle * @regulator: RPM regulator handle * * Parameter reaggregation does not take place when rpm_regulator_put is called. * Therefore, regulator enable state and voltage must be configured * appropriately before calling rpm_regulator_put. * * This function may be called from either atomic or nonatomic context. If this * function is called from atomic context, then the regulator being operated on * must be configured via device tree with qcom,allow-atomic == 1. */ void rpm_regulator_put(struct rpm_regulator *regulator) { struct rpm_vreg *rpm_vreg; int rc = rpm_regulator_check_input(regulator); if (rc) return; rpm_vreg = regulator->rpm_vreg; might_sleep_if(!rpm_vreg->allow_atomic); rpm_vreg_lock(rpm_vreg); list_del(®ulator->list); rpm_vreg_unlock(rpm_vreg); kfree(regulator->rdev); kfree(regulator); } EXPORT_SYMBOL(rpm_regulator_put); /** * rpm_regulator_enable() - enable regulator output * @regulator: RPM regulator handle * * Returns 0 on success or errno on failure. * * This function may be called from either atomic or nonatomic context. If this * function is called from atomic context, then the regulator being operated on * must be configured via device tree with qcom,allow-atomic == 1. */ int rpm_regulator_enable(struct rpm_regulator *regulator) { int rc = rpm_regulator_check_input(regulator); if (rc) return rc; return rpm_vreg_enable(regulator->rdev); } EXPORT_SYMBOL(rpm_regulator_enable); /** * rpm_regulator_disable() - disable regulator output * @regulator: RPM regulator handle * * Returns 0 on success or errno on failure. * * The enable state of the regulator is determined by aggregating the requests * of all consumers. Therefore, it is possible that the regulator will remain * enabled even after rpm_regulator_disable is called. * * This function may be called from either atomic or nonatomic context. If this * function is called from atomic context, then the regulator being operated on * must be configured via device tree with qcom,allow-atomic == 1. */ int rpm_regulator_disable(struct rpm_regulator *regulator) { int rc = rpm_regulator_check_input(regulator); if (rc) return rc; return rpm_vreg_disable(regulator->rdev); } EXPORT_SYMBOL(rpm_regulator_disable); /** * rpm_regulator_set_voltage() - set regulator output voltage * @regulator: RPM regulator handle * @min_uV: minimum required voltage in uV * @max_uV: maximum acceptable voltage in uV * * Sets a voltage regulator to the desired output voltage. This can be set * while the regulator is disabled or enabled. If the regulator is enabled then * the voltage will change to the new value immediately; otherwise, if the * regulator is disabled, then the regulator will output at the new voltage when * enabled. * * The min_uV to max_uV voltage range requested must intersect with the * voltage constraint range configured for the regulator. * * Returns 0 on success or errno on failure. * * The final voltage value that is sent to the RPM is aggregated based upon the * values requested by all consumers of the regulator. This corresponds to the * maximum min_uV value. * * This function may be called from either atomic or nonatomic context. If this * function is called from atomic context, then the regulator being operated on * must be configured via device tree with qcom,allow-atomic == 1. */ int rpm_regulator_set_voltage(struct rpm_regulator *regulator, int min_uV, int max_uV) { int rc = rpm_regulator_check_input(regulator); int uV = min_uV; if (rc) return rc; if (regulator->rpm_vreg->regulator_type == RPM_REGULATOR_TYPE_VS) { vreg_err(regulator, "unsupported regulator type: %d\n", regulator->rpm_vreg->regulator_type); return -EINVAL; } if (min_uV > max_uV) { vreg_err(regulator, "min_uV=%d must be less than max_uV=%d\n", min_uV, max_uV); return -EINVAL; } if (uV < regulator->min_uV && max_uV >= regulator->min_uV) uV = regulator->min_uV; if (uV < regulator->min_uV || uV > regulator->max_uV) { vreg_err(regulator, "request v=[%d, %d] is outside allowed v=[%d, %d]\n", min_uV, max_uV, regulator->min_uV, regulator->max_uV); return -EINVAL; } return regulator->rdesc.ops->set_voltage(regulator->rdev, uV, uV, NULL); } EXPORT_SYMBOL(rpm_regulator_set_voltage); /** * rpm_regulator_set_mode() - set regulator operating mode * @regulator: RPM regulator handle * @mode: operating mode requested for the regulator * * Requests that the mode of the regulator be set to the mode specified. This * parameter is aggregated using a max function such that AUTO < IPEAK < HPM. * * Returns 0 on success or errno on failure. */ int rpm_regulator_set_mode(struct rpm_regulator *regulator, enum rpm_regulator_mode mode) { int index = 0; u32 new_mode, prev_mode; int rc; rc = rpm_regulator_check_input(regulator); if (rc) return rc; if (mode < 0 || mode >= ARRAY_SIZE(mode_mapping)) { vreg_err(regulator, "invalid mode requested: %d\n", mode); return -EINVAL; } switch (regulator->rpm_vreg->regulator_type) { case RPM_REGULATOR_TYPE_SMPS: index = RPM_REGULATOR_PARAM_MODE_SMPS; new_mode = mode_mapping[mode].smps_mode; break; case RPM_REGULATOR_TYPE_LDO: index = RPM_REGULATOR_PARAM_MODE_LDO; new_mode = mode_mapping[mode].ldo_mode; break; default: vreg_err(regulator, "unsupported regulator type: %d\n", regulator->rpm_vreg->regulator_type); return -EINVAL; }; if (new_mode < params[index].min || new_mode > params[index].max) { vreg_err(regulator, "invalid mode requested: %d for type: %d\n", mode, regulator->rpm_vreg->regulator_type); return -EINVAL; } rpm_vreg_lock(regulator->rpm_vreg); prev_mode = regulator->req.param[index]; regulator->req.param[index] = new_mode; regulator->req.modified |= BIT(index); rc = rpm_vreg_aggregate_requests(regulator); if (rc) { vreg_err(regulator, "set mode failed, rc=%d", rc); regulator->req.param[index] = prev_mode; } rpm_vreg_unlock(regulator->rpm_vreg); return rc; } EXPORT_SYMBOL(rpm_regulator_set_mode); static struct regulator_ops ldo_ops = { .enable = rpm_vreg_enable, .disable = rpm_vreg_disable, .is_enabled = rpm_vreg_is_enabled, .set_voltage = rpm_vreg_set_voltage, .get_voltage = rpm_vreg_get_voltage, .set_mode = rpm_vreg_set_mode, .get_mode = rpm_vreg_get_mode, .get_optimum_mode = rpm_vreg_get_optimum_mode, .enable_time = rpm_vreg_enable_time, }; static struct regulator_ops smps_ops = { .enable = rpm_vreg_enable, .disable = rpm_vreg_disable, .is_enabled = rpm_vreg_is_enabled, .set_voltage = rpm_vreg_set_voltage, .get_voltage = rpm_vreg_get_voltage, .set_mode = rpm_vreg_set_mode, .get_mode = rpm_vreg_get_mode, .get_optimum_mode = rpm_vreg_get_optimum_mode, .enable_time = rpm_vreg_enable_time, }; static struct regulator_ops switch_ops = { .enable = rpm_vreg_enable, .disable = rpm_vreg_disable, .is_enabled = rpm_vreg_is_enabled, .enable_time = rpm_vreg_enable_time, }; static struct regulator_ops ncp_ops = { .enable = rpm_vreg_enable, .disable = rpm_vreg_disable, .is_enabled = rpm_vreg_is_enabled, .set_voltage = rpm_vreg_set_voltage, .get_voltage = rpm_vreg_get_voltage, .enable_time = rpm_vreg_enable_time, }; static struct regulator_ops bob_ops = { .enable = rpm_vreg_enable, .disable = rpm_vreg_disable, .is_enabled = rpm_vreg_is_enabled, .set_voltage = rpm_vreg_set_voltage, .get_voltage = rpm_vreg_get_voltage, .set_mode = rpm_vreg_set_bob_mode, .get_mode = rpm_vreg_get_bob_mode, .enable_time = rpm_vreg_enable_time, }; static struct regulator_ops *vreg_ops[] = { [RPM_REGULATOR_TYPE_LDO] = &ldo_ops, [RPM_REGULATOR_TYPE_SMPS] = &smps_ops, [RPM_REGULATOR_TYPE_VS] = &switch_ops, [RPM_REGULATOR_TYPE_NCP] = &ncp_ops, [RPM_REGULATOR_TYPE_BOB] = &bob_ops, }; static int rpm_vreg_device_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rpm_regulator *reg; struct rpm_vreg *rpm_vreg; reg = platform_get_drvdata(pdev); if (reg) { rpm_vreg = reg->rpm_vreg; rpm_vreg_lock(rpm_vreg); regulator_unregister(reg->rdev); list_del(®->list); kfree(reg); rpm_vreg_unlock(rpm_vreg); } else { dev_err(dev, "%s: drvdata missing\n", __func__); return -EINVAL; } platform_set_drvdata(pdev, NULL); return 0; } static int rpm_vreg_resource_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rpm_regulator *reg, *reg_temp; struct rpm_vreg *rpm_vreg; rpm_vreg = platform_get_drvdata(pdev); if (rpm_vreg) { rpm_vreg_lock(rpm_vreg); list_for_each_entry_safe(reg, reg_temp, &rpm_vreg->reg_list, list) { /* Only touch data for private consumers. */ if (reg->rdev->desc == NULL) { list_del(®->list); kfree(reg->rdev); kfree(reg); } else { dev_err(dev, "%s: not all child devices have been removed\n", __func__); } } rpm_vreg_unlock(rpm_vreg); msm_rpm_free_request(rpm_vreg->handle_active); msm_rpm_free_request(rpm_vreg->handle_sleep); kfree(rpm_vreg); } else { dev_err(dev, "%s: drvdata missing\n", __func__); return -EINVAL; } platform_set_drvdata(pdev, NULL); return 0; } static int rpm_vreg_set_smps_ldo_voltage_index(struct device *dev, struct rpm_regulator *reg) { struct device_node *node = dev->of_node; int chosen = 0; if (of_property_read_bool(node, "qcom,use-voltage-corner")) { reg->voltage_index = RPM_REGULATOR_PARAM_CORNER; reg->voltage_offset = RPM_REGULATOR_CORNER_NONE; chosen++; } if (of_property_read_bool(node, "qcom,use-voltage-floor-corner")) { reg->voltage_index = RPM_REGULATOR_PARAM_FLOOR_CORNER; reg->voltage_offset = RPM_REGULATOR_CORNER_NONE; chosen++; } if (of_property_read_bool(node, "qcom,use-voltage-level")) { reg->voltage_index = RPM_REGULATOR_PARAM_LEVEL; chosen++; } if (of_property_read_bool(node, "qcom,use-voltage-floor-level")) { reg->voltage_index = RPM_REGULATOR_PARAM_FLOOR_LEVEL; chosen++; } if (chosen > 1) { dev_err(dev, "only one qcom,use-voltage-* may be specified\n"); return -EINVAL; } return 0; } static int rpm_vreg_set_bob_voltage_index(struct device *dev, struct rpm_regulator *reg) { struct device_node *node = dev->of_node; int chosen = 0; if (of_property_read_bool(node, "qcom,use-pin-ctrl-voltage1")) { reg->voltage_index = RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE1; chosen++; } if (of_property_read_bool(node, "qcom,use-pin-ctrl-voltage2")) { reg->voltage_index = RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE2; chosen++; } if (of_property_read_bool(node, "qcom,use-pin-ctrl-voltage3")) { reg->voltage_index = RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE3; chosen++; } if (chosen > 1) { dev_err(dev, "only one qcom,use-pin-ctrl-voltage* may be specified\n"); return -EINVAL; } return 0; } static int rpm_vreg_device_set_voltage_index(struct device *dev, struct rpm_regulator *reg, int type) { int rc = 0; reg->voltage_index = RPM_REGULATOR_PARAM_VOLTAGE; switch (type) { case RPM_REGULATOR_TYPE_SMPS: case RPM_REGULATOR_TYPE_LDO: rc = rpm_vreg_set_smps_ldo_voltage_index(dev, reg); break; case RPM_REGULATOR_TYPE_BOB: rc = rpm_vreg_set_bob_voltage_index(dev, reg); break; } return rc; } /* * This probe is called for child rpm-regulator devices which have * properties which are required to configure individual regulator * framework regulators for a given RPM regulator resource. */ static int rpm_vreg_device_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; struct regulator_init_data *init_data; struct rpm_vreg *rpm_vreg; struct rpm_regulator *reg; struct regulator_config reg_config = {}; int rc = 0; int i, regulator_type; u32 val; if (!dev->of_node) { dev_err(dev, "%s: device tree information missing\n", __func__); return -ENODEV; } if (pdev->dev.parent == NULL) { dev_err(dev, "%s: parent device missing\n", __func__); return -ENODEV; } rpm_vreg = dev_get_drvdata(pdev->dev.parent); if (rpm_vreg == NULL) { dev_err(dev, "%s: rpm_vreg not found in parent device\n", __func__); return -ENODEV; } reg = kzalloc(sizeof(struct rpm_regulator), GFP_KERNEL); if (reg == NULL) { dev_err(dev, "%s: could not allocate memory for reg\n", __func__); return -ENOMEM; } regulator_type = rpm_vreg->regulator_type; reg->rpm_vreg = rpm_vreg; reg->rdesc.owner = THIS_MODULE; reg->rdesc.type = REGULATOR_VOLTAGE; reg->rdesc.ops = vreg_ops[regulator_type]; rc = rpm_vreg_device_set_voltage_index(dev, reg, regulator_type); if (rc) goto fail_free_reg; reg->always_send_voltage = of_property_read_bool(node, "qcom,always-send-voltage"); reg->always_send_current = of_property_read_bool(node, "qcom,always-send-current"); if (regulator_type == RPM_REGULATOR_TYPE_VS) reg->rdesc.n_voltages = 0; else reg->rdesc.n_voltages = 2; rc = of_property_read_u32(node, "qcom,set", &val); if (rc) { dev_err(dev, "%s: sleep set and/or active set must be configured via qcom,set property, rc=%d\n", __func__, rc); goto fail_free_reg; } else if (!(val & RPM_SET_CONFIG_BOTH)) { dev_err(dev, "%s: qcom,set=%u property is invalid\n", __func__, val); rc = -EINVAL; goto fail_free_reg; } reg->set_active = !!(val & RPM_SET_CONFIG_ACTIVE); reg->set_sleep = !!(val & RPM_SET_CONFIG_SLEEP); init_data = of_get_regulator_init_data(dev, node); if (init_data == NULL) { dev_err(dev, "%s: unable to allocate memory\n", __func__); rc = -ENOMEM; goto fail_free_reg; } if (init_data->constraints.name == NULL) { dev_err(dev, "%s: regulator name not specified\n", __func__); rc = -EINVAL; goto fail_free_reg; } init_data->constraints.input_uV = init_data->constraints.max_uV; if (of_get_property(node, "parent-supply", NULL)) init_data->supply_regulator = "parent"; /* * Fill in ops and mode masks based on callbacks specified for * this type of regulator. */ if (reg->rdesc.ops->enable) init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_STATUS; if (reg->rdesc.ops->get_voltage) init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE; if (reg->rdesc.ops->get_mode) { init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_DRMS; init_data->constraints.valid_modes_mask |= REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE; } reg->rdesc.name = init_data->constraints.name; reg->min_uV = init_data->constraints.min_uV; reg->max_uV = init_data->constraints.max_uV; /* Initialize the param array based on optional properties. */ for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) { rc = of_property_read_u32(node, params[i].property_name, &val); if (rc == 0) { if (params[i].supported_regulator_types & BIT(regulator_type)) { if (val < params[i].min || val > params[i].max) { pr_warn("%s: device tree property: %s=%u is outsided allowed range [%u, %u]\n", reg->rdesc.name, params[i].property_name, val, params[i].min, params[i].max); continue; } reg->req.param[i] = val; reg->req.modified |= BIT(i); } else { pr_warn("%s: regulator type=%d does not support device tree property: %s\n", reg->rdesc.name, regulator_type, params[i].property_name); } } } of_property_read_u32(node, "qcom,system-load", ®->system_load); rc = rpm_vreg_configure_pin_control_enable(reg, node); if (rc) { vreg_err(reg, "could not configure pin control enable, rc=%d\n", rc); goto fail_free_reg; } rpm_vreg_lock(rpm_vreg); list_add(®->list, &rpm_vreg->reg_list); rpm_vreg_unlock(rpm_vreg); if (of_property_read_bool(node, "qcom,send-defaults")) { rc = rpm_vreg_send_defaults(reg); if (rc) { vreg_err(reg, "could not send defaults, rc=%d\n", rc); goto fail_remove_from_list; } } reg_config.dev = dev; reg_config.init_data = init_data; reg_config.of_node = node; reg_config.driver_data = reg; reg->rdev = regulator_register(®->rdesc, ®_config); if (IS_ERR(reg->rdev)) { rc = PTR_ERR(reg->rdev); reg->rdev = NULL; pr_err("regulator_register failed: %s, rc=%d\n", reg->rdesc.name, rc); goto fail_remove_from_list; } platform_set_drvdata(pdev, reg); pr_debug("successfully probed: %s\n", reg->rdesc.name); return 0; fail_remove_from_list: rpm_vreg_lock(rpm_vreg); list_del(®->list); rpm_vreg_unlock(rpm_vreg); fail_free_reg: kfree(reg); return rc; } /* * This probe is called for parent rpm-regulator devices which have * properties which are required to identify a given RPM resource. */ static int rpm_vreg_resource_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; struct rpm_vreg *rpm_vreg; int val = 0; u32 resource_type; int rc; if (!dev->of_node) { dev_err(dev, "%s: device tree information missing\n", __func__); return -ENODEV; } /* Create new rpm_vreg entry. */ rpm_vreg = kzalloc(sizeof(struct rpm_vreg), GFP_KERNEL); if (rpm_vreg == NULL) { dev_err(dev, "%s: could not allocate memory for vreg\n", __func__); return -ENOMEM; } /* Required device tree properties: */ rc = of_property_read_string(node, "qcom,resource-name", &rpm_vreg->resource_name); if (rc) { dev_err(dev, "%s: qcom,resource-name missing in DT node\n", __func__); goto fail_free_vreg; } resource_type = rpm_vreg_string_to_int(rpm_vreg->resource_name); rc = of_property_read_u32(node, "qcom,resource-id", &rpm_vreg->resource_id); if (rc) { dev_err(dev, "%s: qcom,resource-id missing in DT node\n", __func__); goto fail_free_vreg; } rc = of_property_read_u32(node, "qcom,regulator-type", &rpm_vreg->regulator_type); if (rc) { dev_err(dev, "%s: qcom,regulator-type missing in DT node\n", __func__); goto fail_free_vreg; } if ((rpm_vreg->regulator_type < 0) || (rpm_vreg->regulator_type >= RPM_REGULATOR_TYPE_MAX)) { dev_err(dev, "%s: invalid regulator type: %d\n", __func__, rpm_vreg->regulator_type); rc = -EINVAL; goto fail_free_vreg; } /* Optional device tree properties: */ of_property_read_u32(node, "qcom,allow-atomic", &val); rpm_vreg->allow_atomic = !!val; of_property_read_u32(node, "qcom,enable-time", &rpm_vreg->enable_time); of_property_read_u32(node, "qcom,hpm-min-load", &rpm_vreg->hpm_min_load); rpm_vreg->apps_only = of_property_read_bool(node, "qcom,apps-only"); rpm_vreg->always_wait_for_ack = of_property_read_bool(node, "qcom,always-wait-for-ack"); rpm_vreg->handle_active = msm_rpm_create_request(RPM_SET_ACTIVE, resource_type, rpm_vreg->resource_id, RPM_REGULATOR_PARAM_MAX); if (rpm_vreg->handle_active == NULL || IS_ERR(rpm_vreg->handle_active)) { rc = PTR_ERR(rpm_vreg->handle_active); if (rc != -EPROBE_DEFER) dev_err(dev, "%s: failed to create active RPM handle, rc=%d\n", __func__, rc); goto fail_free_vreg; } rpm_vreg->handle_sleep = msm_rpm_create_request(RPM_SET_SLEEP, resource_type, rpm_vreg->resource_id, RPM_REGULATOR_PARAM_MAX); if (rpm_vreg->handle_sleep == NULL || IS_ERR(rpm_vreg->handle_sleep)) { rc = PTR_ERR(rpm_vreg->handle_sleep); if (rc != -EPROBE_DEFER) dev_err(dev, "%s: failed to create sleep RPM handle, rc=%d\n", __func__, rc); goto fail_free_handle_active; } INIT_LIST_HEAD(&rpm_vreg->reg_list); if (rpm_vreg->allow_atomic) spin_lock_init(&rpm_vreg->slock); else mutex_init(&rpm_vreg->mlock); platform_set_drvdata(pdev, rpm_vreg); rc = of_platform_populate(node, NULL, NULL, dev); if (rc) { dev_err(dev, "%s: failed to add child nodes, rc=%d\n", __func__, rc); goto fail_unset_drvdata; } pr_debug("successfully probed: %s (%08X) %u\n", rpm_vreg->resource_name, resource_type, rpm_vreg->resource_id); return rc; fail_unset_drvdata: platform_set_drvdata(pdev, NULL); msm_rpm_free_request(rpm_vreg->handle_sleep); fail_free_handle_active: msm_rpm_free_request(rpm_vreg->handle_active); fail_free_vreg: kfree(rpm_vreg); return rc; } static struct of_device_id rpm_vreg_match_table_device[] = { { .compatible = "qcom,rpm-smd-regulator", }, {} }; static struct of_device_id rpm_vreg_match_table_resource[] = { { .compatible = "qcom,rpm-smd-regulator-resource", }, {} }; static struct platform_driver rpm_vreg_device_driver = { .probe = rpm_vreg_device_probe, .remove = rpm_vreg_device_remove, .driver = { .name = "qcom,rpm-smd-regulator", .owner = THIS_MODULE, .of_match_table = rpm_vreg_match_table_device, }, }; static struct platform_driver rpm_vreg_resource_driver = { .probe = rpm_vreg_resource_probe, .remove = rpm_vreg_resource_remove, .driver = { .name = "qcom,rpm-smd-regulator-resource", .owner = THIS_MODULE, .of_match_table = rpm_vreg_match_table_resource, }, }; /** * rpm_smd_regulator_driver_init() - initialize the RPM SMD regulator drivers * * This function registers the RPM SMD regulator platform drivers. * * Returns 0 on success or errno on failure. */ int __init rpm_smd_regulator_driver_init(void) { static bool initialized; int i, rc; if (initialized) return 0; else initialized = true; /* Store parameter string names as integers */ for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) params[i].key = rpm_vreg_string_to_int(params[i].name); rc = platform_driver_register(&rpm_vreg_device_driver); if (rc) return rc; return platform_driver_register(&rpm_vreg_resource_driver); } EXPORT_SYMBOL(rpm_smd_regulator_driver_init); static void __exit rpm_vreg_exit(void) { platform_driver_unregister(&rpm_vreg_device_driver); platform_driver_unregister(&rpm_vreg_resource_driver); } arch_initcall(rpm_smd_regulator_driver_init); module_exit(rpm_vreg_exit); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MSM RPM SMD regulator driver");