1 // SPDX-License-Identifier: GPL-2.0+
3 // Regulator support for WM8400
5 // Copyright 2008 Wolfson Microelectronics PLC.
7 // Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
10 #include <linux/err.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/regulator/driver.h>
14 #include <linux/mfd/wm8400-private.h>
16 static const struct linear_range wm8400_ldo_ranges
[] = {
17 REGULATOR_LINEAR_RANGE(900000, 0, 14, 50000),
18 REGULATOR_LINEAR_RANGE(1700000, 15, 31, 100000),
21 static const struct regulator_ops wm8400_ldo_ops
= {
22 .is_enabled
= regulator_is_enabled_regmap
,
23 .enable
= regulator_enable_regmap
,
24 .disable
= regulator_disable_regmap
,
25 .list_voltage
= regulator_list_voltage_linear_range
,
26 .get_voltage_sel
= regulator_get_voltage_sel_regmap
,
27 .set_voltage_sel
= regulator_set_voltage_sel_regmap
,
28 .map_voltage
= regulator_map_voltage_linear_range
,
31 static unsigned int wm8400_dcdc_get_mode(struct regulator_dev
*dev
)
33 struct regmap
*rmap
= rdev_get_regmap(dev
);
34 int offset
= (rdev_get_id(dev
) - WM8400_DCDC1
) * 2;
38 ret
= regmap_bulk_read(rmap
, WM8400_DCDC1_CONTROL_1
+ offset
, data
, 2);
42 /* Datasheet: hibernate */
43 if (data
[0] & WM8400_DC1_SLEEP
)
44 return REGULATOR_MODE_STANDBY
;
46 /* Datasheet: standby */
47 if (!(data
[0] & WM8400_DC1_ACTIVE
))
48 return REGULATOR_MODE_IDLE
;
50 /* Datasheet: active with or without force PWM */
51 if (data
[1] & WM8400_DC1_FRC_PWM
)
52 return REGULATOR_MODE_FAST
;
54 return REGULATOR_MODE_NORMAL
;
57 static int wm8400_dcdc_set_mode(struct regulator_dev
*dev
, unsigned int mode
)
59 struct regmap
*rmap
= rdev_get_regmap(dev
);
60 int offset
= (rdev_get_id(dev
) - WM8400_DCDC1
) * 2;
64 case REGULATOR_MODE_FAST
:
65 /* Datasheet: active with force PWM */
66 ret
= regmap_update_bits(rmap
, WM8400_DCDC1_CONTROL_2
+ offset
,
67 WM8400_DC1_FRC_PWM
, WM8400_DC1_FRC_PWM
);
71 return regmap_update_bits(rmap
, WM8400_DCDC1_CONTROL_1
+ offset
,
72 WM8400_DC1_ACTIVE
| WM8400_DC1_SLEEP
,
75 case REGULATOR_MODE_NORMAL
:
76 /* Datasheet: active */
77 ret
= regmap_update_bits(rmap
, WM8400_DCDC1_CONTROL_2
+ offset
,
78 WM8400_DC1_FRC_PWM
, 0);
82 return regmap_update_bits(rmap
, WM8400_DCDC1_CONTROL_1
+ offset
,
83 WM8400_DC1_ACTIVE
| WM8400_DC1_SLEEP
,
86 case REGULATOR_MODE_IDLE
:
87 /* Datasheet: standby */
88 return regmap_update_bits(rmap
, WM8400_DCDC1_CONTROL_1
+ offset
,
89 WM8400_DC1_ACTIVE
| WM8400_DC1_SLEEP
, 0);
95 static unsigned int wm8400_dcdc_get_optimum_mode(struct regulator_dev
*dev
,
96 int input_uV
, int output_uV
,
99 return REGULATOR_MODE_NORMAL
;
102 static const struct regulator_ops wm8400_dcdc_ops
= {
103 .is_enabled
= regulator_is_enabled_regmap
,
104 .enable
= regulator_enable_regmap
,
105 .disable
= regulator_disable_regmap
,
106 .list_voltage
= regulator_list_voltage_linear
,
107 .map_voltage
= regulator_map_voltage_linear
,
108 .get_voltage_sel
= regulator_get_voltage_sel_regmap
,
109 .set_voltage_sel
= regulator_set_voltage_sel_regmap
,
110 .get_mode
= wm8400_dcdc_get_mode
,
111 .set_mode
= wm8400_dcdc_set_mode
,
112 .get_optimum_mode
= wm8400_dcdc_get_optimum_mode
,
115 static struct regulator_desc regulators
[] = {
119 .ops
= &wm8400_ldo_ops
,
120 .enable_reg
= WM8400_LDO1_CONTROL
,
121 .enable_mask
= WM8400_LDO1_ENA
,
122 .n_voltages
= WM8400_LDO1_VSEL_MASK
+ 1,
123 .linear_ranges
= wm8400_ldo_ranges
,
124 .n_linear_ranges
= ARRAY_SIZE(wm8400_ldo_ranges
),
125 .vsel_reg
= WM8400_LDO1_CONTROL
,
126 .vsel_mask
= WM8400_LDO1_VSEL_MASK
,
127 .type
= REGULATOR_VOLTAGE
,
128 .owner
= THIS_MODULE
,
133 .ops
= &wm8400_ldo_ops
,
134 .enable_reg
= WM8400_LDO2_CONTROL
,
135 .enable_mask
= WM8400_LDO2_ENA
,
136 .n_voltages
= WM8400_LDO2_VSEL_MASK
+ 1,
137 .linear_ranges
= wm8400_ldo_ranges
,
138 .n_linear_ranges
= ARRAY_SIZE(wm8400_ldo_ranges
),
139 .type
= REGULATOR_VOLTAGE
,
140 .vsel_reg
= WM8400_LDO2_CONTROL
,
141 .vsel_mask
= WM8400_LDO2_VSEL_MASK
,
142 .owner
= THIS_MODULE
,
147 .ops
= &wm8400_ldo_ops
,
148 .enable_reg
= WM8400_LDO3_CONTROL
,
149 .enable_mask
= WM8400_LDO3_ENA
,
150 .n_voltages
= WM8400_LDO3_VSEL_MASK
+ 1,
151 .linear_ranges
= wm8400_ldo_ranges
,
152 .n_linear_ranges
= ARRAY_SIZE(wm8400_ldo_ranges
),
153 .vsel_reg
= WM8400_LDO3_CONTROL
,
154 .vsel_mask
= WM8400_LDO3_VSEL_MASK
,
155 .type
= REGULATOR_VOLTAGE
,
156 .owner
= THIS_MODULE
,
161 .ops
= &wm8400_ldo_ops
,
162 .enable_reg
= WM8400_LDO4_CONTROL
,
163 .enable_mask
= WM8400_LDO4_ENA
,
164 .n_voltages
= WM8400_LDO4_VSEL_MASK
+ 1,
165 .linear_ranges
= wm8400_ldo_ranges
,
166 .n_linear_ranges
= ARRAY_SIZE(wm8400_ldo_ranges
),
167 .vsel_reg
= WM8400_LDO4_CONTROL
,
168 .vsel_mask
= WM8400_LDO4_VSEL_MASK
,
169 .type
= REGULATOR_VOLTAGE
,
170 .owner
= THIS_MODULE
,
175 .ops
= &wm8400_dcdc_ops
,
176 .enable_reg
= WM8400_DCDC1_CONTROL_1
,
177 .enable_mask
= WM8400_DC1_ENA_MASK
,
178 .n_voltages
= WM8400_DC1_VSEL_MASK
+ 1,
179 .vsel_reg
= WM8400_DCDC1_CONTROL_1
,
180 .vsel_mask
= WM8400_DC1_VSEL_MASK
,
183 .type
= REGULATOR_VOLTAGE
,
184 .owner
= THIS_MODULE
,
189 .ops
= &wm8400_dcdc_ops
,
190 .enable_reg
= WM8400_DCDC2_CONTROL_1
,
191 .enable_mask
= WM8400_DC2_ENA_MASK
,
192 .n_voltages
= WM8400_DC2_VSEL_MASK
+ 1,
193 .vsel_reg
= WM8400_DCDC2_CONTROL_1
,
194 .vsel_mask
= WM8400_DC2_VSEL_MASK
,
197 .type
= REGULATOR_VOLTAGE
,
198 .owner
= THIS_MODULE
,
202 static int wm8400_regulator_probe(struct platform_device
*pdev
)
204 struct wm8400
*wm8400
= container_of(pdev
, struct wm8400
, regulators
[pdev
->id
]);
205 struct regulator_config config
= { };
206 struct regulator_dev
*rdev
;
208 config
.dev
= &pdev
->dev
;
209 config
.init_data
= dev_get_platdata(&pdev
->dev
);
210 config
.driver_data
= wm8400
;
211 config
.regmap
= wm8400
->regmap
;
213 rdev
= devm_regulator_register(&pdev
->dev
, ®ulators
[pdev
->id
],
216 return PTR_ERR(rdev
);
218 platform_set_drvdata(pdev
, rdev
);
223 static struct platform_driver wm8400_regulator_driver
= {
225 .name
= "wm8400-regulator",
226 .probe_type
= PROBE_PREFER_ASYNCHRONOUS
,
228 .probe
= wm8400_regulator_probe
,
232 * wm8400_register_regulator - enable software control of a WM8400 regulator
234 * This function enables software control of a WM8400 regulator via
235 * the regulator API. It is intended to be called from the
236 * platform_init() callback of the WM8400 MFD driver.
238 * @dev: The WM8400 device to operate on.
239 * @reg: The regulator to control.
240 * @initdata: Regulator initdata for the regulator.
242 int wm8400_register_regulator(struct device
*dev
, int reg
,
243 struct regulator_init_data
*initdata
)
245 struct wm8400
*wm8400
= dev_get_drvdata(dev
);
247 if (wm8400
->regulators
[reg
].name
)
250 initdata
->driver_data
= wm8400
;
252 wm8400
->regulators
[reg
].name
= "wm8400-regulator";
253 wm8400
->regulators
[reg
].id
= reg
;
254 wm8400
->regulators
[reg
].dev
.parent
= dev
;
255 wm8400
->regulators
[reg
].dev
.platform_data
= initdata
;
257 return platform_device_register(&wm8400
->regulators
[reg
]);
259 EXPORT_SYMBOL_GPL(wm8400_register_regulator
);
261 static int __init
wm8400_regulator_init(void)
263 return platform_driver_register(&wm8400_regulator_driver
);
265 subsys_initcall(wm8400_regulator_init
);
267 static void __exit
wm8400_regulator_exit(void)
269 platform_driver_unregister(&wm8400_regulator_driver
);
271 module_exit(wm8400_regulator_exit
);
273 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
274 MODULE_DESCRIPTION("WM8400 regulator driver");
275 MODULE_LICENSE("GPL");
276 MODULE_ALIAS("platform:wm8400-regulator");