diff options
author | Beniamino Galvani <b.galvani@gmail.com> | 2014-07-05 09:20:54 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-08-05 13:02:52 -0400 |
commit | 50a03e35b09ea5098ca42a59ad3fdb56a965f2dd (patch) | |
tree | f5217e74c7191916a2f55b1ea638cfeb0ee377ef /drivers/regulator/act8865-regulator.c | |
parent | bbb83f38a8b0702f1b333aef1e8a3aa14068cdc7 (diff) |
regulator: act8865: prepare support for other act88xx devices
This patch prepares support for other devices in the act88xx family of
PMUs manufactured by Active-Semi.
http://www.active-semi.com/products/power-management-units/act88xx/
Signed-off-by: Beniamino Galvani <b.galvani@gmail.com>
Tested-by: Wenyou Yang <wenyou.yang@atmel.com>
Reviewed-by: Axel Lin <axel.lin@ingics.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/regulator/act8865-regulator.c')
-rw-r--r-- | drivers/regulator/act8865-regulator.c | 211 |
1 files changed, 83 insertions, 128 deletions
diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index 52d1b6cad76f..b26eaf7580fc 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * act8865-regulator.c - Voltage regulation for the active-semi ACT8865 | 2 | * act8865-regulator.c - Voltage regulation for active-semi ACT88xx PMUs |
3 | * http://www.active-semi.com/sheets/ACT8865_Datasheet.pdf | 3 | * |
4 | * http://www.active-semi.com/products/power-management-units/act88xx/ | ||
4 | * | 5 | * |
5 | * Copyright (C) 2013 Atmel Corporation | 6 | * Copyright (C) 2013 Atmel Corporation |
6 | * | 7 | * |
@@ -70,7 +71,7 @@ static const struct regmap_config act8865_regmap_config = { | |||
70 | .val_bits = 8, | 71 | .val_bits = 8, |
71 | }; | 72 | }; |
72 | 73 | ||
73 | static const struct regulator_linear_range act8865_volatge_ranges[] = { | 74 | static const struct regulator_linear_range act8865_voltage_ranges[] = { |
74 | REGULATOR_LINEAR_RANGE(600000, 0, 23, 25000), | 75 | REGULATOR_LINEAR_RANGE(600000, 0, 23, 25000), |
75 | REGULATOR_LINEAR_RANGE(1200000, 24, 47, 50000), | 76 | REGULATOR_LINEAR_RANGE(1200000, 24, 47, 50000), |
76 | REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000), | 77 | REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000), |
@@ -86,110 +87,35 @@ static struct regulator_ops act8865_ops = { | |||
86 | .is_enabled = regulator_is_enabled_regmap, | 87 | .is_enabled = regulator_is_enabled_regmap, |
87 | }; | 88 | }; |
88 | 89 | ||
89 | static const struct regulator_desc act8865_reg[] = { | 90 | #define ACT88xx_REG(_name, _family, _id, _vsel_reg) \ |
90 | { | 91 | [_family##_ID_##_id] = { \ |
91 | .name = "DCDC_REG1", | 92 | .name = _name, \ |
92 | .id = ACT8865_ID_DCDC1, | 93 | .id = _family##_ID_##_id, \ |
93 | .ops = &act8865_ops, | 94 | .type = REGULATOR_VOLTAGE, \ |
94 | .type = REGULATOR_VOLTAGE, | 95 | .ops = &act8865_ops, \ |
95 | .n_voltages = ACT8865_VOLTAGE_NUM, | 96 | .n_voltages = ACT8865_VOLTAGE_NUM, \ |
96 | .linear_ranges = act8865_volatge_ranges, | 97 | .linear_ranges = act8865_voltage_ranges, \ |
97 | .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), | 98 | .n_linear_ranges = ARRAY_SIZE(act8865_voltage_ranges), \ |
98 | .vsel_reg = ACT8865_DCDC1_VSET1, | 99 | .vsel_reg = _family##_##_id##_##_vsel_reg, \ |
99 | .vsel_mask = ACT8865_VSEL_MASK, | 100 | .vsel_mask = ACT8865_VSEL_MASK, \ |
100 | .enable_reg = ACT8865_DCDC1_CTRL, | 101 | .enable_reg = _family##_##_id##_CTRL, \ |
101 | .enable_mask = ACT8865_ENA, | 102 | .enable_mask = ACT8865_ENA, \ |
102 | .owner = THIS_MODULE, | 103 | .owner = THIS_MODULE, \ |
103 | }, | 104 | } |
104 | { | 105 | |
105 | .name = "DCDC_REG2", | 106 | static const struct regulator_desc act8865_regulators[] = { |
106 | .id = ACT8865_ID_DCDC2, | 107 | ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET1), |
107 | .ops = &act8865_ops, | 108 | ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET1), |
108 | .type = REGULATOR_VOLTAGE, | 109 | ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET1), |
109 | .n_voltages = ACT8865_VOLTAGE_NUM, | 110 | ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET), |
110 | .linear_ranges = act8865_volatge_ranges, | 111 | ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET), |
111 | .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), | 112 | ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET), |
112 | .vsel_reg = ACT8865_DCDC2_VSET1, | 113 | ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET), |
113 | .vsel_mask = ACT8865_VSEL_MASK, | ||
114 | .enable_reg = ACT8865_DCDC2_CTRL, | ||
115 | .enable_mask = ACT8865_ENA, | ||
116 | .owner = THIS_MODULE, | ||
117 | }, | ||
118 | { | ||
119 | .name = "DCDC_REG3", | ||
120 | .id = ACT8865_ID_DCDC3, | ||
121 | .ops = &act8865_ops, | ||
122 | .type = REGULATOR_VOLTAGE, | ||
123 | .n_voltages = ACT8865_VOLTAGE_NUM, | ||
124 | .linear_ranges = act8865_volatge_ranges, | ||
125 | .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), | ||
126 | .vsel_reg = ACT8865_DCDC3_VSET1, | ||
127 | .vsel_mask = ACT8865_VSEL_MASK, | ||
128 | .enable_reg = ACT8865_DCDC3_CTRL, | ||
129 | .enable_mask = ACT8865_ENA, | ||
130 | .owner = THIS_MODULE, | ||
131 | }, | ||
132 | { | ||
133 | .name = "LDO_REG1", | ||
134 | .id = ACT8865_ID_LDO1, | ||
135 | .ops = &act8865_ops, | ||
136 | .type = REGULATOR_VOLTAGE, | ||
137 | .n_voltages = ACT8865_VOLTAGE_NUM, | ||
138 | .linear_ranges = act8865_volatge_ranges, | ||
139 | .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), | ||
140 | .vsel_reg = ACT8865_LDO1_VSET, | ||
141 | .vsel_mask = ACT8865_VSEL_MASK, | ||
142 | .enable_reg = ACT8865_LDO1_CTRL, | ||
143 | .enable_mask = ACT8865_ENA, | ||
144 | .owner = THIS_MODULE, | ||
145 | }, | ||
146 | { | ||
147 | .name = "LDO_REG2", | ||
148 | .id = ACT8865_ID_LDO2, | ||
149 | .ops = &act8865_ops, | ||
150 | .type = REGULATOR_VOLTAGE, | ||
151 | .n_voltages = ACT8865_VOLTAGE_NUM, | ||
152 | .linear_ranges = act8865_volatge_ranges, | ||
153 | .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), | ||
154 | .vsel_reg = ACT8865_LDO2_VSET, | ||
155 | .vsel_mask = ACT8865_VSEL_MASK, | ||
156 | .enable_reg = ACT8865_LDO2_CTRL, | ||
157 | .enable_mask = ACT8865_ENA, | ||
158 | .owner = THIS_MODULE, | ||
159 | }, | ||
160 | { | ||
161 | .name = "LDO_REG3", | ||
162 | .id = ACT8865_ID_LDO3, | ||
163 | .ops = &act8865_ops, | ||
164 | .type = REGULATOR_VOLTAGE, | ||
165 | .n_voltages = ACT8865_VOLTAGE_NUM, | ||
166 | .linear_ranges = act8865_volatge_ranges, | ||
167 | .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), | ||
168 | .vsel_reg = ACT8865_LDO3_VSET, | ||
169 | .vsel_mask = ACT8865_VSEL_MASK, | ||
170 | .enable_reg = ACT8865_LDO3_CTRL, | ||
171 | .enable_mask = ACT8865_ENA, | ||
172 | .owner = THIS_MODULE, | ||
173 | }, | ||
174 | { | ||
175 | .name = "LDO_REG4", | ||
176 | .id = ACT8865_ID_LDO4, | ||
177 | .ops = &act8865_ops, | ||
178 | .type = REGULATOR_VOLTAGE, | ||
179 | .n_voltages = ACT8865_VOLTAGE_NUM, | ||
180 | .linear_ranges = act8865_volatge_ranges, | ||
181 | .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), | ||
182 | .vsel_reg = ACT8865_LDO4_VSET, | ||
183 | .vsel_mask = ACT8865_VSEL_MASK, | ||
184 | .enable_reg = ACT8865_LDO4_CTRL, | ||
185 | .enable_mask = ACT8865_ENA, | ||
186 | .owner = THIS_MODULE, | ||
187 | }, | ||
188 | }; | 114 | }; |
189 | 115 | ||
190 | #ifdef CONFIG_OF | 116 | #ifdef CONFIG_OF |
191 | static const struct of_device_id act8865_dt_ids[] = { | 117 | static const struct of_device_id act8865_dt_ids[] = { |
192 | { .compatible = "active-semi,act8865" }, | 118 | { .compatible = "active-semi,act8865", .data = (void *)ACT8865 }, |
193 | { } | 119 | { } |
194 | }; | 120 | }; |
195 | MODULE_DEVICE_TABLE(of, act8865_dt_ids); | 121 | MODULE_DEVICE_TABLE(of, act8865_dt_ids); |
@@ -206,7 +132,9 @@ static struct of_regulator_match act8865_matches[] = { | |||
206 | 132 | ||
207 | static int act8865_pdata_from_dt(struct device *dev, | 133 | static int act8865_pdata_from_dt(struct device *dev, |
208 | struct device_node **of_node, | 134 | struct device_node **of_node, |
209 | struct act8865_platform_data *pdata) | 135 | struct act8865_platform_data *pdata, |
136 | struct of_regulator_match *matches, | ||
137 | int num_matches) | ||
210 | { | 138 | { |
211 | int matched, i; | 139 | int matched, i; |
212 | struct device_node *np; | 140 | struct device_node *np; |
@@ -218,26 +146,25 @@ static int act8865_pdata_from_dt(struct device *dev, | |||
218 | return -EINVAL; | 146 | return -EINVAL; |
219 | } | 147 | } |
220 | 148 | ||
221 | matched = of_regulator_match(dev, np, | 149 | matched = of_regulator_match(dev, np, matches, num_matches); |
222 | act8865_matches, ARRAY_SIZE(act8865_matches)); | ||
223 | of_node_put(np); | 150 | of_node_put(np); |
224 | if (matched <= 0) | 151 | if (matched <= 0) |
225 | return matched; | 152 | return matched; |
226 | 153 | ||
227 | pdata->regulators = devm_kzalloc(dev, | 154 | pdata->regulators = devm_kzalloc(dev, |
228 | sizeof(struct act8865_regulator_data) * | 155 | sizeof(struct act8865_regulator_data) * |
229 | ARRAY_SIZE(act8865_matches), GFP_KERNEL); | 156 | num_matches, GFP_KERNEL); |
230 | if (!pdata->regulators) | 157 | if (!pdata->regulators) |
231 | return -ENOMEM; | 158 | return -ENOMEM; |
232 | 159 | ||
233 | pdata->num_regulators = ARRAY_SIZE(act8865_matches); | 160 | pdata->num_regulators = num_matches; |
234 | regulator = pdata->regulators; | 161 | regulator = pdata->regulators; |
235 | 162 | ||
236 | for (i = 0; i < ARRAY_SIZE(act8865_matches); i++) { | 163 | for (i = 0; i < num_matches; i++) { |
237 | regulator->id = i; | 164 | regulator->id = i; |
238 | regulator->name = act8865_matches[i].name; | 165 | regulator->name = matches[i].name; |
239 | regulator->platform_data = act8865_matches[i].init_data; | 166 | regulator->platform_data = matches[i].init_data; |
240 | of_node[i] = act8865_matches[i].of_node; | 167 | of_node[i] = matches[i].of_node; |
241 | regulator++; | 168 | regulator++; |
242 | } | 169 | } |
243 | 170 | ||
@@ -269,34 +196,59 @@ static struct regulator_init_data | |||
269 | } | 196 | } |
270 | 197 | ||
271 | static int act8865_pmic_probe(struct i2c_client *client, | 198 | static int act8865_pmic_probe(struct i2c_client *client, |
272 | const struct i2c_device_id *i2c_id) | 199 | const struct i2c_device_id *i2c_id) |
273 | { | 200 | { |
274 | struct regulator_dev *rdev; | 201 | static const struct regulator_desc *regulators; |
202 | struct act8865_platform_data pdata_of, *pdata; | ||
203 | struct of_regulator_match *matches; | ||
275 | struct device *dev = &client->dev; | 204 | struct device *dev = &client->dev; |
276 | struct act8865_platform_data *pdata = dev_get_platdata(dev); | 205 | struct device_node **of_node; |
277 | struct regulator_config config = { }; | 206 | int i, ret, num_regulators; |
278 | struct act8865 *act8865; | 207 | struct act8865 *act8865; |
279 | struct device_node *of_node[ACT8865_REG_NUM]; | 208 | unsigned long type; |
280 | int i; | 209 | |
281 | int ret; | 210 | pdata = dev_get_platdata(dev); |
282 | 211 | ||
283 | if (dev->of_node && !pdata) { | 212 | if (dev->of_node && !pdata) { |
284 | const struct of_device_id *id; | 213 | const struct of_device_id *id; |
285 | struct act8865_platform_data pdata_of; | ||
286 | 214 | ||
287 | id = of_match_device(of_match_ptr(act8865_dt_ids), dev); | 215 | id = of_match_device(of_match_ptr(act8865_dt_ids), dev); |
288 | if (!id) | 216 | if (!id) |
289 | return -ENODEV; | 217 | return -ENODEV; |
290 | 218 | ||
291 | ret = act8865_pdata_from_dt(dev, of_node, &pdata_of); | 219 | type = (unsigned long) id->data; |
220 | } else { | ||
221 | type = i2c_id->driver_data; | ||
222 | } | ||
223 | |||
224 | switch (type) { | ||
225 | case ACT8865: | ||
226 | matches = act8865_matches; | ||
227 | regulators = act8865_regulators; | ||
228 | num_regulators = ARRAY_SIZE(act8865_regulators); | ||
229 | break; | ||
230 | default: | ||
231 | dev_err(dev, "invalid device id %lu\n", type); | ||
232 | return -EINVAL; | ||
233 | } | ||
234 | |||
235 | of_node = devm_kzalloc(dev, sizeof(struct device_node *) * | ||
236 | num_regulators, GFP_KERNEL); | ||
237 | if (!of_node) | ||
238 | return -ENOMEM; | ||
239 | |||
240 | if (dev->of_node && !pdata) { | ||
241 | ret = act8865_pdata_from_dt(dev, of_node, &pdata_of, matches, | ||
242 | num_regulators); | ||
292 | if (ret < 0) | 243 | if (ret < 0) |
293 | return ret; | 244 | return ret; |
294 | 245 | ||
295 | pdata = &pdata_of; | 246 | pdata = &pdata_of; |
296 | } | 247 | } |
297 | 248 | ||
298 | if (pdata->num_regulators > ACT8865_REG_NUM) { | 249 | if (pdata->num_regulators > num_regulators) { |
299 | dev_err(dev, "Too many regulators found!\n"); | 250 | dev_err(dev, "too many regulators: %d\n", |
251 | pdata->num_regulators); | ||
300 | return -EINVAL; | 252 | return -EINVAL; |
301 | } | 253 | } |
302 | 254 | ||
@@ -313,8 +265,10 @@ static int act8865_pmic_probe(struct i2c_client *client, | |||
313 | } | 265 | } |
314 | 266 | ||
315 | /* Finally register devices */ | 267 | /* Finally register devices */ |
316 | for (i = 0; i < ACT8865_REG_NUM; i++) { | 268 | for (i = 0; i < num_regulators; i++) { |
317 | const struct regulator_desc *desc = &act8865_reg[i]; | 269 | const struct regulator_desc *desc = ®ulators[i]; |
270 | struct regulator_config config = { }; | ||
271 | struct regulator_dev *rdev; | ||
318 | 272 | ||
319 | config.dev = dev; | 273 | config.dev = dev; |
320 | config.init_data = act8865_get_init_data(desc->id, pdata); | 274 | config.init_data = act8865_get_init_data(desc->id, pdata); |
@@ -330,12 +284,13 @@ static int act8865_pmic_probe(struct i2c_client *client, | |||
330 | } | 284 | } |
331 | 285 | ||
332 | i2c_set_clientdata(client, act8865); | 286 | i2c_set_clientdata(client, act8865); |
287 | devm_kfree(dev, of_node); | ||
333 | 288 | ||
334 | return 0; | 289 | return 0; |
335 | } | 290 | } |
336 | 291 | ||
337 | static const struct i2c_device_id act8865_ids[] = { | 292 | static const struct i2c_device_id act8865_ids[] = { |
338 | { "act8865", 0 }, | 293 | { .name = "act8865", .driver_data = ACT8865 }, |
339 | { }, | 294 | { }, |
340 | }; | 295 | }; |
341 | MODULE_DEVICE_TABLE(i2c, act8865_ids); | 296 | MODULE_DEVICE_TABLE(i2c, act8865_ids); |
@@ -351,6 +306,6 @@ static struct i2c_driver act8865_pmic_driver = { | |||
351 | 306 | ||
352 | module_i2c_driver(act8865_pmic_driver); | 307 | module_i2c_driver(act8865_pmic_driver); |
353 | 308 | ||
354 | MODULE_DESCRIPTION("active-semi act8865 voltage regulator driver"); | 309 | MODULE_DESCRIPTION("active-semi act88xx voltage regulator driver"); |
355 | MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>"); | 310 | MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>"); |
356 | MODULE_LICENSE("GPL v2"); | 311 | MODULE_LICENSE("GPL v2"); |