aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2014-09-05 20:11:12 -0400
committerMark Brown <broonie@kernel.org>2014-09-06 07:43:05 -0400
commitdec38b5ce6a9edb406c60c2670b26a1a4262fdb9 (patch)
tree7737715381578ebb888592852984a977763bf16d
parent87ca186f7eb663fc5e52b65452a91fe0fec170a0 (diff)
regulator: isl9305: Add Intersil ISL9305/H driver
The ISL9305 and ISL9305H are mini-PMICs offering two DCDC regulators and two LDO regulators. While there are some register differences between them these do not affect the current Linux driver as the relevant features are not yet supported. Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--Documentation/devicetree/bindings/regulator/isl9305.txt36
-rw-r--r--drivers/regulator/Kconfig6
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/isl9305.c247
-rw-r--r--include/linux/platform_data/isl9305.h30
5 files changed, 320 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/regulator/isl9305.txt b/Documentation/devicetree/bindings/regulator/isl9305.txt
new file mode 100644
index 000000000000..a626fc1bbf0d
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/isl9305.txt
@@ -0,0 +1,36 @@
1Intersil ISL9305/ISL9305H voltage regulator
2
3Required properties:
4
5- compatible: "isl,isl9305" or "isl,isl9305h"
6- reg: I2C slave address, usually 0x68.
7- regulators: A node that houses a sub-node for each regulator within the
8 device. Each sub-node is identified using the node's name, with valid
9 values being "dcd1", "dcd2", "ldo1" and "ldo2". The content of each sub-node
10 is defined by the standard binding for regulators; see regulator.txt.
11- VINDCD1-supply: A phandle to a regulator node supplying VINDCD1.
12 VINDCD2-supply: A phandle to a regulator node supplying VINDCD2.
13 VINLDO1-supply: A phandle to a regulator node supplying VINLDO1.
14 VINLDO2-supply: A phandle to a regulator node supplying VINLDO2.
15
16Optional properties:
17- Per-regulator optional properties are defined in regulator.txt
18
19Example
20
21 pmic: isl9305@68 {
22 compatible = "isl,isl9305";
23 reg = <0x68>;
24
25 VINDCD1-supply = <&system_power>;
26 VINDCD2-supply = <&system_power>;
27 VINLDO1-supply = <&system_power>;
28 VINLDO2-supply = <&system_power>;
29
30 regulators {
31 dcd1 {
32 regulator-name = "VDD_DSP";
33 regulator-always-on;
34 };
35 };
36 };
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index e6b98ed4c12f..3c8b6f401e4f 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -250,6 +250,12 @@ config REGULATOR_HI6421
250 21 general purpose LDOs, 3 dedicated LDOs, and 5 BUCKs. All 250 21 general purpose LDOs, 3 dedicated LDOs, and 5 BUCKs. All
251 of them come with support to either ECO (idle) or sleep mode. 251 of them come with support to either ECO (idle) or sleep mode.
252 252
253config REGULATOR_ISL9305
254 tristate "Intersil ISL9305 regulator"
255 depends on I2C
256 help
257 This driver supports ISL9305 voltage regulator chip.
258
253config REGULATOR_ISL6271A 259config REGULATOR_ISL6271A
254 tristate "Intersil ISL6271A Power regulator" 260 tristate "Intersil ISL6271A Power regulator"
255 depends on I2C 261 depends on I2C
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 5513e2c141b1..e12fee8c943b 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o
34obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o 34obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
35obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o 35obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o
36obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o 36obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
37obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
37obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o 38obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
38obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o 39obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
39obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o 40obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
diff --git a/drivers/regulator/isl9305.c b/drivers/regulator/isl9305.c
new file mode 100644
index 000000000000..b0d12d186b68
--- /dev/null
+++ b/drivers/regulator/isl9305.c
@@ -0,0 +1,247 @@
1/*
2 * isl9305 - Intersil ISL9305 DCDC regulator
3 *
4 * Copyright 2014 Linaro Ltd
5 *
6 * Author: Mark Brown <broonie@kernel.org>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14#include <linux/module.h>
15#include <linux/err.h>
16#include <linux/i2c.h>
17#include <linux/of.h>
18#include <linux/platform_data/isl9305.h>
19#include <linux/regmap.h>
20#include <linux/regulator/driver.h>
21#include <linux/regulator/of_regulator.h>
22#include <linux/slab.h>
23
24/*
25 * Registers
26 */
27#define ISL9305_DCD1OUT 0x0
28#define ISL9305_DCD2OUT 0x1
29#define ISL9305_LDO1OUT 0x2
30#define ISL9305_LDO2OUT 0x3
31#define ISL9305_DCD_PARAMETER 0x4
32#define ISL9305_SYSTEM_PARAMETER 0x5
33#define ISL9305_DCD_SRCTL 0x6
34
35#define ISL9305_MAX_REG ISL9305_DCD_SRCTL
36
37/*
38 * DCD_PARAMETER
39 */
40#define ISL9305_DCD_PHASE 0x40
41#define ISL9305_DCD2_ULTRA 0x20
42#define ISL9305_DCD1_ULTRA 0x10
43#define ISL9305_DCD2_BLD 0x08
44#define ISL9305_DCD1_BLD 0x04
45#define ISL9305_DCD2_MODE 0x02
46#define ISL9305_DCD1_MODE 0x01
47
48/*
49 * SYSTEM_PARAMETER
50 */
51#define ISL9305_I2C_EN 0x40
52#define ISL9305_DCDPOR_MASK 0x30
53#define ISL9305_LDO2_EN 0x08
54#define ISL9305_LDO1_EN 0x04
55#define ISL9305_DCD2_EN 0x02
56#define ISL9305_DCD1_EN 0x01
57
58/*
59 * DCD_SRCTL
60 */
61#define ISL9305_DCD2SR_MASK 0xc0
62#define ISL9305_DCD1SR_MASK 0x07
63
64static const struct regulator_ops isl9305_ops = {
65 .enable = regulator_enable_regmap,
66 .disable = regulator_disable_regmap,
67 .is_enabled = regulator_is_enabled_regmap,
68 .list_voltage = regulator_list_voltage_linear,
69 .get_voltage_sel = regulator_get_voltage_sel_regmap,
70 .set_voltage_sel = regulator_set_voltage_sel_regmap,
71};
72
73static const struct regulator_desc isl9305_regulators[] = {
74 [ISL9305_DCD1] = {
75 .name = "DCD1",
76 .n_voltages = 0x70,
77 .min_uV = 825000,
78 .uV_step = 25000,
79 .vsel_reg = ISL9305_DCD1OUT,
80 .vsel_mask = 0x7f,
81 .enable_reg = ISL9305_SYSTEM_PARAMETER,
82 .enable_mask = ISL9305_DCD1_EN,
83 .supply_name = "VINDCD1",
84 .ops = &isl9305_ops,
85 },
86 [ISL9305_DCD2] = {
87 .name = "DCD2",
88 .n_voltages = 0x70,
89 .min_uV = 825000,
90 .uV_step = 25000,
91 .vsel_reg = ISL9305_DCD2OUT,
92 .vsel_mask = 0x7f,
93 .enable_reg = ISL9305_SYSTEM_PARAMETER,
94 .enable_mask = ISL9305_DCD2_EN,
95 .supply_name = "VINDCD2",
96 .ops = &isl9305_ops,
97 },
98 [ISL9305_LDO1] = {
99 .name = "LDO1",
100 .n_voltages = 0x37,
101 .min_uV = 900000,
102 .uV_step = 50000,
103 .vsel_reg = ISL9305_LDO1OUT,
104 .vsel_mask = 0x3f,
105 .enable_reg = ISL9305_SYSTEM_PARAMETER,
106 .enable_mask = ISL9305_LDO1_EN,
107 .supply_name = "VINLDO1",
108 .ops = &isl9305_ops,
109 },
110 [ISL9305_LDO2] = {
111 .name = "LDO2",
112 .n_voltages = 0x37,
113 .min_uV = 900000,
114 .uV_step = 50000,
115 .vsel_reg = ISL9305_LDO2OUT,
116 .vsel_mask = 0x3f,
117 .enable_reg = ISL9305_SYSTEM_PARAMETER,
118 .enable_mask = ISL9305_LDO2_EN,
119 .supply_name = "VINLDO2",
120 .ops = &isl9305_ops,
121 },
122};
123
124#ifdef CONFIG_OF
125static struct of_regulator_match isl9305_reg_matches[] = {
126 [ISL9305_DCD1] = { .name = "dcd1" },
127 [ISL9305_DCD2] = { .name = "dcd2" },
128 [ISL9305_LDO1] = { .name = "ldo1" },
129 [ISL9305_LDO2] = { .name = "ldo2" },
130};
131
132static struct of_regulator_match *isl9305_parse_dt(struct i2c_client *i2c)
133{
134 struct device_node *node = i2c->dev.of_node;
135 struct of_regulator_match *matches;
136 struct device_node *regs;
137 int count;
138
139 regs = of_get_child_by_name(node, "regulators");
140 if (!regs)
141 return NULL;
142
143 matches = devm_kmemdup(&i2c->dev, isl9305_reg_matches,
144 sizeof(isl9305_reg_matches), GFP_KERNEL);
145 if (!matches)
146 return NULL;
147
148 count = of_regulator_match(&i2c->dev, regs, matches,
149 ARRAY_SIZE(isl9305_reg_matches));
150 of_node_put(regs);
151 if ((count < 0) || (count > ARRAY_SIZE(isl9305_reg_matches)))
152 return NULL;
153
154 return matches;
155}
156#else
157static struct of_regulator_match *isl9305_parse_dt(struct i2c_client *i2c)
158{
159 return NULL;
160}
161#endif
162
163static const struct regmap_config isl9305_regmap = {
164 .reg_bits = 8,
165 .val_bits = 8,
166
167 .max_register = ISL9305_MAX_REG,
168 .cache_type = REGCACHE_RBTREE,
169};
170
171static int isl9305_i2c_probe(struct i2c_client *i2c,
172 const struct i2c_device_id *id)
173{
174 struct regulator_config config = { };
175 struct isl9305_pdata *pdata = i2c->dev.platform_data;
176 struct of_regulator_match *of_matches;
177 struct regulator_dev *rdev;
178 struct regmap *regmap;
179 int i, ret;
180
181 of_matches = isl9305_parse_dt(i2c);
182
183 regmap = devm_regmap_init_i2c(i2c, &isl9305_regmap);
184 if (IS_ERR(regmap)) {
185 ret = PTR_ERR(regmap);
186 dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret);
187 return ret;
188 }
189
190 config.dev = &i2c->dev;
191
192 for (i = 0; i < ARRAY_SIZE(isl9305_regulators); i++) {
193 config.of_node = NULL;
194 config.init_data = NULL;
195
196 if (of_matches) {
197 config.init_data = of_matches[i].init_data;
198 config.of_node = of_matches[i].of_node;
199 }
200
201 if (!config.init_data && pdata)
202 config.init_data = pdata->init_data[i];
203
204 rdev = devm_regulator_register(&i2c->dev,
205 &isl9305_regulators[i],
206 &config);
207 if (IS_ERR(rdev)) {
208 ret = PTR_ERR(rdev);
209 dev_err(&i2c->dev, "Failed to register %s: %d\n",
210 isl9305_regulators[i].name, ret);
211 return ret;
212 }
213 }
214
215 return 0;
216}
217
218#ifdef CONFIG_OF
219static const struct of_device_id isl9305_dt_ids[] = {
220 { .compatible = "isl,isl9305" },
221 { .compatible = "isl,isl9305h" },
222 {},
223};
224#endif
225
226static const struct i2c_device_id isl9305_i2c_id[] = {
227 { "isl9305", },
228 { "isl9305h", },
229 { }
230};
231MODULE_DEVICE_TABLE(i2c, isl9305_i2c_id);
232
233static struct i2c_driver isl9305_regulator_driver = {
234 .driver = {
235 .name = "isl9305",
236 .owner = THIS_MODULE,
237 .of_match_table = of_match_ptr(isl9305_dt_ids),
238 },
239 .probe = isl9305_i2c_probe,
240 .id_table = isl9305_i2c_id,
241};
242
243module_i2c_driver(isl9305_regulator_driver);
244
245MODULE_AUTHOR("Mark Brown");
246MODULE_DESCRIPTION("Intersil ISL9305 DCDC regulator");
247MODULE_LICENSE("GPL");
diff --git a/include/linux/platform_data/isl9305.h b/include/linux/platform_data/isl9305.h
new file mode 100644
index 000000000000..1419133fa69e
--- /dev/null
+++ b/include/linux/platform_data/isl9305.h
@@ -0,0 +1,30 @@
1/*
2 * isl9305 - Intersil ISL9305 DCDC regulator
3 *
4 * Copyright 2014 Linaro Ltd
5 *
6 * Author: Mark Brown <broonie@kernel.org>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14#ifndef __ISL9305_H
15#define __ISL9305_H
16
17#define ISL9305_DCD1 0
18#define ISL9305_DCD2 1
19#define ISL9305_LDO1 2
20#define ISL9305_LDO2 3
21
22#define ISL9305_MAX_REGULATOR ISL9305_LDO2
23
24struct regulator_init_data;
25
26struct isl9305_pdata {
27 struct regulator_init_data *init_data[ISL9305_MAX_REGULATOR];
28};
29
30#endif