blob: e905df3a800dcef15ad88f45949e4cd6ed52e0f5 [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>
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.h>
Jonas Karlman31c3c802023-07-02 12:41:15 +000015#include <linux/delay.h>
Jacob Chen614704b2017-05-02 14:54:52 +080016#include <power/rk8xx_pmic.h>
Simon Glassadecfef2016-01-21 19:43:30 -070017#include <power/pmic.h>
18#include <power/regulator.h>
19
20#ifndef CONFIG_SPL_BUILD
21#define ENABLE_DRIVER
22#endif
23
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080024/* Not used or exisit register and configure */
25#define NA 0xff
26
Jacob Chen21a6a252017-05-02 14:54:50 +080027/* Field Definitions */
28#define RK808_BUCK_VSEL_MASK 0x3f
29#define RK808_BUCK4_VSEL_MASK 0xf
30#define RK808_LDO_VSEL_MASK 0x1f
31
Joseph Chend6b3e832019-09-26 15:45:07 +080032/* RK809 BUCK5 */
33#define RK809_BUCK5_CONFIG(n) (0xde + (n) * 1)
34#define RK809_BUCK5_VSEL_MASK 0x07
35
Joseph Chen4a1ae182019-09-26 15:44:55 +080036/* RK817 BUCK */
37#define RK817_BUCK_ON_VSEL(n) (0xbb + 3 * ((n) - 1))
38#define RK817_BUCK_SLP_VSEL(n) (0xbc + 3 * ((n) - 1))
39#define RK817_BUCK_VSEL_MASK 0x7f
40#define RK817_BUCK_CONFIG(i) (0xba + (i) * 3)
41
42/* RK817 LDO */
43#define RK817_LDO_ON_VSEL(n) (0xcc + 2 * ((n) - 1))
44#define RK817_LDO_SLP_VSEL(n) (0xcd + 2 * ((n) - 1))
45#define RK817_LDO_VSEL_MASK 0x7f
46
47/* RK817 ENABLE */
48#define RK817_POWER_EN(n) (0xb1 + (n))
49#define RK817_POWER_SLP_EN(n) (0xb5 + (n))
50
Jacob Chen36163e32017-05-02 14:54:51 +080051#define RK818_BUCK_VSEL_MASK 0x3f
52#define RK818_BUCK4_VSEL_MASK 0x1f
53#define RK818_LDO_VSEL_MASK 0x1f
54#define RK818_LDO3_ON_VSEL_MASK 0xf
55#define RK818_BOOST_ON_VSEL_MASK 0xe0
Wadim Egorovc2581052017-06-19 12:36:39 +020056#define RK818_USB_ILIM_SEL_MASK 0x0f
57#define RK818_USB_CHG_SD_VSEL_MASK 0x70
58
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080059/*
60 * Ramp delay
61 */
Elaine Zhang1d9077e2019-09-26 15:43:55 +080062#define RK805_RAMP_RATE_OFFSET 3
63#define RK805_RAMP_RATE_MASK (3 << RK805_RAMP_RATE_OFFSET)
64#define RK805_RAMP_RATE_3MV_PER_US (0 << RK805_RAMP_RATE_OFFSET)
65#define RK805_RAMP_RATE_6MV_PER_US (1 << RK805_RAMP_RATE_OFFSET)
66#define RK805_RAMP_RATE_12_5MV_PER_US (2 << RK805_RAMP_RATE_OFFSET)
67#define RK805_RAMP_RATE_25MV_PER_US (3 << RK805_RAMP_RATE_OFFSET)
Joseph Chend6b3e832019-09-26 15:45:07 +080068
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080069#define RK808_RAMP_RATE_OFFSET 3
70#define RK808_RAMP_RATE_MASK (3 << RK808_RAMP_RATE_OFFSET)
71#define RK808_RAMP_RATE_2MV_PER_US (0 << RK808_RAMP_RATE_OFFSET)
72#define RK808_RAMP_RATE_4MV_PER_US (1 << RK808_RAMP_RATE_OFFSET)
73#define RK808_RAMP_RATE_6MV_PER_US (2 << RK808_RAMP_RATE_OFFSET)
74#define RK808_RAMP_RATE_10MV_PER_US (3 << RK808_RAMP_RATE_OFFSET)
Jacob Chen36163e32017-05-02 14:54:51 +080075
Joseph Chen4a1ae182019-09-26 15:44:55 +080076#define RK817_RAMP_RATE_OFFSET 6
77#define RK817_RAMP_RATE_MASK (0x3 << RK817_RAMP_RATE_OFFSET)
78#define RK817_RAMP_RATE_3MV_PER_US (0x0 << RK817_RAMP_RATE_OFFSET)
79#define RK817_RAMP_RATE_6_3MV_PER_US (0x1 << RK817_RAMP_RATE_OFFSET)
80#define RK817_RAMP_RATE_12_5MV_PER_US (0x2 << RK817_RAMP_RATE_OFFSET)
81#define RK817_RAMP_RATE_25MV_PER_US (0x3 << RK817_RAMP_RATE_OFFSET)
82
Jacob Chen614704b2017-05-02 14:54:52 +080083struct rk8xx_reg_info {
Simon Glassadecfef2016-01-21 19:43:30 -070084 uint min_uv;
85 uint step_uv;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080086 u8 vsel_reg;
87 u8 vsel_sleep_reg;
88 u8 config_reg;
Jacob Chen21a6a252017-05-02 14:54:50 +080089 u8 vsel_mask;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +080090 u8 min_sel;
Joseph Chenfb18ddd2023-08-21 22:30:25 +000091 u8 max_sel;
Simon Glassadecfef2016-01-21 19:43:30 -070092};
93
Jacob Chen614704b2017-05-02 14:54:52 +080094static const struct rk8xx_reg_info rk808_buck[] = {
Joseph Chenfb18ddd2023-08-21 22:30:25 +000095 { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK808_BUCK_VSEL_MASK, 0x00, 0x3f },
96 { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK808_BUCK_VSEL_MASK, 0x00, 0x3f },
97 { NA, NA, NA, NA, REG_BUCK3_CONFIG, NA, NA, NA },
98 { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK808_BUCK4_VSEL_MASK, 0x00, 0x0f },
Simon Glassadecfef2016-01-21 19:43:30 -070099};
100
Elaine Zhang04e5a432019-09-26 15:43:54 +0800101static const struct rk8xx_reg_info rk816_buck[] = {
102 /* buck 1 */
Joseph Chenfb18ddd2023-08-21 22:30:25 +0000103 { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, 0x3b },
104 { 1800000, 200000, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, 0x3e },
105 { 2300000, 0, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, 0x3f },
Elaine Zhang04e5a432019-09-26 15:43:54 +0800106 /* buck 2 */
Joseph Chenfb18ddd2023-08-21 22:30:25 +0000107 { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, 0x3b },
108 { 1800000, 200000, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3c, 0x3e },
109 { 2300000, 0, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x3f, 0x3f },
Elaine Zhang04e5a432019-09-26 15:43:54 +0800110 /* buck 3 */
Joseph Chenfb18ddd2023-08-21 22:30:25 +0000111 { NA, NA, NA, NA, REG_BUCK3_CONFIG, NA, NA, NA },
Elaine Zhang04e5a432019-09-26 15:43:54 +0800112 /* buck 4 */
Joseph Chenfb18ddd2023-08-21 22:30:25 +0000113 { 800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, 0x00, 0x1f },
Elaine Zhang04e5a432019-09-26 15:43:54 +0800114};
115
Joseph Chend6b3e832019-09-26 15:45:07 +0800116static const struct rk8xx_reg_info rk809_buck5[] = {
117 /* buck 5 */
Joseph Chenfb18ddd2023-08-21 22:30:25 +0000118 { 1500000, 0, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x00, 0x00 },
119 { 1800000, 200000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x01, 0x03 },
120 { 2800000, 200000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x04, 0x05 },
121 { 3300000, 300000, RK809_BUCK5_CONFIG(0), RK809_BUCK5_CONFIG(1), NA, RK809_BUCK5_VSEL_MASK, 0x06, 0x07 },
Joseph Chend6b3e832019-09-26 15:45:07 +0800122};
123
Joseph Chen4a1ae182019-09-26 15:44:55 +0800124static const struct rk8xx_reg_info rk817_buck[] = {
125 /* buck 1 */
Joseph Chenfb18ddd2023-08-21 22:30:25 +0000126 { 500000, 12500, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x00, 0x4f },
127 { 1500000, 100000, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x50, 0x58 },
128 { 2400000, 0, RK817_BUCK_ON_VSEL(1), RK817_BUCK_SLP_VSEL(1), RK817_BUCK_CONFIG(1), RK817_BUCK_VSEL_MASK, 0x59, 0x7f },
Joseph Chen4a1ae182019-09-26 15:44:55 +0800129 /* buck 2 */
Joseph Chenfb18ddd2023-08-21 22:30:25 +0000130 { 500000, 12500, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x00, 0x4f },
131 { 1500000, 100000, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x50, 0x58 },
132 { 2400000, 0, RK817_BUCK_ON_VSEL(2), RK817_BUCK_SLP_VSEL(2), RK817_BUCK_CONFIG(2), RK817_BUCK_VSEL_MASK, 0x59, 0x7f },
Joseph Chen4a1ae182019-09-26 15:44:55 +0800133 /* buck 3 */
Joseph Chenfb18ddd2023-08-21 22:30:25 +0000134 { 500000, 12500, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x00, 0x4f },
135 { 1500000, 100000, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x50, 0x58 },
136 { 2400000, 0, RK817_BUCK_ON_VSEL(3), RK817_BUCK_SLP_VSEL(3), RK817_BUCK_CONFIG(3), RK817_BUCK_VSEL_MASK, 0x59, 0x7f },
Joseph Chen4a1ae182019-09-26 15:44:55 +0800137 /* buck 4 */
Joseph Chenfb18ddd2023-08-21 22:30:25 +0000138 { 500000, 12500, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x00, 0x4f },
139 { 1500000, 100000, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x50, 0x62 },
140 { 3400000, 0, RK817_BUCK_ON_VSEL(4), RK817_BUCK_SLP_VSEL(4), RK817_BUCK_CONFIG(4), RK817_BUCK_VSEL_MASK, 0x63, 0x7f },
Joseph Chen4a1ae182019-09-26 15:44:55 +0800141};
142
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200143static const struct rk8xx_reg_info rk818_buck[] = {
Joseph Chenfb18ddd2023-08-21 22:30:25 +0000144 { 712500, 12500, REG_BUCK1_ON_VSEL, REG_BUCK1_SLP_VSEL, REG_BUCK1_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, 0x3f },
145 { 712500, 12500, REG_BUCK2_ON_VSEL, REG_BUCK2_SLP_VSEL, REG_BUCK2_CONFIG, RK818_BUCK_VSEL_MASK, 0x00, 0x3f },
146 { NA, NA, NA, NA, REG_BUCK3_CONFIG, NA, NA, NA },
147 { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, 0x00, 0x1f },
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200148};
149
150#ifdef ENABLE_DRIVER
Jacob Chen614704b2017-05-02 14:54:52 +0800151static const struct rk8xx_reg_info rk808_ldo[] = {
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800152 { 1800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
153 { 1800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
154 { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK808_BUCK4_VSEL_MASK, },
155 { 1800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
156 { 1800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
157 { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
158 { 800000, 100000, REG_LDO7_ON_VSEL, REG_LDO7_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
159 { 1800000, 100000, REG_LDO8_ON_VSEL, REG_LDO8_SLP_VSEL, NA, RK808_LDO_VSEL_MASK, },
Simon Glassadecfef2016-01-21 19:43:30 -0700160};
161
Elaine Zhang04e5a432019-09-26 15:43:54 +0800162static const struct rk8xx_reg_info rk816_ldo[] = {
163 { 800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
164 { 800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
165 { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
166 { 800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
167 { 800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
168 { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
169};
170
Joseph Chen4a1ae182019-09-26 15:44:55 +0800171static const struct rk8xx_reg_info rk817_ldo[] = {
172 /* ldo1 */
173 { 600000, 25000, RK817_LDO_ON_VSEL(1), RK817_LDO_SLP_VSEL(1), NA, RK817_LDO_VSEL_MASK, 0x00, },
174 { 3400000, 0, RK817_LDO_ON_VSEL(1), RK817_LDO_SLP_VSEL(1), NA, RK817_LDO_VSEL_MASK, 0x70, },
175 /* ldo2 */
176 { 600000, 25000, RK817_LDO_ON_VSEL(2), RK817_LDO_SLP_VSEL(2), NA, RK817_LDO_VSEL_MASK, 0x00, },
177 { 3400000, 0, RK817_LDO_ON_VSEL(2), RK817_LDO_SLP_VSEL(2), NA, RK817_LDO_VSEL_MASK, 0x70, },
178 /* ldo3 */
179 { 600000, 25000, RK817_LDO_ON_VSEL(3), RK817_LDO_SLP_VSEL(3), NA, RK817_LDO_VSEL_MASK, 0x00, },
180 { 3400000, 0, RK817_LDO_ON_VSEL(3), RK817_LDO_SLP_VSEL(3), NA, RK817_LDO_VSEL_MASK, 0x70, },
181 /* ldo4 */
182 { 600000, 25000, RK817_LDO_ON_VSEL(4), RK817_LDO_SLP_VSEL(4), NA, RK817_LDO_VSEL_MASK, 0x00, },
183 { 3400000, 0, RK817_LDO_ON_VSEL(4), RK817_LDO_SLP_VSEL(4), NA, RK817_LDO_VSEL_MASK, 0x70, },
184 /* ldo5 */
185 { 600000, 25000, RK817_LDO_ON_VSEL(5), RK817_LDO_SLP_VSEL(5), NA, RK817_LDO_VSEL_MASK, 0x00, },
186 { 3400000, 0, RK817_LDO_ON_VSEL(5), RK817_LDO_SLP_VSEL(5), NA, RK817_LDO_VSEL_MASK, 0x70, },
187 /* ldo6 */
188 { 600000, 25000, RK817_LDO_ON_VSEL(6), RK817_LDO_SLP_VSEL(6), NA, RK817_LDO_VSEL_MASK, 0x00, },
189 { 3400000, 0, RK817_LDO_ON_VSEL(6), RK817_LDO_SLP_VSEL(6), NA, RK817_LDO_VSEL_MASK, 0x70, },
190 /* ldo7 */
191 { 600000, 25000, RK817_LDO_ON_VSEL(7), RK817_LDO_SLP_VSEL(7), NA, RK817_LDO_VSEL_MASK, 0x00, },
192 { 3400000, 0, RK817_LDO_ON_VSEL(7), RK817_LDO_SLP_VSEL(7), NA, RK817_LDO_VSEL_MASK, 0x70, },
193 /* ldo8 */
194 { 600000, 25000, RK817_LDO_ON_VSEL(8), RK817_LDO_SLP_VSEL(8), NA, RK817_LDO_VSEL_MASK, 0x00, },
195 { 3400000, 0, RK817_LDO_ON_VSEL(8), RK817_LDO_SLP_VSEL(8), NA, RK817_LDO_VSEL_MASK, 0x70, },
196 /* ldo9 */
197 { 600000, 25000, RK817_LDO_ON_VSEL(9), RK817_LDO_SLP_VSEL(9), NA, RK817_LDO_VSEL_MASK, 0x00, },
198 { 3400000, 0, RK817_LDO_ON_VSEL(9), RK817_LDO_SLP_VSEL(9), NA, RK817_LDO_VSEL_MASK, 0x70, },
199};
200
Jacob Chen614704b2017-05-02 14:54:52 +0800201static const struct rk8xx_reg_info rk818_ldo[] = {
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800202 { 1800000, 100000, REG_LDO1_ON_VSEL, REG_LDO1_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
203 { 1800000, 100000, REG_LDO2_ON_VSEL, REG_LDO2_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
204 { 800000, 100000, REG_LDO3_ON_VSEL, REG_LDO3_SLP_VSEL, NA, RK818_LDO3_ON_VSEL_MASK, },
205 { 1800000, 100000, REG_LDO4_ON_VSEL, REG_LDO4_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
206 { 1800000, 100000, REG_LDO5_ON_VSEL, REG_LDO5_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
207 { 800000, 100000, REG_LDO6_ON_VSEL, REG_LDO6_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
208 { 800000, 100000, REG_LDO7_ON_VSEL, REG_LDO7_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
209 { 1800000, 100000, REG_LDO8_ON_VSEL, REG_LDO8_SLP_VSEL, NA, RK818_LDO_VSEL_MASK, },
Jacob Chen36163e32017-05-02 14:54:51 +0800210};
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200211#endif
Jacob Chen36163e32017-05-02 14:54:51 +0800212
Jacob Chen614704b2017-05-02 14:54:52 +0800213static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800214 int num, int uvolt)
Jacob Chen36163e32017-05-02 14:54:51 +0800215{
Jacob Chen614704b2017-05-02 14:54:52 +0800216 struct rk8xx_priv *priv = dev_get_priv(pmic);
Elaine Zhang04e5a432019-09-26 15:43:54 +0800217
Jacob Chen614704b2017-05-02 14:54:52 +0800218 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800219 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800220 case RK816_ID:
221 switch (num) {
222 case 0:
223 case 1:
224 if (uvolt <= 1450000)
225 return &rk816_buck[num * 3 + 0];
226 else if (uvolt <= 2200000)
227 return &rk816_buck[num * 3 + 1];
228 else
229 return &rk816_buck[num * 3 + 2];
230 default:
231 return &rk816_buck[num + 4];
232 }
Joseph Chen4a1ae182019-09-26 15:44:55 +0800233
Joseph Chend6b3e832019-09-26 15:45:07 +0800234 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800235 case RK817_ID:
236 switch (num) {
237 case 0 ... 2:
238 if (uvolt < 1500000)
239 return &rk817_buck[num * 3 + 0];
240 else if (uvolt < 2400000)
241 return &rk817_buck[num * 3 + 1];
242 else
243 return &rk817_buck[num * 3 + 2];
244 case 3:
245 if (uvolt < 1500000)
246 return &rk817_buck[num * 3 + 0];
247 else if (uvolt < 3400000)
248 return &rk817_buck[num * 3 + 1];
249 else
250 return &rk817_buck[num * 3 + 2];
Joseph Chend6b3e832019-09-26 15:45:07 +0800251 /* BUCK5 for RK809 */
252 default:
253 if (uvolt < 1800000)
254 return &rk809_buck5[0];
255 else if (uvolt < 2800000)
256 return &rk809_buck5[1];
257 else if (uvolt < 3300000)
258 return &rk809_buck5[2];
259 else
260 return &rk809_buck5[3];
Joseph Chen4a1ae182019-09-26 15:44:55 +0800261 }
Jacob Chen36163e32017-05-02 14:54:51 +0800262 case RK818_ID:
263 return &rk818_buck[num];
264 default:
265 return &rk808_buck[num];
266 }
267}
268
Simon Glassadecfef2016-01-21 19:43:30 -0700269static int _buck_set_value(struct udevice *pmic, int buck, int uvolt)
270{
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800271 const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt);
Elaine Zhang04e5a432019-09-26 15:43:54 +0800272 struct rk8xx_priv *priv = dev_get_priv(pmic);
Jacob Chen21a6a252017-05-02 14:54:50 +0800273 int mask = info->vsel_mask;
Simon Glassadecfef2016-01-21 19:43:30 -0700274 int val;
275
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800276 if (info->vsel_reg == NA)
Simon Glassadecfef2016-01-21 19:43:30 -0700277 return -ENOSYS;
Elaine Zhang04e5a432019-09-26 15:43:54 +0800278
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800279 if (info->step_uv == 0) /* Fixed voltage */
280 val = info->min_sel;
281 else
282 val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
283
284 debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
285 __func__, uvolt, buck + 1, info->vsel_reg, mask, val);
286
Elaine Zhang04e5a432019-09-26 15:43:54 +0800287 if (priv->variant == RK816_ID) {
288 pmic_clrsetbits(pmic, info->vsel_reg, mask, val);
289 return pmic_clrsetbits(pmic, RK816_REG_DCDC_EN2,
290 1 << 7, 1 << 7);
291 } else {
292 return pmic_clrsetbits(pmic, info->vsel_reg, mask, val);
293 }
Simon Glassadecfef2016-01-21 19:43:30 -0700294}
295
296static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
297{
Elaine Zhang04e5a432019-09-26 15:43:54 +0800298 uint mask, value, en_reg;
Joseph Chen4a1ae182019-09-26 15:44:55 +0800299 int ret = 0;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800300 struct rk8xx_priv *priv = dev_get_priv(pmic);
Simon Glassadecfef2016-01-21 19:43:30 -0700301
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800302 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800303 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800304 case RK816_ID:
305 if (buck >= 4) {
306 buck -= 4;
307 en_reg = RK816_REG_DCDC_EN2;
308 } else {
309 en_reg = RK816_REG_DCDC_EN1;
310 }
311 if (enable)
312 value = ((1 << buck) | (1 << (buck + 4)));
313 else
314 value = ((0 << buck) | (1 << (buck + 4)));
315 ret = pmic_reg_write(pmic, en_reg, value);
316 break;
317
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800318 case RK808_ID:
319 case RK818_ID:
320 mask = 1 << buck;
321 if (enable) {
322 ret = pmic_clrsetbits(pmic, REG_DCDC_ILMAX,
323 0, 3 << (buck * 2));
324 if (ret)
325 return ret;
326 }
327 ret = pmic_clrsetbits(pmic, REG_DCDC_EN, mask,
328 enable ? mask : 0);
329 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800330 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800331 case RK817_ID:
332 if (buck < 4) {
333 if (enable)
334 value = ((1 << buck) | (1 << (buck + 4)));
335 else
336 value = ((0 << buck) | (1 << (buck + 4)));
337 ret = pmic_reg_write(pmic, RK817_POWER_EN(0), value);
Joseph Chend6b3e832019-09-26 15:45:07 +0800338 /* BUCK5 for RK809 */
339 } else {
340 if (enable)
341 value = ((1 << 1) | (1 << 5));
342 else
343 value = ((0 << 1) | (1 << 5));
344 ret = pmic_reg_write(pmic, RK817_POWER_EN(3), value);
Joseph Chen4a1ae182019-09-26 15:44:55 +0800345 }
346 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800347 default:
348 ret = -EINVAL;
Simon Glassadecfef2016-01-21 19:43:30 -0700349 }
350
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800351 return ret;
Simon Glassadecfef2016-01-21 19:43:30 -0700352}
353
354#ifdef ENABLE_DRIVER
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800355static int _buck_set_suspend_value(struct udevice *pmic, int buck, int uvolt)
356{
357 const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt);
358 int mask = info->vsel_mask;
359 int val;
360
361 if (info->vsel_sleep_reg == NA)
362 return -ENOSYS;
363
364 if (info->step_uv == 0)
365 val = info->min_sel;
366 else
367 val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
368
369 debug("%s: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n",
370 __func__, uvolt, buck + 1, info->vsel_sleep_reg, mask, val);
371
372 return pmic_clrsetbits(pmic, info->vsel_sleep_reg, mask, val);
373}
374
375static int _buck_get_enable(struct udevice *pmic, int buck)
376{
377 struct rk8xx_priv *priv = dev_get_priv(pmic);
378 uint mask = 0;
379 int ret = 0;
380
381 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800382 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800383 case RK816_ID:
384 if (buck >= 4) {
385 mask = 1 << (buck - 4);
386 ret = pmic_reg_read(pmic, RK816_REG_DCDC_EN2);
387 } else {
388 mask = 1 << buck;
389 ret = pmic_reg_read(pmic, RK816_REG_DCDC_EN1);
390 }
391 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800392 case RK808_ID:
393 case RK818_ID:
394 mask = 1 << buck;
395 ret = pmic_reg_read(pmic, REG_DCDC_EN);
396 if (ret < 0)
397 return ret;
398 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800399 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800400 case RK817_ID:
401 if (buck < 4) {
402 mask = 1 << buck;
403 ret = pmic_reg_read(pmic, RK817_POWER_EN(0));
Joseph Chend6b3e832019-09-26 15:45:07 +0800404 /* BUCK5 for RK809 */
405 } else {
406 mask = 1 << 1;
407 ret = pmic_reg_read(pmic, RK817_POWER_EN(3));
Joseph Chen4a1ae182019-09-26 15:44:55 +0800408 }
409 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800410 }
411
412 if (ret < 0)
413 return ret;
414
415 return ret & mask ? true : false;
416}
417
418static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable)
419{
Joseph Chen4a1ae182019-09-26 15:44:55 +0800420 uint mask = 0;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800421 int ret;
422 struct rk8xx_priv *priv = dev_get_priv(pmic);
423
424 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800425 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800426 case RK816_ID:
427 mask = 1 << buck;
428 ret = pmic_clrsetbits(pmic, RK816_REG_DCDC_SLP_EN, mask,
429 enable ? mask : 0);
430 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800431 case RK808_ID:
432 case RK818_ID:
433 mask = 1 << buck;
434 ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF1, mask,
435 enable ? 0 : mask);
436 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800437 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800438 case RK817_ID:
439 if (buck < 4)
440 mask = 1 << buck;
Joseph Chend6b3e832019-09-26 15:45:07 +0800441 else
442 mask = 1 << 5; /* BUCK5 for RK809 */
Joseph Chen4a1ae182019-09-26 15:44:55 +0800443 ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(0), mask,
444 enable ? mask : 0);
445 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800446 default:
447 ret = -EINVAL;
448 }
449
450 return ret;
451}
452
453static int _buck_get_suspend_enable(struct udevice *pmic, int buck)
454{
455 struct rk8xx_priv *priv = dev_get_priv(pmic);
456 int ret, val;
Joseph Chen4a1ae182019-09-26 15:44:55 +0800457 uint mask = 0;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800458
459 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800460 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800461 case RK816_ID:
462 mask = 1 << buck;
463 val = pmic_reg_read(pmic, RK816_REG_DCDC_SLP_EN);
464 if (val < 0)
465 return val;
466 ret = val & mask ? 1 : 0;
467 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800468 case RK808_ID:
469 case RK818_ID:
470 mask = 1 << buck;
471 val = pmic_reg_read(pmic, REG_SLEEP_SET_OFF1);
472 if (val < 0)
473 return val;
474 ret = val & mask ? 0 : 1;
475 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800476 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800477 case RK817_ID:
478 if (buck < 4)
479 mask = 1 << buck;
Joseph Chend6b3e832019-09-26 15:45:07 +0800480 else
481 mask = 1 << 5; /* BUCK5 for RK809 */
Joseph Chen4a1ae182019-09-26 15:44:55 +0800482
483 val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(0));
484 if (val < 0)
485 return val;
486 ret = val & mask ? 1 : 0;
487 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800488 default:
489 ret = -EINVAL;
490 }
491
492 return ret;
493}
494
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200495static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800496 int num, int uvolt)
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200497{
498 struct rk8xx_priv *priv = dev_get_priv(pmic);
Elaine Zhang04e5a432019-09-26 15:43:54 +0800499
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200500 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800501 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800502 case RK816_ID:
503 return &rk816_ldo[num];
Joseph Chend6b3e832019-09-26 15:45:07 +0800504 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800505 case RK817_ID:
506 if (uvolt < 3400000)
507 return &rk817_ldo[num * 2 + 0];
508 else
509 return &rk817_ldo[num * 2 + 1];
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200510 case RK818_ID:
511 return &rk818_ldo[num];
512 default:
513 return &rk808_ldo[num];
514 }
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800515}
516
517static int _ldo_get_enable(struct udevice *pmic, int ldo)
518{
519 struct rk8xx_priv *priv = dev_get_priv(pmic);
520 uint mask = 0;
521 int ret = 0;
522
523 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800524 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800525 case RK816_ID:
526 if (ldo >= 4) {
527 mask = 1 << (ldo - 4);
528 ret = pmic_reg_read(pmic, RK816_REG_LDO_EN2);
529 } else {
530 mask = 1 << ldo;
531 ret = pmic_reg_read(pmic, RK816_REG_LDO_EN1);
532 }
533 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800534 case RK808_ID:
535 case RK818_ID:
536 mask = 1 << ldo;
537 ret = pmic_reg_read(pmic, REG_LDO_EN);
538 if (ret < 0)
539 return ret;
540 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800541 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800542 case RK817_ID:
543 if (ldo < 4) {
544 mask = 1 << ldo;
545 ret = pmic_reg_read(pmic, RK817_POWER_EN(1));
546 } else if (ldo < 8) {
547 mask = 1 << (ldo - 4);
548 ret = pmic_reg_read(pmic, RK817_POWER_EN(2));
549 } else if (ldo == 8) {
550 mask = 1 << 0;
551 ret = pmic_reg_read(pmic, RK817_POWER_EN(3));
552 } else {
553 return false;
554 }
555 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800556 }
557
558 if (ret < 0)
559 return ret;
560
561 return ret & mask ? true : false;
562}
563
564static int _ldo_set_enable(struct udevice *pmic, int ldo, bool enable)
565{
566 struct rk8xx_priv *priv = dev_get_priv(pmic);
Elaine Zhang04e5a432019-09-26 15:43:54 +0800567 uint mask, value, en_reg;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800568 int ret = 0;
569
570 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800571 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800572 case RK816_ID:
573 if (ldo >= 4) {
574 ldo -= 4;
575 en_reg = RK816_REG_LDO_EN2;
576 } else {
577 en_reg = RK816_REG_LDO_EN1;
578 }
579 if (enable)
580 value = ((1 << ldo) | (1 << (ldo + 4)));
581 else
582 value = ((0 << ldo) | (1 << (ldo + 4)));
583
584 ret = pmic_reg_write(pmic, en_reg, value);
585 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800586 case RK808_ID:
587 case RK818_ID:
588 mask = 1 << ldo;
589 ret = pmic_clrsetbits(pmic, REG_LDO_EN, mask,
Elaine Zhang04e5a432019-09-26 15:43:54 +0800590 enable ? mask : 0);
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800591 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800592 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800593 case RK817_ID:
594 if (ldo < 4) {
595 en_reg = RK817_POWER_EN(1);
596 } else if (ldo < 8) {
597 ldo -= 4;
598 en_reg = RK817_POWER_EN(2);
599 } else if (ldo == 8) {
600 ldo = 0; /* BIT 0 */
601 en_reg = RK817_POWER_EN(3);
602 } else {
603 return -EINVAL;
604 }
605 if (enable)
606 value = ((1 << ldo) | (1 << (ldo + 4)));
607 else
608 value = ((0 << ldo) | (1 << (ldo + 4)));
609 ret = pmic_reg_write(pmic, en_reg, value);
610 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800611 }
612
Jonas Karlman31c3c802023-07-02 12:41:15 +0000613 if (enable)
614 udelay(500);
615
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800616 return ret;
Wadim Egorov4c4905f2017-06-19 12:36:38 +0200617}
618
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800619static int _ldo_set_suspend_enable(struct udevice *pmic, int ldo, bool enable)
620{
621 struct rk8xx_priv *priv = dev_get_priv(pmic);
622 uint mask;
623 int ret = 0;
624
625 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800626 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800627 case RK816_ID:
628 mask = 1 << ldo;
629 ret = pmic_clrsetbits(pmic, RK816_REG_LDO_SLP_EN, mask,
630 enable ? mask : 0);
631 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800632 case RK808_ID:
633 case RK818_ID:
634 mask = 1 << ldo;
635 ret = pmic_clrsetbits(pmic, REG_SLEEP_SET_OFF2, mask,
636 enable ? 0 : mask);
637 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800638 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800639 case RK817_ID:
640 if (ldo == 8) {
641 mask = 1 << 4; /* LDO9 */
642 ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(0), mask,
643 enable ? mask : 0);
644 } else {
645 mask = 1 << ldo;
646 ret = pmic_clrsetbits(pmic, RK817_POWER_SLP_EN(1), mask,
647 enable ? mask : 0);
648 }
649 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800650 }
651
652 return ret;
653}
654
655static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo)
656{
657 struct rk8xx_priv *priv = dev_get_priv(pmic);
658 int val, ret = 0;
659 uint mask;
660
661 switch (priv->variant) {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800662 case RK805_ID:
Elaine Zhang04e5a432019-09-26 15:43:54 +0800663 case RK816_ID:
664 mask = 1 << ldo;
665 val = pmic_reg_read(pmic, RK816_REG_LDO_SLP_EN);
666 if (val < 0)
667 return val;
668 ret = val & mask ? 1 : 0;
669 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800670 case RK808_ID:
671 case RK818_ID:
672 mask = 1 << ldo;
673 val = pmic_reg_read(pmic, REG_SLEEP_SET_OFF2);
674 if (val < 0)
675 return val;
676 ret = val & mask ? 0 : 1;
677 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800678 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800679 case RK817_ID:
680 if (ldo == 8) {
681 mask = 1 << 4; /* LDO9 */
682 val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(0));
683 if (val < 0)
684 return val;
685 ret = val & mask ? 1 : 0;
686 } else {
687 mask = 1 << ldo;
688 val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(1));
689 if (val < 0)
690 return val;
691 ret = val & mask ? 1 : 0;
692 }
693 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800694 }
695
696 return ret;
697}
698
Simon Glassadecfef2016-01-21 19:43:30 -0700699static int buck_get_value(struct udevice *dev)
700{
701 int buck = dev->driver_data - 1;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800702 const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0);
Jacob Chen21a6a252017-05-02 14:54:50 +0800703 int mask = info->vsel_mask;
Simon Glassadecfef2016-01-21 19:43:30 -0700704 int ret, val;
705
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800706 if (info->vsel_reg == NA)
Simon Glassadecfef2016-01-21 19:43:30 -0700707 return -ENOSYS;
Elaine Zhang04e5a432019-09-26 15:43:54 +0800708
Simon Glassadecfef2016-01-21 19:43:30 -0700709 ret = pmic_reg_read(dev->parent, info->vsel_reg);
710 if (ret < 0)
711 return ret;
Joseph Chenfb18ddd2023-08-21 22:30:25 +0000712
Simon Glassadecfef2016-01-21 19:43:30 -0700713 val = ret & mask;
Joseph Chenfb18ddd2023-08-21 22:30:25 +0000714 while (val > info->max_sel)
715 info++;
Simon Glassadecfef2016-01-21 19:43:30 -0700716
Joseph Chenfb18ddd2023-08-21 22:30:25 +0000717 return info->min_uv + (val - info->min_sel) * info->step_uv;
Simon Glassadecfef2016-01-21 19:43:30 -0700718}
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;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800730 const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck, 0);
731 int mask = info->vsel_mask;
732 int ret, val;
733
734 if (info->vsel_sleep_reg == NA)
735 return -ENOSYS;
736
737 ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg);
738 if (ret < 0)
739 return ret;
740
741 val = ret & mask;
Joseph Chenfb18ddd2023-08-21 22:30:25 +0000742 while (val > info->max_sel)
743 info++;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800744
Joseph Chenfb18ddd2023-08-21 22:30:25 +0000745 return info->min_uv + (val - info->min_sel) * info->step_uv;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800746}
747
748static 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
Simon Glassadecfef2016-01-21 19:43:30 -0700755static int buck_set_enable(struct udevice *dev, bool enable)
756{
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800757 int buck = dev->driver_data - 1;
Simon Glassadecfef2016-01-21 19:43:30 -0700758
759 return _buck_set_enable(dev->parent, buck, enable);
760}
761
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800762static int buck_set_suspend_enable(struct udevice *dev, bool enable)
Simon Glassadecfef2016-01-21 19:43:30 -0700763{
764 int buck = dev->driver_data - 1;
Simon Glassadecfef2016-01-21 19:43:30 -0700765
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800766 return _buck_set_suspend_enable(dev->parent, buck, enable);
767}
Simon Glassadecfef2016-01-21 19:43:30 -0700768
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800769static int buck_get_suspend_enable(struct udevice *dev)
770{
771 int buck = dev->driver_data - 1;
Simon Glassadecfef2016-01-21 19:43:30 -0700772
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800773 return _buck_get_suspend_enable(dev->parent, buck);
Simon Glassadecfef2016-01-21 19:43:30 -0700774}
775
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800776static int buck_get_enable(struct udevice *dev)
777{
778 int buck = dev->driver_data - 1;
779
780 return _buck_get_enable(dev->parent, buck);
781}
782
Simon Glassadecfef2016-01-21 19:43:30 -0700783static int ldo_get_value(struct udevice *dev)
784{
785 int ldo = dev->driver_data - 1;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800786 const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0);
Jacob Chen21a6a252017-05-02 14:54:50 +0800787 int mask = info->vsel_mask;
Simon Glassadecfef2016-01-21 19:43:30 -0700788 int ret, val;
789
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800790 if (info->vsel_reg == NA)
Simon Glassadecfef2016-01-21 19:43:30 -0700791 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
800static int ldo_set_value(struct udevice *dev, int uvolt)
801{
802 int ldo = dev->driver_data - 1;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800803 const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, uvolt);
Jacob Chen21a6a252017-05-02 14:54:50 +0800804 int mask = info->vsel_mask;
Simon Glassadecfef2016-01-21 19:43:30 -0700805 int val;
806
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800807 if (info->vsel_reg == NA)
Simon Glassadecfef2016-01-21 19:43:30 -0700808 return -ENOSYS;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800809
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);
Simon Glassadecfef2016-01-21 19:43:30 -0700817
818 return pmic_clrsetbits(dev->parent, info->vsel_reg, mask, val);
819}
820
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800821static int ldo_set_suspend_value(struct udevice *dev, int uvolt)
Simon Glassadecfef2016-01-21 19:43:30 -0700822{
823 int ldo = dev->driver_data - 1;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800824 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;
Simon Glassadecfef2016-01-21 19:43:30 -0700830
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800831 if (info->step_uv == 0)
832 val = info->min_sel;
833 else
834 val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel;
Simon Glassadecfef2016-01-21 19:43:30 -0700835
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800836 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);
Simon Glassadecfef2016-01-21 19:43:30 -0700840}
841
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800842static int ldo_get_suspend_value(struct udevice *dev)
Simon Glassadecfef2016-01-21 19:43:30 -0700843{
844 int ldo = dev->driver_data - 1;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800845 const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0);
846 int mask = info->vsel_mask;
847 int val, ret;
Simon Glassadecfef2016-01-21 19:43:30 -0700848
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800849 if (info->vsel_sleep_reg == NA)
850 return -ENOSYS;
Simon Glassadecfef2016-01-21 19:43:30 -0700851
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800852 ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg);
Simon Glassadecfef2016-01-21 19:43:30 -0700853 if (ret < 0)
854 return ret;
855
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800856 val = ret & mask;
857
858 return info->min_uv + val * info->step_uv;
859}
860
861static 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
868static 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
875static 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
882static int ldo_get_enable(struct udevice *dev)
883{
884 int ldo = dev->driver_data - 1;
885
886 return _ldo_get_enable(dev->parent, ldo);
Simon Glassadecfef2016-01-21 19:43:30 -0700887}
888
889static int switch_set_enable(struct udevice *dev, bool enable)
890{
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800891 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;
Joseph Chend6b3e832019-09-26 15:45:07 +0800901 case RK809_ID:
902 mask = (1 << (sw + 2)) | (1 << (sw + 6));
903 ret = pmic_clrsetbits(dev->parent, RK817_POWER_EN(3), mask,
William Wub863e492024-03-14 10:36:16 +0100904 enable ? mask : (1 << (sw + 6)));
Joseph Chend6b3e832019-09-26 15:45:07 +0800905 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800906 case RK818_ID:
907 mask = 1 << 6;
908 ret = pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask,
909 enable ? mask : 0);
910 break;
911 }
Simon Glassadecfef2016-01-21 19:43:30 -0700912
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800913 debug("%s: switch%d, enable=%d, mask=0x%x\n",
914 __func__, sw + 1, enable, mask);
Simon Glassadecfef2016-01-21 19:43:30 -0700915
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800916 return ret;
Simon Glassadecfef2016-01-21 19:43:30 -0700917}
918
Keerthyc8f82fb2017-06-13 09:53:52 +0530919static int switch_get_enable(struct udevice *dev)
Simon Glassadecfef2016-01-21 19:43:30 -0700920{
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800921 struct rk8xx_priv *priv = dev_get_priv(dev->parent);
922 int ret = 0, sw = dev->driver_data - 1;
923 uint mask = 0;
Simon Glassadecfef2016-01-21 19:43:30 -0700924
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800925 switch (priv->variant) {
926 case RK808_ID:
927 mask = 1 << (sw + 5);
928 ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
929 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800930 case RK809_ID:
931 mask = 1 << (sw + 2);
932 ret = pmic_reg_read(dev->parent, RK817_POWER_EN(3));
933 break;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800934 case RK818_ID:
935 mask = 1 << 6;
936 ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
937 break;
938 }
Simon Glassadecfef2016-01-21 19:43:30 -0700939
Simon Glassadecfef2016-01-21 19:43:30 -0700940 if (ret < 0)
941 return ret;
942
943 return ret & mask ? true : false;
944}
945
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800946static int switch_set_suspend_value(struct udevice *dev, int uvolt)
947{
948 return 0;
949}
950
951static int switch_get_suspend_value(struct udevice *dev)
952{
953 return 0;
954}
955
956static 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;
Joseph Chend6b3e832019-09-26 15:45:07 +0800968 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;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +0800973 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
986static 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;
Joseph Chend6b3e832019-09-26 15:45:07 +08001000 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;
Elaine Zhangfa9cccc2019-09-26 15:43:53 +08001007 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 */
1025static int switch_get_value(struct udevice *dev)
1026{
shengfei Xu7851d4e2023-08-21 22:30:26 +00001027 static const char * const supply_name_rk809[] = {
1028 "vcc9-supply",
1029 "vcc8-supply",
1030 };
1031 struct rk8xx_priv *priv = dev_get_priv(dev->parent);
1032 struct udevice *supply;
1033 int id = dev->driver_data - 1;
1034
1035 if (!switch_get_enable(dev))
1036 return 0;
1037
1038 if (priv->variant == RK809_ID) {
1039 if (!uclass_get_device_by_phandle(UCLASS_REGULATOR,
1040 dev->parent,
1041 supply_name_rk809[id],
1042 &supply))
1043 return regulator_get_value(supply);
1044 }
1045
Elaine Zhangfa9cccc2019-09-26 15:43:53 +08001046 return 0;
1047}
1048
1049static int switch_set_value(struct udevice *dev, int uvolt)
1050{
1051 return 0;
1052}
1053
Jacob Chen614704b2017-05-02 14:54:52 +08001054static int rk8xx_buck_probe(struct udevice *dev)
Simon Glassadecfef2016-01-21 19:43:30 -07001055{
Simon Glass71fa5b42020-12-03 16:55:18 -07001056 struct dm_regulator_uclass_plat *uc_pdata;
Simon Glassadecfef2016-01-21 19:43:30 -07001057
Simon Glass71fa5b42020-12-03 16:55:18 -07001058 uc_pdata = dev_get_uclass_plat(dev);
Simon Glassadecfef2016-01-21 19:43:30 -07001059
1060 uc_pdata->type = REGULATOR_TYPE_BUCK;
1061 uc_pdata->mode_count = 0;
1062
1063 return 0;
1064}
1065
Jacob Chen614704b2017-05-02 14:54:52 +08001066static int rk8xx_ldo_probe(struct udevice *dev)
Simon Glassadecfef2016-01-21 19:43:30 -07001067{
Simon Glass71fa5b42020-12-03 16:55:18 -07001068 struct dm_regulator_uclass_plat *uc_pdata;
Simon Glassadecfef2016-01-21 19:43:30 -07001069
Simon Glass71fa5b42020-12-03 16:55:18 -07001070 uc_pdata = dev_get_uclass_plat(dev);
Simon Glassadecfef2016-01-21 19:43:30 -07001071
1072 uc_pdata->type = REGULATOR_TYPE_LDO;
1073 uc_pdata->mode_count = 0;
1074
1075 return 0;
1076}
1077
Jacob Chen614704b2017-05-02 14:54:52 +08001078static int rk8xx_switch_probe(struct udevice *dev)
Simon Glassadecfef2016-01-21 19:43:30 -07001079{
Simon Glass71fa5b42020-12-03 16:55:18 -07001080 struct dm_regulator_uclass_plat *uc_pdata;
Simon Glassadecfef2016-01-21 19:43:30 -07001081
Simon Glass71fa5b42020-12-03 16:55:18 -07001082 uc_pdata = dev_get_uclass_plat(dev);
Simon Glassadecfef2016-01-21 19:43:30 -07001083
1084 uc_pdata->type = REGULATOR_TYPE_FIXED;
1085 uc_pdata->mode_count = 0;
1086
1087 return 0;
1088}
1089
Jacob Chen614704b2017-05-02 14:54:52 +08001090static const struct dm_regulator_ops rk8xx_buck_ops = {
Simon Glassadecfef2016-01-21 19:43:30 -07001091 .get_value = buck_get_value,
1092 .set_value = buck_set_value,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +08001093 .set_suspend_value = buck_set_suspend_value,
1094 .get_suspend_value = buck_get_suspend_value,
Simon Glassadecfef2016-01-21 19:43:30 -07001095 .get_enable = buck_get_enable,
1096 .set_enable = buck_set_enable,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +08001097 .set_suspend_enable = buck_set_suspend_enable,
1098 .get_suspend_enable = buck_get_suspend_enable,
Simon Glassadecfef2016-01-21 19:43:30 -07001099};
1100
Jacob Chen614704b2017-05-02 14:54:52 +08001101static const struct dm_regulator_ops rk8xx_ldo_ops = {
Simon Glassadecfef2016-01-21 19:43:30 -07001102 .get_value = ldo_get_value,
1103 .set_value = ldo_set_value,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +08001104 .set_suspend_value = ldo_set_suspend_value,
1105 .get_suspend_value = ldo_get_suspend_value,
Simon Glassadecfef2016-01-21 19:43:30 -07001106 .get_enable = ldo_get_enable,
1107 .set_enable = ldo_set_enable,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +08001108 .set_suspend_enable = ldo_set_suspend_enable,
1109 .get_suspend_enable = ldo_get_suspend_enable,
Simon Glassadecfef2016-01-21 19:43:30 -07001110};
1111
Jacob Chen614704b2017-05-02 14:54:52 +08001112static const struct dm_regulator_ops rk8xx_switch_ops = {
Elaine Zhangfa9cccc2019-09-26 15:43:53 +08001113 .get_value = switch_get_value,
1114 .set_value = switch_set_value,
Simon Glassadecfef2016-01-21 19:43:30 -07001115 .get_enable = switch_get_enable,
1116 .set_enable = switch_set_enable,
Elaine Zhangfa9cccc2019-09-26 15:43:53 +08001117 .set_suspend_enable = switch_set_suspend_enable,
1118 .get_suspend_enable = switch_get_suspend_enable,
1119 .set_suspend_value = switch_set_suspend_value,
1120 .get_suspend_value = switch_get_suspend_value,
Simon Glassadecfef2016-01-21 19:43:30 -07001121};
1122
Jacob Chen614704b2017-05-02 14:54:52 +08001123U_BOOT_DRIVER(rk8xx_buck) = {
1124 .name = "rk8xx_buck",
Simon Glassadecfef2016-01-21 19:43:30 -07001125 .id = UCLASS_REGULATOR,
Jacob Chen614704b2017-05-02 14:54:52 +08001126 .ops = &rk8xx_buck_ops,
1127 .probe = rk8xx_buck_probe,
Simon Glassadecfef2016-01-21 19:43:30 -07001128};
1129
Jacob Chen614704b2017-05-02 14:54:52 +08001130U_BOOT_DRIVER(rk8xx_ldo) = {
1131 .name = "rk8xx_ldo",
Simon Glassadecfef2016-01-21 19:43:30 -07001132 .id = UCLASS_REGULATOR,
Jacob Chen614704b2017-05-02 14:54:52 +08001133 .ops = &rk8xx_ldo_ops,
1134 .probe = rk8xx_ldo_probe,
Simon Glassadecfef2016-01-21 19:43:30 -07001135};
1136
Jacob Chen614704b2017-05-02 14:54:52 +08001137U_BOOT_DRIVER(rk8xx_switch) = {
1138 .name = "rk8xx_switch",
Simon Glassadecfef2016-01-21 19:43:30 -07001139 .id = UCLASS_REGULATOR,
Jacob Chen614704b2017-05-02 14:54:52 +08001140 .ops = &rk8xx_switch_ops,
1141 .probe = rk8xx_switch_probe,
Simon Glassadecfef2016-01-21 19:43:30 -07001142};
1143#endif
1144
Jacob Chen614704b2017-05-02 14:54:52 +08001145int rk8xx_spl_configure_buck(struct udevice *pmic, int buck, int uvolt)
Simon Glassadecfef2016-01-21 19:43:30 -07001146{
1147 int ret;
1148
1149 ret = _buck_set_value(pmic, buck, uvolt);
1150 if (ret)
1151 return ret;
1152
1153 return _buck_set_enable(pmic, buck, true);
1154}