1 // SPDX-License-Identifier: GPL-2.0
3 // MP8867/MP8869 regulator driver
5 // Copyright (C) 2020 Synaptics Incorporated
7 // Author: Jisheng Zhang <jszhang@kernel.org>
9 #include <linux/gpio/consumer.h>
10 #include <linux/i2c.h>
11 #include <linux/module.h>
13 #include <linux/regmap.h>
14 #include <linux/regulator/driver.h>
15 #include <linux/regulator/of_regulator.h>
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
27 struct mp886x_cfg_info
{
28 const struct regulator_ops
*rops
;
29 const unsigned int slew_rates
[8];
30 const int switch_freq
[4];
35 struct mp886x_device_info
{
37 struct regulator_desc desc
;
38 struct regulator_init_data
*regulator
;
39 struct gpio_desc
*en_gpio
;
40 const struct mp886x_cfg_info
*ci
;
45 static void mp886x_set_switch_freq(struct mp886x_device_info
*di
,
46 struct regmap
*regmap
,
49 const struct mp886x_cfg_info
*ci
= di
->ci
;
52 for (i
= 0; i
< ARRAY_SIZE(ci
->switch_freq
); i
++) {
53 if (freq
== ci
->switch_freq
[i
]) {
54 regmap_update_bits(regmap
, ci
->fs_reg
,
55 0x3 << ci
->fs_shift
, i
<< ci
->fs_shift
);
60 dev_err(di
->dev
, "invalid frequency %d\n", freq
);
63 static int mp886x_set_mode(struct regulator_dev
*rdev
, unsigned int mode
)
66 case REGULATOR_MODE_FAST
:
67 regmap_update_bits(rdev
->regmap
, MP886X_SYSCNTLREG1
,
68 MP886X_MODE
, MP886X_MODE
);
70 case REGULATOR_MODE_NORMAL
:
71 regmap_update_bits(rdev
->regmap
, MP886X_SYSCNTLREG1
,
80 static unsigned int mp886x_get_mode(struct regulator_dev
*rdev
)
85 ret
= regmap_read(rdev
->regmap
, MP886X_SYSCNTLREG1
, &val
);
88 if (val
& MP886X_MODE
)
89 return REGULATOR_MODE_FAST
;
91 return REGULATOR_MODE_NORMAL
;
94 static int mp8869_set_voltage_sel(struct regulator_dev
*rdev
, unsigned int sel
)
98 ret
= regmap_update_bits(rdev
->regmap
, MP886X_SYSCNTLREG1
,
99 MP886X_GO
, MP886X_GO
);
103 sel
<<= ffs(rdev
->desc
->vsel_mask
) - 1;
104 return regmap_update_bits(rdev
->regmap
, rdev
->desc
->vsel_reg
,
105 MP886X_V_BOOT
| rdev
->desc
->vsel_mask
, sel
);
108 static inline unsigned int mp8869_scale(unsigned int uv
, u32 r1
, u32 r2
)
110 u32 tmp
= uv
* r1
/ r2
;
115 static int mp8869_get_voltage_sel(struct regulator_dev
*rdev
)
117 struct mp886x_device_info
*di
= rdev_get_drvdata(rdev
);
122 ret
= regmap_read(rdev
->regmap
, rdev
->desc
->vsel_reg
, &val
);
126 fbloop
= val
& MP886X_V_BOOT
;
128 uv
= rdev
->desc
->min_uV
;
129 uv
= mp8869_scale(uv
, di
->r
[0], di
->r
[1]);
130 return regulator_map_voltage_linear(rdev
, uv
, uv
);
133 val
&= rdev
->desc
->vsel_mask
;
134 val
>>= ffs(rdev
->desc
->vsel_mask
) - 1;
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
,
153 static const struct mp886x_cfg_info mp8869_ci
= {
154 .rops
= &mp8869_regulator_ops
,
171 .fs_reg
= MP8869_SYSCNTLREG2
,
175 static int mp8867_set_voltage_sel(struct regulator_dev
*rdev
, unsigned int sel
)
177 struct mp886x_device_info
*di
= rdev_get_drvdata(rdev
);
180 ret
= mp8869_set_voltage_sel(rdev
, sel
);
184 delta
= di
->sel
- sel
;
186 ret
= regmap_update_bits(rdev
->regmap
, MP886X_SYSCNTLREG1
,
193 static int mp8867_get_voltage_sel(struct regulator_dev
*rdev
)
195 struct mp886x_device_info
*di
= rdev_get_drvdata(rdev
);
200 ret
= regmap_read(rdev
->regmap
, rdev
->desc
->vsel_reg
, &val
);
204 fbloop
= val
& MP886X_V_BOOT
;
206 val
&= rdev
->desc
->vsel_mask
;
207 val
>>= ffs(rdev
->desc
->vsel_mask
) - 1;
210 uv
= regulator_list_voltage_linear(rdev
, val
);
211 uv
= mp8869_scale(uv
, di
->r
[0], di
->r
[1]);
212 return regulator_map_voltage_linear(rdev
, uv
, uv
);
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
,
232 static const struct mp886x_cfg_info mp8867_ci
= {
233 .rops
= &mp8867_regulator_ops
,
250 .fs_reg
= MP886X_SYSCNTLREG1
,
254 static int mp886x_regulator_register(struct mp886x_device_info
*di
,
255 struct regulator_config
*config
)
257 struct regulator_desc
*rdesc
= &di
->desc
;
258 struct regulator_dev
*rdev
;
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
;
277 rdev
= devm_regulator_register(di
->dev
, &di
->desc
, config
);
279 return PTR_ERR(rdev
);
280 di
->sel
= rdesc
->ops
->get_voltage_sel(rdev
);
284 static const struct regmap_config mp886x_regmap_config
= {
289 static int mp886x_i2c_probe(struct i2c_client
*client
)
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
;
299 di
= devm_kzalloc(dev
, sizeof(struct mp886x_device_info
), GFP_KERNEL
);
303 di
->regulator
= of_get_regulator_init_data(dev
, np
, &di
->desc
);
304 if (!di
->regulator
) {
305 dev_err(dev
, "Platform data not found!\n");
309 ret
= of_property_read_u32_array(np
, "mps,fb-voltage-divider",
314 di
->en_gpio
= devm_gpiod_get(dev
, "enable", GPIOD_OUT_HIGH
);
315 if (IS_ERR(di
->en_gpio
))
316 return PTR_ERR(di
->en_gpio
);
318 di
->ci
= i2c_get_match_data(client
);
321 regmap
= devm_regmap_init_i2c(client
, &mp886x_regmap_config
);
322 if (IS_ERR(regmap
)) {
323 dev_err(dev
, "Failed to allocate regmap!\n");
324 return PTR_ERR(regmap
);
326 i2c_set_clientdata(client
, di
);
328 config
.dev
= di
->dev
;
329 config
.init_data
= di
->regulator
;
330 config
.regmap
= regmap
;
331 config
.driver_data
= di
;
334 if (!of_property_read_u32(np
, "mps,switch-frequency-hz", &freq
))
335 mp886x_set_switch_freq(di
, regmap
, freq
);
337 ret
= mp886x_regulator_register(di
, &config
);
339 dev_err(dev
, "Failed to register regulator!\n");
343 static const struct of_device_id mp886x_dt_ids
[] = {
344 { .compatible
= "mps,mp8867", .data
= &mp8867_ci
},
345 { .compatible
= "mps,mp8869", .data
= &mp8869_ci
},
348 MODULE_DEVICE_TABLE(of
, mp886x_dt_ids
);
350 static const struct i2c_device_id mp886x_id
[] = {
351 { "mp886x", (kernel_ulong_t
)&mp8869_ci
},
354 MODULE_DEVICE_TABLE(i2c
, mp886x_id
);
356 static struct i2c_driver mp886x_regulator_driver
= {
358 .name
= "mp886x-regulator",
359 .probe_type
= PROBE_PREFER_ASYNCHRONOUS
,
360 .of_match_table
= mp886x_dt_ids
,
362 .probe
= mp886x_i2c_probe
,
363 .id_table
= mp886x_id
,
365 module_i2c_driver(mp886x_regulator_driver
);
367 MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
368 MODULE_DESCRIPTION("MP886x regulator driver");
369 MODULE_LICENSE("GPL v2");