blob: 2dc261d83e3727a5b2f72a5d13c1ef17a9677a8c [file] [log] [blame]
Caleb Connollyc0e6aa62024-07-15 12:08:15 +02001// SPDX-License-Identifier: GPL-2.0
2// Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
3// Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
4
5#define pr_fmt(fmt) "%s: " fmt, __func__
6
7#include <linux/err.h>
Caleb Connolly812aacf2024-07-15 12:08:16 +02008#include <dm/device_compat.h>
9#include <dm/device.h>
10#include <dm/devres.h>
11#include <dm/lists.h>
12#include <power/regulator.h>
13#include <log.h>
Caleb Connollyc0e6aa62024-07-15 12:08:15 +020014
15#include <soc/qcom/cmd-db.h>
16#include <soc/qcom/rpmh.h>
17
18#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
19
20/**
21 * enum rpmh_regulator_type - supported RPMh accelerator types
22 * @VRM: RPMh VRM accelerator which supports voting on enable, voltage,
23 * and mode of LDO, SMPS, and BOB type PMIC regulators.
24 * @XOB: RPMh XOB accelerator which supports voting on the enable state
25 * of PMIC regulators.
26 */
27enum rpmh_regulator_type {
28 VRM,
29 XOB,
30};
31
Caleb Connolly924d9a72024-07-15 12:08:17 +020032enum rpmh_regulator_mode {
33 REGULATOR_MODE_RETENTION,
34 REGULATOR_MODE_LPM,
35 REGULATOR_MODE_AUTO,
36 REGULATOR_MODE_HPM,
37};
38
Caleb Connollyc0e6aa62024-07-15 12:08:15 +020039#define RPMH_REGULATOR_REG_VRM_VOLTAGE 0x0
40#define RPMH_REGULATOR_REG_ENABLE 0x4
41#define RPMH_REGULATOR_REG_VRM_MODE 0x8
42
43#define PMIC4_LDO_MODE_RETENTION 4
44#define PMIC4_LDO_MODE_LPM 5
45#define PMIC4_LDO_MODE_HPM 7
46
47#define PMIC4_SMPS_MODE_RETENTION 4
48#define PMIC4_SMPS_MODE_PFM 5
49#define PMIC4_SMPS_MODE_AUTO 6
50#define PMIC4_SMPS_MODE_PWM 7
51
52#define PMIC4_BOB_MODE_PASS 0
53#define PMIC4_BOB_MODE_PFM 1
54#define PMIC4_BOB_MODE_AUTO 2
55#define PMIC4_BOB_MODE_PWM 3
56
57#define PMIC5_LDO_MODE_RETENTION 3
58#define PMIC5_LDO_MODE_LPM 4
59#define PMIC5_LDO_MODE_HPM 7
60
61#define PMIC5_SMPS_MODE_RETENTION 3
62#define PMIC5_SMPS_MODE_PFM 4
63#define PMIC5_SMPS_MODE_AUTO 6
64#define PMIC5_SMPS_MODE_PWM 7
65
66#define PMIC5_BOB_MODE_PASS 2
67#define PMIC5_BOB_MODE_PFM 4
68#define PMIC5_BOB_MODE_AUTO 6
69#define PMIC5_BOB_MODE_PWM 7
70
Caleb Connolly924d9a72024-07-15 12:08:17 +020071
72/**
73 * struct linear_range - table of selector - value pairs
74 *
75 * Define a lookup-table for range of values. Intended to help when looking
76 * for a register value matching certaing physical measure (like voltage).
77 * Usable when increment of one in register always results a constant increment
78 * of the physical measure (like voltage).
79 *
80 * @min: Lowest value in range
81 * @min_sel: Lowest selector for range
82 * @max_sel: Highest selector for range
83 * @step: Value step size
84 */
85struct linear_range {
86 unsigned int min;
87 unsigned int min_sel;
88 unsigned int max_sel;
89 unsigned int step;
90};
91
92/* Initialize struct linear_range for regulators */
93#define REGULATOR_LINEAR_RANGE(_min_uV, _min_sel, _max_sel, _step_uV) \
94{ \
95 .min = _min_uV, \
96 .min_sel = _min_sel, \
97 .max_sel = _max_sel, \
98 .step = _step_uV, \
99}
100
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200101/**
102 * struct rpmh_vreg_hw_data - RPMh regulator hardware configurations
103 * @regulator_type: RPMh accelerator type used to manage this
104 * regulator
105 * @ops: Pointer to regulator ops callback structure
Caleb Connollyc4c9cc02024-07-15 12:08:18 +0200106 * @voltage_range: The single range of voltages supported by this
107 * PMIC regulator type
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200108 * @n_voltages: The number of unique voltage set points defined
Caleb Connollyc4c9cc02024-07-15 12:08:18 +0200109 * by voltage_range
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200110 * @hpm_min_load_uA: Minimum load current in microamps that requires
111 * high power mode (HPM) operation. This is used
112 * for LDO hardware type regulators only.
113 * @pmic_mode_map: Array indexed by regulator framework mode
114 * containing PMIC hardware modes. Must be large
115 * enough to index all framework modes supported
116 * by this regulator hardware type.
117 * @of_map_mode: Maps an RPMH_REGULATOR_MODE_* mode value defined
118 * in device tree to a regulator framework mode
119 */
120struct rpmh_vreg_hw_data {
121 enum rpmh_regulator_type regulator_type;
Caleb Connollyc4c9cc02024-07-15 12:08:18 +0200122 const struct dm_regulator_ops *ops;
123 struct linear_range voltage_range;
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200124 int n_voltages;
125 int hpm_min_load_uA;
Caleb Connollyc4c9cc02024-07-15 12:08:18 +0200126 struct dm_regulator_mode *pmic_mode_map;
127 int n_modes;
128 unsigned int (*of_map_mode)(unsigned int mode);
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200129};
130
131/**
132 * struct rpmh_vreg - individual RPMh regulator data structure encapsulating a
133 * single regulator device
134 * @dev: Device pointer for the top-level PMIC RPMh
135 * regulator parent device. This is used as a
136 * handle in RPMh write requests.
137 * @addr: Base address of the regulator resource within
138 * an RPMh accelerator
139 * @rdesc: Regulator descriptor
140 * @hw_data: PMIC regulator configuration data for this RPMh
141 * regulator
142 * @always_wait_for_ack: Boolean flag indicating if a request must always
143 * wait for an ACK from RPMh before continuing even
144 * if it corresponds to a strictly lower power
145 * state (e.g. enabled --> disabled).
146 * @enabled: Flag indicating if the regulator is enabled or
147 * not
148 * @bypassed: Boolean indicating if the regulator is in
149 * bypass (pass-through) mode or not. This is
150 * only used by BOB rpmh-regulator resources.
Caleb Connollyc4c9cc02024-07-15 12:08:18 +0200151 * @uv: Selector used for get_voltage_sel() and
152 * set_value() callbacks
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200153 * @mode: RPMh VRM regulator current framework mode
154 */
155struct rpmh_vreg {
Caleb Connollyc4c9cc02024-07-15 12:08:18 +0200156 struct udevice *dev;
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200157 u32 addr;
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200158 const struct rpmh_vreg_hw_data *hw_data;
159 bool always_wait_for_ack;
160
161 int enabled;
162 bool bypassed;
Caleb Connollyc4c9cc02024-07-15 12:08:18 +0200163 int uv;
164 int mode;
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200165};
166
167/**
168 * struct rpmh_vreg_init_data - initialization data for an RPMh regulator
169 * @name: Name for the regulator which also corresponds
170 * to the device tree subnode name of the regulator
171 * @resource_name: RPMh regulator resource name format string.
172 * This must include exactly one field: '%s' which
173 * is filled at run-time with the PMIC ID provided
174 * by device tree property qcom,pmic-id. Example:
175 * "ldo%s1" for RPMh resource "ldoa1".
176 * @supply_name: Parent supply regulator name
177 * @hw_data: Configuration data for this PMIC regulator type
178 */
179struct rpmh_vreg_init_data {
180 const char *name;
181 const char *resource_name;
182 const char *supply_name;
183 const struct rpmh_vreg_hw_data *hw_data;
184};
185
186/**
187 * rpmh_regulator_send_request() - send the request to RPMh
188 * @vreg: Pointer to the RPMh regulator
189 * @cmd: Pointer to the RPMh command to send
190 * @wait_for_ack: Boolean indicating if execution must wait until the
191 * request has been acknowledged as complete
192 *
193 * Return: 0 on success, errno on failure
194 */
195static int rpmh_regulator_send_request(struct rpmh_vreg *vreg,
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200196 const struct tcs_cmd *cmd, bool wait_for_ack)
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200197{
198 int ret;
199
200 if (wait_for_ack || vreg->always_wait_for_ack)
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200201 ret = rpmh_write(vreg->dev->parent, RPMH_ACTIVE_ONLY_STATE, cmd, 1);
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200202 else
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200203 ret = rpmh_write_async(vreg->dev->parent, RPMH_ACTIVE_ONLY_STATE, cmd, 1);
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200204
205 return ret;
206}
207
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200208static int _rpmh_regulator_vrm_set_value(struct udevice *rdev,
209 int uv, bool wait_for_ack)
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200210{
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200211 struct rpmh_vreg *vreg = dev_get_priv(rdev);
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200212 struct tcs_cmd cmd = {
213 .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_VOLTAGE,
214 };
215 int ret;
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200216 unsigned int selector;
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200217
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200218 selector = (uv - vreg->hw_data->voltage_range.min) / vreg->hw_data->voltage_range.step;
219 cmd.data = DIV_ROUND_UP(vreg->hw_data->voltage_range.min +
220 selector * vreg->hw_data->voltage_range.step, 1000);
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200221
222 ret = rpmh_regulator_send_request(vreg, &cmd, wait_for_ack);
223 if (!ret)
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200224 vreg->uv = cmd.data * 1000;
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200225
226 return ret;
227}
228
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200229static int rpmh_regulator_vrm_set_value(struct udevice *rdev,
230 int uv)
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200231{
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200232 struct rpmh_vreg *vreg = dev_get_priv(rdev);
233
234 debug("%s: set_value %d (current %d)\n", rdev->name, uv, vreg->uv);
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200235
236 if (vreg->enabled == -EINVAL) {
237 /*
238 * Cache the voltage and send it later when the regulator is
239 * enabled or disabled.
240 */
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200241 vreg->uv = uv;
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200242 return 0;
243 }
244
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200245 return _rpmh_regulator_vrm_set_value(rdev, uv,
246 uv > vreg->uv);
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200247}
248
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200249static int rpmh_regulator_vrm_get_value(struct udevice *rdev)
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200250{
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200251 struct rpmh_vreg *vreg = dev_get_priv(rdev);
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200252
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200253 debug("%s: get_value %d\n", rdev->name, vreg->uv);
254
255 return vreg->uv;
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200256}
257
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200258static int rpmh_regulator_is_enabled(struct udevice *rdev)
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200259{
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200260 struct rpmh_vreg *vreg = dev_get_priv(rdev);
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200261
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200262 debug("%s: is_enabled %d\n", rdev->name, vreg->enabled);
263
264 return vreg->enabled > 0;
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200265}
266
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200267static int rpmh_regulator_set_enable_state(struct udevice *rdev,
268 bool enable)
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200269{
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200270 struct rpmh_vreg *vreg = dev_get_priv(rdev);
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200271 struct tcs_cmd cmd = {
272 .addr = vreg->addr + RPMH_REGULATOR_REG_ENABLE,
273 .data = enable,
274 };
275 int ret;
276
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200277 debug("%s: set_enable %d (current %d)\n", rdev->name, enable,
278 vreg->enabled);
279
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200280 if (vreg->enabled == -EINVAL &&
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200281 vreg->uv != -ENOTRECOVERABLE) {
282 ret = _rpmh_regulator_vrm_set_value(rdev,
283 vreg->uv, true);
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200284 if (ret < 0)
285 return ret;
286 }
287
288 ret = rpmh_regulator_send_request(vreg, &cmd, enable);
289 if (!ret)
290 vreg->enabled = enable;
291
292 return ret;
293}
294
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200295static int rpmh_regulator_vrm_set_mode_bypass(struct rpmh_vreg *vreg,
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200296 unsigned int mode, bool bypassed)
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200297{
298 struct tcs_cmd cmd = {
299 .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_MODE,
300 };
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200301 struct dm_regulator_mode *pmic_mode;
302 int i;
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200303
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200304 if (mode > REGULATOR_MODE_HPM)
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200305 return -EINVAL;
306
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200307 for (i = 0; i < vreg->hw_data->n_modes; i++) {
308 pmic_mode = &vreg->hw_data->pmic_mode_map[i];
309 if (pmic_mode->id == mode)
310 break;
311 }
312 if (pmic_mode->id != mode) {
313 printf("Invalid mode %d\n", mode);
314 return -EINVAL;
315 }
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200316
317 if (bypassed)
318 cmd.data = PMIC4_BOB_MODE_PASS;
319 else
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200320 cmd.data = pmic_mode->id;
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200321
322 return rpmh_regulator_send_request(vreg, &cmd, true);
323}
324
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200325static int rpmh_regulator_vrm_set_mode(struct udevice *rdev,
326 int mode)
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200327{
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200328 struct rpmh_vreg *vreg = dev_get_priv(rdev);
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200329 int ret;
330
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200331 debug("%s: set_mode %d (current %d)\n", rdev->name, mode, vreg->mode);
332
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200333 if (mode == vreg->mode)
334 return 0;
335
336 ret = rpmh_regulator_vrm_set_mode_bypass(vreg, mode, vreg->bypassed);
337 if (!ret)
338 vreg->mode = mode;
339
340 return ret;
341}
342
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200343static int rpmh_regulator_vrm_get_mode(struct udevice *rdev)
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200344{
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200345 struct rpmh_vreg *vreg = dev_get_priv(rdev);
346
347 debug("%s: get_mode %d\n", rdev->name, vreg->mode);
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200348
349 return vreg->mode;
350}
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200351static const struct dm_regulator_ops rpmh_regulator_vrm_drms_ops = {
352 .get_value = rpmh_regulator_vrm_get_value,
353 .set_value = rpmh_regulator_vrm_set_value,
354 .set_enable = rpmh_regulator_set_enable_state,
355 .get_enable = rpmh_regulator_is_enabled,
356 .set_mode = rpmh_regulator_vrm_set_mode,
357 .get_mode = rpmh_regulator_vrm_get_mode,
358};
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200359
Neil Armstrongcc65ee92024-09-03 18:13:31 +0200360static struct dm_regulator_mode pmic_mode_map_pmic5_bob[] = {
361 {
362 .id = REGULATOR_MODE_LPM,
363 .register_value = PMIC5_BOB_MODE_PFM,
364 .name = "PMIC5_BOB_MODE_PFM"
365 }, {
366 .id = REGULATOR_MODE_AUTO,
367 .register_value = PMIC5_BOB_MODE_AUTO,
368 .name = "PMIC5_BOB_MODE_AUTO"
369 }, {
370 .id = REGULATOR_MODE_HPM,
371 .register_value = PMIC5_BOB_MODE_PWM,
372 .name = "PMIC5_BOB_MODE_PWM"
373 },
374};
375
376static struct dm_regulator_mode pmic_mode_map_pmic5_smps[] = {
377 {
378 .id = REGULATOR_MODE_RETENTION,
379 .register_value = PMIC5_SMPS_MODE_RETENTION,
380 .name = "PMIC5_SMPS_MODE_RETENTION"
381 }, {
382 .id = REGULATOR_MODE_LPM,
383 .register_value = PMIC5_SMPS_MODE_PFM,
384 .name = "PMIC5_SMPS_MODE_PFM"
385 }, {
386 .id = REGULATOR_MODE_AUTO,
387 .register_value = PMIC5_SMPS_MODE_AUTO,
388 .name = "PMIC5_SMPS_MODE_AUTO"
389 }, {
390 .id = REGULATOR_MODE_HPM,
391 .register_value = PMIC5_SMPS_MODE_PWM,
392 .name = "PMIC5_SMPS_MODE_PWM"
393 },
394};
395
396static const struct rpmh_vreg_hw_data pmic5_bob = {
397 .regulator_type = VRM,
398 .ops = &rpmh_regulator_vrm_drms_ops,
399 .voltage_range = REGULATOR_LINEAR_RANGE(3000000, 0, 31, 32000),
400 .n_voltages = 32,
401 .pmic_mode_map = pmic_mode_map_pmic5_bob,
402 .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_bob),
403};
404
405static const struct rpmh_vreg_hw_data pmic5_ftsmps525_lv = {
406 .regulator_type = VRM,
407 .ops = &rpmh_regulator_vrm_drms_ops,
408 .voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 267, 4000),
409 .n_voltages = 268,
410 .pmic_mode_map = pmic_mode_map_pmic5_smps,
411 .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_smps),
412};
413
414static const struct rpmh_vreg_hw_data pmic5_ftsmps525_mv = {
415 .regulator_type = VRM,
416 .ops = &rpmh_regulator_vrm_drms_ops,
417 .voltage_range = REGULATOR_LINEAR_RANGE(600000, 0, 267, 8000),
418 .n_voltages = 268,
419 .pmic_mode_map = pmic_mode_map_pmic5_smps,
420 .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_smps),
421};
422
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200423static struct dm_regulator_mode pmic_mode_map_pmic5_ldo[] = {
424 {
425 .id = REGULATOR_MODE_RETENTION,
426 .register_value = PMIC5_LDO_MODE_RETENTION,
427 .name = "PMIC5_LDO_MODE_RETENTION"
428 }, {
429 .id = REGULATOR_MODE_LPM,
430 .register_value = PMIC5_LDO_MODE_LPM,
431 .name = "PMIC5_LDO_MODE_LPM"
432 }, {
433 .id = REGULATOR_MODE_HPM,
434 .register_value = PMIC5_LDO_MODE_HPM,
435 .name = "PMIC5_LDO_MODE_HPM"
436 },
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200437};
438
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200439static const struct rpmh_vreg_hw_data pmic5_pldo = {
440 .regulator_type = VRM,
441 .ops = &rpmh_regulator_vrm_drms_ops,
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200442 .voltage_range = REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000),
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200443 .n_voltages = 256,
444 .hpm_min_load_uA = 10000,
445 .pmic_mode_map = pmic_mode_map_pmic5_ldo,
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200446 .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo),
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200447};
448
449static const struct rpmh_vreg_hw_data pmic5_pldo_lv = {
450 .regulator_type = VRM,
451 .ops = &rpmh_regulator_vrm_drms_ops,
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200452 .voltage_range = REGULATOR_LINEAR_RANGE(1504000, 0, 62, 8000),
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200453 .n_voltages = 63,
454 .hpm_min_load_uA = 10000,
455 .pmic_mode_map = pmic_mode_map_pmic5_ldo,
Caleb Connollyf0e5db52024-07-15 12:08:20 +0200456 .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo),
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200457};
458
Neil Armstrongcc65ee92024-09-03 18:13:31 +0200459static const struct rpmh_vreg_hw_data pmic5_nldo515 = {
460 .regulator_type = VRM,
461 .ops = &rpmh_regulator_vrm_drms_ops,
462 .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 210, 8000),
463 .n_voltages = 211,
464 .hpm_min_load_uA = 30000,
465 .pmic_mode_map = pmic_mode_map_pmic5_ldo,
466 .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo),
467};
468
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200469#define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \
470{ \
471 .name = _name, \
472 .resource_name = _resource_name, \
473 .hw_data = _hw_data, \
474 .supply_name = _supply_name, \
475}
476
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200477static const struct rpmh_vreg_init_data pm8150_vreg_data[] = {
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200478 RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l16-l17"),
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200479 {}
480};
481
482static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = {
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200483 RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l8"),
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200484 RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"),
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200485 {}
486};
487
Neil Armstrongcc65ee92024-09-03 18:13:31 +0200488static const struct rpmh_vreg_init_data pm8550_vreg_data[] = {
489 RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1-l4-l10"),
490 RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l13-l14"),
491 RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
492 RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-l1-l4-l10"),
493 RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l16"),
494 RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l6-l7"),
495 RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l6-l7"),
496 RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, "vdd-l8-l9"),
497 RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l8-l9"),
498 RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo515, "vdd-l1-l4-l10"),
499 RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo515, "vdd-l11"),
500 RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo515, "vdd-l12"),
501 RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l2-l13-l14"),
502 RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo, "vdd-l2-l13-l14"),
503 RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo515, "vdd-l15"),
504 RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l5-l16"),
505 RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l17"),
506 RPMH_VREG("bob1", "bob%s1", &pmic5_bob, "vdd-bob1"),
507 RPMH_VREG("bob2", "bob%s2", &pmic5_bob, "vdd-bob2"),
508 {}
509};
510
511static const struct rpmh_vreg_init_data pm8550vs_vreg_data[] = {
512 RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
513 RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
514 RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
515 RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_lv, "vdd-s4"),
516 RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
517 RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_mv, "vdd-s6"),
518 RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
519 RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"),
520 RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
521 {}
522};
523
524static const struct rpmh_vreg_init_data pm8550ve_vreg_data[] = {
525 RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
526 RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
527 RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
528 RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"),
529 RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
530 RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"),
531 RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"),
532 RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"),
533 RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
534 RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"),
535 RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
536 {}
537};
538
Caleb Connollyc58644d2024-07-15 12:08:21 +0200539/* probe an individual regulator */
540static int rpmh_regulator_probe(struct udevice *dev)
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200541{
Caleb Connollyc58644d2024-07-15 12:08:21 +0200542 const struct rpmh_vreg_init_data *init_data;
543 struct rpmh_vreg *priv;
544 struct dm_regulator_uclass_plat *plat_data;
545
546 init_data = (const struct rpmh_vreg_init_data *)dev_get_driver_data(dev);
547 priv = dev_get_priv(dev);
548 plat_data = dev_get_uclass_plat(dev);
549
550 priv->dev = dev;
551 priv->addr = cmd_db_read_addr(dev->name);
552 if (!priv->addr) {
553 dev_err(dev, "Failed to read RPMh address for %s\n", dev->name);
554 return -ENODEV;
555 }
556
557 priv->hw_data = init_data->hw_data;
558 priv->enabled = -EINVAL;
559 priv->uv = -ENOTRECOVERABLE;
560 if (ofnode_read_u32(dev_ofnode(dev), "regulator-initial-mode", &priv->mode))
561 priv->mode = -EINVAL;
562
563 plat_data->mode = priv->hw_data->pmic_mode_map;
564 plat_data->mode_count = priv->hw_data->n_modes;
565
566 return 0;
567}
568
569/* for non-drm, xob, or bypass regulators add additional driver definitions */
570U_BOOT_DRIVER(rpmh_regulator_drm) = {
571 .name = "rpmh_regulator_drm",
572 .id = UCLASS_REGULATOR,
573 .probe = rpmh_regulator_probe,
574 .priv_auto = sizeof(struct rpmh_vreg),
575 .ops = &rpmh_regulator_vrm_drms_ops,
576};
577
578/* This driver intentionally only supports a subset of the available regulators.
579 * This function checks to see if a given regulator node in DT matches a regulator
580 * defined in the driver.
581 */
582static const struct rpmh_vreg_init_data *
583vreg_get_init_data(const struct rpmh_vreg_init_data *init_data, ofnode node)
584{
585 const struct rpmh_vreg_init_data *data;
586
587 for (data = init_data; data->name; data++) {
588 if (!strcmp(data->name, ofnode_get_name(node)))
589 return data;
590 }
591
592 return NULL;
593}
594
595static int rpmh_regulators_bind(struct udevice *dev)
596{
597 const struct rpmh_vreg_init_data *init_data, *data;
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200598 const char *pmic_id;
Caleb Connollyc58644d2024-07-15 12:08:21 +0200599 char *name;
600 struct driver *drv;
601 ofnode node;
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200602 int ret;
Caleb Connollyc58644d2024-07-15 12:08:21 +0200603 size_t namelen;
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200604
Caleb Connollyc58644d2024-07-15 12:08:21 +0200605 init_data = (const struct rpmh_vreg_init_data *)dev_get_driver_data(dev);
606 if (!init_data) {
607 dev_err(dev, "No RPMh regulator init data\n");
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200608 return -ENODEV;
Caleb Connollyc58644d2024-07-15 12:08:21 +0200609 }
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200610
Caleb Connollyc58644d2024-07-15 12:08:21 +0200611 pmic_id = ofnode_read_string(dev_ofnode(dev), "qcom,pmic-id");
612 if (!pmic_id) {
613 dev_err(dev, "No PMIC ID\n");
614 return -ENODEV;
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200615 }
616
Caleb Connollyc58644d2024-07-15 12:08:21 +0200617 drv = lists_driver_lookup_name("rpmh_regulator_drm");
618
619 ofnode_for_each_subnode(node, dev_ofnode(dev)) {
620 data = vreg_get_init_data(init_data, node);
621 if (!data)
622 continue;
623
624 /* %s is replaced with pmic_id, so subtract 2, then add 1 for the null terminator */
625 namelen = strlen(data->resource_name) + strlen(pmic_id) - 1;
626 name = devm_kzalloc(dev, namelen, GFP_KERNEL);
627 ret = snprintf(name, namelen, data->resource_name, pmic_id);
628 if (ret < 0 || ret >= namelen) {
629 dev_err(dev, "Failed to create RPMh regulator name\n");
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200630 return -ENOMEM;
631 }
632
Caleb Connollyc58644d2024-07-15 12:08:21 +0200633 ret = device_bind_with_driver_data(dev, drv, name, (ulong)data,
634 node, NULL);
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200635 if (ret < 0) {
Caleb Connollyc58644d2024-07-15 12:08:21 +0200636 dev_err(dev, "Failed to bind RPMh regulator %s: %d\n", name, ret);
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200637 return ret;
638 }
639 }
640
641 return 0;
642}
643
Caleb Connollyc58644d2024-07-15 12:08:21 +0200644static const struct udevice_id rpmh_regulator_ids[] = {
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200645 {
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200646 .compatible = "qcom,pm8150-rpmh-regulators",
Caleb Connollyc58644d2024-07-15 12:08:21 +0200647 .data = (ulong)pm8150_vreg_data,
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200648 },
649 {
650 .compatible = "qcom,pm8150l-rpmh-regulators",
Caleb Connollyc58644d2024-07-15 12:08:21 +0200651 .data = (ulong)pm8150l_vreg_data,
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200652 },
Neil Armstrongcc65ee92024-09-03 18:13:31 +0200653 {
654 .compatible = "qcom,pm8550-rpmh-regulators",
655 .data = (ulong)pm8550_vreg_data,
656 },
657 {
658 .compatible = "qcom,pm8550ve-rpmh-regulators",
659 .data = (ulong)pm8550ve_vreg_data,
660 },
661 {
662 .compatible = "qcom,pm8550vs-rpmh-regulators",
663 .data = (ulong)pm8550vs_vreg_data,
664 },
Caleb Connollyc58644d2024-07-15 12:08:21 +0200665 { /* sentinal */ },
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200666};
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200667
Caleb Connollyc58644d2024-07-15 12:08:21 +0200668/* Driver for a 'bank' of regulators. This creates devices for each
669 * individual regulator
670 */
671U_BOOT_DRIVER(rpmh_regulators) = {
672 .name = "rpmh_regulators",
673 .id = UCLASS_MISC,
674 .bind = rpmh_regulators_bind,
675 .of_match = rpmh_regulator_ids,
676 .ops = &rpmh_regulator_vrm_drms_ops,
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200677};
Caleb Connollyc0e6aa62024-07-15 12:08:15 +0200678
679MODULE_DESCRIPTION("Qualcomm RPMh regulator driver");
680MODULE_LICENSE("GPL v2");