diff options
Diffstat (limited to 'drivers/regulator/da9211-regulator.c')
-rw-r--r-- | drivers/regulator/da9211-regulator.c | 174 |
1 files changed, 152 insertions, 22 deletions
diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index 1482adafa1ad..c78d2106d6cb 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * da9211-regulator.c - Regulator device driver for DA9211 | 2 | * da9211-regulator.c - Regulator device driver for DA9211/DA9213 |
3 | * Copyright (C) 2014 Dialog Semiconductor Ltd. | 3 | * Copyright (C) 2014 Dialog Semiconductor Ltd. |
4 | * | 4 | * |
5 | * This library is free software; you can redistribute it and/or | 5 | * This library is free software; you can redistribute it and/or |
@@ -24,9 +24,14 @@ | |||
24 | #include <linux/regmap.h> | 24 | #include <linux/regmap.h> |
25 | #include <linux/irq.h> | 25 | #include <linux/irq.h> |
26 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
27 | #include <linux/regulator/of_regulator.h> | ||
27 | #include <linux/regulator/da9211.h> | 28 | #include <linux/regulator/da9211.h> |
28 | #include "da9211-regulator.h" | 29 | #include "da9211-regulator.h" |
29 | 30 | ||
31 | /* DEVICE IDs */ | ||
32 | #define DA9211_DEVICE_ID 0x22 | ||
33 | #define DA9213_DEVICE_ID 0x23 | ||
34 | |||
30 | #define DA9211_BUCK_MODE_SLEEP 1 | 35 | #define DA9211_BUCK_MODE_SLEEP 1 |
31 | #define DA9211_BUCK_MODE_SYNC 2 | 36 | #define DA9211_BUCK_MODE_SYNC 2 |
32 | #define DA9211_BUCK_MODE_AUTO 3 | 37 | #define DA9211_BUCK_MODE_AUTO 3 |
@@ -42,6 +47,7 @@ struct da9211 { | |||
42 | struct regulator_dev *rdev[DA9211_MAX_REGULATORS]; | 47 | struct regulator_dev *rdev[DA9211_MAX_REGULATORS]; |
43 | int num_regulator; | 48 | int num_regulator; |
44 | int chip_irq; | 49 | int chip_irq; |
50 | int chip_id; | ||
45 | }; | 51 | }; |
46 | 52 | ||
47 | static const struct regmap_range_cfg da9211_regmap_range[] = { | 53 | static const struct regmap_range_cfg da9211_regmap_range[] = { |
@@ -52,14 +58,14 @@ static const struct regmap_range_cfg da9211_regmap_range[] = { | |||
52 | .window_start = 0, | 58 | .window_start = 0, |
53 | .window_len = 256, | 59 | .window_len = 256, |
54 | .range_min = 0, | 60 | .range_min = 0, |
55 | .range_max = 2*256, | 61 | .range_max = 5*128, |
56 | }, | 62 | }, |
57 | }; | 63 | }; |
58 | 64 | ||
59 | static const struct regmap_config da9211_regmap_config = { | 65 | static const struct regmap_config da9211_regmap_config = { |
60 | .reg_bits = 8, | 66 | .reg_bits = 8, |
61 | .val_bits = 8, | 67 | .val_bits = 8, |
62 | .max_register = 2 * 256, | 68 | .max_register = 5 * 128, |
63 | .ranges = da9211_regmap_range, | 69 | .ranges = da9211_regmap_range, |
64 | .num_ranges = ARRAY_SIZE(da9211_regmap_range), | 70 | .num_ranges = ARRAY_SIZE(da9211_regmap_range), |
65 | }; | 71 | }; |
@@ -69,11 +75,20 @@ static const struct regmap_config da9211_regmap_config = { | |||
69 | #define DA9211_MAX_MV 1570 | 75 | #define DA9211_MAX_MV 1570 |
70 | #define DA9211_STEP_MV 10 | 76 | #define DA9211_STEP_MV 10 |
71 | 77 | ||
72 | /* Current limits for buck (uA) indices corresponds with register values */ | 78 | /* Current limits for DA9211 buck (uA) indices |
79 | * corresponds with register values | ||
80 | */ | ||
73 | static const int da9211_current_limits[] = { | 81 | static const int da9211_current_limits[] = { |
74 | 2000000, 2200000, 2400000, 2600000, 2800000, 3000000, 3200000, 3400000, | 82 | 2000000, 2200000, 2400000, 2600000, 2800000, 3000000, 3200000, 3400000, |
75 | 3600000, 3800000, 4000000, 4200000, 4400000, 4600000, 4800000, 5000000 | 83 | 3600000, 3800000, 4000000, 4200000, 4400000, 4600000, 4800000, 5000000 |
76 | }; | 84 | }; |
85 | /* Current limits for DA9213 buck (uA) indices | ||
86 | * corresponds with register values | ||
87 | */ | ||
88 | static const int da9213_current_limits[] = { | ||
89 | 3000000, 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, | ||
90 | 4600000, 4800000, 5000000, 5200000, 5400000, 5600000, 5800000, 6000000 | ||
91 | }; | ||
77 | 92 | ||
78 | static unsigned int da9211_buck_get_mode(struct regulator_dev *rdev) | 93 | static unsigned int da9211_buck_get_mode(struct regulator_dev *rdev) |
79 | { | 94 | { |
@@ -129,12 +144,26 @@ static int da9211_set_current_limit(struct regulator_dev *rdev, int min, | |||
129 | { | 144 | { |
130 | int id = rdev_get_id(rdev); | 145 | int id = rdev_get_id(rdev); |
131 | struct da9211 *chip = rdev_get_drvdata(rdev); | 146 | struct da9211 *chip = rdev_get_drvdata(rdev); |
132 | int i; | 147 | int i, max_size; |
148 | const int *current_limits; | ||
149 | |||
150 | switch (chip->chip_id) { | ||
151 | case DA9211: | ||
152 | current_limits = da9211_current_limits; | ||
153 | max_size = ARRAY_SIZE(da9211_current_limits)-1; | ||
154 | break; | ||
155 | case DA9213: | ||
156 | current_limits = da9213_current_limits; | ||
157 | max_size = ARRAY_SIZE(da9213_current_limits)-1; | ||
158 | break; | ||
159 | default: | ||
160 | return -EINVAL; | ||
161 | } | ||
133 | 162 | ||
134 | /* search for closest to maximum */ | 163 | /* search for closest to maximum */ |
135 | for (i = ARRAY_SIZE(da9211_current_limits)-1; i >= 0; i--) { | 164 | for (i = max_size; i >= 0; i--) { |
136 | if (min <= da9211_current_limits[i] && | 165 | if (min <= current_limits[i] && |
137 | max >= da9211_current_limits[i]) { | 166 | max >= current_limits[i]) { |
138 | return regmap_update_bits(chip->regmap, | 167 | return regmap_update_bits(chip->regmap, |
139 | DA9211_REG_BUCK_ILIM, | 168 | DA9211_REG_BUCK_ILIM, |
140 | (0x0F << id*4), (i << id*4)); | 169 | (0x0F << id*4), (i << id*4)); |
@@ -150,14 +179,28 @@ static int da9211_get_current_limit(struct regulator_dev *rdev) | |||
150 | struct da9211 *chip = rdev_get_drvdata(rdev); | 179 | struct da9211 *chip = rdev_get_drvdata(rdev); |
151 | unsigned int data; | 180 | unsigned int data; |
152 | int ret; | 181 | int ret; |
182 | const int *current_limits; | ||
183 | |||
184 | switch (chip->chip_id) { | ||
185 | case DA9211: | ||
186 | current_limits = da9211_current_limits; | ||
187 | break; | ||
188 | case DA9213: | ||
189 | current_limits = da9213_current_limits; | ||
190 | break; | ||
191 | default: | ||
192 | return -EINVAL; | ||
193 | } | ||
153 | 194 | ||
154 | ret = regmap_read(chip->regmap, DA9211_REG_BUCK_ILIM, &data); | 195 | ret = regmap_read(chip->regmap, DA9211_REG_BUCK_ILIM, &data); |
155 | if (ret < 0) | 196 | if (ret < 0) |
156 | return ret; | 197 | return ret; |
157 | 198 | ||
158 | /* select one of 16 values: 0000 (2000mA) to 1111 (5000mA) */ | 199 | /* select one of 16 values: 0000 (2000mA or 3000mA) |
200 | * to 1111 (5000mA or 6000mA). | ||
201 | */ | ||
159 | data = (data >> id*4) & 0x0F; | 202 | data = (data >> id*4) & 0x0F; |
160 | return da9211_current_limits[data]; | 203 | return current_limits[data]; |
161 | } | 204 | } |
162 | 205 | ||
163 | static struct regulator_ops da9211_buck_ops = { | 206 | static struct regulator_ops da9211_buck_ops = { |
@@ -194,6 +237,59 @@ static struct regulator_desc da9211_regulators[] = { | |||
194 | DA9211_BUCK(BUCKB), | 237 | DA9211_BUCK(BUCKB), |
195 | }; | 238 | }; |
196 | 239 | ||
240 | #ifdef CONFIG_OF | ||
241 | static struct of_regulator_match da9211_matches[] = { | ||
242 | [DA9211_ID_BUCKA] = { .name = "BUCKA" }, | ||
243 | [DA9211_ID_BUCKB] = { .name = "BUCKB" }, | ||
244 | }; | ||
245 | |||
246 | static struct da9211_pdata *da9211_parse_regulators_dt( | ||
247 | struct device *dev) | ||
248 | { | ||
249 | struct da9211_pdata *pdata; | ||
250 | struct device_node *node; | ||
251 | int i, num, n; | ||
252 | |||
253 | node = of_get_child_by_name(dev->of_node, "regulators"); | ||
254 | if (!node) { | ||
255 | dev_err(dev, "regulators node not found\n"); | ||
256 | return ERR_PTR(-ENODEV); | ||
257 | } | ||
258 | |||
259 | num = of_regulator_match(dev, node, da9211_matches, | ||
260 | ARRAY_SIZE(da9211_matches)); | ||
261 | of_node_put(node); | ||
262 | if (num < 0) { | ||
263 | dev_err(dev, "Failed to match regulators\n"); | ||
264 | return ERR_PTR(-EINVAL); | ||
265 | } | ||
266 | |||
267 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | ||
268 | if (!pdata) | ||
269 | return ERR_PTR(-ENOMEM); | ||
270 | |||
271 | pdata->num_buck = num; | ||
272 | |||
273 | n = 0; | ||
274 | for (i = 0; i < ARRAY_SIZE(da9211_matches); i++) { | ||
275 | if (!da9211_matches[i].init_data) | ||
276 | continue; | ||
277 | |||
278 | pdata->init_data[n] = da9211_matches[i].init_data; | ||
279 | |||
280 | n++; | ||
281 | } | ||
282 | |||
283 | return pdata; | ||
284 | } | ||
285 | #else | ||
286 | static struct da9211_pdata *da9211_parse_regulators_dt( | ||
287 | struct device *dev) | ||
288 | { | ||
289 | return ERR_PTR(-ENODEV); | ||
290 | } | ||
291 | #endif | ||
292 | |||
197 | static irqreturn_t da9211_irq_handler(int irq, void *data) | 293 | static irqreturn_t da9211_irq_handler(int irq, void *data) |
198 | { | 294 | { |
199 | struct da9211 *chip = data; | 295 | struct da9211 *chip = data; |
@@ -264,13 +360,11 @@ static int da9211_regulator_init(struct da9211 *chip) | |||
264 | } | 360 | } |
265 | 361 | ||
266 | for (i = 0; i < chip->num_regulator; i++) { | 362 | for (i = 0; i < chip->num_regulator; i++) { |
267 | if (chip->pdata) | 363 | config.init_data = chip->pdata->init_data[i]; |
268 | config.init_data = | ||
269 | &(chip->pdata->init_data[i]); | ||
270 | |||
271 | config.dev = chip->dev; | 364 | config.dev = chip->dev; |
272 | config.driver_data = chip; | 365 | config.driver_data = chip; |
273 | config.regmap = chip->regmap; | 366 | config.regmap = chip->regmap; |
367 | config.of_node = chip->dev->of_node; | ||
274 | 368 | ||
275 | chip->rdev[i] = devm_regulator_register(chip->dev, | 369 | chip->rdev[i] = devm_regulator_register(chip->dev, |
276 | &da9211_regulators[i], &config); | 370 | &da9211_regulators[i], &config); |
@@ -282,7 +376,7 @@ static int da9211_regulator_init(struct da9211 *chip) | |||
282 | 376 | ||
283 | if (chip->chip_irq != 0) { | 377 | if (chip->chip_irq != 0) { |
284 | ret = regmap_update_bits(chip->regmap, | 378 | ret = regmap_update_bits(chip->regmap, |
285 | DA9211_REG_MASK_B, DA9211_M_OV_CURR_A << i, 1); | 379 | DA9211_REG_MASK_B, DA9211_M_OV_CURR_A << i, 0); |
286 | if (ret < 0) { | 380 | if (ret < 0) { |
287 | dev_err(chip->dev, | 381 | dev_err(chip->dev, |
288 | "Failed to update mask reg: %d\n", ret); | 382 | "Failed to update mask reg: %d\n", ret); |
@@ -293,6 +387,7 @@ static int da9211_regulator_init(struct da9211 *chip) | |||
293 | 387 | ||
294 | return 0; | 388 | return 0; |
295 | } | 389 | } |
390 | |||
296 | /* | 391 | /* |
297 | * I2C driver interface functions | 392 | * I2C driver interface functions |
298 | */ | 393 | */ |
@@ -301,14 +396,17 @@ static int da9211_i2c_probe(struct i2c_client *i2c, | |||
301 | { | 396 | { |
302 | struct da9211 *chip; | 397 | struct da9211 *chip; |
303 | int error, ret; | 398 | int error, ret; |
399 | unsigned int data; | ||
304 | 400 | ||
305 | chip = devm_kzalloc(&i2c->dev, sizeof(struct da9211), GFP_KERNEL); | 401 | chip = devm_kzalloc(&i2c->dev, sizeof(struct da9211), GFP_KERNEL); |
402 | if (!chip) | ||
403 | return -ENOMEM; | ||
306 | 404 | ||
307 | chip->dev = &i2c->dev; | 405 | chip->dev = &i2c->dev; |
308 | chip->regmap = devm_regmap_init_i2c(i2c, &da9211_regmap_config); | 406 | chip->regmap = devm_regmap_init_i2c(i2c, &da9211_regmap_config); |
309 | if (IS_ERR(chip->regmap)) { | 407 | if (IS_ERR(chip->regmap)) { |
310 | error = PTR_ERR(chip->regmap); | 408 | error = PTR_ERR(chip->regmap); |
311 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", | 409 | dev_err(chip->dev, "Failed to allocate register map: %d\n", |
312 | error); | 410 | error); |
313 | return error; | 411 | return error; |
314 | } | 412 | } |
@@ -316,11 +414,33 @@ static int da9211_i2c_probe(struct i2c_client *i2c, | |||
316 | i2c_set_clientdata(i2c, chip); | 414 | i2c_set_clientdata(i2c, chip); |
317 | 415 | ||
318 | chip->pdata = i2c->dev.platform_data; | 416 | chip->pdata = i2c->dev.platform_data; |
319 | if (!chip->pdata) { | 417 | |
320 | dev_err(&i2c->dev, "No platform init data supplied\n"); | 418 | ret = regmap_read(chip->regmap, DA9211_REG_DEVICE_ID, &data); |
419 | if (ret < 0) { | ||
420 | dev_err(chip->dev, "Failed to read DEVICE_ID reg: %d\n", ret); | ||
421 | return ret; | ||
422 | } | ||
423 | |||
424 | switch (data) { | ||
425 | case DA9211_DEVICE_ID: | ||
426 | chip->chip_id = DA9211; | ||
427 | break; | ||
428 | case DA9213_DEVICE_ID: | ||
429 | chip->chip_id = DA9213; | ||
430 | break; | ||
431 | default: | ||
432 | dev_err(chip->dev, "Unsupported device id = 0x%x.\n", data); | ||
321 | return -ENODEV; | 433 | return -ENODEV; |
322 | } | 434 | } |
323 | 435 | ||
436 | if (!chip->pdata) | ||
437 | chip->pdata = da9211_parse_regulators_dt(chip->dev); | ||
438 | |||
439 | if (IS_ERR(chip->pdata)) { | ||
440 | dev_err(chip->dev, "No regulators defined for the platform\n"); | ||
441 | return PTR_ERR(chip->pdata); | ||
442 | } | ||
443 | |||
324 | chip->chip_irq = i2c->irq; | 444 | chip->chip_irq = i2c->irq; |
325 | 445 | ||
326 | if (chip->chip_irq != 0) { | 446 | if (chip->chip_irq != 0) { |
@@ -340,22 +460,32 @@ static int da9211_i2c_probe(struct i2c_client *i2c, | |||
340 | ret = da9211_regulator_init(chip); | 460 | ret = da9211_regulator_init(chip); |
341 | 461 | ||
342 | if (ret < 0) | 462 | if (ret < 0) |
343 | dev_err(&i2c->dev, "Failed to initialize regulator: %d\n", ret); | 463 | dev_err(chip->dev, "Failed to initialize regulator: %d\n", ret); |
344 | 464 | ||
345 | return ret; | 465 | return ret; |
346 | } | 466 | } |
347 | 467 | ||
348 | static const struct i2c_device_id da9211_i2c_id[] = { | 468 | static const struct i2c_device_id da9211_i2c_id[] = { |
349 | {"da9211", 0}, | 469 | {"da9211", DA9211}, |
470 | {"da9213", DA9213}, | ||
350 | {}, | 471 | {}, |
351 | }; | 472 | }; |
352 | |||
353 | MODULE_DEVICE_TABLE(i2c, da9211_i2c_id); | 473 | MODULE_DEVICE_TABLE(i2c, da9211_i2c_id); |
354 | 474 | ||
475 | #ifdef CONFIG_OF | ||
476 | static const struct of_device_id da9211_dt_ids[] = { | ||
477 | { .compatible = "dlg,da9211", .data = &da9211_i2c_id[0] }, | ||
478 | { .compatible = "dlg,da9213", .data = &da9211_i2c_id[1] }, | ||
479 | {}, | ||
480 | }; | ||
481 | MODULE_DEVICE_TABLE(of, da9211_dt_ids); | ||
482 | #endif | ||
483 | |||
355 | static struct i2c_driver da9211_regulator_driver = { | 484 | static struct i2c_driver da9211_regulator_driver = { |
356 | .driver = { | 485 | .driver = { |
357 | .name = "da9211", | 486 | .name = "da9211", |
358 | .owner = THIS_MODULE, | 487 | .owner = THIS_MODULE, |
488 | .of_match_table = of_match_ptr(da9211_dt_ids), | ||
359 | }, | 489 | }, |
360 | .probe = da9211_i2c_probe, | 490 | .probe = da9211_i2c_probe, |
361 | .id_table = da9211_i2c_id, | 491 | .id_table = da9211_i2c_id, |
@@ -364,5 +494,5 @@ static struct i2c_driver da9211_regulator_driver = { | |||
364 | module_i2c_driver(da9211_regulator_driver); | 494 | module_i2c_driver(da9211_regulator_driver); |
365 | 495 | ||
366 | MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>"); | 496 | MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>"); |
367 | MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211"); | 497 | MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211/DA9213"); |
368 | MODULE_LICENSE("GPL v2"); | 498 | MODULE_LICENSE("GPL v2"); |