]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
2a4febfd SG |
2 | /* |
3 | * Copyright (C) 2015 Google, Inc | |
4 | * Written by Simon Glass <[email protected]> | |
2a4febfd SG |
5 | */ |
6 | ||
7 | #include <common.h> | |
8 | #include <dm.h> | |
9 | #include <errno.h> | |
f7ae49fc | 10 | #include <log.h> |
453c5a92 | 11 | #include <power/rk8xx_pmic.h> |
2a4febfd SG |
12 | #include <power/pmic.h> |
13 | ||
b4a35574 JC |
14 | static struct reg_data rk817_init_reg[] = { |
15 | /* enable the under-voltage protection, | |
16 | * the under-voltage protection will shutdown the LDO3 and reset the PMIC | |
17 | */ | |
18 | { RK817_BUCK4_CMIN, 0x60, 0x60}, | |
19 | }; | |
20 | ||
2a4febfd | 21 | static const struct pmic_child_info pmic_children_info[] = { |
453c5a92 JC |
22 | { .prefix = "DCDC_REG", .driver = "rk8xx_buck"}, |
23 | { .prefix = "LDO_REG", .driver = "rk8xx_ldo"}, | |
24 | { .prefix = "SWITCH_REG", .driver = "rk8xx_switch"}, | |
2a4febfd SG |
25 | { }, |
26 | }; | |
27 | ||
453c5a92 | 28 | static int rk8xx_reg_count(struct udevice *dev) |
2a4febfd SG |
29 | { |
30 | return RK808_NUM_OF_REGS; | |
31 | } | |
32 | ||
453c5a92 | 33 | static int rk8xx_write(struct udevice *dev, uint reg, const uint8_t *buff, |
2a4febfd SG |
34 | int len) |
35 | { | |
7d577999 SG |
36 | int ret; |
37 | ||
38 | ret = dm_i2c_write(dev, reg, buff, len); | |
39 | if (ret) { | |
c83c436d | 40 | debug("write error to device: %p register: %#x!\n", dev, reg); |
7d577999 | 41 | return ret; |
2a4febfd SG |
42 | } |
43 | ||
44 | return 0; | |
45 | } | |
46 | ||
453c5a92 | 47 | static int rk8xx_read(struct udevice *dev, uint reg, uint8_t *buff, int len) |
2a4febfd | 48 | { |
7d577999 SG |
49 | int ret; |
50 | ||
51 | ret = dm_i2c_read(dev, reg, buff, len); | |
52 | if (ret) { | |
c83c436d | 53 | debug("read error from device: %p register: %#x!\n", dev, reg); |
7d577999 | 54 | return ret; |
2a4febfd SG |
55 | } |
56 | ||
57 | return 0; | |
58 | } | |
59 | ||
60 | #if CONFIG_IS_ENABLED(PMIC_CHILDREN) | |
453c5a92 | 61 | static int rk8xx_bind(struct udevice *dev) |
2a4febfd | 62 | { |
7a869e6c | 63 | ofnode regulators_node; |
2a4febfd SG |
64 | int children; |
65 | ||
7a869e6c SG |
66 | regulators_node = dev_read_subnode(dev, "regulators"); |
67 | if (!ofnode_valid(regulators_node)) { | |
c83c436d | 68 | debug("%s: %s regulators subnode not found!\n", __func__, |
2a4febfd SG |
69 | dev->name); |
70 | return -ENXIO; | |
71 | } | |
72 | ||
73 | debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); | |
74 | ||
75 | children = pmic_bind_children(dev, regulators_node, pmic_children_info); | |
76 | if (!children) | |
77 | debug("%s: %s - no child found\n", __func__, dev->name); | |
78 | ||
79 | /* Always return success for this device */ | |
80 | return 0; | |
81 | } | |
82 | #endif | |
83 | ||
453c5a92 | 84 | static int rk8xx_probe(struct udevice *dev) |
d77af8a8 | 85 | { |
453c5a92 | 86 | struct rk8xx_priv *priv = dev_get_priv(dev); |
b4a35574 JC |
87 | struct reg_data *init_data = NULL; |
88 | int init_data_num = 0; | |
89 | int ret = 0, i, show_variant; | |
90 | u8 msb, lsb, id_msb, id_lsb; | |
91 | u8 on_source = 0, off_source = 0; | |
92 | u8 power_en0, power_en1, power_en2, power_en3; | |
93 | u8 value; | |
d77af8a8 JC |
94 | |
95 | /* read Chip variant */ | |
ee30068f JC |
96 | if (device_is_compatible(dev, "rockchip,rk817") || |
97 | device_is_compatible(dev, "rockchip,rk809")) { | |
b4a35574 JC |
98 | id_msb = RK817_ID_MSB; |
99 | id_lsb = RK817_ID_LSB; | |
100 | } else { | |
101 | id_msb = ID_MSB; | |
102 | id_lsb = ID_LSB; | |
103 | } | |
104 | ||
105 | ret = rk8xx_read(dev, id_msb, &msb, 1); | |
106 | if (ret) | |
107 | return ret; | |
108 | ret = rk8xx_read(dev, id_lsb, &lsb, 1); | |
109 | if (ret) | |
110 | return ret; | |
d77af8a8 JC |
111 | |
112 | priv->variant = ((msb << 8) | lsb) & RK8XX_ID_MSK; | |
b4a35574 JC |
113 | show_variant = priv->variant; |
114 | switch (priv->variant) { | |
115 | case RK808_ID: | |
116 | show_variant = 0x808; /* RK808 hardware ID is 0 */ | |
117 | break; | |
118 | case RK805_ID: | |
119 | case RK816_ID: | |
120 | case RK818_ID: | |
121 | on_source = RK8XX_ON_SOURCE; | |
122 | off_source = RK8XX_OFF_SOURCE; | |
123 | break; | |
ee30068f | 124 | case RK809_ID: |
b4a35574 JC |
125 | case RK817_ID: |
126 | on_source = RK817_ON_SOURCE; | |
127 | off_source = RK817_OFF_SOURCE; | |
128 | init_data = rk817_init_reg; | |
129 | init_data_num = ARRAY_SIZE(rk817_init_reg); | |
130 | power_en0 = pmic_reg_read(dev, RK817_POWER_EN0); | |
131 | power_en1 = pmic_reg_read(dev, RK817_POWER_EN1); | |
132 | power_en2 = pmic_reg_read(dev, RK817_POWER_EN2); | |
133 | power_en3 = pmic_reg_read(dev, RK817_POWER_EN3); | |
134 | ||
135 | value = (power_en0 & 0x0f) | ((power_en1 & 0x0f) << 4); | |
136 | pmic_reg_write(dev, RK817_POWER_EN_SAVE0, value); | |
137 | value = (power_en2 & 0x0f) | ((power_en3 & 0x0f) << 4); | |
138 | pmic_reg_write(dev, RK817_POWER_EN_SAVE1, value); | |
139 | break; | |
140 | default: | |
141 | printf("Unknown PMIC: RK%x!!\n", priv->variant); | |
142 | return -EINVAL; | |
143 | } | |
144 | ||
145 | for (i = 0; i < init_data_num; i++) { | |
146 | ret = pmic_clrsetbits(dev, | |
147 | init_data[i].reg, | |
148 | init_data[i].mask, | |
149 | init_data[i].val); | |
150 | if (ret < 0) { | |
151 | printf("%s: i2c set reg 0x%x failed, ret=%d\n", | |
152 | __func__, init_data[i].reg, ret); | |
153 | } | |
154 | ||
155 | debug("%s: reg[0x%x] = 0x%x\n", __func__, init_data[i].reg, | |
156 | pmic_reg_read(dev, init_data[i].reg)); | |
157 | } | |
158 | ||
159 | printf("PMIC: RK%x ", show_variant); | |
160 | ||
161 | if (on_source && off_source) | |
162 | printf("(on=0x%02x, off=0x%02x)", | |
163 | pmic_reg_read(dev, on_source), | |
164 | pmic_reg_read(dev, off_source)); | |
165 | printf("\n"); | |
d77af8a8 JC |
166 | |
167 | return 0; | |
168 | } | |
169 | ||
453c5a92 JC |
170 | static struct dm_pmic_ops rk8xx_ops = { |
171 | .reg_count = rk8xx_reg_count, | |
172 | .read = rk8xx_read, | |
173 | .write = rk8xx_write, | |
2a4febfd SG |
174 | }; |
175 | ||
453c5a92 | 176 | static const struct udevice_id rk8xx_ids[] = { |
b6228074 | 177 | { .compatible = "rockchip,rk805" }, |
2a4febfd | 178 | { .compatible = "rockchip,rk808" }, |
ee30068f | 179 | { .compatible = "rockchip,rk809" }, |
addd062b | 180 | { .compatible = "rockchip,rk816" }, |
b4a35574 | 181 | { .compatible = "rockchip,rk817" }, |
d77af8a8 | 182 | { .compatible = "rockchip,rk818" }, |
2a4febfd SG |
183 | { } |
184 | }; | |
185 | ||
453c5a92 JC |
186 | U_BOOT_DRIVER(pmic_rk8xx) = { |
187 | .name = "rk8xx pmic", | |
2a4febfd | 188 | .id = UCLASS_PMIC, |
453c5a92 | 189 | .of_match = rk8xx_ids, |
2a4febfd | 190 | #if CONFIG_IS_ENABLED(PMIC_CHILDREN) |
453c5a92 | 191 | .bind = rk8xx_bind, |
2a4febfd | 192 | #endif |
7c1fb0a7 | 193 | .priv_auto_alloc_size = sizeof(struct rk8xx_priv), |
453c5a92 JC |
194 | .probe = rk8xx_probe, |
195 | .ops = &rk8xx_ops, | |
2a4febfd | 196 | }; |