diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-13 12:04:35 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-13 12:04:35 -0800 |
commit | 8b0cab14951fbf8126795ab301835a8f8126a988 (patch) | |
tree | 2bf23662944ac9bfcd34d13ef81a6e331266ebf9 /drivers/regulator/tps6586x-regulator.c | |
parent | fd62c5450324af7f6cc12897b09b77285cd48a92 (diff) | |
parent | 4ffc45c3604dd8e283884ce006faf0e955cbd9e6 (diff) | |
download | linux-8b0cab14951fbf8126795ab301835a8f8126a988.tar.gz linux-8b0cab14951fbf8126795ab301835a8f8126a988.tar.bz2 linux-8b0cab14951fbf8126795ab301835a8f8126a988.zip |
Merge tag 'regulator-3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator
Pull regulator updates from Mark Brown:
"A fairly quiet release again, a couple of relatively small new
features and a bunch of driver specific work including yet more code
elimination and fixes from Axel Lin.
- Addidion of linear_min_sel for offsetting linear selectors in the
helpers.
- Support for continuous voltage ranges for regulators with extremely
high resolution.
- Drivers for AS3711, DA9055, MAX9873, TPS51632, TPS80031 and ARM
vexpress."
Fix up trivial conflict (due to typo fix) in palmas-regulator.c
* tag 'regulator-3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (80 commits)
regulator: core: Fix logic to determinate if regulator can change voltage
regulator: s5m8767: Fix to work even if no DVS gpio present
regulator: s5m8767: Fix to read the first DVS register.
regulator: s5m8767: Fix to work when platform registers less regulators
regulator: gpio-regulator: gpio_set_value should use cansleep
regulator: gpio-regulator: Fix logical error in for() loop
regulator: anatop: Use regulator_[get|set]_voltage_sel_regmap
regulator: anatop: Use linear_min_sel with linear mapping
regulator: max1586: Implement get_voltage_sel callback
regulator: lp8788-buck: Kill _gpio_request function
regulator: tps80031: Convert tps80031_ldo_ops to linear_min_sel and list_voltage_linear
regulator: lp8788-ldo: Remove val array in lp8788_config_ldo_enable_mode
regulator: gpio-regulator: Add ifdef CONFIG_OF guard for regulator_gpio_of_match
regulator: palmas: Convert palmas_ops_smps to regulator_[get|set]_voltage_sel_regmap
regulator: palmas: Return raw register values as the selectors in [get|set]_voltage_sel
regulators: add regulator_can_change_voltage() function
regulator: tps51632: Ensure [base|max]_voltage_uV pdata settings are valid
regulator: wm831x-dcdc: Add MODULE_ALIAS for wm831x-boostp
regulator: wm831x-dcdc: Ensure selected voltage falls within requested range
regulator: tps51632: Use linear_min_sel and regulator_[map|list]_voltage_linear
...
Diffstat (limited to 'drivers/regulator/tps6586x-regulator.c')
-rw-r--r-- | drivers/regulator/tps6586x-regulator.c | 189 |
1 files changed, 159 insertions, 30 deletions
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index ce1e7cb8d513..f86da672c758 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -17,10 +17,12 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/err.h> +#include <linux/of.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> #include <linux/mfd/tps6586x.h> /* supply control and voltage setting */ @@ -255,10 +257,10 @@ static inline int tps6586x_regulator_preinit(struct device *parent, 1 << ri->enable_bit[1]); } -static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev) +static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev, + int id, struct regulator_init_data *p) { struct device *parent = pdev->dev.parent; - struct regulator_init_data *p = pdev->dev.platform_data; struct tps6586x_settings *setting = p->driver_data; uint8_t reg; @@ -269,7 +271,7 @@ static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev) return 0; /* only SM0 and SM1 can have the slew rate settings */ - switch (pdev->id) { + switch (id) { case TPS6586X_ID_SM_0: reg = TPS6586X_SM0SL; break; @@ -298,58 +300,185 @@ static inline struct tps6586x_regulator *find_regulator_info(int id) return NULL; } -static int __devinit tps6586x_regulator_probe(struct platform_device *pdev) +#ifdef CONFIG_OF +static struct of_regulator_match tps6586x_matches[] = { + { .name = "sys", .driver_data = (void *)TPS6586X_ID_SYS }, + { .name = "sm0", .driver_data = (void *)TPS6586X_ID_SM_0 }, + { .name = "sm1", .driver_data = (void *)TPS6586X_ID_SM_1 }, + { .name = "sm2", .driver_data = (void *)TPS6586X_ID_SM_2 }, + { .name = "ldo0", .driver_data = (void *)TPS6586X_ID_LDO_0 }, + { .name = "ldo1", .driver_data = (void *)TPS6586X_ID_LDO_1 }, + { .name = "ldo2", .driver_data = (void *)TPS6586X_ID_LDO_2 }, + { .name = "ldo3", .driver_data = (void *)TPS6586X_ID_LDO_3 }, + { .name = "ldo4", .driver_data = (void *)TPS6586X_ID_LDO_4 }, + { .name = "ldo5", .driver_data = (void *)TPS6586X_ID_LDO_5 }, + { .name = "ldo6", .driver_data = (void *)TPS6586X_ID_LDO_6 }, + { .name = "ldo7", .driver_data = (void *)TPS6586X_ID_LDO_7 }, + { .name = "ldo8", .driver_data = (void *)TPS6586X_ID_LDO_8 }, + { .name = "ldo9", .driver_data = (void *)TPS6586X_ID_LDO_9 }, + { .name = "ldo_rtc", .driver_data = (void *)TPS6586X_ID_LDO_RTC }, +}; + +static struct tps6586x_platform_data *tps6586x_parse_regulator_dt( + struct platform_device *pdev, + struct of_regulator_match **tps6586x_reg_matches) +{ + const unsigned int num = ARRAY_SIZE(tps6586x_matches); + struct device_node *np = pdev->dev.parent->of_node; + struct device_node *regs; + const char *sys_rail = NULL; + unsigned int i; + struct tps6586x_platform_data *pdata; + int err; + + regs = of_find_node_by_name(np, "regulators"); + if (!regs) { + dev_err(&pdev->dev, "regulator node not found\n"); + return NULL; + } + + err = of_regulator_match(&pdev->dev, regs, tps6586x_matches, num); + if (err < 0) { + dev_err(&pdev->dev, "Regulator match failed, e %d\n", err); + of_node_put(regs); + return NULL; + } + + of_node_put(regs); + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "Memory alloction failed\n"); + return NULL; + } + + for (i = 0; i < num; i++) { + int id; + if (!tps6586x_matches[i].init_data) + continue; + + pdata->reg_init_data[i] = tps6586x_matches[i].init_data; + id = (int)tps6586x_matches[i].driver_data; + if (id == TPS6586X_ID_SYS) + sys_rail = pdata->reg_init_data[i]->constraints.name; + + if ((id == TPS6586X_ID_LDO_5) || (id == TPS6586X_ID_LDO_RTC)) + pdata->reg_init_data[i]->supply_regulator = sys_rail; + } + *tps6586x_reg_matches = tps6586x_matches; + return pdata; +} +#else +static struct tps6586x_platform_data *tps6586x_parse_regulator_dt( + struct platform_device *pdev, + struct of_regulator_match **tps6586x_reg_matches) +{ + *tps6586x_reg_matches = NULL; + return NULL; +} +#endif + +static int tps6586x_regulator_probe(struct platform_device *pdev) { struct tps6586x_regulator *ri = NULL; struct regulator_config config = { }; - struct regulator_dev *rdev; - int id = pdev->id; + struct regulator_dev **rdev; + struct regulator_init_data *reg_data; + struct tps6586x_platform_data *pdata; + struct of_regulator_match *tps6586x_reg_matches = NULL; + int id; int err; - dev_dbg(&pdev->dev, "Probing regulator %d\n", id); + dev_dbg(&pdev->dev, "Probing regulator\n"); - ri = find_regulator_info(id); - if (ri == NULL) { - dev_err(&pdev->dev, "invalid regulator ID specified\n"); - return -EINVAL; - } + pdata = dev_get_platdata(pdev->dev.parent); + if ((!pdata) && (pdev->dev.parent->of_node)) + pdata = tps6586x_parse_regulator_dt(pdev, + &tps6586x_reg_matches); - err = tps6586x_regulator_preinit(pdev->dev.parent, ri); - if (err) - return err; + if (!pdata) { + dev_err(&pdev->dev, "Platform data not available, exiting\n"); + return -ENODEV; + } - config.dev = pdev->dev.parent; - config.of_node = pdev->dev.of_node; - config.init_data = pdev->dev.platform_data; - config.driver_data = ri; + rdev = devm_kzalloc(&pdev->dev, TPS6586X_ID_MAX_REGULATOR * + sizeof(*rdev), GFP_KERNEL); + if (!rdev) { + dev_err(&pdev->dev, "Mmemory alloc failed\n"); + return -ENOMEM; + } - rdev = regulator_register(&ri->desc, &config); - if (IS_ERR(rdev)) { - dev_err(&pdev->dev, "failed to register regulator %s\n", - ri->desc.name); - return PTR_ERR(rdev); + for (id = 0; id < TPS6586X_ID_MAX_REGULATOR; ++id) { + reg_data = pdata->reg_init_data[id]; + + ri = find_regulator_info(id); + if (!ri) { + dev_err(&pdev->dev, "invalid regulator ID specified\n"); + err = -EINVAL; + goto fail; + } + + err = tps6586x_regulator_preinit(pdev->dev.parent, ri); + if (err) { + dev_err(&pdev->dev, + "regulator %d preinit failed, e %d\n", id, err); + goto fail; + } + + config.dev = pdev->dev.parent; + config.init_data = reg_data; + config.driver_data = ri; + + if (tps6586x_reg_matches) + config.of_node = tps6586x_reg_matches[id].of_node; + + rdev[id] = regulator_register(&ri->desc, &config); + if (IS_ERR(rdev[id])) { + dev_err(&pdev->dev, "failed to register regulator %s\n", + ri->desc.name); + err = PTR_ERR(rdev[id]); + goto fail; + } + + if (reg_data) { + err = tps6586x_regulator_set_slew_rate(pdev, id, + reg_data); + if (err < 0) { + dev_err(&pdev->dev, + "Slew rate config failed, e %d\n", err); + regulator_unregister(rdev[id]); + goto fail; + } + } } platform_set_drvdata(pdev, rdev); + return 0; - return tps6586x_regulator_set_slew_rate(pdev); +fail: + while (--id >= 0) + regulator_unregister(rdev[id]); + return err; } -static int __devexit tps6586x_regulator_remove(struct platform_device *pdev) +static int tps6586x_regulator_remove(struct platform_device *pdev) { - struct regulator_dev *rdev = platform_get_drvdata(pdev); + struct regulator_dev **rdev = platform_get_drvdata(pdev); + int id = TPS6586X_ID_MAX_REGULATOR; + + while (--id >= 0) + regulator_unregister(rdev[id]); - regulator_unregister(rdev); return 0; } static struct platform_driver tps6586x_regulator_driver = { .driver = { - .name = "tps6586x-regulator", + .name = "tps6586x-pmic", .owner = THIS_MODULE, }, .probe = tps6586x_regulator_probe, - .remove = __devexit_p(tps6586x_regulator_remove), + .remove = tps6586x_regulator_remove, }; static int __init tps6586x_regulator_init(void) |