blob: e99331f6c964bb286862144d8d16ff98954e3e0d [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
Joseph Chend6b3e832019-09-26 15:45:07 +080030/* RK809 BUCK5 */
31#define RK809_BUCK5_CONFIG(n) (0xde + (n) * 1)
32#define RK809_BUCK5_VSEL_MASK 0x07
33
Joseph Chen4a1ae182019-09-26 15:44:55 +080034/* RK817 BUCK */
35#define RK817_BUCK_ON_VSEL(n) (0xbb + 3 * ((n) - 1))
36#define RK817_BUCK_SLP_VSEL(n) (0xbc + 3 * ((n) - 1))
37#define RK817_BUCK_VSEL_MASK 0x7f
38#define RK817_BUCK_CONFIG(i) (0xba + (i) * 3)
39
40/* RK817 LDO */
41#define RK817_LDO_ON_VSEL(n) (0xcc + 2 * ((n) - 1))
42#define RK817_LDO_SLP_VSEL(n) (0xcd + 2 * ((n) - 1))
43#define RK817_LDO_VSEL_MASK 0x7f
44
45/* RK817 ENABLE */
46#define RK817_POWER_EN(n) (0xb1 + (n))
47#define RK817_POWER_SLP_EN(n) (0xb5 + (n))
48
Jacob Chen36163e32017-05-02 14:54:51 +080049#define RK818_BUCK_VSEL_MASK 0x3f
50#define RK818_BUCK4_VSEL_MASK 0x1f
51#define RK818_LDO_VSEL_MASK 0x1f
52#define RK818_LDO3_ON_VSEL_MASK 0xf
53#define RK818_BOOST_ON_VSEL_MASK 0xe0
Wadim Egorovc2581052017-06-19 12:36:39 +020054#define RK818_USB_ILIM_SEL_MASK 0x0f
55#define RK818_USB_CHG_SD_VSEL_MASK 0x70
56
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080057/*
58 * Ramp delay
59 */
Elaine Zhang1d9077e2019-09-26 15:43:55 +080060#define RK805_RAMP_RATE_OFFSET 3
61#define RK805_RAMP_RATE_MASK (3 << RK805_RAMP_RATE_OFFSET)
62#define RK805_RAMP_RATE_3MV_PER_US (0 << RK805_RAMP_RATE_OFFSET)
63#define RK805_RAMP_RATE_6MV_PER_US (1 << RK805_RAMP_RATE_OFFSET)
64#define RK805_RAMP_RATE_12_5MV_PER_US (2 << RK805_RAMP_RATE_OFFSET)
65#define RK805_RAMP_RATE_25MV_PER_US (3 << RK805_RAMP_RATE_OFFSET)
Joseph Chend6b3e832019-09-26 15:45:07 +080066
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080067#define RK808_RAMP_RATE_OFFSET 3
68#define RK808_RAMP_RATE_MASK (3 << RK808_RAMP_RATE_OFFSET)
69#define RK808_RAMP_RATE_2MV_PER_US (0 << RK808_RAMP_RATE_OFFSET)
70#define RK808_RAMP_RATE_4MV_PER_US (1 << RK808_RAMP_RATE_OFFSET)
71#define RK808_RAMP_RATE_6MV_PER_US (2 << RK808_RAMP_RATE_OFFSET)
72#define RK808_RAMP_RATE_10MV_PER_US (3 << RK808_RAMP_RATE_OFFSET)
Jacob Chen36163e32017-05-02 14:54:51 +080073
Joseph Chen4a1ae182019-09-26 15:44:55 +080074#define RK817_RAMP_RATE_OFFSET 6
75#define RK817_RAMP_RATE_MASK (0x3 << RK817_RAMP_RATE_OFFSET)
76#define RK817_RAMP_RATE_3MV_PER_US (0x0 << RK817_RAMP_RATE_OFFSET)
77#define RK817_RAMP_RATE_6_3MV_PER_US (0x1 << RK817_RAMP_RATE_OFFSET)
78#define RK817_RAMP_RATE_12_5MV_PER_US (0x2 << RK817_RAMP_RATE_OFFSET)
79#define RK817_RAMP_RATE_25MV_PER_US (0x3 << RK817_RAMP_RATE_OFFSET)
80
Jacob Chen614704b2017-05-02 14:54:52 +080081struct rk8xx_reg_info {
Simon Glassadecfef2016-01-21 19:43:30 -070082 uint min_uv;
83 uint step_uv;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080084 u8 vsel_reg;
85 u8 vsel_sleep_reg;
86 u8 config_reg;
Jacob Chen21a6a252017-05-02 14:54:50 +080087 u8 vsel_mask;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080088 u8 min_sel;
Simon Glassadecfef2016-01-21 19:43:30 -070089};
90
Jacob Chen614704b2017-05-02 14:54:52 +080091static const struct rk8xx_reg_info rk808_buck[] = {
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080092 { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK808_BUCK_VSEL_MASK, },
93 { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK808_BUCK_VSEL_MASK, },
94 { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK808_BUCK_VSEL_MASK, },
95 { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK808_BUCK4_VSEL_MASK, },
Simon Glassadecfef2016-01-21 19:43:30 -070096};
97
Elaine Zhang04e5a432019-09-26 15:43:54 +080098static const struct rk8xx_reg_info rk816_buck[] = {
99 /* buck 1 */
100 { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, },
101 { 1800000, 200000, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, },
102 { 2300000, 0, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, },
103 /* buck 2 */
104 { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, },
105 { 1800000, 200000, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, },
106 { 2300000, 0, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, },
107 /* buck 3 */
108 { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK818_BUCK_VSEL_MASK, },
109 /* buck 4 */
110 { 800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, },
111};
112
Joseph Chend6b3e832019-09-26 15:45:07 +0800113static const struct rk8xx_reg_info rk809_buck5[] = {
114 /* buck 5 */
115 { 1500000, 0, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x00, },
116 { 1800000, 200000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x01, },
117 { 2800000, 200000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x04, },
118 { 3300000, 300000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x06, },
119};
120
Joseph Chen4a1ae182019-09-26 15:44:55 +0800121static const struct rk8xx_reg_info rk817_buck[] = {
122 /* buck 1 */
123 { 500000, 12500, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x00, },
124 { 1500000, 100000, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x50, },
125 { 2400000, 0, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x59, },
126 /* buck 2 */
127 { 500000, 12500, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x00, },
128 { 1500000, 100000, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x50, },
129 { 2400000, 0, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x59, },
130 /* buck 3 */
131 { 500000, 12500, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x00, },
132 { 1500000, 100000, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x50, },
133 { 2400000, 0, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x59, },
134 /* buck 4 */
135 { 500000, 12500, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x00, },
136 { 1500000, 100000, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x50, },
137 { 3400000, 0, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x63, },
138};
139
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200140static const struct rk8xx_reg_info rk818_buck[] = {
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800141 { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, },
142 { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, },
143 { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK818_BUCK_VSEL_MASK, },
144 { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, },
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200145};
146
147#ifdef ENABLE_DRIVER
Jacob Chen614704b2017-05-02 14:54:52 +0800148static const struct rk8xx_reg_info rk808_ldo[] = {
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800149 { 1800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
150 { 1800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
151 { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK808_BUCK4_VSEL_MASK, },
152 { 1800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
153 { 1800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
154 { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
155 { 800000, 100000, REG_LDO7_ON_VSEL, REG_LDO7_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
156 { 1800000, 100000, REG_LDO8_ON_VSEL, REG_LDO8_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
Simon Glassadecfef2016-01-21 19:43:30 -0700157};
158
Elaine Zhang04e5a432019-09-26 15:43:54 +0800159static const struct rk8xx_reg_info rk816_ldo[] = {
160 { 800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
161 { 800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
162 { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
163 { 800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
164 { 800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
165 { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
166};
167
Joseph Chen4a1ae182019-09-26 15:44:55 +0800168static const struct rk8xx_reg_info rk817_ldo[] = {
169 /* ldo1 */
170 { 600000, 25000, RK817_LDO_ON_VSEL(1), RK817_LDO_SLP_VSEL(1), NA, RK817_LDO_VSEL_MASK, 0x00, },
171 { 3400000, 0, RK817_LDO_ON_VSEL(1), RK817_LDO_SLP_VSEL(1), NA, RK817_LDO_VSEL_MASK, 0x70, },
172 /* ldo2 */
173 { 600000, 25000, RK817_LDO_ON_VSEL(2), RK817_LDO_SLP_VSEL(2), NA, RK817_LDO_VSEL_MASK, 0x00, },
174 { 3400000, 0, RK817_LDO_ON_VSEL(2), RK817_LDO_SLP_VSEL(2), NA, RK817_LDO_VSEL_MASK, 0x70, },
175 /* ldo3 */
176 { 600000, 25000, RK817_LDO_ON_VSEL(3), RK817_LDO_SLP_VSEL(3), NA, RK817_LDO_VSEL_MASK, 0x00, },
177 { 3400000, 0, RK817_LDO_ON_VSEL(3), RK817_LDO_SLP_VSEL(3), NA, RK817_LDO_VSEL_MASK, 0x70, },
178 /* ldo4 */
179 { 600000, 25000, RK817_LDO_ON_VSEL(4), RK817_LDO_SLP_VSEL(4), NA, RK817_LDO_VSEL_MASK, 0x00, },
180 { 3400000, 0, RK817_LDO_ON_VSEL(4), RK817_LDO_SLP_VSEL(4), NA, RK817_LDO_VSEL_MASK, 0x70, },
181 /* ldo5 */
182 { 600000, 25000, RK817_LDO_ON_VSEL(5), RK817_LDO_SLP_VSEL(5), NA, RK817_LDO_VSEL_MASK, 0x00, },
183 { 3400000, 0, RK817_LDO_ON_VSEL(5), RK817_LDO_SLP_VSEL(5), NA, RK817_LDO_VSEL_MASK, 0x70, },
184 /* ldo6 */
185 { 600000, 25000, RK817_LDO_ON_VSEL(6), RK817_LDO_SLP_VSEL(6), NA, RK817_LDO_VSEL_MASK, 0x00, },
186 { 3400000, 0, RK817_LDO_ON_VSEL(6), RK817_LDO_SLP_VSEL(6), NA, RK817_LDO_VSEL_MASK, 0x70, },
187 /* ldo7 */
188 { 600000, 25000, RK817_LDO_ON_VSEL(7), RK817_LDO_SLP_VSEL(7), NA, RK817_LDO_VSEL_MASK, 0x00, },
189 { 3400000, 0, RK817_LDO_ON_VSEL(7), RK817_LDO_SLP_VSEL(7), NA, RK817_LDO_VSEL_MASK, 0x70, },
190 /* ldo8 */
191 { 600000, 25000, RK817_LDO_ON_VSEL(8), RK817_LDO_SLP_VSEL(8), NA, RK817_LDO_VSEL_MASK, 0x00, },
192 { 3400000, 0, RK817_LDO_ON_VSEL(8), RK817_LDO_SLP_VSEL(8), NA, RK817_LDO_VSEL_MASK, 0x70, },
193 /* ldo9 */
194 { 600000, 25000, RK817_LDO_ON_VSEL(9), RK817_LDO_SLP_VSEL(9), NA, RK817_LDO_VSEL_MASK, 0x00, },
195 { 3400000, 0, RK817_LDO_ON_VSEL(9), RK817_LDO_SLP_VSEL(9), NA, RK817_LDO_VSEL_MASK, 0x70, },
196};
197
Jacob Chen614704b2017-05-02 14:54:52 +0800198static const struct rk8xx_reg_info rk818_ldo[] = {
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800199 { 1800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
200 { 1800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
201 { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK818_LDO3_ON_VSEL_MASK, },
202 { 1800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
203 { 1800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
204 { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
205 { 800000, 100000, REG_LDO7_ON_VSEL, REG_LDO7_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
206 { 1800000, 100000, REG_LDO8_ON_VSEL, REG_LDO8_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
Jacob Chen36163e32017-05-02 14:54:51 +0800207};
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200208#endif
Jacob Chen36163e32017-05-02 14:54:51 +0800209
Wadim Egorovc2581052017-06-19 12:36:39 +0200210static const u16 rk818_chrg_cur_input_array[] = {
211 450, 800, 850, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000
212};
213
214static const uint rk818_chrg_shutdown_vsel_array[] = {
215 2780000, 2850000, 2920000, 2990000, 3060000, 3130000, 3190000, 3260000
216};
217
Jacob Chen614704b2017-05-02 14:54:52 +0800218static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800219 int num, int uvolt)
Jacob Chen36163e32017-05-02 14:54:51 +0800220{
Jacob Chen614704b2017-05-02 14:54:52 +0800221 struct rk8xx_priv *priv = dev_get_priv(pmic);
Elaine Zhang04e5a432019-09-26 15:43:54 +0800222
Jacob Chen614704b2017-05-02 14:54:52 +0800223 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800224 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800225 case RK816_ID:
226 switch (num) {
227 case 0:
228 case 1:
229 if (uvolt <= 1450000)
230 return &rk816_buck[num * 3 + 0];
231 else if (uvolt <= 2200000)
232 return &rk816_buck[num * 3 + 1];
233 else
234 return &rk816_buck[num * 3 + 2];
235 default:
236 return &rk816_buck[num + 4];
237 }
Joseph Chen4a1ae182019-09-26 15:44:55 +0800238
Joseph Chend6b3e832019-09-26 15:45:07 +0800239 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800240 case RK817_ID:
241 switch (num) {
242 case 0 ... 2:
243 if (uvolt < 1500000)
244 return &rk817_buck[num * 3 + 0];
245 else if (uvolt < 2400000)
246 return &rk817_buck[num * 3 + 1];
247 else
248 return &rk817_buck[num * 3 + 2];
249 case 3:
250 if (uvolt < 1500000)
251 return &rk817_buck[num * 3 + 0];
252 else if (uvolt < 3400000)
253 return &rk817_buck[num * 3 + 1];
254 else
255 return &rk817_buck[num * 3 + 2];
Joseph Chend6b3e832019-09-26 15:45:07 +0800256 /* BUCK5 for RK809 */
257 default:
258 if (uvolt < 1800000)
259 return &rk809_buck5[0];
260 else if (uvolt < 2800000)
261 return &rk809_buck5[1];
262 else if (uvolt < 3300000)
263 return &rk809_buck5[2];
264 else
265 return &rk809_buck5[3];
Joseph Chen4a1ae182019-09-26 15:44:55 +0800266 }
Jacob Chen36163e32017-05-02 14:54:51 +0800267 case RK818_ID:
268 return &rk818_buck[num];
269 default:
270 return &rk808_buck[num];
271 }
272}
273
Simon Glassadecfef2016-01-21 19:43:30 -0700274static int _buck_set_value(struct udevice *pmic, int buck, int uvolt)
275{
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800276 const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt);
Elaine Zhang04e5a432019-09-26 15:43:54 +0800277 struct rk8xx_priv *priv = dev_get_priv(pmic);
Jacob Chen21a6a252017-05-02 14:54:50 +0800278 int mask = info->vsel_mask;
Simon Glassadecfef2016-01-21 19:43:30 -0700279 int val;
280
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800281 if (info->vsel_reg == NA)
Simon Glassadecfef2016-01-21 19:43:30 -0700282 return -ENOSYS;
Elaine Zhang04e5a432019-09-26 15:43:54 +0800283
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800284 if (info->step_uv == 0) /* Fixed voltage */
285 val = info->min_sel;
286 else
287 val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
288
289 debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
290 __func__, uvolt, buck + 1, info->vsel_reg, mask, val);
291
Elaine Zhang04e5a432019-09-26 15:43:54 +0800292 if (priv->variant == RK816_ID) {
293 pmic_clrsetbits(pmic, info->vsel_reg, mask, val);
294 return pmic_clrsetbits(pmic, RK816_REG_DCDC_EN2,
295 1 << 7, 1 << 7);
296 } else {
297 return pmic_clrsetbits(pmic, info->vsel_reg, mask, val);
298 }
Simon Glassadecfef2016-01-21 19:43:30 -0700299}
300
301static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
302{
Elaine Zhang04e5a432019-09-26 15:43:54 +0800303 uint mask, value, en_reg;
Joseph Chen4a1ae182019-09-26 15:44:55 +0800304 int ret = 0;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800305 struct rk8xx_priv *priv = dev_get_priv(pmic);
Simon Glassadecfef2016-01-21 19:43:30 -0700306
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800307 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800308 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800309 case RK816_ID:
310 if (buck >= 4) {
311 buck -= 4;
312 en_reg = RK816_REG_DCDC_EN2;
313 } else {
314 en_reg = RK816_REG_DCDC_EN1;
315 }
316 if (enable)
317 value = ((1 << buck) | (1 << (buck + 4)));
318 else
319 value = ((0 << buck) | (1 << (buck + 4)));
320 ret = pmic_reg_write(pmic, en_reg, value);
321 break;
322
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800323 case RK808_ID:
324 case RK818_ID:
325 mask = 1 << buck;
326 if (enable) {
327 ret = pmic_clrsetbits(pmic, REG_DCDC_ILMAX,
328 0, 3 << (buck * 2));
329 if (ret)
330 return ret;
331 }
332 ret = pmic_clrsetbits(pmic, REG_DCDC_EN, mask,
333 enable ? mask : 0);
334 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800335 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800336 case RK817_ID:
337 if (buck < 4) {
338 if (enable)
339 value = ((1 << buck) | (1 << (buck + 4)));
340 else
341 value = ((0 << buck) | (1 << (buck + 4)));
342 ret = pmic_reg_write(pmic, RK817_POWER_EN(0), value);
Joseph Chend6b3e832019-09-26 15:45:07 +0800343 /* BUCK5 for RK809 */
344 } else {
345 if (enable)
346 value = ((1 << 1) | (1 << 5));
347 else
348 value = ((0 << 1) | (1 << 5));
349 ret = pmic_reg_write(pmic, RK817_POWER_EN(3), value);
Joseph Chen4a1ae182019-09-26 15:44:55 +0800350 }
351 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800352 default:
353 ret = -EINVAL;
Simon Glassadecfef2016-01-21 19:43:30 -0700354 }
355
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800356 return ret;
Simon Glassadecfef2016-01-21 19:43:30 -0700357}
358
359#ifdef ENABLE_DRIVER
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800360static int _buck_set_suspend_value(struct udevice *pmic, int buck, int uvolt)
361{
362 const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt);
363 int mask = info->vsel_mask;
364 int val;
365
366 if (info->vsel_sleep_reg == NA)
367 return -ENOSYS;
368
369 if (info->step_uv == 0)
370 val = info->min_sel;
371 else
372 val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
373
374 debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
375 __func__, uvolt, buck + 1, info->vsel_sleep_reg, mask, val);
376
377 return pmic_clrsetbits(pmic, info->vsel_sleep_reg, mask, val);
378}
379
380static int _buck_get_enable(struct udevice *pmic, int buck)
381{
382 struct rk8xx_priv *priv = dev_get_priv(pmic);
383 uint mask = 0;
384 int ret = 0;
385
386 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800387 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800388 case RK816_ID:
389 if (buck >= 4) {
390 mask = 1 << (buck - 4);
391 ret = pmic_reg_read(pmic, RK816_REG_DCDC_EN2);
392 } else {
393 mask = 1 << buck;
394 ret = pmic_reg_read(pmic, RK816_REG_DCDC_EN1);
395 }
396 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800397 case RK808_ID:
398 case RK818_ID:
399 mask = 1 << buck;
400 ret = pmic_reg_read(pmic, REG_DCDC_EN);
401 if (ret < 0)
402 return ret;
403 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800404 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800405 case RK817_ID:
406 if (buck < 4) {
407 mask = 1 << buck;
408 ret = pmic_reg_read(pmic, RK817_POWER_EN(0));
Joseph Chend6b3e832019-09-26 15:45:07 +0800409 /* BUCK5 for RK809 */
410 } else {
411 mask = 1 << 1;
412 ret = pmic_reg_read(pmic, RK817_POWER_EN(3));
Joseph Chen4a1ae182019-09-26 15:44:55 +0800413 }
414 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800415 }
416
417 if (ret < 0)
418 return ret;
419
420 return ret & mask ? true : false;
421}
422
423static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable)
424{
Joseph Chen4a1ae182019-09-26 15:44:55 +0800425 uint mask = 0;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800426 int ret;
427 struct rk8xx_priv *priv = dev_get_priv(pmic);
428
429 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800430 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800431 case RK816_ID:
432 mask = 1 << buck;
433 ret = pmic_clrsetbits(pmic, RK816_REG_DCDC_SLP_EN, mask,
434 enable ? mask : 0);
435 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800436 case RK808_ID:
437 case RK818_ID:
438 mask = 1 << buck;
439 ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF1, mask,
440 enable ? 0 : mask);
441 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800442 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800443 case RK817_ID:
444 if (buck < 4)
445 mask = 1 << buck;
Joseph Chend6b3e832019-09-26 15:45:07 +0800446 else
447 mask = 1 << 5; /* BUCK5 for RK809 */
Joseph Chen4a1ae182019-09-26 15:44:55 +0800448 ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(0), mask,
449 enable ? mask : 0);
450 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800451 default:
452 ret = -EINVAL;
453 }
454
455 return ret;
456}
457
458static int _buck_get_suspend_enable(struct udevice *pmic, int buck)
459{
460 struct rk8xx_priv *priv = dev_get_priv(pmic);
461 int ret, val;
Joseph Chen4a1ae182019-09-26 15:44:55 +0800462 uint mask = 0;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800463
464 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800465 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800466 case RK816_ID:
467 mask = 1 << buck;
468 val = pmic_reg_read(pmic, RK816_REG_DCDC_SLP_EN);
469 if (val < 0)
470 return val;
471 ret = val & mask ? 1 : 0;
472 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800473 case RK808_ID:
474 case RK818_ID:
475 mask = 1 << buck;
476 val = pmic_reg_read(pmic, REG_SLEEP_SET_OFF1);
477 if (val < 0)
478 return val;
479 ret = val & mask ? 0 : 1;
480 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800481 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800482 case RK817_ID:
483 if (buck < 4)
484 mask = 1 << buck;
Joseph Chend6b3e832019-09-26 15:45:07 +0800485 else
486 mask = 1 << 5; /* BUCK5 for RK809 */
Joseph Chen4a1ae182019-09-26 15:44:55 +0800487
488 val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(0));
489 if (val < 0)
490 return val;
491 ret = val & mask ? 1 : 0;
492 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800493 default:
494 ret = -EINVAL;
495 }
496
497 return ret;
498}
499
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200500static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800501 int num, int uvolt)
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200502{
503 struct rk8xx_priv *priv = dev_get_priv(pmic);
Elaine Zhang04e5a432019-09-26 15:43:54 +0800504
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200505 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800506 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800507 case RK816_ID:
508 return &rk816_ldo[num];
Joseph Chend6b3e832019-09-26 15:45:07 +0800509 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800510 case RK817_ID:
511 if (uvolt < 3400000)
512 return &rk817_ldo[num * 2 + 0];
513 else
514 return &rk817_ldo[num * 2 + 1];
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200515 case RK818_ID:
516 return &rk818_ldo[num];
517 default:
518 return &rk808_ldo[num];
519 }
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800520}
521
522static int _ldo_get_enable(struct udevice *pmic, int ldo)
523{
524 struct rk8xx_priv *priv = dev_get_priv(pmic);
525 uint mask = 0;
526 int ret = 0;
527
528 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800529 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800530 case RK816_ID:
531 if (ldo >= 4) {
532 mask = 1 << (ldo - 4);
533 ret = pmic_reg_read(pmic, RK816_REG_LDO_EN2);
534 } else {
535 mask = 1 << ldo;
536 ret = pmic_reg_read(pmic, RK816_REG_LDO_EN1);
537 }
538 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800539 case RK808_ID:
540 case RK818_ID:
541 mask = 1 << ldo;
542 ret = pmic_reg_read(pmic, REG_LDO_EN);
543 if (ret < 0)
544 return ret;
545 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800546 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800547 case RK817_ID:
548 if (ldo < 4) {
549 mask = 1 << ldo;
550 ret = pmic_reg_read(pmic, RK817_POWER_EN(1));
551 } else if (ldo < 8) {
552 mask = 1 << (ldo - 4);
553 ret = pmic_reg_read(pmic, RK817_POWER_EN(2));
554 } else if (ldo == 8) {
555 mask = 1 << 0;
556 ret = pmic_reg_read(pmic, RK817_POWER_EN(3));
557 } else {
558 return false;
559 }
560 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800561 }
562
563 if (ret < 0)
564 return ret;
565
566 return ret & mask ? true : false;
567}
568
569static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable)
570{
571 struct rk8xx_priv *priv = dev_get_priv(pmic);
Elaine Zhang04e5a432019-09-26 15:43:54 +0800572 uint mask, value, en_reg;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800573 int ret = 0;
574
575 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800576 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800577 case RK816_ID:
578 if (ldo >= 4) {
579 ldo -= 4;
580 en_reg = RK816_REG_LDO_EN2;
581 } else {
582 en_reg = RK816_REG_LDO_EN1;
583 }
584 if (enable)
585 value = ((1 << ldo) | (1 << (ldo + 4)));
586 else
587 value = ((0 << ldo) | (1 << (ldo + 4)));
588
589 ret = pmic_reg_write(pmic, en_reg, value);
590 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800591 case RK808_ID:
592 case RK818_ID:
593 mask = 1 << ldo;
594 ret = pmic_clrsetbits(pmic, REG_LDO_EN, mask,
Elaine Zhang04e5a432019-09-26 15:43:54 +0800595 enable ? mask : 0);
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800596 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800597 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800598 case RK817_ID:
599 if (ldo < 4) {
600 en_reg = RK817_POWER_EN(1);
601 } else if (ldo < 8) {
602 ldo -= 4;
603 en_reg = RK817_POWER_EN(2);
604 } else if (ldo == 8) {
605 ldo = 0; /* BIT 0 */
606 en_reg = RK817_POWER_EN(3);
607 } else {
608 return -EINVAL;
609 }
610 if (enable)
611 value = ((1 << ldo) | (1 << (ldo + 4)));
612 else
613 value = ((0 << ldo) | (1 << (ldo + 4)));
614 ret = pmic_reg_write(pmic, en_reg, value);
615 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800616 }
617
618 return ret;
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200619}
620
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800621static int _ldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable)
622{
623 struct rk8xx_priv *priv = dev_get_priv(pmic);
624 uint mask;
625 int ret = 0;
626
627 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800628 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800629 case RK816_ID:
630 mask = 1 << ldo;
631 ret = pmic_clrsetbits(pmic, RK816_REG_LDO_SLP_EN, mask,
632 enable ? mask : 0);
633 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800634 case RK808_ID:
635 case RK818_ID:
636 mask = 1 << ldo;
637 ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF2, mask,
638 enable ? 0 : mask);
639 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800640 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800641 case RK817_ID:
642 if (ldo == 8) {
643 mask = 1 << 4; /* LDO9 */
644 ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(0), mask,
645 enable ? mask : 0);
646 } else {
647 mask = 1 << ldo;
648 ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(1), mask,
649 enable ? mask : 0);
650 }
651 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800652 }
653
654 return ret;
655}
656
657static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo)
658{
659 struct rk8xx_priv *priv = dev_get_priv(pmic);
660 int val, ret = 0;
661 uint mask;
662
663 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800664 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800665 case RK816_ID:
666 mask = 1 << ldo;
667 val = pmic_reg_read(pmic, RK816_REG_LDO_SLP_EN);
668 if (val < 0)
669 return val;
670 ret = val & mask ? 1 : 0;
671 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800672 case RK808_ID:
673 case RK818_ID:
674 mask = 1 << ldo;
675 val = pmic_reg_read(pmic, REG_SLEEP_SET_OFF2);
676 if (val < 0)
677 return val;
678 ret = val & mask ? 0 : 1;
679 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800680 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800681 case RK817_ID:
682 if (ldo == 8) {
683 mask = 1 << 4; /* LDO9 */
684 val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(0));
685 if (val < 0)
686 return val;
687 ret = val & mask ? 1 : 0;
688 } else {
689 mask = 1 << ldo;
690 val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(1));
691 if (val < 0)
692 return val;
693 ret = val & mask ? 1 : 0;
694 }
695 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800696 }
697
698 return ret;
699}
700
Simon Glassadecfef2016-01-21 19:43:30 -0700701static int buck_get_value(struct udevice *dev)
702{
703 int buck = dev->driver_data - 1;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800704 /* We assume level-1 voltage is enough for usage in U-Boot */
705 const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0);
Jacob Chen21a6a252017-05-02 14:54:50 +0800706 int mask = info->vsel_mask;
Simon Glassadecfef2016-01-21 19:43:30 -0700707 int ret, val;
708
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800709 if (info->vsel_reg == NA)
Simon Glassadecfef2016-01-21 19:43:30 -0700710 return -ENOSYS;
Elaine Zhang04e5a432019-09-26 15:43:54 +0800711
Simon Glassadecfef2016-01-21 19:43:30 -0700712 ret = pmic_reg_read(dev->parent, info->vsel_reg);
713 if (ret < 0)
714 return ret;
715 val = ret & mask;
716
717 return info->min_uv + val * info->step_uv;
718}
719
720static int buck_set_value(struct udevice *dev, int uvolt)
721{
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800722 int buck = dev->driver_data - 1;
Simon Glassadecfef2016-01-21 19:43:30 -0700723
724 return _buck_set_value(dev->parent, buck, uvolt);
725}
726
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800727static int buck_get_suspend_value(struct udevice *dev)
728{
729 int buck = dev->driver_data - 1;
730 /* We assume level-1 voltage is enough for usage in U-Boot */
731 const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0);
732 int mask = info->vsel_mask;
733 int ret, val;
734
735 if (info->vsel_sleep_reg == NA)
736 return -ENOSYS;
737
738 ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg);
739 if (ret < 0)
740 return ret;
741
742 val = ret & mask;
743
744 return info->min_uv + val * info->step_uv;
745}
746
747static int buck_set_suspend_value(struct udevice *dev, int uvolt)
748{
749 int buck = dev->driver_data - 1;
750
751 return _buck_set_suspend_value(dev->parent, buck, uvolt);
752}
753
Simon Glassadecfef2016-01-21 19:43:30 -0700754static int buck_set_enable(struct udevice *dev, bool enable)
755{
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800756 int buck = dev->driver_data - 1;
Simon Glassadecfef2016-01-21 19:43:30 -0700757
758 return _buck_set_enable(dev->parent, buck, enable);
759}
760
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800761static int buck_set_suspend_enable(struct udevice *dev, bool enable)
Simon Glassadecfef2016-01-21 19:43:30 -0700762{
763 int buck = dev->driver_data - 1;
Simon Glassadecfef2016-01-21 19:43:30 -0700764
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800765 return _buck_set_suspend_enable(dev->parent, buck, enable);
766}
Simon Glassadecfef2016-01-21 19:43:30 -0700767
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800768static int buck_get_suspend_enable(struct udevice *dev)
769{
770 int buck = dev->driver_data - 1;
Simon Glassadecfef2016-01-21 19:43:30 -0700771
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800772 return _buck_get_suspend_enable(dev->parent, buck);
Simon Glassadecfef2016-01-21 19:43:30 -0700773}
774
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800775static int buck_get_enable(struct udevice *dev)
776{
777 int buck = dev->driver_data - 1;
778
779 return _buck_get_enable(dev->parent, buck);
780}
781
Simon Glassadecfef2016-01-21 19:43:30 -0700782static int ldo_get_value(struct udevice *dev)
783{
784 int ldo = dev->driver_data - 1;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800785 const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0);
Jacob Chen21a6a252017-05-02 14:54:50 +0800786 int mask = info->vsel_mask;
Simon Glassadecfef2016-01-21 19:43:30 -0700787 int ret, val;
788
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800789 if (info->vsel_reg == NA)
Simon Glassadecfef2016-01-21 19:43:30 -0700790 return -ENOSYS;
791 ret = pmic_reg_read(dev->parent, info->vsel_reg);
792 if (ret < 0)
793 return ret;
794 val = ret & mask;
795
796 return info->min_uv + val * info->step_uv;
797}
798
799static int ldo_set_value(struct udevice *dev, int uvolt)
800{
801 int ldo = dev->driver_data - 1;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800802 const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, uvolt);
Jacob Chen21a6a252017-05-02 14:54:50 +0800803 int mask = info->vsel_mask;
Simon Glassadecfef2016-01-21 19:43:30 -0700804 int val;
805
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800806 if (info->vsel_reg == NA)
Simon Glassadecfef2016-01-21 19:43:30 -0700807 return -ENOSYS;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800808
809 if (info->step_uv == 0)
810 val = info->min_sel;
811 else
812 val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
813
814 debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
815 __func__, uvolt, ldo + 1, info->vsel_reg, mask, val);
Simon Glassadecfef2016-01-21 19:43:30 -0700816
817 return pmic_clrsetbits(dev->parent, info->vsel_reg, mask, val);
818}
819
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800820static int ldo_set_suspend_value(struct udevice *dev, int uvolt)
Simon Glassadecfef2016-01-21 19:43:30 -0700821{
822 int ldo = dev->driver_data - 1;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800823 const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, uvolt);
824 int mask = info->vsel_mask;
825 int val;
826
827 if (info->vsel_sleep_reg == NA)
828 return -ENOSYS;
Simon Glassadecfef2016-01-21 19:43:30 -0700829
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800830 if (info->step_uv == 0)
831 val = info->min_sel;
832 else
833 val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
Simon Glassadecfef2016-01-21 19:43:30 -0700834
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800835 debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
836 __func__, uvolt, ldo + 1, info->vsel_sleep_reg, mask, val);
837
838 return pmic_clrsetbits(dev->parent, info->vsel_sleep_reg, mask, val);
Simon Glassadecfef2016-01-21 19:43:30 -0700839}
840
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800841static int ldo_get_suspend_value(struct udevice *dev)
Simon Glassadecfef2016-01-21 19:43:30 -0700842{
843 int ldo = dev->driver_data - 1;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800844 const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0);
845 int mask = info->vsel_mask;
846 int val, ret;
Simon Glassadecfef2016-01-21 19:43:30 -0700847
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800848 if (info->vsel_sleep_reg == NA)
849 return -ENOSYS;
Simon Glassadecfef2016-01-21 19:43:30 -0700850
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800851 ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg);
Simon Glassadecfef2016-01-21 19:43:30 -0700852 if (ret < 0)
853 return ret;
854
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800855 val = ret & mask;
856
857 return info->min_uv + val * info->step_uv;
858}
859
860static int ldo_set_enable(struct udevice *dev, bool enable)
861{
862 int ldo = dev->driver_data - 1;
863
864 return _ldo_set_enable(dev->parent, ldo, enable);
865}
866
867static int ldo_set_suspend_enable(struct udevice *dev, bool enable)
868{
869 int ldo = dev->driver_data - 1;
870
871 return _ldo_set_suspend_enable(dev->parent, ldo, enable);
872}
873
874static int ldo_get_suspend_enable(struct udevice *dev)
875{
876 int ldo = dev->driver_data - 1;
877
878 return _ldo_get_suspend_enable(dev->parent, ldo);
879}
880
881static int ldo_get_enable(struct udevice *dev)
882{
883 int ldo = dev->driver_data - 1;
884
885 return _ldo_get_enable(dev->parent, ldo);
Simon Glassadecfef2016-01-21 19:43:30 -0700886}
887
888static int switch_set_enable(struct udevice *dev, bool enable)
889{
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800890 struct rk8xx_priv *priv = dev_get_priv(dev->parent);
891 int ret = 0, sw = dev->driver_data - 1;
892 uint mask = 0;
893
894 switch (priv->variant) {
895 case RK808_ID:
896 mask = 1 << (sw + 5);
897 ret = pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask,
898 enable ? mask : 0);
899 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800900 case RK809_ID:
901 mask = (1 << (sw + 2)) | (1 << (sw + 6));
902 ret = pmic_clrsetbits(dev->parent, RK817_POWER_EN(3), mask,
903 enable ? mask : 0);
904 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800905 case RK818_ID:
906 mask = 1 << 6;
907 ret = pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask,
908 enable ? mask : 0);
909 break;
910 }
Simon Glassadecfef2016-01-21 19:43:30 -0700911
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800912 debug("%s: switch%d, enable=%d, mask=0x%x\n",
913 __func__, sw + 1, enable, mask);
Simon Glassadecfef2016-01-21 19:43:30 -0700914
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800915 return ret;
Simon Glassadecfef2016-01-21 19:43:30 -0700916}
917
Keerthyc8f82fb2017-06-13 09:53:52 +0530918static int switch_get_enable(struct udevice *dev)
Simon Glassadecfef2016-01-21 19:43:30 -0700919{
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800920 struct rk8xx_priv *priv = dev_get_priv(dev->parent);
921 int ret = 0, sw = dev->driver_data - 1;
922 uint mask = 0;
Simon Glassadecfef2016-01-21 19:43:30 -0700923
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800924 switch (priv->variant) {
925 case RK808_ID:
926 mask = 1 << (sw + 5);
927 ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
928 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800929 case RK809_ID:
930 mask = 1 << (sw + 2);
931 ret = pmic_reg_read(dev->parent, RK817_POWER_EN(3));
932 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800933 case RK818_ID:
934 mask = 1 << 6;
935 ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
936 break;
937 }
Simon Glassadecfef2016-01-21 19:43:30 -0700938
Simon Glassadecfef2016-01-21 19:43:30 -0700939 if (ret < 0)
940 return ret;
941
942 return ret & mask ? true : false;
943}
944
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800945static int switch_set_suspend_value(struct udevice *dev, int uvolt)
946{
947 return 0;
948}
949
950static int switch_get_suspend_value(struct udevice *dev)
951{
952 return 0;
953}
954
955static int switch_set_suspend_enable(struct udevice *dev, bool enable)
956{
957 struct rk8xx_priv *priv = dev_get_priv(dev->parent);
958 int ret = 0, sw = dev->driver_data - 1;
959 uint mask = 0;
960
961 switch (priv->variant) {
962 case RK808_ID:
963 mask = 1 << (sw + 5);
964 ret = pmic_clrsetbits(dev->parent, REG_SLEEP_SET_OFF1, mask,
965 enable ? 0 : mask);
966 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800967 case RK809_ID:
968 mask = 1 << (sw + 6);
969 ret = pmic_clrsetbits(dev->parent, RK817_POWER_SLP_EN(0), mask,
970 enable ? mask : 0);
971 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800972 case RK818_ID:
973 mask = 1 << 6;
974 ret = pmic_clrsetbits(dev->parent, REG_SLEEP_SET_OFF1, mask,
975 enable ? 0 : mask);
976 break;
977 }
978
979 debug("%s: switch%d, enable=%d, mask=0x%x\n",
980 __func__, sw + 1, enable, mask);
981
982 return ret;
983}
984
985static int switch_get_suspend_enable(struct udevice *dev)
986{
987 struct rk8xx_priv *priv = dev_get_priv(dev->parent);
988 int val, ret = 0, sw = dev->driver_data - 1;
989 uint mask = 0;
990
991 switch (priv->variant) {
992 case RK808_ID:
993 mask = 1 << (sw + 5);
994 val = pmic_reg_read(dev->parent, REG_SLEEP_SET_OFF1);
995 if (val < 0)
996 return val;
997 ret = val & mask ? 0 : 1;
998 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800999 case RK809_ID:
1000 mask = 1 << (sw + 6);
1001 val = pmic_reg_read(dev->parent, RK817_POWER_SLP_EN(0));
1002 if (val < 0)
1003 return val;
1004 ret = val & mask ? 1 : 0;
1005 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +08001006 case RK818_ID:
1007 mask = 1 << 6;
1008 val = pmic_reg_read(dev->parent, REG_SLEEP_SET_OFF1);
1009 if (val < 0)
1010 return val;
1011 ret = val & mask ? 0 : 1;
1012 break;
1013 }
1014
1015 return ret;
1016}
1017
1018/*
1019 * RK8xx switch does not need to set the voltage,
1020 * but if dts set regulator-min-microvolt/regulator-max-microvolt,
1021 * will cause regulator set value fail and not to enable this switch.
1022 * So add an empty function to return success.
1023 */
1024static int switch_get_value(struct udevice *dev)
1025{
1026 return 0;
1027}
1028
1029static int switch_set_value(struct udevice *dev, int uvolt)
1030{
1031 return 0;
1032}
1033
Jacob Chen614704b2017-05-02 14:54:52 +08001034static int rk8xx_buck_probe(struct udevice *dev)
Simon Glassadecfef2016-01-21 19:43:30 -07001035{
1036 struct dm_regulator_uclass_platdata *uc_pdata;
1037
1038 uc_pdata = dev_get_uclass_platdata(dev);
1039
1040 uc_pdata->type = REGULATOR_TYPE_BUCK;
1041 uc_pdata->mode_count = 0;
1042
1043 return 0;
1044}
1045
Jacob Chen614704b2017-05-02 14:54:52 +08001046static int rk8xx_ldo_probe(struct udevice *dev)
Simon Glassadecfef2016-01-21 19:43:30 -07001047{
1048 struct dm_regulator_uclass_platdata *uc_pdata;
1049
1050 uc_pdata = dev_get_uclass_platdata(dev);
1051
1052 uc_pdata->type = REGULATOR_TYPE_LDO;
1053 uc_pdata->mode_count = 0;
1054
1055 return 0;
1056}
1057
Jacob Chen614704b2017-05-02 14:54:52 +08001058static int rk8xx_switch_probe(struct udevice *dev)
Simon Glassadecfef2016-01-21 19:43:30 -07001059{
1060 struct dm_regulator_uclass_platdata *uc_pdata;
1061
1062 uc_pdata = dev_get_uclass_platdata(dev);
1063
1064 uc_pdata->type = REGULATOR_TYPE_FIXED;
1065 uc_pdata->mode_count = 0;
1066
1067 return 0;
1068}
1069
Jacob Chen614704b2017-05-02 14:54:52 +08001070static const struct dm_regulator_ops rk8xx_buck_ops = {
Simon Glassadecfef2016-01-21 19:43:30 -07001071 .get_value = buck_get_value,
1072 .set_value = buck_set_value,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +08001073 .set_suspend_value = buck_set_suspend_value,
1074 .get_suspend_value = buck_get_suspend_value,
Simon Glassadecfef2016-01-21 19:43:30 -07001075 .get_enable = buck_get_enable,
1076 .set_enable = buck_set_enable,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +08001077 .set_suspend_enable = buck_set_suspend_enable,
1078 .get_suspend_enable = buck_get_suspend_enable,
Simon Glassadecfef2016-01-21 19:43:30 -07001079};
1080
Jacob Chen614704b2017-05-02 14:54:52 +08001081static const struct dm_regulator_ops rk8xx_ldo_ops = {
Simon Glassadecfef2016-01-21 19:43:30 -07001082 .get_value = ldo_get_value,
1083 .set_value = ldo_set_value,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +08001084 .set_suspend_value = ldo_set_suspend_value,
1085 .get_suspend_value = ldo_get_suspend_value,
Simon Glassadecfef2016-01-21 19:43:30 -07001086 .get_enable = ldo_get_enable,
1087 .set_enable = ldo_set_enable,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +08001088 .set_suspend_enable = ldo_set_suspend_enable,
1089 .get_suspend_enable = ldo_get_suspend_enable,
Simon Glassadecfef2016-01-21 19:43:30 -07001090};
1091
Jacob Chen614704b2017-05-02 14:54:52 +08001092static const struct dm_regulator_ops rk8xx_switch_ops = {
Elaine Zhangfa9cccc2019-09-26 15:43:53 +08001093 .get_value = switch_get_value,
1094 .set_value = switch_set_value,
Simon Glassadecfef2016-01-21 19:43:30 -07001095 .get_enable = switch_get_enable,
1096 .set_enable = switch_set_enable,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +08001097 .set_suspend_enable = switch_set_suspend_enable,
1098 .get_suspend_enable = switch_get_suspend_enable,
1099 .set_suspend_value = switch_set_suspend_value,
1100 .get_suspend_value = switch_get_suspend_value,
Simon Glassadecfef2016-01-21 19:43:30 -07001101};
1102
Jacob Chen614704b2017-05-02 14:54:52 +08001103U_BOOT_DRIVER(rk8xx_buck) = {
1104 .name = "rk8xx_buck",
Simon Glassadecfef2016-01-21 19:43:30 -07001105 .id = UCLASS_REGULATOR,
Jacob Chen614704b2017-05-02 14:54:52 +08001106 .ops = &rk8xx_buck_ops,
1107 .probe = rk8xx_buck_probe,
Simon Glassadecfef2016-01-21 19:43:30 -07001108};
1109
Jacob Chen614704b2017-05-02 14:54:52 +08001110U_BOOT_DRIVER(rk8xx_ldo) = {
1111 .name = "rk8xx_ldo",
Simon Glassadecfef2016-01-21 19:43:30 -07001112 .id = UCLASS_REGULATOR,
Jacob Chen614704b2017-05-02 14:54:52 +08001113 .ops = &rk8xx_ldo_ops,
1114 .probe = rk8xx_ldo_probe,
Simon Glassadecfef2016-01-21 19:43:30 -07001115};
1116
Jacob Chen614704b2017-05-02 14:54:52 +08001117U_BOOT_DRIVER(rk8xx_switch) = {
1118 .name = "rk8xx_switch",
Simon Glassadecfef2016-01-21 19:43:30 -07001119 .id = UCLASS_REGULATOR,
Jacob Chen614704b2017-05-02 14:54:52 +08001120 .ops = &rk8xx_switch_ops,
1121 .probe = rk8xx_switch_probe,
Simon Glassadecfef2016-01-21 19:43:30 -07001122};
1123#endif
1124
Jacob Chen614704b2017-05-02 14:54:52 +08001125int rk8xx_spl_configure_buck(struct udevice *pmic, int buck, int uvolt)
Simon Glassadecfef2016-01-21 19:43:30 -07001126{
1127 int ret;
1128
1129 ret = _buck_set_value(pmic, buck, uvolt);
1130 if (ret)
1131 return ret;
1132
1133 return _buck_set_enable(pmic, buck, true);
1134}
Wadim Egorovc2581052017-06-19 12:36:39 +02001135
1136int rk818_spl_configure_usb_input_current(struct udevice *pmic, int current_ma)
1137{
1138 uint i;
1139
1140 for (i = 0; i < ARRAY_SIZE(rk818_chrg_cur_input_array); i++)
1141 if (current_ma <= rk818_chrg_cur_input_array[i])
1142 break;
1143
1144 return pmic_clrsetbits(pmic, REG_USB_CTRL, RK818_USB_ILIM_SEL_MASK, i);
1145}
1146
1147int rk818_spl_configure_usb_chrg_shutdown(struct udevice *pmic, int uvolt)
1148{
1149 uint i;
1150
1151 for (i = 0; i < ARRAY_SIZE(rk818_chrg_shutdown_vsel_array); i++)
1152 if (uvolt <= rk818_chrg_shutdown_vsel_array[i])
1153 break;
1154
1155 return pmic_clrsetbits(pmic, REG_USB_CTRL, RK818_USB_CHG_SD_VSEL_MASK,
1156 i);
1157}