blob: 00ecd4b808bedffea54d5120a75862b230fc1e11 [file] [log] [blame]
Svyatoslav Ryhel8df7d472024-10-06 14:59:54 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright(C) 2024 Svyatoslav Ryhel <clamor95@gmail.com>
4 */
5
6#include <dm.h>
7#include <power/pmic.h>
8#include <power/regulator.h>
9#include <power/max8907.h>
10
11static const char max8907_regmap[] = {
12 0x00, MAX8907_REG_SDCTL1, MAX8907_REG_SDCTL2, MAX8907_REG_SDCTL3,
13 MAX8907_REG_LDOCTL1, MAX8907_REG_LDOCTL2, MAX8907_REG_LDOCTL3,
14 MAX8907_REG_LDOCTL4, MAX8907_REG_LDOCTL5, MAX8907_REG_LDOCTL6,
15 MAX8907_REG_LDOCTL7, MAX8907_REG_LDOCTL8, MAX8907_REG_LDOCTL9,
16 MAX8907_REG_LDOCTL10, MAX8907_REG_LDOCTL11, MAX8907_REG_LDOCTL12,
17 MAX8907_REG_LDOCTL13, MAX8907_REG_LDOCTL14, MAX8907_REG_LDOCTL15,
18 MAX8907_REG_LDOCTL16, MAX8907_REG_LDOCTL17, MAX8907_REG_LDOCTL18,
19 MAX8907_REG_LDOCTL19, MAX8907_REG_LDOCTL20
20};
21
22static int max8907_enable(struct udevice *dev, int op, bool *enable)
23{
24 struct dm_regulator_uclass_plat *uc_pdata =
25 dev_get_uclass_plat(dev);
26 int val, ret = 0;
27
28 if (op == PMIC_OP_GET) {
29 val = pmic_reg_read(dev->parent, uc_pdata->ctrl_reg);
30 if (val < 0)
31 return val;
32
33 if (val & MAX8907_MASK_LDO_EN)
34 *enable = true;
35 else
36 *enable = false;
37 } else if (op == PMIC_OP_SET) {
38 if (*enable) {
39 ret = pmic_clrsetbits(dev->parent,
40 uc_pdata->ctrl_reg,
41 MAX8907_MASK_LDO_EN |
42 MAX8907_MASK_LDO_SEQ,
43 MAX8907_MASK_LDO_EN |
44 MAX8907_MASK_LDO_SEQ);
45 } else {
46 ret = pmic_clrsetbits(dev->parent,
47 uc_pdata->ctrl_reg,
48 MAX8907_MASK_LDO_EN |
49 MAX8907_MASK_LDO_SEQ,
50 MAX8907_MASK_LDO_SEQ);
51 }
52 }
53
54 return ret;
55}
56
57static int max8907_get_enable(struct udevice *dev)
58{
59 bool enable = false;
60 int ret;
61
62 ret = max8907_enable(dev, PMIC_OP_GET, &enable);
63 if (ret)
64 return ret;
65
66 return enable;
67}
68
69static int max8907_set_enable(struct udevice *dev, bool enable)
70{
71 return max8907_enable(dev, PMIC_OP_SET, &enable);
72}
73
74/**
75 * max8907_volt2hex() - convert voltage in uV into
76 * applicable to register hex value
77 *
78 * @idx: regulator index
79 * @uV: voltage in uV
80 *
81 * Return: voltage in hex on success, -ve on failure
82 */
83static int max8907_volt2hex(int idx, int uV)
84{
85 switch (idx) {
86 case 1: /* SD1 */
87 if (uV > SD1_VOLT_MAX || uV < SD1_VOLT_MIN)
88 break;
89
90 return (uV - SD1_VOLT_MIN) / SD1_VOLT_STEP;
91
92 case 2: /* SD2 */
93 if (uV > SD2_VOLT_MAX || uV < SD2_VOLT_MIN)
94 break;
95
96 return (uV - SD2_VOLT_MIN) / SD2_VOLT_STEP;
97
98 case 3: /* SD3 */
99 if (uV > SD2_VOLT_MAX || uV < SD2_VOLT_MIN)
100 break;
101
102 return (uV - SD2_VOLT_MIN) / SD2_VOLT_STEP;
103
104 case 5: /* LDO2 */
105 case 6: /* LDO3 */
106 case 20: /* LDO17 */
107 case 21: /* LDO18 */
108 if (uV > LDO_650_VOLT_MAX || uV < LDO_650_VOLT_MIN)
109 break;
110
111 return (uV - LDO_650_VOLT_MIN) / LDO_650_VOLT_STEP;
112
113 default: /* LDO1, 4..16, 19..20 */
114 if (uV > LDO_750_VOLT_MAX || uV < LDO_750_VOLT_MIN)
115 break;
116
117 return (uV - LDO_750_VOLT_MIN) / LDO_750_VOLT_STEP;
118 };
119
120 return -EINVAL;
121}
122
123/**
124 * max8907_hex2volt() - convert register hex value into
125 * actual voltage in uV
126 *
127 * @idx: regulator index
128 * @hex: hex value of register
129 *
130 * Return: voltage in uV on success, -ve on failure
131 */
132static int max8907_hex2volt(int idx, int hex)
133{
134 switch (idx) {
135 case 1:
136 return hex * SD1_VOLT_STEP + SD1_VOLT_MIN;
137
138 case 2:
139 return hex * SD2_VOLT_STEP + SD2_VOLT_MIN;
140
141 case 3:
142 return hex * SD3_VOLT_STEP + SD3_VOLT_MIN;
143
144 case 5: /* LDO2 */
145 case 6: /* LDO3 */
146 case 20: /* LDO17 */
147 case 21: /* LDO18 */
148 return hex * LDO_650_VOLT_STEP + LDO_650_VOLT_MIN;
149
150 default: /* LDO1, 4..16, 19..20 */
151 return hex * LDO_750_VOLT_STEP + LDO_750_VOLT_MIN;
152 };
153
154 return -EINVAL;
155}
156
157static int max8907_val(struct udevice *dev, int op, int *uV)
158{
159 struct dm_regulator_uclass_plat *uc_pdata =
160 dev_get_uclass_plat(dev);
161 int idx = dev->driver_data;
162 int hex, ret;
163
164 if (op == PMIC_OP_GET) {
165 hex = pmic_reg_read(dev->parent, uc_pdata->volt_reg);
166 if (hex < 0)
167 return hex;
168
169 *uV = 0;
170
171 ret = max8907_hex2volt(idx, hex);
172 if (ret < 0)
173 return ret;
174 *uV = ret;
175
176 return 0;
177 }
178
179 hex = max8907_volt2hex(idx, *uV);
180 if (hex < 0)
181 return hex;
182
183 return pmic_reg_write(dev->parent, uc_pdata->volt_reg, hex);
184}
185
186static int max8907_get_value(struct udevice *dev)
187{
188 int uV;
189 int ret;
190
191 ret = max8907_val(dev, PMIC_OP_GET, &uV);
192 if (ret)
193 return ret;
194
195 return uV;
196}
197
198static int max8907_set_value(struct udevice *dev, int uV)
199{
200 return max8907_val(dev, PMIC_OP_SET, &uV);
201}
202
203static const struct dm_regulator_ops max8907_regulator_ops = {
204 .get_value = max8907_get_value,
205 .set_value = max8907_set_value,
206 .get_enable = max8907_get_enable,
207 .set_enable = max8907_set_enable,
208};
209
210static int max8907_sd_probe(struct udevice *dev)
211{
212 struct dm_regulator_uclass_plat *uc_pdata =
213 dev_get_uclass_plat(dev);
214 int idx = dev->driver_data;
215
216 uc_pdata->type = REGULATOR_TYPE_BUCK;
217 uc_pdata->ctrl_reg = max8907_regmap[idx];
218 uc_pdata->volt_reg = uc_pdata->ctrl_reg + MAX8907_VOUT;
219
220 return 0;
221}
222
223U_BOOT_DRIVER(max8907_sd) = {
224 .name = MAX8907_SD_DRIVER,
225 .id = UCLASS_REGULATOR,
226 .ops = &max8907_regulator_ops,
227 .probe = max8907_sd_probe,
228};
229
230static int max8907_ldo_probe(struct udevice *dev)
231{
232 struct dm_regulator_uclass_plat *uc_pdata =
233 dev_get_uclass_plat(dev);
234 /* LDO regulator id is shifted by number for SD regulators */
235 int idx = dev->driver_data + 3;
236
237 uc_pdata->type = REGULATOR_TYPE_LDO;
238 uc_pdata->ctrl_reg = max8907_regmap[idx];
239 uc_pdata->volt_reg = uc_pdata->ctrl_reg + MAX8907_VOUT;
240
241 return 0;
242}
243
244U_BOOT_DRIVER(max8907_ldo) = {
245 .name = MAX8907_LDO_DRIVER,
246 .id = UCLASS_REGULATOR,
247 .ops = &max8907_regulator_ops,
248 .probe = max8907_ldo_probe,
249};