diff options
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/tps6586x-regulator.c | 181 |
1 files changed, 155 insertions, 26 deletions
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index b91400cdbd95..7206f4e3e760 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c | |||
@@ -17,10 +17,12 @@ | |||
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/err.h> | 19 | #include <linux/err.h> |
20 | #include <linux/of.h> | ||
20 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
21 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
22 | #include <linux/regulator/driver.h> | 23 | #include <linux/regulator/driver.h> |
23 | #include <linux/regulator/machine.h> | 24 | #include <linux/regulator/machine.h> |
25 | #include <linux/regulator/of_regulator.h> | ||
24 | #include <linux/mfd/tps6586x.h> | 26 | #include <linux/mfd/tps6586x.h> |
25 | 27 | ||
26 | /* supply control and voltage setting */ | 28 | /* supply control and voltage setting */ |
@@ -255,10 +257,10 @@ static inline int tps6586x_regulator_preinit(struct device *parent, | |||
255 | 1 << ri->enable_bit[1]); | 257 | 1 << ri->enable_bit[1]); |
256 | } | 258 | } |
257 | 259 | ||
258 | static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev) | 260 | static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev, |
261 | int id, struct regulator_init_data *p) | ||
259 | { | 262 | { |
260 | struct device *parent = pdev->dev.parent; | 263 | struct device *parent = pdev->dev.parent; |
261 | struct regulator_init_data *p = pdev->dev.platform_data; | ||
262 | struct tps6586x_settings *setting = p->driver_data; | 264 | struct tps6586x_settings *setting = p->driver_data; |
263 | uint8_t reg; | 265 | uint8_t reg; |
264 | 266 | ||
@@ -269,7 +271,7 @@ static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev) | |||
269 | return 0; | 271 | return 0; |
270 | 272 | ||
271 | /* only SM0 and SM1 can have the slew rate settings */ | 273 | /* only SM0 and SM1 can have the slew rate settings */ |
272 | switch (pdev->id) { | 274 | switch (id) { |
273 | case TPS6586X_ID_SM_0: | 275 | case TPS6586X_ID_SM_0: |
274 | reg = TPS6586X_SM0SL; | 276 | reg = TPS6586X_SM0SL; |
275 | break; | 277 | break; |
@@ -298,54 +300,181 @@ static inline struct tps6586x_regulator *find_regulator_info(int id) | |||
298 | return NULL; | 300 | return NULL; |
299 | } | 301 | } |
300 | 302 | ||
303 | #ifdef CONFIG_OF | ||
304 | static struct of_regulator_match tps6586x_matches[] = { | ||
305 | { .name = "sys", .driver_data = (void *)TPS6586X_ID_SYS }, | ||
306 | { .name = "sm0", .driver_data = (void *)TPS6586X_ID_SM_0 }, | ||
307 | { .name = "sm1", .driver_data = (void *)TPS6586X_ID_SM_1 }, | ||
308 | { .name = "sm2", .driver_data = (void *)TPS6586X_ID_SM_2 }, | ||
309 | { .name = "ldo0", .driver_data = (void *)TPS6586X_ID_LDO_0 }, | ||
310 | { .name = "ldo1", .driver_data = (void *)TPS6586X_ID_LDO_1 }, | ||
311 | { .name = "ldo2", .driver_data = (void *)TPS6586X_ID_LDO_2 }, | ||
312 | { .name = "ldo3", .driver_data = (void *)TPS6586X_ID_LDO_3 }, | ||
313 | { .name = "ldo4", .driver_data = (void *)TPS6586X_ID_LDO_4 }, | ||
314 | { .name = "ldo5", .driver_data = (void *)TPS6586X_ID_LDO_5 }, | ||
315 | { .name = "ldo6", .driver_data = (void *)TPS6586X_ID_LDO_6 }, | ||
316 | { .name = "ldo7", .driver_data = (void *)TPS6586X_ID_LDO_7 }, | ||
317 | { .name = "ldo8", .driver_data = (void *)TPS6586X_ID_LDO_8 }, | ||
318 | { .name = "ldo9", .driver_data = (void *)TPS6586X_ID_LDO_9 }, | ||
319 | { .name = "ldo_rtc", .driver_data = (void *)TPS6586X_ID_LDO_RTC }, | ||
320 | }; | ||
321 | |||
322 | static struct tps6586x_platform_data *tps6586x_parse_regulator_dt( | ||
323 | struct platform_device *pdev, | ||
324 | struct of_regulator_match **tps6586x_reg_matches) | ||
325 | { | ||
326 | const unsigned int num = ARRAY_SIZE(tps6586x_matches); | ||
327 | struct device_node *np = pdev->dev.parent->of_node; | ||
328 | struct device_node *regs; | ||
329 | const char *sys_rail = NULL; | ||
330 | unsigned int i; | ||
331 | struct tps6586x_platform_data *pdata; | ||
332 | int err; | ||
333 | |||
334 | regs = of_find_node_by_name(np, "regulators"); | ||
335 | if (!regs) { | ||
336 | dev_err(&pdev->dev, "regulator node not found\n"); | ||
337 | return NULL; | ||
338 | } | ||
339 | |||
340 | err = of_regulator_match(&pdev->dev, regs, tps6586x_matches, num); | ||
341 | if (err < 0) { | ||
342 | dev_err(&pdev->dev, "Regulator match failed, e %d\n", err); | ||
343 | of_node_put(regs); | ||
344 | return NULL; | ||
345 | } | ||
346 | |||
347 | of_node_put(regs); | ||
348 | |||
349 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
350 | if (!pdata) { | ||
351 | dev_err(&pdev->dev, "Memory alloction failed\n"); | ||
352 | return NULL; | ||
353 | } | ||
354 | |||
355 | for (i = 0; i < num; i++) { | ||
356 | int id; | ||
357 | if (!tps6586x_matches[i].init_data) | ||
358 | continue; | ||
359 | |||
360 | pdata->reg_init_data[i] = tps6586x_matches[i].init_data; | ||
361 | id = (int)tps6586x_matches[i].driver_data; | ||
362 | if (id == TPS6586X_ID_SYS) | ||
363 | sys_rail = pdata->reg_init_data[i]->constraints.name; | ||
364 | |||
365 | if ((id == TPS6586X_ID_LDO_5) || (id == TPS6586X_ID_LDO_RTC)) | ||
366 | pdata->reg_init_data[i]->supply_regulator = sys_rail; | ||
367 | } | ||
368 | *tps6586x_reg_matches = tps6586x_matches; | ||
369 | return pdata; | ||
370 | } | ||
371 | #else | ||
372 | static struct tps6586x_platform_data *tps6586x_parse_regulator_dt( | ||
373 | struct platform_device *pdev, | ||
374 | struct of_regulator_match **tps6586x_reg_matches) | ||
375 | { | ||
376 | *tps6586x_reg_matches = NULL; | ||
377 | return NULL; | ||
378 | } | ||
379 | #endif | ||
380 | |||
301 | static int tps6586x_regulator_probe(struct platform_device *pdev) | 381 | static int tps6586x_regulator_probe(struct platform_device *pdev) |
302 | { | 382 | { |
303 | struct tps6586x_regulator *ri = NULL; | 383 | struct tps6586x_regulator *ri = NULL; |
304 | struct regulator_config config = { }; | 384 | struct regulator_config config = { }; |
305 | struct regulator_dev *rdev; | 385 | struct regulator_dev **rdev; |
306 | int id = pdev->id; | 386 | struct regulator_init_data *reg_data; |
387 | struct tps6586x_platform_data *pdata; | ||
388 | struct of_regulator_match *tps6586x_reg_matches = NULL; | ||
389 | int id; | ||
307 | int err; | 390 | int err; |
308 | 391 | ||
309 | dev_dbg(&pdev->dev, "Probing regulator %d\n", id); | 392 | dev_dbg(&pdev->dev, "Probing regulator %d\n", id); |
310 | 393 | ||
311 | ri = find_regulator_info(id); | 394 | pdata = dev_get_platdata(pdev->dev.parent); |
312 | if (ri == NULL) { | 395 | if ((!pdata) && (pdev->dev.parent->of_node)) |
313 | dev_err(&pdev->dev, "invalid regulator ID specified\n"); | 396 | pdata = tps6586x_parse_regulator_dt(pdev, |
314 | return -EINVAL; | 397 | &tps6586x_reg_matches); |
315 | } | ||
316 | 398 | ||
317 | err = tps6586x_regulator_preinit(pdev->dev.parent, ri); | 399 | if (!pdata) { |
318 | if (err) | 400 | dev_err(&pdev->dev, "Platform data not available, exiting\n"); |
319 | return err; | 401 | return -ENODEV; |
402 | } | ||
320 | 403 | ||
321 | config.dev = pdev->dev.parent; | 404 | rdev = devm_kzalloc(&pdev->dev, TPS6586X_ID_MAX_REGULATOR * |
322 | config.of_node = pdev->dev.of_node; | 405 | sizeof(*rdev), GFP_KERNEL); |
323 | config.init_data = pdev->dev.platform_data; | 406 | if (!rdev) { |
324 | config.driver_data = ri; | 407 | dev_err(&pdev->dev, "Mmemory alloc failed\n"); |
408 | return -ENOMEM; | ||
409 | } | ||
325 | 410 | ||
326 | rdev = regulator_register(&ri->desc, &config); | 411 | for (id = 0; id < TPS6586X_ID_MAX_REGULATOR; ++id) { |
327 | if (IS_ERR(rdev)) { | 412 | reg_data = pdata->reg_init_data[id]; |
328 | dev_err(&pdev->dev, "failed to register regulator %s\n", | 413 | |
329 | ri->desc.name); | 414 | ri = find_regulator_info(id); |
330 | return PTR_ERR(rdev); | 415 | if (!ri) { |
416 | dev_err(&pdev->dev, "invalid regulator ID specified\n"); | ||
417 | err = -EINVAL; | ||
418 | goto fail; | ||
419 | } | ||
420 | |||
421 | err = tps6586x_regulator_preinit(pdev->dev.parent, ri); | ||
422 | if (err) { | ||
423 | dev_err(&pdev->dev, | ||
424 | "regulator %d preinit failed, e %d\n", id, err); | ||
425 | goto fail; | ||
426 | } | ||
427 | |||
428 | config.dev = pdev->dev.parent; | ||
429 | config.init_data = reg_data; | ||
430 | config.driver_data = ri; | ||
431 | |||
432 | if (tps6586x_reg_matches) | ||
433 | config.of_node = tps6586x_reg_matches[id].of_node; | ||
434 | |||
435 | rdev[id] = regulator_register(&ri->desc, &config); | ||
436 | if (IS_ERR(rdev[id])) { | ||
437 | dev_err(&pdev->dev, "failed to register regulator %s\n", | ||
438 | ri->desc.name); | ||
439 | err = PTR_ERR(rdev[id]); | ||
440 | goto fail; | ||
441 | } | ||
442 | |||
443 | if (reg_data) { | ||
444 | err = tps6586x_regulator_set_slew_rate(pdev, id, | ||
445 | reg_data); | ||
446 | if (err < 0) { | ||
447 | dev_err(&pdev->dev, | ||
448 | "Slew rate config failed, e %d\n", err); | ||
449 | regulator_unregister(rdev[id]); | ||
450 | goto fail; | ||
451 | } | ||
452 | } | ||
331 | } | 453 | } |
332 | 454 | ||
333 | platform_set_drvdata(pdev, rdev); | 455 | platform_set_drvdata(pdev, rdev); |
456 | return 0; | ||
334 | 457 | ||
335 | return tps6586x_regulator_set_slew_rate(pdev); | 458 | fail: |
459 | while (--id >= 0) | ||
460 | regulator_unregister(rdev[id]); | ||
461 | return err; | ||
336 | } | 462 | } |
337 | 463 | ||
338 | static int __devexit tps6586x_regulator_remove(struct platform_device *pdev) | 464 | static int __devexit tps6586x_regulator_remove(struct platform_device *pdev) |
339 | { | 465 | { |
340 | struct regulator_dev *rdev = platform_get_drvdata(pdev); | 466 | struct regulator_dev **rdev = platform_get_drvdata(pdev); |
467 | int id = TPS6586X_ID_MAX_REGULATOR; | ||
468 | |||
469 | while (--id >= 0) | ||
470 | regulator_unregister(rdev[id]); | ||
341 | 471 | ||
342 | regulator_unregister(rdev); | ||
343 | return 0; | 472 | return 0; |
344 | } | 473 | } |
345 | 474 | ||
346 | static struct platform_driver tps6586x_regulator_driver = { | 475 | static struct platform_driver tps6586x_regulator_driver = { |
347 | .driver = { | 476 | .driver = { |
348 | .name = "tps6586x-regulator", | 477 | .name = "tps6586x-pmic", |
349 | .owner = THIS_MODULE, | 478 | .owner = THIS_MODULE, |
350 | }, | 479 | }, |
351 | .probe = tps6586x_regulator_probe, | 480 | .probe = tps6586x_regulator_probe, |