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