162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2020 Samsung Electronics Co., Ltd. 462306a36Sopenharmony_ci * http://www.samsung.com/ 562306a36Sopenharmony_ci * Author: Marek Szyprowski <m.szyprowski@samsung.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Simplified generic voltage coupler from regulator core.c 862306a36Sopenharmony_ci * The main difference is that it keeps current regulator voltage 962306a36Sopenharmony_ci * if consumers didn't apply their constraints yet. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/of.h> 1562306a36Sopenharmony_ci#include <linux/regulator/coupler.h> 1662306a36Sopenharmony_ci#include <linux/regulator/driver.h> 1762306a36Sopenharmony_ci#include <linux/regulator/machine.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic int regulator_get_optimal_voltage(struct regulator_dev *rdev, 2062306a36Sopenharmony_ci int *current_uV, 2162306a36Sopenharmony_ci int *min_uV, int *max_uV, 2262306a36Sopenharmony_ci suspend_state_t state) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci struct coupling_desc *c_desc = &rdev->coupling_desc; 2562306a36Sopenharmony_ci struct regulator_dev **c_rdevs = c_desc->coupled_rdevs; 2662306a36Sopenharmony_ci struct regulation_constraints *constraints = rdev->constraints; 2762306a36Sopenharmony_ci int desired_min_uV = 0, desired_max_uV = INT_MAX; 2862306a36Sopenharmony_ci int max_current_uV = 0, min_current_uV = INT_MAX; 2962306a36Sopenharmony_ci int highest_min_uV = 0, target_uV, possible_uV; 3062306a36Sopenharmony_ci int i, ret, max_spread, n_coupled = c_desc->n_coupled; 3162306a36Sopenharmony_ci bool done; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci *current_uV = -1; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci /* Find highest min desired voltage */ 3662306a36Sopenharmony_ci for (i = 0; i < n_coupled; i++) { 3762306a36Sopenharmony_ci int tmp_min = 0; 3862306a36Sopenharmony_ci int tmp_max = INT_MAX; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci lockdep_assert_held_once(&c_rdevs[i]->mutex.base); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci ret = regulator_check_consumers(c_rdevs[i], 4362306a36Sopenharmony_ci &tmp_min, 4462306a36Sopenharmony_ci &tmp_max, state); 4562306a36Sopenharmony_ci if (ret < 0) 4662306a36Sopenharmony_ci return ret; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (tmp_min == 0) { 4962306a36Sopenharmony_ci ret = regulator_get_voltage_rdev(c_rdevs[i]); 5062306a36Sopenharmony_ci if (ret < 0) 5162306a36Sopenharmony_ci return ret; 5262306a36Sopenharmony_ci tmp_min = ret; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* apply constraints */ 5662306a36Sopenharmony_ci ret = regulator_check_voltage(c_rdevs[i], &tmp_min, &tmp_max); 5762306a36Sopenharmony_ci if (ret < 0) 5862306a36Sopenharmony_ci return ret; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci highest_min_uV = max(highest_min_uV, tmp_min); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (i == 0) { 6362306a36Sopenharmony_ci desired_min_uV = tmp_min; 6462306a36Sopenharmony_ci desired_max_uV = tmp_max; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci max_spread = constraints->max_spread[0]; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* 7162306a36Sopenharmony_ci * Let target_uV be equal to the desired one if possible. 7262306a36Sopenharmony_ci * If not, set it to minimum voltage, allowed by other coupled 7362306a36Sopenharmony_ci * regulators. 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci target_uV = max(desired_min_uV, highest_min_uV - max_spread); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* 7862306a36Sopenharmony_ci * Find min and max voltages, which currently aren't violating 7962306a36Sopenharmony_ci * max_spread. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci for (i = 1; i < n_coupled; i++) { 8262306a36Sopenharmony_ci int tmp_act; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci tmp_act = regulator_get_voltage_rdev(c_rdevs[i]); 8562306a36Sopenharmony_ci if (tmp_act < 0) 8662306a36Sopenharmony_ci return tmp_act; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci min_current_uV = min(tmp_act, min_current_uV); 8962306a36Sopenharmony_ci max_current_uV = max(tmp_act, max_current_uV); 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* 9362306a36Sopenharmony_ci * Correct target voltage, so as it currently isn't 9462306a36Sopenharmony_ci * violating max_spread 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ci possible_uV = max(target_uV, max_current_uV - max_spread); 9762306a36Sopenharmony_ci possible_uV = min(possible_uV, min_current_uV + max_spread); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (possible_uV > desired_max_uV) 10062306a36Sopenharmony_ci return -EINVAL; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci done = (possible_uV == target_uV); 10362306a36Sopenharmony_ci desired_min_uV = possible_uV; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* Set current_uV if wasn't done earlier in the code and if necessary */ 10662306a36Sopenharmony_ci if (*current_uV == -1) { 10762306a36Sopenharmony_ci ret = regulator_get_voltage_rdev(rdev); 10862306a36Sopenharmony_ci if (ret < 0) 10962306a36Sopenharmony_ci return ret; 11062306a36Sopenharmony_ci *current_uV = ret; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci *min_uV = desired_min_uV; 11462306a36Sopenharmony_ci *max_uV = desired_max_uV; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci return done; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int exynos_coupler_balance_voltage(struct regulator_coupler *coupler, 12062306a36Sopenharmony_ci struct regulator_dev *rdev, 12162306a36Sopenharmony_ci suspend_state_t state) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct regulator_dev **c_rdevs; 12462306a36Sopenharmony_ci struct regulator_dev *best_rdev; 12562306a36Sopenharmony_ci struct coupling_desc *c_desc = &rdev->coupling_desc; 12662306a36Sopenharmony_ci int i, ret, n_coupled, best_min_uV, best_max_uV, best_c_rdev; 12762306a36Sopenharmony_ci unsigned int delta, best_delta; 12862306a36Sopenharmony_ci unsigned long c_rdev_done = 0; 12962306a36Sopenharmony_ci bool best_c_rdev_done; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci c_rdevs = c_desc->coupled_rdevs; 13262306a36Sopenharmony_ci n_coupled = c_desc->n_coupled; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* 13562306a36Sopenharmony_ci * Find the best possible voltage change on each loop. Leave the loop 13662306a36Sopenharmony_ci * if there isn't any possible change. 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_ci do { 13962306a36Sopenharmony_ci best_c_rdev_done = false; 14062306a36Sopenharmony_ci best_delta = 0; 14162306a36Sopenharmony_ci best_min_uV = 0; 14262306a36Sopenharmony_ci best_max_uV = 0; 14362306a36Sopenharmony_ci best_c_rdev = 0; 14462306a36Sopenharmony_ci best_rdev = NULL; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* 14762306a36Sopenharmony_ci * Find highest difference between optimal voltage 14862306a36Sopenharmony_ci * and current voltage. 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci for (i = 0; i < n_coupled; i++) { 15162306a36Sopenharmony_ci /* 15262306a36Sopenharmony_ci * optimal_uV is the best voltage that can be set for 15362306a36Sopenharmony_ci * i-th regulator at the moment without violating 15462306a36Sopenharmony_ci * max_spread constraint in order to balance 15562306a36Sopenharmony_ci * the coupled voltages. 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_ci int optimal_uV = 0, optimal_max_uV = 0, current_uV = 0; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (test_bit(i, &c_rdev_done)) 16062306a36Sopenharmony_ci continue; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci ret = regulator_get_optimal_voltage(c_rdevs[i], 16362306a36Sopenharmony_ci ¤t_uV, 16462306a36Sopenharmony_ci &optimal_uV, 16562306a36Sopenharmony_ci &optimal_max_uV, 16662306a36Sopenharmony_ci state); 16762306a36Sopenharmony_ci if (ret < 0) 16862306a36Sopenharmony_ci goto out; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci delta = abs(optimal_uV - current_uV); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (delta && best_delta <= delta) { 17362306a36Sopenharmony_ci best_c_rdev_done = ret; 17462306a36Sopenharmony_ci best_delta = delta; 17562306a36Sopenharmony_ci best_rdev = c_rdevs[i]; 17662306a36Sopenharmony_ci best_min_uV = optimal_uV; 17762306a36Sopenharmony_ci best_max_uV = optimal_max_uV; 17862306a36Sopenharmony_ci best_c_rdev = i; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* Nothing to change, return successfully */ 18362306a36Sopenharmony_ci if (!best_rdev) { 18462306a36Sopenharmony_ci ret = 0; 18562306a36Sopenharmony_ci goto out; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci ret = regulator_set_voltage_rdev(best_rdev, best_min_uV, 18962306a36Sopenharmony_ci best_max_uV, state); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (ret < 0) 19262306a36Sopenharmony_ci goto out; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (best_c_rdev_done) 19562306a36Sopenharmony_ci set_bit(best_c_rdev, &c_rdev_done); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci } while (n_coupled > 1); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ciout: 20062306a36Sopenharmony_ci return ret; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int exynos_coupler_attach(struct regulator_coupler *coupler, 20462306a36Sopenharmony_ci struct regulator_dev *rdev) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci return 0; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic struct regulator_coupler exynos_coupler = { 21062306a36Sopenharmony_ci .attach_regulator = exynos_coupler_attach, 21162306a36Sopenharmony_ci .balance_voltage = exynos_coupler_balance_voltage, 21262306a36Sopenharmony_ci}; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic int __init exynos_coupler_init(void) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci if (!of_machine_is_compatible("samsung,exynos5800")) 21762306a36Sopenharmony_ci return 0; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci return regulator_coupler_register(&exynos_coupler); 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ciarch_initcall(exynos_coupler_init); 222