1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2f615e6a6SSimon Glass /*
3f615e6a6SSimon Glass * Copyright (C) 2015 Google, Inc
4f615e6a6SSimon Glass */
5f615e6a6SSimon Glass
6f615e6a6SSimon Glass #include <common.h>
7f615e6a6SSimon Glass #include <fdtdec.h>
8f615e6a6SSimon Glass #include <errno.h>
9f615e6a6SSimon Glass #include <dm.h>
10f615e6a6SSimon Glass #include <i2c.h>
11f615e6a6SSimon Glass #include <power/pmic.h>
12f615e6a6SSimon Glass #include <power/regulator.h>
13f615e6a6SSimon Glass #include <power/s5m8767.h>
14f615e6a6SSimon Glass
15f615e6a6SSimon Glass static const struct sec_voltage_desc buck_v1 = {
16f615e6a6SSimon Glass .max = 2225000,
17f615e6a6SSimon Glass .min = 650000,
18f615e6a6SSimon Glass .step = 6250,
19f615e6a6SSimon Glass };
20f615e6a6SSimon Glass
21f615e6a6SSimon Glass static const struct sec_voltage_desc buck_v2 = {
22f615e6a6SSimon Glass .max = 1600000,
23f615e6a6SSimon Glass .min = 600000,
24f615e6a6SSimon Glass .step = 6250,
25f615e6a6SSimon Glass };
26f615e6a6SSimon Glass
27f615e6a6SSimon Glass static const struct sec_voltage_desc buck_v3 = {
28f615e6a6SSimon Glass .max = 3000000,
29f615e6a6SSimon Glass .min = 750000,
30f615e6a6SSimon Glass .step = 12500,
31f615e6a6SSimon Glass };
32f615e6a6SSimon Glass
33f615e6a6SSimon Glass static const struct sec_voltage_desc ldo_v1 = {
34f615e6a6SSimon Glass .max = 3950000,
35f615e6a6SSimon Glass .min = 800000,
36f615e6a6SSimon Glass .step = 50000,
37f615e6a6SSimon Glass };
38f615e6a6SSimon Glass
39f615e6a6SSimon Glass static const struct sec_voltage_desc ldo_v2 = {
40f615e6a6SSimon Glass .max = 2375000,
41f615e6a6SSimon Glass .min = 800000,
42f615e6a6SSimon Glass .step = 25000,
43f615e6a6SSimon Glass };
44f615e6a6SSimon Glass
45f615e6a6SSimon Glass static const struct s5m8767_para buck_param[] = {
46f615e6a6SSimon Glass /*
47f615e6a6SSimon Glass * | voltage ----| | enable -| voltage
48f615e6a6SSimon Glass * regnum addr bpos mask addr on desc
49f615e6a6SSimon Glass */
50f615e6a6SSimon Glass {S5M8767_BUCK1, 0x33, 0x0, 0xff, 0x32, 0x3, &buck_v1},
51f615e6a6SSimon Glass {S5M8767_BUCK2, 0x35, 0x0, 0xff, 0x34, 0x1, &buck_v2},
52f615e6a6SSimon Glass {S5M8767_BUCK3, 0x3e, 0x0, 0xff, 0x3d, 0x1, &buck_v2},
53f615e6a6SSimon Glass {S5M8767_BUCK4, 0x47, 0x0, 0xff, 0x46, 0x1, &buck_v2},
54f615e6a6SSimon Glass {S5M8767_BUCK5, 0x50, 0x0, 0xff, 0x4f, 0x3, &buck_v1},
55f615e6a6SSimon Glass {S5M8767_BUCK6, 0x55, 0x0, 0xff, 0x54, 0x3, &buck_v1},
56f615e6a6SSimon Glass {S5M8767_BUCK7, 0x57, 0x0, 0xff, 0x56, 0x3, &buck_v3},
57f615e6a6SSimon Glass {S5M8767_BUCK8, 0x59, 0x0, 0xff, 0x58, 0x3, &buck_v3},
58f615e6a6SSimon Glass {S5M8767_BUCK9, 0x5b, 0x0, 0xff, 0x5a, 0x3, &buck_v3},
59f615e6a6SSimon Glass };
60f615e6a6SSimon Glass
61f615e6a6SSimon Glass static const struct s5m8767_para ldo_param[] = {
62f615e6a6SSimon Glass {S5M8767_LDO1, 0x5c, 0x0, 0x3f, 0x5c, 0x3, &ldo_v2},
63f615e6a6SSimon Glass {S5M8767_LDO2, 0x5d, 0x0, 0x3f, 0x5d, 0x1, &ldo_v2},
64f615e6a6SSimon Glass {S5M8767_LDO3, 0x61, 0x0, 0x3f, 0x61, 0x3, &ldo_v1},
65f615e6a6SSimon Glass {S5M8767_LDO4, 0x62, 0x0, 0x3f, 0x62, 0x3, &ldo_v1},
66f615e6a6SSimon Glass {S5M8767_LDO5, 0x63, 0x0, 0x3f, 0x63, 0x3, &ldo_v1},
67f615e6a6SSimon Glass {S5M8767_LDO6, 0x64, 0x0, 0x3f, 0x64, 0x1, &ldo_v2},
68f615e6a6SSimon Glass {S5M8767_LDO7, 0x65, 0x0, 0x3f, 0x65, 0x1, &ldo_v2},
69f615e6a6SSimon Glass {S5M8767_LDO8, 0x66, 0x0, 0x3f, 0x66, 0x1, &ldo_v2},
70f615e6a6SSimon Glass {S5M8767_LDO9, 0x67, 0x0, 0x3f, 0x67, 0x3, &ldo_v1},
71f615e6a6SSimon Glass {S5M8767_LDO10, 0x68, 0x0, 0x3f, 0x68, 0x1, &ldo_v1},
72f615e6a6SSimon Glass {S5M8767_LDO11, 0x69, 0x0, 0x3f, 0x69, 0x1, &ldo_v1},
73f615e6a6SSimon Glass {S5M8767_LDO12, 0x6a, 0x0, 0x3f, 0x6a, 0x1, &ldo_v1},
74f615e6a6SSimon Glass {S5M8767_LDO13, 0x6b, 0x0, 0x3f, 0x6b, 0x3, &ldo_v1},
75f615e6a6SSimon Glass {S5M8767_LDO14, 0x6c, 0x0, 0x3f, 0x6c, 0x1, &ldo_v1},
76f615e6a6SSimon Glass {S5M8767_LDO15, 0x6d, 0x0, 0x3f, 0x6d, 0x1, &ldo_v2},
77f615e6a6SSimon Glass {S5M8767_LDO16, 0x6e, 0x0, 0x3f, 0x6e, 0x1, &ldo_v1},
78f615e6a6SSimon Glass {S5M8767_LDO17, 0x6f, 0x0, 0x3f, 0x6f, 0x3, &ldo_v1},
79f615e6a6SSimon Glass {S5M8767_LDO18, 0x70, 0x0, 0x3f, 0x70, 0x3, &ldo_v1},
80f615e6a6SSimon Glass {S5M8767_LDO19, 0x71, 0x0, 0x3f, 0x71, 0x3, &ldo_v1},
81f615e6a6SSimon Glass {S5M8767_LDO20, 0x72, 0x0, 0x3f, 0x72, 0x3, &ldo_v1},
82f615e6a6SSimon Glass {S5M8767_LDO21, 0x73, 0x0, 0x3f, 0x73, 0x3, &ldo_v1},
83f615e6a6SSimon Glass {S5M8767_LDO22, 0x74, 0x0, 0x3f, 0x74, 0x3, &ldo_v1},
84f615e6a6SSimon Glass {S5M8767_LDO23, 0x75, 0x0, 0x3f, 0x75, 0x3, &ldo_v1},
85f615e6a6SSimon Glass {S5M8767_LDO24, 0x76, 0x0, 0x3f, 0x76, 0x3, &ldo_v1},
86f615e6a6SSimon Glass {S5M8767_LDO25, 0x77, 0x0, 0x3f, 0x77, 0x3, &ldo_v1},
87f615e6a6SSimon Glass {S5M8767_LDO26, 0x78, 0x0, 0x3f, 0x78, 0x3, &ldo_v1},
88f615e6a6SSimon Glass {S5M8767_LDO27, 0x79, 0x0, 0x3f, 0x79, 0x3, &ldo_v1},
89f615e6a6SSimon Glass {S5M8767_LDO28, 0x7a, 0x0, 0x3f, 0x7a, 0x3, &ldo_v1},
90f615e6a6SSimon Glass };
91f615e6a6SSimon Glass
92f615e6a6SSimon Glass enum {
93f615e6a6SSimon Glass ENABLE_SHIFT = 6,
94f615e6a6SSimon Glass ENABLE_MASK = 3,
95f615e6a6SSimon Glass };
96f615e6a6SSimon Glass
reg_get_value(struct udevice * dev,const struct s5m8767_para * param)97f615e6a6SSimon Glass static int reg_get_value(struct udevice *dev, const struct s5m8767_para *param)
98f615e6a6SSimon Glass {
99f615e6a6SSimon Glass const struct sec_voltage_desc *desc;
100f615e6a6SSimon Glass int ret, uv, val;
101f615e6a6SSimon Glass
102f615e6a6SSimon Glass ret = pmic_reg_read(dev->parent, param->vol_addr);
103f615e6a6SSimon Glass if (ret < 0)
104f615e6a6SSimon Glass return ret;
105f615e6a6SSimon Glass
106f615e6a6SSimon Glass desc = param->vol;
107f615e6a6SSimon Glass val = (ret >> param->vol_bitpos) & param->vol_bitmask;
108f615e6a6SSimon Glass uv = desc->min + val * desc->step;
109f615e6a6SSimon Glass
110f615e6a6SSimon Glass return uv;
111f615e6a6SSimon Glass }
112f615e6a6SSimon Glass
reg_set_value(struct udevice * dev,const struct s5m8767_para * param,int uv)113f615e6a6SSimon Glass static int reg_set_value(struct udevice *dev, const struct s5m8767_para *param,
114f615e6a6SSimon Glass int uv)
115f615e6a6SSimon Glass {
116f615e6a6SSimon Glass const struct sec_voltage_desc *desc;
117f615e6a6SSimon Glass int ret, val;
118f615e6a6SSimon Glass
119f615e6a6SSimon Glass desc = param->vol;
120f615e6a6SSimon Glass if (uv < desc->min || uv > desc->max)
121f615e6a6SSimon Glass return -EINVAL;
122f615e6a6SSimon Glass val = (uv - desc->min) / desc->step;
123f615e6a6SSimon Glass val = (val & param->vol_bitmask) << param->vol_bitpos;
124f615e6a6SSimon Glass ret = pmic_clrsetbits(dev->parent, param->vol_addr,
125f615e6a6SSimon Glass param->vol_bitmask << param->vol_bitpos,
126f615e6a6SSimon Glass val);
127f615e6a6SSimon Glass
128f615e6a6SSimon Glass return ret;
129f615e6a6SSimon Glass }
130f615e6a6SSimon Glass
s5m8767_ldo_probe(struct udevice * dev)131f615e6a6SSimon Glass static int s5m8767_ldo_probe(struct udevice *dev)
132f615e6a6SSimon Glass {
133f615e6a6SSimon Glass struct dm_regulator_uclass_platdata *uc_pdata;
134f615e6a6SSimon Glass
135f615e6a6SSimon Glass uc_pdata = dev_get_uclass_platdata(dev);
136f615e6a6SSimon Glass
137f615e6a6SSimon Glass uc_pdata->type = REGULATOR_TYPE_LDO;
138f615e6a6SSimon Glass uc_pdata->mode_count = 0;
139f615e6a6SSimon Glass
140f615e6a6SSimon Glass return 0;
141f615e6a6SSimon Glass }
ldo_get_value(struct udevice * dev)142f615e6a6SSimon Glass static int ldo_get_value(struct udevice *dev)
143f615e6a6SSimon Glass {
144f615e6a6SSimon Glass int ldo = dev->driver_data;
145f615e6a6SSimon Glass
146f615e6a6SSimon Glass return reg_get_value(dev, &ldo_param[ldo]);
147f615e6a6SSimon Glass }
148f615e6a6SSimon Glass
ldo_set_value(struct udevice * dev,int uv)149f615e6a6SSimon Glass static int ldo_set_value(struct udevice *dev, int uv)
150f615e6a6SSimon Glass {
151f615e6a6SSimon Glass int ldo = dev->driver_data;
152f615e6a6SSimon Glass
153f615e6a6SSimon Glass return reg_set_value(dev, &ldo_param[ldo], uv);
154f615e6a6SSimon Glass }
155f615e6a6SSimon Glass
reg_get_enable(struct udevice * dev,const struct s5m8767_para * param)156f615e6a6SSimon Glass static int reg_get_enable(struct udevice *dev, const struct s5m8767_para *param)
157f615e6a6SSimon Glass {
158f615e6a6SSimon Glass bool enable;
159f615e6a6SSimon Glass int ret;
160f615e6a6SSimon Glass
161f615e6a6SSimon Glass ret = pmic_reg_read(dev->parent, param->reg_enaddr);
162f615e6a6SSimon Glass if (ret < 0)
163f615e6a6SSimon Glass return ret;
164f615e6a6SSimon Glass
165f615e6a6SSimon Glass enable = (ret >> ENABLE_SHIFT) & ENABLE_MASK;
166f615e6a6SSimon Glass
167f615e6a6SSimon Glass return enable;
168f615e6a6SSimon Glass }
169f615e6a6SSimon Glass
reg_set_enable(struct udevice * dev,const struct s5m8767_para * param,bool enable)170f615e6a6SSimon Glass static int reg_set_enable(struct udevice *dev, const struct s5m8767_para *param,
171f615e6a6SSimon Glass bool enable)
172f615e6a6SSimon Glass {
173f615e6a6SSimon Glass int ret;
174f615e6a6SSimon Glass
175f615e6a6SSimon Glass ret = pmic_reg_read(dev->parent, param->reg_enaddr);
176f615e6a6SSimon Glass if (ret < 0)
177f615e6a6SSimon Glass return ret;
178f615e6a6SSimon Glass
179f615e6a6SSimon Glass ret = pmic_clrsetbits(dev->parent, param->reg_enaddr,
180f615e6a6SSimon Glass ENABLE_MASK << ENABLE_SHIFT,
181f615e6a6SSimon Glass enable ? param->reg_enbiton << ENABLE_SHIFT : 0);
182f615e6a6SSimon Glass
183f615e6a6SSimon Glass return ret;
184f615e6a6SSimon Glass }
185f615e6a6SSimon Glass
ldo_get_enable(struct udevice * dev)1864e98a140SKeerthy static int ldo_get_enable(struct udevice *dev)
187f615e6a6SSimon Glass {
188f615e6a6SSimon Glass int ldo = dev->driver_data;
189f615e6a6SSimon Glass
190f615e6a6SSimon Glass return reg_get_enable(dev, &ldo_param[ldo]);
191f615e6a6SSimon Glass }
192f615e6a6SSimon Glass
ldo_set_enable(struct udevice * dev,bool enable)193f615e6a6SSimon Glass static int ldo_set_enable(struct udevice *dev, bool enable)
194f615e6a6SSimon Glass {
195f615e6a6SSimon Glass int ldo = dev->driver_data;
196f615e6a6SSimon Glass
197f615e6a6SSimon Glass return reg_set_enable(dev, &ldo_param[ldo], enable);
198f615e6a6SSimon Glass }
199f615e6a6SSimon Glass
s5m8767_buck_probe(struct udevice * dev)200f615e6a6SSimon Glass static int s5m8767_buck_probe(struct udevice *dev)
201f615e6a6SSimon Glass {
202f615e6a6SSimon Glass struct dm_regulator_uclass_platdata *uc_pdata;
203f615e6a6SSimon Glass
204f615e6a6SSimon Glass uc_pdata = dev_get_uclass_platdata(dev);
205f615e6a6SSimon Glass
206f615e6a6SSimon Glass uc_pdata->type = REGULATOR_TYPE_BUCK;
207f615e6a6SSimon Glass uc_pdata->mode_count = 0;
208f615e6a6SSimon Glass
209f615e6a6SSimon Glass return 0;
210f615e6a6SSimon Glass }
211f615e6a6SSimon Glass
buck_get_value(struct udevice * dev)212f615e6a6SSimon Glass static int buck_get_value(struct udevice *dev)
213f615e6a6SSimon Glass {
214f615e6a6SSimon Glass int buck = dev->driver_data;
215f615e6a6SSimon Glass
216f615e6a6SSimon Glass return reg_get_value(dev, &buck_param[buck]);
217f615e6a6SSimon Glass }
218f615e6a6SSimon Glass
buck_set_value(struct udevice * dev,int uv)219f615e6a6SSimon Glass static int buck_set_value(struct udevice *dev, int uv)
220f615e6a6SSimon Glass {
221f615e6a6SSimon Glass int buck = dev->driver_data;
222f615e6a6SSimon Glass
223f615e6a6SSimon Glass return reg_set_value(dev, &buck_param[buck], uv);
224f615e6a6SSimon Glass }
225f615e6a6SSimon Glass
buck_get_enable(struct udevice * dev)2264e98a140SKeerthy static int buck_get_enable(struct udevice *dev)
227f615e6a6SSimon Glass {
228f615e6a6SSimon Glass int buck = dev->driver_data;
229f615e6a6SSimon Glass
230f615e6a6SSimon Glass return reg_get_enable(dev, &buck_param[buck]);
231f615e6a6SSimon Glass }
232f615e6a6SSimon Glass
buck_set_enable(struct udevice * dev,bool enable)233f615e6a6SSimon Glass static int buck_set_enable(struct udevice *dev, bool enable)
234f615e6a6SSimon Glass {
235f615e6a6SSimon Glass int buck = dev->driver_data;
236f615e6a6SSimon Glass
237f615e6a6SSimon Glass return reg_set_enable(dev, &buck_param[buck], enable);
238f615e6a6SSimon Glass }
239f615e6a6SSimon Glass
240f615e6a6SSimon Glass static const struct dm_regulator_ops s5m8767_ldo_ops = {
241f615e6a6SSimon Glass .get_value = ldo_get_value,
242f615e6a6SSimon Glass .set_value = ldo_set_value,
243f615e6a6SSimon Glass .get_enable = ldo_get_enable,
244f615e6a6SSimon Glass .set_enable = ldo_set_enable,
245f615e6a6SSimon Glass };
246f615e6a6SSimon Glass
247f615e6a6SSimon Glass U_BOOT_DRIVER(s5m8767_ldo) = {
248f615e6a6SSimon Glass .name = S5M8767_LDO_DRIVER,
249f615e6a6SSimon Glass .id = UCLASS_REGULATOR,
250f615e6a6SSimon Glass .ops = &s5m8767_ldo_ops,
251f615e6a6SSimon Glass .probe = s5m8767_ldo_probe,
252f615e6a6SSimon Glass };
253f615e6a6SSimon Glass
254f615e6a6SSimon Glass static const struct dm_regulator_ops s5m8767_buck_ops = {
255f615e6a6SSimon Glass .get_value = buck_get_value,
256f615e6a6SSimon Glass .set_value = buck_set_value,
257f615e6a6SSimon Glass .get_enable = buck_get_enable,
258f615e6a6SSimon Glass .set_enable = buck_set_enable,
259f615e6a6SSimon Glass };
260f615e6a6SSimon Glass
261f615e6a6SSimon Glass U_BOOT_DRIVER(s5m8767_buck) = {
262f615e6a6SSimon Glass .name = S5M8767_BUCK_DRIVER,
263f615e6a6SSimon Glass .id = UCLASS_REGULATOR,
264f615e6a6SSimon Glass .ops = &s5m8767_buck_ops,
265f615e6a6SSimon Glass .probe = s5m8767_buck_probe,
266f615e6a6SSimon Glass };
267