]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
e1227764 SG |
2 | /* |
3 | * Copyright (C) 2015 Google, Inc | |
4 | * Written by Simon Glass <[email protected]> | |
5 | * | |
6 | * Based on Rockchip's drivers/power/pmic/pmic_rk808.c: | |
7 | * Copyright (C) 2012 rockchips | |
8 | * zyw <[email protected]> | |
e1227764 SG |
9 | */ |
10 | ||
11 | #include <common.h> | |
12 | #include <dm.h> | |
13 | #include <errno.h> | |
f7ae49fc | 14 | #include <log.h> |
453c5a92 | 15 | #include <power/rk8xx_pmic.h> |
e1227764 SG |
16 | #include <power/pmic.h> |
17 | #include <power/regulator.h> | |
18 | ||
19 | #ifndef CONFIG_SPL_BUILD | |
20 | #define ENABLE_DRIVER | |
21 | #endif | |
22 | ||
94afc1cb EZ |
23 | /* Not used or exisit register and configure */ |
24 | #define NA 0xff | |
25 | ||
b049acc9 JC |
26 | /* Field Definitions */ |
27 | #define RK808_BUCK_VSEL_MASK 0x3f | |
28 | #define RK808_BUCK4_VSEL_MASK 0xf | |
29 | #define RK808_LDO_VSEL_MASK 0x1f | |
30 | ||
ee30068f JC |
31 | /* RK809 BUCK5 */ |
32 | #define RK809_BUCK5_CONFIG(n) (0xde + (n) * 1) | |
33 | #define RK809_BUCK5_VSEL_MASK 0x07 | |
34 | ||
b4a35574 JC |
35 | /* RK817 BUCK */ |
36 | #define RK817_BUCK_ON_VSEL(n) (0xbb + 3 * ((n) - 1)) | |
37 | #define RK817_BUCK_SLP_VSEL(n) (0xbc + 3 * ((n) - 1)) | |
38 | #define RK817_BUCK_VSEL_MASK 0x7f | |
39 | #define RK817_BUCK_CONFIG(i) (0xba + (i) * 3) | |
40 | ||
41 | /* RK817 LDO */ | |
42 | #define RK817_LDO_ON_VSEL(n) (0xcc + 2 * ((n) - 1)) | |
43 | #define RK817_LDO_SLP_VSEL(n) (0xcd + 2 * ((n) - 1)) | |
44 | #define RK817_LDO_VSEL_MASK 0x7f | |
45 | ||
46 | /* RK817 ENABLE */ | |
47 | #define RK817_POWER_EN(n) (0xb1 + (n)) | |
48 | #define RK817_POWER_SLP_EN(n) (0xb5 + (n)) | |
49 | ||
eff4ca72 JC |
50 | #define RK818_BUCK_VSEL_MASK 0x3f |
51 | #define RK818_BUCK4_VSEL_MASK 0x1f | |
52 | #define RK818_LDO_VSEL_MASK 0x1f | |
53 | #define RK818_LDO3_ON_VSEL_MASK 0xf | |
54 | #define RK818_BOOST_ON_VSEL_MASK 0xe0 | |
ad98f882 WE |
55 | #define RK818_USB_ILIM_SEL_MASK 0x0f |
56 | #define RK818_USB_CHG_SD_VSEL_MASK 0x70 | |
57 | ||
94afc1cb EZ |
58 | /* |
59 | * Ramp delay | |
60 | */ | |
b6228074 EZ |
61 | #define RK805_RAMP_RATE_OFFSET 3 |
62 | #define RK805_RAMP_RATE_MASK (3 << RK805_RAMP_RATE_OFFSET) | |
63 | #define RK805_RAMP_RATE_3MV_PER_US (0 << RK805_RAMP_RATE_OFFSET) | |
64 | #define RK805_RAMP_RATE_6MV_PER_US (1 << RK805_RAMP_RATE_OFFSET) | |
65 | #define RK805_RAMP_RATE_12_5MV_PER_US (2 << RK805_RAMP_RATE_OFFSET) | |
66 | #define RK805_RAMP_RATE_25MV_PER_US (3 << RK805_RAMP_RATE_OFFSET) | |
ee30068f | 67 | |
94afc1cb EZ |
68 | #define RK808_RAMP_RATE_OFFSET 3 |
69 | #define RK808_RAMP_RATE_MASK (3 << RK808_RAMP_RATE_OFFSET) | |
70 | #define RK808_RAMP_RATE_2MV_PER_US (0 << RK808_RAMP_RATE_OFFSET) | |
71 | #define RK808_RAMP_RATE_4MV_PER_US (1 << RK808_RAMP_RATE_OFFSET) | |
72 | #define RK808_RAMP_RATE_6MV_PER_US (2 << RK808_RAMP_RATE_OFFSET) | |
73 | #define RK808_RAMP_RATE_10MV_PER_US (3 << RK808_RAMP_RATE_OFFSET) | |
eff4ca72 | 74 | |
b4a35574 JC |
75 | #define RK817_RAMP_RATE_OFFSET 6 |
76 | #define RK817_RAMP_RATE_MASK (0x3 << RK817_RAMP_RATE_OFFSET) | |
77 | #define RK817_RAMP_RATE_3MV_PER_US (0x0 << RK817_RAMP_RATE_OFFSET) | |
78 | #define RK817_RAMP_RATE_6_3MV_PER_US (0x1 << RK817_RAMP_RATE_OFFSET) | |
79 | #define RK817_RAMP_RATE_12_5MV_PER_US (0x2 << RK817_RAMP_RATE_OFFSET) | |
80 | #define RK817_RAMP_RATE_25MV_PER_US (0x3 << RK817_RAMP_RATE_OFFSET) | |
81 | ||
453c5a92 | 82 | struct rk8xx_reg_info { |
e1227764 SG |
83 | uint min_uv; |
84 | uint step_uv; | |
94afc1cb EZ |
85 | u8 vsel_reg; |
86 | u8 vsel_sleep_reg; | |
87 | u8 config_reg; | |
b049acc9 | 88 | u8 vsel_mask; |
94afc1cb | 89 | u8 min_sel; |
e1227764 SG |
90 | }; |
91 | ||
453c5a92 | 92 | static const struct rk8xx_reg_info rk808_buck[] = { |
94afc1cb EZ |
93 | { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK808_BUCK_VSEL_MASK, }, |
94 | { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK808_BUCK_VSEL_MASK, }, | |
95 | { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK808_BUCK_VSEL_MASK, }, | |
96 | { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK808_BUCK4_VSEL_MASK, }, | |
e1227764 SG |
97 | }; |
98 | ||
addd062b EZ |
99 | static const struct rk8xx_reg_info rk816_buck[] = { |
100 | /* buck 1 */ | |
101 | { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, }, | |
102 | { 1800000, 200000, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, }, | |
103 | { 2300000, 0, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, }, | |
104 | /* buck 2 */ | |
105 | { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, }, | |
106 | { 1800000, 200000, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, }, | |
107 | { 2300000, 0, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, }, | |
108 | /* buck 3 */ | |
109 | { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK818_BUCK_VSEL_MASK, }, | |
110 | /* buck 4 */ | |
111 | { 800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, }, | |
112 | }; | |
113 | ||
ee30068f JC |
114 | static const struct rk8xx_reg_info rk809_buck5[] = { |
115 | /* buck 5 */ | |
116 | { 1500000, 0, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x00, }, | |
117 | { 1800000, 200000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x01, }, | |
118 | { 2800000, 200000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x04, }, | |
119 | { 3300000, 300000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x06, }, | |
120 | }; | |
121 | ||
b4a35574 JC |
122 | static const struct rk8xx_reg_info rk817_buck[] = { |
123 | /* buck 1 */ | |
124 | { 500000, 12500, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x00, }, | |
125 | { 1500000, 100000, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x50, }, | |
126 | { 2400000, 0, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x59, }, | |
127 | /* buck 2 */ | |
128 | { 500000, 12500, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x00, }, | |
129 | { 1500000, 100000, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x50, }, | |
130 | { 2400000, 0, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x59, }, | |
131 | /* buck 3 */ | |
132 | { 500000, 12500, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x00, }, | |
133 | { 1500000, 100000, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x50, }, | |
134 | { 2400000, 0, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x59, }, | |
135 | /* buck 4 */ | |
136 | { 500000, 12500, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x00, }, | |
137 | { 1500000, 100000, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x50, }, | |
138 | { 3400000, 0, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x63, }, | |
139 | }; | |
140 | ||
8926c2f5 | 141 | static const struct rk8xx_reg_info rk818_buck[] = { |
94afc1cb EZ |
142 | { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, }, |
143 | { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, }, | |
144 | { 712500, 12500, NA, NA, REG_BUCK3_CONFIG, RK818_BUCK_VSEL_MASK, }, | |
145 | { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, }, | |
8926c2f5 WE |
146 | }; |
147 | ||
148 | #ifdef ENABLE_DRIVER | |
453c5a92 | 149 | static const struct rk8xx_reg_info rk808_ldo[] = { |
94afc1cb EZ |
150 | { 1800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, }, |
151 | { 1800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, }, | |
152 | { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK808_BUCK4_VSEL_MASK, }, | |
153 | { 1800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, }, | |
154 | { 1800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, }, | |
155 | { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, }, | |
156 | { 800000, 100000, REG_LDO7_ON_VSEL, REG_LDO7_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, }, | |
157 | { 1800000, 100000, REG_LDO8_ON_VSEL, REG_LDO8_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, }, | |
e1227764 SG |
158 | }; |
159 | ||
addd062b EZ |
160 | static const struct rk8xx_reg_info rk816_ldo[] = { |
161 | { 800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, | |
162 | { 800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, | |
163 | { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, | |
164 | { 800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, | |
165 | { 800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, | |
166 | { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, | |
167 | }; | |
168 | ||
b4a35574 JC |
169 | static const struct rk8xx_reg_info rk817_ldo[] = { |
170 | /* ldo1 */ | |
171 | { 600000, 25000, RK817_LDO_ON_VSEL(1), RK817_LDO_SLP_VSEL(1), NA, RK817_LDO_VSEL_MASK, 0x00, }, | |
172 | { 3400000, 0, RK817_LDO_ON_VSEL(1), RK817_LDO_SLP_VSEL(1), NA, RK817_LDO_VSEL_MASK, 0x70, }, | |
173 | /* ldo2 */ | |
174 | { 600000, 25000, RK817_LDO_ON_VSEL(2), RK817_LDO_SLP_VSEL(2), NA, RK817_LDO_VSEL_MASK, 0x00, }, | |
175 | { 3400000, 0, RK817_LDO_ON_VSEL(2), RK817_LDO_SLP_VSEL(2), NA, RK817_LDO_VSEL_MASK, 0x70, }, | |
176 | /* ldo3 */ | |
177 | { 600000, 25000, RK817_LDO_ON_VSEL(3), RK817_LDO_SLP_VSEL(3), NA, RK817_LDO_VSEL_MASK, 0x00, }, | |
178 | { 3400000, 0, RK817_LDO_ON_VSEL(3), RK817_LDO_SLP_VSEL(3), NA, RK817_LDO_VSEL_MASK, 0x70, }, | |
179 | /* ldo4 */ | |
180 | { 600000, 25000, RK817_LDO_ON_VSEL(4), RK817_LDO_SLP_VSEL(4), NA, RK817_LDO_VSEL_MASK, 0x00, }, | |
181 | { 3400000, 0, RK817_LDO_ON_VSEL(4), RK817_LDO_SLP_VSEL(4), NA, RK817_LDO_VSEL_MASK, 0x70, }, | |
182 | /* ldo5 */ | |
183 | { 600000, 25000, RK817_LDO_ON_VSEL(5), RK817_LDO_SLP_VSEL(5), NA, RK817_LDO_VSEL_MASK, 0x00, }, | |
184 | { 3400000, 0, RK817_LDO_ON_VSEL(5), RK817_LDO_SLP_VSEL(5), NA, RK817_LDO_VSEL_MASK, 0x70, }, | |
185 | /* ldo6 */ | |
186 | { 600000, 25000, RK817_LDO_ON_VSEL(6), RK817_LDO_SLP_VSEL(6), NA, RK817_LDO_VSEL_MASK, 0x00, }, | |
187 | { 3400000, 0, RK817_LDO_ON_VSEL(6), RK817_LDO_SLP_VSEL(6), NA, RK817_LDO_VSEL_MASK, 0x70, }, | |
188 | /* ldo7 */ | |
189 | { 600000, 25000, RK817_LDO_ON_VSEL(7), RK817_LDO_SLP_VSEL(7), NA, RK817_LDO_VSEL_MASK, 0x00, }, | |
190 | { 3400000, 0, RK817_LDO_ON_VSEL(7), RK817_LDO_SLP_VSEL(7), NA, RK817_LDO_VSEL_MASK, 0x70, }, | |
191 | /* ldo8 */ | |
192 | { 600000, 25000, RK817_LDO_ON_VSEL(8), RK817_LDO_SLP_VSEL(8), NA, RK817_LDO_VSEL_MASK, 0x00, }, | |
193 | { 3400000, 0, RK817_LDO_ON_VSEL(8), RK817_LDO_SLP_VSEL(8), NA, RK817_LDO_VSEL_MASK, 0x70, }, | |
194 | /* ldo9 */ | |
195 | { 600000, 25000, RK817_LDO_ON_VSEL(9), RK817_LDO_SLP_VSEL(9), NA, RK817_LDO_VSEL_MASK, 0x00, }, | |
196 | { 3400000, 0, RK817_LDO_ON_VSEL(9), RK817_LDO_SLP_VSEL(9), NA, RK817_LDO_VSEL_MASK, 0x70, }, | |
197 | }; | |
198 | ||
453c5a92 | 199 | static const struct rk8xx_reg_info rk818_ldo[] = { |
94afc1cb EZ |
200 | { 1800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, |
201 | { 1800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, | |
202 | { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK818_LDO3_ON_VSEL_MASK, }, | |
203 | { 1800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, | |
204 | { 1800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, | |
205 | { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, | |
206 | { 800000, 100000, REG_LDO7_ON_VSEL, REG_LDO7_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, | |
207 | { 1800000, 100000, REG_LDO8_ON_VSEL, REG_LDO8_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, }, | |
eff4ca72 | 208 | }; |
8926c2f5 | 209 | #endif |
eff4ca72 | 210 | |
ad98f882 WE |
211 | static const u16 rk818_chrg_cur_input_array[] = { |
212 | 450, 800, 850, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000 | |
213 | }; | |
214 | ||
215 | static const uint rk818_chrg_shutdown_vsel_array[] = { | |
216 | 2780000, 2850000, 2920000, 2990000, 3060000, 3130000, 3190000, 3260000 | |
217 | }; | |
218 | ||
453c5a92 | 219 | static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic, |
94afc1cb | 220 | int num, int uvolt) |
eff4ca72 | 221 | { |
453c5a92 | 222 | struct rk8xx_priv *priv = dev_get_priv(pmic); |
addd062b | 223 | |
453c5a92 | 224 | switch (priv->variant) { |
b6228074 | 225 | case RK805_ID: |
addd062b EZ |
226 | case RK816_ID: |
227 | switch (num) { | |
228 | case 0: | |
229 | case 1: | |
230 | if (uvolt <= 1450000) | |
231 | return &rk816_buck[num * 3 + 0]; | |
232 | else if (uvolt <= 2200000) | |
233 | return &rk816_buck[num * 3 + 1]; | |
234 | else | |
235 | return &rk816_buck[num * 3 + 2]; | |
236 | default: | |
237 | return &rk816_buck[num + 4]; | |
238 | } | |
b4a35574 | 239 | |
ee30068f | 240 | case RK809_ID: |
b4a35574 JC |
241 | case RK817_ID: |
242 | switch (num) { | |
243 | case 0 ... 2: | |
244 | if (uvolt < 1500000) | |
245 | return &rk817_buck[num * 3 + 0]; | |
246 | else if (uvolt < 2400000) | |
247 | return &rk817_buck[num * 3 + 1]; | |
248 | else | |
249 | return &rk817_buck[num * 3 + 2]; | |
250 | case 3: | |
251 | if (uvolt < 1500000) | |
252 | return &rk817_buck[num * 3 + 0]; | |
253 | else if (uvolt < 3400000) | |
254 | return &rk817_buck[num * 3 + 1]; | |
255 | else | |
256 | return &rk817_buck[num * 3 + 2]; | |
ee30068f JC |
257 | /* BUCK5 for RK809 */ |
258 | default: | |
259 | if (uvolt < 1800000) | |
260 | return &rk809_buck5[0]; | |
261 | else if (uvolt < 2800000) | |
262 | return &rk809_buck5[1]; | |
263 | else if (uvolt < 3300000) | |
264 | return &rk809_buck5[2]; | |
265 | else | |
266 | return &rk809_buck5[3]; | |
b4a35574 | 267 | } |
eff4ca72 JC |
268 | case RK818_ID: |
269 | return &rk818_buck[num]; | |
270 | default: | |
271 | return &rk808_buck[num]; | |
272 | } | |
273 | } | |
274 | ||
e1227764 SG |
275 | static int _buck_set_value(struct udevice *pmic, int buck, int uvolt) |
276 | { | |
94afc1cb | 277 | const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt); |
addd062b | 278 | struct rk8xx_priv *priv = dev_get_priv(pmic); |
b049acc9 | 279 | int mask = info->vsel_mask; |
e1227764 SG |
280 | int val; |
281 | ||
94afc1cb | 282 | if (info->vsel_reg == NA) |
e1227764 | 283 | return -ENOSYS; |
addd062b | 284 | |
94afc1cb EZ |
285 | if (info->step_uv == 0) /* Fixed voltage */ |
286 | val = info->min_sel; | |
287 | else | |
288 | val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel; | |
289 | ||
290 | debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n", | |
291 | __func__, uvolt, buck + 1, info->vsel_reg, mask, val); | |
292 | ||
addd062b EZ |
293 | if (priv->variant == RK816_ID) { |
294 | pmic_clrsetbits(pmic, info->vsel_reg, mask, val); | |
295 | return pmic_clrsetbits(pmic, RK816_REG_DCDC_EN2, | |
296 | 1 << 7, 1 << 7); | |
297 | } else { | |
298 | return pmic_clrsetbits(pmic, info->vsel_reg, mask, val); | |
299 | } | |
e1227764 SG |
300 | } |
301 | ||
302 | static int _buck_set_enable(struct udevice *pmic, int buck, bool enable) | |
303 | { | |
addd062b | 304 | uint mask, value, en_reg; |
b4a35574 | 305 | int ret = 0; |
94afc1cb | 306 | struct rk8xx_priv *priv = dev_get_priv(pmic); |
e1227764 | 307 | |
94afc1cb | 308 | switch (priv->variant) { |
b6228074 | 309 | case RK805_ID: |
addd062b EZ |
310 | case RK816_ID: |
311 | if (buck >= 4) { | |
312 | buck -= 4; | |
313 | en_reg = RK816_REG_DCDC_EN2; | |
314 | } else { | |
315 | en_reg = RK816_REG_DCDC_EN1; | |
316 | } | |
317 | if (enable) | |
318 | value = ((1 << buck) | (1 << (buck + 4))); | |
319 | else | |
320 | value = ((0 << buck) | (1 << (buck + 4))); | |
321 | ret = pmic_reg_write(pmic, en_reg, value); | |
322 | break; | |
323 | ||
94afc1cb EZ |
324 | case RK808_ID: |
325 | case RK818_ID: | |
326 | mask = 1 << buck; | |
327 | if (enable) { | |
328 | ret = pmic_clrsetbits(pmic, REG_DCDC_ILMAX, | |
329 | 0, 3 << (buck * 2)); | |
330 | if (ret) | |
331 | return ret; | |
332 | } | |
333 | ret = pmic_clrsetbits(pmic, REG_DCDC_EN, mask, | |
334 | enable ? mask : 0); | |
335 | break; | |
ee30068f | 336 | case RK809_ID: |
b4a35574 JC |
337 | case RK817_ID: |
338 | if (buck < 4) { | |
339 | if (enable) | |
340 | value = ((1 << buck) | (1 << (buck + 4))); | |
341 | else | |
342 | value = ((0 << buck) | (1 << (buck + 4))); | |
343 | ret = pmic_reg_write(pmic, RK817_POWER_EN(0), value); | |
ee30068f JC |
344 | /* BUCK5 for RK809 */ |
345 | } else { | |
346 | if (enable) | |
347 | value = ((1 << 1) | (1 << 5)); | |
348 | else | |
349 | value = ((0 << 1) | (1 << 5)); | |
350 | ret = pmic_reg_write(pmic, RK817_POWER_EN(3), value); | |
b4a35574 JC |
351 | } |
352 | break; | |
94afc1cb EZ |
353 | default: |
354 | ret = -EINVAL; | |
e1227764 SG |
355 | } |
356 | ||
94afc1cb | 357 | return ret; |
e1227764 SG |
358 | } |
359 | ||
360 | #ifdef ENABLE_DRIVER | |
94afc1cb EZ |
361 | static int _buck_set_suspend_value(struct udevice *pmic, int buck, int uvolt) |
362 | { | |
363 | const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt); | |
364 | int mask = info->vsel_mask; | |
365 | int val; | |
366 | ||
367 | if (info->vsel_sleep_reg == NA) | |
368 | return -ENOSYS; | |
369 | ||
370 | if (info->step_uv == 0) | |
371 | val = info->min_sel; | |
372 | else | |
373 | val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel; | |
374 | ||
375 | debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n", | |
376 | __func__, uvolt, buck + 1, info->vsel_sleep_reg, mask, val); | |
377 | ||
378 | return pmic_clrsetbits(pmic, info->vsel_sleep_reg, mask, val); | |
379 | } | |
380 | ||
381 | static int _buck_get_enable(struct udevice *pmic, int buck) | |
382 | { | |
383 | struct rk8xx_priv *priv = dev_get_priv(pmic); | |
384 | uint mask = 0; | |
385 | int ret = 0; | |
386 | ||
387 | switch (priv->variant) { | |
b6228074 | 388 | case RK805_ID: |
addd062b EZ |
389 | case RK816_ID: |
390 | if (buck >= 4) { | |
391 | mask = 1 << (buck - 4); | |
392 | ret = pmic_reg_read(pmic, RK816_REG_DCDC_EN2); | |
393 | } else { | |
394 | mask = 1 << buck; | |
395 | ret = pmic_reg_read(pmic, RK816_REG_DCDC_EN1); | |
396 | } | |
397 | break; | |
94afc1cb EZ |
398 | case RK808_ID: |
399 | case RK818_ID: | |
400 | mask = 1 << buck; | |
401 | ret = pmic_reg_read(pmic, REG_DCDC_EN); | |
402 | if (ret < 0) | |
403 | return ret; | |
404 | break; | |
ee30068f | 405 | case RK809_ID: |
b4a35574 JC |
406 | case RK817_ID: |
407 | if (buck < 4) { | |
408 | mask = 1 << buck; | |
409 | ret = pmic_reg_read(pmic, RK817_POWER_EN(0)); | |
ee30068f JC |
410 | /* BUCK5 for RK809 */ |
411 | } else { | |
412 | mask = 1 << 1; | |
413 | ret = pmic_reg_read(pmic, RK817_POWER_EN(3)); | |
b4a35574 JC |
414 | } |
415 | break; | |
94afc1cb EZ |
416 | } |
417 | ||
418 | if (ret < 0) | |
419 | return ret; | |
420 | ||
421 | return ret & mask ? true : false; | |
422 | } | |
423 | ||
424 | static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable) | |
425 | { | |
b4a35574 | 426 | uint mask = 0; |
94afc1cb EZ |
427 | int ret; |
428 | struct rk8xx_priv *priv = dev_get_priv(pmic); | |
429 | ||
430 | switch (priv->variant) { | |
b6228074 | 431 | case RK805_ID: |
addd062b EZ |
432 | case RK816_ID: |
433 | mask = 1 << buck; | |
434 | ret = pmic_clrsetbits(pmic, RK816_REG_DCDC_SLP_EN, mask, | |
435 | enable ? mask : 0); | |
436 | break; | |
94afc1cb EZ |
437 | case RK808_ID: |
438 | case RK818_ID: | |
439 | mask = 1 << buck; | |
440 | ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF1, mask, | |
441 | enable ? 0 : mask); | |
442 | break; | |
ee30068f | 443 | case RK809_ID: |
b4a35574 JC |
444 | case RK817_ID: |
445 | if (buck < 4) | |
446 | mask = 1 << buck; | |
ee30068f JC |
447 | else |
448 | mask = 1 << 5; /* BUCK5 for RK809 */ | |
b4a35574 JC |
449 | ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(0), mask, |
450 | enable ? mask : 0); | |
451 | break; | |
94afc1cb EZ |
452 | default: |
453 | ret = -EINVAL; | |
454 | } | |
455 | ||
456 | return ret; | |
457 | } | |
458 | ||
459 | static int _buck_get_suspend_enable(struct udevice *pmic, int buck) | |
460 | { | |
461 | struct rk8xx_priv *priv = dev_get_priv(pmic); | |
462 | int ret, val; | |
b4a35574 | 463 | uint mask = 0; |
94afc1cb EZ |
464 | |
465 | switch (priv->variant) { | |
b6228074 | 466 | case RK805_ID: |
addd062b EZ |
467 | case RK816_ID: |
468 | mask = 1 << buck; | |
469 | val = pmic_reg_read(pmic, RK816_REG_DCDC_SLP_EN); | |
470 | if (val < 0) | |
471 | return val; | |
472 | ret = val & mask ? 1 : 0; | |
473 | break; | |
94afc1cb EZ |
474 | case RK808_ID: |
475 | case RK818_ID: | |
476 | mask = 1 << buck; | |
477 | val = pmic_reg_read(pmic, REG_SLEEP_SET_OFF1); | |
478 | if (val < 0) | |
479 | return val; | |
480 | ret = val & mask ? 0 : 1; | |
481 | break; | |
ee30068f | 482 | case RK809_ID: |
b4a35574 JC |
483 | case RK817_ID: |
484 | if (buck < 4) | |
485 | mask = 1 << buck; | |
ee30068f JC |
486 | else |
487 | mask = 1 << 5; /* BUCK5 for RK809 */ | |
b4a35574 JC |
488 | |
489 | val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(0)); | |
490 | if (val < 0) | |
491 | return val; | |
492 | ret = val & mask ? 1 : 0; | |
493 | break; | |
94afc1cb EZ |
494 | default: |
495 | ret = -EINVAL; | |
496 | } | |
497 | ||
498 | return ret; | |
499 | } | |
500 | ||
8926c2f5 | 501 | static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic, |
94afc1cb | 502 | int num, int uvolt) |
8926c2f5 WE |
503 | { |
504 | struct rk8xx_priv *priv = dev_get_priv(pmic); | |
addd062b | 505 | |
8926c2f5 | 506 | switch (priv->variant) { |
b6228074 | 507 | case RK805_ID: |
addd062b EZ |
508 | case RK816_ID: |
509 | return &rk816_ldo[num]; | |
ee30068f | 510 | case RK809_ID: |
b4a35574 JC |
511 | case RK817_ID: |
512 | if (uvolt < 3400000) | |
513 | return &rk817_ldo[num * 2 + 0]; | |
514 | else | |
515 | return &rk817_ldo[num * 2 + 1]; | |
8926c2f5 WE |
516 | case RK818_ID: |
517 | return &rk818_ldo[num]; | |
518 | default: | |
519 | return &rk808_ldo[num]; | |
520 | } | |
521 | } | |
522 | ||
94afc1cb EZ |
523 | static int _ldo_get_enable(struct udevice *pmic, int ldo) |
524 | { | |
525 | struct rk8xx_priv *priv = dev_get_priv(pmic); | |
526 | uint mask = 0; | |
527 | int ret = 0; | |
528 | ||
529 | switch (priv->variant) { | |
b6228074 | 530 | case RK805_ID: |
addd062b EZ |
531 | case RK816_ID: |
532 | if (ldo >= 4) { | |
533 | mask = 1 << (ldo - 4); | |
534 | ret = pmic_reg_read(pmic, RK816_REG_LDO_EN2); | |
535 | } else { | |
536 | mask = 1 << ldo; | |
537 | ret = pmic_reg_read(pmic, RK816_REG_LDO_EN1); | |
538 | } | |
539 | break; | |
94afc1cb EZ |
540 | case RK808_ID: |
541 | case RK818_ID: | |
542 | mask = 1 << ldo; | |
543 | ret = pmic_reg_read(pmic, REG_LDO_EN); | |
544 | if (ret < 0) | |
545 | return ret; | |
546 | break; | |
ee30068f | 547 | case RK809_ID: |
b4a35574 JC |
548 | case RK817_ID: |
549 | if (ldo < 4) { | |
550 | mask = 1 << ldo; | |
551 | ret = pmic_reg_read(pmic, RK817_POWER_EN(1)); | |
552 | } else if (ldo < 8) { | |
553 | mask = 1 << (ldo - 4); | |
554 | ret = pmic_reg_read(pmic, RK817_POWER_EN(2)); | |
555 | } else if (ldo == 8) { | |
556 | mask = 1 << 0; | |
557 | ret = pmic_reg_read(pmic, RK817_POWER_EN(3)); | |
558 | } else { | |
559 | return false; | |
560 | } | |
561 | break; | |
94afc1cb EZ |
562 | } |
563 | ||
564 | if (ret < 0) | |
565 | return ret; | |
566 | ||
567 | return ret & mask ? true : false; | |
568 | } | |
569 | ||
570 | static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable) | |
571 | { | |
572 | struct rk8xx_priv *priv = dev_get_priv(pmic); | |
addd062b | 573 | uint mask, value, en_reg; |
94afc1cb EZ |
574 | int ret = 0; |
575 | ||
576 | switch (priv->variant) { | |
b6228074 | 577 | case RK805_ID: |
addd062b EZ |
578 | case RK816_ID: |
579 | if (ldo >= 4) { | |
580 | ldo -= 4; | |
581 | en_reg = RK816_REG_LDO_EN2; | |
582 | } else { | |
583 | en_reg = RK816_REG_LDO_EN1; | |
584 | } | |
585 | if (enable) | |
586 | value = ((1 << ldo) | (1 << (ldo + 4))); | |
587 | else | |
588 | value = ((0 << ldo) | (1 << (ldo + 4))); | |
589 | ||
590 | ret = pmic_reg_write(pmic, en_reg, value); | |
591 | break; | |
94afc1cb EZ |
592 | case RK808_ID: |
593 | case RK818_ID: | |
594 | mask = 1 << ldo; | |
595 | ret = pmic_clrsetbits(pmic, REG_LDO_EN, mask, | |
addd062b | 596 | enable ? mask : 0); |
94afc1cb | 597 | break; |
ee30068f | 598 | case RK809_ID: |
b4a35574 JC |
599 | case RK817_ID: |
600 | if (ldo < 4) { | |
601 | en_reg = RK817_POWER_EN(1); | |
602 | } else if (ldo < 8) { | |
603 | ldo -= 4; | |
604 | en_reg = RK817_POWER_EN(2); | |
605 | } else if (ldo == 8) { | |
606 | ldo = 0; /* BIT 0 */ | |
607 | en_reg = RK817_POWER_EN(3); | |
608 | } else { | |
609 | return -EINVAL; | |
610 | } | |
611 | if (enable) | |
612 | value = ((1 << ldo) | (1 << (ldo + 4))); | |
613 | else | |
614 | value = ((0 << ldo) | (1 << (ldo + 4))); | |
615 | ret = pmic_reg_write(pmic, en_reg, value); | |
616 | break; | |
94afc1cb EZ |
617 | } |
618 | ||
619 | return ret; | |
620 | } | |
621 | ||
622 | static int _ldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable) | |
623 | { | |
624 | struct rk8xx_priv *priv = dev_get_priv(pmic); | |
625 | uint mask; | |
626 | int ret = 0; | |
627 | ||
628 | switch (priv->variant) { | |
b6228074 | 629 | case RK805_ID: |
addd062b EZ |
630 | case RK816_ID: |
631 | mask = 1 << ldo; | |
632 | ret = pmic_clrsetbits(pmic, RK816_REG_LDO_SLP_EN, mask, | |
633 | enable ? mask : 0); | |
634 | break; | |
94afc1cb EZ |
635 | case RK808_ID: |
636 | case RK818_ID: | |
637 | mask = 1 << ldo; | |
638 | ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF2, mask, | |
639 | enable ? 0 : mask); | |
640 | break; | |
ee30068f | 641 | case RK809_ID: |
b4a35574 JC |
642 | case RK817_ID: |
643 | if (ldo == 8) { | |
644 | mask = 1 << 4; /* LDO9 */ | |
645 | ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(0), mask, | |
646 | enable ? mask : 0); | |
647 | } else { | |
648 | mask = 1 << ldo; | |
649 | ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(1), mask, | |
650 | enable ? mask : 0); | |
651 | } | |
652 | break; | |
94afc1cb EZ |
653 | } |
654 | ||
655 | return ret; | |
656 | } | |
657 | ||
658 | static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo) | |
659 | { | |
660 | struct rk8xx_priv *priv = dev_get_priv(pmic); | |
661 | int val, ret = 0; | |
662 | uint mask; | |
663 | ||
664 | switch (priv->variant) { | |
b6228074 | 665 | case RK805_ID: |
addd062b EZ |
666 | case RK816_ID: |
667 | mask = 1 << ldo; | |
668 | val = pmic_reg_read(pmic, RK816_REG_LDO_SLP_EN); | |
669 | if (val < 0) | |
670 | return val; | |
671 | ret = val & mask ? 1 : 0; | |
672 | break; | |
94afc1cb EZ |
673 | case RK808_ID: |
674 | case RK818_ID: | |
675 | mask = 1 << ldo; | |
676 | val = pmic_reg_read(pmic, REG_SLEEP_SET_OFF2); | |
677 | if (val < 0) | |
678 | return val; | |
679 | ret = val & mask ? 0 : 1; | |
680 | break; | |
ee30068f | 681 | case RK809_ID: |
b4a35574 JC |
682 | case RK817_ID: |
683 | if (ldo == 8) { | |
684 | mask = 1 << 4; /* LDO9 */ | |
685 | val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(0)); | |
686 | if (val < 0) | |
687 | return val; | |
688 | ret = val & mask ? 1 : 0; | |
689 | } else { | |
690 | mask = 1 << ldo; | |
691 | val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(1)); | |
692 | if (val < 0) | |
693 | return val; | |
694 | ret = val & mask ? 1 : 0; | |
695 | } | |
696 | break; | |
94afc1cb EZ |
697 | } |
698 | ||
699 | return ret; | |
700 | } | |
701 | ||
e1227764 SG |
702 | static int buck_get_value(struct udevice *dev) |
703 | { | |
704 | int buck = dev->driver_data - 1; | |
94afc1cb EZ |
705 | /* We assume level-1 voltage is enough for usage in U-Boot */ |
706 | const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0); | |
b049acc9 | 707 | int mask = info->vsel_mask; |
e1227764 SG |
708 | int ret, val; |
709 | ||
94afc1cb | 710 | if (info->vsel_reg == NA) |
e1227764 | 711 | return -ENOSYS; |
addd062b | 712 | |
e1227764 SG |
713 | ret = pmic_reg_read(dev->parent, info->vsel_reg); |
714 | if (ret < 0) | |
715 | return ret; | |
716 | val = ret & mask; | |
717 | ||
718 | return info->min_uv + val * info->step_uv; | |
719 | } | |
720 | ||
721 | static int buck_set_value(struct udevice *dev, int uvolt) | |
722 | { | |
94afc1cb | 723 | int buck = dev->driver_data - 1; |
e1227764 SG |
724 | |
725 | return _buck_set_value(dev->parent, buck, uvolt); | |
726 | } | |
727 | ||
94afc1cb EZ |
728 | static int buck_get_suspend_value(struct udevice *dev) |
729 | { | |
730 | int buck = dev->driver_data - 1; | |
731 | /* We assume level-1 voltage is enough for usage in U-Boot */ | |
732 | const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0); | |
733 | int mask = info->vsel_mask; | |
734 | int ret, val; | |
735 | ||
736 | if (info->vsel_sleep_reg == NA) | |
737 | return -ENOSYS; | |
738 | ||
739 | ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg); | |
740 | if (ret < 0) | |
741 | return ret; | |
742 | ||
743 | val = ret & mask; | |
744 | ||
745 | return info->min_uv + val * info->step_uv; | |
746 | } | |
747 | ||
748 | static int buck_set_suspend_value(struct udevice *dev, int uvolt) | |
749 | { | |
750 | int buck = dev->driver_data - 1; | |
751 | ||
752 | return _buck_set_suspend_value(dev->parent, buck, uvolt); | |
753 | } | |
754 | ||
e1227764 SG |
755 | static int buck_set_enable(struct udevice *dev, bool enable) |
756 | { | |
94afc1cb | 757 | int buck = dev->driver_data - 1; |
e1227764 SG |
758 | |
759 | return _buck_set_enable(dev->parent, buck, enable); | |
760 | } | |
761 | ||
94afc1cb | 762 | static int buck_set_suspend_enable(struct udevice *dev, bool enable) |
e1227764 SG |
763 | { |
764 | int buck = dev->driver_data - 1; | |
e1227764 | 765 | |
94afc1cb EZ |
766 | return _buck_set_suspend_enable(dev->parent, buck, enable); |
767 | } | |
e1227764 | 768 | |
94afc1cb EZ |
769 | static int buck_get_suspend_enable(struct udevice *dev) |
770 | { | |
771 | int buck = dev->driver_data - 1; | |
e1227764 | 772 | |
94afc1cb EZ |
773 | return _buck_get_suspend_enable(dev->parent, buck); |
774 | } | |
775 | ||
776 | static int buck_get_enable(struct udevice *dev) | |
777 | { | |
778 | int buck = dev->driver_data - 1; | |
779 | ||
780 | return _buck_get_enable(dev->parent, buck); | |
e1227764 SG |
781 | } |
782 | ||
783 | static int ldo_get_value(struct udevice *dev) | |
784 | { | |
785 | int ldo = dev->driver_data - 1; | |
94afc1cb | 786 | const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0); |
b049acc9 | 787 | int mask = info->vsel_mask; |
e1227764 SG |
788 | int ret, val; |
789 | ||
94afc1cb | 790 | if (info->vsel_reg == NA) |
e1227764 SG |
791 | return -ENOSYS; |
792 | ret = pmic_reg_read(dev->parent, info->vsel_reg); | |
793 | if (ret < 0) | |
794 | return ret; | |
795 | val = ret & mask; | |
796 | ||
797 | return info->min_uv + val * info->step_uv; | |
798 | } | |
799 | ||
800 | static int ldo_set_value(struct udevice *dev, int uvolt) | |
801 | { | |
802 | int ldo = dev->driver_data - 1; | |
94afc1cb | 803 | const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, uvolt); |
b049acc9 | 804 | int mask = info->vsel_mask; |
e1227764 SG |
805 | int val; |
806 | ||
94afc1cb | 807 | if (info->vsel_reg == NA) |
e1227764 | 808 | return -ENOSYS; |
94afc1cb EZ |
809 | |
810 | if (info->step_uv == 0) | |
811 | val = info->min_sel; | |
812 | else | |
813 | val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel; | |
814 | ||
815 | debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n", | |
816 | __func__, uvolt, ldo + 1, info->vsel_reg, mask, val); | |
e1227764 SG |
817 | |
818 | return pmic_clrsetbits(dev->parent, info->vsel_reg, mask, val); | |
819 | } | |
820 | ||
94afc1cb | 821 | static int ldo_set_suspend_value(struct udevice *dev, int uvolt) |
e1227764 SG |
822 | { |
823 | int ldo = dev->driver_data - 1; | |
94afc1cb EZ |
824 | const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, uvolt); |
825 | int mask = info->vsel_mask; | |
826 | int val; | |
827 | ||
828 | if (info->vsel_sleep_reg == NA) | |
829 | return -ENOSYS; | |
e1227764 | 830 | |
94afc1cb EZ |
831 | if (info->step_uv == 0) |
832 | val = info->min_sel; | |
833 | else | |
834 | val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel; | |
e1227764 | 835 | |
94afc1cb EZ |
836 | debug("%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n", |
837 | __func__, uvolt, ldo + 1, info->vsel_sleep_reg, mask, val); | |
838 | ||
839 | return pmic_clrsetbits(dev->parent, info->vsel_sleep_reg, mask, val); | |
e1227764 SG |
840 | } |
841 | ||
94afc1cb | 842 | static int ldo_get_suspend_value(struct udevice *dev) |
e1227764 SG |
843 | { |
844 | int ldo = dev->driver_data - 1; | |
94afc1cb EZ |
845 | const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0); |
846 | int mask = info->vsel_mask; | |
847 | int val, ret; | |
e1227764 | 848 | |
94afc1cb EZ |
849 | if (info->vsel_sleep_reg == NA) |
850 | return -ENOSYS; | |
e1227764 | 851 | |
94afc1cb | 852 | ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg); |
e1227764 SG |
853 | if (ret < 0) |
854 | return ret; | |
855 | ||
94afc1cb EZ |
856 | val = ret & mask; |
857 | ||
858 | return info->min_uv + val * info->step_uv; | |
859 | } | |
860 | ||
861 | static int ldo_set_enable(struct udevice *dev, bool enable) | |
862 | { | |
863 | int ldo = dev->driver_data - 1; | |
864 | ||
865 | return _ldo_set_enable(dev->parent, ldo, enable); | |
866 | } | |
867 | ||
868 | static int ldo_set_suspend_enable(struct udevice *dev, bool enable) | |
869 | { | |
870 | int ldo = dev->driver_data - 1; | |
871 | ||
872 | return _ldo_set_suspend_enable(dev->parent, ldo, enable); | |
873 | } | |
874 | ||
875 | static int ldo_get_suspend_enable(struct udevice *dev) | |
876 | { | |
877 | int ldo = dev->driver_data - 1; | |
878 | ||
879 | return _ldo_get_suspend_enable(dev->parent, ldo); | |
880 | } | |
881 | ||
882 | static int ldo_get_enable(struct udevice *dev) | |
883 | { | |
884 | int ldo = dev->driver_data - 1; | |
885 | ||
886 | return _ldo_get_enable(dev->parent, ldo); | |
e1227764 SG |
887 | } |
888 | ||
889 | static int switch_set_enable(struct udevice *dev, bool enable) | |
890 | { | |
94afc1cb EZ |
891 | struct rk8xx_priv *priv = dev_get_priv(dev->parent); |
892 | int ret = 0, sw = dev->driver_data - 1; | |
893 | uint mask = 0; | |
894 | ||
895 | switch (priv->variant) { | |
896 | case RK808_ID: | |
897 | mask = 1 << (sw + 5); | |
898 | ret = pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask, | |
899 | enable ? mask : 0); | |
900 | break; | |
ee30068f JC |
901 | case RK809_ID: |
902 | mask = (1 << (sw + 2)) | (1 << (sw + 6)); | |
903 | ret = pmic_clrsetbits(dev->parent, RK817_POWER_EN(3), mask, | |
904 | enable ? mask : 0); | |
905 | break; | |
94afc1cb EZ |
906 | case RK818_ID: |
907 | mask = 1 << 6; | |
908 | ret = pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask, | |
909 | enable ? mask : 0); | |
910 | break; | |
911 | } | |
e1227764 | 912 | |
94afc1cb EZ |
913 | debug("%s: switch%d, enable=%d, mask=0x%x\n", |
914 | __func__, sw + 1, enable, mask); | |
e1227764 | 915 | |
94afc1cb | 916 | return ret; |
e1227764 SG |
917 | } |
918 | ||
585c7032 | 919 | static int switch_get_enable(struct udevice *dev) |
e1227764 | 920 | { |
94afc1cb EZ |
921 | struct rk8xx_priv *priv = dev_get_priv(dev->parent); |
922 | int ret = 0, sw = dev->driver_data - 1; | |
923 | uint mask = 0; | |
e1227764 | 924 | |
94afc1cb EZ |
925 | switch (priv->variant) { |
926 | case RK808_ID: | |
927 | mask = 1 << (sw + 5); | |
928 | ret = pmic_reg_read(dev->parent, REG_DCDC_EN); | |
929 | break; | |
ee30068f JC |
930 | case RK809_ID: |
931 | mask = 1 << (sw + 2); | |
932 | ret = pmic_reg_read(dev->parent, RK817_POWER_EN(3)); | |
933 | break; | |
94afc1cb EZ |
934 | case RK818_ID: |
935 | mask = 1 << 6; | |
936 | ret = pmic_reg_read(dev->parent, REG_DCDC_EN); | |
937 | break; | |
938 | } | |
e1227764 | 939 | |
e1227764 SG |
940 | if (ret < 0) |
941 | return ret; | |
942 | ||
943 | return ret & mask ? true : false; | |
944 | } | |
945 | ||
94afc1cb EZ |
946 | static int switch_set_suspend_value(struct udevice *dev, int uvolt) |
947 | { | |
948 | return 0; | |
949 | } | |
950 | ||
951 | static int switch_get_suspend_value(struct udevice *dev) | |
952 | { | |
953 | return 0; | |
954 | } | |
955 | ||
956 | static int switch_set_suspend_enable(struct udevice *dev, bool enable) | |
957 | { | |
958 | struct rk8xx_priv *priv = dev_get_priv(dev->parent); | |
959 | int ret = 0, sw = dev->driver_data - 1; | |
960 | uint mask = 0; | |
961 | ||
962 | switch (priv->variant) { | |
963 | case RK808_ID: | |
964 | mask = 1 << (sw + 5); | |
965 | ret = pmic_clrsetbits(dev->parent, REG_SLEEP_SET_OFF1, mask, | |
966 | enable ? 0 : mask); | |
967 | break; | |
ee30068f JC |
968 | case RK809_ID: |
969 | mask = 1 << (sw + 6); | |
970 | ret = pmic_clrsetbits(dev->parent, RK817_POWER_SLP_EN(0), mask, | |
971 | enable ? mask : 0); | |
972 | break; | |
94afc1cb EZ |
973 | case RK818_ID: |
974 | mask = 1 << 6; | |
975 | ret = pmic_clrsetbits(dev->parent, REG_SLEEP_SET_OFF1, mask, | |
976 | enable ? 0 : mask); | |
977 | break; | |
978 | } | |
979 | ||
980 | debug("%s: switch%d, enable=%d, mask=0x%x\n", | |
981 | __func__, sw + 1, enable, mask); | |
982 | ||
983 | return ret; | |
984 | } | |
985 | ||
986 | static int switch_get_suspend_enable(struct udevice *dev) | |
987 | { | |
988 | struct rk8xx_priv *priv = dev_get_priv(dev->parent); | |
989 | int val, ret = 0, sw = dev->driver_data - 1; | |
990 | uint mask = 0; | |
991 | ||
992 | switch (priv->variant) { | |
993 | case RK808_ID: | |
994 | mask = 1 << (sw + 5); | |
995 | val = pmic_reg_read(dev->parent, REG_SLEEP_SET_OFF1); | |
996 | if (val < 0) | |
997 | return val; | |
998 | ret = val & mask ? 0 : 1; | |
999 | break; | |
ee30068f JC |
1000 | case RK809_ID: |
1001 | mask = 1 << (sw + 6); | |
1002 | val = pmic_reg_read(dev->parent, RK817_POWER_SLP_EN(0)); | |
1003 | if (val < 0) | |
1004 | return val; | |
1005 | ret = val & mask ? 1 : 0; | |
1006 | break; | |
94afc1cb EZ |
1007 | case RK818_ID: |
1008 | mask = 1 << 6; | |
1009 | val = pmic_reg_read(dev->parent, REG_SLEEP_SET_OFF1); | |
1010 | if (val < 0) | |
1011 | return val; | |
1012 | ret = val & mask ? 0 : 1; | |
1013 | break; | |
1014 | } | |
1015 | ||
1016 | return ret; | |
1017 | } | |
1018 | ||
1019 | /* | |
1020 | * RK8xx switch does not need to set the voltage, | |
1021 | * but if dts set regulator-min-microvolt/regulator-max-microvolt, | |
1022 | * will cause regulator set value fail and not to enable this switch. | |
1023 | * So add an empty function to return success. | |
1024 | */ | |
1025 | static int switch_get_value(struct udevice *dev) | |
1026 | { | |
1027 | return 0; | |
1028 | } | |
1029 | ||
1030 | static int switch_set_value(struct udevice *dev, int uvolt) | |
1031 | { | |
1032 | return 0; | |
1033 | } | |
1034 | ||
453c5a92 | 1035 | static int rk8xx_buck_probe(struct udevice *dev) |
e1227764 | 1036 | { |
caa4daa2 | 1037 | struct dm_regulator_uclass_plat *uc_pdata; |
e1227764 | 1038 | |
caa4daa2 | 1039 | uc_pdata = dev_get_uclass_plat(dev); |
e1227764 SG |
1040 | |
1041 | uc_pdata->type = REGULATOR_TYPE_BUCK; | |
1042 | uc_pdata->mode_count = 0; | |
1043 | ||
1044 | return 0; | |
1045 | } | |
1046 | ||
453c5a92 | 1047 | static int rk8xx_ldo_probe(struct udevice *dev) |
e1227764 | 1048 | { |
caa4daa2 | 1049 | struct dm_regulator_uclass_plat *uc_pdata; |
e1227764 | 1050 | |
caa4daa2 | 1051 | uc_pdata = dev_get_uclass_plat(dev); |
e1227764 SG |
1052 | |
1053 | uc_pdata->type = REGULATOR_TYPE_LDO; | |
1054 | uc_pdata->mode_count = 0; | |
1055 | ||
1056 | return 0; | |
1057 | } | |
1058 | ||
453c5a92 | 1059 | static int rk8xx_switch_probe(struct udevice *dev) |
e1227764 | 1060 | { |
caa4daa2 | 1061 | struct dm_regulator_uclass_plat *uc_pdata; |
e1227764 | 1062 | |
caa4daa2 | 1063 | uc_pdata = dev_get_uclass_plat(dev); |
e1227764 SG |
1064 | |
1065 | uc_pdata->type = REGULATOR_TYPE_FIXED; | |
1066 | uc_pdata->mode_count = 0; | |
1067 | ||
1068 | return 0; | |
1069 | } | |
1070 | ||
453c5a92 | 1071 | static const struct dm_regulator_ops rk8xx_buck_ops = { |
e1227764 SG |
1072 | .get_value = buck_get_value, |
1073 | .set_value = buck_set_value, | |
94afc1cb EZ |
1074 | .set_suspend_value = buck_set_suspend_value, |
1075 | .get_suspend_value = buck_get_suspend_value, | |
e1227764 SG |
1076 | .get_enable = buck_get_enable, |
1077 | .set_enable = buck_set_enable, | |
94afc1cb EZ |
1078 | .set_suspend_enable = buck_set_suspend_enable, |
1079 | .get_suspend_enable = buck_get_suspend_enable, | |
e1227764 SG |
1080 | }; |
1081 | ||
453c5a92 | 1082 | static const struct dm_regulator_ops rk8xx_ldo_ops = { |
e1227764 SG |
1083 | .get_value = ldo_get_value, |
1084 | .set_value = ldo_set_value, | |
94afc1cb EZ |
1085 | .set_suspend_value = ldo_set_suspend_value, |
1086 | .get_suspend_value = ldo_get_suspend_value, | |
e1227764 SG |
1087 | .get_enable = ldo_get_enable, |
1088 | .set_enable = ldo_set_enable, | |
94afc1cb EZ |
1089 | .set_suspend_enable = ldo_set_suspend_enable, |
1090 | .get_suspend_enable = ldo_get_suspend_enable, | |
e1227764 SG |
1091 | }; |
1092 | ||
453c5a92 | 1093 | static const struct dm_regulator_ops rk8xx_switch_ops = { |
94afc1cb EZ |
1094 | .get_value = switch_get_value, |
1095 | .set_value = switch_set_value, | |
e1227764 SG |
1096 | .get_enable = switch_get_enable, |
1097 | .set_enable = switch_set_enable, | |
94afc1cb EZ |
1098 | .set_suspend_enable = switch_set_suspend_enable, |
1099 | .get_suspend_enable = switch_get_suspend_enable, | |
1100 | .set_suspend_value = switch_set_suspend_value, | |
1101 | .get_suspend_value = switch_get_suspend_value, | |
e1227764 SG |
1102 | }; |
1103 | ||
453c5a92 JC |
1104 | U_BOOT_DRIVER(rk8xx_buck) = { |
1105 | .name = "rk8xx_buck", | |
e1227764 | 1106 | .id = UCLASS_REGULATOR, |
453c5a92 JC |
1107 | .ops = &rk8xx_buck_ops, |
1108 | .probe = rk8xx_buck_probe, | |
e1227764 SG |
1109 | }; |
1110 | ||
453c5a92 JC |
1111 | U_BOOT_DRIVER(rk8xx_ldo) = { |
1112 | .name = "rk8xx_ldo", | |
e1227764 | 1113 | .id = UCLASS_REGULATOR, |
453c5a92 JC |
1114 | .ops = &rk8xx_ldo_ops, |
1115 | .probe = rk8xx_ldo_probe, | |
e1227764 SG |
1116 | }; |
1117 | ||
453c5a92 JC |
1118 | U_BOOT_DRIVER(rk8xx_switch) = { |
1119 | .name = "rk8xx_switch", | |
e1227764 | 1120 | .id = UCLASS_REGULATOR, |
453c5a92 JC |
1121 | .ops = &rk8xx_switch_ops, |
1122 | .probe = rk8xx_switch_probe, | |
e1227764 SG |
1123 | }; |
1124 | #endif | |
1125 | ||
453c5a92 | 1126 | int rk8xx_spl_configure_buck(struct udevice *pmic, int buck, int uvolt) |
e1227764 SG |
1127 | { |
1128 | int ret; | |
1129 | ||
1130 | ret = _buck_set_value(pmic, buck, uvolt); | |
1131 | if (ret) | |
1132 | return ret; | |
1133 | ||
1134 | return _buck_set_enable(pmic, buck, true); | |
1135 | } | |
ad98f882 WE |
1136 | |
1137 | int rk818_spl_configure_usb_input_current(struct udevice *pmic, int current_ma) | |
1138 | { | |
1139 | uint i; | |
1140 | ||
1141 | for (i = 0; i < ARRAY_SIZE(rk818_chrg_cur_input_array); i++) | |
1142 | if (current_ma <= rk818_chrg_cur_input_array[i]) | |
1143 | break; | |
1144 | ||
1145 | return pmic_clrsetbits(pmic, REG_USB_CTRL, RK818_USB_ILIM_SEL_MASK, i); | |
1146 | } | |
1147 | ||
1148 | int rk818_spl_configure_usb_chrg_shutdown(struct udevice *pmic, int uvolt) | |
1149 | { | |
1150 | uint i; | |
1151 | ||
1152 | for (i = 0; i < ARRAY_SIZE(rk818_chrg_shutdown_vsel_array); i++) | |
1153 | if (uvolt <= rk818_chrg_shutdown_vsel_array[i]) | |
1154 | break; | |
1155 | ||
1156 | return pmic_clrsetbits(pmic, REG_USB_CTRL, RK818_USB_CHG_SD_VSEL_MASK, | |
1157 | i); | |
1158 | } |