blob: 0da8867bdf4c5a0cbb16d8abde88a0cada8cd9a6 [file] [log] [blame]
Chris Zhong2cd64ae2014-08-20 11:36:42 +08001/*
2 * Regulator driver for Rockchip RK808
3 *
4 * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
5 *
6 * Author: Chris Zhong <zyw@rock-chips.com>
7 * Author: Zhang Qing <zhangqing@rock-chips.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms and conditions of the GNU General Public License,
11 * version 2, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 */
19
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/i2c.h>
23#include <linux/err.h>
24#include <linux/platform_device.h>
25#include <linux/mfd/rk808.h>
26#include <linux/of.h>
27#include <linux/of_device.h>
28#include <linux/regulator/driver.h>
29#include <linux/regulator/of_regulator.h>
30#include <linux/regmap.h>
31#include <linux/slab.h>
32/*
33 * Field Definitions.
34 */
35#define RK808_BUCK_VSEL_MASK 0x3f
36#define RK808_BUCK4_VSEL_MASK 0xf
37#define RK808_LDO_VSEL_MASK 0x1f
38
39static const int buck_set_vol_base_addr[] = {
40 RK808_BUCK1_ON_VSEL_REG,
41 RK808_BUCK2_ON_VSEL_REG,
42 RK808_BUCK3_CONFIG_REG,
43 RK808_BUCK4_ON_VSEL_REG,
44};
45
46static const int buck_contr_base_addr[] = {
47 RK808_BUCK1_CONFIG_REG,
48 RK808_BUCK2_CONFIG_REG,
49 RK808_BUCK3_CONFIG_REG,
50 RK808_BUCK4_CONFIG_REG,
51};
52
53#define rk808_BUCK_SET_VOL_REG(x) (buck_set_vol_base_addr[x])
54#define rk808_BUCK_CONTR_REG(x) (buck_contr_base_addr[x])
55#define rk808_LDO_SET_VOL_REG(x) (ldo_set_vol_base_addr[x])
56
57static const int ldo_set_vol_base_addr[] = {
58 RK808_LDO1_ON_VSEL_REG,
59 RK808_LDO2_ON_VSEL_REG,
60 RK808_LDO3_ON_VSEL_REG,
61 RK808_LDO4_ON_VSEL_REG,
62 RK808_LDO5_ON_VSEL_REG,
63 RK808_LDO6_ON_VSEL_REG,
64 RK808_LDO7_ON_VSEL_REG,
65 RK808_LDO8_ON_VSEL_REG,
66};
67
68/*
69 * rk808 voltage number
70 */
71static const struct regulator_linear_range rk808_buck_voltage_ranges[] = {
72 REGULATOR_LINEAR_RANGE(700000, 0, 63, 12500),
73};
74
75static const struct regulator_linear_range rk808_buck4_voltage_ranges[] = {
76 REGULATOR_LINEAR_RANGE(1800000, 0, 15, 100000),
77};
78
79static const struct regulator_linear_range rk808_ldo_voltage_ranges[] = {
80 REGULATOR_LINEAR_RANGE(1800000, 0, 16, 100000),
81};
82
83static const struct regulator_linear_range rk808_ldo3_voltage_ranges[] = {
84 REGULATOR_LINEAR_RANGE(800000, 0, 13, 100000),
85 REGULATOR_LINEAR_RANGE(2500000, 15, 15, 0),
86};
87
88static const struct regulator_linear_range rk808_ldo6_voltage_ranges[] = {
89 REGULATOR_LINEAR_RANGE(800000, 0, 17, 100000),
90};
91
92static struct regulator_ops rk808_reg_ops = {
93 .list_voltage = regulator_list_voltage_linear_range,
94 .map_voltage = regulator_map_voltage_linear_range,
95 .get_voltage_sel = regulator_get_voltage_sel_regmap,
96 .set_voltage_sel = regulator_set_voltage_sel_regmap,
97 .enable = regulator_enable_regmap,
98 .disable = regulator_disable_regmap,
99 .is_enabled = regulator_is_enabled_regmap,
100};
101
102static struct regulator_ops rk808_switch_ops = {
103 .enable = regulator_enable_regmap,
104 .disable = regulator_disable_regmap,
105 .is_enabled = regulator_is_enabled_regmap,
106};
107
108static const struct regulator_desc rk808_reg[] = {
109 {
110 .name = "DCDC_REG1",
111 .id = RK808_ID_DCDC1,
112 .ops = &rk808_reg_ops,
113 .type = REGULATOR_VOLTAGE,
114 .n_voltages = 64,
115 .linear_ranges = rk808_buck_voltage_ranges,
116 .n_linear_ranges = ARRAY_SIZE(rk808_buck_voltage_ranges),
117 .vsel_reg = RK808_BUCK1_ON_VSEL_REG,
118 .vsel_mask = RK808_BUCK_VSEL_MASK,
119 .enable_reg = RK808_DCDC_EN_REG,
120 .enable_mask = BIT(0),
121 .owner = THIS_MODULE,
122 }, {
123 .name = "DCDC_REG2",
124 .id = RK808_ID_DCDC2,
125 .ops = &rk808_reg_ops,
126 .type = REGULATOR_VOLTAGE,
127 .n_voltages = 64,
128 .linear_ranges = rk808_buck_voltage_ranges,
129 .n_linear_ranges = ARRAY_SIZE(rk808_buck_voltage_ranges),
130 .vsel_reg = RK808_BUCK2_ON_VSEL_REG,
131 .vsel_mask = RK808_BUCK_VSEL_MASK,
132 .enable_reg = RK808_DCDC_EN_REG,
133 .enable_mask = BIT(1),
134 .owner = THIS_MODULE,
135 }, {
136 .name = "DCDC_REG3",
137 .id = RK808_ID_DCDC3,
138 .ops = &rk808_switch_ops,
139 .type = REGULATOR_VOLTAGE,
140 .n_voltages = 1,
141 .enable_reg = RK808_DCDC_EN_REG,
142 .enable_mask = BIT(2),
143 .owner = THIS_MODULE,
144 }, {
145 .name = "DCDC_REG4",
146 .id = RK808_ID_DCDC4,
147 .ops = &rk808_reg_ops,
148 .type = REGULATOR_VOLTAGE,
Axel Lin5a820672014-09-02 08:47:31 +0800149 .n_voltages = 16,
Chris Zhong2cd64ae2014-08-20 11:36:42 +0800150 .linear_ranges = rk808_buck4_voltage_ranges,
151 .n_linear_ranges = ARRAY_SIZE(rk808_buck4_voltage_ranges),
152 .vsel_reg = RK808_BUCK4_ON_VSEL_REG,
153 .vsel_mask = RK808_BUCK4_VSEL_MASK,
154 .enable_reg = RK808_DCDC_EN_REG,
155 .enable_mask = BIT(3),
156 .owner = THIS_MODULE,
157 }, {
158 .name = "LDO_REG1",
159 .id = RK808_ID_LDO1,
160 .ops = &rk808_reg_ops,
161 .type = REGULATOR_VOLTAGE,
162 .n_voltages = 17,
163 .linear_ranges = rk808_ldo_voltage_ranges,
164 .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges),
165 .vsel_reg = RK808_LDO1_ON_VSEL_REG,
166 .vsel_mask = RK808_LDO_VSEL_MASK,
167 .enable_reg = RK808_LDO_EN_REG,
168 .enable_mask = BIT(0),
169 .owner = THIS_MODULE,
170 }, {
171 .name = "LDO_REG2",
172 .id = RK808_ID_LDO2,
173 .ops = &rk808_reg_ops,
174 .type = REGULATOR_VOLTAGE,
175 .n_voltages = 17,
176 .linear_ranges = rk808_ldo_voltage_ranges,
177 .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges),
178 .vsel_reg = RK808_LDO2_ON_VSEL_REG,
179 .vsel_mask = RK808_LDO_VSEL_MASK,
180 .enable_reg = RK808_LDO_EN_REG,
181 .enable_mask = BIT(1),
182 .owner = THIS_MODULE,
183 }, {
184 .name = "LDO_REG3",
185 .id = RK808_ID_LDO3,
186 .ops = &rk808_reg_ops,
187 .type = REGULATOR_VOLTAGE,
188 .n_voltages = 16,
189 .linear_ranges = rk808_ldo3_voltage_ranges,
190 .n_linear_ranges = ARRAY_SIZE(rk808_ldo3_voltage_ranges),
191 .vsel_reg = RK808_LDO3_ON_VSEL_REG,
192 .vsel_mask = RK808_BUCK4_VSEL_MASK,
193 .enable_reg = RK808_LDO_EN_REG,
194 .enable_mask = BIT(2),
195 .owner = THIS_MODULE,
196 }, {
197 .name = "LDO_REG4",
198 .id = RK808_ID_LDO4,
199 .ops = &rk808_reg_ops,
200 .type = REGULATOR_VOLTAGE,
201 .n_voltages = 17,
202 .linear_ranges = rk808_ldo_voltage_ranges,
203 .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges),
204 .vsel_reg = RK808_LDO4_ON_VSEL_REG,
205 .vsel_mask = RK808_LDO_VSEL_MASK,
206 .enable_reg = RK808_LDO_EN_REG,
207 .enable_mask = BIT(3),
208 .owner = THIS_MODULE,
209 }, {
210 .name = "LDO_REG5",
211 .id = RK808_ID_LDO5,
212 .ops = &rk808_reg_ops,
213 .type = REGULATOR_VOLTAGE,
214 .n_voltages = 17,
215 .linear_ranges = rk808_ldo_voltage_ranges,
216 .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges),
217 .vsel_reg = RK808_LDO5_ON_VSEL_REG,
218 .vsel_mask = RK808_LDO_VSEL_MASK,
219 .enable_reg = RK808_LDO_EN_REG,
220 .enable_mask = BIT(4),
221 .owner = THIS_MODULE,
222 }, {
223 .name = "LDO_REG6",
224 .id = RK808_ID_LDO6,
225 .ops = &rk808_reg_ops,
226 .type = REGULATOR_VOLTAGE,
227 .n_voltages = 18,
228 .linear_ranges = rk808_ldo6_voltage_ranges,
229 .n_linear_ranges = ARRAY_SIZE(rk808_ldo6_voltage_ranges),
230 .vsel_reg = RK808_LDO6_ON_VSEL_REG,
231 .vsel_mask = RK808_LDO_VSEL_MASK,
232 .enable_reg = RK808_LDO_EN_REG,
233 .enable_mask = BIT(5),
234 .owner = THIS_MODULE,
235 }, {
236 .name = "LDO_REG7",
237 .id = RK808_ID_LDO7,
238 .ops = &rk808_reg_ops,
239 .type = REGULATOR_VOLTAGE,
240 .n_voltages = 18,
241 .linear_ranges = rk808_ldo6_voltage_ranges,
242 .n_linear_ranges = ARRAY_SIZE(rk808_ldo6_voltage_ranges),
243 .vsel_reg = RK808_LDO7_ON_VSEL_REG,
244 .vsel_mask = RK808_LDO_VSEL_MASK,
245 .enable_reg = RK808_LDO_EN_REG,
246 .enable_mask = BIT(6),
247 .owner = THIS_MODULE,
248 }, {
249 .name = "LDO_REG8",
250 .id = RK808_ID_LDO8,
251 .ops = &rk808_reg_ops,
252 .type = REGULATOR_VOLTAGE,
253 .n_voltages = 17,
254 .linear_ranges = rk808_ldo_voltage_ranges,
255 .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges),
256 .vsel_reg = RK808_LDO8_ON_VSEL_REG,
257 .vsel_mask = RK808_LDO_VSEL_MASK,
258 .enable_reg = RK808_LDO_EN_REG,
259 .enable_mask = BIT(7),
260 .owner = THIS_MODULE,
261 }, {
262 .name = "SWITCH_REG1",
263 .id = RK808_ID_SWITCH1,
264 .ops = &rk808_switch_ops,
265 .type = REGULATOR_VOLTAGE,
266 .enable_reg = RK808_DCDC_EN_REG,
267 .enable_mask = BIT(5),
268 .owner = THIS_MODULE,
269 }, {
270 .name = "SWITCH_REG2",
271 .id = RK808_ID_SWITCH2,
272 .ops = &rk808_switch_ops,
273 .type = REGULATOR_VOLTAGE,
274 .enable_reg = RK808_DCDC_EN_REG,
275 .enable_mask = BIT(6),
276 .owner = THIS_MODULE,
277 },
278};
279
280static struct of_regulator_match rk808_reg_matches[] = {
281 [RK808_ID_DCDC1] = { .name = "DCDC_REG1" },
282 [RK808_ID_DCDC2] = { .name = "DCDC_REG2" },
283 [RK808_ID_DCDC3] = { .name = "DCDC_REG3" },
284 [RK808_ID_DCDC4] = { .name = "DCDC_REG4" },
285 [RK808_ID_LDO1] = { .name = "LDO_REG1" },
286 [RK808_ID_LDO2] = { .name = "LDO_REG2" },
287 [RK808_ID_LDO3] = { .name = "LDO_REG3" },
288 [RK808_ID_LDO4] = { .name = "LDO_REG4" },
289 [RK808_ID_LDO5] = { .name = "LDO_REG5" },
290 [RK808_ID_LDO6] = { .name = "LDO_REG6" },
291 [RK808_ID_LDO7] = { .name = "LDO_REG7" },
292 [RK808_ID_LDO8] = { .name = "LDO_REG8" },
293 [RK808_ID_SWITCH1] = { .name = "SWITCH_REG1" },
294 [RK808_ID_SWITCH2] = { .name = "SWITCH_REG2" },
295};
296
Chris Zhong2a8d1302014-08-26 22:18:57 +0800297static int rk808_regulator_dts(struct i2c_client *client,
298 struct rk808_board *pdata)
Chris Zhong2cd64ae2014-08-20 11:36:42 +0800299{
Chris Zhong2cd64ae2014-08-20 11:36:42 +0800300 struct device_node *np, *reg_np;
301 int i, ret;
302
Chris Zhongd76c3332014-08-25 21:37:06 +0800303 np = client->dev.of_node;
Chris Zhong2cd64ae2014-08-20 11:36:42 +0800304 if (!np) {
Chris Zhongd76c3332014-08-25 21:37:06 +0800305 dev_err(&client->dev, "could not find pmic sub-node\n");
Chris Zhong2cd64ae2014-08-20 11:36:42 +0800306 return -ENXIO;
307 }
308
309 reg_np = of_get_child_by_name(np, "regulators");
310 if (!reg_np)
311 return -ENXIO;
312
Chris Zhongd76c3332014-08-25 21:37:06 +0800313 ret = of_regulator_match(&client->dev, reg_np, rk808_reg_matches,
Chris Zhong2cd64ae2014-08-20 11:36:42 +0800314 RK808_NUM_REGULATORS);
Chris Zhongd76c3332014-08-25 21:37:06 +0800315 if (ret < 0) {
316 dev_err(&client->dev,
Chris Zhong2cd64ae2014-08-20 11:36:42 +0800317 "failed to parse regulator data: %d\n", ret);
318 return ret;
319 }
320
321 for (i = 0; i < RK808_NUM_REGULATORS; i++) {
322 if (!rk808_reg_matches[i].init_data ||
323 !rk808_reg_matches[i].of_node)
324 continue;
325
326 pdata->rk808_init_data[i] = rk808_reg_matches[i].init_data;
327 pdata->of_node[i] = rk808_reg_matches[i].of_node;
328 }
329
330 return 0;
331}
332
333static int rk808_regulator_probe(struct platform_device *pdev)
334{
335 struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
Chris Zhongd76c3332014-08-25 21:37:06 +0800336 struct i2c_client *client = rk808->i2c;
Chris Zhong2a8d1302014-08-26 22:18:57 +0800337 struct rk808_board *pdata = dev_get_platdata(&client->dev);
Doug Anderson462004f2014-08-21 17:54:55 -0700338 struct regulator_config config = {};
Chris Zhong2cd64ae2014-08-20 11:36:42 +0800339 struct regulator_dev *rk808_rdev;
340 struct regulator_init_data *reg_data;
341 int i = 0;
342 int ret = 0;
343
Chris Zhong2cd64ae2014-08-20 11:36:42 +0800344 if (!pdata) {
Axel Linc61519f2014-08-28 21:04:49 +0800345 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
Chris Zhong2cd64ae2014-08-20 11:36:42 +0800346 if (!pdata)
347 return -ENOMEM;
348 }
349
Chris Zhong2a8d1302014-08-26 22:18:57 +0800350 ret = rk808_regulator_dts(client, pdata);
Chris Zhong2cd64ae2014-08-20 11:36:42 +0800351 if (ret)
352 return ret;
353
Chris Zhong2cd64ae2014-08-20 11:36:42 +0800354 /* Instantiate the regulators */
355 for (i = 0; i < RK808_NUM_REGULATORS; i++) {
356 reg_data = pdata->rk808_init_data[i];
357 if (!reg_data)
358 continue;
359
Chris Zhongd76c3332014-08-25 21:37:06 +0800360 config.dev = &client->dev;
Chris Zhong2cd64ae2014-08-20 11:36:42 +0800361 config.driver_data = rk808;
362 config.regmap = rk808->regmap;
363
Chris Zhongd76c3332014-08-25 21:37:06 +0800364 if (client->dev.of_node)
Chris Zhong2cd64ae2014-08-20 11:36:42 +0800365 config.of_node = pdata->of_node[i];
366
367 reg_data->supply_regulator = rk808_reg[i].name;
368 config.init_data = reg_data;
369
370 rk808_rdev = devm_regulator_register(&pdev->dev,
371 &rk808_reg[i], &config);
372 if (IS_ERR(rk808_rdev)) {
Chris Zhongd76c3332014-08-25 21:37:06 +0800373 dev_err(&client->dev,
Chris Zhong2cd64ae2014-08-20 11:36:42 +0800374 "failed to register %d regulator\n", i);
375 return PTR_ERR(rk808_rdev);
376 }
Chris Zhong2cd64ae2014-08-20 11:36:42 +0800377 }
378 return 0;
379}
380
381static struct platform_driver rk808_regulator_driver = {
382 .probe = rk808_regulator_probe,
383 .driver = {
384 .name = "rk808-regulator",
385 .owner = THIS_MODULE,
386 },
387};
388
389module_platform_driver(rk808_regulator_driver);
390
391MODULE_DESCRIPTION("regulator driver for the rk808 series PMICs");
392MODULE_AUTHOR("Chris Zhong<zyw@rock-chips.com>");
393MODULE_AUTHOR("Zhang Qing<zhanqging@rock-chips.com>");
394MODULE_LICENSE("GPL");
395MODULE_ALIAS("platform:rk808-regulator");