1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // MP8867/MP8869 regulator driver |
4 | // |
5 | // Copyright (C) 2020 Synaptics Incorporated |
6 | // |
7 | // Author: Jisheng Zhang <jszhang@kernel.org> |
8 | |
9 | #include <linux/gpio/consumer.h> |
10 | #include <linux/i2c.h> |
11 | #include <linux/module.h> |
12 | #include <linux/of.h> |
13 | #include <linux/regmap.h> |
14 | #include <linux/regulator/driver.h> |
15 | #include <linux/regulator/of_regulator.h> |
16 | |
17 | #define MP886X_VSEL 0x00 |
18 | #define MP886X_V_BOOT (1 << 7) |
19 | #define MP886X_SYSCNTLREG1 0x01 |
20 | #define MP886X_MODE (1 << 0) |
21 | #define MP886X_SLEW_SHIFT 3 |
22 | #define MP886X_SLEW_MASK (0x7 << MP886X_SLEW_SHIFT) |
23 | #define MP886X_GO (1 << 6) |
24 | #define MP886X_EN (1 << 7) |
25 | #define MP8869_SYSCNTLREG2 0x02 |
26 | |
27 | struct mp886x_cfg_info { |
28 | const struct regulator_ops *rops; |
29 | const unsigned int slew_rates[8]; |
30 | const int switch_freq[4]; |
31 | const u8 fs_reg; |
32 | const u8 fs_shift; |
33 | }; |
34 | |
35 | struct mp886x_device_info { |
36 | struct device *dev; |
37 | struct regulator_desc desc; |
38 | struct regulator_init_data *regulator; |
39 | struct gpio_desc *en_gpio; |
40 | const struct mp886x_cfg_info *ci; |
41 | u32 r[2]; |
42 | unsigned int sel; |
43 | }; |
44 | |
45 | static void mp886x_set_switch_freq(struct mp886x_device_info *di, |
46 | struct regmap *regmap, |
47 | u32 freq) |
48 | { |
49 | const struct mp886x_cfg_info *ci = di->ci; |
50 | int i; |
51 | |
52 | for (i = 0; i < ARRAY_SIZE(ci->switch_freq); i++) { |
53 | if (freq == ci->switch_freq[i]) { |
54 | regmap_update_bits(map: regmap, reg: ci->fs_reg, |
55 | mask: 0x3 << ci->fs_shift, val: i << ci->fs_shift); |
56 | return; |
57 | } |
58 | } |
59 | |
60 | dev_err(di->dev, "invalid frequency %d\n" , freq); |
61 | } |
62 | |
63 | static int mp886x_set_mode(struct regulator_dev *rdev, unsigned int mode) |
64 | { |
65 | switch (mode) { |
66 | case REGULATOR_MODE_FAST: |
67 | regmap_update_bits(map: rdev->regmap, MP886X_SYSCNTLREG1, |
68 | MP886X_MODE, MP886X_MODE); |
69 | break; |
70 | case REGULATOR_MODE_NORMAL: |
71 | regmap_update_bits(map: rdev->regmap, MP886X_SYSCNTLREG1, |
72 | MP886X_MODE, val: 0); |
73 | break; |
74 | default: |
75 | return -EINVAL; |
76 | } |
77 | return 0; |
78 | } |
79 | |
80 | static unsigned int mp886x_get_mode(struct regulator_dev *rdev) |
81 | { |
82 | u32 val; |
83 | int ret; |
84 | |
85 | ret = regmap_read(map: rdev->regmap, MP886X_SYSCNTLREG1, val: &val); |
86 | if (ret < 0) |
87 | return ret; |
88 | if (val & MP886X_MODE) |
89 | return REGULATOR_MODE_FAST; |
90 | else |
91 | return REGULATOR_MODE_NORMAL; |
92 | } |
93 | |
94 | static int mp8869_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel) |
95 | { |
96 | int ret; |
97 | |
98 | ret = regmap_update_bits(map: rdev->regmap, MP886X_SYSCNTLREG1, |
99 | MP886X_GO, MP886X_GO); |
100 | if (ret < 0) |
101 | return ret; |
102 | |
103 | sel <<= ffs(rdev->desc->vsel_mask) - 1; |
104 | return regmap_update_bits(map: rdev->regmap, reg: rdev->desc->vsel_reg, |
105 | MP886X_V_BOOT | rdev->desc->vsel_mask, val: sel); |
106 | } |
107 | |
108 | static inline unsigned int mp8869_scale(unsigned int uv, u32 r1, u32 r2) |
109 | { |
110 | u32 tmp = uv * r1 / r2; |
111 | |
112 | return uv + tmp; |
113 | } |
114 | |
115 | static int mp8869_get_voltage_sel(struct regulator_dev *rdev) |
116 | { |
117 | struct mp886x_device_info *di = rdev_get_drvdata(rdev); |
118 | int ret, uv; |
119 | unsigned int val; |
120 | bool fbloop; |
121 | |
122 | ret = regmap_read(map: rdev->regmap, reg: rdev->desc->vsel_reg, val: &val); |
123 | if (ret) |
124 | return ret; |
125 | |
126 | fbloop = val & MP886X_V_BOOT; |
127 | if (fbloop) { |
128 | uv = rdev->desc->min_uV; |
129 | uv = mp8869_scale(uv, r1: di->r[0], r2: di->r[1]); |
130 | return regulator_map_voltage_linear(rdev, min_uV: uv, max_uV: uv); |
131 | } |
132 | |
133 | val &= rdev->desc->vsel_mask; |
134 | val >>= ffs(rdev->desc->vsel_mask) - 1; |
135 | |
136 | return val; |
137 | } |
138 | |
139 | static const struct regulator_ops mp8869_regulator_ops = { |
140 | .set_voltage_sel = mp8869_set_voltage_sel, |
141 | .get_voltage_sel = mp8869_get_voltage_sel, |
142 | .set_voltage_time_sel = regulator_set_voltage_time_sel, |
143 | .map_voltage = regulator_map_voltage_linear, |
144 | .list_voltage = regulator_list_voltage_linear, |
145 | .enable = regulator_enable_regmap, |
146 | .disable = regulator_disable_regmap, |
147 | .is_enabled = regulator_is_enabled_regmap, |
148 | .set_mode = mp886x_set_mode, |
149 | .get_mode = mp886x_get_mode, |
150 | .set_ramp_delay = regulator_set_ramp_delay_regmap, |
151 | }; |
152 | |
153 | static const struct mp886x_cfg_info mp8869_ci = { |
154 | .rops = &mp8869_regulator_ops, |
155 | .slew_rates = { |
156 | 40000, |
157 | 30000, |
158 | 20000, |
159 | 10000, |
160 | 5000, |
161 | 2500, |
162 | 1250, |
163 | 625, |
164 | }, |
165 | .switch_freq = { |
166 | 500000, |
167 | 750000, |
168 | 1000000, |
169 | 1250000, |
170 | }, |
171 | .fs_reg = MP8869_SYSCNTLREG2, |
172 | .fs_shift = 4, |
173 | }; |
174 | |
175 | static int mp8867_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel) |
176 | { |
177 | struct mp886x_device_info *di = rdev_get_drvdata(rdev); |
178 | int ret, delta; |
179 | |
180 | ret = mp8869_set_voltage_sel(rdev, sel); |
181 | if (ret < 0) |
182 | return ret; |
183 | |
184 | delta = di->sel - sel; |
185 | if (abs(delta) <= 5) |
186 | ret = regmap_update_bits(map: rdev->regmap, MP886X_SYSCNTLREG1, |
187 | MP886X_GO, val: 0); |
188 | di->sel = sel; |
189 | |
190 | return ret; |
191 | } |
192 | |
193 | static int mp8867_get_voltage_sel(struct regulator_dev *rdev) |
194 | { |
195 | struct mp886x_device_info *di = rdev_get_drvdata(rdev); |
196 | int ret, uv; |
197 | unsigned int val; |
198 | bool fbloop; |
199 | |
200 | ret = regmap_read(map: rdev->regmap, reg: rdev->desc->vsel_reg, val: &val); |
201 | if (ret) |
202 | return ret; |
203 | |
204 | fbloop = val & MP886X_V_BOOT; |
205 | |
206 | val &= rdev->desc->vsel_mask; |
207 | val >>= ffs(rdev->desc->vsel_mask) - 1; |
208 | |
209 | if (fbloop) { |
210 | uv = regulator_list_voltage_linear(rdev, selector: val); |
211 | uv = mp8869_scale(uv, r1: di->r[0], r2: di->r[1]); |
212 | return regulator_map_voltage_linear(rdev, min_uV: uv, max_uV: uv); |
213 | } |
214 | |
215 | return val; |
216 | } |
217 | |
218 | static const struct regulator_ops mp8867_regulator_ops = { |
219 | .set_voltage_sel = mp8867_set_voltage_sel, |
220 | .get_voltage_sel = mp8867_get_voltage_sel, |
221 | .set_voltage_time_sel = regulator_set_voltage_time_sel, |
222 | .map_voltage = regulator_map_voltage_linear, |
223 | .list_voltage = regulator_list_voltage_linear, |
224 | .enable = regulator_enable_regmap, |
225 | .disable = regulator_disable_regmap, |
226 | .is_enabled = regulator_is_enabled_regmap, |
227 | .set_mode = mp886x_set_mode, |
228 | .get_mode = mp886x_get_mode, |
229 | .set_ramp_delay = regulator_set_ramp_delay_regmap, |
230 | }; |
231 | |
232 | static const struct mp886x_cfg_info mp8867_ci = { |
233 | .rops = &mp8867_regulator_ops, |
234 | .slew_rates = { |
235 | 64000, |
236 | 32000, |
237 | 16000, |
238 | 8000, |
239 | 4000, |
240 | 2000, |
241 | 1000, |
242 | 500, |
243 | }, |
244 | .switch_freq = { |
245 | 500000, |
246 | 750000, |
247 | 1000000, |
248 | 1500000, |
249 | }, |
250 | .fs_reg = MP886X_SYSCNTLREG1, |
251 | .fs_shift = 1, |
252 | }; |
253 | |
254 | static int mp886x_regulator_register(struct mp886x_device_info *di, |
255 | struct regulator_config *config) |
256 | { |
257 | struct regulator_desc *rdesc = &di->desc; |
258 | struct regulator_dev *rdev; |
259 | |
260 | rdesc->name = "mp886x-reg" ; |
261 | rdesc->supply_name = "vin" ; |
262 | rdesc->ops = di->ci->rops; |
263 | rdesc->type = REGULATOR_VOLTAGE; |
264 | rdesc->n_voltages = 128; |
265 | rdesc->enable_reg = MP886X_SYSCNTLREG1; |
266 | rdesc->enable_mask = MP886X_EN; |
267 | rdesc->min_uV = 600000; |
268 | rdesc->uV_step = 10000; |
269 | rdesc->vsel_reg = MP886X_VSEL; |
270 | rdesc->vsel_mask = 0x3f; |
271 | rdesc->ramp_reg = MP886X_SYSCNTLREG1; |
272 | rdesc->ramp_mask = MP886X_SLEW_MASK; |
273 | rdesc->ramp_delay_table = di->ci->slew_rates; |
274 | rdesc->n_ramp_values = ARRAY_SIZE(di->ci->slew_rates); |
275 | rdesc->owner = THIS_MODULE; |
276 | |
277 | rdev = devm_regulator_register(dev: di->dev, regulator_desc: &di->desc, config); |
278 | if (IS_ERR(ptr: rdev)) |
279 | return PTR_ERR(ptr: rdev); |
280 | di->sel = rdesc->ops->get_voltage_sel(rdev); |
281 | return 0; |
282 | } |
283 | |
284 | static const struct regmap_config mp886x_regmap_config = { |
285 | .reg_bits = 8, |
286 | .val_bits = 8, |
287 | }; |
288 | |
289 | static int mp886x_i2c_probe(struct i2c_client *client) |
290 | { |
291 | struct device *dev = &client->dev; |
292 | struct device_node *np = dev->of_node; |
293 | struct mp886x_device_info *di; |
294 | struct regulator_config config = { }; |
295 | struct regmap *regmap; |
296 | u32 freq; |
297 | int ret; |
298 | |
299 | di = devm_kzalloc(dev, size: sizeof(struct mp886x_device_info), GFP_KERNEL); |
300 | if (!di) |
301 | return -ENOMEM; |
302 | |
303 | di->regulator = of_get_regulator_init_data(dev, node: np, desc: &di->desc); |
304 | if (!di->regulator) { |
305 | dev_err(dev, "Platform data not found!\n" ); |
306 | return -EINVAL; |
307 | } |
308 | |
309 | ret = of_property_read_u32_array(np, propname: "mps,fb-voltage-divider" , |
310 | out_values: di->r, sz: 2); |
311 | if (ret) |
312 | return ret; |
313 | |
314 | di->en_gpio = devm_gpiod_get(dev, con_id: "enable" , flags: GPIOD_OUT_HIGH); |
315 | if (IS_ERR(ptr: di->en_gpio)) |
316 | return PTR_ERR(ptr: di->en_gpio); |
317 | |
318 | di->ci = i2c_get_match_data(client); |
319 | di->dev = dev; |
320 | |
321 | regmap = devm_regmap_init_i2c(client, &mp886x_regmap_config); |
322 | if (IS_ERR(ptr: regmap)) { |
323 | dev_err(dev, "Failed to allocate regmap!\n" ); |
324 | return PTR_ERR(ptr: regmap); |
325 | } |
326 | i2c_set_clientdata(client, data: di); |
327 | |
328 | config.dev = di->dev; |
329 | config.init_data = di->regulator; |
330 | config.regmap = regmap; |
331 | config.driver_data = di; |
332 | config.of_node = np; |
333 | |
334 | if (!of_property_read_u32(np, propname: "mps,switch-frequency-hz" , out_value: &freq)) |
335 | mp886x_set_switch_freq(di, regmap, freq); |
336 | |
337 | ret = mp886x_regulator_register(di, config: &config); |
338 | if (ret < 0) |
339 | dev_err(dev, "Failed to register regulator!\n" ); |
340 | return ret; |
341 | } |
342 | |
343 | static const struct of_device_id mp886x_dt_ids[] = { |
344 | { .compatible = "mps,mp8867" , .data = &mp8867_ci }, |
345 | { .compatible = "mps,mp8869" , .data = &mp8869_ci }, |
346 | { } |
347 | }; |
348 | MODULE_DEVICE_TABLE(of, mp886x_dt_ids); |
349 | |
350 | static const struct i2c_device_id mp886x_id[] = { |
351 | { "mp886x" , (kernel_ulong_t)&mp8869_ci }, |
352 | { }, |
353 | }; |
354 | MODULE_DEVICE_TABLE(i2c, mp886x_id); |
355 | |
356 | static struct i2c_driver mp886x_regulator_driver = { |
357 | .driver = { |
358 | .name = "mp886x-regulator" , |
359 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
360 | .of_match_table = mp886x_dt_ids, |
361 | }, |
362 | .probe = mp886x_i2c_probe, |
363 | .id_table = mp886x_id, |
364 | }; |
365 | module_i2c_driver(mp886x_regulator_driver); |
366 | |
367 | MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>" ); |
368 | MODULE_DESCRIPTION("MP886x regulator driver" ); |
369 | MODULE_LICENSE("GPL v2" ); |
370 | |