SPDX: Convert all of our single license tags to Linux Kernel style
[oweals/u-boot.git] / drivers / power / pmic / pmic_max77686.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  Copyright (C) 2012 Samsung Electronics
4  *  Rajeshwari Shinde <rajeshwari.s@samsung.com>
5  */
6
7 #include <common.h>
8 #include <fdtdec.h>
9 #include <i2c.h>
10 #include <power/pmic.h>
11 #include <power/max77686_pmic.h>
12 #include <errno.h>
13
14 DECLARE_GLOBAL_DATA_PTR;
15
16 static const char max77686_buck_addr[] = {
17         0xff, 0x10, 0x12, 0x1c, 0x26, 0x30, 0x32, 0x34, 0x36, 0x38
18 };
19
20 static unsigned int max77686_ldo_volt2hex(int ldo, ulong uV)
21 {
22         unsigned int hex = 0;
23
24         switch (ldo) {
25         case 1:
26         case 2:
27         case 6:
28         case 7:
29         case 8:
30         case 15:
31                 hex = (uV - 800000) / 25000;
32                 break;
33         default:
34                 hex = (uV - 800000) / 50000;
35         }
36
37         if (hex >= 0 && hex <= MAX77686_LDO_VOLT_MAX_HEX)
38                 return hex;
39
40         debug("%s: %ld is wrong voltage value for LDO%d\n", __func__, uV, ldo);
41         return 0;
42 }
43
44 static int max77686_buck_volt2hex(int buck, ulong uV)
45 {
46         int hex = 0;
47
48         if (buck < 5 || buck > 9) {
49                 debug("%s: buck %d is not supported\n", __func__, buck);
50                 return -EINVAL;
51         }
52
53         hex = (uV - 750000) / 50000;
54
55         if (hex >= 0 && hex <= MAX77686_BUCK_VOLT_MAX_HEX)
56                 return hex;
57
58         debug("%s: %ld is wrong voltage value for BUCK%d\n",
59               __func__, uV, buck);
60         return -EINVAL;
61 }
62
63 int max77686_set_ldo_voltage(struct pmic *p, int ldo, ulong uV)
64 {
65         unsigned int val, ret, hex, adr;
66
67         if (ldo < 1 || ldo > 26) {
68                 printf("%s: %d is wrong ldo number\n", __func__, ldo);
69                 return -EINVAL;
70         }
71
72         adr = MAX77686_REG_PMIC_LDO1CTRL1 + ldo - 1;
73         hex = max77686_ldo_volt2hex(ldo, uV);
74
75         if (!hex)
76                 return -EINVAL;
77
78         ret = pmic_reg_read(p, adr, &val);
79         if (ret)
80                 return ret;
81
82         val &= ~MAX77686_LDO_VOLT_MASK;
83         val |= hex;
84         ret |= pmic_reg_write(p, adr, val);
85
86         return ret;
87 }
88
89 int max77686_set_buck_voltage(struct pmic *p, int buck, ulong uV)
90 {
91         unsigned int val, adr;
92         int hex, ret;
93
94         if (buck < 5 || buck > 9) {
95                 printf("%s: %d is an unsupported bucket number\n",
96                        __func__, buck);
97                 return -EINVAL;
98         }
99
100         adr = max77686_buck_addr[buck] + 1;
101         hex = max77686_buck_volt2hex(buck, uV);
102
103         if (hex < 0)
104                 return hex;
105
106         ret = pmic_reg_read(p, adr, &val);
107         if (ret)
108                 return ret;
109
110         val &= ~MAX77686_BUCK_VOLT_MASK;
111         ret |= pmic_reg_write(p, adr, val | hex);
112
113         return ret;
114 }
115
116 int max77686_set_ldo_mode(struct pmic *p, int ldo, char opmode)
117 {
118         unsigned int val, ret, adr, mode;
119
120         if (ldo < 1 || 26 < ldo) {
121                 printf("%s: %d is wrong ldo number\n", __func__, ldo);
122                 return -EINVAL;
123         }
124
125         adr = MAX77686_REG_PMIC_LDO1CTRL1 + ldo - 1;
126
127         /* mode */
128         switch (opmode) {
129         case OPMODE_OFF:
130                 mode = MAX77686_LDO_MODE_OFF;
131                 break;
132         case OPMODE_STANDBY:
133                 switch (ldo) {
134                 case 2:
135                 case 6:
136                 case 7:
137                 case 8:
138                 case 10:
139                 case 11:
140                 case 12:
141                 case 14:
142                 case 15:
143                 case 16:
144                         mode = MAX77686_LDO_MODE_STANDBY;
145                         break;
146                 default:
147                         mode = 0xff;
148                 }
149                 break;
150         case OPMODE_LPM:
151                 mode = MAX77686_LDO_MODE_LPM;
152                 break;
153         case OPMODE_ON:
154                 mode = MAX77686_LDO_MODE_ON;
155                 break;
156         default:
157                 mode = 0xff;
158         }
159
160         if (mode == 0xff) {
161                 printf("%s: %d is not supported on LDO%d\n",
162                        __func__, opmode, ldo);
163                 return -ENOTSUPP;
164         }
165
166         ret = pmic_reg_read(p, adr, &val);
167         if (ret)
168                 return ret;
169
170         val &= ~MAX77686_LDO_MODE_MASK;
171         val |= mode;
172         ret |= pmic_reg_write(p, adr, val);
173
174         return ret;
175 }
176
177 int max77686_set_buck_mode(struct pmic *p, int buck, char opmode)
178 {
179         unsigned int val, ret, mask, adr, size, mode, mode_shift;
180
181         size = ARRAY_SIZE(max77686_buck_addr);
182         if (buck >= size) {
183                 printf("%s: %d is wrong buck number\n", __func__, buck);
184                 return -EINVAL;
185         }
186
187         adr = max77686_buck_addr[buck];
188
189         /* mask */
190         switch (buck) {
191         case 2:
192         case 3:
193         case 4:
194                 mode_shift = MAX77686_BUCK_MODE_SHIFT_2;
195                 break;
196         default:
197                 mode_shift = MAX77686_BUCK_MODE_SHIFT_1;
198         }
199
200         mask = MAX77686_BUCK_MODE_MASK << mode_shift;
201
202         /* mode */
203         switch (opmode) {
204         case OPMODE_OFF:
205                 mode = MAX77686_BUCK_MODE_OFF << mode_shift;
206                 break;
207         case OPMODE_STANDBY:
208                 switch (buck) {
209                 case 1:
210                 case 2:
211                 case 3:
212                 case 4:
213                         mode = MAX77686_BUCK_MODE_STANDBY << mode_shift;
214                         break;
215                 default:
216                         mode = 0xff;
217                 }
218                 break;
219         case OPMODE_LPM:
220                 switch (buck) {
221                 case 2:
222                 case 3:
223                 case 4:
224                         mode = MAX77686_BUCK_MODE_LPM << mode_shift;
225                         break;
226                 default:
227                         mode = 0xff;
228                 }
229                 break;
230         case OPMODE_ON:
231                 mode = MAX77686_BUCK_MODE_ON << mode_shift;
232                 break;
233         default:
234                 mode = 0xff;
235         }
236
237         if (mode == 0xff) {
238                 printf("%s: %d is not supported on BUCK%d\n",
239                        __func__, opmode, buck);
240                 return -ENOTSUPP;
241         }
242
243         ret = pmic_reg_read(p, adr, &val);
244         if (ret)
245                 return ret;
246
247         val &= ~mask;
248         val |= mode;
249         ret |= pmic_reg_write(p, adr, val);
250
251         return ret;
252 }
253
254 int pmic_init(unsigned char bus)
255 {
256         static const char name[] = "MAX77686_PMIC";
257         struct pmic *p = pmic_alloc();
258 #if CONFIG_IS_ENABLED(OF_CONTROL)
259         const void *blob = gd->fdt_blob;
260         int node, parent, tmp;
261 #endif
262
263         if (!p) {
264                 printf("%s: POWER allocation error!\n", __func__);
265                 return -ENOMEM;
266         }
267
268 #if CONFIG_IS_ENABLED(OF_CONTROL)
269         node = fdtdec_next_compatible(blob, 0, COMPAT_MAXIM_MAX77686_PMIC);
270         if (node < 0) {
271                 debug("PMIC: No node for PMIC Chip in device tree\n");
272                 debug("node = %d\n", node);
273                 return -ENODEV;
274         }
275
276         parent = fdt_parent_offset(blob, node);
277         if (parent < 0) {
278                 debug("%s: Cannot find node parent\n", __func__);
279                 return -ENODEV;
280         }
281
282         /* tmp since p->bus is unsigned */
283         tmp = i2c_get_bus_num_fdt(parent);
284         if (tmp < 0) {
285                 debug("%s: Cannot find I2C bus\n", __func__);
286                 return -ENODEV;
287         }
288         p->bus = tmp;
289         p->hw.i2c.addr = fdtdec_get_int(blob, node, "reg", 9);
290 #else
291         p->bus = bus;
292         p->hw.i2c.addr = MAX77686_I2C_ADDR;
293 #endif
294
295         p->name = name;
296         p->interface = PMIC_I2C;
297         p->number_of_regs = MAX77686_NUM_OF_REGS;
298         p->hw.i2c.tx_num = 1;
299
300         puts("Board PMIC init\n");
301
302         return 0;
303 }