1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2020 Samsung Electronics Co., Ltd. |
4 | * http://www.samsung.com/ |
5 | * Author: Marek Szyprowski <m.szyprowski@samsung.com> |
6 | * |
7 | * Simplified generic voltage coupler from regulator core.c |
8 | * The main difference is that it keeps current regulator voltage |
9 | * if consumers didn't apply their constraints yet. |
10 | */ |
11 | |
12 | #include <linux/init.h> |
13 | #include <linux/kernel.h> |
14 | #include <linux/of.h> |
15 | #include <linux/regulator/coupler.h> |
16 | #include <linux/regulator/driver.h> |
17 | #include <linux/regulator/machine.h> |
18 | |
19 | static int regulator_get_optimal_voltage(struct regulator_dev *rdev, |
20 | int *current_uV, |
21 | int *min_uV, int *max_uV, |
22 | suspend_state_t state) |
23 | { |
24 | struct coupling_desc *c_desc = &rdev->coupling_desc; |
25 | struct regulator_dev **c_rdevs = c_desc->coupled_rdevs; |
26 | struct regulation_constraints *constraints = rdev->constraints; |
27 | int desired_min_uV = 0, desired_max_uV = INT_MAX; |
28 | int max_current_uV = 0, min_current_uV = INT_MAX; |
29 | int highest_min_uV = 0, target_uV, possible_uV; |
30 | int i, ret, max_spread, n_coupled = c_desc->n_coupled; |
31 | bool done; |
32 | |
33 | *current_uV = -1; |
34 | |
35 | /* Find highest min desired voltage */ |
36 | for (i = 0; i < n_coupled; i++) { |
37 | int tmp_min = 0; |
38 | int tmp_max = INT_MAX; |
39 | |
40 | lockdep_assert_held_once(&c_rdevs[i]->mutex.base); |
41 | |
42 | ret = regulator_check_consumers(rdev: c_rdevs[i], |
43 | min_uV: &tmp_min, |
44 | max_uV: &tmp_max, state); |
45 | if (ret < 0) |
46 | return ret; |
47 | |
48 | if (tmp_min == 0) { |
49 | ret = regulator_get_voltage_rdev(rdev: c_rdevs[i]); |
50 | if (ret < 0) |
51 | return ret; |
52 | tmp_min = ret; |
53 | } |
54 | |
55 | /* apply constraints */ |
56 | ret = regulator_check_voltage(rdev: c_rdevs[i], min_uV: &tmp_min, max_uV: &tmp_max); |
57 | if (ret < 0) |
58 | return ret; |
59 | |
60 | highest_min_uV = max(highest_min_uV, tmp_min); |
61 | |
62 | if (i == 0) { |
63 | desired_min_uV = tmp_min; |
64 | desired_max_uV = tmp_max; |
65 | } |
66 | } |
67 | |
68 | max_spread = constraints->max_spread[0]; |
69 | |
70 | /* |
71 | * Let target_uV be equal to the desired one if possible. |
72 | * If not, set it to minimum voltage, allowed by other coupled |
73 | * regulators. |
74 | */ |
75 | target_uV = max(desired_min_uV, highest_min_uV - max_spread); |
76 | |
77 | /* |
78 | * Find min and max voltages, which currently aren't violating |
79 | * max_spread. |
80 | */ |
81 | for (i = 1; i < n_coupled; i++) { |
82 | int tmp_act; |
83 | |
84 | tmp_act = regulator_get_voltage_rdev(rdev: c_rdevs[i]); |
85 | if (tmp_act < 0) |
86 | return tmp_act; |
87 | |
88 | min_current_uV = min(tmp_act, min_current_uV); |
89 | max_current_uV = max(tmp_act, max_current_uV); |
90 | } |
91 | |
92 | /* |
93 | * Correct target voltage, so as it currently isn't |
94 | * violating max_spread |
95 | */ |
96 | possible_uV = max(target_uV, max_current_uV - max_spread); |
97 | possible_uV = min(possible_uV, min_current_uV + max_spread); |
98 | |
99 | if (possible_uV > desired_max_uV) |
100 | return -EINVAL; |
101 | |
102 | done = (possible_uV == target_uV); |
103 | desired_min_uV = possible_uV; |
104 | |
105 | /* Set current_uV if wasn't done earlier in the code and if necessary */ |
106 | if (*current_uV == -1) { |
107 | ret = regulator_get_voltage_rdev(rdev); |
108 | if (ret < 0) |
109 | return ret; |
110 | *current_uV = ret; |
111 | } |
112 | |
113 | *min_uV = desired_min_uV; |
114 | *max_uV = desired_max_uV; |
115 | |
116 | return done; |
117 | } |
118 | |
119 | static int exynos_coupler_balance_voltage(struct regulator_coupler *coupler, |
120 | struct regulator_dev *rdev, |
121 | suspend_state_t state) |
122 | { |
123 | struct regulator_dev **c_rdevs; |
124 | struct regulator_dev *best_rdev; |
125 | struct coupling_desc *c_desc = &rdev->coupling_desc; |
126 | int i, ret, n_coupled, best_min_uV, best_max_uV, best_c_rdev; |
127 | unsigned int delta, best_delta; |
128 | unsigned long c_rdev_done = 0; |
129 | bool best_c_rdev_done; |
130 | |
131 | c_rdevs = c_desc->coupled_rdevs; |
132 | n_coupled = c_desc->n_coupled; |
133 | |
134 | /* |
135 | * Find the best possible voltage change on each loop. Leave the loop |
136 | * if there isn't any possible change. |
137 | */ |
138 | do { |
139 | best_c_rdev_done = false; |
140 | best_delta = 0; |
141 | best_min_uV = 0; |
142 | best_max_uV = 0; |
143 | best_c_rdev = 0; |
144 | best_rdev = NULL; |
145 | |
146 | /* |
147 | * Find highest difference between optimal voltage |
148 | * and current voltage. |
149 | */ |
150 | for (i = 0; i < n_coupled; i++) { |
151 | /* |
152 | * optimal_uV is the best voltage that can be set for |
153 | * i-th regulator at the moment without violating |
154 | * max_spread constraint in order to balance |
155 | * the coupled voltages. |
156 | */ |
157 | int optimal_uV = 0, optimal_max_uV = 0, current_uV = 0; |
158 | |
159 | if (test_bit(i, &c_rdev_done)) |
160 | continue; |
161 | |
162 | ret = regulator_get_optimal_voltage(rdev: c_rdevs[i], |
163 | current_uV: ¤t_uV, |
164 | min_uV: &optimal_uV, |
165 | max_uV: &optimal_max_uV, |
166 | state); |
167 | if (ret < 0) |
168 | goto out; |
169 | |
170 | delta = abs(optimal_uV - current_uV); |
171 | |
172 | if (delta && best_delta <= delta) { |
173 | best_c_rdev_done = ret; |
174 | best_delta = delta; |
175 | best_rdev = c_rdevs[i]; |
176 | best_min_uV = optimal_uV; |
177 | best_max_uV = optimal_max_uV; |
178 | best_c_rdev = i; |
179 | } |
180 | } |
181 | |
182 | /* Nothing to change, return successfully */ |
183 | if (!best_rdev) { |
184 | ret = 0; |
185 | goto out; |
186 | } |
187 | |
188 | ret = regulator_set_voltage_rdev(rdev: best_rdev, min_uV: best_min_uV, |
189 | max_uV: best_max_uV, state); |
190 | |
191 | if (ret < 0) |
192 | goto out; |
193 | |
194 | if (best_c_rdev_done) |
195 | set_bit(nr: best_c_rdev, addr: &c_rdev_done); |
196 | |
197 | } while (n_coupled > 1); |
198 | |
199 | out: |
200 | return ret; |
201 | } |
202 | |
203 | static int exynos_coupler_attach(struct regulator_coupler *coupler, |
204 | struct regulator_dev *rdev) |
205 | { |
206 | return 0; |
207 | } |
208 | |
209 | static struct regulator_coupler exynos_coupler = { |
210 | .attach_regulator = exynos_coupler_attach, |
211 | .balance_voltage = exynos_coupler_balance_voltage, |
212 | }; |
213 | |
214 | static int __init exynos_coupler_init(void) |
215 | { |
216 | if (!of_machine_is_compatible(compat: "samsung,exynos5800" )) |
217 | return 0; |
218 | |
219 | return regulator_coupler_register(coupler: &exynos_coupler); |
220 | } |
221 | arch_initcall(exynos_coupler_init); |
222 | |