Merge branches 'pm-opp', 'pm-misc', 'pm-avs' and 'pm-tools'
[linux-2.6-microblaze.git] / drivers / regulator / wm8400-regulator.c
1 // SPDX-License-Identifier: GPL-2.0+
2 //
3 // Regulator support for WM8400
4 //
5 // Copyright 2008 Wolfson Microelectronics PLC.
6 //
7 // Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
8
9 #include <linux/bug.h>
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>
15
16 static const struct regulator_linear_range wm8400_ldo_ranges[] = {
17         REGULATOR_LINEAR_RANGE(900000, 0, 14, 50000),
18         REGULATOR_LINEAR_RANGE(1700000, 15, 31, 100000),
19 };
20
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,
29 };
30
31 static unsigned int wm8400_dcdc_get_mode(struct regulator_dev *dev)
32 {
33         struct regmap *rmap = rdev_get_regmap(dev);
34         int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
35         u16 data[2];
36         int ret;
37
38         ret = regmap_bulk_read(rmap, WM8400_DCDC1_CONTROL_1 + offset, data, 2);
39         if (ret != 0)
40                 return 0;
41
42         /* Datasheet: hibernate */
43         if (data[0] & WM8400_DC1_SLEEP)
44                 return REGULATOR_MODE_STANDBY;
45
46         /* Datasheet: standby */
47         if (!(data[0] & WM8400_DC1_ACTIVE))
48                 return REGULATOR_MODE_IDLE;
49
50         /* Datasheet: active with or without force PWM */
51         if (data[1] & WM8400_DC1_FRC_PWM)
52                 return REGULATOR_MODE_FAST;
53         else
54                 return REGULATOR_MODE_NORMAL;
55 }
56
57 static int wm8400_dcdc_set_mode(struct regulator_dev *dev, unsigned int mode)
58 {
59         struct regmap *rmap = rdev_get_regmap(dev);
60         int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
61         int ret;
62
63         switch (mode) {
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);
68                 if (ret != 0)
69                         return ret;
70
71                 return regmap_update_bits(rmap, WM8400_DCDC1_CONTROL_1 + offset,
72                                        WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP,
73                                        WM8400_DC1_ACTIVE);
74
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);
79                 if (ret != 0)
80                         return ret;
81
82                 return regmap_update_bits(rmap, WM8400_DCDC1_CONTROL_1 + offset,
83                                        WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP,
84                                        WM8400_DC1_ACTIVE);
85
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);
90         default:
91                 return -EINVAL;
92         }
93 }
94
95 static unsigned int wm8400_dcdc_get_optimum_mode(struct regulator_dev *dev,
96                                                  int input_uV, int output_uV,
97                                                  int load_uA)
98 {
99         return REGULATOR_MODE_NORMAL;
100 }
101
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,
113 };
114
115 static struct regulator_desc regulators[] = {
116         {
117                 .name = "LDO1",
118                 .id = WM8400_LDO1,
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,
129         },
130         {
131                 .name = "LDO2",
132                 .id = WM8400_LDO2,
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,
143         },
144         {
145                 .name = "LDO3",
146                 .id = WM8400_LDO3,
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,
157         },
158         {
159                 .name = "LDO4",
160                 .id = WM8400_LDO4,
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,
171         },
172         {
173                 .name = "DCDC1",
174                 .id = WM8400_DCDC1,
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,
181                 .min_uV = 850000,
182                 .uV_step = 25000,
183                 .type = REGULATOR_VOLTAGE,
184                 .owner = THIS_MODULE,
185         },
186         {
187                 .name = "DCDC2",
188                 .id = WM8400_DCDC2,
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,
195                 .min_uV = 850000,
196                 .uV_step = 25000,
197                 .type = REGULATOR_VOLTAGE,
198                 .owner = THIS_MODULE,
199         },
200 };
201
202 static int wm8400_regulator_probe(struct platform_device *pdev)
203 {
204         struct wm8400 *wm8400 = container_of(pdev, struct wm8400, regulators[pdev->id]);
205         struct regulator_config config = { };
206         struct regulator_dev *rdev;
207
208         config.dev = &pdev->dev;
209         config.init_data = dev_get_platdata(&pdev->dev);
210         config.driver_data = wm8400;
211         config.regmap = wm8400->regmap;
212
213         rdev = devm_regulator_register(&pdev->dev, &regulators[pdev->id],
214                                        &config);
215         if (IS_ERR(rdev))
216                 return PTR_ERR(rdev);
217
218         platform_set_drvdata(pdev, rdev);
219
220         return 0;
221 }
222
223 static struct platform_driver wm8400_regulator_driver = {
224         .driver = {
225                 .name = "wm8400-regulator",
226         },
227         .probe = wm8400_regulator_probe,
228 };
229
230 /**
231  * wm8400_register_regulator - enable software control of a WM8400 regulator
232  *
233  * This function enables software control of a WM8400 regulator via
234  * the regulator API.  It is intended to be called from the
235  * platform_init() callback of the WM8400 MFD driver.
236  *
237  * @param dev      The WM8400 device to operate on.
238  * @param reg      The regulator to control.
239  * @param initdata Regulator initdata for the regulator.
240  */
241 int wm8400_register_regulator(struct device *dev, int reg,
242                               struct regulator_init_data *initdata)
243 {
244         struct wm8400 *wm8400 = dev_get_drvdata(dev);
245
246         if (wm8400->regulators[reg].name)
247                 return -EBUSY;
248
249         initdata->driver_data = wm8400;
250
251         wm8400->regulators[reg].name = "wm8400-regulator";
252         wm8400->regulators[reg].id = reg;
253         wm8400->regulators[reg].dev.parent = dev;
254         wm8400->regulators[reg].dev.platform_data = initdata;
255
256         return platform_device_register(&wm8400->regulators[reg]);
257 }
258 EXPORT_SYMBOL_GPL(wm8400_register_regulator);
259
260 static int __init wm8400_regulator_init(void)
261 {
262         return platform_driver_register(&wm8400_regulator_driver);
263 }
264 subsys_initcall(wm8400_regulator_init);
265
266 static void __exit wm8400_regulator_exit(void)
267 {
268         platform_driver_unregister(&wm8400_regulator_driver);
269 }
270 module_exit(wm8400_regulator_exit);
271
272 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
273 MODULE_DESCRIPTION("WM8400 regulator driver");
274 MODULE_LICENSE("GPL");
275 MODULE_ALIAS("platform:wm8400-regulator");