blob: 466a871b7e8ff07b4ca5a9618ad7c96eb69008d7 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glassadecfef2016-01-21 19:43:30 -07002/*
3 * Copyright (C) 2015 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
5 *
6 * Based on Rockchip's drivers/power/pmic/pmic_rk808.c:
7 * Copyright (C) 2012 rockchips
8 * zyw <zyw@rock-chips.com>
Simon Glassadecfef2016-01-21 19:43:30 -07009 */
10
11#include <common.h>
12#include <dm.h>
13#include <errno.h>
Jacob Chen614704b2017-05-02 14:54:52 +080014#include <power/rk8xx_pmic.h>
Simon Glassadecfef2016-01-21 19:43:30 -070015#include <power/pmic.h>
16#include <power/regulator.h>
17
18#ifndef CONFIG_SPL_BUILD
19#define ENABLE_DRIVER
20#endif
21
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080022/* Not used or exisit register and configure */
23#define NA 0xff
24
Jacob Chen21a6a252017-05-02 14:54:50 +080025/* Field Definitions */
26#define RK808_BUCK_VSEL_MASK 0x3f
27#define RK808_BUCK4_VSEL_MASK 0xf
28#define RK808_LDO_VSEL_MASK 0x1f
29
Jacob Chen36163e32017-05-02 14:54:51 +080030#define RK818_BUCK_VSEL_MASK 0x3f
31#define RK818_BUCK4_VSEL_MASK 0x1f
32#define RK818_LDO_VSEL_MASK 0x1f
33#define RK818_LDO3_ON_VSEL_MASK 0xf
34#define RK818_BOOST_ON_VSEL_MASK 0xe0
Wadim Egorovc2581052017-06-19 12:36:39 +020035#define RK818_USB_ILIM_SEL_MASK 0x0f
36#define RK818_USB_CHG_SD_VSEL_MASK 0x70
37
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080038/*
39 * Ramp delay
40 */
Elaine Zhang1d9077e2019-09-26 15:43:55 +080041#define RK805_RAMP_RATE_OFFSET 3
42#define RK805_RAMP_RATE_MASK (3 << RK805_RAMP_RATE_OFFSET)
43#define RK805_RAMP_RATE_3MV_PER_US (0 << RK805_RAMP_RATE_OFFSET)
44#define RK805_RAMP_RATE_6MV_PER_US (1 << RK805_RAMP_RATE_OFFSET)
45#define RK805_RAMP_RATE_12_5MV_PER_US (2 << RK805_RAMP_RATE_OFFSET)
46#define RK805_RAMP_RATE_25MV_PER_US (3 << RK805_RAMP_RATE_OFFSET)
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080047#define RK808_RAMP_RATE_OFFSET 3
Elaine Zhang1d9077e2019-09-26 15:43:55 +080048
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080049#define RK808_RAMP_RATE_MASK (3 << RK808_RAMP_RATE_OFFSET)
50#define RK808_RAMP_RATE_2MV_PER_US (0 << RK808_RAMP_RATE_OFFSET)
51#define RK808_RAMP_RATE_4MV_PER_US (1 << RK808_RAMP_RATE_OFFSET)
52#define RK808_RAMP_RATE_6MV_PER_US (2 << RK808_RAMP_RATE_OFFSET)
53#define RK808_RAMP_RATE_10MV_PER_US (3 << RK808_RAMP_RATE_OFFSET)
Jacob Chen36163e32017-05-02 14:54:51 +080054
Jacob Chen614704b2017-05-02 14:54:52 +080055struct rk8xx_reg_info {
Simon Glassadecfef2016-01-21 19:43:30 -070056 uint min_uv;
57 uint step_uv;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080058 u8 vsel_reg;
59 u8 vsel_sleep_reg;
60 u8 config_reg;
Jacob Chen21a6a252017-05-02 14:54:50 +080061 u8 vsel_mask;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080062 u8 min_sel;
Simon Glassadecfef2016-01-21 19:43:30 -070063};
64
Jacob Chen614704b2017-05-02 14:54:52 +080065static const struct rk8xx_reg_info rk808_buck[] = {
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080066 { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK808_BUCK_VSEL_MASK, },
67 { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK808_BUCK_VSEL_MASK, },
68 { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK808_BUCK_VSEL_MASK, },
69 { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK808_BUCK4_VSEL_MASK, },
Simon Glassadecfef2016-01-21 19:43:30 -070070};
71
Elaine Zhang04e5a432019-09-26 15:43:54 +080072static const struct rk8xx_reg_info rk816_buck[] = {
73 /* buck 1 */
74 { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, },
75 { 1800000, 200000, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, },
76 { 2300000, 0, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, },
77 /* buck 2 */
78 { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, },
79 { 1800000, 200000, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, },
80 { 2300000, 0, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, },
81 /* buck 3 */
82 { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK818_BUCK_VSEL_MASK, },
83 /* buck 4 */
84 { 800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, },
85};
86
Wadim Egorov4c4905f2017-06-19 12:36:38 +020087static const struct rk8xx_reg_info rk818_buck[] = {
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080088 { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, },
89 { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, },
90 { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK818_BUCK_VSEL_MASK, },
91 { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, },
Wadim Egorov4c4905f2017-06-19 12:36:38 +020092};
93
94#ifdef ENABLE_DRIVER
Jacob Chen614704b2017-05-02 14:54:52 +080095static const struct rk8xx_reg_info rk808_ldo[] = {
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080096 { 1800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
97 { 1800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
98 { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK808_BUCK4_VSEL_MASK, },
99 { 1800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
100 { 1800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
101 { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
102 { 800000, 100000, REG_LDO7_ON_VSEL, REG_LDO7_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
103 { 1800000, 100000, REG_LDO8_ON_VSEL, REG_LDO8_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
Simon Glassadecfef2016-01-21 19:43:30 -0700104};
105
Elaine Zhang04e5a432019-09-26 15:43:54 +0800106static const struct rk8xx_reg_info rk816_ldo[] = {
107 { 800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
108 { 800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
109 { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
110 { 800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
111 { 800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
112 { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
113};
114
Jacob Chen614704b2017-05-02 14:54:52 +0800115static const struct rk8xx_reg_info rk818_ldo[] = {
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800116 { 1800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
117 { 1800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
118 { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK818_LDO3_ON_VSEL_MASK, },
119 { 1800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
120 { 1800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
121 { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
122 { 800000, 100000, REG_LDO7_ON_VSEL, REG_LDO7_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
123 { 1800000, 100000, REG_LDO8_ON_VSEL, REG_LDO8_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
Jacob Chen36163e32017-05-02 14:54:51 +0800124};
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200125#endif
Jacob Chen36163e32017-05-02 14:54:51 +0800126
Wadim Egorovc2581052017-06-19 12:36:39 +0200127static const u16 rk818_chrg_cur_input_array[] = {
128 450, 800, 850, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000
129};
130
131static const uint rk818_chrg_shutdown_vsel_array[] = {
132 2780000, 2850000, 2920000, 2990000, 3060000, 3130000, 3190000, 3260000
133};
134
Jacob Chen614704b2017-05-02 14:54:52 +0800135static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800136 int num, int uvolt)
Jacob Chen36163e32017-05-02 14:54:51 +0800137{
Jacob Chen614704b2017-05-02 14:54:52 +0800138 struct rk8xx_priv *priv = dev_get_priv(pmic);
Elaine Zhang04e5a432019-09-26 15:43:54 +0800139
Jacob Chen614704b2017-05-02 14:54:52 +0800140 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800141 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800142 case RK816_ID:
143 switch (num) {
144 case 0:
145 case 1:
146 if (uvolt <= 1450000)
147 return &rk816_buck[num * 3 + 0];
148 else if (uvolt <= 2200000)
149 return &rk816_buck[num * 3 + 1];
150 else
151 return &rk816_buck[num * 3 + 2];
152 default:
153 return &rk816_buck[num + 4];
154 }
Jacob Chen36163e32017-05-02 14:54:51 +0800155 case RK818_ID:
156 return &rk818_buck[num];
157 default:
158 return &rk808_buck[num];
159 }
160}
161
Simon Glassadecfef2016-01-21 19:43:30 -0700162static int _buck_set_value(struct udevice *pmic, int buck, int uvolt)
163{
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800164 const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt);
Elaine Zhang04e5a432019-09-26 15:43:54 +0800165 struct rk8xx_priv *priv = dev_get_priv(pmic);
Jacob Chen21a6a252017-05-02 14:54:50 +0800166 int mask = info->vsel_mask;
Simon Glassadecfef2016-01-21 19:43:30 -0700167 int val;
168
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800169 if (info->vsel_reg == NA)
Simon Glassadecfef2016-01-21 19:43:30 -0700170 return -ENOSYS;
Elaine Zhang04e5a432019-09-26 15:43:54 +0800171
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800172 if (info->step_uv == 0) /* Fixed voltage */
173 val = info->min_sel;
174 else
175 val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
176
177 debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
178 __func__, uvolt, buck + 1, info->vsel_reg, mask, val);
179
Elaine Zhang04e5a432019-09-26 15:43:54 +0800180 if (priv->variant == RK816_ID) {
181 pmic_clrsetbits(pmic, info->vsel_reg, mask, val);
182 return pmic_clrsetbits(pmic, RK816_REG_DCDC_EN2,
183 1 << 7, 1 << 7);
184 } else {
185 return pmic_clrsetbits(pmic, info->vsel_reg, mask, val);
186 }
Simon Glassadecfef2016-01-21 19:43:30 -0700187}
188
189static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
190{
Elaine Zhang04e5a432019-09-26 15:43:54 +0800191 uint mask, value, en_reg;
Simon Glassadecfef2016-01-21 19:43:30 -0700192 int ret;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800193 struct rk8xx_priv *priv = dev_get_priv(pmic);
Simon Glassadecfef2016-01-21 19:43:30 -0700194
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800195 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800196 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800197 case RK816_ID:
198 if (buck >= 4) {
199 buck -= 4;
200 en_reg = RK816_REG_DCDC_EN2;
201 } else {
202 en_reg = RK816_REG_DCDC_EN1;
203 }
204 if (enable)
205 value = ((1 << buck) | (1 << (buck + 4)));
206 else
207 value = ((0 << buck) | (1 << (buck + 4)));
208 ret = pmic_reg_write(pmic, en_reg, value);
209 break;
210
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800211 case RK808_ID:
212 case RK818_ID:
213 mask = 1 << buck;
214 if (enable) {
215 ret = pmic_clrsetbits(pmic, REG_DCDC_ILMAX,
216 0, 3 << (buck * 2));
217 if (ret)
218 return ret;
219 }
220 ret = pmic_clrsetbits(pmic, REG_DCDC_EN, mask,
221 enable ? mask : 0);
222 break;
223 default:
224 ret = -EINVAL;
Simon Glassadecfef2016-01-21 19:43:30 -0700225 }
226
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800227 return ret;
Simon Glassadecfef2016-01-21 19:43:30 -0700228}
229
230#ifdef ENABLE_DRIVER
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800231static int _buck_set_suspend_value(struct udevice *pmic, int buck, int uvolt)
232{
233 const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt);
234 int mask = info->vsel_mask;
235 int val;
236
237 if (info->vsel_sleep_reg == NA)
238 return -ENOSYS;
239
240 if (info->step_uv == 0)
241 val = info->min_sel;
242 else
243 val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
244
245 debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
246 __func__, uvolt, buck + 1, info->vsel_sleep_reg, mask, val);
247
248 return pmic_clrsetbits(pmic, info->vsel_sleep_reg, mask, val);
249}
250
251static int _buck_get_enable(struct udevice *pmic, int buck)
252{
253 struct rk8xx_priv *priv = dev_get_priv(pmic);
254 uint mask = 0;
255 int ret = 0;
256
257 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800258 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800259 case RK816_ID:
260 if (buck >= 4) {
261 mask = 1 << (buck - 4);
262 ret = pmic_reg_read(pmic, RK816_REG_DCDC_EN2);
263 } else {
264 mask = 1 << buck;
265 ret = pmic_reg_read(pmic, RK816_REG_DCDC_EN1);
266 }
267 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800268 case RK808_ID:
269 case RK818_ID:
270 mask = 1 << buck;
271 ret = pmic_reg_read(pmic, REG_DCDC_EN);
272 if (ret < 0)
273 return ret;
274 break;
275 }
276
277 if (ret < 0)
278 return ret;
279
280 return ret & mask ? true : false;
281}
282
283static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable)
284{
285 uint mask;
286 int ret;
287 struct rk8xx_priv *priv = dev_get_priv(pmic);
288
289 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800290 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800291 case RK816_ID:
292 mask = 1 << buck;
293 ret = pmic_clrsetbits(pmic, RK816_REG_DCDC_SLP_EN, mask,
294 enable ? mask : 0);
295 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800296 case RK808_ID:
297 case RK818_ID:
298 mask = 1 << buck;
299 ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF1, mask,
300 enable ? 0 : mask);
301 break;
302 default:
303 ret = -EINVAL;
304 }
305
306 return ret;
307}
308
309static int _buck_get_suspend_enable(struct udevice *pmic, int buck)
310{
311 struct rk8xx_priv *priv = dev_get_priv(pmic);
312 int ret, val;
313 uint mask;
314
315 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800316 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800317 case RK816_ID:
318 mask = 1 << buck;
319 val = pmic_reg_read(pmic, RK816_REG_DCDC_SLP_EN);
320 if (val < 0)
321 return val;
322 ret = val & mask ? 1 : 0;
323 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800324 case RK808_ID:
325 case RK818_ID:
326 mask = 1 << buck;
327 val = pmic_reg_read(pmic, REG_SLEEP_SET_OFF1);
328 if (val < 0)
329 return val;
330 ret = val & mask ? 0 : 1;
331 break;
332 default:
333 ret = -EINVAL;
334 }
335
336 return ret;
337}
338
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200339static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800340 int num, int uvolt)
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200341{
342 struct rk8xx_priv *priv = dev_get_priv(pmic);
Elaine Zhang04e5a432019-09-26 15:43:54 +0800343
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200344 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800345 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800346 case RK816_ID:
347 return &rk816_ldo[num];
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200348 case RK818_ID:
349 return &rk818_ldo[num];
350 default:
351 return &rk808_ldo[num];
352 }
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800353}
354
355static int _ldo_get_enable(struct udevice *pmic, int ldo)
356{
357 struct rk8xx_priv *priv = dev_get_priv(pmic);
358 uint mask = 0;
359 int ret = 0;
360
361 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800362 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800363 case RK816_ID:
364 if (ldo >= 4) {
365 mask = 1 << (ldo - 4);
366 ret = pmic_reg_read(pmic, RK816_REG_LDO_EN2);
367 } else {
368 mask = 1 << ldo;
369 ret = pmic_reg_read(pmic, RK816_REG_LDO_EN1);
370 }
371 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800372 case RK808_ID:
373 case RK818_ID:
374 mask = 1 << ldo;
375 ret = pmic_reg_read(pmic, REG_LDO_EN);
376 if (ret < 0)
377 return ret;
378 break;
379 }
380
381 if (ret < 0)
382 return ret;
383
384 return ret & mask ? true : false;
385}
386
387static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable)
388{
389 struct rk8xx_priv *priv = dev_get_priv(pmic);
Elaine Zhang04e5a432019-09-26 15:43:54 +0800390 uint mask, value, en_reg;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800391 int ret = 0;
392
393 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800394 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800395 case RK816_ID:
396 if (ldo >= 4) {
397 ldo -= 4;
398 en_reg = RK816_REG_LDO_EN2;
399 } else {
400 en_reg = RK816_REG_LDO_EN1;
401 }
402 if (enable)
403 value = ((1 << ldo) | (1 << (ldo + 4)));
404 else
405 value = ((0 << ldo) | (1 << (ldo + 4)));
406
407 ret = pmic_reg_write(pmic, en_reg, value);
408 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800409 case RK808_ID:
410 case RK818_ID:
411 mask = 1 << ldo;
412 ret = pmic_clrsetbits(pmic, REG_LDO_EN, mask,
Elaine Zhang04e5a432019-09-26 15:43:54 +0800413 enable ? mask : 0);
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800414 break;
415 }
416
417 return ret;
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200418}
419
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800420static int _ldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable)
421{
422 struct rk8xx_priv *priv = dev_get_priv(pmic);
423 uint mask;
424 int ret = 0;
425
426 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800427 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800428 case RK816_ID:
429 mask = 1 << ldo;
430 ret = pmic_clrsetbits(pmic, RK816_REG_LDO_SLP_EN, mask,
431 enable ? mask : 0);
432 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800433 case RK808_ID:
434 case RK818_ID:
435 mask = 1 << ldo;
436 ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF2, mask,
437 enable ? 0 : mask);
438 break;
439 }
440
441 return ret;
442}
443
444static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo)
445{
446 struct rk8xx_priv *priv = dev_get_priv(pmic);
447 int val, ret = 0;
448 uint mask;
449
450 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800451 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800452 case RK816_ID:
453 mask = 1 << ldo;
454 val = pmic_reg_read(pmic, RK816_REG_LDO_SLP_EN);
455 if (val < 0)
456 return val;
457 ret = val & mask ? 1 : 0;
458 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800459 case RK808_ID:
460 case RK818_ID:
461 mask = 1 << ldo;
462 val = pmic_reg_read(pmic, REG_SLEEP_SET_OFF2);
463 if (val < 0)
464 return val;
465 ret = val & mask ? 0 : 1;
466 break;
467 }
468
469 return ret;
470}
471
Simon Glassadecfef2016-01-21 19:43:30 -0700472static int buck_get_value(struct udevice *dev)
473{
474 int buck = dev->driver_data - 1;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800475 /* We assume level-1 voltage is enough for usage in U-Boot */
476 const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0);
Jacob Chen21a6a252017-05-02 14:54:50 +0800477 int mask = info->vsel_mask;
Simon Glassadecfef2016-01-21 19:43:30 -0700478 int ret, val;
479
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800480 if (info->vsel_reg == NA)
Simon Glassadecfef2016-01-21 19:43:30 -0700481 return -ENOSYS;
Elaine Zhang04e5a432019-09-26 15:43:54 +0800482
Simon Glassadecfef2016-01-21 19:43:30 -0700483 ret = pmic_reg_read(dev->parent, info->vsel_reg);
484 if (ret < 0)
485 return ret;
486 val = ret & mask;
487
488 return info->min_uv + val * info->step_uv;
489}
490
491static int buck_set_value(struct udevice *dev, int uvolt)
492{
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800493 int buck = dev->driver_data - 1;
Simon Glassadecfef2016-01-21 19:43:30 -0700494
495 return _buck_set_value(dev->parent, buck, uvolt);
496}
497
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800498static int buck_get_suspend_value(struct udevice *dev)
499{
500 int buck = dev->driver_data - 1;
501 /* We assume level-1 voltage is enough for usage in U-Boot */
502 const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0);
503 int mask = info->vsel_mask;
504 int ret, val;
505
506 if (info->vsel_sleep_reg == NA)
507 return -ENOSYS;
508
509 ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg);
510 if (ret < 0)
511 return ret;
512
513 val = ret & mask;
514
515 return info->min_uv + val * info->step_uv;
516}
517
518static int buck_set_suspend_value(struct udevice *dev, int uvolt)
519{
520 int buck = dev->driver_data - 1;
521
522 return _buck_set_suspend_value(dev->parent, buck, uvolt);
523}
524
Simon Glassadecfef2016-01-21 19:43:30 -0700525static int buck_set_enable(struct udevice *dev, bool enable)
526{
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800527 int buck = dev->driver_data - 1;
Simon Glassadecfef2016-01-21 19:43:30 -0700528
529 return _buck_set_enable(dev->parent, buck, enable);
530}
531
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800532static int buck_set_suspend_enable(struct udevice *dev, bool enable)
Simon Glassadecfef2016-01-21 19:43:30 -0700533{
534 int buck = dev->driver_data - 1;
Simon Glassadecfef2016-01-21 19:43:30 -0700535
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800536 return _buck_set_suspend_enable(dev->parent, buck, enable);
537}
Simon Glassadecfef2016-01-21 19:43:30 -0700538
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800539static int buck_get_suspend_enable(struct udevice *dev)
540{
541 int buck = dev->driver_data - 1;
Simon Glassadecfef2016-01-21 19:43:30 -0700542
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800543 return _buck_get_suspend_enable(dev->parent, buck);
Simon Glassadecfef2016-01-21 19:43:30 -0700544}
545
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800546static int buck_get_enable(struct udevice *dev)
547{
548 int buck = dev->driver_data - 1;
549
550 return _buck_get_enable(dev->parent, buck);
551}
552
Simon Glassadecfef2016-01-21 19:43:30 -0700553static int ldo_get_value(struct udevice *dev)
554{
555 int ldo = dev->driver_data - 1;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800556 const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0);
Jacob Chen21a6a252017-05-02 14:54:50 +0800557 int mask = info->vsel_mask;
Simon Glassadecfef2016-01-21 19:43:30 -0700558 int ret, val;
559
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800560 if (info->vsel_reg == NA)
Simon Glassadecfef2016-01-21 19:43:30 -0700561 return -ENOSYS;
562 ret = pmic_reg_read(dev->parent, info->vsel_reg);
563 if (ret < 0)
564 return ret;
565 val = ret & mask;
566
567 return info->min_uv + val * info->step_uv;
568}
569
570static int ldo_set_value(struct udevice *dev, int uvolt)
571{
572 int ldo = dev->driver_data - 1;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800573 const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, uvolt);
Jacob Chen21a6a252017-05-02 14:54:50 +0800574 int mask = info->vsel_mask;
Simon Glassadecfef2016-01-21 19:43:30 -0700575 int val;
576
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800577 if (info->vsel_reg == NA)
Simon Glassadecfef2016-01-21 19:43:30 -0700578 return -ENOSYS;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800579
580 if (info->step_uv == 0)
581 val = info->min_sel;
582 else
583 val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
584
585 debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
586 __func__, uvolt, ldo + 1, info->vsel_reg, mask, val);
Simon Glassadecfef2016-01-21 19:43:30 -0700587
588 return pmic_clrsetbits(dev->parent, info->vsel_reg, mask, val);
589}
590
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800591static int ldo_set_suspend_value(struct udevice *dev, int uvolt)
Simon Glassadecfef2016-01-21 19:43:30 -0700592{
593 int ldo = dev->driver_data - 1;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800594 const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, uvolt);
595 int mask = info->vsel_mask;
596 int val;
597
598 if (info->vsel_sleep_reg == NA)
599 return -ENOSYS;
Simon Glassadecfef2016-01-21 19:43:30 -0700600
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800601 if (info->step_uv == 0)
602 val = info->min_sel;
603 else
604 val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
Simon Glassadecfef2016-01-21 19:43:30 -0700605
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800606 debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
607 __func__, uvolt, ldo + 1, info->vsel_sleep_reg, mask, val);
608
609 return pmic_clrsetbits(dev->parent, info->vsel_sleep_reg, mask, val);
Simon Glassadecfef2016-01-21 19:43:30 -0700610}
611
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800612static int ldo_get_suspend_value(struct udevice *dev)
Simon Glassadecfef2016-01-21 19:43:30 -0700613{
614 int ldo = dev->driver_data - 1;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800615 const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0);
616 int mask = info->vsel_mask;
617 int val, ret;
Simon Glassadecfef2016-01-21 19:43:30 -0700618
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800619 if (info->vsel_sleep_reg == NA)
620 return -ENOSYS;
Simon Glassadecfef2016-01-21 19:43:30 -0700621
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800622 ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg);
Simon Glassadecfef2016-01-21 19:43:30 -0700623 if (ret < 0)
624 return ret;
625
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800626 val = ret & mask;
627
628 return info->min_uv + val * info->step_uv;
629}
630
631static int ldo_set_enable(struct udevice *dev, bool enable)
632{
633 int ldo = dev->driver_data - 1;
634
635 return _ldo_set_enable(dev->parent, ldo, enable);
636}
637
638static int ldo_set_suspend_enable(struct udevice *dev, bool enable)
639{
640 int ldo = dev->driver_data - 1;
641
642 return _ldo_set_suspend_enable(dev->parent, ldo, enable);
643}
644
645static int ldo_get_suspend_enable(struct udevice *dev)
646{
647 int ldo = dev->driver_data - 1;
648
649 return _ldo_get_suspend_enable(dev->parent, ldo);
650}
651
652static int ldo_get_enable(struct udevice *dev)
653{
654 int ldo = dev->driver_data - 1;
655
656 return _ldo_get_enable(dev->parent, ldo);
Simon Glassadecfef2016-01-21 19:43:30 -0700657}
658
659static int switch_set_enable(struct udevice *dev, bool enable)
660{
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800661 struct rk8xx_priv *priv = dev_get_priv(dev->parent);
662 int ret = 0, sw = dev->driver_data - 1;
663 uint mask = 0;
664
665 switch (priv->variant) {
666 case RK808_ID:
667 mask = 1 << (sw + 5);
668 ret = pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask,
669 enable ? mask : 0);
670 break;
671 case RK818_ID:
672 mask = 1 << 6;
673 ret = pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask,
674 enable ? mask : 0);
675 break;
676 }
Simon Glassadecfef2016-01-21 19:43:30 -0700677
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800678 debug("%s: switch%d, enable=%d, mask=0x%x\n",
679 __func__, sw + 1, enable, mask);
Simon Glassadecfef2016-01-21 19:43:30 -0700680
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800681 return ret;
Simon Glassadecfef2016-01-21 19:43:30 -0700682}
683
Keerthyc8f82fb2017-06-13 09:53:52 +0530684static int switch_get_enable(struct udevice *dev)
Simon Glassadecfef2016-01-21 19:43:30 -0700685{
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800686 struct rk8xx_priv *priv = dev_get_priv(dev->parent);
687 int ret = 0, sw = dev->driver_data - 1;
688 uint mask = 0;
Simon Glassadecfef2016-01-21 19:43:30 -0700689
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800690 switch (priv->variant) {
691 case RK808_ID:
692 mask = 1 << (sw + 5);
693 ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
694 break;
695 case RK818_ID:
696 mask = 1 << 6;
697 ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
698 break;
699 }
Simon Glassadecfef2016-01-21 19:43:30 -0700700
Simon Glassadecfef2016-01-21 19:43:30 -0700701 if (ret < 0)
702 return ret;
703
704 return ret & mask ? true : false;
705}
706
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800707static int switch_set_suspend_value(struct udevice *dev, int uvolt)
708{
709 return 0;
710}
711
712static int switch_get_suspend_value(struct udevice *dev)
713{
714 return 0;
715}
716
717static int switch_set_suspend_enable(struct udevice *dev, bool enable)
718{
719 struct rk8xx_priv *priv = dev_get_priv(dev->parent);
720 int ret = 0, sw = dev->driver_data - 1;
721 uint mask = 0;
722
723 switch (priv->variant) {
724 case RK808_ID:
725 mask = 1 << (sw + 5);
726 ret = pmic_clrsetbits(dev->parent, REG_SLEEP_SET_OFF1, mask,
727 enable ? 0 : mask);
728 break;
729 case RK818_ID:
730 mask = 1 << 6;
731 ret = pmic_clrsetbits(dev->parent, REG_SLEEP_SET_OFF1, mask,
732 enable ? 0 : mask);
733 break;
734 }
735
736 debug("%s: switch%d, enable=%d, mask=0x%x\n",
737 __func__, sw + 1, enable, mask);
738
739 return ret;
740}
741
742static int switch_get_suspend_enable(struct udevice *dev)
743{
744 struct rk8xx_priv *priv = dev_get_priv(dev->parent);
745 int val, ret = 0, sw = dev->driver_data - 1;
746 uint mask = 0;
747
748 switch (priv->variant) {
749 case RK808_ID:
750 mask = 1 << (sw + 5);
751 val = pmic_reg_read(dev->parent, REG_SLEEP_SET_OFF1);
752 if (val < 0)
753 return val;
754 ret = val & mask ? 0 : 1;
755 break;
756 case RK818_ID:
757 mask = 1 << 6;
758 val = pmic_reg_read(dev->parent, REG_SLEEP_SET_OFF1);
759 if (val < 0)
760 return val;
761 ret = val & mask ? 0 : 1;
762 break;
763 }
764
765 return ret;
766}
767
768/*
769 * RK8xx switch does not need to set the voltage,
770 * but if dts set regulator-min-microvolt/regulator-max-microvolt,
771 * will cause regulator set value fail and not to enable this switch.
772 * So add an empty function to return success.
773 */
774static int switch_get_value(struct udevice *dev)
775{
776 return 0;
777}
778
779static int switch_set_value(struct udevice *dev, int uvolt)
780{
781 return 0;
782}
783
Jacob Chen614704b2017-05-02 14:54:52 +0800784static int rk8xx_buck_probe(struct udevice *dev)
Simon Glassadecfef2016-01-21 19:43:30 -0700785{
786 struct dm_regulator_uclass_platdata *uc_pdata;
787
788 uc_pdata = dev_get_uclass_platdata(dev);
789
790 uc_pdata->type = REGULATOR_TYPE_BUCK;
791 uc_pdata->mode_count = 0;
792
793 return 0;
794}
795
Jacob Chen614704b2017-05-02 14:54:52 +0800796static int rk8xx_ldo_probe(struct udevice *dev)
Simon Glassadecfef2016-01-21 19:43:30 -0700797{
798 struct dm_regulator_uclass_platdata *uc_pdata;
799
800 uc_pdata = dev_get_uclass_platdata(dev);
801
802 uc_pdata->type = REGULATOR_TYPE_LDO;
803 uc_pdata->mode_count = 0;
804
805 return 0;
806}
807
Jacob Chen614704b2017-05-02 14:54:52 +0800808static int rk8xx_switch_probe(struct udevice *dev)
Simon Glassadecfef2016-01-21 19:43:30 -0700809{
810 struct dm_regulator_uclass_platdata *uc_pdata;
811
812 uc_pdata = dev_get_uclass_platdata(dev);
813
814 uc_pdata->type = REGULATOR_TYPE_FIXED;
815 uc_pdata->mode_count = 0;
816
817 return 0;
818}
819
Jacob Chen614704b2017-05-02 14:54:52 +0800820static const struct dm_regulator_ops rk8xx_buck_ops = {
Simon Glassadecfef2016-01-21 19:43:30 -0700821 .get_value = buck_get_value,
822 .set_value = buck_set_value,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800823 .set_suspend_value = buck_set_suspend_value,
824 .get_suspend_value = buck_get_suspend_value,
Simon Glassadecfef2016-01-21 19:43:30 -0700825 .get_enable = buck_get_enable,
826 .set_enable = buck_set_enable,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800827 .set_suspend_enable = buck_set_suspend_enable,
828 .get_suspend_enable = buck_get_suspend_enable,
Simon Glassadecfef2016-01-21 19:43:30 -0700829};
830
Jacob Chen614704b2017-05-02 14:54:52 +0800831static const struct dm_regulator_ops rk8xx_ldo_ops = {
Simon Glassadecfef2016-01-21 19:43:30 -0700832 .get_value = ldo_get_value,
833 .set_value = ldo_set_value,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800834 .set_suspend_value = ldo_set_suspend_value,
835 .get_suspend_value = ldo_get_suspend_value,
Simon Glassadecfef2016-01-21 19:43:30 -0700836 .get_enable = ldo_get_enable,
837 .set_enable = ldo_set_enable,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800838 .set_suspend_enable = ldo_set_suspend_enable,
839 .get_suspend_enable = ldo_get_suspend_enable,
Simon Glassadecfef2016-01-21 19:43:30 -0700840};
841
Jacob Chen614704b2017-05-02 14:54:52 +0800842static const struct dm_regulator_ops rk8xx_switch_ops = {
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800843 .get_value = switch_get_value,
844 .set_value = switch_set_value,
Simon Glassadecfef2016-01-21 19:43:30 -0700845 .get_enable = switch_get_enable,
846 .set_enable = switch_set_enable,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800847 .set_suspend_enable = switch_set_suspend_enable,
848 .get_suspend_enable = switch_get_suspend_enable,
849 .set_suspend_value = switch_set_suspend_value,
850 .get_suspend_value = switch_get_suspend_value,
Simon Glassadecfef2016-01-21 19:43:30 -0700851};
852
Jacob Chen614704b2017-05-02 14:54:52 +0800853U_BOOT_DRIVER(rk8xx_buck) = {
854 .name = "rk8xx_buck",
Simon Glassadecfef2016-01-21 19:43:30 -0700855 .id = UCLASS_REGULATOR,
Jacob Chen614704b2017-05-02 14:54:52 +0800856 .ops = &rk8xx_buck_ops,
857 .probe = rk8xx_buck_probe,
Simon Glassadecfef2016-01-21 19:43:30 -0700858};
859
Jacob Chen614704b2017-05-02 14:54:52 +0800860U_BOOT_DRIVER(rk8xx_ldo) = {
861 .name = "rk8xx_ldo",
Simon Glassadecfef2016-01-21 19:43:30 -0700862 .id = UCLASS_REGULATOR,
Jacob Chen614704b2017-05-02 14:54:52 +0800863 .ops = &rk8xx_ldo_ops,
864 .probe = rk8xx_ldo_probe,
Simon Glassadecfef2016-01-21 19:43:30 -0700865};
866
Jacob Chen614704b2017-05-02 14:54:52 +0800867U_BOOT_DRIVER(rk8xx_switch) = {
868 .name = "rk8xx_switch",
Simon Glassadecfef2016-01-21 19:43:30 -0700869 .id = UCLASS_REGULATOR,
Jacob Chen614704b2017-05-02 14:54:52 +0800870 .ops = &rk8xx_switch_ops,
871 .probe = rk8xx_switch_probe,
Simon Glassadecfef2016-01-21 19:43:30 -0700872};
873#endif
874
Jacob Chen614704b2017-05-02 14:54:52 +0800875int rk8xx_spl_configure_buck(struct udevice *pmic, int buck, int uvolt)
Simon Glassadecfef2016-01-21 19:43:30 -0700876{
877 int ret;
878
879 ret = _buck_set_value(pmic, buck, uvolt);
880 if (ret)
881 return ret;
882
883 return _buck_set_enable(pmic, buck, true);
884}
Wadim Egorovc2581052017-06-19 12:36:39 +0200885
886int rk818_spl_configure_usb_input_current(struct udevice *pmic, int current_ma)
887{
888 uint i;
889
890 for (i = 0; i < ARRAY_SIZE(rk818_chrg_cur_input_array); i++)
891 if (current_ma <= rk818_chrg_cur_input_array[i])
892 break;
893
894 return pmic_clrsetbits(pmic, REG_USB_CTRL, RK818_USB_ILIM_SEL_MASK, i);
895}
896
897int rk818_spl_configure_usb_chrg_shutdown(struct udevice *pmic, int uvolt)
898{
899 uint i;
900
901 for (i = 0; i < ARRAY_SIZE(rk818_chrg_shutdown_vsel_array); i++)
902 if (uvolt <= rk818_chrg_shutdown_vsel_array[i])
903 break;
904
905 return pmic_clrsetbits(pmic, REG_USB_CTRL, RK818_USB_CHG_SD_VSEL_MASK,
906 i);
907}