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>
12 #include <linux/of_device.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_GO (1 << 6)
22 #define MP886X_EN (1 << 7)
24 struct mp886x_device_info
{
26 struct regulator_desc desc
;
27 struct regulator_init_data
*regulator
;
28 struct gpio_desc
*en_gpio
;
33 static int mp886x_set_mode(struct regulator_dev
*rdev
, unsigned int mode
)
36 case REGULATOR_MODE_FAST
:
37 regmap_update_bits(rdev
->regmap
, MP886X_SYSCNTLREG1
,
38 MP886X_MODE
, MP886X_MODE
);
40 case REGULATOR_MODE_NORMAL
:
41 regmap_update_bits(rdev
->regmap
, MP886X_SYSCNTLREG1
,
50 static unsigned int mp886x_get_mode(struct regulator_dev
*rdev
)
55 ret
= regmap_read(rdev
->regmap
, MP886X_SYSCNTLREG1
, &val
);
58 if (val
& MP886X_MODE
)
59 return REGULATOR_MODE_FAST
;
61 return REGULATOR_MODE_NORMAL
;
64 static int mp8869_set_voltage_sel(struct regulator_dev
*rdev
, unsigned int sel
)
68 ret
= regmap_update_bits(rdev
->regmap
, MP886X_SYSCNTLREG1
,
69 MP886X_GO
, MP886X_GO
);
73 sel
<<= ffs(rdev
->desc
->vsel_mask
) - 1;
74 return regmap_update_bits(rdev
->regmap
, rdev
->desc
->vsel_reg
,
75 MP886X_V_BOOT
| rdev
->desc
->vsel_mask
, sel
);
78 static inline unsigned int mp8869_scale(unsigned int uv
, u32 r1
, u32 r2
)
80 u32 tmp
= uv
* r1
/ r2
;
85 static int mp8869_get_voltage_sel(struct regulator_dev
*rdev
)
87 struct mp886x_device_info
*di
= rdev_get_drvdata(rdev
);
92 ret
= regmap_read(rdev
->regmap
, rdev
->desc
->vsel_reg
, &val
);
96 fbloop
= val
& MP886X_V_BOOT
;
98 uv
= rdev
->desc
->min_uV
;
99 uv
= mp8869_scale(uv
, di
->r
[0], di
->r
[1]);
100 return regulator_map_voltage_linear(rdev
, uv
, uv
);
103 val
&= rdev
->desc
->vsel_mask
;
104 val
>>= ffs(rdev
->desc
->vsel_mask
) - 1;
109 static const struct regulator_ops mp8869_regulator_ops
= {
110 .set_voltage_sel
= mp8869_set_voltage_sel
,
111 .get_voltage_sel
= mp8869_get_voltage_sel
,
112 .set_voltage_time_sel
= regulator_set_voltage_time_sel
,
113 .map_voltage
= regulator_map_voltage_linear
,
114 .list_voltage
= regulator_list_voltage_linear
,
115 .enable
= regulator_enable_regmap
,
116 .disable
= regulator_disable_regmap
,
117 .is_enabled
= regulator_is_enabled_regmap
,
118 .set_mode
= mp886x_set_mode
,
119 .get_mode
= mp886x_get_mode
,
122 static int mp8867_set_voltage_sel(struct regulator_dev
*rdev
, unsigned int sel
)
124 struct mp886x_device_info
*di
= rdev_get_drvdata(rdev
);
127 ret
= mp8869_set_voltage_sel(rdev
, sel
);
131 delta
= di
->sel
- sel
;
133 ret
= regmap_update_bits(rdev
->regmap
, MP886X_SYSCNTLREG1
,
140 static int mp8867_get_voltage_sel(struct regulator_dev
*rdev
)
142 struct mp886x_device_info
*di
= rdev_get_drvdata(rdev
);
147 ret
= regmap_read(rdev
->regmap
, rdev
->desc
->vsel_reg
, &val
);
151 fbloop
= val
& MP886X_V_BOOT
;
153 val
&= rdev
->desc
->vsel_mask
;
154 val
>>= ffs(rdev
->desc
->vsel_mask
) - 1;
157 uv
= regulator_list_voltage_linear(rdev
, val
);
158 uv
= mp8869_scale(uv
, di
->r
[0], di
->r
[1]);
159 return regulator_map_voltage_linear(rdev
, uv
, uv
);
165 static const struct regulator_ops mp8867_regulator_ops
= {
166 .set_voltage_sel
= mp8867_set_voltage_sel
,
167 .get_voltage_sel
= mp8867_get_voltage_sel
,
168 .set_voltage_time_sel
= regulator_set_voltage_time_sel
,
169 .map_voltage
= regulator_map_voltage_linear
,
170 .list_voltage
= regulator_list_voltage_linear
,
171 .enable
= regulator_enable_regmap
,
172 .disable
= regulator_disable_regmap
,
173 .is_enabled
= regulator_is_enabled_regmap
,
174 .set_mode
= mp886x_set_mode
,
175 .get_mode
= mp886x_get_mode
,
178 static int mp886x_regulator_register(struct mp886x_device_info
*di
,
179 struct regulator_config
*config
)
181 struct regulator_desc
*rdesc
= &di
->desc
;
182 struct regulator_dev
*rdev
;
184 rdesc
->name
= "mp886x-reg";
185 rdesc
->supply_name
= "vin";
186 rdesc
->ops
= of_device_get_match_data(di
->dev
);
187 rdesc
->type
= REGULATOR_VOLTAGE
;
188 rdesc
->n_voltages
= 128;
189 rdesc
->enable_reg
= MP886X_SYSCNTLREG1
;
190 rdesc
->enable_mask
= MP886X_EN
;
191 rdesc
->min_uV
= 600000;
192 rdesc
->uV_step
= 10000;
193 rdesc
->vsel_reg
= MP886X_VSEL
;
194 rdesc
->vsel_mask
= 0x3f;
195 rdesc
->owner
= THIS_MODULE
;
197 rdev
= devm_regulator_register(di
->dev
, &di
->desc
, config
);
199 return PTR_ERR(rdev
);
200 di
->sel
= rdesc
->ops
->get_voltage_sel(rdev
);
204 static const struct regmap_config mp886x_regmap_config
= {
209 static int mp886x_i2c_probe(struct i2c_client
*client
,
210 const struct i2c_device_id
*id
)
212 struct device
*dev
= &client
->dev
;
213 struct device_node
*np
= dev
->of_node
;
214 struct mp886x_device_info
*di
;
215 struct regulator_config config
= { };
216 struct regmap
*regmap
;
219 di
= devm_kzalloc(dev
, sizeof(struct mp886x_device_info
), GFP_KERNEL
);
223 di
->regulator
= of_get_regulator_init_data(dev
, np
, &di
->desc
);
224 if (!di
->regulator
) {
225 dev_err(dev
, "Platform data not found!\n");
229 ret
= of_property_read_u32_array(np
, "mps,fb-voltage-divider",
234 di
->en_gpio
= devm_gpiod_get(dev
, "enable", GPIOD_OUT_HIGH
);
235 if (IS_ERR(di
->en_gpio
))
236 return PTR_ERR(di
->en_gpio
);
240 regmap
= devm_regmap_init_i2c(client
, &mp886x_regmap_config
);
241 if (IS_ERR(regmap
)) {
242 dev_err(dev
, "Failed to allocate regmap!\n");
243 return PTR_ERR(regmap
);
245 i2c_set_clientdata(client
, di
);
247 config
.dev
= di
->dev
;
248 config
.init_data
= di
->regulator
;
249 config
.regmap
= regmap
;
250 config
.driver_data
= di
;
253 ret
= mp886x_regulator_register(di
, &config
);
255 dev_err(dev
, "Failed to register regulator!\n");
259 static const struct of_device_id mp886x_dt_ids
[] = {
261 .compatible
= "mps,mp8867",
262 .data
= &mp8867_regulator_ops
265 .compatible
= "mps,mp8869",
266 .data
= &mp8869_regulator_ops
270 MODULE_DEVICE_TABLE(of
, mp886x_dt_ids
);
272 static const struct i2c_device_id mp886x_id
[] = {
276 MODULE_DEVICE_TABLE(i2c
, mp886x_id
);
278 static struct i2c_driver mp886x_regulator_driver
= {
280 .name
= "mp886x-regulator",
281 .of_match_table
= of_match_ptr(mp886x_dt_ids
),
283 .probe
= mp886x_i2c_probe
,
284 .id_table
= mp886x_id
,
286 module_i2c_driver(mp886x_regulator_driver
);
288 MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
289 MODULE_DESCRIPTION("MP886x regulator driver");
290 MODULE_LICENSE("GPL v2");