blob: 12ff26a08558e7e2dc5bfb9bbc387ccd1dd8339b [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
Simon Glassa8bd2ac2016-01-21 19:43:29 -07007#include <dm.h>
Chris Morganb02712f2022-05-27 13:18:19 -05008#include <dm/lists.h>
Simon Glassa8bd2ac2016-01-21 19:43:29 -07009#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Quentin Schulzf7c6da12024-03-14 10:36:18 +010011#include <linux/bitfield.h>
Jacob Chen614704b2017-05-02 14:54:52 +080012#include <power/rk8xx_pmic.h>
Simon Glassa8bd2ac2016-01-21 19:43:29 -070013#include <power/pmic.h>
Quentin Schulzf7c6da12024-03-14 10:36:18 +010014#include <spi.h>
Chris Morganb02712f2022-05-27 13:18:19 -050015#include <sysreset.h>
16
17static int rk8xx_sysreset_request(struct udevice *dev, enum sysreset_t type)
18{
19 struct rk8xx_priv *priv = dev_get_priv(dev->parent);
20
21 if (type != SYSRESET_POWER_OFF)
22 return -EPROTONOSUPPORT;
23
24 switch (priv->variant) {
25 case RK805_ID:
26 case RK808_ID:
27 case RK816_ID:
28 case RK818_ID:
29 pmic_clrsetbits(dev->parent, REG_DEVCTRL, 0, BIT(0));
30 break;
31 case RK809_ID:
32 case RK817_ID:
33 pmic_clrsetbits(dev->parent, RK817_REG_SYS_CFG3, 0,
34 BIT(0));
35 break;
Quentin Schulzf7c6da12024-03-14 10:36:18 +010036 case RK806_ID:
37 pmic_clrsetbits(dev->parent, RK806_REG_SYS_CFG3, 0,
38 BIT(0));
39 break;
Chris Morganb02712f2022-05-27 13:18:19 -050040 default:
41 printf("Unknown PMIC RK%x: Cannot shutdown\n",
42 priv->variant);
43 return -EPROTONOSUPPORT;
44 };
45
46 return -EINPROGRESS;
47}
48
49static struct sysreset_ops rk8xx_sysreset_ops = {
50 .request = rk8xx_sysreset_request,
51};
52
53U_BOOT_DRIVER(rk8xx_sysreset) = {
54 .name = "rk8xx_sysreset",
55 .id = UCLASS_SYSRESET,
56 .ops = &rk8xx_sysreset_ops,
57};
Simon Glassa8bd2ac2016-01-21 19:43:29 -070058
Chris Morgan7c9de742022-05-27 13:18:20 -050059/* In the event of a plug-in and the appropriate option has been
60 * selected, we simply shutdown instead of continue the normal boot
61 * process. Please note the rk808 is not supported as it doesn't
62 * have the appropriate register.
63 */
64void rk8xx_off_for_plugin(struct udevice *dev)
65{
66 struct rk8xx_priv *priv = dev_get_priv(dev);
67
68 switch (priv->variant) {
69 case RK805_ID:
70 case RK816_ID:
71 case RK818_ID:
72 if (pmic_reg_read(dev, RK8XX_ON_SOURCE) & RK8XX_ON_PLUG_IN) {
73 printf("Power Off due to plug-in event\n");
74 pmic_clrsetbits(dev, REG_DEVCTRL, 0, BIT(0));
75 }
76 break;
77 case RK809_ID:
78 case RK817_ID:
79 if (pmic_reg_read(dev, RK817_ON_SOURCE) & RK8XX_ON_PLUG_IN) {
80 printf("Power Off due to plug-in event\n");
81 pmic_clrsetbits(dev, RK817_REG_SYS_CFG3, 0,
82 BIT(0));
83 }
84 break;
85 default:
86 printf("PMIC RK%x: Cannot read boot reason.\n",
87 priv->variant);
88 }
89}
90
Quentin Schulzf7c6da12024-03-14 10:36:18 +010091static struct reg_data rk806_init_reg[] = {
92 /* RST_FUN */
93 { RK806_REG_SYS_CFG3, GENMASK(7, 6), BIT(7)},
94};
95
Joseph Chen4a1ae182019-09-26 15:44:55 +080096static struct reg_data rk817_init_reg[] = {
97/* enable the under-voltage protection,
98 * the under-voltage protection will shutdown the LDO3 and reset the PMIC
99 */
100 { RK817_BUCK4_CMIN, 0x60, 0x60},
101};
102
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700103static const struct pmic_child_info pmic_children_info[] = {
Jacob Chen614704b2017-05-02 14:54:52 +0800104 { .prefix = "DCDC_REG", .driver = "rk8xx_buck"},
Quentin Schulzf7c6da12024-03-14 10:36:18 +0100105 { .prefix = "dcdc-reg", .driver = "rk8xx_buck"},
Jacob Chen614704b2017-05-02 14:54:52 +0800106 { .prefix = "LDO_REG", .driver = "rk8xx_ldo"},
Quentin Schulzf7c6da12024-03-14 10:36:18 +0100107 { .prefix = "nldo-reg", .driver = "rk8xx_nldo"},
108 { .prefix = "pldo-reg", .driver = "rk8xx_pldo"},
Jacob Chen614704b2017-05-02 14:54:52 +0800109 { .prefix = "SWITCH_REG", .driver = "rk8xx_switch"},
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700110 { },
111};
112
Jacob Chen614704b2017-05-02 14:54:52 +0800113static int rk8xx_reg_count(struct udevice *dev)
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700114{
115 return RK808_NUM_OF_REGS;
116}
117
Quentin Schulzf7c6da12024-03-14 10:36:18 +0100118#if CONFIG_IS_ENABLED(SPI) && CONFIG_IS_ENABLED(DM_SPI)
119struct rk806_cmd {
120 uint8_t len: 4; /* Payload size in bytes - 1 */
121 uint8_t reserved: 2;
122 uint8_t crc_en: 1;
123 uint8_t op: 1; /* READ=0; WRITE=1; */
124 uint8_t reg_l;
125#define REG_L_MASK GENMASK(7, 0)
126 uint8_t reg_h;
127#define REG_H_MASK GENMASK(15, 8)
128};
129#endif
130
Jacob Chen614704b2017-05-02 14:54:52 +0800131static int rk8xx_write(struct udevice *dev, uint reg, const uint8_t *buff,
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700132 int len)
133{
Simon Glass46ad8cb2016-01-21 19:43:58 -0700134 int ret;
135
Quentin Schulzf7c6da12024-03-14 10:36:18 +0100136#if CONFIG_IS_ENABLED(SPI) && CONFIG_IS_ENABLED(DM_SPI)
137 if (device_get_uclass_id(dev->parent) == UCLASS_SPI) {
138 struct spi_slave *spi = dev_get_parent_priv(dev);
139 struct rk806_cmd cmd = {
140 .op = 1,
141 .len = len - 1,
142 .reg_l = FIELD_GET(REG_L_MASK, reg),
143 .reg_h = FIELD_GET(REG_H_MASK, reg),
144 };
145
146 ret = dm_spi_claim_bus(dev);
147 if (ret) {
148 debug("Couldn't claim bus for device: %p!\n", dev);
149 return ret;
150 }
151
152 ret = spi_write_then_read(spi, (u8 *)&cmd, sizeof(cmd), buff, NULL, len);
153 if (ret)
154 debug("write error to device: %p register: %#x!\n",
155 dev, reg);
156
157 dm_spi_release_bus(dev);
158
159 return ret;
160 }
161#endif
162
Simon Glass46ad8cb2016-01-21 19:43:58 -0700163 ret = dm_i2c_write(dev, reg, buff, len);
164 if (ret) {
Simon Glass73126ac2018-11-18 08:14:28 -0700165 debug("write error to device: %p register: %#x!\n", dev, reg);
Simon Glass46ad8cb2016-01-21 19:43:58 -0700166 return ret;
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700167 }
168
169 return 0;
170}
171
Jacob Chen614704b2017-05-02 14:54:52 +0800172static int rk8xx_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700173{
Simon Glass46ad8cb2016-01-21 19:43:58 -0700174 int ret;
175
Quentin Schulzf7c6da12024-03-14 10:36:18 +0100176#if CONFIG_IS_ENABLED(SPI) && CONFIG_IS_ENABLED(DM_SPI)
177 if (device_get_uclass_id(dev->parent) == UCLASS_SPI) {
178 struct spi_slave *spi = dev_get_parent_priv(dev);
179 struct rk806_cmd cmd = {
180 .op = 0,
181 .len = len - 1,
182 .reg_l = FIELD_GET(REG_L_MASK, reg),
183 .reg_h = FIELD_GET(REG_H_MASK, reg),
184 };
185
186 ret = dm_spi_claim_bus(dev);
187 if (ret) {
188 debug("Couldn't claim bus for device: %p!\n", dev);
189 return ret;
190 }
191
192 ret = spi_write_then_read(spi, (u8 *)&cmd, sizeof(cmd), NULL, buff, len);
193 if (ret)
194 debug("read error to device: %p register: %#x!\n",
195 dev, reg);
196
197 dm_spi_release_bus(dev);
198
199 return ret;
200 }
201#endif
202
Simon Glass46ad8cb2016-01-21 19:43:58 -0700203 ret = dm_i2c_read(dev, reg, buff, len);
204 if (ret) {
Simon Glass73126ac2018-11-18 08:14:28 -0700205 debug("read error from device: %p register: %#x!\n", dev, reg);
Simon Glass46ad8cb2016-01-21 19:43:58 -0700206 return ret;
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700207 }
208
209 return 0;
210}
211
212#if CONFIG_IS_ENABLED(PMIC_CHILDREN)
Jacob Chen614704b2017-05-02 14:54:52 +0800213static int rk8xx_bind(struct udevice *dev)
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700214{
Simon Glass2c2d2c22017-05-18 20:09:32 -0600215 ofnode regulators_node;
Chris Morganb02712f2022-05-27 13:18:19 -0500216 int children, ret;
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700217
Simon Glass2c2d2c22017-05-18 20:09:32 -0600218 regulators_node = dev_read_subnode(dev, "regulators");
219 if (!ofnode_valid(regulators_node)) {
Simon Glass73126ac2018-11-18 08:14:28 -0700220 debug("%s: %s regulators subnode not found!\n", __func__,
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700221 dev->name);
222 return -ENXIO;
223 }
224
225 debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
226
Chris Morganb02712f2022-05-27 13:18:19 -0500227 if (CONFIG_IS_ENABLED(SYSRESET)) {
228 ret = device_bind_driver_to_node(dev, "rk8xx_sysreset",
229 "rk8xx_sysreset",
230 dev_ofnode(dev), NULL);
231 if (ret)
232 return ret;
233 }
234
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700235 children = pmic_bind_children(dev, regulators_node, pmic_children_info);
236 if (!children)
237 debug("%s: %s - no child found\n", __func__, dev->name);
238
Jonas Karlmanb9090662023-08-03 21:02:42 +0000239 if (IS_ENABLED(CONFIG_SPL_BUILD) &&
240 IS_ENABLED(CONFIG_ROCKCHIP_RK8XX_DISABLE_BOOT_ON_POWERON))
241 dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
242
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700243 /* Always return success for this device */
244 return 0;
245}
246#endif
247
Jacob Chen614704b2017-05-02 14:54:52 +0800248static int rk8xx_probe(struct udevice *dev)
Jacob Chen0234adb2017-05-02 14:54:49 +0800249{
Jacob Chen614704b2017-05-02 14:54:52 +0800250 struct rk8xx_priv *priv = dev_get_priv(dev);
Joseph Chen4a1ae182019-09-26 15:44:55 +0800251 struct reg_data *init_data = NULL;
252 int init_data_num = 0;
253 int ret = 0, i, show_variant;
254 u8 msb, lsb, id_msb, id_lsb;
255 u8 on_source = 0, off_source = 0;
256 u8 power_en0, power_en1, power_en2, power_en3;
257 u8 value;
Jacob Chen0234adb2017-05-02 14:54:49 +0800258
259 /* read Chip variant */
Joseph Chend6b3e832019-09-26 15:45:07 +0800260 if (device_is_compatible(dev, "rockchip,rk817") ||
261 device_is_compatible(dev, "rockchip,rk809")) {
Joseph Chen4a1ae182019-09-26 15:44:55 +0800262 id_msb = RK817_ID_MSB;
263 id_lsb = RK817_ID_LSB;
Quentin Schulzf7c6da12024-03-14 10:36:18 +0100264 } else if (device_is_compatible(dev, "rockchip,rk806")) {
265 id_msb = RK806_ID_MSB;
266 id_lsb = RK806_ID_LSB;
Joseph Chen4a1ae182019-09-26 15:44:55 +0800267 } else {
268 id_msb = ID_MSB;
269 id_lsb = ID_LSB;
270 }
271
272 ret = rk8xx_read(dev, id_msb, &msb, 1);
273 if (ret)
274 return ret;
275 ret = rk8xx_read(dev, id_lsb, &lsb, 1);
276 if (ret)
277 return ret;
Jacob Chen0234adb2017-05-02 14:54:49 +0800278
279 priv->variant = ((msb << 8) | lsb) & RK8XX_ID_MSK;
Joseph Chen4a1ae182019-09-26 15:44:55 +0800280 show_variant = priv->variant;
281 switch (priv->variant) {
282 case RK808_ID:
283 show_variant = 0x808; /* RK808 hardware ID is 0 */
284 break;
285 case RK805_ID:
286 case RK816_ID:
287 case RK818_ID:
288 on_source = RK8XX_ON_SOURCE;
289 off_source = RK8XX_OFF_SOURCE;
290 break;
Joseph Chend6b3e832019-09-26 15:45:07 +0800291 case RK809_ID:
Joseph Chen4a1ae182019-09-26 15:44:55 +0800292 case RK817_ID:
293 on_source = RK817_ON_SOURCE;
294 off_source = RK817_OFF_SOURCE;
295 init_data = rk817_init_reg;
296 init_data_num = ARRAY_SIZE(rk817_init_reg);
297 power_en0 = pmic_reg_read(dev, RK817_POWER_EN0);
298 power_en1 = pmic_reg_read(dev, RK817_POWER_EN1);
299 power_en2 = pmic_reg_read(dev, RK817_POWER_EN2);
300 power_en3 = pmic_reg_read(dev, RK817_POWER_EN3);
301
302 value = (power_en0 & 0x0f) | ((power_en1 & 0x0f) << 4);
303 pmic_reg_write(dev, RK817_POWER_EN_SAVE0, value);
304 value = (power_en2 & 0x0f) | ((power_en3 & 0x0f) << 4);
305 pmic_reg_write(dev, RK817_POWER_EN_SAVE1, value);
306 break;
Quentin Schulzf7c6da12024-03-14 10:36:18 +0100307 case RK806_ID:
308 on_source = RK806_ON_SOURCE;
309 off_source = RK806_OFF_SOURCE;
310 init_data = rk806_init_reg;
311 init_data_num = ARRAY_SIZE(rk806_init_reg);
312 break;
Joseph Chen4a1ae182019-09-26 15:44:55 +0800313 default:
314 printf("Unknown PMIC: RK%x!!\n", priv->variant);
315 return -EINVAL;
316 }
317
318 for (i = 0; i < init_data_num; i++) {
319 ret = pmic_clrsetbits(dev,
320 init_data[i].reg,
321 init_data[i].mask,
322 init_data[i].val);
323 if (ret < 0) {
324 printf("%s: i2c set reg 0x%x failed, ret=%d\n",
325 __func__, init_data[i].reg, ret);
326 }
327
328 debug("%s: reg[0x%x] = 0x%x\n", __func__, init_data[i].reg,
329 pmic_reg_read(dev, init_data[i].reg));
330 }
331
Jonas Karlmanb9090662023-08-03 21:02:42 +0000332 if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
333 printf("PMIC: RK%x ", show_variant);
334 if (on_source && off_source)
335 printf("(on=0x%02x, off=0x%02x)",
336 pmic_reg_read(dev, on_source),
337 pmic_reg_read(dev, off_source));
338 printf("\n");
339 }
Joseph Chen4a1ae182019-09-26 15:44:55 +0800340
Jonas Karlmanb9090662023-08-03 21:02:42 +0000341 if (IS_ENABLED(CONFIG_ROCKCHIP_RK8XX_DISABLE_BOOT_ON_POWERON))
Chris Morgan7c9de742022-05-27 13:18:20 -0500342 rk8xx_off_for_plugin(dev);
Jacob Chen0234adb2017-05-02 14:54:49 +0800343
344 return 0;
345}
346
Jacob Chen614704b2017-05-02 14:54:52 +0800347static struct dm_pmic_ops rk8xx_ops = {
348 .reg_count = rk8xx_reg_count,
349 .read = rk8xx_read,
350 .write = rk8xx_write,
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700351};
352
Jacob Chen614704b2017-05-02 14:54:52 +0800353static const struct udevice_id rk8xx_ids[] = {
Elaine Zhang1d9077e2019-09-26 15:43:55 +0800354 { .compatible = "rockchip,rk805" },
Quentin Schulzf7c6da12024-03-14 10:36:18 +0100355 { .compatible = "rockchip,rk806" },
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700356 { .compatible = "rockchip,rk808" },
Joseph Chend6b3e832019-09-26 15:45:07 +0800357 { .compatible = "rockchip,rk809" },
Elaine Zhang04e5a432019-09-26 15:43:54 +0800358 { .compatible = "rockchip,rk816" },
Joseph Chen4a1ae182019-09-26 15:44:55 +0800359 { .compatible = "rockchip,rk817" },
Jacob Chen0234adb2017-05-02 14:54:49 +0800360 { .compatible = "rockchip,rk818" },
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700361 { }
362};
363
Walter Lozano2901ac62020-06-25 01:10:04 -0300364U_BOOT_DRIVER(rockchip_rk805) = {
365 .name = "rockchip_rk805",
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700366 .id = UCLASS_PMIC,
Jacob Chen614704b2017-05-02 14:54:52 +0800367 .of_match = rk8xx_ids,
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700368#if CONFIG_IS_ENABLED(PMIC_CHILDREN)
Jacob Chen614704b2017-05-02 14:54:52 +0800369 .bind = rk8xx_bind,
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700370#endif
Simon Glass8a2b47f2020-12-03 16:55:17 -0700371 .priv_auto = sizeof(struct rk8xx_priv),
Jacob Chen614704b2017-05-02 14:54:52 +0800372 .probe = rk8xx_probe,
373 .ops = &rk8xx_ops,
Simon Glassa8bd2ac2016-01-21 19:43:29 -0700374};
Walter Lozano48e5b042020-06-25 01:10:06 -0300375
Simon Glassdf65db82020-12-28 20:34:57 -0700376DM_DRIVER_ALIAS(rockchip_rk805, rockchip_rk808)