blob: 3a8261d1749f053afec82825a255349e64490c6c [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glassa8bd2ac2016-01-21 19:43:29 -07002/*
3 * Copyright (C) 2015 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glassa8bd2ac2016-01-21 19:43:29 -07005 */
6
Tom Riniabb9a042024-05-18 20:20:43 -06007#include <common.h>
Simon Glassa8bd2ac2016-01-21 19:43:29 -07008#include <dm.h>
Chris Morganb02712f2022-05-27 13:18:19 -05009#include <dm/lists.h>
Simon Glassa8bd2ac2016-01-21 19:43:29 -070010#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Quentin Schulzf7c6da12024-03-14 10:36:18 +010012#include <linux/bitfield.h>
Jacob Chen614704b2017-05-02 14:54:52 +080013#include <power/rk8xx_pmic.h>
Simon Glassa8bd2ac2016-01-21 19:43:29 -070014#include <power/pmic.h>
Quentin Schulzf7c6da12024-03-14 10:36:18 +010015#include <spi.h>
Chris Morganb02712f2022-05-27 13:18:19 -050016#include <sysreset.h>
17
18static int rk8xx_sysreset_request(struct udevice *dev, enum sysreset_t type)
19{
20 struct rk8xx_priv *priv = dev_get_priv(dev->parent);
21
22 if (type != SYSRESET_POWER_OFF)
23 return -EPROTONOSUPPORT;
24
25 switch (priv->variant) {
26 case RK805_ID:
27 case RK808_ID:
28 case RK816_ID:
29 case RK818_ID:
30 pmic_clrsetbits(dev->parent, REG_DEVCTRL, 0, BIT(0));
31 break;
32 case RK809_ID:
33 case RK817_ID:
34 pmic_clrsetbits(dev->parent, RK817_REG_SYS_CFG3, 0,
35 BIT(0));
36 break;
Quentin Schulzf7c6da12024-03-14 10:36:18 +010037 case RK806_ID:
38 pmic_clrsetbits(dev->parent, RK806_REG_SYS_CFG3, 0,
39 BIT(0));
40 break;
Chris Morganb02712f2022-05-27 13:18:19 -050041 default:
42 printf("Unknown PMIC RK%x: Cannot shutdown\n",
43 priv->variant);
44 return -EPROTONOSUPPORT;
45 };
46
47 return -EINPROGRESS;
48}
49
50static struct sysreset_ops rk8xx_sysreset_ops = {
51 .request = rk8xx_sysreset_request,
52};
53
54U_BOOT_DRIVER(rk8xx_sysreset) = {
55 .name = "rk8xx_sysreset",
56 .id = UCLASS_SYSRESET,
57 .ops = &rk8xx_sysreset_ops,
58};
Simon Glassa8bd2ac2016-01-21 19:43:29 -070059
Chris Morgan7c9de742022-05-27 13:18:20 -050060/* In the event of a plug-in and the appropriate option has been
61 * selected, we simply shutdown instead of continue the normal boot
62 * process. Please note the rk808 is not supported as it doesn't
63 * have the appropriate register.
64 */
65void rk8xx_off_for_plugin(struct udevice *dev)
66{
67 struct rk8xx_priv *priv = dev_get_priv(dev);
68
69 switch (priv->variant) {
70 case RK805_ID:
71 case RK816_ID:
72 case RK818_ID:
73 if (pmic_reg_read(dev, RK8XX_ON_SOURCE) & RK8XX_ON_PLUG_IN) {
74 printf("Power Off due to plug-in event\n");
75 pmic_clrsetbits(dev, REG_DEVCTRL, 0, BIT(0));
76 }
77 break;
78 case RK809_ID:
79 case RK817_ID:
80 if (pmic_reg_read(dev, RK817_ON_SOURCE) & RK8XX_ON_PLUG_IN) {
81 printf("Power Off due to plug-in event\n");
82 pmic_clrsetbits(dev, RK817_REG_SYS_CFG3, 0,
83 BIT(0));
84 }
85 break;
86 default:
87 printf("PMIC RK%x: Cannot read boot reason.\n",
88 priv->variant);
89 }
90}
91
Quentin Schulzf7c6da12024-03-14 10:36:18 +010092static struct reg_data rk806_init_reg[] = {
93 /* RST_FUN */
94 { RK806_REG_SYS_CFG3, GENMASK(7, 6), BIT(7)},
95};
96
Joseph Chen4a1ae182019-09-26 15:44:55 +080097static struct reg_data rk817_init_reg[] = {
98/* enable the under-voltage protection,
99 * the under-voltage protection will shutdown the LDO3 and reset the PMIC
100 */
101 { RK817_BUCK4_CMIN, 0x60, 0x60},
102};
103
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700104static const struct pmic_child_info pmic_children_info[] = {
Jacob Chen614704b2017-05-02 14:54:52 +0800105 { .prefix = "DCDC_REG", .driver = "rk8xx_buck"},
Quentin Schulzf7c6da12024-03-14 10:36:18 +0100106 { .prefix = "dcdc-reg", .driver = "rk8xx_buck"},
Jacob Chen614704b2017-05-02 14:54:52 +0800107 { .prefix = "LDO_REG", .driver = "rk8xx_ldo"},
Quentin Schulzf7c6da12024-03-14 10:36:18 +0100108 { .prefix = "nldo-reg", .driver = "rk8xx_nldo"},
109 { .prefix = "pldo-reg", .driver = "rk8xx_pldo"},
Jacob Chen614704b2017-05-02 14:54:52 +0800110 { .prefix = "SWITCH_REG", .driver = "rk8xx_switch"},
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700111 { },
112};
113
Jacob Chen614704b2017-05-02 14:54:52 +0800114static int rk8xx_reg_count(struct udevice *dev)
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700115{
116 return RK808_NUM_OF_REGS;
117}
118
Quentin Schulzf7c6da12024-03-14 10:36:18 +0100119#if CONFIG_IS_ENABLED(SPI) && CONFIG_IS_ENABLED(DM_SPI)
120struct rk806_cmd {
121 uint8_t len: 4; /* Payload size in bytes - 1 */
122 uint8_t reserved: 2;
123 uint8_t crc_en: 1;
124 uint8_t op: 1; /* READ=0; WRITE=1; */
125 uint8_t reg_l;
126#define REG_L_MASK GENMASK(7, 0)
127 uint8_t reg_h;
128#define REG_H_MASK GENMASK(15, 8)
129};
130#endif
131
Jacob Chen614704b2017-05-02 14:54:52 +0800132static int rk8xx_write(struct udevice *dev, uint reg, const uint8_t *buff,
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700133 int len)
134{
Simon Glass46ad8cb2016-01-21 19:43:58 -0700135 int ret;
136
Quentin Schulzf7c6da12024-03-14 10:36:18 +0100137#if CONFIG_IS_ENABLED(SPI) && CONFIG_IS_ENABLED(DM_SPI)
138 if (device_get_uclass_id(dev->parent) == UCLASS_SPI) {
139 struct spi_slave *spi = dev_get_parent_priv(dev);
140 struct rk806_cmd cmd = {
141 .op = 1,
142 .len = len - 1,
143 .reg_l = FIELD_GET(REG_L_MASK, reg),
144 .reg_h = FIELD_GET(REG_H_MASK, reg),
145 };
146
147 ret = dm_spi_claim_bus(dev);
148 if (ret) {
149 debug("Couldn't claim bus for device: %p!\n", dev);
150 return ret;
151 }
152
153 ret = spi_write_then_read(spi, (u8 *)&cmd, sizeof(cmd), buff, NULL, len);
154 if (ret)
155 debug("write error to device: %p register: %#x!\n",
156 dev, reg);
157
158 dm_spi_release_bus(dev);
159
160 return ret;
161 }
162#endif
163
Simon Glass46ad8cb2016-01-21 19:43:58 -0700164 ret = dm_i2c_write(dev, reg, buff, len);
165 if (ret) {
Simon Glass73126ac2018-11-18 08:14:28 -0700166 debug("write error to device: %p register: %#x!\n", dev, reg);
Simon Glass46ad8cb2016-01-21 19:43:58 -0700167 return ret;
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700168 }
169
170 return 0;
171}
172
Jacob Chen614704b2017-05-02 14:54:52 +0800173static int rk8xx_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700174{
Simon Glass46ad8cb2016-01-21 19:43:58 -0700175 int ret;
176
Quentin Schulzf7c6da12024-03-14 10:36:18 +0100177#if CONFIG_IS_ENABLED(SPI) && CONFIG_IS_ENABLED(DM_SPI)
178 if (device_get_uclass_id(dev->parent) == UCLASS_SPI) {
179 struct spi_slave *spi = dev_get_parent_priv(dev);
180 struct rk806_cmd cmd = {
181 .op = 0,
182 .len = len - 1,
183 .reg_l = FIELD_GET(REG_L_MASK, reg),
184 .reg_h = FIELD_GET(REG_H_MASK, reg),
185 };
186
187 ret = dm_spi_claim_bus(dev);
188 if (ret) {
189 debug("Couldn't claim bus for device: %p!\n", dev);
190 return ret;
191 }
192
193 ret = spi_write_then_read(spi, (u8 *)&cmd, sizeof(cmd), NULL, buff, len);
194 if (ret)
195 debug("read error to device: %p register: %#x!\n",
196 dev, reg);
197
198 dm_spi_release_bus(dev);
199
200 return ret;
201 }
202#endif
203
Simon Glass46ad8cb2016-01-21 19:43:58 -0700204 ret = dm_i2c_read(dev, reg, buff, len);
205 if (ret) {
Simon Glass73126ac2018-11-18 08:14:28 -0700206 debug("read error from device: %p register: %#x!\n", dev, reg);
Simon Glass46ad8cb2016-01-21 19:43:58 -0700207 return ret;
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700208 }
209
210 return 0;
211}
212
213#if CONFIG_IS_ENABLED(PMIC_CHILDREN)
Jacob Chen614704b2017-05-02 14:54:52 +0800214static int rk8xx_bind(struct udevice *dev)
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700215{
Simon Glass2c2d2c22017-05-18 20:09:32 -0600216 ofnode regulators_node;
Chris Morganb02712f2022-05-27 13:18:19 -0500217 int children, ret;
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700218
Simon Glass2c2d2c22017-05-18 20:09:32 -0600219 regulators_node = dev_read_subnode(dev, "regulators");
220 if (!ofnode_valid(regulators_node)) {
Simon Glass73126ac2018-11-18 08:14:28 -0700221 debug("%s: %s regulators subnode not found!\n", __func__,
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700222 dev->name);
223 return -ENXIO;
224 }
225
226 debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
227
Chris Morganb02712f2022-05-27 13:18:19 -0500228 if (CONFIG_IS_ENABLED(SYSRESET)) {
229 ret = device_bind_driver_to_node(dev, "rk8xx_sysreset",
230 "rk8xx_sysreset",
231 dev_ofnode(dev), NULL);
232 if (ret)
233 return ret;
234 }
235
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700236 children = pmic_bind_children(dev, regulators_node, pmic_children_info);
237 if (!children)
238 debug("%s: %s - no child found\n", __func__, dev->name);
239
Jonas Karlmanb9090662023-08-03 21:02:42 +0000240 if (IS_ENABLED(CONFIG_SPL_BUILD) &&
241 IS_ENABLED(CONFIG_ROCKCHIP_RK8XX_DISABLE_BOOT_ON_POWERON))
242 dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
243
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700244 /* Always return success for this device */
245 return 0;
246}
247#endif
248
Jacob Chen614704b2017-05-02 14:54:52 +0800249static int rk8xx_probe(struct udevice *dev)
Jacob Chen0234adb2017-05-02 14:54:49 +0800250{
Jacob Chen614704b2017-05-02 14:54:52 +0800251 struct rk8xx_priv *priv = dev_get_priv(dev);
Joseph Chen4a1ae182019-09-26 15:44:55 +0800252 struct reg_data *init_data = NULL;
253 int init_data_num = 0;
254 int ret = 0, i, show_variant;
255 u8 msb, lsb, id_msb, id_lsb;
256 u8 on_source = 0, off_source = 0;
257 u8 power_en0, power_en1, power_en2, power_en3;
258 u8 value;
Jacob Chen0234adb2017-05-02 14:54:49 +0800259
260 /* read Chip variant */
Joseph Chend6b3e832019-09-26 15:45:07 +0800261 if (device_is_compatible(dev, "rockchip,rk817") ||
262 device_is_compatible(dev, "rockchip,rk809")) {
Joseph Chen4a1ae182019-09-26 15:44:55 +0800263 id_msb = RK817_ID_MSB;
264 id_lsb = RK817_ID_LSB;
Quentin Schulzf7c6da12024-03-14 10:36:18 +0100265 } else if (device_is_compatible(dev, "rockchip,rk806")) {
266 id_msb = RK806_ID_MSB;
267 id_lsb = RK806_ID_LSB;
Joseph Chen4a1ae182019-09-26 15:44:55 +0800268 } else {
269 id_msb = ID_MSB;
270 id_lsb = ID_LSB;
271 }
272
273 ret = rk8xx_read(dev, id_msb, &msb, 1);
274 if (ret)
275 return ret;
276 ret = rk8xx_read(dev, id_lsb, &lsb, 1);
277 if (ret)
278 return ret;
Jacob Chen0234adb2017-05-02 14:54:49 +0800279
280 priv->variant = ((msb << 8) | lsb) & RK8XX_ID_MSK;
Joseph Chen4a1ae182019-09-26 15:44:55 +0800281 show_variant = priv->variant;
282 switch (priv->variant) {
283 case RK808_ID:
284 show_variant = 0x808; /* RK808 hardware ID is 0 */
285 break;
286 case RK805_ID:
287 case RK816_ID:
288 case RK818_ID:
289 on_source = RK8XX_ON_SOURCE;
290 off_source = RK8XX_OFF_SOURCE;
291 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800292 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800293 case RK817_ID:
294 on_source = RK817_ON_SOURCE;
295 off_source = RK817_OFF_SOURCE;
296 init_data = rk817_init_reg;
297 init_data_num = ARRAY_SIZE(rk817_init_reg);
298 power_en0 = pmic_reg_read(dev, RK817_POWER_EN0);
299 power_en1 = pmic_reg_read(dev, RK817_POWER_EN1);
300 power_en2 = pmic_reg_read(dev, RK817_POWER_EN2);
301 power_en3 = pmic_reg_read(dev, RK817_POWER_EN3);
302
303 value = (power_en0 & 0x0f) | ((power_en1 & 0x0f) << 4);
304 pmic_reg_write(dev, RK817_POWER_EN_SAVE0, value);
305 value = (power_en2 & 0x0f) | ((power_en3 & 0x0f) << 4);
306 pmic_reg_write(dev, RK817_POWER_EN_SAVE1, value);
307 break;
Quentin Schulzf7c6da12024-03-14 10:36:18 +0100308 case RK806_ID:
309 on_source = RK806_ON_SOURCE;
310 off_source = RK806_OFF_SOURCE;
311 init_data = rk806_init_reg;
312 init_data_num = ARRAY_SIZE(rk806_init_reg);
313 break;
Joseph Chen4a1ae182019-09-26 15:44:55 +0800314 default:
315 printf("Unknown PMIC: RK%x!!\n", priv->variant);
316 return -EINVAL;
317 }
318
319 for (i = 0; i < init_data_num; i++) {
320 ret = pmic_clrsetbits(dev,
321 init_data[i].reg,
322 init_data[i].mask,
323 init_data[i].val);
324 if (ret < 0) {
325 printf("%s: i2c set reg 0x%x failed, ret=%d\n",
326 __func__, init_data[i].reg, ret);
327 }
328
329 debug("%s: reg[0x%x] = 0x%x\n", __func__, init_data[i].reg,
330 pmic_reg_read(dev, init_data[i].reg));
331 }
332
Jonas Karlmanb9090662023-08-03 21:02:42 +0000333 if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
334 printf("PMIC: RK%x ", show_variant);
335 if (on_source && off_source)
336 printf("(on=0x%02x, off=0x%02x)",
337 pmic_reg_read(dev, on_source),
338 pmic_reg_read(dev, off_source));
339 printf("\n");
340 }
Joseph Chen4a1ae182019-09-26 15:44:55 +0800341
Jonas Karlmanb9090662023-08-03 21:02:42 +0000342 if (IS_ENABLED(CONFIG_ROCKCHIP_RK8XX_DISABLE_BOOT_ON_POWERON))
Chris Morgan7c9de742022-05-27 13:18:20 -0500343 rk8xx_off_for_plugin(dev);
Jacob Chen0234adb2017-05-02 14:54:49 +0800344
345 return 0;
346}
347
Jacob Chen614704b2017-05-02 14:54:52 +0800348static struct dm_pmic_ops rk8xx_ops = {
349 .reg_count = rk8xx_reg_count,
350 .read = rk8xx_read,
351 .write = rk8xx_write,
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700352};
353
Jacob Chen614704b2017-05-02 14:54:52 +0800354static const struct udevice_id rk8xx_ids[] = {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800355 { .compatible = "rockchip,rk805" },
Quentin Schulzf7c6da12024-03-14 10:36:18 +0100356 { .compatible = "rockchip,rk806" },
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700357 { .compatible = "rockchip,rk808" },
Joseph Chend6b3e832019-09-26 15:45:07 +0800358 { .compatible = "rockchip,rk809" },
Elaine Zhang04e5a432019-09-26 15:43:54 +0800359 { .compatible = "rockchip,rk816" },
Joseph Chen4a1ae182019-09-26 15:44:55 +0800360 { .compatible = "rockchip,rk817" },
Jacob Chen0234adb2017-05-02 14:54:49 +0800361 { .compatible = "rockchip,rk818" },
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700362 { }
363};
364
Walter Lozano2901ac62020-06-25 01:10:04 -0300365U_BOOT_DRIVER(rockchip_rk805) = {
366 .name = "rockchip_rk805",
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700367 .id = UCLASS_PMIC,
Jacob Chen614704b2017-05-02 14:54:52 +0800368 .of_match = rk8xx_ids,
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700369#if CONFIG_IS_ENABLED(PMIC_CHILDREN)
Jacob Chen614704b2017-05-02 14:54:52 +0800370 .bind = rk8xx_bind,
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700371#endif
Simon Glass8a2b47f2020-12-03 16:55:17 -0700372 .priv_auto = sizeof(struct rk8xx_priv),
Jacob Chen614704b2017-05-02 14:54:52 +0800373 .probe = rk8xx_probe,
374 .ops = &rk8xx_ops,
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700375};
Walter Lozano48e5b042020-06-25 01:10:06 -0300376
Simon Glassdf65db82020-12-28 20:34:57 -0700377DM_DRIVER_ALIAS(rockchip_rk805, rockchip_rk808)