1 // SPDX-License-Identifier: GPL-2.0
3 // Copyright (c) 2019 five technologies GmbH
4 // Author: Markus Reichl <m.reichl@fivetechno.de>
6 #include <linux/module.h>
9 #include <linux/regulator/driver.h>
10 #include <linux/regmap.h>
13 #define VOL_MIN_IDX 0x00
14 #define VOL_MAX_IDX 0x7ff
16 /* Register definitions */
17 #define MP8859_VOUT_L_REG 0 //3 lo Bits
18 #define MP8859_VOUT_H_REG 1 //8 hi Bits
19 #define MP8859_VOUT_GO_REG 2
20 #define MP8859_IOUT_LIM_REG 3
21 #define MP8859_CTL1_REG 4
22 #define MP8859_CTL2_REG 5
23 #define MP8859_RESERVED1_REG 6
24 #define MP8859_RESERVED2_REG 7
25 #define MP8859_RESERVED3_REG 8
26 #define MP8859_STATUS_REG 9
27 #define MP8859_INTERRUPT_REG 0x0A
28 #define MP8859_MASK_REG 0x0B
29 #define MP8859_ID1_REG 0x0C
30 #define MP8859_MFR_ID_REG 0x27
31 #define MP8859_DEV_ID_REG 0x28
32 #define MP8859_IC_REV_REG 0x29
34 #define MP8859_MAX_REG 0x29
36 #define MP8859_GO_BIT 0x01
38 #define MP8859_IOUT_LIM_MASK 0x7f
40 #define MP8859_ENABLE_MASK 0x80
41 #define MP8859_DISCHG_EN_MASK 0x10
42 #define MP8859_MODE_MASK 0x08
44 #define MP8859_PG_MASK 0x80
45 #define MP8859_OTP_MASK 0x40
46 #define MP8859_OTW_MASK 0x20
47 #define MP8859_CC_CV_MASK 0x10
49 static int mp8859_set_voltage_sel(struct regulator_dev
*rdev
, unsigned int sel
)
53 ret
= regmap_write(rdev
->regmap
, MP8859_VOUT_L_REG
, sel
& 0x7);
57 ret
= regmap_write(rdev
->regmap
, MP8859_VOUT_H_REG
, sel
>> 3);
61 ret
= regmap_update_bits(rdev
->regmap
, MP8859_VOUT_GO_REG
,
66 static int mp8859_get_voltage_sel(struct regulator_dev
*rdev
)
72 ret
= regmap_read(rdev
->regmap
, MP8859_VOUT_H_REG
, &val_tmp
);
78 ret
= regmap_read(rdev
->regmap
, MP8859_VOUT_L_REG
, &val_tmp
);
82 val
|= val_tmp
& 0x07;
86 static int mp8859_set_voltage_time_sel(struct regulator_dev
*rdev
,
87 unsigned int from
, unsigned int to
)
91 /* The voltage ramps at 1mV/uS, selectors are 10mV */
97 return change
* 10 * 1000;
100 static unsigned int mp8859_get_mode(struct regulator_dev
*rdev
)
105 ret
= regmap_read(rdev
->regmap
, MP8859_CTL1_REG
, &val
);
107 dev_err(&rdev
->dev
, "Failed to read mode: %d\n", ret
);
111 if (val
& MP8859_MODE_MASK
)
112 return REGULATOR_MODE_FAST
;
114 return REGULATOR_MODE_NORMAL
;
117 static int mp8859_set_mode(struct regulator_dev
*rdev
, unsigned int mode
)
122 case REGULATOR_MODE_FAST
:
123 val
= MP8859_MODE_MASK
;
125 case REGULATOR_MODE_NORMAL
:
132 return regmap_update_bits(rdev
->regmap
, MP8859_CTL1_REG
,
133 MP8859_MODE_MASK
, val
);
136 static int mp8859_set_current_limit(struct regulator_dev
*rdev
,
137 int min_uA
, int max_uA
)
139 unsigned int cur_val
, new_val
;
143 new_val
= max_uA
/ 50000;
144 if (new_val
> MP8859_IOUT_LIM_MASK
)
150 * If the regulator is limiting then ramp gradually as per
151 * datasheet, otherwise just set the value directly.
153 ret
= regmap_read(rdev
->regmap
, MP8859_STATUS_REG
, &cur_val
);
156 if (!(cur_val
& MP8859_CC_CV_MASK
)) {
157 return regmap_update_bits(rdev
->regmap
, MP8859_IOUT_LIM_REG
,
158 MP8859_IOUT_LIM_MASK
, new_val
);
161 ret
= regmap_read(rdev
->regmap
, MP8859_IOUT_LIM_REG
, &cur_val
);
165 if (cur_val
>= new_val
) {
166 for (i
= cur_val
; i
>= new_val
; i
--) {
167 ret
= regmap_update_bits(rdev
->regmap
,
169 MP8859_IOUT_LIM_MASK
,
175 for (i
= cur_val
; i
<= new_val
; i
++) {
176 ret
= regmap_update_bits(rdev
->regmap
,
178 MP8859_IOUT_LIM_MASK
,
188 static int mp8859_get_status(struct regulator_dev
*rdev
)
193 /* Output status is only meaingful when enabled */
194 ret
= regmap_read(rdev
->regmap
, MP8859_CTL1_REG
, &val
);
197 if (!(val
& MP8859_ENABLE_MASK
))
198 return REGULATOR_STATUS_UNDEFINED
;
200 ret
= regmap_read(rdev
->regmap
, MP8859_STATUS_REG
, &val
);
204 if (val
& MP8859_PG_MASK
)
205 return REGULATOR_STATUS_ON
;
207 return REGULATOR_STATUS_ERROR
;
210 static int mp8859_get_error_flags(struct regulator_dev
*rdev
,
213 unsigned int status
, enabled
;
218 /* Output status is only meaingful when enabled */
219 ret
= regmap_read(rdev
->regmap
, MP8859_CTL1_REG
, &enabled
);
222 enabled
&= MP8859_ENABLE_MASK
;
224 ret
= regmap_read(rdev
->regmap
, MP8859_STATUS_REG
, &status
);
228 if (enabled
&& !(status
& MP8859_PG_MASK
))
229 status
|= REGULATOR_ERROR_FAIL
;
230 if (status
& MP8859_OTP_MASK
)
231 status
|= REGULATOR_ERROR_OVER_TEMP
;
232 if (status
& MP8859_OTW_MASK
)
233 status
|= REGULATOR_ERROR_OVER_TEMP_WARN
;
234 if (status
& MP8859_CC_CV_MASK
)
235 status
|= REGULATOR_ERROR_OVER_CURRENT
;
240 static const struct linear_range mp8859_dcdc_ranges
[] = {
241 REGULATOR_LINEAR_RANGE(0, VOL_MIN_IDX
, VOL_MAX_IDX
, 10000),
244 static bool mp8859_readable(struct device
*dev
, unsigned int reg
)
247 case MP8859_VOUT_L_REG
:
248 case MP8859_VOUT_H_REG
:
249 case MP8859_VOUT_GO_REG
:
250 case MP8859_IOUT_LIM_REG
:
251 case MP8859_CTL1_REG
:
252 case MP8859_CTL2_REG
:
253 case MP8859_STATUS_REG
:
254 case MP8859_INTERRUPT_REG
:
255 case MP8859_MASK_REG
:
257 case MP8859_MFR_ID_REG
:
258 case MP8859_DEV_ID_REG
:
259 case MP8859_IC_REV_REG
:
266 static bool mp8859_volatile(struct device
*dev
, unsigned int reg
)
269 case MP8859_VOUT_GO_REG
:
270 case MP8859_STATUS_REG
:
271 case MP8859_INTERRUPT_REG
:
278 static const struct regmap_config mp8859_regmap
= {
281 .max_register
= MP8859_MAX_REG
,
282 .cache_type
= REGCACHE_MAPLE
,
283 .readable_reg
= mp8859_readable
,
284 .volatile_reg
= mp8859_volatile
,
287 static const struct regulator_ops mp8859_ops
= {
288 .set_voltage_sel
= mp8859_set_voltage_sel
,
289 .get_voltage_sel
= mp8859_get_voltage_sel
,
290 .list_voltage
= regulator_list_voltage_linear_range
,
291 .set_voltage_time_sel
= mp8859_set_voltage_time_sel
,
292 .enable
= regulator_enable_regmap
,
293 .disable
= regulator_disable_regmap
,
294 .is_enabled
= regulator_is_enabled_regmap
,
295 .set_mode
= mp8859_set_mode
,
296 .get_mode
= mp8859_get_mode
,
297 .set_active_discharge
= regulator_set_active_discharge_regmap
,
298 .set_current_limit
= mp8859_set_current_limit
,
299 .get_status
= mp8859_get_status
,
300 .get_error_flags
= mp8859_get_error_flags
,
303 static const struct regulator_desc mp8859_regulators
[] = {
306 .type
= REGULATOR_VOLTAGE
,
307 .name
= "mp8859_dcdc",
308 .supply_name
= "vin",
309 .of_match
= of_match_ptr("mp8859_dcdc"),
310 .n_voltages
= VOL_MAX_IDX
+ 1,
311 .linear_ranges
= mp8859_dcdc_ranges
,
312 .n_linear_ranges
= 1,
313 .enable_reg
= MP8859_CTL1_REG
,
314 .enable_mask
= MP8859_ENABLE_MASK
,
315 .enable_val
= MP8859_ENABLE_MASK
,
316 .active_discharge_reg
= MP8859_CTL1_REG
,
317 .active_discharge_on
= MP8859_DISCHG_EN_MASK
,
318 .active_discharge_mask
= MP8859_DISCHG_EN_MASK
,
320 .owner
= THIS_MODULE
,
324 static int mp8859_i2c_probe(struct i2c_client
*i2c
)
327 struct regulator_config config
= {.dev
= &i2c
->dev
};
328 struct regmap
*regmap
= devm_regmap_init_i2c(i2c
, &mp8859_regmap
);
329 struct regulator_dev
*rdev
;
330 unsigned int val
, rev
;
332 if (IS_ERR(regmap
)) {
333 ret
= PTR_ERR(regmap
);
334 dev_err(&i2c
->dev
, "regmap init failed: %d\n", ret
);
338 ret
= regmap_read(regmap
, MP8859_MFR_ID_REG
, &val
);
340 dev_err(&i2c
->dev
, "Failed to read manufacturer ID: %d\n", ret
);
344 dev_err(&i2c
->dev
, "Manufacturer ID %x != 9\n", val
);
348 ret
= regmap_read(regmap
, MP8859_DEV_ID_REG
, &val
);
350 dev_err(&i2c
->dev
, "Failed to read device ID: %d\n", ret
);
354 dev_err(&i2c
->dev
, "Manufacturer ID %x != 0x58\n", val
);
358 ret
= regmap_read(regmap
, MP8859_IC_REV_REG
, &rev
);
360 dev_err(&i2c
->dev
, "Failed to read device revision: %d\n", ret
);
363 ret
= regmap_read(regmap
, MP8859_ID1_REG
, &val
);
365 dev_err(&i2c
->dev
, "Failed to read device ID1: %d\n", ret
);
368 dev_info(&i2c
->dev
, "MP8859-%04d revision %d\n", val
, rev
);
370 rdev
= devm_regulator_register(&i2c
->dev
, &mp8859_regulators
[0],
375 dev_err(&i2c
->dev
, "failed to register %s: %d\n",
376 mp8859_regulators
[0].name
, ret
);
382 static const struct of_device_id mp8859_dt_id
[] __maybe_unused
= {
383 {.compatible
= "mps,mp8859"},
386 MODULE_DEVICE_TABLE(of
, mp8859_dt_id
);
388 static const struct i2c_device_id mp8859_i2c_id
[] = {
392 MODULE_DEVICE_TABLE(i2c
, mp8859_i2c_id
);
394 static struct i2c_driver mp8859_regulator_driver
= {
397 .probe_type
= PROBE_PREFER_ASYNCHRONOUS
,
398 .of_match_table
= of_match_ptr(mp8859_dt_id
),
400 .probe
= mp8859_i2c_probe
,
401 .id_table
= mp8859_i2c_id
,
404 module_i2c_driver(mp8859_regulator_driver
);
406 MODULE_DESCRIPTION("Monolithic Power Systems MP8859 voltage regulator driver");
407 MODULE_AUTHOR("Markus Reichl <m.reichl@fivetechno.de>");
408 MODULE_LICENSE("GPL v2");