blob: adef8f57f27a086ad1e47be76c80acccd4492ca5 [file] [log] [blame]
Simon Glassadecfef2016-01-21 19:43:30 -07001/*
2 * Copyright (C) 2015 Google, Inc
3 * Written by Simon Glass <sjg@chromium.org>
4 *
5 * Based on Rockchip's drivers/power/pmic/pmic_rk808.c:
6 * Copyright (C) 2012 rockchips
7 * zyw <zyw@rock-chips.com>
8 *
9 * SPDX-License-Identifier: GPL-2.0+
10 */
11
12#include <common.h>
13#include <dm.h>
14#include <errno.h>
15#include <power/rk808_pmic.h>
16#include <power/pmic.h>
17#include <power/regulator.h>
18
19#ifndef CONFIG_SPL_BUILD
20#define ENABLE_DRIVER
21#endif
22
23struct rk808_reg_info {
24 uint min_uv;
25 uint step_uv;
26 s8 vsel_reg;
27 u8 vsel_bits;
28};
29
30static const struct rk808_reg_info rk808_buck[] = {
31 { 712500, 12500, REG_BUCK1_ON_VSEL, 6, },
32 { 712500, 12500, REG_BUCK2_ON_VSEL, 6, },
33 { 712500, 12500, -1, 6, },
34 { 1800000, 100000, REG_BUCK4_ON_VSEL, 4, },
35};
36
37static const struct rk808_reg_info rk808_ldo[] = {
38 { 1800000, 100000, LDO1_ON_VSEL, 5, },
39 { 1800000, 100000, LDO2_ON_VSEL, 5, },
40 { 800000, 100000, LDO3_ON_VSEL, 4, },
41 { 1800000, 100000, LDO4_ON_VSEL, 5, },
42 { 1800000, 100000, LDO5_ON_VSEL, 5, },
43 { 800000, 100000, LDO6_ON_VSEL, 5, },
44 { 800000, 100000, LDO7_ON_VSEL, 5, },
45 { 1800000, 100000, LDO8_ON_VSEL, 5, },
46};
47
48
49static int _buck_set_value(struct udevice *pmic, int buck, int uvolt)
50{
51 const struct rk808_reg_info *info = &rk808_buck[buck - 1];
52 int mask = (1 << info->vsel_bits) - 1;
53 int val;
54
55 if (info->vsel_reg == -1)
56 return -ENOSYS;
57 val = (uvolt - info->min_uv) / info->step_uv;
58 debug("%s: reg=%x, mask=%x, val=%x\n", __func__, info->vsel_reg, mask,
59 val);
60
61 return pmic_clrsetbits(pmic, info->vsel_reg, mask, val);
62}
63
64static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
65{
66 uint mask;
67 int ret;
68
69 buck--;
70 mask = 1 << buck;
71 if (enable) {
72 ret = pmic_clrsetbits(pmic, DCDC_ILMAX, 0, 3 << (buck * 2));
73 if (ret)
74 return ret;
75 ret = pmic_clrsetbits(pmic, REG_DCDC_UV_ACT, 1 << buck, 0);
76 if (ret)
77 return ret;
78 }
79
80 return pmic_clrsetbits(pmic, REG_DCDC_EN, mask, enable ? mask : 0);
81}
82
83#ifdef ENABLE_DRIVER
84static int buck_get_value(struct udevice *dev)
85{
86 int buck = dev->driver_data - 1;
87 const struct rk808_reg_info *info = &rk808_buck[buck];
88 int mask = (1 << info->vsel_bits) - 1;
89 int ret, val;
90
91 if (info->vsel_reg == -1)
92 return -ENOSYS;
93 ret = pmic_reg_read(dev->parent, info->vsel_reg);
94 if (ret < 0)
95 return ret;
96 val = ret & mask;
97
98 return info->min_uv + val * info->step_uv;
99}
100
101static int buck_set_value(struct udevice *dev, int uvolt)
102{
103 int buck = dev->driver_data;
104
105 return _buck_set_value(dev->parent, buck, uvolt);
106}
107
108static int buck_set_enable(struct udevice *dev, bool enable)
109{
110 int buck = dev->driver_data;
111
112 return _buck_set_enable(dev->parent, buck, enable);
113}
114
115static bool buck_get_enable(struct udevice *dev)
116{
117 int buck = dev->driver_data - 1;
118 int ret;
119 uint mask;
120
121 mask = 1 << buck;
122
123 ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
124 if (ret < 0)
125 return ret;
126
127 return ret & mask ? true : false;
128}
129
130static int ldo_get_value(struct udevice *dev)
131{
132 int ldo = dev->driver_data - 1;
133 const struct rk808_reg_info *info = &rk808_ldo[ldo];
134 int mask = (1 << info->vsel_bits) - 1;
135 int ret, val;
136
137 if (info->vsel_reg == -1)
138 return -ENOSYS;
139 ret = pmic_reg_read(dev->parent, info->vsel_reg);
140 if (ret < 0)
141 return ret;
142 val = ret & mask;
143
144 return info->min_uv + val * info->step_uv;
145}
146
147static int ldo_set_value(struct udevice *dev, int uvolt)
148{
149 int ldo = dev->driver_data - 1;
150 const struct rk808_reg_info *info = &rk808_ldo[ldo];
151 int mask = (1 << info->vsel_bits) - 1;
152 int val;
153
154 if (info->vsel_reg == -1)
155 return -ENOSYS;
156 val = (uvolt - info->min_uv) / info->step_uv;
157 debug("%s: reg=%x, mask=%x, val=%x\n", __func__, info->vsel_reg, mask,
158 val);
159
160 return pmic_clrsetbits(dev->parent, info->vsel_reg, mask, val);
161}
162
163static int ldo_set_enable(struct udevice *dev, bool enable)
164{
165 int ldo = dev->driver_data - 1;
166 uint mask;
167
168 mask = 1 << ldo;
169
170 return pmic_clrsetbits(dev->parent, REG_LDO_EN, mask,
171 enable ? mask : 0);
172}
173
174static bool ldo_get_enable(struct udevice *dev)
175{
176 int ldo = dev->driver_data - 1;
177 int ret;
178 uint mask;
179
180 mask = 1 << ldo;
181
182 ret = pmic_reg_read(dev->parent, REG_LDO_EN);
183 if (ret < 0)
184 return ret;
185
186 return ret & mask ? true : false;
187}
188
189static int switch_set_enable(struct udevice *dev, bool enable)
190{
191 int sw = dev->driver_data - 1;
192 uint mask;
193
194 mask = 1 << (sw + 5);
195
196 return pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask,
197 enable ? mask : 0);
198}
199
200static bool switch_get_enable(struct udevice *dev)
201{
202 int sw = dev->driver_data - 1;
203 int ret;
204 uint mask;
205
206 mask = 1 << (sw + 5);
207
208 ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
209 if (ret < 0)
210 return ret;
211
212 return ret & mask ? true : false;
213}
214
215static int rk808_buck_probe(struct udevice *dev)
216{
217 struct dm_regulator_uclass_platdata *uc_pdata;
218
219 uc_pdata = dev_get_uclass_platdata(dev);
220
221 uc_pdata->type = REGULATOR_TYPE_BUCK;
222 uc_pdata->mode_count = 0;
223
224 return 0;
225}
226
227static int rk808_ldo_probe(struct udevice *dev)
228{
229 struct dm_regulator_uclass_platdata *uc_pdata;
230
231 uc_pdata = dev_get_uclass_platdata(dev);
232
233 uc_pdata->type = REGULATOR_TYPE_LDO;
234 uc_pdata->mode_count = 0;
235
236 return 0;
237}
238
239static int rk808_switch_probe(struct udevice *dev)
240{
241 struct dm_regulator_uclass_platdata *uc_pdata;
242
243 uc_pdata = dev_get_uclass_platdata(dev);
244
245 uc_pdata->type = REGULATOR_TYPE_FIXED;
246 uc_pdata->mode_count = 0;
247
248 return 0;
249}
250
251static const struct dm_regulator_ops rk808_buck_ops = {
252 .get_value = buck_get_value,
253 .set_value = buck_set_value,
254 .get_enable = buck_get_enable,
255 .set_enable = buck_set_enable,
256};
257
258static const struct dm_regulator_ops rk808_ldo_ops = {
259 .get_value = ldo_get_value,
260 .set_value = ldo_set_value,
261 .get_enable = ldo_get_enable,
262 .set_enable = ldo_set_enable,
263};
264
265static const struct dm_regulator_ops rk808_switch_ops = {
266 .get_enable = switch_get_enable,
267 .set_enable = switch_set_enable,
268};
269
270U_BOOT_DRIVER(rk808_buck) = {
271 .name = "rk808_buck",
272 .id = UCLASS_REGULATOR,
273 .ops = &rk808_buck_ops,
274 .probe = rk808_buck_probe,
275};
276
277U_BOOT_DRIVER(rk808_ldo) = {
278 .name = "rk808_ldo",
279 .id = UCLASS_REGULATOR,
280 .ops = &rk808_ldo_ops,
281 .probe = rk808_ldo_probe,
282};
283
284U_BOOT_DRIVER(rk808_switch) = {
285 .name = "rk808_switch",
286 .id = UCLASS_REGULATOR,
287 .ops = &rk808_switch_ops,
288 .probe = rk808_switch_probe,
289};
290#endif
291
292int rk808_spl_configure_buck(struct udevice *pmic, int buck, int uvolt)
293{
294 int ret;
295
296 ret = _buck_set_value(pmic, buck, uvolt);
297 if (ret)
298 return ret;
299
300 return _buck_set_enable(pmic, buck, true);
301}