diff options
Diffstat (limited to 'drivers/regulator/da9052-regulator.c')
| -rw-r--r-- | drivers/regulator/da9052-regulator.c | 233 |
1 files changed, 128 insertions, 105 deletions
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index 96b569abb46c..fbebe538a648 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -1,16 +1,10 @@ -/* -* da9052-regulator.c: Regulator driver for DA9052 -* -* Copyright(c) 2011 Dialog Semiconductor Ltd. -* -* Author: David Dajun Chen <dchen@diasemi.com> -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -*/ +// SPDX-License-Identifier: GPL-2.0+ +// +// da9052-regulator.c: Regulator driver for DA9052 +// +// Copyright(c) 2011 Dialog Semiconductor Ltd. +// +// Author: David Dajun Chen <dchen@diasemi.com> #include <linux/module.h> #include <linux/moduleparam.h> @@ -19,10 +13,8 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> -#ifdef CONFIG_OF #include <linux/of.h> #include <linux/regulator/of_regulator.h> -#endif #include <linux/mfd/da9052/da9052.h> #include <linux/mfd/da9052/reg.h> @@ -70,15 +62,16 @@ struct da9052_regulator_info { int step_uV; int min_uV; int max_uV; + unsigned char activate_bit; }; struct da9052_regulator { struct da9052 *da9052; - struct da9052_regulator_info *info; + const struct da9052_regulator_info *info; struct regulator_dev *rdev; }; -static int verify_range(struct da9052_regulator_info *info, +static int verify_range(const struct da9052_regulator_info *info, int min_uV, int max_uV) { if (min_uV > info->max_uV || max_uV < info->min_uV) @@ -158,7 +151,7 @@ static int da9052_list_voltage(struct regulator_dev *rdev, unsigned int selector) { struct da9052_regulator *regulator = rdev_get_drvdata(rdev); - struct da9052_regulator_info *info = regulator->info; + const struct da9052_regulator_info *info = regulator->info; int id = rdev_get_id(rdev); int volt_uV; @@ -182,7 +175,7 @@ static int da9052_map_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) { struct da9052_regulator *regulator = rdev_get_drvdata(rdev); - struct da9052_regulator_info *info = regulator->info; + const struct da9052_regulator_info *info = regulator->info; int id = rdev_get_id(rdev); int ret, sel; @@ -209,33 +202,93 @@ static int da9052_map_voltage(struct regulator_dev *rdev, return sel; } -static struct regulator_ops da9052_dcdc_ops = { +static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + const struct da9052_regulator_info *info = regulator->info; + int id = rdev_get_id(rdev); + int ret; + + ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, selector); + if (ret < 0) + return ret; + + /* Some LDOs and DCDCs are DVC controlled which requires enabling of + * the activate bit to implment the changes on the output. + */ + switch (id) { + case DA9052_ID_BUCK1: + case DA9052_ID_BUCK2: + case DA9052_ID_BUCK3: + case DA9052_ID_LDO2: + case DA9052_ID_LDO3: + ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, + info->activate_bit, info->activate_bit); + break; + } + + return ret; +} + +static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_sel, + unsigned int new_sel) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + const struct da9052_regulator_info *info = regulator->info; + int id = rdev_get_id(rdev); + int ret = 0; + + /* The DVC controlled LDOs and DCDCs ramp with 6.25mV/µs after enabling + * the activate bit. + */ + switch (id) { + case DA9052_ID_BUCK1: + case DA9052_ID_BUCK2: + case DA9052_ID_BUCK3: + case DA9052_ID_LDO2: + case DA9052_ID_LDO3: + ret = DIV_ROUND_UP(abs(new_sel - old_sel) * info->step_uV, + 6250); + break; + } + + return ret; +} + +static const struct regulator_ops da9052_dcdc_ops = { .get_current_limit = da9052_dcdc_get_current_limit, .set_current_limit = da9052_dcdc_set_current_limit, .list_voltage = da9052_list_voltage, .map_voltage = da9052_map_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_sel = da9052_regulator_set_voltage_sel, + .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, }; -static struct regulator_ops da9052_ldo_ops = { +static const struct regulator_ops da9052_ldo_ops = { .list_voltage = da9052_list_voltage, .map_voltage = da9052_map_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_sel = da9052_regulator_set_voltage_sel, + .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, }; -#define DA9052_LDO(_id, step, min, max, sbits, ebits, abits) \ +#define DA9052_LDO(_id, _name, step, min, max, sbits, ebits, abits) \ {\ .reg_desc = {\ - .name = #_id,\ + .name = #_name,\ + .of_match = of_match_ptr(#_name),\ + .regulators_node = of_match_ptr("regulators"),\ .ops = &da9052_ldo_ops,\ .type = REGULATOR_VOLTAGE,\ .id = DA9052_ID_##_id,\ @@ -243,20 +296,21 @@ static struct regulator_ops da9052_ldo_ops = { .owner = THIS_MODULE,\ .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .vsel_mask = (1 << (sbits)) - 1,\ - .apply_reg = DA9052_SUPPLY_REG, \ - .apply_bit = (abits), \ .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .enable_mask = 1 << (ebits),\ },\ .min_uV = (min) * 1000,\ .max_uV = (max) * 1000,\ .step_uV = (step) * 1000,\ + .activate_bit = (abits),\ } -#define DA9052_DCDC(_id, step, min, max, sbits, ebits, abits) \ +#define DA9052_DCDC(_id, _name, step, min, max, sbits, ebits, abits) \ {\ .reg_desc = {\ - .name = #_id,\ + .name = #_name,\ + .of_match = of_match_ptr(#_name),\ + .regulators_node = of_match_ptr("regulators"),\ .ops = &da9052_dcdc_ops,\ .type = REGULATOR_VOLTAGE,\ .id = DA9052_ID_##_id,\ @@ -264,54 +318,53 @@ static struct regulator_ops da9052_ldo_ops = { .owner = THIS_MODULE,\ .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .vsel_mask = (1 << (sbits)) - 1,\ - .apply_reg = DA9052_SUPPLY_REG, \ - .apply_bit = (abits), \ .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .enable_mask = 1 << (ebits),\ },\ .min_uV = (min) * 1000,\ .max_uV = (max) * 1000,\ .step_uV = (step) * 1000,\ + .activate_bit = (abits),\ } -static struct da9052_regulator_info da9052_regulator_info[] = { - DA9052_DCDC(BUCK1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), - DA9052_DCDC(BUCK2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), - DA9052_DCDC(BUCK3, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO), - DA9052_DCDC(BUCK4, 50, 1800, 3600, 5, 6, 0), - DA9052_LDO(LDO1, 50, 600, 1800, 5, 6, 0), - DA9052_LDO(LDO2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), - DA9052_LDO(LDO3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), - DA9052_LDO(LDO4, 25, 1725, 3300, 6, 6, 0), - DA9052_LDO(LDO5, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(LDO6, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(LDO7, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(LDO8, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(LDO9, 50, 1250, 3650, 6, 6, 0), - DA9052_LDO(LDO10, 50, 1200, 3600, 6, 6, 0), +static const struct da9052_regulator_info da9052_regulator_info[] = { + DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), + DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), + DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO), + DA9052_DCDC(BUCK4, buck4, 50, 1800, 3600, 5, 6, 0), + DA9052_LDO(LDO1, ldo1, 50, 600, 1800, 5, 6, 0), + DA9052_LDO(LDO2, ldo2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), + DA9052_LDO(LDO3, ldo3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), + DA9052_LDO(LDO4, ldo4, 25, 1725, 3300, 6, 6, 0), + DA9052_LDO(LDO5, ldo5, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO6, ldo6, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO7, ldo7, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO8, ldo8, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO9, ldo9, 50, 1250, 3650, 6, 6, 0), + DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0), }; -static struct da9052_regulator_info da9053_regulator_info[] = { - DA9052_DCDC(BUCK1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), - DA9052_DCDC(BUCK2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), - DA9052_DCDC(BUCK3, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO), - DA9052_DCDC(BUCK4, 25, 925, 2500, 6, 6, 0), - DA9052_LDO(LDO1, 50, 600, 1800, 5, 6, 0), - DA9052_LDO(LDO2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), - DA9052_LDO(LDO3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), - DA9052_LDO(LDO4, 25, 1725, 3300, 6, 6, 0), - DA9052_LDO(LDO5, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(LDO6, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(LDO7, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(LDO8, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(LDO9, 50, 1250, 3650, 6, 6, 0), - DA9052_LDO(LDO10, 50, 1200, 3600, 6, 6, 0), +static const struct da9052_regulator_info da9053_regulator_info[] = { + DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), + DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), + DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO), + DA9052_DCDC(BUCK4, buck4, 25, 950, 2525, 6, 6, 0), + DA9052_LDO(LDO1, ldo1, 50, 600, 1800, 5, 6, 0), + DA9052_LDO(LDO2, ldo2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), + DA9052_LDO(LDO3, ldo3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), + DA9052_LDO(LDO4, ldo4, 25, 1725, 3300, 6, 6, 0), + DA9052_LDO(LDO5, ldo5, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO6, ldo6, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO7, ldo7, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO8, ldo8, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO9, ldo9, 50, 1250, 3650, 6, 6, 0), + DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0), }; -static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id, - int id) +static inline const struct da9052_regulator_info *find_regulator_info(u8 chip_id, + int id) { - struct da9052_regulator_info *info; + const struct da9052_regulator_info *info; int i; switch (chip_id) { @@ -325,6 +378,7 @@ static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id, case DA9053_AA: case DA9053_BA: case DA9053_BB: + case DA9053_BC: for (i = 0; i < ARRAY_SIZE(da9053_regulator_info); i++) { info = &da9053_regulator_info[i]; if (info->reg_desc.id == id) @@ -338,6 +392,7 @@ static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id, static int da9052_regulator_probe(struct platform_device *pdev) { + const struct mfd_cell *cell = mfd_get_cell(pdev); struct regulator_config config = { }; struct da9052_regulator *regulator; struct da9052 *da9052; @@ -349,48 +404,25 @@ static int da9052_regulator_probe(struct platform_device *pdev) return -ENOMEM; da9052 = dev_get_drvdata(pdev->dev.parent); - pdata = da9052->dev->platform_data; + pdata = dev_get_platdata(da9052->dev); regulator->da9052 = da9052; regulator->info = find_regulator_info(regulator->da9052->chip_id, - pdev->id); + cell->id); if (regulator->info == NULL) { dev_err(&pdev->dev, "invalid regulator ID specified\n"); return -EINVAL; } - config.dev = &pdev->dev; + config.dev = da9052->dev; config.driver_data = regulator; config.regmap = da9052->regmap; - if (pdata && pdata->regulators) { - config.init_data = pdata->regulators[pdev->id]; - } else { -#ifdef CONFIG_OF - struct device_node *nproot, *np; - - nproot = of_node_get(da9052->dev->of_node); - if (!nproot) - return -ENODEV; - - nproot = of_find_node_by_name(nproot, "regulators"); - if (!nproot) - return -ENODEV; - - for_each_child_of_node(nproot, np) { - if (!of_node_cmp(np->name, - regulator->info->reg_desc.name)) { - config.init_data = of_get_regulator_init_data( - &pdev->dev, np); - config.of_node = np; - break; - } - } - of_node_put(nproot); -#endif - } + if (pdata) + config.init_data = pdata->regulators[cell->id]; - regulator->rdev = regulator_register(®ulator->info->reg_desc, - &config); + regulator->rdev = devm_regulator_register(&pdev->dev, + ®ulator->info->reg_desc, + &config); if (IS_ERR(regulator->rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", regulator->info->reg_desc.name); @@ -402,20 +434,11 @@ static int da9052_regulator_probe(struct platform_device *pdev) return 0; } -static int da9052_regulator_remove(struct platform_device *pdev) -{ - struct da9052_regulator *regulator = platform_get_drvdata(pdev); - - regulator_unregister(regulator->rdev); - return 0; -} - static struct platform_driver da9052_regulator_driver = { .probe = da9052_regulator_probe, - .remove = da9052_regulator_remove, .driver = { .name = "da9052-regulator", - .owner = THIS_MODULE, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; |
