Merge branch 'x86-ras-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / drivers / regulator / as3711-regulator.c
1 /*
2  * AS3711 PMIC regulator driver, using DCDC Step Down and LDO supplies
3  *
4  * Copyright (C) 2012 Renesas Electronics Corporation
5  * Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the version 2 of the GNU General Public License as
9  * published by the Free Software Foundation
10  */
11
12 #include <linux/err.h>
13 #include <linux/init.h>
14 #include <linux/mfd/as3711.h>
15 #include <linux/module.h>
16 #include <linux/platform_device.h>
17 #include <linux/regmap.h>
18 #include <linux/regulator/driver.h>
19 #include <linux/slab.h>
20
21 struct as3711_regulator_info {
22         struct regulator_desc   desc;
23         unsigned int            max_uV;
24 };
25
26 struct as3711_regulator {
27         struct as3711_regulator_info *reg_info;
28         struct regulator_dev *rdev;
29 };
30
31 static int as3711_list_voltage_sd(struct regulator_dev *rdev,
32                                   unsigned int selector)
33 {
34         if (selector >= rdev->desc->n_voltages)
35                 return -EINVAL;
36
37         if (!selector)
38                 return 0;
39         if (selector < 0x41)
40                 return 600000 + selector * 12500;
41         if (selector < 0x71)
42                 return 1400000 + (selector - 0x40) * 25000;
43         return 2600000 + (selector - 0x70) * 50000;
44 }
45
46 static int as3711_list_voltage_aldo(struct regulator_dev *rdev,
47                                     unsigned int selector)
48 {
49         if (selector >= rdev->desc->n_voltages)
50                 return -EINVAL;
51
52         if (selector < 0x10)
53                 return 1200000 + selector * 50000;
54         return 1800000 + (selector - 0x10) * 100000;
55 }
56
57 static int as3711_list_voltage_dldo(struct regulator_dev *rdev,
58                                     unsigned int selector)
59 {
60         if (selector >= rdev->desc->n_voltages ||
61             (selector > 0x10 && selector < 0x20))
62                 return -EINVAL;
63
64         if (selector < 0x11)
65                 return 900000 + selector * 50000;
66         return 1750000 + (selector - 0x20) * 50000;
67 }
68
69 static int as3711_bound_check(struct regulator_dev *rdev,
70                               int *min_uV, int *max_uV)
71 {
72         struct as3711_regulator *reg = rdev_get_drvdata(rdev);
73         struct as3711_regulator_info *info = reg->reg_info;
74
75         dev_dbg(&rdev->dev, "%s(), %d, %d, %d\n", __func__,
76                 *min_uV, rdev->desc->min_uV, info->max_uV);
77
78         if (*max_uV < *min_uV ||
79             *min_uV > info->max_uV || rdev->desc->min_uV > *max_uV)
80                 return -EINVAL;
81
82         if (rdev->desc->n_voltages == 1)
83                 return 0;
84
85         if (*max_uV > info->max_uV)
86                 *max_uV = info->max_uV;
87
88         if (*min_uV < rdev->desc->min_uV)
89                 *min_uV = rdev->desc->min_uV;
90
91         return *min_uV;
92 }
93
94 static int as3711_sel_check(int min, int max, int bottom, int step)
95 {
96         int sel, voltage;
97
98         /* Round up min, when dividing: keeps us within the range */
99         sel = DIV_ROUND_UP(min - bottom, step);
100         voltage = sel * step + bottom;
101         pr_debug("%s(): select %d..%d in %d+N*%d: %d\n", __func__,
102                min, max, bottom, step, sel);
103         if (voltage > max)
104                 return -EINVAL;
105
106         return sel;
107 }
108
109 static int as3711_map_voltage_sd(struct regulator_dev *rdev,
110                                  int min_uV, int max_uV)
111 {
112         int ret;
113
114         ret = as3711_bound_check(rdev, &min_uV, &max_uV);
115         if (ret <= 0)
116                 return ret;
117
118         if (min_uV <= 1400000)
119                 return as3711_sel_check(min_uV, max_uV, 600000, 12500);
120
121         if (min_uV <= 2600000)
122                 return as3711_sel_check(min_uV, max_uV, 1400000, 25000) + 0x40;
123
124         return as3711_sel_check(min_uV, max_uV, 2600000, 50000) + 0x70;
125 }
126
127 /*
128  * The regulator API supports 4 modes of operataion: FAST, NORMAL, IDLE and
129  * STANDBY. We map them in the following way to AS3711 SD1-4 DCDC modes:
130  * FAST:        sdX_fast=1
131  * NORMAL:      low_noise=1
132  * IDLE:        low_noise=0
133  */
134
135 static int as3711_set_mode_sd(struct regulator_dev *rdev, unsigned int mode)
136 {
137         unsigned int fast_bit = rdev->desc->enable_mask,
138                 low_noise_bit = fast_bit << 4;
139         u8 val;
140
141         switch (mode) {
142         case REGULATOR_MODE_FAST:
143                 val = fast_bit | low_noise_bit;
144                 break;
145         case REGULATOR_MODE_NORMAL:
146                 val = low_noise_bit;
147                 break;
148         case REGULATOR_MODE_IDLE:
149                 val = 0;
150                 break;
151         default:
152                 return -EINVAL;
153         }
154
155         return regmap_update_bits(rdev->regmap, AS3711_SD_CONTROL_1,
156                                   low_noise_bit | fast_bit, val);
157 }
158
159 static unsigned int as3711_get_mode_sd(struct regulator_dev *rdev)
160 {
161         unsigned int fast_bit = rdev->desc->enable_mask,
162                 low_noise_bit = fast_bit << 4, mask = fast_bit | low_noise_bit;
163         unsigned int val;
164         int ret = regmap_read(rdev->regmap, AS3711_SD_CONTROL_1, &val);
165
166         if (ret < 0)
167                 return ret;
168
169         if ((val & mask) == mask)
170                 return REGULATOR_MODE_FAST;
171
172         if ((val & mask) == low_noise_bit)
173                 return REGULATOR_MODE_NORMAL;
174
175         if (!(val & mask))
176                 return REGULATOR_MODE_IDLE;
177
178         return -EINVAL;
179 }
180
181 static int as3711_map_voltage_aldo(struct regulator_dev *rdev,
182                                   int min_uV, int max_uV)
183 {
184         int ret;
185
186         ret = as3711_bound_check(rdev, &min_uV, &max_uV);
187         if (ret <= 0)
188                 return ret;
189
190         if (min_uV <= 1800000)
191                 return as3711_sel_check(min_uV, max_uV, 1200000, 50000);
192
193         return as3711_sel_check(min_uV, max_uV, 1800000, 100000) + 0x10;
194 }
195
196 static int as3711_map_voltage_dldo(struct regulator_dev *rdev,
197                                   int min_uV, int max_uV)
198 {
199         int ret;
200
201         ret = as3711_bound_check(rdev, &min_uV, &max_uV);
202         if (ret <= 0)
203                 return ret;
204
205         if (min_uV <= 1700000)
206                 return as3711_sel_check(min_uV, max_uV, 900000, 50000);
207
208         return as3711_sel_check(min_uV, max_uV, 1750000, 50000) + 0x20;
209 }
210
211 static struct regulator_ops as3711_sd_ops = {
212         .is_enabled             = regulator_is_enabled_regmap,
213         .enable                 = regulator_enable_regmap,
214         .disable                = regulator_disable_regmap,
215         .get_voltage_sel        = regulator_get_voltage_sel_regmap,
216         .set_voltage_sel        = regulator_set_voltage_sel_regmap,
217         .list_voltage           = as3711_list_voltage_sd,
218         .map_voltage            = as3711_map_voltage_sd,
219         .get_mode               = as3711_get_mode_sd,
220         .set_mode               = as3711_set_mode_sd,
221 };
222
223 static struct regulator_ops as3711_aldo_ops = {
224         .is_enabled             = regulator_is_enabled_regmap,
225         .enable                 = regulator_enable_regmap,
226         .disable                = regulator_disable_regmap,
227         .get_voltage_sel        = regulator_get_voltage_sel_regmap,
228         .set_voltage_sel        = regulator_set_voltage_sel_regmap,
229         .list_voltage           = as3711_list_voltage_aldo,
230         .map_voltage            = as3711_map_voltage_aldo,
231 };
232
233 static struct regulator_ops as3711_dldo_ops = {
234         .is_enabled             = regulator_is_enabled_regmap,
235         .enable                 = regulator_enable_regmap,
236         .disable                = regulator_disable_regmap,
237         .get_voltage_sel        = regulator_get_voltage_sel_regmap,
238         .set_voltage_sel        = regulator_set_voltage_sel_regmap,
239         .list_voltage           = as3711_list_voltage_dldo,
240         .map_voltage            = as3711_map_voltage_dldo,
241 };
242
243 #define AS3711_REG(_id, _en_reg, _en_bit, _vmask, _vshift, _min_uV, _max_uV, _sfx)      \
244         [AS3711_REGULATOR_ ## _id] = {                                                  \
245         .desc = {                                                                       \
246                 .name = "as3711-regulator-" # _id,                                      \
247                 .id = AS3711_REGULATOR_ ## _id,                                         \
248                 .n_voltages = (_vmask + 1),                                             \
249                 .ops = &as3711_ ## _sfx ## _ops,                                        \
250                 .type = REGULATOR_VOLTAGE,                                              \
251                 .owner = THIS_MODULE,                                                   \
252                 .vsel_reg = AS3711_ ## _id ## _VOLTAGE,                                 \
253                 .vsel_mask = _vmask << _vshift,                                         \
254                 .enable_reg = AS3711_ ## _en_reg,                                       \
255                 .enable_mask = BIT(_en_bit),                                            \
256                 .min_uV = _min_uV,                                                      \
257         },                                                                              \
258         .max_uV = _max_uV,                                                              \
259 }
260
261 static struct as3711_regulator_info as3711_reg_info[] = {
262         AS3711_REG(SD_1, SD_CONTROL, 0, 0x7f, 0, 612500, 3350000, sd),
263         AS3711_REG(SD_2, SD_CONTROL, 1, 0x7f, 0, 612500, 3350000, sd),
264         AS3711_REG(SD_3, SD_CONTROL, 2, 0x7f, 0, 612500, 3350000, sd),
265         AS3711_REG(SD_4, SD_CONTROL, 3, 0x7f, 0, 612500, 3350000, sd),
266         AS3711_REG(LDO_1, LDO_1_VOLTAGE, 7, 0x1f, 0, 1200000, 3300000, aldo),
267         AS3711_REG(LDO_2, LDO_2_VOLTAGE, 7, 0x1f, 0, 1200000, 3300000, aldo),
268         AS3711_REG(LDO_3, LDO_3_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo),
269         AS3711_REG(LDO_4, LDO_4_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo),
270         AS3711_REG(LDO_5, LDO_5_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo),
271         AS3711_REG(LDO_6, LDO_6_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo),
272         AS3711_REG(LDO_7, LDO_7_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo),
273         AS3711_REG(LDO_8, LDO_8_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo),
274         /* StepUp output voltage depends on supplying regulator */
275 };
276
277 #define AS3711_REGULATOR_NUM ARRAY_SIZE(as3711_reg_info)
278
279 static int as3711_regulator_probe(struct platform_device *pdev)
280 {
281         struct as3711_regulator_pdata *pdata = dev_get_platdata(&pdev->dev);
282         struct as3711 *as3711 = dev_get_drvdata(pdev->dev.parent);
283         struct regulator_init_data *reg_data;
284         struct regulator_config config = {.dev = &pdev->dev,};
285         struct as3711_regulator *reg = NULL;
286         struct as3711_regulator *regs;
287         struct regulator_dev *rdev;
288         struct as3711_regulator_info *ri;
289         int ret;
290         int id;
291
292         if (!pdata)
293                 dev_dbg(&pdev->dev, "No platform data...\n");
294
295         regs = devm_kzalloc(&pdev->dev, AS3711_REGULATOR_NUM *
296                         sizeof(struct as3711_regulator), GFP_KERNEL);
297         if (!regs) {
298                 dev_err(&pdev->dev, "Memory allocation failed exiting..\n");
299                 return -ENOMEM;
300         }
301
302         for (id = 0, ri = as3711_reg_info; id < AS3711_REGULATOR_NUM; ++id, ri++) {
303                 reg_data = pdata ? pdata->init_data[id] : NULL;
304
305                 /* No need to register if there is no regulator data */
306                 if (!ri->desc.name)
307                         continue;
308
309                 reg = &regs[id];
310                 reg->reg_info = ri;
311
312                 config.init_data = reg_data;
313                 config.driver_data = reg;
314                 config.regmap = as3711->regmap;
315
316                 rdev = regulator_register(&ri->desc, &config);
317                 if (IS_ERR(rdev)) {
318                         dev_err(&pdev->dev, "Failed to register regulator %s\n",
319                                 ri->desc.name);
320                         ret = PTR_ERR(rdev);
321                         goto eregreg;
322                 }
323                 reg->rdev = rdev;
324         }
325         platform_set_drvdata(pdev, regs);
326         return 0;
327
328 eregreg:
329         while (--id >= 0)
330                 regulator_unregister(regs[id].rdev);
331
332         return ret;
333 }
334
335 static int as3711_regulator_remove(struct platform_device *pdev)
336 {
337         struct as3711_regulator *regs = platform_get_drvdata(pdev);
338         int id;
339
340         for (id = 0; id < AS3711_REGULATOR_NUM; ++id)
341                 regulator_unregister(regs[id].rdev);
342         return 0;
343 }
344
345 static struct platform_driver as3711_regulator_driver = {
346         .driver = {
347                 .name   = "as3711-regulator",
348                 .owner  = THIS_MODULE,
349         },
350         .probe          = as3711_regulator_probe,
351         .remove         = as3711_regulator_remove,
352 };
353
354 static int __init as3711_regulator_init(void)
355 {
356         return platform_driver_register(&as3711_regulator_driver);
357 }
358 subsys_initcall(as3711_regulator_init);
359
360 static void __exit as3711_regulator_exit(void)
361 {
362         platform_driver_unregister(&as3711_regulator_driver);
363 }
364 module_exit(as3711_regulator_exit);
365
366 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
367 MODULE_DESCRIPTION("AS3711 regulator driver");
368 MODULE_ALIAS("platform:as3711-regulator");
369 MODULE_LICENSE("GPL v2");