diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-29 23:32:25 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-29 23:32:25 (GMT) |
commit | 8ded8d4e4facab78acf616bc34085ddd15c2c21c (patch) | |
tree | 7cb470ffbaffd4c1119d1baf4b0341f76cb4242a /drivers | |
parent | 7b053842b95914119f132fdac294fb2591b2e9a8 (diff) | |
parent | bee546581424b5514ec6a034fb83fd4e95b804da (diff) | |
download | linux-fsl-qoriq-8ded8d4e4facab78acf616bc34085ddd15c2c21c.tar.xz |
Merge tag 'regulator-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator
Pull regulator updates from Mark Brown:
"The diffstat and changelog here is dominated by Lee Jones' heroic
efforts to sync the ab8500 driver that's been maintained out of tree
with mainline (plus Axel's cleanup work on the results) but there's a
few other things here:
- Axel Lin added regulator_map_voltage_ascend() optimising a common
pattern for drivers using the core code.
- Milo Kim tought the regulator core to handle regulators sharing an
enable GPIO, avoiding the need to do hacks to support such systems.
- Andrew Bresticker added code to handle missing supplies for
regulators more sensibly for device tree systems, reducing the need
for stubbing there.
plus the usual batch of driver specific updates and fixes"
* tag 'regulator-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (152 commits)
regulator: mc13892: Fix MC13892_SWITCHERS0_SWxHI bit in set_voltage_sel
regulator: Remove NULL test before calling regulator_unregister()
regulator: mc13783: Add device tree probe support
regulator: mc13xxx: Add warning of incorrect names of regulators
regulator: max77686: Don't update max77686->opmode if update register fails
regulator: max8952: Add missing config.of_node setting for regulator register
regulator: ab3100: Fix regulator register error handling
regulator: tps6524x: Use regulator_map_voltage_ascend
regulator: lp8788-buck: Use regulator_map_voltage_ascend
regulator: lp872x: Use regulator_map_voltage_ascend
regulator: mc13892: Use regulator_map_voltage_ascend for mc13892_sw_regulator_ops
regulator: tps65023: Use regulator_map_voltage_ascend
regulator: tps65023: Merge tps65020 ldo1 and ldo2 vsel table
regulator: tps6507x: Use regulator_map_voltage_ascend
regulator: mc13892: Fix MC13892_SWITCHERS0_SWxHI bit in set_voltage_sel
regulator: ab3100: device tree support
regulator: ab3100: refactor probe to use IDs
regulator: max8973: Don't override control1 variable when set ramp delay bits
regulator: tps80031: Convert tps80031_dcdc_ops to [get|set]_voltage_sel_regmap
regulator: tps80031: Fix LDO2 track mode for TPS80031 or TPS80032-ES1.0
...
Diffstat (limited to 'drivers')
41 files changed, 3987 insertions, 702 deletions
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 2ec7725..a9bb140 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -753,6 +753,7 @@ static struct mfd_cell ab3100_devs[] = { }, { .name = "ab3100-regulators", + .of_compatible = "stericsson,ab3100-regulators", .id = -1, }, { diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index c79ab84..493948a 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -220,35 +220,6 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) return ret; } -static int pm8606_preg_enable(struct regulator_dev *rdev) -{ - struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - - return pm860x_set_bits(info->i2c, rdev->desc->enable_reg, - 1 << rdev->desc->enable_mask, 0); -} - -static int pm8606_preg_disable(struct regulator_dev *rdev) -{ - struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - - return pm860x_set_bits(info->i2c, rdev->desc->enable_reg, - 1 << rdev->desc->enable_mask, - 1 << rdev->desc->enable_mask); -} - -static int pm8606_preg_is_enabled(struct regulator_dev *rdev) -{ - struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - int ret; - - ret = pm860x_reg_read(info->i2c, rdev->desc->enable_reg); - if (ret < 0) - return ret; - - return !((unsigned char)ret & (1 << rdev->desc->enable_mask)); -} - static struct regulator_ops pm8607_regulator_ops = { .list_voltage = pm8607_list_voltage, .set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -259,9 +230,9 @@ static struct regulator_ops pm8607_regulator_ops = { }; static struct regulator_ops pm8606_preg_ops = { - .enable = pm8606_preg_enable, - .disable = pm8606_preg_disable, - .is_enabled = pm8606_preg_is_enabled, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, }; #define PM8606_PREG(ereg, ebit) \ @@ -274,6 +245,7 @@ static struct regulator_ops pm8606_preg_ops = { .owner = THIS_MODULE, \ .enable_reg = PM8606_##ereg, \ .enable_mask = (ebit), \ + .enable_is_inverted = true, \ }, \ } diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 6e82503..47a34ff 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -12,7 +12,7 @@ obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o -obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o +obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o ab8500-ext.o obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index 111ec69..3be9e46 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -17,6 +17,8 @@ #include <linux/regulator/driver.h> #include <linux/mfd/ab3100.h> #include <linux/mfd/abx500.h> +#include <linux/of.h> +#include <linux/regulator/of_regulator.h> /* LDO registers and some handy masking definitions for AB3100 */ #define AB3100_LDO_A 0x40 @@ -345,7 +347,11 @@ static int ab3100_get_voltage_regulator_external(struct regulator_dev *reg) { struct ab3100_regulator *abreg = rdev_get_drvdata(reg); - return abreg->plfdata->external_voltage; + if (abreg->plfdata) + return abreg->plfdata->external_voltage; + else + /* TODO: encode external voltage into device tree */ + return 0; } static struct regulator_ops regulator_ops_fixed = { @@ -488,16 +494,174 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = { }, }; +static int ab3100_regulator_register(struct platform_device *pdev, + struct ab3100_platform_data *plfdata, + struct regulator_init_data *init_data, + struct device_node *np, + int id) +{ + struct regulator_desc *desc; + struct ab3100_regulator *reg; + struct regulator_dev *rdev; + struct regulator_config config = { }; + int err, i; + + for (i = 0; i < AB3100_NUM_REGULATORS; i++) { + desc = &ab3100_regulator_desc[i]; + if (desc->id == id) + break; + } + if (desc->id != id) + return -ENODEV; + + /* Same index used for this array */ + reg = &ab3100_regulators[i]; + + /* + * Initialize per-regulator struct. + * Inherit platform data, this comes down from the + * i2c boarddata, from the machine. So if you want to + * see what it looks like for a certain machine, go + * into the machine I2C setup. + */ + reg->dev = &pdev->dev; + if (plfdata) { + reg->plfdata = plfdata; + config.init_data = &plfdata->reg_constraints[i]; + } else if (np) { + config.of_node = np; + config.init_data = init_data; + } + config.dev = &pdev->dev; + config.driver_data = reg; + + rdev = regulator_register(desc, &config); + if (IS_ERR(rdev)) { + err = PTR_ERR(rdev); + dev_err(&pdev->dev, + "%s: failed to register regulator %s err %d\n", + __func__, desc->name, + err); + return err; + } + + /* Then set a pointer back to the registered regulator */ + reg->rdev = rdev; + return 0; +} + +static struct of_regulator_match ab3100_regulator_matches[] = { + { .name = "ab3100_ldo_a", .driver_data = (void *) AB3100_LDO_A, }, + { .name = "ab3100_ldo_c", .driver_data = (void *) AB3100_LDO_C, }, + { .name = "ab3100_ldo_d", .driver_data = (void *) AB3100_LDO_D, }, + { .name = "ab3100_ldo_e", .driver_data = (void *) AB3100_LDO_E, }, + { .name = "ab3100_ldo_f", .driver_data = (void *) AB3100_LDO_F }, + { .name = "ab3100_ldo_g", .driver_data = (void *) AB3100_LDO_G }, + { .name = "ab3100_ldo_h", .driver_data = (void *) AB3100_LDO_H }, + { .name = "ab3100_ldo_k", .driver_data = (void *) AB3100_LDO_K }, + { .name = "ab3100_ext", .driver_data = (void *) AB3100_LDO_EXT }, + { .name = "ab3100_buck", .driver_data = (void *) AB3100_BUCK }, +}; + /* - * NOTE: the following functions are regulators pluralis - it is the - * binding to the AB3100 core driver and the parent platform device - * for all the different regulators. + * Initial settings of ab3100 registers. + * Common for below LDO regulator settings are that + * bit 7-5 controls voltage. Bit 4 turns regulator ON(1) or OFF(0). + * Bit 3-2 controls sleep enable and bit 1-0 controls sleep mode. */ +/* LDO_A 0x16: 2.75V, ON, SLEEP_A, SLEEP OFF GND */ +#define LDO_A_SETTING 0x16 +/* LDO_C 0x10: 2.65V, ON, SLEEP_A or B, SLEEP full power */ +#define LDO_C_SETTING 0x10 +/* LDO_D 0x10: 2.65V, ON, sleep mode not used */ +#define LDO_D_SETTING 0x10 +/* LDO_E 0x10: 1.8V, ON, SLEEP_A or B, SLEEP full power */ +#define LDO_E_SETTING 0x10 +/* LDO_E SLEEP 0x00: 1.8V, not used, SLEEP_A or B, not used */ +#define LDO_E_SLEEP_SETTING 0x00 +/* LDO_F 0xD0: 2.5V, ON, SLEEP_A or B, SLEEP full power */ +#define LDO_F_SETTING 0xD0 +/* LDO_G 0x00: 2.85V, OFF, SLEEP_A or B, SLEEP full power */ +#define LDO_G_SETTING 0x00 +/* LDO_H 0x18: 2.75V, ON, SLEEP_B, SLEEP full power */ +#define LDO_H_SETTING 0x18 +/* LDO_K 0x00: 2.75V, OFF, SLEEP_A or B, SLEEP full power */ +#define LDO_K_SETTING 0x00 +/* LDO_EXT 0x00: Voltage not set, OFF, not used, not used */ +#define LDO_EXT_SETTING 0x00 +/* BUCK 0x7D: 1.2V, ON, SLEEP_A and B, SLEEP low power */ +#define BUCK_SETTING 0x7D +/* BUCK SLEEP 0xAC: 1.05V, Not used, SLEEP_A and B, Not used */ +#define BUCK_SLEEP_SETTING 0xAC + +static const u8 ab3100_reg_initvals[] = { + LDO_A_SETTING, + LDO_C_SETTING, + LDO_E_SETTING, + LDO_E_SLEEP_SETTING, + LDO_F_SETTING, + LDO_G_SETTING, + LDO_H_SETTING, + LDO_K_SETTING, + LDO_EXT_SETTING, + BUCK_SETTING, + BUCK_SLEEP_SETTING, + LDO_D_SETTING, +}; + +static int ab3100_regulators_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < AB3100_NUM_REGULATORS; i++) { + struct ab3100_regulator *reg = &ab3100_regulators[i]; + + regulator_unregister(reg->rdev); + reg->rdev = NULL; + } + return 0; +} + +static int +ab3100_regulator_of_probe(struct platform_device *pdev, struct device_node *np) +{ + int err, i; + + /* + * Set up the regulator registers, as was previously done with + * platform data. + */ + /* Set up regulators */ + for (i = 0; i < ARRAY_SIZE(ab3100_reg_init_order); i++) { + err = abx500_set_register_interruptible(&pdev->dev, 0, + ab3100_reg_init_order[i], + ab3100_reg_initvals[i]); + if (err) { + dev_err(&pdev->dev, "regulator initialization failed with error %d\n", + err); + return err; + } + } + + for (i = 0; i < ARRAY_SIZE(ab3100_regulator_matches); i++) { + err = ab3100_regulator_register( + pdev, NULL, ab3100_regulator_matches[i].init_data, + ab3100_regulator_matches[i].of_node, + (int) ab3100_regulator_matches[i].driver_data); + if (err) { + ab3100_regulators_remove(pdev); + return err; + } + } + + return 0; +} + static int ab3100_regulators_probe(struct platform_device *pdev) { struct ab3100_platform_data *plfdata = pdev->dev.platform_data; - struct regulator_config config = { }; + struct device_node *np = pdev->dev.of_node; int err = 0; u8 data; int i; @@ -516,6 +680,18 @@ static int ab3100_regulators_probe(struct platform_device *pdev) dev_notice(&pdev->dev, "chip is in inactive mode (Cold start)\n"); + if (np) { + err = of_regulator_match(&pdev->dev, np, + ab3100_regulator_matches, + ARRAY_SIZE(ab3100_regulator_matches)); + if (err < 0) { + dev_err(&pdev->dev, + "Error parsing regulator init data: %d\n", err); + return err; + } + return ab3100_regulator_of_probe(pdev, np); + } + /* Set up regulators */ for (i = 0; i < ARRAY_SIZE(ab3100_reg_init_order); i++) { err = abx500_set_register_interruptible(&pdev->dev, 0, @@ -530,59 +706,19 @@ static int ab3100_regulators_probe(struct platform_device *pdev) /* Register the regulators */ for (i = 0; i < AB3100_NUM_REGULATORS; i++) { - struct ab3100_regulator *reg = &ab3100_regulators[i]; - struct regulator_dev *rdev; - - /* - * Initialize per-regulator struct. - * Inherit platform data, this comes down from the - * i2c boarddata, from the machine. So if you want to - * see what it looks like for a certain machine, go - * into the machine I2C setup. - */ - reg->dev = &pdev->dev; - reg->plfdata = plfdata; + struct regulator_desc *desc = &ab3100_regulator_desc[i]; - config.dev = &pdev->dev; - config.driver_data = reg; - config.init_data = &plfdata->reg_constraints[i]; - - /* - * Register the regulator, pass around - * the ab3100_regulator struct - */ - rdev = regulator_register(&ab3100_regulator_desc[i], &config); - if (IS_ERR(rdev)) { - err = PTR_ERR(rdev); - dev_err(&pdev->dev, - "%s: failed to register regulator %s err %d\n", - __func__, ab3100_regulator_desc[i].name, - err); - /* remove the already registered regulators */ - while (--i >= 0) - regulator_unregister(ab3100_regulators[i].rdev); + err = ab3100_regulator_register(pdev, plfdata, NULL, NULL, + desc->id); + if (err) { + ab3100_regulators_remove(pdev); return err; } - - /* Then set a pointer back to the registered regulator */ - reg->rdev = rdev; } return 0; } -static int ab3100_regulators_remove(struct platform_device *pdev) -{ - int i; - - for (i = 0; i < AB3100_NUM_REGULATORS; i++) { - struct ab3100_regulator *reg = &ab3100_regulators[i]; - - regulator_unregister(reg->rdev); - } - return 0; -} - static struct platform_driver ab3100_regulators_driver = { .driver = { .name = "ab3100-regulators", diff --git a/drivers/regulator/ab8500-ext.c b/drivers/regulator/ab8500-ext.c new file mode 100644 index 0000000..b4d4547 --- /dev/null +++ b/drivers/regulator/ab8500-ext.c @@ -0,0 +1,407 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * + * Authors: Bengt Jonsson <bengt.g.jonsson@stericsson.com> + * + * This file is based on drivers/regulator/ab8500.c + * + * AB8500 external regulators + * + * ab8500-ext supports the following regulators: + * - VextSupply3 + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/abx500.h> +#include <linux/mfd/abx500/ab8500.h> +#include <linux/regulator/ab8500.h> + +/** + * struct ab8500_ext_regulator_info - ab8500 regulator information + * @dev: device pointer + * @desc: regulator description + * @rdev: regulator device + * @cfg: regulator configuration (extension of regulator FW configuration) + * @update_bank: bank to control on/off + * @update_reg: register to control on/off + * @update_mask: mask to enable/disable and set mode of regulator + * @update_val: bits holding the regulator current mode + * @update_val_hp: bits to set EN pin active (LPn pin deactive) + * normally this means high power mode + * @update_val_lp: bits to set EN pin active and LPn pin active + * normally this means low power mode + * @update_val_hw: bits to set regulator pins in HW control + * SysClkReq pins and logic will choose mode + */ +struct ab8500_ext_regulator_info { + struct device *dev; + struct regulator_desc desc; + struct regulator_dev *rdev; + struct ab8500_ext_regulator_cfg *cfg; + u8 update_bank; + u8 update_reg; + u8 update_mask; + u8 update_val; + u8 update_val_hp; + u8 update_val_lp; + u8 update_val_hw; +}; + +static int ab8500_ext_regulator_enable(struct regulator_dev *rdev) +{ + int ret; + struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); + u8 regval; + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + /* + * To satisfy both HW high power request and SW request, the regulator + * must be on in high power. + */ + if (info->cfg && info->cfg->hwreq) + regval = info->update_val_hp; + else + regval = info->update_val; + + ret = abx500_mask_and_set_register_interruptible(info->dev, + info->update_bank, info->update_reg, + info->update_mask, regval); + if (ret < 0) { + dev_err(rdev_get_dev(info->rdev), + "couldn't set enable bits for regulator\n"); + return ret; + } + + dev_dbg(rdev_get_dev(rdev), + "%s-enable (bank, reg, mask, value): 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", + info->desc.name, info->update_bank, info->update_reg, + info->update_mask, regval); + + return 0; +} + +static int ab8500_ext_regulator_disable(struct regulator_dev *rdev) +{ + int ret; + struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); + u8 regval; + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + /* + * Set the regulator in HW request mode if configured + */ + if (info->cfg && info->cfg->hwreq) + regval = info->update_val_hw; + else + regval = 0; + + ret = abx500_mask_and_set_register_interruptible(info->dev, + info->update_bank, info->update_reg, + info->update_mask, regval); + if (ret < 0) { + dev_err(rdev_get_dev(info->rdev), + "couldn't set disable bits for regulator\n"); + return ret; + } + + dev_dbg(rdev_get_dev(rdev), "%s-disable (bank, reg, mask, value):" + " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", + info->desc.name, info->update_bank, info->update_reg, + info->update_mask, regval); + + return 0; +} + +static int ab8500_ext_regulator_is_enabled(struct regulator_dev *rdev) +{ + int ret; + struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); + u8 regval; + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + ret = abx500_get_register_interruptible(info->dev, + info->update_bank, info->update_reg, ®val); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), + "couldn't read 0x%x register\n", info->update_reg); + return ret; + } + + dev_dbg(rdev_get_dev(rdev), "%s-is_enabled (bank, reg, mask, value):" + " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", + info->desc.name, info->update_bank, info->update_reg, + info->update_mask, regval); + + if (((regval & info->update_mask) == info->update_val_lp) || + ((regval & info->update_mask) == info->update_val_hp)) + return 1; + else + return 0; +} + +static int ab8500_ext_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + int ret = 0; + struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); + u8 regval; + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + switch (mode) { + case REGULATOR_MODE_NORMAL: + regval = info->update_val_hp; + break; + case REGULATOR_MODE_IDLE: + regval = info->update_val_lp; + break; + + default: + return -EINVAL; + } + + /* If regulator is enabled and info->cfg->hwreq is set, the regulator + must be on in high power, so we don't need to write the register with + the same value. + */ + if (ab8500_ext_regulator_is_enabled(rdev) && + !(info->cfg && info->cfg->hwreq)) { + ret = abx500_mask_and_set_register_interruptible(info->dev, + info->update_bank, info->update_reg, + info->update_mask, regval); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), + "Could not set regulator mode.\n"); + return ret; + } + + dev_dbg(rdev_get_dev(rdev), + "%s-set_mode (bank, reg, mask, value): " + "0x%x, 0x%x, 0x%x, 0x%x\n", + info->desc.name, info->update_bank, info->update_reg, + info->update_mask, regval); + } + + info->update_val = regval; + + return 0; +} + +static unsigned int ab8500_ext_regulator_get_mode(struct regulator_dev *rdev) +{ + struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); + int ret; + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + if (info->update_val == info->update_val_hp) + ret = REGULATOR_MODE_NORMAL; + else if (info->update_val == info->update_val_lp) + ret = REGULATOR_MODE_IDLE; + else + ret = -EINVAL; + + return ret; +} + +static int ab8500_ext_list_voltage(struct regulator_dev *rdev, + unsigned selector) +{ + struct regulation_constraints *regu_constraints = rdev->constraints; + + if (regu_constraints == NULL) { + dev_err(rdev_get_dev(rdev), "regulator constraints null pointer\n"); + return -EINVAL; + } + /* return the uV for the fixed regulators */ + if (regu_constraints->min_uV && regu_constraints->max_uV) { + if (regu_constraints->min_uV == regu_constraints->max_uV) + return regu_constraints->min_uV; + } + return -EINVAL; +} + +static struct regulator_ops ab8500_ext_regulator_ops = { + .enable = ab8500_ext_regulator_enable, + .disable = ab8500_ext_regulator_disable, + .is_enabled = ab8500_ext_regulator_is_enabled, + .set_mode = ab8500_ext_regulator_set_mode, + .get_mode = ab8500_ext_regulator_get_mode, + .list_voltage = ab8500_ext_list_voltage, +}; + +static struct ab8500_ext_regulator_info + ab8500_ext_regulator_info[AB8500_NUM_EXT_REGULATORS] = { + [AB8500_EXT_SUPPLY1] = { + .desc = { + .name = "VEXTSUPPLY1", + .ops = &ab8500_ext_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_EXT_SUPPLY1, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .update_bank = 0x04, + .update_reg = 0x08, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_hp = 0x01, + .update_val_lp = 0x03, + .update_val_hw = 0x02, + }, + [AB8500_EXT_SUPPLY2] = { + .desc = { + .name = "VEXTSUPPLY2", + .ops = &ab8500_ext_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_EXT_SUPPLY2, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .update_bank = 0x04, + .update_reg = 0x08, + .update_mask = 0x0c, + .update_val = 0x04, + .update_val_hp = 0x04, + .update_val_lp = 0x0c, + .update_val_hw = 0x08, + }, + [AB8500_EXT_SUPPLY3] = { + .desc = { + .name = "VEXTSUPPLY3", + .ops = &ab8500_ext_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_EXT_SUPPLY3, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .update_bank = 0x04, + .update_reg = 0x08, + .update_mask = 0x30, + .update_val = 0x10, + .update_val_hp = 0x10, + .update_val_lp = 0x30, + .update_val_hw = 0x20, + }, +}; + +int ab8500_ext_regulator_init(struct platform_device *pdev) +{ + struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); + struct ab8500_platform_data *ppdata; + struct ab8500_regulator_platform_data *pdata; + struct regulator_config config = { }; + int i, err; + + if (!ab8500) { + dev_err(&pdev->dev, "null mfd parent\n"); + return -EINVAL; + } + ppdata = dev_get_platdata(ab8500->dev); + if (!ppdata) { + dev_err(&pdev->dev, "null parent pdata\n"); + return -EINVAL; + } + + pdata = ppdata->regulator; + if (!pdata) { + dev_err(&pdev->dev, "null pdata\n"); + return -EINVAL; + } + + /* make sure the platform data has the correct size */ + if (pdata->num_ext_regulator != ARRAY_SIZE(ab8500_ext_regulator_info)) { + dev_err(&pdev->dev, "Configuration error: size mismatch.\n"); + return -EINVAL; + } + + /* check for AB8500 2.x */ + if (is_ab8500_2p0_or_earlier(ab8500)) { + struct ab8500_ext_regulator_info *info; + + /* VextSupply3LPn is inverted on AB8500 2.x */ + info = &ab8500_ext_regulator_info[AB8500_EXT_SUPPLY3]; + info->update_val = 0x30; + info->update_val_hp = 0x30; + info->update_val_lp = 0x10; + } + + /* register all regulators */ + for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) { + struct ab8500_ext_regulator_info *info = NULL; + + /* assign per-regulator data */ + info = &ab8500_ext_regulator_info[i]; + info->dev = &pdev->dev; + info->cfg = (struct ab8500_ext_regulator_cfg *) + pdata->ext_regulator[i].driver_data; + + config.dev = &pdev->dev; + config.init_data = &pdata->ext_regulator[i]; + config.driver_data = info; + + /* register regulator with framework */ + info->rdev = regulator_register(&info->desc, &config); + if (IS_ERR(info->rdev)) { + err = PTR_ERR(info->rdev); + dev_err(&pdev->dev, "failed to register regulator %s\n", + info->desc.name); + /* when we fail, un-register all earlier regulators */ + while (--i >= 0) { + info = &ab8500_ext_regulator_info[i]; + regulator_unregister(info->rdev); + } + return err; + } + + dev_dbg(rdev_get_dev(info->rdev), + "%s-probed\n", info->desc.name); + } + + return 0; +} + +void ab8500_ext_regulator_exit(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) { + struct ab8500_ext_regulator_info *info = NULL; + info = &ab8500_ext_regulator_info[i]; + + dev_vdbg(rdev_get_dev(info->rdev), + "%s-remove\n", info->desc.name); + + regulator_unregister(info->rdev); + } +} + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com>"); +MODULE_DESCRIPTION("AB8500 external regulator driver"); +MODULE_ALIAS("platform:ab8500-ext-regulator"); diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 09014f3..f6656b8 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -5,11 +5,15 @@ * * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson + * Daniel Willerud <daniel.willerud@stericsson.com> for ST-Ericsson * * AB8500 peripheral regulators * * AB8500 supports the following regulators: * VAUX1/2/3, VINTCORE, VTVOUT, VUSB, VAUDIO, VAMIC1/2, VDMIC, VANA + * + * AB8505 supports the following regulators: + * VAUX1/2/3/4/5/6, VINTCORE, VADC, VUSB, VAUDIO, VAMIC1/2, VDMIC, VANA */ #include <linux/init.h> #include <linux/kernel.h> @@ -26,33 +30,64 @@ #include <linux/slab.h> /** + * struct ab8500_shared_mode - is used when mode is shared between + * two regulators. + * @shared_regulator: pointer to the other sharing regulator + * @lp_mode_req: low power mode requested by this regulator + */ +struct ab8500_shared_mode { + struct ab8500_regulator_info *shared_regulator; + bool lp_mode_req; +}; + +/** * struct ab8500_regulator_info - ab8500 regulator information * @dev: device pointer * @desc: regulator description * @regulator_dev: regulator device + * @shared_mode: used when mode is shared between two regulators + * @load_lp_uA: maximum load in idle (low power) mode * @update_bank: bank to control on/off * @update_reg: register to control on/off - * @update_mask: mask to enable/disable regulator - * @update_val_enable: bits to enable the regulator in normal (high power) mode + * @update_mask: mask to enable/disable and set mode of regulator + * @update_val: bits holding the regulator current mode + * @update_val_idle: bits to enable the regulator in idle (low power) mode + * @update_val_normal: bits to enable the regulator in normal (high power) mode + * @mode_bank: bank with location of mode register + * @mode_reg: mode register + * @mode_mask: mask for setting mode + * @mode_val_idle: mode setting for low power + * @mode_val_normal: mode setting for normal power * @voltage_bank: bank to control regulator voltage * @voltage_reg: register to control regulator voltage * @voltage_mask: mask to control regulator voltage - * @voltage_shift: shift to control regulator voltage - * @delay: startup/set voltage delay in us */ struct ab8500_regulator_info { struct device *dev; struct regulator_desc desc; struct regulator_dev *regulator; + struct ab8500_shared_mode *shared_mode; + int load_lp_uA; u8 update_bank; u8 update_reg; u8 update_mask; - u8 update_val_enable; + u8 update_val; + u8 update_val_idle; + u8 update_val_normal; + u8 mode_bank; + u8 mode_reg; + u8 mode_mask; + u8 mode_val_idle; + u8 mode_val_normal; u8 voltage_bank; u8 voltage_reg; u8 voltage_mask; - u8 voltage_shift; - unsigned int delay; + struct { + u8 voltage_limit; + u8 voltage_bank; + u8 voltage_reg; + u8 voltage_mask; + } expand_register; }; /* voltage tables for the vauxn/vintcore supplies */ @@ -86,6 +121,44 @@ static const unsigned int ldo_vaux3_voltages[] = { 2910000, }; +static const unsigned int ldo_vaux56_voltages[] = { + 1800000, + 1050000, + 1100000, + 1200000, + 1500000, + 2200000, + 2500000, + 2790000, +}; + +static const unsigned int ldo_vaux3_ab8540_voltages[] = { + 1200000, + 1500000, + 1800000, + 2100000, + 2500000, + 2750000, + 2790000, + 2910000, + 3050000, +}; + +static const unsigned int ldo_vaux56_ab8540_voltages[] = { + 750000, 760000, 770000, 780000, 790000, 800000, + 810000, 820000, 830000, 840000, 850000, 860000, + 870000, 880000, 890000, 900000, 910000, 920000, + 930000, 940000, 950000, 960000, 970000, 980000, + 990000, 1000000, 1010000, 1020000, 1030000, + 1040000, 1050000, 1060000, 1070000, 1080000, + 1090000, 1100000, 1110000, 1120000, 1130000, + 1140000, 1150000, 1160000, 1170000, 1180000, + 1190000, 1200000, 1210000, 1220000, 1230000, + 1240000, 1250000, 1260000, 1270000, 1280000, + 1290000, 1300000, 1310000, 1320000, 1330000, + 1340000, 1350000, 1360000, 1800000, 2790000, +}; + static const unsigned int ldo_vintcore_voltages[] = { 1200000, 1225000, @@ -96,6 +169,72 @@ static const unsigned int ldo_vintcore_voltages[] = { 1350000, }; +static const unsigned int ldo_sdio_voltages[] = { + 1160000, + 1050000, + 1100000, + 1500000, + 1800000, + 2200000, + 2910000, + 3050000, +}; + +static const unsigned int fixed_1200000_voltage[] = { + 1200000, +}; + +static const unsigned int fixed_1800000_voltage[] = { + 1800000, +}; + +static const unsigned int fixed_2000000_voltage[] = { + 2000000, +}; + +static const unsigned int fixed_2050000_voltage[] = { + 2050000, +}; + +static const unsigned int fixed_3300000_voltage[] = { + 3300000, +}; + +static const unsigned int ldo_vana_voltages[] = { + 1050000, + 1075000, + 1100000, + 1125000, + 1150000, + 1175000, + 1200000, + 1225000, +}; + +static const unsigned int ldo_vaudio_voltages[] = { + 2000000, + 2100000, + 2200000, + 2300000, + 2400000, + 2500000, + 2600000, + 2600000, /* Duplicated in Vaudio and IsoUicc Control register. */ +}; + +static const unsigned int ldo_vdmic_voltages[] = { + 1800000, + 1900000, + 2000000, + 2850000, +}; + +static DEFINE_MUTEX(shared_mode_mutex); +static struct ab8500_shared_mode ldo_anamic1_shared; +static struct ab8500_shared_mode ldo_anamic2_shared; +static struct ab8500_shared_mode ab8540_ldo_anamic1_shared; +static struct ab8500_shared_mode ab8540_ldo_anamic2_shared; + static int ab8500_regulator_enable(struct regulator_dev *rdev) { int ret; @@ -108,15 +247,17 @@ static int ab8500_regulator_enable(struct regulator_dev *rdev) ret = abx500_mask_and_set_register_interruptible(info->dev, info->update_bank, info->update_reg, - info->update_mask, info->update_val_enable); - if (ret < 0) + info->update_mask, info->update_val); + if (ret < 0) { dev_err(rdev_get_dev(rdev), "couldn't set enable bits for regulator\n"); + return ret; + } dev_vdbg(rdev_get_dev(rdev), "%s-enable (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", info->desc.name, info->update_bank, info->update_reg, - info->update_mask, info->update_val_enable); + info->update_mask, info->update_val); return ret; } @@ -134,9 +275,11 @@ static int ab8500_regulator_disable(struct regulator_dev *rdev) ret = abx500_mask_and_set_register_interruptible(info->dev, info->update_bank, info->update_reg, info->update_mask, 0x0); - if (ret < 0) + if (ret < 0) { dev_err(rdev_get_dev(rdev), "couldn't set disable bits for regulator\n"); + return ret; + } dev_vdbg(rdev_get_dev(rdev), "%s-disable (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", @@ -172,14 +315,170 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) info->update_mask, regval); if (regval & info->update_mask) - return true; + return 1; + else + return 0; +} + +static unsigned int ab8500_regulator_get_optimum_mode( + struct regulator_dev *rdev, int input_uV, + int output_uV, int load_uA) +{ + unsigned int mode; + + struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + if (load_uA <= info->load_lp_uA) + mode = REGULATOR_MODE_IDLE; + else + mode = REGULATOR_MODE_NORMAL; + + return mode; +} + +static int ab8500_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + int ret = 0; + u8 bank, reg, mask, val; + bool lp_mode_req = false; + struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + if (info->mode_mask) { + bank = info->mode_bank; + reg = info->mode_reg; + mask = info->mode_mask; + } else { + bank = info->update_bank; + reg = info->update_reg; + mask = info->update_mask; + } + + if (info->shared_mode) + mutex_lock(&shared_mode_mutex); + + switch (mode) { + case REGULATOR_MODE_NORMAL: + if (info->shared_mode) + lp_mode_req = false; + + if (info->mode_mask) + val = info->mode_val_normal; + else + val = info->update_val_normal; + break; + case REGULATOR_MODE_IDLE: + if (info->shared_mode) { + struct ab8500_regulator_info *shared_regulator; + + shared_regulator = info->shared_mode->shared_regulator; + if (!shared_regulator->shared_mode->lp_mode_req) { + /* Other regulator prevent LP mode */ + info->shared_mode->lp_mode_req = true; + goto out_unlock; + } + + lp_mode_req = true; + } + + if (info->mode_mask) + val = info->mode_val_idle; + else + val = info->update_val_idle; + break; + default: + ret = -EINVAL; + goto out_unlock; + } + + if (info->mode_mask || ab8500_regulator_is_enabled(rdev)) { + ret = abx500_mask_and_set_register_interruptible(info->dev, + bank, reg, mask, val); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), + "couldn't set regulator mode\n"); + goto out_unlock; + } + + dev_vdbg(rdev_get_dev(rdev), + "%s-set_mode (bank, reg, mask, value): " + "0x%x, 0x%x, 0x%x, 0x%x\n", + info->desc.name, bank, reg, + mask, val); + } + + if (!info->mode_mask) + info->update_val = val; + + if (info->shared_mode) + info->shared_mode->lp_mode_req = lp_mode_req; + +out_unlock: + if (info->shared_mode) + mutex_unlock(&shared_mode_mutex); + + return ret; +} + +static unsigned int ab8500_regulator_get_mode(struct regulator_dev *rdev) +{ + struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + int ret; + u8 val; + u8 val_normal; + u8 val_idle; + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + /* Need special handling for shared mode */ + if (info->shared_mode) { + if (info->shared_mode->lp_mode_req) + return REGULATOR_MODE_IDLE; + else + return REGULATOR_MODE_NORMAL; + } + + if (info->mode_mask) { + /* Dedicated register for handling mode */ + ret = abx500_get_register_interruptible(info->dev, + info->mode_bank, info->mode_reg, &val); + val = val & info->mode_mask; + + val_normal = info->mode_val_normal; + val_idle = info->mode_val_idle; + } else { + /* Mode register same as enable register */ + val = info->update_val; + val_normal = info->update_val_normal; + val_idle = info->update_val_idle; + } + + if (val == val_normal) + ret = REGULATOR_MODE_NORMAL; + else if (val == val_idle) + ret = REGULATOR_MODE_IDLE; else - return false; + ret = -EINVAL; + + return ret; } static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev) { - int ret, val; + int ret, voltage_shift; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); u8 regval; @@ -188,6 +487,8 @@ static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev) return -EINVAL; } + voltage_shift = ffs(info->voltage_mask) - 1; + ret = abx500_get_register_interruptible(info->dev, info->voltage_bank, info->voltage_reg, ®val); if (ret < 0) { @@ -201,16 +502,62 @@ static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev) "0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", info->desc.name, info->voltage_bank, info->voltage_reg, info->voltage_mask, - info->voltage_shift, regval); + voltage_shift, regval); - val = regval & info->voltage_mask; - return val >> info->voltage_shift; + return (regval & info->voltage_mask) >> voltage_shift; +} + +static int ab8540_aux3_regulator_get_voltage_sel(struct regulator_dev *rdev) +{ + int ret, voltage_shift; + struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + u8 regval, regval_expand; + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + ret = abx500_get_register_interruptible(info->dev, + info->expand_register.voltage_bank, + info->expand_register.voltage_reg, ®val_expand); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), + "couldn't read voltage expand reg for regulator\n"); + return ret; + } + + dev_vdbg(rdev_get_dev(rdev), + "%s-get_voltage expand (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", + info->desc.name, info->expand_register.voltage_bank, + info->expand_register.voltage_reg, + info->expand_register.voltage_mask, regval_expand); + + if (regval_expand & info->expand_register.voltage_mask) + return info->expand_register.voltage_limit; + + ret = abx500_get_register_interruptible(info->dev, + info->voltage_bank, info->voltage_reg, ®val); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), + "couldn't read voltage reg for regulator\n"); + return ret; + } + + dev_vdbg(rdev_get_dev(rdev), + "%s-get_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", + info->desc.name, info->voltage_bank, info->voltage_reg, + info->voltage_mask, regval); + + voltage_shift = ffs(info->voltage_mask) - 1; + + return (regval & info->voltage_mask) >> voltage_shift; } static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { - int ret; + int ret, voltage_shift; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); u8 regval; @@ -219,8 +566,10 @@ static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev, return -EINVAL; } + voltage_shift = ffs(info->voltage_mask) - 1; + /* set the registers for the request */ - regval = (u8)selector << info->voltage_shift; + regval = (u8)selector << voltage_shift; ret = abx500_mask_and_set_register_interruptible(info->dev, info->voltage_bank, info->voltage_reg, info->voltage_mask, regval); @@ -237,32 +586,121 @@ static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev, return ret; } -static int ab8500_regulator_set_voltage_time_sel(struct regulator_dev *rdev, - unsigned int old_sel, - unsigned int new_sel) +static int ab8540_aux3_regulator_set_voltage_sel(struct regulator_dev *rdev, + unsigned selector) { + int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + u8 regval, regval_expand; + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + if (selector < info->expand_register.voltage_limit) { + int voltage_shift = ffs(info->voltage_mask) - 1; + + regval = (u8)selector << voltage_shift; + ret = abx500_mask_and_set_register_interruptible(info->dev, + info->voltage_bank, info->voltage_reg, + info->voltage_mask, regval); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), + "couldn't set voltage reg for regulator\n"); + return ret; + } - return info->delay; + dev_vdbg(rdev_get_dev(rdev), + "%s-set_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", + info->desc.name, info->voltage_bank, info->voltage_reg, + info->voltage_mask, regval); + + regval_expand = 0; + } else { + regval_expand = info->expand_register.voltage_mask; + } + + ret = abx500_mask_and_set_register_interruptible(info->dev, + info->expand_register.voltage_bank, + info->expand_register.voltage_reg, + info->expand_register.voltage_mask, + regval_expand); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), + "couldn't set expand voltage reg for regulator\n"); + return ret; + } + + dev_vdbg(rdev_get_dev(rdev), + "%s-set_voltage expand (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", + info->desc.name, info->expand_register.voltage_bank, + info->expand_register.voltage_reg, + info->expand_register.voltage_mask, regval_expand); + + return 0; } -static struct regulator_ops ab8500_regulator_ops = { +static struct regulator_ops ab8500_regulator_volt_mode_ops = { + .enable = ab8500_regulator_enable, + .disable = ab8500_regulator_disable, + .is_enabled = ab8500_regulator_is_enabled, + .get_optimum_mode = ab8500_regulator_get_optimum_mode, + .set_mode = ab8500_regulator_set_mode, + .get_mode = ab8500_regulator_get_mode, + .get_voltage_sel = ab8500_regulator_get_voltage_sel, + .set_voltage_sel = ab8500_regulator_set_voltage_sel, + .list_voltage = regulator_list_voltage_table, +}; + +static struct regulator_ops ab8540_aux3_regulator_volt_mode_ops = { + .enable = ab8500_regulator_enable, + .disable = ab8500_regulator_disable, + .get_optimum_mode = ab8500_regulator_get_optimum_mode, + .set_mode = ab8500_regulator_set_mode, + .get_mode = ab8500_regulator_get_mode, + .is_enabled = ab8500_regulator_is_enabled, + .get_voltage_sel = ab8540_aux3_regulator_get_voltage_sel, + .set_voltage_sel = ab8540_aux3_regulator_set_voltage_sel, + .list_voltage = regulator_list_voltage_table, +}; + +static struct regulator_ops ab8500_regulator_volt_ops = { .enable = ab8500_regulator_enable, .disable = ab8500_regulator_disable, .is_enabled = ab8500_regulator_is_enabled, .get_voltage_sel = ab8500_regulator_get_voltage_sel, .set_voltage_sel = ab8500_regulator_set_voltage_sel, .list_voltage = regulator_list_voltage_table, - .set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel, }; -static struct regulator_ops ab8500_regulator_fixed_ops = { +static struct regulator_ops ab8500_regulator_mode_ops = { + .enable = ab8500_regulator_enable, + .disable = ab8500_regulator_disable, + .is_enabled = ab8500_regulator_is_enabled, + .get_optimum_mode = ab8500_regulator_get_optimum_mode, + .set_mode = ab8500_regulator_set_mode, + .get_mode = ab8500_regulator_get_mode, + .list_voltage = regulator_list_voltage_table, +}; + +static struct regulator_ops ab8500_regulator_ops = { + .enable = ab8500_regulator_enable, + .disable = ab8500_regulator_disable, + .is_enabled = ab8500_regulator_is_enabled, + .list_voltage = regulator_list_voltage_table, +}; + +static struct regulator_ops ab8500_regulator_anamic_mode_ops = { .enable = ab8500_regulator_enable, .disable = ab8500_regulator_disable, .is_enabled = ab8500_regulator_is_enabled, - .list_voltage = regulator_list_voltage_linear, + .set_mode = ab8500_regulator_set_mode, + .get_mode = ab8500_regulator_get_mode, + .list_voltage = regulator_list_voltage_table, }; +/* AB8500 regulator information */ static struct ab8500_regulator_info ab8500_regulator_info[AB8500_NUM_REGULATORS] = { /* @@ -274,17 +712,21 @@ static struct ab8500_regulator_info [AB8500_LDO_AUX1] = { .desc = { .name = "LDO-AUX1", - .ops = &ab8500_regulator_ops, + .ops = &ab8500_regulator_volt_mode_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_AUX1, .owner = THIS_MODULE, .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), .volt_table = ldo_vauxn_voltages, + .enable_time = 200, }, + .load_lp_uA = 5000, .update_bank = 0x04, .update_reg = 0x09, .update_mask = 0x03, - .update_val_enable = 0x01, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, .voltage_bank = 0x04, .voltage_reg = 0x1f, .voltage_mask = 0x0f, @@ -292,17 +734,21 @@ static struct ab8500_regulator_info [AB8500_LDO_AUX2] = { .desc = { .name = "LDO-AUX2", - .ops = &ab8500_regulator_ops, + .ops = &ab8500_regulator_volt_mode_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_AUX2, .owner = THIS_MODULE, .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), .volt_table = ldo_vauxn_voltages, + .enable_time = 200, }, + .load_lp_uA = 5000, .update_bank = 0x04, .update_reg = 0x09, .update_mask = 0x0c, - .update_val_enable = 0x04, + .update_val = 0x04, + .update_val_idle = 0x0c, + .update_val_normal = 0x04, .voltage_bank = 0x04, .voltage_reg = 0x20, .voltage_mask = 0x0f, @@ -310,17 +756,21 @@ static struct ab8500_regulator_info [AB8500_LDO_AUX3] = { .desc = { .name = "LDO-AUX3", - .ops = &ab8500_regulator_ops, + .ops = &ab8500_regulator_volt_mode_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_AUX3, .owner = THIS_MODULE, .n_voltages = ARRAY_SIZE(ldo_vaux3_voltages), .volt_table = ldo_vaux3_voltages, + .enable_time = 450, }, + .load_lp_uA = 5000, .update_bank = 0x04, .update_reg = 0x0a, .update_mask = 0x03, - .update_val_enable = 0x01, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, .voltage_bank = 0x04, .voltage_reg = 0x21, .voltage_mask = 0x07, @@ -328,21 +778,24 @@ static struct ab8500_regulator_info [AB8500_LDO_INTCORE] = { .desc = { .name = "LDO-INTCORE", - .ops = &ab8500_regulator_ops, + .ops = &ab8500_regulator_volt_mode_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_INTCORE, .owner = THIS_MODULE, .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages), .volt_table = ldo_vintcore_voltages, + .enable_time = 750, }, + .load_lp_uA = 5000, .update_bank = 0x03, .update_reg = 0x80, .update_mask = 0x44, - .update_val_enable = 0x04, + .update_val = 0x44, + .update_val_idle = 0x44, + .update_val_normal = 0x04, .voltage_bank = 0x03, .voltage_reg = 0x80, .voltage_mask = 0x38, - .voltage_shift = 3, }, /* @@ -353,112 +806,984 @@ static struct ab8500_regulator_info [AB8500_LDO_TVOUT] = { .desc = { .name = "LDO-TVOUT", - .ops = &ab8500_regulator_fixed_ops, + .ops = &ab8500_regulator_mode_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_TVOUT, .owner = THIS_MODULE, .n_voltages = 1, - .min_uV = 2000000, + .volt_table = fixed_2000000_voltage, + .enable_time = 500, + }, + .load_lp_uA = 1000, + .update_bank = 0x03, + .update_reg = 0x80, + .update_mask = 0x82, + .update_val = 0x02, + .update_val_idle = 0x82, + .update_val_normal = 0x02, + }, + [AB8500_LDO_AUDIO] = { + .desc = { + .name = "LDO-AUDIO", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUDIO, + .owner = THIS_MODULE, + .n_voltages = 1, + .enable_time = 140, + .volt_table = fixed_2000000_voltage, + }, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x02, + .update_val = 0x02, + }, + [AB8500_LDO_ANAMIC1] = { + .desc = { + .name = "LDO-ANAMIC1", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANAMIC1, + .owner = THIS_MODULE, + .n_voltages = 1, + .enable_time = 500, + .volt_table = fixed_2050000_voltage, + }, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x08, + .update_val = 0x08, + }, + [AB8500_LDO_ANAMIC2] = { + .desc = { + .name = "LDO-ANAMIC2", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANAMIC2, + .owner = THIS_MODULE, + .n_voltages = 1, + .enable_time = 500, + .volt_table = fixed_2050000_voltage, + }, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x10, + .update_val = 0x10, + }, + [AB8500_LDO_DMIC] = { + .desc = { + .name = "LDO-DMIC", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_DMIC, + .owner = THIS_MODULE, + .n_voltages = 1, + .enable_time = 420, + .volt_table = fixed_1800000_voltage, + }, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x04, + .update_val = 0x04, + }, + + /* + * Regulators with fixed voltage and normal/idle modes + */ + [AB8500_LDO_ANA] = { + .desc = { + .name = "LDO-ANA", + .ops = &ab8500_regulator_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANA, + .owner = THIS_MODULE, + .n_voltages = 1, + .enable_time = 140, + .volt_table = fixed_1200000_voltage, + }, + .load_lp_uA = 1000, + .update_bank = 0x04, + .update_reg = 0x06, + .update_mask = 0x0c, + .update_val = 0x04, + .update_val_idle = 0x0c, + .update_val_normal = 0x04, + }, +}; + +/* AB8505 regulator information */ +static struct ab8500_regulator_info + ab8505_regulator_info[AB8505_NUM_REGULATORS] = { + /* + * Variable Voltage Regulators + * name, min mV, max mV, + * update bank, reg, mask, enable val + * volt bank, reg, mask + */ + [AB8505_LDO_AUX1] = { + .desc = { + .name = "LDO-AUX1", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_LDO_AUX1, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + .volt_table = ldo_vauxn_voltages, + }, + .load_lp_uA = 5000, + .update_bank = 0x04, + .update_reg = 0x09, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x1f, + .voltage_mask = 0x0f, + }, + [AB8505_LDO_AUX2] = { + .desc = { + .name = "LDO-AUX2", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_LDO_AUX2, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + .volt_table = ldo_vauxn_voltages, + }, + .load_lp_uA = 5000, + .update_bank = 0x04, + .update_reg = 0x09, + .update_mask = 0x0c, + .update_val = 0x04, + .update_val_idle = 0x0c, + .update_val_normal = 0x04, + .voltage_bank = 0x04, + .voltage_reg = 0x20, + .voltage_mask = 0x0f, + }, + [AB8505_LDO_AUX3] = { + .desc = { + .name = "LDO-AUX3", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_LDO_AUX3, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaux3_voltages), + .volt_table = ldo_vaux3_voltages, + }, + .load_lp_uA = 5000, + .update_bank = 0x04, + .update_reg = 0x0a, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x21, + .voltage_mask = 0x07, + }, + [AB8505_LDO_AUX4] = { + .desc = { + .name = "LDO-AUX4", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_LDO_AUX4, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + .volt_table = ldo_vauxn_voltages, + }, + .load_lp_uA = 5000, + /* values for Vaux4Regu register */ + .update_bank = 0x04, + .update_reg = 0x2e, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + /* values for Vaux4SEL register */ + .voltage_bank = 0x04, + .voltage_reg = 0x2f, + .voltage_mask = 0x0f, + }, + [AB8505_LDO_AUX5] = { + .desc = { + .name = "LDO-AUX5", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_LDO_AUX5, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaux56_voltages), + .volt_table = ldo_vaux56_voltages, + }, + .load_lp_uA = 2000, + /* values for CtrlVaux5 register */ + .update_bank = 0x01, + .update_reg = 0x55, + .update_mask = 0x18, + .update_val = 0x10, + .update_val_idle = 0x18, + .update_val_normal = 0x10, + .voltage_bank = 0x01, + .voltage_reg = 0x55, + .voltage_mask = 0x07, + }, + [AB8505_LDO_AUX6] = { + .desc = { + .name = "LDO-AUX6", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_LDO_AUX6, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaux56_voltages), + .volt_table = ldo_vaux56_voltages, + }, + .load_lp_uA = 2000, + /* values for CtrlVaux6 register */ + .update_bank = 0x01, + .update_reg = 0x56, + .update_mask = 0x18, + .update_val = 0x10, + .update_val_idle = 0x18, + .update_val_normal = 0x10, + .voltage_bank = 0x01, + .voltage_reg = 0x56, + .voltage_mask = 0x07, + }, + [AB8505_LDO_INTCORE] = { + .desc = { + .name = "LDO-INTCORE", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_LDO_INTCORE, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages), + .volt_table = ldo_vintcore_voltages, + }, + .load_lp_uA = 5000, + .update_bank = 0x03, + .update_reg = 0x80, + .update_mask = 0x44, + .update_val = 0x04, + .update_val_idle = 0x44, + .update_val_normal = 0x04, + .voltage_bank = 0x03, + .voltage_reg = 0x80, + .voltage_mask = 0x38, + }, + + /* + * Fixed Voltage Regulators + * name, fixed mV, + * update bank, reg, mask, enable val + */ + [AB8505_LDO_ADC] = { + .desc = { + .name = "LDO-ADC", + .ops = &ab8500_regulator_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_LDO_ADC, + .owner = THIS_MODULE, + .n_voltages = 1, + .volt_table = fixed_2000000_voltage, .enable_time = 10000, }, - .delay = 10000, + .load_lp_uA = 1000, .update_bank = 0x03, .update_reg = 0x80, .update_mask = 0x82, - .update_val_enable = 0x02, + .update_val = 0x02, + .update_val_idle = 0x82, + .update_val_normal = 0x02, }, - [AB8500_LDO_USB] = { + [AB8505_LDO_USB] = { .desc = { .name = "LDO-USB", - .ops = &ab8500_regulator_fixed_ops, + .ops = &ab8500_regulator_mode_ops, .type = REGULATOR_VOLTAGE, - .id = AB8500_LDO_USB, + .id = AB8505_LDO_USB, .owner = THIS_MODULE, .n_voltages = 1, - .min_uV = 3300000, + .volt_table = fixed_3300000_voltage, }, .update_bank = 0x03, .update_reg = 0x82, .update_mask = 0x03, - .update_val_enable = 0x01, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, }, - [AB8500_LDO_AUDIO] = { + [AB8505_LDO_AUDIO] = { .desc = { .name = "LDO-AUDIO", - .ops = &ab8500_regulator_fixed_ops, + .ops = &ab8500_regulator_volt_ops, .type = REGULATOR_VOLTAGE, - .id = AB8500_LDO_AUDIO, + .id = AB8505_LDO_AUDIO, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaudio_voltages), + .volt_table = ldo_vaudio_voltages, + }, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x02, + .update_val = 0x02, + .voltage_bank = 0x01, + .voltage_reg = 0x57, + .voltage_mask = 0x70, + }, + [AB8505_LDO_ANAMIC1] = { + .desc = { + .name = "LDO-ANAMIC1", + .ops = &ab8500_regulator_anamic_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_LDO_ANAMIC1, + .owner = THIS_MODULE, + .n_voltages = 1, + .volt_table = fixed_2050000_voltage, + }, + .shared_mode = &ldo_anamic1_shared, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x08, + .update_val = 0x08, + .mode_bank = 0x01, + .mode_reg = 0x54, + .mode_mask = 0x04, + .mode_val_idle = 0x04, + .mode_val_normal = 0x00, + }, + [AB8505_LDO_ANAMIC2] = { + .desc = { + .name = "LDO-ANAMIC2", + .ops = &ab8500_regulator_anamic_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_LDO_ANAMIC2, .owner = THIS_MODULE, .n_voltages = 1, - .min_uV = 2000000, + .volt_table = fixed_2050000_voltage, + }, + .shared_mode = &ldo_anamic2_shared, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x10, + .update_val = 0x10, + .mode_bank = 0x01, + .mode_reg = 0x54, + .mode_mask = 0x04, + .mode_val_idle = 0x04, + .mode_val_normal = 0x00, + }, + [AB8505_LDO_AUX8] = { + .desc = { + .name = "LDO-AUX8", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_LDO_AUX8, + .owner = THIS_MODULE, + .n_voltages = 1, + .volt_table = fixed_1800000_voltage, + }, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x04, + .update_val = 0x04, + }, + /* + * Regulators with fixed voltage and normal/idle modes + */ + [AB8505_LDO_ANA] = { + .desc = { + .name = "LDO-ANA", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_LDO_ANA, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vana_voltages), + .volt_table = ldo_vana_voltages, + }, + .load_lp_uA = 1000, + .update_bank = 0x04, + .update_reg = 0x06, + .update_mask = 0x0c, + .update_val = 0x04, + .update_val_idle = 0x0c, + .update_val_normal = 0x04, + .voltage_bank = 0x04, + .voltage_reg = 0x29, + .voltage_mask = 0x7, + }, +}; + +/* AB9540 regulator information */ +static struct ab8500_regulator_info + ab9540_regulator_info[AB9540_NUM_REGULATORS] = { + /* + * Variable Voltage Regulators + * name, min mV, max mV, + * update bank, reg, mask, enable val + * volt bank, reg, mask + */ + [AB9540_LDO_AUX1] = { + .desc = { + .name = "LDO-AUX1", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB9540_LDO_AUX1, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + .volt_table = ldo_vauxn_voltages, + }, + .load_lp_uA = 5000, + .update_bank = 0x04, + .update_reg = 0x09, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x1f, + .voltage_mask = 0x0f, + }, + [AB9540_LDO_AUX2] = { + .desc = { + .name = "LDO-AUX2", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB9540_LDO_AUX2, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + .volt_table = ldo_vauxn_voltages, + }, + .load_lp_uA = 5000, + .update_bank = 0x04, + .update_reg = 0x09, + .update_mask = 0x0c, + .update_val = 0x04, + .update_val_idle = 0x0c, + .update_val_normal = 0x04, + .voltage_bank = 0x04, + .voltage_reg = 0x20, + .voltage_mask = 0x0f, + }, + [AB9540_LDO_AUX3] = { + .desc = { + .name = "LDO-AUX3", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB9540_LDO_AUX3, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaux3_voltages), + .volt_table = ldo_vaux3_voltages, + }, + .load_lp_uA = 5000, + .update_bank = 0x04, + .update_reg = 0x0a, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x21, + .voltage_mask = 0x07, + }, + [AB9540_LDO_AUX4] = { + .desc = { + .name = "LDO-AUX4", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB9540_LDO_AUX4, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + .volt_table = ldo_vauxn_voltages, + }, + .load_lp_uA = 5000, + /* values for Vaux4Regu register */ + .update_bank = 0x04, + .update_reg = 0x2e, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + /* values for Vaux4SEL register */ + .voltage_bank = 0x04, + .voltage_reg = 0x2f, + .voltage_mask = 0x0f, + }, + [AB9540_LDO_INTCORE] = { + .desc = { + .name = "LDO-INTCORE", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB9540_LDO_INTCORE, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages), + .volt_table = ldo_vintcore_voltages, + }, + .load_lp_uA = 5000, + .update_bank = 0x03, + .update_reg = 0x80, + .update_mask = 0x44, + .update_val = 0x44, + .update_val_idle = 0x44, + .update_val_normal = 0x04, + .voltage_bank = 0x03, + .voltage_reg = 0x80, + .voltage_mask = 0x38, + }, + + /* + * Fixed Voltage Regulators + * name, fixed mV, + * update bank, reg, mask, enable val + */ + [AB9540_LDO_TVOUT] = { + .desc = { + .name = "LDO-TVOUT", + .ops = &ab8500_regulator_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB9540_LDO_TVOUT, + .owner = THIS_MODULE, + .n_voltages = 1, + .volt_table = fixed_2000000_voltage, + .enable_time = 10000, + }, + .load_lp_uA = 1000, + .update_bank = 0x03, + .update_reg = 0x80, + .update_mask = 0x82, + .update_val = 0x02, + .update_val_idle = 0x82, + .update_val_normal = 0x02, + }, + [AB9540_LDO_USB] = { + .desc = { + .name = "LDO-USB", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB9540_LDO_USB, + .owner = THIS_MODULE, + .n_voltages = 1, + .volt_table = fixed_3300000_voltage, + }, + .update_bank = 0x03, + .update_reg = 0x82, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + }, + [AB9540_LDO_AUDIO] = { + .desc = { + .name = "LDO-AUDIO", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB9540_LDO_AUDIO, + .owner = THIS_MODULE, + .n_voltages = 1, + .volt_table = fixed_2000000_voltage, }, .update_bank = 0x03, .update_reg = 0x83, .update_mask = 0x02, - .update_val_enable = 0x02, + .update_val = 0x02, }, - [AB8500_LDO_ANAMIC1] = { + [AB9540_LDO_ANAMIC1] = { .desc = { .name = "LDO-ANAMIC1", - .ops = &ab8500_regulator_fixed_ops, + .ops = &ab8500_regulator_ops, .type = REGULATOR_VOLTAGE, - .id = AB8500_LDO_ANAMIC1, + .id = AB9540_LDO_ANAMIC1, .owner = THIS_MODULE, .n_voltages = 1, - .min_uV = 2050000, + .volt_table = fixed_2050000_voltage, }, .update_bank = 0x03, .update_reg = 0x83, .update_mask = 0x08, - .update_val_enable = 0x08, + .update_val = 0x08, }, - [AB8500_LDO_ANAMIC2] = { + [AB9540_LDO_ANAMIC2] = { .desc = { .name = "LDO-ANAMIC2", - .ops = &ab8500_regulator_fixed_ops, + .ops = &ab8500_regulator_ops, .type = REGULATOR_VOLTAGE, - .id = AB8500_LDO_ANAMIC2, + .id = AB9540_LDO_ANAMIC2, .owner = THIS_MODULE, .n_voltages = 1, - .min_uV = 2050000, + .volt_table = fixed_2050000_voltage, }, .update_bank = 0x03, .update_reg = 0x83, .update_mask = 0x10, - .update_val_enable = 0x10, + .update_val = 0x10, }, - [AB8500_LDO_DMIC] = { + [AB9540_LDO_DMIC] = { .desc = { .name = "LDO-DMIC", - .ops = &ab8500_regulator_fixed_ops, + .ops = &ab8500_regulator_ops, .type = REGULATOR_VOLTAGE, - .id = AB8500_LDO_DMIC, + .id = AB9540_LDO_DMIC, .owner = THIS_MODULE, .n_voltages = 1, - .min_uV = 1800000, + .volt_table = fixed_1800000_voltage, }, .update_bank = 0x03, .update_reg = 0x83, .update_mask = 0x04, - .update_val_enable = 0x04, + .update_val = 0x04, }, - [AB8500_LDO_ANA] = { + + /* + * Regulators with fixed voltage and normal/idle modes + */ + [AB9540_LDO_ANA] = { .desc = { .name = "LDO-ANA", - .ops = &ab8500_regulator_fixed_ops, + .ops = &ab8500_regulator_mode_ops, .type = REGULATOR_VOLTAGE, - .id = AB8500_LDO_ANA, + .id = AB9540_LDO_ANA, .owner = THIS_MODULE, .n_voltages = 1, - .min_uV = 1200000, + .volt_table = fixed_1200000_voltage, }, + .load_lp_uA = 1000, .update_bank = 0x04, .update_reg = 0x06, .update_mask = 0x0c, - .update_val_enable = 0x04, + .update_val = 0x08, + .update_val_idle = 0x0c, + .update_val_normal = 0x08, }, +}; +/* AB8540 regulator information */ +static struct ab8500_regulator_info + ab8540_regulator_info[AB8540_NUM_REGULATORS] = { + /* + * Variable Voltage Regulators + * name, min mV, max mV, + * update bank, reg, mask, enable val + * volt bank, reg, mask + */ + [AB8540_LDO_AUX1] = { + .desc = { + .name = "LDO-AUX1", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_AUX1, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + .volt_table = ldo_vauxn_voltages, + }, + .load_lp_uA = 5000, + .update_bank = 0x04, + .update_reg = 0x09, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x1f, + .voltage_mask = 0x0f, + }, + [AB8540_LDO_AUX2] = { + .desc = { + .name = "LDO-AUX2", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_AUX2, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + .volt_table = ldo_vauxn_voltages, + }, + .load_lp_uA = 5000, + .update_bank = 0x04, + .update_reg = 0x09, + .update_mask = 0x0c, + .update_val = 0x04, + .update_val_idle = 0x0c, + .update_val_normal = 0x04, + .voltage_bank = 0x04, + .voltage_reg = 0x20, + .voltage_mask = 0x0f, + }, + [AB8540_LDO_AUX3] = { + .desc = { + .name = "LDO-AUX3", + .ops = &ab8540_aux3_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_AUX3, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaux3_ab8540_voltages), + .volt_table = ldo_vaux3_ab8540_voltages, + }, + .load_lp_uA = 5000, + .update_bank = 0x04, + .update_reg = 0x0a, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x21, + .voltage_mask = 0x07, + .expand_register = { + .voltage_limit = 8, + .voltage_bank = 0x04, + .voltage_reg = 0x01, + .voltage_mask = 0x10, + } + }, + [AB8540_LDO_AUX4] = { + .desc = { + .name = "LDO-AUX4", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_AUX4, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + .volt_table = ldo_vauxn_voltages, + }, + .load_lp_uA = 5000, + /* values for Vaux4Regu register */ + .update_bank = 0x04, + .update_reg = 0x2e, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + /* values for Vaux4SEL register */ + .voltage_bank = 0x04, + .voltage_reg = 0x2f, + .voltage_mask = 0x0f, + }, + [AB8540_LDO_AUX5] = { + .desc = { + .name = "LDO-AUX5", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_AUX5, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaux56_ab8540_voltages), + .volt_table = ldo_vaux56_ab8540_voltages, + }, + .load_lp_uA = 20000, + /* values for Vaux5Regu register */ + .update_bank = 0x04, + .update_reg = 0x32, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + /* values for Vaux5SEL register */ + .voltage_bank = 0x04, + .voltage_reg = 0x33, + .voltage_mask = 0x3f, + }, + [AB8540_LDO_AUX6] = { + .desc = { + .name = "LDO-AUX6", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_AUX6, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaux56_ab8540_voltages), + .volt_table = ldo_vaux56_ab8540_voltages, + }, + .load_lp_uA = 20000, + /* values for Vaux6Regu register */ + .update_bank = 0x04, + .update_reg = 0x35, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + /* values for Vaux6SEL register */ + .voltage_bank = 0x04, + .voltage_reg = 0x36, + .voltage_mask = 0x3f, + }, + [AB8540_LDO_INTCORE] = { + .desc = { + .name = "LDO-INTCORE", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_INTCORE, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages), + .volt_table = ldo_vintcore_voltages, + }, + .load_lp_uA = 5000, + .update_bank = 0x03, + .update_reg = 0x80, + .update_mask = 0x44, + .update_val = 0x44, + .update_val_idle = 0x44, + .update_val_normal = 0x04, + .voltage_bank = 0x03, + .voltage_reg = 0x80, + .voltage_mask = 0x38, + }, + /* + * Fixed Voltage Regulators + * name, fixed mV, + * update bank, reg, mask, enable val + */ + [AB8540_LDO_TVOUT] = { + .desc = { + .name = "LDO-TVOUT", + .ops = &ab8500_regulator_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_TVOUT, + .owner = THIS_MODULE, + .n_voltages = 1, + .volt_table = fixed_2000000_voltage, + .enable_time = 10000, + }, + .load_lp_uA = 1000, + .update_bank = 0x03, + .update_reg = 0x80, + .update_mask = 0x82, + .update_val = 0x02, + .update_val_idle = 0x82, + .update_val_normal = 0x02, + }, + [AB8540_LDO_AUDIO] = { + .desc = { + .name = "LDO-AUDIO", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_AUDIO, + .owner = THIS_MODULE, + .n_voltages = 1, + .volt_table = fixed_2000000_voltage, + }, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x02, + .update_val = 0x02, + }, + [AB8540_LDO_ANAMIC1] = { + .desc = { + .name = "LDO-ANAMIC1", + .ops = &ab8500_regulator_anamic_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_ANAMIC1, + .owner = THIS_MODULE, + .n_voltages = 1, + .volt_table = fixed_2050000_voltage, + }, + .shared_mode = &ab8540_ldo_anamic1_shared, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x08, + .update_val = 0x08, + .mode_bank = 0x03, + .mode_reg = 0x83, + .mode_mask = 0x20, + .mode_val_idle = 0x20, + .mode_val_normal = 0x00, + }, + [AB8540_LDO_ANAMIC2] = { + .desc = { + .name = "LDO-ANAMIC2", + .ops = &ab8500_regulator_anamic_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_ANAMIC2, + .owner = THIS_MODULE, + .n_voltages = 1, + .volt_table = fixed_2050000_voltage, + }, + .shared_mode = &ab8540_ldo_anamic2_shared, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x10, + .update_val = 0x10, + .mode_bank = 0x03, + .mode_reg = 0x83, + .mode_mask = 0x20, + .mode_val_idle = 0x20, + .mode_val_normal = 0x00, + }, + [AB8540_LDO_DMIC] = { + .desc = { + .name = "LDO-DMIC", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_DMIC, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vdmic_voltages), + .volt_table = ldo_vdmic_voltages, + }, + .load_lp_uA = 1000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x04, + .update_val = 0x04, + .voltage_bank = 0x03, + .voltage_reg = 0x83, + .voltage_mask = 0xc0, + }, + + /* + * Regulators with fixed voltage and normal/idle modes + */ + [AB8540_LDO_ANA] = { + .desc = { + .name = "LDO-ANA", + .ops = &ab8500_regulator_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_ANA, + .owner = THIS_MODULE, + .n_voltages = 1, + .volt_table = fixed_1200000_voltage, + }, + .load_lp_uA = 1000, + .update_bank = 0x04, + .update_reg = 0x06, + .update_mask = 0x0c, + .update_val = 0x04, + .update_val_idle = 0x0c, + .update_val_normal = 0x04, + }, + [AB8540_LDO_SDIO] = { + .desc = { + .name = "LDO-SDIO", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_SDIO, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_sdio_voltages), + .volt_table = ldo_sdio_voltages, + }, + .load_lp_uA = 5000, + .update_bank = 0x03, + .update_reg = 0x88, + .update_mask = 0x30, + .update_val = 0x10, + .update_val_idle = 0x30, + .update_val_normal = 0x10, + .voltage_bank = 0x03, + .voltage_reg = 0x88, + .voltage_mask = 0x07, + }, +}; + +static struct ab8500_shared_mode ldo_anamic1_shared = { + .shared_regulator = &ab8505_regulator_info[AB8505_LDO_ANAMIC2], +}; + +static struct ab8500_shared_mode ldo_anamic2_shared = { + .shared_regulator = &ab8505_regulator_info[AB8505_LDO_ANAMIC1], +}; + +static struct ab8500_shared_mode ab8540_ldo_anamic1_shared = { + .shared_regulator = &ab8540_regulator_info[AB8540_LDO_ANAMIC2], +}; + +static struct ab8500_shared_mode ab8540_ldo_anamic2_shared = { + .shared_regulator = &ab8540_regulator_info[AB8540_LDO_ANAMIC1], }; struct ab8500_reg_init { @@ -474,13 +1799,13 @@ struct ab8500_reg_init { .mask = _mask, \ } +/* AB8500 register init */ static struct ab8500_reg_init ab8500_reg_init[] = { /* * 0x30, VanaRequestCtrl - * 0x0C, VpllRequestCtrl * 0xc0, VextSupply1RequestCtrl */ - REG_INIT(AB8500_REGUREQUESTCTRL2, 0x03, 0x04, 0xfc), + REG_INIT(AB8500_REGUREQUESTCTRL2, 0x03, 0x04, 0xf0), /* * 0x03, VextSupply2RequestCtrl * 0x0c, VextSupply3RequestCtrl @@ -547,13 +1872,21 @@ static struct ab8500_reg_init ab8500_reg_init[] = { REG_INIT(AB8500_REGUSWHPREQVALID2, 0x03, 0x0e, 0x1f), /* * 0x02, SysClkReq2Valid1 - * ... + * 0x04, SysClkReq3Valid1 + * 0x08, SysClkReq4Valid1 + * 0x10, SysClkReq5Valid1 + * 0x20, SysClkReq6Valid1 + * 0x40, SysClkReq7Valid1 * 0x80, SysClkReq8Valid1 */ REG_INIT(AB8500_REGUSYSCLKREQVALID1, 0x03, 0x0f, 0xfe), /* * 0x02, SysClkReq2Valid2 - * ... + * 0x04, SysClkReq3Valid2 + * 0x08, SysClkReq4Valid2 + * 0x10, SysClkReq5Valid2 + * 0x20, SysClkReq6Valid2 + * 0x40, SysClkReq7Valid2 * 0x80, SysClkReq8Valid2 */ REG_INIT(AB8500_REGUSYSCLKREQVALID2, 0x03, 0x10, 0xfe), @@ -578,8 +1911,8 @@ static struct ab8500_reg_init ab8500_reg_init[] = { */ REG_INIT(AB8500_REGUCTRL1VAMIC, 0x03, 0x84, 0x03), /* + * 0x03, VpllRegu (NOTE! PRCMU register bits) * 0x0c, VanaRegu - * 0x03, VpllRegu */ REG_INIT(AB8500_VPLLVANAREGU, 0x04, 0x06, 0x0f), /* @@ -605,10 +1938,6 @@ static struct ab8500_reg_init ab8500_reg_init[] = { */ REG_INIT(AB8500_VRF1VAUX3REGU, 0x04, 0x0a, 0x03), /* - * 0x3f, Vsmps1Sel1 - */ - REG_INIT(AB8500_VSMPS1SEL1, 0x04, 0x13, 0x3f), - /* * 0x0f, Vaux1Sel */ REG_INIT(AB8500_VAUX1SEL, 0x04, 0x1f, 0x0f), @@ -641,52 +1970,1073 @@ static struct ab8500_reg_init ab8500_reg_init[] = { REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x16), }; -static int -ab8500_regulator_init_registers(struct platform_device *pdev, int id, int value) +/* AB8505 register init */ +static struct ab8500_reg_init ab8505_reg_init[] = { + /* + * 0x03, VarmRequestCtrl + * 0x0c, VsmpsCRequestCtrl + * 0x30, VsmpsARequestCtrl + * 0xc0, VsmpsBRequestCtrl + */ + REG_INIT(AB8505_REGUREQUESTCTRL1, 0x03, 0x03, 0xff), + /* + * 0x03, VsafeRequestCtrl + * 0x0c, VpllRequestCtrl + * 0x30, VanaRequestCtrl + */ + REG_INIT(AB8505_REGUREQUESTCTRL2, 0x03, 0x04, 0x3f), + /* + * 0x30, Vaux1RequestCtrl + * 0xc0, Vaux2RequestCtrl + */ + REG_INIT(AB8505_REGUREQUESTCTRL3, 0x03, 0x05, 0xf0), + /* + * 0x03, Vaux3RequestCtrl + * 0x04, SwHPReq + */ + REG_INIT(AB8505_REGUREQUESTCTRL4, 0x03, 0x06, 0x07), + /* + * 0x01, VsmpsASysClkReq1HPValid + * 0x02, VsmpsBSysClkReq1HPValid + * 0x04, VsafeSysClkReq1HPValid + * 0x08, VanaSysClkReq1HPValid + * 0x10, VpllSysClkReq1HPValid + * 0x20, Vaux1SysClkReq1HPValid + * 0x40, Vaux2SysClkReq1HPValid + * 0x80, Vaux3SysClkReq1HPValid + */ + REG_INIT(AB8505_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xff), + /* + * 0x01, VsmpsCSysClkReq1HPValid + * 0x02, VarmSysClkReq1HPValid + * 0x04, VbbSysClkReq1HPValid + * 0x08, VsmpsMSysClkReq1HPValid + */ + REG_INIT(AB8505_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x0f), + /* + * 0x01, VsmpsAHwHPReq1Valid + * 0x02, VsmpsBHwHPReq1Valid + * 0x04, VsafeHwHPReq1Valid + * 0x08, VanaHwHPReq1Valid + * 0x10, VpllHwHPReq1Valid + * 0x20, Vaux1HwHPReq1Valid + * 0x40, Vaux2HwHPReq1Valid + * 0x80, Vaux3HwHPReq1Valid + */ + REG_INIT(AB8505_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xff), + /* + * 0x08, VsmpsMHwHPReq1Valid + */ + REG_INIT(AB8505_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x08), + /* + * 0x01, VsmpsAHwHPReq2Valid + * 0x02, VsmpsBHwHPReq2Valid + * 0x04, VsafeHwHPReq2Valid + * 0x08, VanaHwHPReq2Valid + * 0x10, VpllHwHPReq2Valid + * 0x20, Vaux1HwHPReq2Valid + * 0x40, Vaux2HwHPReq2Valid + * 0x80, Vaux3HwHPReq2Valid + */ + REG_INIT(AB8505_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xff), + /* + * 0x08, VsmpsMHwHPReq2Valid + */ + REG_INIT(AB8505_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x08), + /* + * 0x01, VsmpsCSwHPReqValid + * 0x02, VarmSwHPReqValid + * 0x04, VsmpsASwHPReqValid + * 0x08, VsmpsBSwHPReqValid + * 0x10, VsafeSwHPReqValid + * 0x20, VanaSwHPReqValid + * 0x40, VpllSwHPReqValid + * 0x80, Vaux1SwHPReqValid + */ + REG_INIT(AB8505_REGUSWHPREQVALID1, 0x03, 0x0d, 0xff), + /* + * 0x01, Vaux2SwHPReqValid + * 0x02, Vaux3SwHPReqValid + * 0x20, VsmpsMSwHPReqValid + */ + REG_INIT(AB8505_REGUSWHPREQVALID2, 0x03, 0x0e, 0x23), + /* + * 0x02, SysClkReq2Valid1 + * 0x04, SysClkReq3Valid1 + * 0x08, SysClkReq4Valid1 + */ + REG_INIT(AB8505_REGUSYSCLKREQVALID1, 0x03, 0x0f, 0x0e), + /* + * 0x02, SysClkReq2Valid2 + * 0x04, SysClkReq3Valid2 + * 0x08, SysClkReq4Valid2 + */ + REG_INIT(AB8505_REGUSYSCLKREQVALID2, 0x03, 0x10, 0x0e), + /* + * 0x01, Vaux4SwHPReqValid + * 0x02, Vaux4HwHPReq2Valid + * 0x04, Vaux4HwHPReq1Valid + * 0x08, Vaux4SysClkReq1HPValid + */ + REG_INIT(AB8505_REGUVAUX4REQVALID, 0x03, 0x11, 0x0f), + /* + * 0x02, VadcEna + * 0x04, VintCore12Ena + * 0x38, VintCore12Sel + * 0x40, VintCore12LP + * 0x80, VadcLP + */ + REG_INIT(AB8505_REGUMISC1, 0x03, 0x80, 0xfe), + /* + * 0x02, VaudioEna + * 0x04, VdmicEna + * 0x08, Vamic1Ena + * 0x10, Vamic2Ena + */ + REG_INIT(AB8505_VAUDIOSUPPLY, 0x03, 0x83, 0x1e), + /* + * 0x01, Vamic1_dzout + * 0x02, Vamic2_dzout + */ + REG_INIT(AB8505_REGUCTRL1VAMIC, 0x03, 0x84, 0x03), + /* + * 0x03, VsmpsARegu + * 0x0c, VsmpsASelCtrl + * 0x10, VsmpsAAutoMode + * 0x20, VsmpsAPWMMode + */ + REG_INIT(AB8505_VSMPSAREGU, 0x04, 0x03, 0x3f), + /* + * 0x03, VsmpsBRegu + * 0x0c, VsmpsBSelCtrl + * 0x10, VsmpsBAutoMode + * 0x20, VsmpsBPWMMode + */ + REG_INIT(AB8505_VSMPSBREGU, 0x04, 0x04, 0x3f), + /* + * 0x03, VsafeRegu + * 0x0c, VsafeSelCtrl + * 0x10, VsafeAutoMode + * 0x20, VsafePWMMode + */ + REG_INIT(AB8505_VSAFEREGU, 0x04, 0x05, 0x3f), + /* + * 0x03, VpllRegu (NOTE! PRCMU register bits) + * 0x0c, VanaRegu + */ + REG_INIT(AB8505_VPLLVANAREGU, 0x04, 0x06, 0x0f), + /* + * 0x03, VextSupply1Regu + * 0x0c, VextSupply2Regu + * 0x30, VextSupply3Regu + * 0x40, ExtSupply2Bypass + * 0x80, ExtSupply3Bypass + */ + REG_INIT(AB8505_EXTSUPPLYREGU, 0x04, 0x08, 0xff), + /* + * 0x03, Vaux1Regu + * 0x0c, Vaux2Regu + */ + REG_INIT(AB8505_VAUX12REGU, 0x04, 0x09, 0x0f), + /* + * 0x0f, Vaux3Regu + */ + REG_INIT(AB8505_VRF1VAUX3REGU, 0x04, 0x0a, 0x0f), + /* + * 0x3f, VsmpsASel1 + */ + REG_INIT(AB8505_VSMPSASEL1, 0x04, 0x13, 0x3f), + /* + * 0x3f, VsmpsASel2 + */ + REG_INIT(AB8505_VSMPSASEL2, 0x04, 0x14, 0x3f), + /* + * 0x3f, VsmpsASel3 + */ + REG_INIT(AB8505_VSMPSASEL3, 0x04, 0x15, 0x3f), + /* + * 0x3f, VsmpsBSel1 + */ + REG_INIT(AB8505_VSMPSBSEL1, 0x04, 0x17, 0x3f), + /* + * 0x3f, VsmpsBSel2 + */ + REG_INIT(AB8505_VSMPSBSEL2, 0x04, 0x18, 0x3f), + /* + * 0x3f, VsmpsBSel3 + */ + REG_INIT(AB8505_VSMPSBSEL3, 0x04, 0x19, 0x3f), + /* + * 0x7f, VsafeSel1 + */ + REG_INIT(AB8505_VSAFESEL1, 0x04, 0x1b, 0x7f), + /* + * 0x3f, VsafeSel2 + */ + REG_INIT(AB8505_VSAFESEL2, 0x04, 0x1c, 0x7f), + /* + * 0x3f, VsafeSel3 + */ + REG_INIT(AB8505_VSAFESEL3, 0x04, 0x1d, 0x7f), + /* + * 0x0f, Vaux1Sel + */ + REG_INIT(AB8505_VAUX1SEL, 0x04, 0x1f, 0x0f), + /* + * 0x0f, Vaux2Sel + */ + REG_INIT(AB8505_VAUX2SEL, 0x04, 0x20, 0x0f), + /* + * 0x07, Vaux3Sel + * 0x30, VRF1Sel + */ + REG_INIT(AB8505_VRF1VAUX3SEL, 0x04, 0x21, 0x37), + /* + * 0x03, Vaux4RequestCtrl + */ + REG_INIT(AB8505_VAUX4REQCTRL, 0x04, 0x2d, 0x03), + /* + * 0x03, Vaux4Regu + */ + REG_INIT(AB8505_VAUX4REGU, 0x04, 0x2e, 0x03), + /* + * 0x0f, Vaux4Sel + */ + REG_INIT(AB8505_VAUX4SEL, 0x04, 0x2f, 0x0f), + /* + * 0x04, Vaux1Disch + * 0x08, Vaux2Disch + * 0x10, Vaux3Disch + * 0x20, Vintcore12Disch + * 0x40, VTVoutDisch + * 0x80, VaudioDisch + */ + REG_INIT(AB8505_REGUCTRLDISCH, 0x04, 0x43, 0xfc), + /* + * 0x02, VanaDisch + * 0x04, VdmicPullDownEna + * 0x10, VdmicDisch + */ + REG_INIT(AB8505_REGUCTRLDISCH2, 0x04, 0x44, 0x16), + /* + * 0x01, Vaux4Disch + */ + REG_INIT(AB8505_REGUCTRLDISCH3, 0x04, 0x48, 0x01), + /* + * 0x07, Vaux5Sel + * 0x08, Vaux5LP + * 0x10, Vaux5Ena + * 0x20, Vaux5Disch + * 0x40, Vaux5DisSfst + * 0x80, Vaux5DisPulld + */ + REG_INIT(AB8505_CTRLVAUX5, 0x01, 0x55, 0xff), + /* + * 0x07, Vaux6Sel + * 0x08, Vaux6LP + * 0x10, Vaux6Ena + * 0x80, Vaux6DisPulld + */ + REG_INIT(AB8505_CTRLVAUX6, 0x01, 0x56, 0x9f), +}; + +/* AB9540 register init */ +static struct ab8500_reg_init ab9540_reg_init[] = { + /* + * 0x03, VarmRequestCtrl + * 0x0c, VapeRequestCtrl + * 0x30, Vsmps1RequestCtrl + * 0xc0, Vsmps2RequestCtrl + */ + REG_INIT(AB9540_REGUREQUESTCTRL1, 0x03, 0x03, 0xff), + /* + * 0x03, Vsmps3RequestCtrl + * 0x0c, VpllRequestCtrl + * 0x30, VanaRequestCtrl + * 0xc0, VextSupply1RequestCtrl + */ + REG_INIT(AB9540_REGUREQUESTCTRL2, 0x03, 0x04, 0xff), + /* + * 0x03, VextSupply2RequestCtrl + * 0x0c, VextSupply3RequestCtrl + * 0x30, Vaux1RequestCtrl + * 0xc0, Vaux2RequestCtrl + */ + REG_INIT(AB9540_REGUREQUESTCTRL3, 0x03, 0x05, 0xff), + /* + * 0x03, Vaux3RequestCtrl + * 0x04, SwHPReq + */ + REG_INIT(AB9540_REGUREQUESTCTRL4, 0x03, 0x06, 0x07), + /* + * 0x01, Vsmps1SysClkReq1HPValid + * 0x02, Vsmps2SysClkReq1HPValid + * 0x04, Vsmps3SysClkReq1HPValid + * 0x08, VanaSysClkReq1HPValid + * 0x10, VpllSysClkReq1HPValid + * 0x20, Vaux1SysClkReq1HPValid + * 0x40, Vaux2SysClkReq1HPValid + * 0x80, Vaux3SysClkReq1HPValid + */ + REG_INIT(AB9540_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xff), + /* + * 0x01, VapeSysClkReq1HPValid + * 0x02, VarmSysClkReq1HPValid + * 0x04, VbbSysClkReq1HPValid + * 0x08, VmodSysClkReq1HPValid + * 0x10, VextSupply1SysClkReq1HPValid + * 0x20, VextSupply2SysClkReq1HPValid + * 0x40, VextSupply3SysClkReq1HPValid + */ + REG_INIT(AB9540_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x7f), + /* + * 0x01, Vsmps1HwHPReq1Valid + * 0x02, Vsmps2HwHPReq1Valid + * 0x04, Vsmps3HwHPReq1Valid + * 0x08, VanaHwHPReq1Valid + * 0x10, VpllHwHPReq1Valid + * 0x20, Vaux1HwHPReq1Valid + * 0x40, Vaux2HwHPReq1Valid + * 0x80, Vaux3HwHPReq1Valid + */ + REG_INIT(AB9540_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xff), + /* + * 0x01, VextSupply1HwHPReq1Valid + * 0x02, VextSupply2HwHPReq1Valid + * 0x04, VextSupply3HwHPReq1Valid + * 0x08, VmodHwHPReq1Valid + */ + REG_INIT(AB9540_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x0f), + /* + * 0x01, Vsmps1HwHPReq2Valid + * 0x02, Vsmps2HwHPReq2Valid + * 0x03, Vsmps3HwHPReq2Valid + * 0x08, VanaHwHPReq2Valid + * 0x10, VpllHwHPReq2Valid + * 0x20, Vaux1HwHPReq2Valid + * 0x40, Vaux2HwHPReq2Valid + * 0x80, Vaux3HwHPReq2Valid + */ + REG_INIT(AB9540_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xff), + /* + * 0x01, VextSupply1HwHPReq2Valid + * 0x02, VextSupply2HwHPReq2Valid + * 0x04, VextSupply3HwHPReq2Valid + * 0x08, VmodHwHPReq2Valid + */ + REG_INIT(AB9540_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x0f), + /* + * 0x01, VapeSwHPReqValid + * 0x02, VarmSwHPReqValid + * 0x04, Vsmps1SwHPReqValid + * 0x08, Vsmps2SwHPReqValid + * 0x10, Vsmps3SwHPReqValid + * 0x20, VanaSwHPReqValid + * 0x40, VpllSwHPReqValid + * 0x80, Vaux1SwHPReqValid + */ + REG_INIT(AB9540_REGUSWHPREQVALID1, 0x03, 0x0d, 0xff), + /* + * 0x01, Vaux2SwHPReqValid + * 0x02, Vaux3SwHPReqValid + * 0x04, VextSupply1SwHPReqValid + * 0x08, VextSupply2SwHPReqValid + * 0x10, VextSupply3SwHPReqValid + * 0x20, VmodSwHPReqValid + */ + REG_INIT(AB9540_REGUSWHPREQVALID2, 0x03, 0x0e, 0x3f), + /* + * 0x02, SysClkReq2Valid1 + * ... + * 0x80, SysClkReq8Valid1 + */ + REG_INIT(AB9540_REGUSYSCLKREQVALID1, 0x03, 0x0f, 0xfe), + /* + * 0x02, SysClkReq2Valid2 + * ... + * 0x80, SysClkReq8Valid2 + */ + REG_INIT(AB9540_REGUSYSCLKREQVALID2, 0x03, 0x10, 0xfe), + /* + * 0x01, Vaux4SwHPReqValid + * 0x02, Vaux4HwHPReq2Valid + * 0x04, Vaux4HwHPReq1Valid + * 0x08, Vaux4SysClkReq1HPValid + */ + REG_INIT(AB9540_REGUVAUX4REQVALID, 0x03, 0x11, 0x0f), + /* + * 0x02, VTVoutEna + * 0x04, Vintcore12Ena + * 0x38, Vintcore12Sel + * 0x40, Vintcore12LP + * 0x80, VTVoutLP + */ + REG_INIT(AB9540_REGUMISC1, 0x03, 0x80, 0xfe), + /* + * 0x02, VaudioEna + * 0x04, VdmicEna + * 0x08, Vamic1Ena + * 0x10, Vamic2Ena + */ + REG_INIT(AB9540_VAUDIOSUPPLY, 0x03, 0x83, 0x1e), + /* + * 0x01, Vamic1_dzout + * 0x02, Vamic2_dzout + */ + REG_INIT(AB9540_REGUCTRL1VAMIC, 0x03, 0x84, 0x03), + /* + * 0x03, Vsmps1Regu + * 0x0c, Vsmps1SelCtrl + * 0x10, Vsmps1AutoMode + * 0x20, Vsmps1PWMMode + */ + REG_INIT(AB9540_VSMPS1REGU, 0x04, 0x03, 0x3f), + /* + * 0x03, Vsmps2Regu + * 0x0c, Vsmps2SelCtrl + * 0x10, Vsmps2AutoMode + * 0x20, Vsmps2PWMMode + */ + REG_INIT(AB9540_VSMPS2REGU, 0x04, 0x04, 0x3f), + /* + * 0x03, Vsmps3Regu + * 0x0c, Vsmps3SelCtrl + * NOTE! PRCMU register + */ + REG_INIT(AB9540_VSMPS3REGU, 0x04, 0x05, 0x0f), + /* + * 0x03, VpllRegu + * 0x0c, VanaRegu + */ + REG_INIT(AB9540_VPLLVANAREGU, 0x04, 0x06, 0x0f), + /* + * 0x03, VextSupply1Regu + * 0x0c, VextSupply2Regu + * 0x30, VextSupply3Regu + * 0x40, ExtSupply2Bypass + * 0x80, ExtSupply3Bypass + */ + REG_INIT(AB9540_EXTSUPPLYREGU, 0x04, 0x08, 0xff), + /* + * 0x03, Vaux1Regu + * 0x0c, Vaux2Regu + */ + REG_INIT(AB9540_VAUX12REGU, 0x04, 0x09, 0x0f), + /* + * 0x0c, Vrf1Regu + * 0x03, Vaux3Regu + */ + REG_INIT(AB9540_VRF1VAUX3REGU, 0x04, 0x0a, 0x0f), + /* + * 0x3f, Vsmps1Sel1 + */ + REG_INIT(AB9540_VSMPS1SEL1, 0x04, 0x13, 0x3f), + /* + * 0x3f, Vsmps1Sel2 + */ + REG_INIT(AB9540_VSMPS1SEL2, 0x04, 0x14, 0x3f), + /* + * 0x3f, Vsmps1Sel3 + */ + REG_INIT(AB9540_VSMPS1SEL3, 0x04, 0x15, 0x3f), + /* + * 0x3f, Vsmps2Sel1 + */ + REG_INIT(AB9540_VSMPS2SEL1, 0x04, 0x17, 0x3f), + /* + * 0x3f, Vsmps2Sel2 + */ + REG_INIT(AB9540_VSMPS2SEL2, 0x04, 0x18, 0x3f), + /* + * 0x3f, Vsmps2Sel3 + */ + REG_INIT(AB9540_VSMPS2SEL3, 0x04, 0x19, 0x3f), + /* + * 0x7f, Vsmps3Sel1 + * NOTE! PRCMU register + */ + REG_INIT(AB9540_VSMPS3SEL1, 0x04, 0x1b, 0x7f), + /* + * 0x7f, Vsmps3Sel2 + * NOTE! PRCMU register + */ + REG_INIT(AB9540_VSMPS3SEL2, 0x04, 0x1c, 0x7f), + /* + * 0x0f, Vaux1Sel + */ + REG_INIT(AB9540_VAUX1SEL, 0x04, 0x1f, 0x0f), + /* + * 0x0f, Vaux2Sel + */ + REG_INIT(AB9540_VAUX2SEL, 0x04, 0x20, 0x0f), + /* + * 0x07, Vaux3Sel + * 0x30, Vrf1Sel + */ + REG_INIT(AB9540_VRF1VAUX3SEL, 0x04, 0x21, 0x37), + /* + * 0x01, VextSupply12LP + */ + REG_INIT(AB9540_REGUCTRL2SPARE, 0x04, 0x22, 0x01), + /* + * 0x03, Vaux4RequestCtrl + */ + REG_INIT(AB9540_VAUX4REQCTRL, 0x04, 0x2d, 0x03), + /* + * 0x03, Vaux4Regu + */ + REG_INIT(AB9540_VAUX4REGU, 0x04, 0x2e, 0x03), + /* + * 0x08, Vaux4Sel + */ + REG_INIT(AB9540_VAUX4SEL, 0x04, 0x2f, 0x0f), + /* + * 0x01, VpllDisch + * 0x02, Vrf1Disch + * 0x04, Vaux1Disch + * 0x08, Vaux2Disch + * 0x10, Vaux3Disch + * 0x20, Vintcore12Disch + * 0x40, VTVoutDisch + * 0x80, VaudioDisch + */ + REG_INIT(AB9540_REGUCTRLDISCH, 0x04, 0x43, 0xff), + /* + * 0x01, VsimDisch + * 0x02, VanaDisch + * 0x04, VdmicPullDownEna + * 0x08, VpllPullDownEna + * 0x10, VdmicDisch + */ + REG_INIT(AB9540_REGUCTRLDISCH2, 0x04, 0x44, 0x1f), + /* + * 0x01, Vaux4Disch + */ + REG_INIT(AB9540_REGUCTRLDISCH3, 0x04, 0x48, 0x01), +}; + +/* AB8540 register init */ +static struct ab8500_reg_init ab8540_reg_init[] = { + /* + * 0x01, VSimSycClkReq1Valid + * 0x02, VSimSycClkReq2Valid + * 0x04, VSimSycClkReq3Valid + * 0x08, VSimSycClkReq4Valid + * 0x10, VSimSycClkReq5Valid + * 0x20, VSimSycClkReq6Valid + * 0x40, VSimSycClkReq7Valid + * 0x80, VSimSycClkReq8Valid + */ + REG_INIT(AB8540_VSIMSYSCLKCTRL, 0x02, 0x33, 0xff), + /* + * 0x03, VarmRequestCtrl + * 0x0c, VapeRequestCtrl + * 0x30, Vsmps1RequestCtrl + * 0xc0, Vsmps2RequestCtrl + */ + REG_INIT(AB8540_REGUREQUESTCTRL1, 0x03, 0x03, 0xff), + /* + * 0x03, Vsmps3RequestCtrl + * 0x0c, VpllRequestCtrl + * 0x30, VanaRequestCtrl + * 0xc0, VextSupply1RequestCtrl + */ + REG_INIT(AB8540_REGUREQUESTCTRL2, 0x03, 0x04, 0xff), + /* + * 0x03, VextSupply2RequestCtrl + * 0x0c, VextSupply3RequestCtrl + * 0x30, Vaux1RequestCtrl + * 0xc0, Vaux2RequestCtrl + */ + REG_INIT(AB8540_REGUREQUESTCTRL3, 0x03, 0x05, 0xff), + /* + * 0x03, Vaux3RequestCtrl + * 0x04, SwHPReq + */ + REG_INIT(AB8540_REGUREQUESTCTRL4, 0x03, 0x06, 0x07), + /* + * 0x01, Vsmps1SysClkReq1HPValid + * 0x02, Vsmps2SysClkReq1HPValid + * 0x04, Vsmps3SysClkReq1HPValid + * 0x08, VanaSysClkReq1HPValid + * 0x10, VpllSysClkReq1HPValid + * 0x20, Vaux1SysClkReq1HPValid + * 0x40, Vaux2SysClkReq1HPValid + * 0x80, Vaux3SysClkReq1HPValid + */ + REG_INIT(AB8540_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xff), + /* + * 0x01, VapeSysClkReq1HPValid + * 0x02, VarmSysClkReq1HPValid + * 0x04, VbbSysClkReq1HPValid + * 0x10, VextSupply1SysClkReq1HPValid + * 0x20, VextSupply2SysClkReq1HPValid + * 0x40, VextSupply3SysClkReq1HPValid + */ + REG_INIT(AB8540_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x77), + /* + * 0x01, Vsmps1HwHPReq1Valid + * 0x02, Vsmps2HwHPReq1Valid + * 0x04, Vsmps3HwHPReq1Valid + * 0x08, VanaHwHPReq1Valid + * 0x10, VpllHwHPReq1Valid + * 0x20, Vaux1HwHPReq1Valid + * 0x40, Vaux2HwHPReq1Valid + * 0x80, Vaux3HwHPReq1Valid + */ + REG_INIT(AB8540_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xff), + /* + * 0x01, VextSupply1HwHPReq1Valid + * 0x02, VextSupply2HwHPReq1Valid + * 0x04, VextSupply3HwHPReq1Valid + */ + REG_INIT(AB8540_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x07), + /* + * 0x01, Vsmps1HwHPReq2Valid + * 0x02, Vsmps2HwHPReq2Valid + * 0x03, Vsmps3HwHPReq2Valid + * 0x08, VanaHwHPReq2Valid + * 0x10, VpllHwHPReq2Valid + * 0x20, Vaux1HwHPReq2Valid + * 0x40, Vaux2HwHPReq2Valid + * 0x80, Vaux3HwHPReq2Valid + */ + REG_INIT(AB8540_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xff), + /* + * 0x01, VextSupply1HwHPReq2Valid + * 0x02, VextSupply2HwHPReq2Valid + * 0x04, VextSupply3HwHPReq2Valid + */ + REG_INIT(AB8540_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x07), + /* + * 0x01, VapeSwHPReqValid + * 0x02, VarmSwHPReqValid + * 0x04, Vsmps1SwHPReqValid + * 0x08, Vsmps2SwHPReqValid + * 0x10, Vsmps3SwHPReqValid + * 0x20, VanaSwHPReqValid + * 0x40, VpllSwHPReqValid + * 0x80, Vaux1SwHPReqValid + */ + REG_INIT(AB8540_REGUSWHPREQVALID1, 0x03, 0x0d, 0xff), + /* + * 0x01, Vaux2SwHPReqValid + * 0x02, Vaux3SwHPReqValid + * 0x04, VextSupply1SwHPReqValid + * 0x08, VextSupply2SwHPReqValid + * 0x10, VextSupply3SwHPReqValid + */ + REG_INIT(AB8540_REGUSWHPREQVALID2, 0x03, 0x0e, 0x1f), + /* + * 0x02, SysClkReq2Valid1 + * ... + * 0x80, SysClkReq8Valid1 + */ + REG_INIT(AB8540_REGUSYSCLKREQVALID1, 0x03, 0x0f, 0xff), + /* + * 0x02, SysClkReq2Valid2 + * ... + * 0x80, SysClkReq8Valid2 + */ + REG_INIT(AB8540_REGUSYSCLKREQVALID2, 0x03, 0x10, 0xff), + /* + * 0x01, Vaux4SwHPReqValid + * 0x02, Vaux4HwHPReq2Valid + * 0x04, Vaux4HwHPReq1Valid + * 0x08, Vaux4SysClkReq1HPValid + */ + REG_INIT(AB8540_REGUVAUX4REQVALID, 0x03, 0x11, 0x0f), + /* + * 0x01, Vaux5SwHPReqValid + * 0x02, Vaux5HwHPReq2Valid + * 0x04, Vaux5HwHPReq1Valid + * 0x08, Vaux5SysClkReq1HPValid + */ + REG_INIT(AB8540_REGUVAUX5REQVALID, 0x03, 0x12, 0x0f), + /* + * 0x01, Vaux6SwHPReqValid + * 0x02, Vaux6HwHPReq2Valid + * 0x04, Vaux6HwHPReq1Valid + * 0x08, Vaux6SysClkReq1HPValid + */ + REG_INIT(AB8540_REGUVAUX6REQVALID, 0x03, 0x13, 0x0f), + /* + * 0x01, VclkbSwHPReqValid + * 0x02, VclkbHwHPReq2Valid + * 0x04, VclkbHwHPReq1Valid + * 0x08, VclkbSysClkReq1HPValid + */ + REG_INIT(AB8540_REGUVCLKBREQVALID, 0x03, 0x14, 0x0f), + /* + * 0x01, Vrf1SwHPReqValid + * 0x02, Vrf1HwHPReq2Valid + * 0x04, Vrf1HwHPReq1Valid + * 0x08, Vrf1SysClkReq1HPValid + */ + REG_INIT(AB8540_REGUVRF1REQVALID, 0x03, 0x15, 0x0f), + /* + * 0x02, VTVoutEna + * 0x04, Vintcore12Ena + * 0x38, Vintcore12Sel + * 0x40, Vintcore12LP + * 0x80, VTVoutLP + */ + REG_INIT(AB8540_REGUMISC1, 0x03, 0x80, 0xfe), + /* + * 0x02, VaudioEna + * 0x04, VdmicEna + * 0x08, Vamic1Ena + * 0x10, Vamic2Ena + * 0x20, Vamic12LP + * 0xC0, VdmicSel + */ + REG_INIT(AB8540_VAUDIOSUPPLY, 0x03, 0x83, 0xfe), + /* + * 0x01, Vamic1_dzout + * 0x02, Vamic2_dzout + */ + REG_INIT(AB8540_REGUCTRL1VAMIC, 0x03, 0x84, 0x03), + /* + * 0x07, VHSICSel + * 0x08, VHSICOffState + * 0x10, VHSIEna + * 0x20, VHSICLP + */ + REG_INIT(AB8540_VHSIC, 0x03, 0x87, 0x3f), + /* + * 0x07, VSDIOSel + * 0x08, VSDIOOffState + * 0x10, VSDIOEna + * 0x20, VSDIOLP + */ + REG_INIT(AB8540_VSDIO, 0x03, 0x88, 0x3f), + /* + * 0x03, Vsmps1Regu + * 0x0c, Vsmps1SelCtrl + * 0x10, Vsmps1AutoMode + * 0x20, Vsmps1PWMMode + */ + REG_INIT(AB8540_VSMPS1REGU, 0x04, 0x03, 0x3f), + /* + * 0x03, Vsmps2Regu + * 0x0c, Vsmps2SelCtrl + * 0x10, Vsmps2AutoMode + * 0x20, Vsmps2PWMMode + */ + REG_INIT(AB8540_VSMPS2REGU, 0x04, 0x04, 0x3f), + /* + * 0x03, Vsmps3Regu + * 0x0c, Vsmps3SelCtrl + * 0x10, Vsmps3AutoMode + * 0x20, Vsmps3PWMMode + * NOTE! PRCMU register + */ + REG_INIT(AB8540_VSMPS3REGU, 0x04, 0x05, 0x0f), + /* + * 0x03, VpllRegu + * 0x0c, VanaRegu + */ + REG_INIT(AB8540_VPLLVANAREGU, 0x04, 0x06, 0x0f), + /* + * 0x03, VextSupply1Regu + * 0x0c, VextSupply2Regu + * 0x30, VextSupply3Regu + * 0x40, ExtSupply2Bypass + * 0x80, ExtSupply3Bypass + */ + REG_INIT(AB8540_EXTSUPPLYREGU, 0x04, 0x08, 0xff), + /* + * 0x03, Vaux1Regu + * 0x0c, Vaux2Regu + */ + REG_INIT(AB8540_VAUX12REGU, 0x04, 0x09, 0x0f), + /* + * 0x0c, VRF1Regu + * 0x03, Vaux3Regu + */ + REG_INIT(AB8540_VRF1VAUX3REGU, 0x04, 0x0a, 0x0f), + /* + * 0x3f, Vsmps1Sel1 + */ + REG_INIT(AB8540_VSMPS1SEL1, 0x04, 0x13, 0x3f), + /* + * 0x3f, Vsmps1Sel2 + */ + REG_INIT(AB8540_VSMPS1SEL2, 0x04, 0x14, 0x3f), + /* + * 0x3f, Vsmps1Sel3 + */ + REG_INIT(AB8540_VSMPS1SEL3, 0x04, 0x15, 0x3f), + /* + * 0x3f, Vsmps2Sel1 + */ + REG_INIT(AB8540_VSMPS2SEL1, 0x04, 0x17, 0x3f), + /* + * 0x3f, Vsmps2Sel2 + */ + REG_INIT(AB8540_VSMPS2SEL2, 0x04, 0x18, 0x3f), + /* + * 0x3f, Vsmps2Sel3 + */ + REG_INIT(AB8540_VSMPS2SEL3, 0x04, 0x19, 0x3f), + /* + * 0x7f, Vsmps3Sel1 + * NOTE! PRCMU register + */ + REG_INIT(AB8540_VSMPS3SEL1, 0x04, 0x1b, 0x7f), + /* + * 0x7f, Vsmps3Sel2 + * NOTE! PRCMU register + */ + REG_INIT(AB8540_VSMPS3SEL2, 0x04, 0x1c, 0x7f), + /* + * 0x0f, Vaux1Sel + */ + REG_INIT(AB8540_VAUX1SEL, 0x04, 0x1f, 0x0f), + /* + * 0x0f, Vaux2Sel + */ + REG_INIT(AB8540_VAUX2SEL, 0x04, 0x20, 0x0f), + /* + * 0x07, Vaux3Sel + * 0x70, Vrf1Sel + */ + REG_INIT(AB8540_VRF1VAUX3SEL, 0x04, 0x21, 0x77), + /* + * 0x01, VextSupply12LP + */ + REG_INIT(AB8540_REGUCTRL2SPARE, 0x04, 0x22, 0x01), + /* + * 0x07, Vanasel + * 0x30, Vpllsel + */ + REG_INIT(AB8540_VANAVPLLSEL, 0x04, 0x29, 0x37), + /* + * 0x03, Vaux4RequestCtrl + */ + REG_INIT(AB8540_VAUX4REQCTRL, 0x04, 0x2d, 0x03), + /* + * 0x03, Vaux4Regu + */ + REG_INIT(AB8540_VAUX4REGU, 0x04, 0x2e, 0x03), + /* + * 0x0f, Vaux4Sel + */ + REG_INIT(AB8540_VAUX4SEL, 0x04, 0x2f, 0x0f), + /* + * 0x03, Vaux5RequestCtrl + */ + REG_INIT(AB8540_VAUX5REQCTRL, 0x04, 0x31, 0x03), + /* + * 0x03, Vaux5Regu + */ + REG_INIT(AB8540_VAUX5REGU, 0x04, 0x32, 0x03), + /* + * 0x3f, Vaux5Sel + */ + REG_INIT(AB8540_VAUX5SEL, 0x04, 0x33, 0x3f), + /* + * 0x03, Vaux6RequestCtrl + */ + REG_INIT(AB8540_VAUX6REQCTRL, 0x04, 0x34, 0x03), + /* + * 0x03, Vaux6Regu + */ + REG_INIT(AB8540_VAUX6REGU, 0x04, 0x35, 0x03), + /* + * 0x3f, Vaux6Sel + */ + REG_INIT(AB8540_VAUX6SEL, 0x04, 0x36, 0x3f), + /* + * 0x03, VCLKBRequestCtrl + */ + REG_INIT(AB8540_VCLKBREQCTRL, 0x04, 0x37, 0x03), + /* + * 0x03, VCLKBRegu + */ + REG_INIT(AB8540_VCLKBREGU, 0x04, 0x38, 0x03), + /* + * 0x07, VCLKBSel + */ + REG_INIT(AB8540_VCLKBSEL, 0x04, 0x39, 0x07), + /* + * 0x03, Vrf1RequestCtrl + */ + REG_INIT(AB8540_VRF1REQCTRL, 0x04, 0x3a, 0x03), + /* + * 0x01, VpllDisch + * 0x02, Vrf1Disch + * 0x04, Vaux1Disch + * 0x08, Vaux2Disch + * 0x10, Vaux3Disch + * 0x20, Vintcore12Disch + * 0x40, VTVoutDisch + * 0x80, VaudioDisch + */ + REG_INIT(AB8540_REGUCTRLDISCH, 0x04, 0x43, 0xff), + /* + * 0x02, VanaDisch + * 0x04, VdmicPullDownEna + * 0x08, VpllPullDownEna + * 0x10, VdmicDisch + */ + REG_INIT(AB8540_REGUCTRLDISCH2, 0x04, 0x44, 0x1e), + /* + * 0x01, Vaux4Disch + */ + REG_INIT(AB8540_REGUCTRLDISCH3, 0x04, 0x48, 0x01), + /* + * 0x01, Vaux5Disch + * 0x02, Vaux6Disch + * 0x04, VCLKBDisch + */ + REG_INIT(AB8540_REGUCTRLDISCH4, 0x04, 0x49, 0x07), +}; + +static struct of_regulator_match ab8500_regulator_match[] = { + { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB8500_LDO_AUX1, }, + { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB8500_LDO_AUX2, }, + { .name = "ab8500_ldo_aux3", .driver_data = (void *) AB8500_LDO_AUX3, }, + { .name = "ab8500_ldo_intcore", .driver_data = (void *) AB8500_LDO_INTCORE, }, + { .name = "ab8500_ldo_tvout", .driver_data = (void *) AB8500_LDO_TVOUT, }, + { .name = "ab8500_ldo_audio", .driver_data = (void *) AB8500_LDO_AUDIO, }, + { .name = "ab8500_ldo_anamic1", .driver_data = (void *) AB8500_LDO_ANAMIC1, }, + { .name = "ab8500_ldo_amamic2", .driver_data = (void *) AB8500_LDO_ANAMIC2, }, + { .name = "ab8500_ldo_dmic", .driver_data = (void *) AB8500_LDO_DMIC, }, + { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8500_LDO_ANA, }, +}; + +static struct of_regulator_match ab8505_regulator_match[] = { + { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB8505_LDO_AUX1, }, + { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB8505_LDO_AUX2, }, + { .name = "ab8500_ldo_aux3", .driver_data = (void *) AB8505_LDO_AUX3, }, + { .name = "ab8500_ldo_aux4", .driver_data = (void *) AB8505_LDO_AUX4, }, + { .name = "ab8500_ldo_aux5", .driver_data = (void *) AB8505_LDO_AUX5, }, + { .name = "ab8500_ldo_aux6", .driver_data = (void *) AB8505_LDO_AUX6, }, + { .name = "ab8500_ldo_intcore", .driver_data = (void *) AB8505_LDO_INTCORE, }, + { .name = "ab8500_ldo_adc", .driver_data = (void *) AB8505_LDO_ADC, }, + { .name = "ab8500_ldo_audio", .driver_data = (void *) AB8505_LDO_AUDIO, }, + { .name = "ab8500_ldo_anamic1", .driver_data = (void *) AB8505_LDO_ANAMIC1, }, + { .name = "ab8500_ldo_amamic2", .driver_data = (void *) AB8505_LDO_ANAMIC2, }, + { .name = "ab8500_ldo_aux8", .driver_data = (void *) AB8505_LDO_AUX8, }, + { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8505_LDO_ANA, }, +}; + +static struct of_regulator_match ab8540_regulator_match[] = { + { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB8540_LDO_AUX1, }, + { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB8540_LDO_AUX2, }, + { .name = "ab8500_ldo_aux3", .driver_data = (void *) AB8540_LDO_AUX3, }, + { .name = "ab8500_ldo_aux4", .driver_data = (void *) AB8540_LDO_AUX4, }, + { .name = "ab8500_ldo_aux5", .driver_data = (void *) AB8540_LDO_AUX5, }, + { .name = "ab8500_ldo_aux6", .driver_data = (void *) AB8540_LDO_AUX6, }, + { .name = "ab8500_ldo_intcore", .driver_data = (void *) AB8540_LDO_INTCORE, }, + { .name = "ab8500_ldo_tvout", .driver_data = (void *) AB8540_LDO_TVOUT, }, + { .name = "ab8500_ldo_audio", .driver_data = (void *) AB8540_LDO_AUDIO, }, + { .name = "ab8500_ldo_anamic1", .driver_data = (void *) AB8540_LDO_ANAMIC1, }, + { .name = "ab8500_ldo_amamic2", .driver_data = (void *) AB8540_LDO_ANAMIC2, }, + { .name = "ab8500_ldo_dmic", .driver_data = (void *) AB8540_LDO_DMIC, }, + { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8540_LDO_ANA, }, + { .name = "ab8500_ldo_sdio", .driver_data = (void *) AB8540_LDO_SDIO, }, +}; + +static struct of_regulator_match ab9540_regulator_match[] = { + { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB9540_LDO_AUX1, }, + { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB9540_LDO_AUX2, }, + { .name = "ab8500_ldo_aux3", .driver_data = (void *) AB9540_LDO_AUX3, }, + { .name = "ab8500_ldo_aux4", .driver_data = (void *) AB9540_LDO_AUX4, }, + { .name = "ab8500_ldo_intcore", .driver_data = (void *) AB9540_LDO_INTCORE, }, + { .name = "ab8500_ldo_tvout", .driver_data = (void *) AB9540_LDO_TVOUT, }, + { .name = "ab8500_ldo_audio", .driver_data = (void *) AB9540_LDO_AUDIO, }, + { .name = "ab8500_ldo_anamic1", .driver_data = (void *) AB9540_LDO_ANAMIC1, }, + { .name = "ab8500_ldo_amamic2", .driver_data = (void *) AB9540_LDO_ANAMIC2, }, + { .name = "ab8500_ldo_dmic", .driver_data = (void *) AB9540_LDO_DMIC, }, + { .name = "ab8500_ldo_ana", .driver_data = (void *) AB9540_LDO_ANA, }, +}; + +static struct { + struct ab8500_regulator_info *info; + int info_size; + struct ab8500_reg_init *init; + int init_size; + struct of_regulator_match *match; + int match_size; +} abx500_regulator; + +static void abx500_get_regulator_info(struct ab8500 *ab8500) +{ + if (is_ab9540(ab8500)) { + abx500_regulator.info = ab9540_regulator_info; + abx500_regulator.info_size = ARRAY_SIZE(ab9540_regulator_info); + abx500_regulator.init = ab9540_reg_init; + abx500_regulator.init_size = AB9540_NUM_REGULATOR_REGISTERS; + abx500_regulator.match = ab9540_regulator_match; + abx500_regulator.match_size = ARRAY_SIZE(ab9540_regulator_match); + } else if (is_ab8505(ab8500)) { + abx500_regulator.info = ab8505_regulator_info; + abx500_regulator.info_size = ARRAY_SIZE(ab8505_regulator_info); + abx500_regulator.init = ab8505_reg_init; + abx500_regulator.init_size = AB8505_NUM_REGULATOR_REGISTERS; + abx500_regulator.match = ab8505_regulator_match; + abx500_regulator.match_size = ARRAY_SIZE(ab8505_regulator_match); + } else if (is_ab8540(ab8500)) { + abx500_regulator.info = ab8540_regulator_info; + abx500_regulator.info_size = ARRAY_SIZE(ab8540_regulator_info); + abx500_regulator.init = ab8540_reg_init; + abx500_regulator.init_size = AB8540_NUM_REGULATOR_REGISTERS; + abx500_regulator.match = ab8540_regulator_match; + abx500_regulator.match_size = ARRAY_SIZE(ab8540_regulator_match); + } else { + abx500_regulator.info = ab8500_regulator_info; + abx500_regulator.info_size = ARRAY_SIZE(ab8500_regulator_info); + abx500_regulator.init = ab8500_reg_init; + abx500_regulator.init_size = AB8500_NUM_REGULATOR_REGISTERS; + abx500_regulator.match = ab8500_regulator_match; + abx500_regulator.match_size = ARRAY_SIZE(ab8500_regulator_match); + } +} + +static int ab8500_regulator_init_registers(struct platform_device *pdev, + int id, int mask, int value) { + struct ab8500_reg_init *reg_init = abx500_regulator.init; int err; - if (value & ~ab8500_reg_init[id].mask) { - dev_err(&pdev->dev, - "Configuration error: value outside mask.\n"); - return -EINVAL; - } + BUG_ON(value & ~mask); + BUG_ON(mask & ~reg_init[id].mask); + /* initialize register */ err = abx500_mask_and_set_register_interruptible( &pdev->dev, - ab8500_reg_init[id].bank, - ab8500_reg_init[id].addr, - ab8500_reg_init[id].mask, - value); + reg_init[id].bank, + reg_init[id].addr, + mask, value); if (err < 0) { dev_err(&pdev->dev, "Failed to initialize 0x%02x, 0x%02x.\n", - ab8500_reg_init[id].bank, - ab8500_reg_init[id].addr); + reg_init[id].bank, + reg_init[id].addr); return err; } - dev_vdbg(&pdev->dev, - "init: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", - ab8500_reg_init[id].bank, - ab8500_reg_init[id].addr, - ab8500_reg_init[id].mask, - value); + " init: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", + reg_init[id].bank, + reg_init[id].addr, + mask, value); return 0; } static int ab8500_regulator_register(struct platform_device *pdev, - struct regulator_init_data *init_data, - int id, - struct device_node *np) + struct regulator_init_data *init_data, + int id, struct device_node *np) { + struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); struct ab8500_regulator_info *info = NULL; struct regulator_config config = { }; int err; /* assign per-regulator data */ - info = &ab8500_regulator_info[id]; + info = &abx500_regulator.info[id]; info->dev = &pdev->dev; config.dev = &pdev->dev; @@ -695,7 +3045,7 @@ static int ab8500_regulator_register(struct platform_device *pdev, config.of_node = np; /* fix for hardware before ab8500v2.0 */ - if (abx500_get_chip_id(info->dev) < 0x20) { + if (is_ab8500_1p1_or_earlier(ab8500)) { if (info->desc.id == AB8500_LDO_AUX3) { info->desc.n_voltages = ARRAY_SIZE(ldo_vauxn_voltages); @@ -712,7 +3062,7 @@ static int ab8500_regulator_register(struct platform_device *pdev, info->desc.name); /* when we fail, un-register all earlier regulators */ while (--id >= 0) { - info = &ab8500_regulator_info[id]; + info = &abx500_regulator.info[id]; regulator_unregister(info->regulator); } return err; @@ -721,29 +3071,16 @@ static int ab8500_regulator_register(struct platform_device *pdev, return 0; } -static struct of_regulator_match ab8500_regulator_matches[] = { - { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB8500_LDO_AUX1, }, - { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB8500_LDO_AUX2, }, - { .name = "ab8500_ldo_aux3", .driver_data = (void *) AB8500_LDO_AUX3, }, - { .name = "ab8500_ldo_intcore", .driver_data = (void *) AB8500_LDO_INTCORE, }, - { .name = "ab8500_ldo_tvout", .driver_data = (void *) AB8500_LDO_TVOUT, }, - { .name = "ab8500_ldo_usb", .driver_data = (void *) AB8500_LDO_USB, }, - { .name = "ab8500_ldo_audio", .driver_data = (void *) AB8500_LDO_AUDIO, }, - { .name = "ab8500_ldo_anamic1", .driver_data = (void *) AB8500_LDO_ANAMIC1, }, - { .name = "ab8500_ldo_amamic2", .driver_data = (void *) AB8500_LDO_ANAMIC2, }, - { .name = "ab8500_ldo_dmic", .driver_data = (void *) AB8500_LDO_DMIC, }, - { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8500_LDO_ANA, }, -}; - static int -ab8500_regulator_of_probe(struct platform_device *pdev, struct device_node *np) +ab8500_regulator_of_probe(struct platform_device *pdev, + struct device_node *np) { + struct of_regulator_match *match = abx500_regulator.match; int err, i; - for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { + for (i = 0; i < abx500_regulator.info_size; i++) { err = ab8500_regulator_register( - pdev, ab8500_regulator_matches[i].init_data, - i, ab8500_regulator_matches[i].of_node); + pdev, match[i].init_data, i, match[i].of_node); if (err) return err; } @@ -754,14 +3091,22 @@ ab8500_regulator_of_probe(struct platform_device *pdev, struct device_node *np) static int ab8500_regulator_probe(struct platform_device *pdev) { struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); - struct ab8500_platform_data *pdata; struct device_node *np = pdev->dev.of_node; + struct ab8500_platform_data *ppdata; + struct ab8500_regulator_platform_data *pdata; int i, err; + if (!ab8500) { + dev_err(&pdev->dev, "null mfd parent\n"); + return -EINVAL; + } + + abx500_get_regulator_info(ab8500); + if (np) { err = of_regulator_match(&pdev->dev, np, - ab8500_regulator_matches, - ARRAY_SIZE(ab8500_regulator_matches)); + abx500_regulator.match, + abx500_regulator.match_size); if (err < 0) { dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", err); @@ -772,46 +3117,61 @@ static int ab8500_regulator_probe(struct platform_device *pdev) return err; } - if (!ab8500) { - dev_err(&pdev->dev, "null mfd parent\n"); + ppdata = dev_get_platdata(ab8500->dev); + if (!ppdata) { + dev_err(&pdev->dev, "null parent pdata\n"); return -EINVAL; } - pdata = dev_get_platdata(ab8500->dev); + + pdata = ppdata->regulator; if (!pdata) { dev_err(&pdev->dev, "null pdata\n"); return -EINVAL; } /* make sure the platform data has the correct size */ - if (pdata->num_regulator != ARRAY_SIZE(ab8500_regulator_info)) { + if (pdata->num_regulator != abx500_regulator.info_size) { dev_err(&pdev->dev, "Configuration error: size mismatch.\n"); return -EINVAL; } + /* initialize debug (initial state is recorded with this call) */ + err = ab8500_regulator_debug_init(pdev); + if (err) + return err; + /* initialize registers */ - for (i = 0; i < pdata->num_regulator_reg_init; i++) { - int id, value; + for (i = 0; i < pdata->num_reg_init; i++) { + int id, mask, value; - id = pdata->regulator_reg_init[i].id; - value = pdata->regulator_reg_init[i].value; + id = pdata->reg_init[i].id; + mask = pdata->reg_init[i].mask; + value = pdata->reg_init[i].value; /* check for configuration errors */ - if (id >= AB8500_NUM_REGULATOR_REGISTERS) { - dev_err(&pdev->dev, - "Configuration error: id outside range.\n"); - return -EINVAL; - } + BUG_ON(id >= abx500_regulator.init_size); - err = ab8500_regulator_init_registers(pdev, id, value); + err = ab8500_regulator_init_registers(pdev, id, mask, value); if (err < 0) return err; } + if (!is_ab8505(ab8500)) { + /* register external regulators (before Vaux1, 2 and 3) */ + err = ab8500_ext_regulator_init(pdev); + if (err) + return err; + } + /* register all regulators */ - for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { - err = ab8500_regulator_register(pdev, &pdata->regulator[i], i, NULL); - if (err < 0) + for (i = 0; i < abx500_regulator.info_size; i++) { + err = ab8500_regulator_register(pdev, &pdata->regulator[i], + i, NULL); + if (err < 0) { + if (!is_ab8505(ab8500)) + ab8500_ext_regulator_exit(pdev); return err; + } } return 0; @@ -819,11 +3179,12 @@ static int ab8500_regulator_probe(struct platform_device *pdev) static int ab8500_regulator_remove(struct platform_device *pdev) { - int i; + int i, err; + struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); - for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { + for (i = 0; i < abx500_regulator.info_size; i++) { struct ab8500_regulator_info *info = NULL; - info = &ab8500_regulator_info[i]; + info = &abx500_regulator.info[i]; dev_vdbg(rdev_get_dev(info->regulator), "%s-remove\n", info->desc.name); @@ -831,6 +3192,15 @@ static int ab8500_regulator_remove(struct platform_device *pdev) regulator_unregister(info->regulator); } + /* remove external regulators (after Vaux1, 2 and 3) */ + if (!is_ab8505(ab8500)) + ab8500_ext_regulator_exit(pdev); + + /* remove regulator debug */ + err = ab8500_regulator_debug_exit(pdev); + if (err) + return err; + return 0; } @@ -863,5 +3233,7 @@ module_exit(ab8500_regulator_exit); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>"); +MODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com>"); +MODULE_AUTHOR("Daniel Willerud <daniel.willerud@stericsson.com>"); MODULE_DESCRIPTION("Regulator Driver for ST-Ericsson AB8500 Mixed-Sig PMIC"); MODULE_ALIAS("platform:ab8500-regulator"); diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index ed7beec..81d8681 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -131,7 +131,7 @@ static const struct regulator_desc arizona_ldo1_hc = { .min_uV = 900000, .uV_step = 50000, .n_voltages = 8, - .enable_time = 500, + .enable_time = 1500, .owner = THIS_MODULE, }; diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c index f0ba8c4..3da6bd6 100644 --- a/drivers/regulator/as3711-regulator.c +++ b/drivers/regulator/as3711-regulator.c @@ -13,9 +13,11 @@ #include <linux/init.h> #include <linux/mfd/as3711.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> #include <linux/slab.h> struct as3711_regulator_info { @@ -276,6 +278,53 @@ static struct as3711_regulator_info as3711_reg_info[] = { #define AS3711_REGULATOR_NUM ARRAY_SIZE(as3711_reg_info) +static struct of_regulator_match +as3711_regulator_matches[AS3711_REGULATOR_NUM] = { + [AS3711_REGULATOR_SD_1] = { .name = "sd1" }, + [AS3711_REGULATOR_SD_2] = { .name = "sd2" }, + [AS3711_REGULATOR_SD_3] = { .name = "sd3" }, + [AS3711_REGULATOR_SD_4] = { .name = "sd4" }, + [AS3711_REGULATOR_LDO_1] = { .name = "ldo1" }, + [AS3711_REGULATOR_LDO_2] = { .name = "ldo2" }, + [AS3711_REGULATOR_LDO_3] = { .name = "ldo3" }, + [AS3711_REGULATOR_LDO_4] = { .name = "ldo4" }, + [AS3711_REGULATOR_LDO_5] = { .name = "ldo5" }, + [AS3711_REGULATOR_LDO_6] = { .name = "ldo6" }, + [AS3711_REGULATOR_LDO_7] = { .name = "ldo7" }, + [AS3711_REGULATOR_LDO_8] = { .name = "ldo8" }, +}; + +static int as3711_regulator_parse_dt(struct device *dev, + struct device_node **of_node, const int count) +{ + struct as3711_regulator_pdata *pdata = dev_get_platdata(dev); + struct device_node *regulators = + of_find_node_by_name(dev->parent->of_node, "regulators"); + struct of_regulator_match *match; + int ret, i; + + if (!regulators) { + dev_err(dev, "regulator node not found\n"); + return -ENODEV; + } + + ret = of_regulator_match(dev->parent, regulators, + as3711_regulator_matches, count); + of_node_put(regulators); + if (ret < 0) { + dev_err(dev, "Error parsing regulator init data: %d\n", ret); + return ret; + } + + for (i = 0, match = as3711_regulator_matches; i < count; i++, match++) + if (match->of_node) { + pdata->init_data[i] = match->init_data; + of_node[i] = match->of_node; + } + + return 0; +} + static int as3711_regulator_probe(struct platform_device *pdev) { struct as3711_regulator_pdata *pdata = dev_get_platdata(&pdev->dev); @@ -284,13 +333,24 @@ static int as3711_regulator_probe(struct platform_device *pdev) struct regulator_config config = {.dev = &pdev->dev,}; struct as3711_regulator *reg = NULL; struct as3711_regulator *regs; + struct device_node *of_node[AS3711_REGULATOR_NUM] = {}; struct regulator_dev *rdev; struct as3711_regulator_info *ri; int ret; int id; - if (!pdata) - dev_dbg(&pdev->dev, "No platform data...\n"); + if (!pdata) { + dev_err(&pdev->dev, "No platform data...\n"); + return -ENODEV; + } + + if (pdev->dev.parent->of_node) { + ret = as3711_regulator_parse_dt(&pdev->dev, of_node, AS3711_REGULATOR_NUM); + if (ret < 0) { + dev_err(&pdev->dev, "DT parsing failed: %d\n", ret); + return ret; + } + } regs = devm_kzalloc(&pdev->dev, AS3711_REGULATOR_NUM * sizeof(struct as3711_regulator), GFP_KERNEL); @@ -300,7 +360,7 @@ static int as3711_regulator_probe(struct platform_device *pdev) } for (id = 0, ri = as3711_reg_info; id < AS3711_REGULATOR_NUM; ++id, ri++) { - reg_data = pdata ? pdata->init_data[id] : NULL; + reg_data = pdata->init_data[id]; /* No need to register if there is no regulator data */ if (!reg_data) @@ -312,6 +372,7 @@ static int as3711_regulator_probe(struct platform_device *pdev) config.init_data = reg_data; config.driver_data = reg; config.regmap = as3711->regmap; + config.of_node = of_node[id]; rdev = regulator_register(&ri->desc, &config); if (IS_ERR(rdev)) { diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e3661c2..6e50178 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -51,6 +51,7 @@ static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); +static LIST_HEAD(regulator_ena_gpio_list); static bool has_full_constraints; static bool board_wants_dummy_regulator; @@ -69,6 +70,19 @@ struct regulator_map { }; /* + * struct regulator_enable_gpio + * + * Management for shared enable GPIO pin + */ +struct regulator_enable_gpio { + struct list_head list; + int gpio; + u32 enable_count; /* a number of enabled shared GPIO */ + u32 request_count; /* a number of requested shared GPIO */ + unsigned int ena_gpio_invert:1; +}; + +/* * struct regulator * * One for each consumer device. @@ -116,7 +130,7 @@ static const char *rdev_get_name(struct regulator_dev *rdev) * @supply: regulator supply name * * Extract the regulator device node corresponding to the supply name. - * retruns the device node corresponding to the regulator if found, else + * returns the device node corresponding to the regulator if found, else * returns NULL. */ static struct device_node *of_get_regulator(struct device *dev, const char *supply) @@ -1229,7 +1243,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, struct regulator_dev *rdev; struct regulator *regulator = ERR_PTR(-EPROBE_DEFER); const char *devname = NULL; - int ret; + int ret = 0; if (id == NULL) { pr_err("get() with no identifier\n"); @@ -1245,6 +1259,15 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, if (rdev) goto found; + /* + * If we have return value from dev_lookup fail, we do not expect to + * succeed, so, quit with appropriate error value + */ + if (ret) { + regulator = ERR_PTR(ret); + goto out; + } + if (board_wants_dummy_regulator) { rdev = dummy_regulator_rdev; goto found; @@ -1456,6 +1479,101 @@ void devm_regulator_put(struct regulator *regulator) } EXPORT_SYMBOL_GPL(devm_regulator_put); +/* Manage enable GPIO list. Same GPIO pin can be shared among regulators */ +static int regulator_ena_gpio_request(struct regulator_dev *rdev, + const struct regulator_config *config) +{ + struct regulator_enable_gpio *pin; + int ret; + + list_for_each_entry(pin, ®ulator_ena_gpio_list, list) { + if (pin->gpio == config->ena_gpio) { + rdev_dbg(rdev, "GPIO %d is already used\n", + config->ena_gpio); + goto update_ena_gpio_to_rdev; + } + } + + ret = gpio_request_one(config->ena_gpio, + GPIOF_DIR_OUT | config->ena_gpio_flags, + rdev_get_name(rdev)); + if (ret) + return ret; + + pin = kzalloc(sizeof(struct regulator_enable_gpio), GFP_KERNEL); + if (pin == NULL) { + gpio_free(config->ena_gpio); + return -ENOMEM; + } + + pin->gpio = config->ena_gpio; + pin->ena_gpio_invert = config->ena_gpio_invert; + list_add(&pin->list, ®ulator_ena_gpio_list); + +update_ena_gpio_to_rdev: + pin->request_count++; + rdev->ena_pin = pin; + return 0; +} + +static void regulator_ena_gpio_free(struct regulator_dev *rdev) +{ + struct regulator_enable_gpio *pin, *n; + + if (!rdev->ena_pin) + return; + + /* Free the GPIO only in case of no use */ + list_for_each_entry_safe(pin, n, ®ulator_ena_gpio_list, list) { + if (pin->gpio == rdev->ena_pin->gpio) { + if (pin->request_count <= 1) { + pin->request_count = 0; + gpio_free(pin->gpio); + list_del(&pin->list); + kfree(pin); + } else { + pin->request_count--; + } + } + } +} + +/** + * Balance enable_count of each GPIO and actual GPIO pin control. + * GPIO is enabled in case of initial use. (enable_count is 0) + * GPIO is disabled when it is not shared any more. (enable_count <= 1) + */ +static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) +{ + struct regulator_enable_gpio *pin = rdev->ena_pin; + + if (!pin) + return -EINVAL; + + if (enable) { + /* Enable GPIO at initial use */ + if (pin->enable_count == 0) + gpio_set_value_cansleep(pin->gpio, + !pin->ena_gpio_invert); + + pin->enable_count++; + } else { + if (pin->enable_count > 1) { + pin->enable_count--; + return 0; + } + + /* Disable GPIO if not used */ + if (pin->enable_count <= 1) { + gpio_set_value_cansleep(pin->gpio, + pin->ena_gpio_invert); + pin->enable_count = 0; + } + } + + return 0; +} + static int _regulator_do_enable(struct regulator_dev *rdev) { int ret, delay; @@ -1471,9 +1589,10 @@ static int _regulator_do_enable(struct regulator_dev *rdev) trace_regulator_enable(rdev_get_name(rdev)); - if (rdev->ena_gpio) { - gpio_set_value_cansleep(rdev->ena_gpio, - !rdev->ena_gpio_invert); + if (rdev->ena_pin) { + ret = regulator_ena_gpio_ctrl(rdev, true); + if (ret < 0) + return ret; rdev->ena_gpio_state = 1; } else if (rdev->desc->ops->enable) { ret = rdev->desc->ops->enable(rdev); @@ -1575,9 +1694,10 @@ static int _regulator_do_disable(struct regulator_dev *rdev) trace_regulator_disable(rdev_get_name(rdev)); - if (rdev->ena_gpio) { - gpio_set_value_cansleep(rdev->ena_gpio, - rdev->ena_gpio_invert); + if (rdev->ena_pin) { + ret = regulator_ena_gpio_ctrl(rdev, false); + if (ret < 0) + return ret; rdev->ena_gpio_state = 0; } else if (rdev->desc->ops->disable) { @@ -1794,7 +1914,10 @@ int regulator_is_enabled_regmap(struct regulator_dev *rdev) if (ret != 0) return ret; - return (val & rdev->desc->enable_mask) != 0; + if (rdev->desc->enable_is_inverted) + return (val & rdev->desc->enable_mask) == 0; + else + return (val & rdev->desc->enable_mask) != 0; } EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap); @@ -1809,9 +1932,15 @@ EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap); */ int regulator_enable_regmap(struct regulator_dev *rdev) { + unsigned int val; + + if (rdev->desc->enable_is_inverted) + val = 0; + else + val = rdev->desc->enable_mask; + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, - rdev->desc->enable_mask); + rdev->desc->enable_mask, val); } EXPORT_SYMBOL_GPL(regulator_enable_regmap); @@ -1826,15 +1955,22 @@ EXPORT_SYMBOL_GPL(regulator_enable_regmap); */ int regulator_disable_regmap(struct regulator_dev *rdev) { + unsigned int val; + + if (rdev->desc->enable_is_inverted) + val = rdev->desc->enable_mask; + else + val = 0; + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, 0); + rdev->desc->enable_mask, val); } EXPORT_SYMBOL_GPL(regulator_disable_regmap); static int _regulator_is_enabled(struct regulator_dev *rdev) { /* A GPIO control always takes precedence */ - if (rdev->ena_gpio) + if (rdev->ena_pin) return rdev->ena_gpio_state; /* If we don't know then assume that the regulator is always on */ @@ -2138,6 +2274,37 @@ int regulator_map_voltage_iterate(struct regulator_dev *rdev, EXPORT_SYMBOL_GPL(regulator_map_voltage_iterate); /** + * regulator_map_voltage_ascend - map_voltage() for ascendant voltage list + * + * @rdev: Regulator to operate on + * @min_uV: Lower bound for voltage + * @max_uV: Upper bound for voltage + * + * Drivers that have ascendant voltage list can use this as their + * map_voltage() operation. + */ +int regulator_map_voltage_ascend(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int i, ret; + + for (i = 0; i < rdev->desc->n_voltages; i++) { + ret = rdev->desc->ops->list_voltage(rdev, i); + if (ret < 0) + continue; + + if (ret > max_uV) + break; + + if (ret >= min_uV && ret <= max_uV) + return i; + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(regulator_map_voltage_ascend); + +/** * regulator_map_voltage_linear - map_voltage() for simple linear mappings * * @rdev: Regulator to operate on @@ -3237,7 +3404,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev) if (status < 0) return status; } - if (rdev->ena_gpio || ops->is_enabled) { + if (rdev->ena_pin || ops->is_enabled) { status = device_create_file(dev, &dev_attr_state); if (status < 0) return status; @@ -3439,22 +3606,17 @@ regulator_register(const struct regulator_desc *regulator_desc, dev_set_drvdata(&rdev->dev, rdev); if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) { - ret = gpio_request_one(config->ena_gpio, - GPIOF_DIR_OUT | config->ena_gpio_flags, - rdev_get_name(rdev)); + ret = regulator_ena_gpio_request(rdev, config); if (ret != 0) { rdev_err(rdev, "Failed to request enable GPIO%d: %d\n", config->ena_gpio, ret); goto wash; } - rdev->ena_gpio = config->ena_gpio; - rdev->ena_gpio_invert = config->ena_gpio_invert; - if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH) rdev->ena_gpio_state = 1; - if (rdev->ena_gpio_invert) + if (config->ena_gpio_invert) rdev->ena_gpio_state = !rdev->ena_gpio_state; } @@ -3481,7 +3643,14 @@ regulator_register(const struct regulator_desc *regulator_desc, r = regulator_dev_lookup(dev, supply, &ret); - if (!r) { + if (ret == -ENODEV) { + /* + * No supply was specified for this regulator and + * there will never be one. + */ + ret = 0; + goto add_dev; + } else if (!r) { dev_err(dev, "Failed to find supply %s\n", supply); ret = -EPROBE_DEFER; goto scrub; @@ -3499,6 +3668,7 @@ regulator_register(const struct regulator_desc *regulator_desc, } } +add_dev: /* add consumers devices */ if (init_data) { for (i = 0; i < init_data->num_consumer_supplies; i++) { @@ -3526,8 +3696,7 @@ unset_supplies: scrub: if (rdev->supply) _regulator_put(rdev->supply); - if (rdev->ena_gpio) - gpio_free(rdev->ena_gpio); + regulator_ena_gpio_free(rdev); kfree(rdev->constraints); wash: device_unregister(&rdev->dev); @@ -3562,8 +3731,7 @@ void regulator_unregister(struct regulator_dev *rdev) unset_regulator_supplies(rdev); list_del(&rdev->list); kfree(rdev->constraints); - if (rdev->ena_gpio) - gpio_free(rdev->ena_gpio); + regulator_ena_gpio_free(rdev); device_unregister(&rdev->dev); mutex_unlock(®ulator_list_mutex); } diff --git a/drivers/regulator/dbx500-prcmu.h b/drivers/regulator/dbx500-prcmu.h index e763883..c8e51ac 100644 --- a/drivers/regulator/dbx500-prcmu.h +++ b/drivers/regulator/dbx500-prcmu.h @@ -21,7 +21,6 @@ * @is_enabled: status of the regulator * @epod_id: id for EPOD (power domain) * @is_ramret: RAM retention switch for EPOD (power domain) - * @operating_point: operating point (only for vape, to be removed) * */ struct dbx500_regulator_info { @@ -32,7 +31,6 @@ struct dbx500_regulator_info { u16 epod_id; bool is_ramret; bool exclude_from_power_state; - unsigned int operating_point; }; void power_state_active_enable(void); diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 9165b0c..f0e1ae5 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -219,9 +219,7 @@ static int fan53555_regulator_register(struct fan53555_device_info *di, rdesc->owner = THIS_MODULE; di->rdev = regulator_register(&di->desc, config); - if (IS_ERR(di->rdev)) - return PTR_ERR(di->rdev); - return 0; + return PTR_RET(di->rdev); } diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 9cb2c0f..d8af9e7 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -163,6 +163,7 @@ static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev, static struct regulator_ops lp3971_ldo_ops = { .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .is_enabled = lp3971_ldo_is_enabled, .enable = lp3971_ldo_enable, .disable = lp3971_ldo_disable, @@ -236,6 +237,7 @@ static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev, static struct regulator_ops lp3971_dcdc_ops = { .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .is_enabled = lp3971_dcdc_is_enabled, .enable = lp3971_dcdc_enable, .disable = lp3971_dcdc_disable, diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index 0baabcf..61e4cf9 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -309,6 +309,7 @@ static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev, static struct regulator_ops lp3972_ldo_ops = { .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .is_enabled = lp3972_ldo_is_enabled, .enable = lp3972_ldo_enable, .disable = lp3972_ldo_disable, @@ -389,6 +390,7 @@ static int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev, static struct regulator_ops lp3972_dcdc_ops = { .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .is_enabled = lp3972_dcdc_is_enabled, .enable = lp3972_dcdc_enable, .disable = lp3972_dcdc_disable, diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index 8e3c7ae..f5fc4a1 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -478,6 +478,7 @@ static unsigned int lp872x_buck_get_mode(struct regulator_dev *rdev) static struct regulator_ops lp872x_ldo_ops = { .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .enable = regulator_enable_regmap, @@ -488,6 +489,7 @@ static struct regulator_ops lp872x_ldo_ops = { static struct regulator_ops lp8720_buck_ops = { .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = lp872x_buck_set_voltage_sel, .get_voltage_sel = lp872x_buck_get_voltage_sel, .enable = regulator_enable_regmap, @@ -500,6 +502,7 @@ static struct regulator_ops lp8720_buck_ops = { static struct regulator_ops lp8725_buck_ops = { .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = lp872x_buck_set_voltage_sel, .get_voltage_sel = lp872x_buck_get_voltage_sel, .enable = regulator_enable_regmap, diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c index 97891a7..eb1e1e8 100644 --- a/drivers/regulator/lp8788-buck.c +++ b/drivers/regulator/lp8788-buck.c @@ -346,6 +346,7 @@ static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev) static struct regulator_ops lp8788_buck12_ops = { .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = lp8788_buck12_set_voltage_sel, .get_voltage_sel = lp8788_buck12_get_voltage_sel, .enable = regulator_enable_regmap, @@ -358,6 +359,7 @@ static struct regulator_ops lp8788_buck12_ops = { static struct regulator_ops lp8788_buck34_ops = { .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .enable = regulator_enable_regmap, diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c index cd5a14a..0ce2c4c 100644 --- a/drivers/regulator/lp8788-ldo.c +++ b/drivers/regulator/lp8788-ldo.c @@ -156,68 +156,6 @@ static const int lp8788_aldo7_vtbl[] = { 1200000, 1300000, 1400000, 1500000, 1600000, 1700000, 1800000, 1800000, }; -static enum lp8788_ldo_id lp8788_dldo_id[] = { - DLDO1, - DLDO2, - DLDO3, - DLDO4, - DLDO5, - DLDO6, - DLDO7, - DLDO8, - DLDO9, - DLDO10, - DLDO11, - DLDO12, -}; - -static enum lp8788_ldo_id lp8788_aldo_id[] = { - ALDO1, - ALDO2, - ALDO3, - ALDO4, - ALDO5, - ALDO6, - ALDO7, - ALDO8, - ALDO9, - ALDO10, -}; - -static int lp8788_ldo_enable(struct regulator_dev *rdev) -{ - struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); - - if (ldo->en_pin) { - gpio_set_value(ldo->en_pin->gpio, ENABLE); - return 0; - } else { - return regulator_enable_regmap(rdev); - } -} - -static int lp8788_ldo_disable(struct regulator_dev *rdev) -{ - struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); - - if (ldo->en_pin) { - gpio_set_value(ldo->en_pin->gpio, DISABLE); - return 0; - } else { - return regulator_disable_regmap(rdev); - } -} - -static int lp8788_ldo_is_enabled(struct regulator_dev *rdev) -{ - struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); - - if (ldo->en_pin) - return gpio_get_value(ldo->en_pin->gpio) ? 1 : 0; - else - return regulator_is_enabled_regmap(rdev); -} - static int lp8788_ldo_enable_time(struct regulator_dev *rdev) { struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); @@ -232,38 +170,21 @@ static int lp8788_ldo_enable_time(struct regulator_dev *rdev) return ENABLE_TIME_USEC * val; } -static int lp8788_ldo_fixed_get_voltage(struct regulator_dev *rdev) -{ - enum lp8788_ldo_id id = rdev_get_id(rdev); - - switch (id) { - case ALDO2 ... ALDO5: - return 2850000; - case DLDO12: - case ALDO8 ... ALDO9: - return 2500000; - case ALDO10: - return 1100000; - default: - return -EINVAL; - } -} - static struct regulator_ops lp8788_ldo_voltage_table_ops = { .list_voltage = regulator_list_voltage_table, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .enable = lp8788_ldo_enable, - .disable = lp8788_ldo_disable, - .is_enabled = lp8788_ldo_is_enabled, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, .enable_time = lp8788_ldo_enable_time, }; static struct regulator_ops lp8788_ldo_voltage_fixed_ops = { - .get_voltage = lp8788_ldo_fixed_get_voltage, - .enable = lp8788_ldo_enable, - .disable = lp8788_ldo_disable, - .is_enabled = lp8788_ldo_is_enabled, + .list_voltage = regulator_list_voltage_linear, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, .enable_time = lp8788_ldo_enable_time, }; @@ -420,6 +341,7 @@ static struct regulator_desc lp8788_dldo_desc[] = { .owner = THIS_MODULE, .enable_reg = LP8788_EN_LDO_B, .enable_mask = LP8788_EN_DLDO12_M, + .min_uV = 2500000, }, }; @@ -446,6 +368,7 @@ static struct regulator_desc lp8788_aldo_desc[] = { .owner = THIS_MODULE, .enable_reg = LP8788_EN_LDO_B, .enable_mask = LP8788_EN_ALDO2_M, + .min_uV = 2850000, }, { .name = "aldo3", @@ -456,6 +379,7 @@ static struct regulator_desc lp8788_aldo_desc[] = { .owner = THIS_MODULE, .enable_reg = LP8788_EN_LDO_B, .enable_mask = LP8788_EN_ALDO3_M, + .min_uV = 2850000, }, { .name = "aldo4", @@ -466,6 +390,7 @@ static struct regulator_desc lp8788_aldo_desc[] = { .owner = THIS_MODULE, .enable_reg = LP8788_EN_LDO_B, .enable_mask = LP8788_EN_ALDO4_M, + .min_uV = 2850000, }, { .name = "aldo5", @@ -476,6 +401,7 @@ static struct regulator_desc lp8788_aldo_desc[] = { .owner = THIS_MODULE, .enable_reg = LP8788_EN_LDO_C, .enable_mask = LP8788_EN_ALDO5_M, + .min_uV = 2850000, }, { .name = "aldo6", @@ -512,6 +438,7 @@ static struct regulator_desc lp8788_aldo_desc[] = { .owner = THIS_MODULE, .enable_reg = LP8788_EN_LDO_C, .enable_mask = LP8788_EN_ALDO8_M, + .min_uV = 2500000, }, { .name = "aldo9", @@ -522,6 +449,7 @@ static struct regulator_desc lp8788_aldo_desc[] = { .owner = THIS_MODULE, .enable_reg = LP8788_EN_LDO_C, .enable_mask = LP8788_EN_ALDO9_M, + .min_uV = 2500000, }, { .name = "aldo10", @@ -532,46 +460,14 @@ static struct regulator_desc lp8788_aldo_desc[] = { .owner = THIS_MODULE, .enable_reg = LP8788_EN_LDO_C, .enable_mask = LP8788_EN_ALDO10_M, + .min_uV = 1100000, }, }; -static int lp8788_gpio_request_ldo_en(struct platform_device *pdev, - struct lp8788_ldo *ldo, - enum lp8788_ext_ldo_en_id id) -{ - struct device *dev = &pdev->dev; - struct lp8788_ldo_enable_pin *pin = ldo->en_pin; - int ret, gpio, pinstate; - char *name[] = { - [EN_ALDO1] = "LP8788_EN_ALDO1", - [EN_ALDO234] = "LP8788_EN_ALDO234", - [EN_ALDO5] = "LP8788_EN_ALDO5", - [EN_ALDO7] = "LP8788_EN_ALDO7", - [EN_DLDO7] = "LP8788_EN_DLDO7", - [EN_DLDO911] = "LP8788_EN_DLDO911", - }; - - gpio = pin->gpio; - if (!gpio_is_valid(gpio)) { - dev_err(dev, "invalid gpio: %d\n", gpio); - return -EINVAL; - } - - pinstate = pin->init_state; - ret = devm_gpio_request_one(dev, gpio, pinstate, name[id]); - if (ret == -EBUSY) { - dev_warn(dev, "gpio%d already used\n", gpio); - return 0; - } - - return ret; -} - static int lp8788_config_ldo_enable_mode(struct platform_device *pdev, struct lp8788_ldo *ldo, enum lp8788_ldo_id id) { - int ret; struct lp8788 *lp = ldo->lp; struct lp8788_platform_data *pdata = lp->pdata; enum lp8788_ext_ldo_en_id enable_id; @@ -613,14 +509,7 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev, goto set_default_ldo_enable_mode; ldo->en_pin = pdata->ldo_pin[enable_id]; - - ret = lp8788_gpio_request_ldo_en(pdev, ldo, enable_id); - if (ret) { - ldo->en_pin = NULL; - goto set_default_ldo_enable_mode; - } - - return ret; + return 0; set_default_ldo_enable_mode: return lp8788_update_bits(lp, LP8788_EN_SEL, en_mask[enable_id], 0); @@ -640,10 +529,15 @@ static int lp8788_dldo_probe(struct platform_device *pdev) return -ENOMEM; ldo->lp = lp; - ret = lp8788_config_ldo_enable_mode(pdev, ldo, lp8788_dldo_id[id]); + ret = lp8788_config_ldo_enable_mode(pdev, ldo, id); if (ret) return ret; + if (ldo->en_pin) { + cfg.ena_gpio = ldo->en_pin->gpio; + cfg.ena_gpio_flags = ldo->en_pin->init_state; + } + cfg.dev = pdev->dev.parent; cfg.init_data = lp->pdata ? lp->pdata->dldo_data[id] : NULL; cfg.driver_data = ldo; @@ -696,10 +590,15 @@ static int lp8788_aldo_probe(struct platform_device *pdev) return -ENOMEM; ldo->lp = lp; - ret = lp8788_config_ldo_enable_mode(pdev, ldo, lp8788_aldo_id[id]); + ret = lp8788_config_ldo_enable_mode(pdev, ldo, id + ALDO1); if (ret) return ret; + if (ldo->en_pin) { + cfg.ena_gpio = ldo->en_pin->gpio; + cfg.ena_gpio_flags = ldo->en_pin->init_state; + } + cfg.dev = pdev->dev.parent; cfg.init_data = lp->pdata ? lp->pdata->aldo_data[id] : NULL; cfg.driver_data = ldo; diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index 8c5a54f..54af610 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -56,7 +56,7 @@ struct max1586_data { * set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3) * As regulator framework doesn't accept voltages to be 0V, we use 1uV. */ -static int v6_voltages_uv[] = { 1, 1800000, 2500000, 3000000 }; +static const unsigned int v6_voltages_uv[] = { 1, 1800000, 2500000, 3000000 }; /* * V3 voltage @@ -232,8 +232,7 @@ static int max1586_pmic_remove(struct i2c_client *client) int i; for (i = 0; i <= MAX1586_V6; i++) - if (max1586->rdev[i]) - regulator_unregister(max1586->rdev[i]); + regulator_unregister(max1586->rdev[i]); return 0; } diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c index e4586ee..20935b1 100644 --- a/drivers/regulator/max77686.c +++ b/drivers/regulator/max77686.c @@ -75,17 +75,20 @@ static int max77686_buck_set_suspend_disable(struct regulator_dev *rdev) { unsigned int val; struct max77686_data *max77686 = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); + int ret, id = rdev_get_id(rdev); if (id == MAX77686_BUCK1) val = 0x1; else val = 0x1 << MAX77686_OPMODE_BUCK234_SHIFT; + ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, val); + if (ret) + return ret; + max77686->opmode[id] = val; - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, - val); + return 0; } /* Some LDOs supports [LPM/Normal]ON mode during suspend state */ @@ -94,7 +97,7 @@ static int max77686_set_suspend_mode(struct regulator_dev *rdev, { struct max77686_data *max77686 = rdev_get_drvdata(rdev); unsigned int val; - int id = rdev_get_id(rdev); + int ret, id = rdev_get_id(rdev); /* BUCK[5-9] doesn't support this feature */ if (id >= MAX77686_BUCK5) @@ -113,10 +116,13 @@ static int max77686_set_suspend_mode(struct regulator_dev *rdev, return -EINVAL; } + ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, val); + if (ret) + return ret; + max77686->opmode[id] = val; - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, - val); + return 0; } /* Some LDOs supports LPM-ON/OFF/Normal-ON mode during suspend state */ @@ -125,6 +131,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev, { unsigned int val; struct max77686_data *max77686 = rdev_get_drvdata(rdev); + int ret; switch (mode) { case REGULATOR_MODE_STANDBY: /* switch off */ @@ -142,10 +149,13 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev, return -EINVAL; } + ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, val); + if (ret) + return ret; + max77686->opmode[rdev_get_id(rdev)] = val; - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, - val); + return 0; } static int max77686_enable(struct regulator_dev *rdev) diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index 3ca1438..db6c9be 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -60,36 +60,6 @@ struct max8649_regulator_info { unsigned ramp_down:1; }; -/* EN_PD means pulldown on EN input */ -static int max8649_enable(struct regulator_dev *rdev) -{ - struct max8649_regulator_info *info = rdev_get_drvdata(rdev); - return regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_EN_PD, 0); -} - -/* - * Applied internal pulldown resistor on EN input pin. - * If pulldown EN pin outside, it would be better. - */ -static int max8649_disable(struct regulator_dev *rdev) -{ - struct max8649_regulator_info *info = rdev_get_drvdata(rdev); - return regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_EN_PD, - MAX8649_EN_PD); -} - -static int max8649_is_enabled(struct regulator_dev *rdev) -{ - struct max8649_regulator_info *info = rdev_get_drvdata(rdev); - unsigned int val; - int ret; - - ret = regmap_read(info->regmap, MAX8649_CONTROL, &val); - if (ret != 0) - return ret; - return !((unsigned char)val & MAX8649_EN_PD); -} - static int max8649_enable_time(struct regulator_dev *rdev) { struct max8649_regulator_info *info = rdev_get_drvdata(rdev); @@ -151,9 +121,9 @@ static struct regulator_ops max8649_dcdc_ops = { .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, - .enable = max8649_enable, - .disable = max8649_disable, - .is_enabled = max8649_is_enabled, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, .enable_time = max8649_enable_time, .set_mode = max8649_set_mode, .get_mode = max8649_get_mode, @@ -169,6 +139,9 @@ static struct regulator_desc dcdc_desc = { .vsel_mask = MAX8649_VOL_MASK, .min_uV = MAX8649_DCDC_VMIN, .uV_step = MAX8649_DCDC_STEP, + .enable_reg = MAX8649_CONTROL, + .enable_mask = MAX8649_EN_PD, + .enable_is_inverted = true, }; static struct regmap_config max8649_regmap_config = { @@ -275,10 +248,8 @@ static int max8649_regulator_remove(struct i2c_client *client) { struct max8649_regulator_info *info = i2c_get_clientdata(client); - if (info) { - if (info->regulator) - regulator_unregister(info->regulator); - } + if (info) + regulator_unregister(info->regulator); return 0; } diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index 4d7c635..d428ef9 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -426,8 +426,7 @@ static int max8660_remove(struct i2c_client *client) int i; for (i = 0; i < MAX8660_V_END; i++) - if (max8660->rdev[i]) - regulator_unregister(max8660->rdev[i]); + regulator_unregister(max8660->rdev[i]); return 0; } diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index 0d5f64a..3597da8 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -246,7 +246,6 @@ static struct max8925_regulator_info max8925_regulator_info[] = { #ifdef CONFIG_OF static int max8925_regulator_dt_init(struct platform_device *pdev, - struct max8925_regulator_info *info, struct regulator_config *config, int ridx) { @@ -272,7 +271,7 @@ static int max8925_regulator_dt_init(struct platform_device *pdev, return 0; } #else -#define max8925_regulator_dt_init(w, x, y, z) (-1) +#define max8925_regulator_dt_init(x, y, z) (-1) #endif static int max8925_regulator_probe(struct platform_device *pdev) @@ -309,7 +308,7 @@ static int max8925_regulator_probe(struct platform_device *pdev) config.dev = &pdev->dev; config.driver_data = ri; - if (max8925_regulator_dt_init(pdev, ri, &config, regulator_idx)) + if (max8925_regulator_dt_init(pdev, &config, regulator_idx)) if (pdata) config.init_data = pdata; diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index fc7935a..5259c2f 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -28,6 +28,9 @@ #include <linux/regulator/max8952.h> #include <linux/gpio.h> #include <linux/io.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/regulator/of_regulator.h> #include <linux/slab.h> /* Registers */ @@ -126,6 +129,69 @@ static const struct regulator_desc regulator = { .owner = THIS_MODULE, }; +#ifdef CONFIG_OF +static struct of_device_id max8952_dt_match[] = { + { .compatible = "maxim,max8952" }, + {}, +}; +MODULE_DEVICE_TABLE(of, max8952_dt_match); + +static struct max8952_platform_data *max8952_parse_dt(struct device *dev) +{ + struct max8952_platform_data *pd; + struct device_node *np = dev->of_node; + int ret; + int i; + + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); + if (!pd) { + dev_err(dev, "Failed to allocate platform data\n"); + return NULL; + } + + pd->gpio_vid0 = of_get_named_gpio(np, "max8952,vid-gpios", 0); + pd->gpio_vid1 = of_get_named_gpio(np, "max8952,vid-gpios", 1); + pd->gpio_en = of_get_named_gpio(np, "max8952,en-gpio", 0); + + if (of_property_read_u32(np, "max8952,default-mode", &pd->default_mode)) + dev_warn(dev, "Default mode not specified, assuming 0\n"); + + ret = of_property_read_u32_array(np, "max8952,dvs-mode-microvolt", + pd->dvs_mode, ARRAY_SIZE(pd->dvs_mode)); + if (ret) { + dev_err(dev, "max8952,dvs-mode-microvolt property not specified"); + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(pd->dvs_mode); ++i) { + if (pd->dvs_mode[i] < 770000 || pd->dvs_mode[i] > 1400000) { + dev_err(dev, "DVS voltage %d out of range\n", i); + return NULL; + } + pd->dvs_mode[i] = (pd->dvs_mode[i] - 770000) / 10000; + } + + if (of_property_read_u32(np, "max8952,sync-freq", &pd->sync_freq)) + dev_warn(dev, "max8952,sync-freq property not specified, defaulting to 26MHz\n"); + + if (of_property_read_u32(np, "max8952,ramp-speed", &pd->ramp_speed)) + dev_warn(dev, "max8952,ramp-speed property not specified, defaulting to 32mV/us\n"); + + pd->reg_data = of_get_regulator_init_data(dev, np); + if (!pd->reg_data) { + dev_err(dev, "Failed to parse regulator init data\n"); + return NULL; + } + + return pd; +} +#else +static struct max8952_platform_data *max8952_parse_dt(struct device *dev) +{ + return NULL; +} +#endif + static int max8952_pmic_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { @@ -136,6 +202,9 @@ static int max8952_pmic_probe(struct i2c_client *client, int ret = 0, err = 0; + if (client->dev.of_node) + pdata = max8952_parse_dt(&client->dev); + if (!pdata) { dev_err(&client->dev, "Require the platform data\n"); return -EINVAL; @@ -154,11 +223,12 @@ static int max8952_pmic_probe(struct i2c_client *client, max8952->pdata = pdata; config.dev = max8952->dev; - config.init_data = &pdata->reg_data; + config.init_data = pdata->reg_data; config.driver_data = max8952; + config.of_node = client->dev.of_node; config.ena_gpio = pdata->gpio_en; - if (pdata->reg_data.constraints.boot_on) + if (pdata->reg_data->constraints.boot_on) config.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; max8952->rdev = regulator_register(®ulator, &config); @@ -271,6 +341,7 @@ static struct i2c_driver max8952_pmic_driver = { .remove = max8952_pmic_remove, .driver = { .name = "max8952", + .of_match_table = of_match_ptr(max8952_dt_match), }, .id_table = max8952_ids, }; diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 9a8ea91..adb1414 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -274,15 +274,15 @@ static int max8973_init_dcdc(struct max8973_chip *max, if (pdata->reg_init_data && pdata->reg_init_data->constraints.ramp_delay) { if (pdata->reg_init_data->constraints.ramp_delay < 25000) - control1 = MAX8973_RAMP_12mV_PER_US; + control1 |= MAX8973_RAMP_12mV_PER_US; else if (pdata->reg_init_data->constraints.ramp_delay < 50000) - control1 = MAX8973_RAMP_25mV_PER_US; + control1 |= MAX8973_RAMP_25mV_PER_US; else if (pdata->reg_init_data->constraints.ramp_delay < 200000) - control1 = MAX8973_RAMP_50mV_PER_US; + control1 |= MAX8973_RAMP_50mV_PER_US; else - control1 = MAX8973_RAMP_200mV_PER_US; + control1 |= MAX8973_RAMP_200mV_PER_US; } else { - control1 = MAX8973_RAMP_12mV_PER_US; + control1 |= MAX8973_RAMP_12mV_PER_US; max->desc.ramp_delay = 12500; } diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index 0ac7a87..df20069 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -1035,8 +1035,8 @@ static int max8997_pmic_probe(struct platform_device *pdev) int i, ret, size, nr_dvs; u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0; - if (IS_ERR_OR_NULL(pdata)) { - dev_err(pdev->dev.parent, "No platform init data supplied.\n"); + if (!pdata) { + dev_err(&pdev->dev, "No platform init data supplied.\n"); return -ENODEV; } diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index b588f07..a57a1b1 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -665,14 +665,16 @@ static int max8998_pmic_probe(struct platform_device *pdev) gpio_is_valid(pdata->buck1_set2)) { /* Check if SET1 is not equal to 0 */ if (!pdata->buck1_set1) { - printk(KERN_ERR "MAX8998 SET1 GPIO defined as 0 !\n"); + dev_err(&pdev->dev, + "MAX8998 SET1 GPIO defined as 0 !\n"); WARN_ON(!pdata->buck1_set1); ret = -EIO; goto err_out; } /* Check if SET2 is not equal to 0 */ if (!pdata->buck1_set2) { - printk(KERN_ERR "MAX8998 SET2 GPIO defined as 0 !\n"); + dev_err(&pdev->dev, + "MAX8998 SET2 GPIO defined as 0 !\n"); WARN_ON(!pdata->buck1_set2); ret = -EIO; goto err_out; @@ -738,7 +740,8 @@ static int max8998_pmic_probe(struct platform_device *pdev) if (gpio_is_valid(pdata->buck2_set3)) { /* Check if SET3 is not equal to 0 */ if (!pdata->buck2_set3) { - printk(KERN_ERR "MAX8998 SET3 GPIO defined as 0 !\n"); + dev_err(&pdev->dev, + "MAX8998 SET3 GPIO defined as 0 !\n"); WARN_ON(!pdata->buck2_set3); ret = -EIO; goto err_out; diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index c46c670..fdf7f0a 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -398,33 +398,51 @@ static int mc13783_regulator_probe(struct platform_device *pdev) struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent); struct mc13xxx_regulator_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct mc13xxx_regulator_init_data *init_data; + struct mc13xxx_regulator_init_data *mc13xxx_data; struct regulator_config config = { }; - int i, ret; + int i, ret, num_regulators; - dev_dbg(&pdev->dev, "%s id %d\n", __func__, pdev->id); + num_regulators = mc13xxx_get_num_regulators_dt(pdev); - if (!pdata) + if (num_regulators <= 0 && pdata) + num_regulators = pdata->num_regulators; + if (num_regulators <= 0) return -EINVAL; priv = devm_kzalloc(&pdev->dev, sizeof(*priv) + - pdata->num_regulators * sizeof(priv->regulators[0]), + num_regulators * sizeof(priv->regulators[0]), GFP_KERNEL); if (!priv) return -ENOMEM; + priv->num_regulators = num_regulators; priv->mc13xxx_regulators = mc13783_regulators; priv->mc13xxx = mc13783; + platform_set_drvdata(pdev, priv); - for (i = 0; i < pdata->num_regulators; i++) { - struct regulator_desc *desc; + mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13783_regulators, + ARRAY_SIZE(mc13783_regulators)); - init_data = &pdata->regulators[i]; - desc = &mc13783_regulators[init_data->id].desc; + for (i = 0; i < priv->num_regulators; i++) { + struct regulator_init_data *init_data; + struct regulator_desc *desc; + struct device_node *node = NULL; + int id; + + if (mc13xxx_data) { + id = mc13xxx_data[i].id; + init_data = mc13xxx_data[i].init_data; + node = mc13xxx_data[i].node; + } else { + id = pdata->regulators[i].id; + init_data = pdata->regulators[i].init_data; + } + desc = &mc13783_regulators[id].desc; config.dev = &pdev->dev; - config.init_data = init_data->init_data; + config.init_data = init_data; config.driver_data = priv; + config.of_node = node; priv->regulators[i] = regulator_register(desc, &config); if (IS_ERR(priv->regulators[i])) { @@ -435,8 +453,6 @@ static int mc13783_regulator_probe(struct platform_device *pdev) } } - platform_set_drvdata(pdev, priv); - return 0; err: while (--i >= 0) @@ -448,13 +464,11 @@ err: static int mc13783_regulator_remove(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); - struct mc13xxx_regulator_platform_data *pdata = - dev_get_platdata(&pdev->dev); int i; platform_set_drvdata(pdev, NULL); - for (i = 0; i < pdata->num_regulators; i++) + for (i = 0; i < priv->num_regulators; i++) regulator_unregister(priv->regulators[i]); return 0; diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index 9891aec..b716283 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -465,13 +465,13 @@ static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev, */ if (mc13892_regulators[id].vsel_reg != MC13892_SWITCHERS0) { + mask |= MC13892_SWITCHERS0_SWxHI; + if (volt > 1375000) { reg_value -= MC13892_SWxHI_SEL_OFFSET; reg_value |= MC13892_SWITCHERS0_SWxHI; - mask |= MC13892_SWITCHERS0_SWxHI; - } else if (volt < 1100000) { + } else { reg_value &= ~MC13892_SWITCHERS0_SWxHI; - mask |= MC13892_SWITCHERS0_SWxHI; } } @@ -485,6 +485,7 @@ static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev, static struct regulator_ops mc13892_sw_regulator_ops = { .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = mc13892_sw_regulator_set_voltage_sel, .get_voltage_sel = mc13892_sw_regulator_get_voltage_sel, }; @@ -535,7 +536,7 @@ static int mc13892_regulator_probe(struct platform_device *pdev) struct mc13xxx_regulator_init_data *mc13xxx_data; struct regulator_config config = { }; int i, ret; - int num_regulators = 0, num_parsed; + int num_regulators = 0; u32 val; num_regulators = mc13xxx_get_num_regulators_dt(pdev); @@ -545,8 +546,6 @@ static int mc13892_regulator_probe(struct platform_device *pdev) if (num_regulators <= 0) return -EINVAL; - num_parsed = num_regulators; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv) + num_regulators * sizeof(priv->regulators[0]), GFP_KERNEL); @@ -589,40 +588,9 @@ static int mc13892_regulator_probe(struct platform_device *pdev) = mc13892_vcam_get_mode; mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13892_regulators, - ARRAY_SIZE(mc13892_regulators), - &num_parsed); - - /* - * Perform a little sanity check on the regulator tree - if we found - * a number of regulators from mc13xxx_get_num_regulators_dt and - * then parsed a smaller number in mc13xxx_parse_regulators_dt then - * there is a regulator defined in the regulators node which has - * not matched any usable regulator in the driver. In this case, - * there is one missing and what will happen is the first regulator - * will get registered again. - * - * Fix this by basically making our number of registerable regulators - * equal to the number of regulators we parsed. We are allocating - * too much memory for priv, but this is unavoidable at this point. - * - * As an example of how this can happen, try making a typo in your - * regulators node (vviohi {} instead of viohi {}) so that the name - * does not match.. - * - * The check will basically pass for platform data (non-DT) because - * mc13xxx_parse_regulators_dt for !CONFIG_OF will not touch num_parsed. - * - */ - if (num_parsed != num_regulators) { - dev_warn(&pdev->dev, - "parsed %d != regulators %d - check your device tree!\n", - num_parsed, num_regulators); - - num_regulators = num_parsed; - priv->num_regulators = num_regulators; - } + ARRAY_SIZE(mc13892_regulators)); - for (i = 0; i < num_regulators; i++) { + for (i = 0; i < priv->num_regulators; i++) { struct regulator_init_data *init_data; struct regulator_desc *desc; struct device_node *node = NULL; diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index 23cf9f9..da48592 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -180,15 +180,13 @@ EXPORT_SYMBOL_GPL(mc13xxx_get_num_regulators_dt); struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( struct platform_device *pdev, struct mc13xxx_regulator *regulators, - int num_regulators, int *num_parsed) + int num_regulators) { struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); struct mc13xxx_regulator_init_data *data, *p; struct device_node *parent, *child; int i, parsed = 0; - *num_parsed = 0; - of_node_get(pdev->dev.parent->of_node); parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); if (!parent) @@ -204,10 +202,13 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( p = data; for_each_child_of_node(parent, child) { + int found = 0; + for (i = 0; i < num_regulators; i++) { + if (!regulators[i].desc.name) + continue; if (!of_node_cmp(child->name, regulators[i].desc.name)) { - p->id = i; p->init_data = of_get_regulator_init_data( &pdev->dev, child); @@ -215,13 +216,19 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( p++; parsed++; + found = 1; break; } } + + if (!found) + dev_warn(&pdev->dev, + "Unknown regulator: %s\n", child->name); } of_node_put(parent); - *num_parsed = parsed; + priv->num_regulators = parsed; + return data; } EXPORT_SYMBOL_GPL(mc13xxx_parse_regulators_dt); diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h index 007f833..06c8903 100644 --- a/drivers/regulator/mc13xxx.h +++ b/drivers/regulator/mc13xxx.h @@ -39,7 +39,7 @@ extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, extern int mc13xxx_get_num_regulators_dt(struct platform_device *pdev); extern struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( struct platform_device *pdev, struct mc13xxx_regulator *regulators, - int num_regulators, int *num_parsed); + int num_regulators); #else static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev) { @@ -48,7 +48,7 @@ static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev) static inline struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( struct platform_device *pdev, struct mc13xxx_regulator *regulators, - int num_regulators, int *num_parsed) + int num_regulators) { return NULL; } diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 39cf146..92ceed0 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -1,7 +1,7 @@ /* * Driver for Regulator part of Palmas PMIC Chips * - * Copyright 2011-2012 Texas Instruments Inc. + * Copyright 2011-2013 Texas Instruments Inc. * * Author: Graeme Gregory <gg@slimlogic.co.uk> * Author: Ian Lartey <ian@slimlogic.co.uk> @@ -29,6 +29,7 @@ struct regs_info { char *name; + char *sname; u8 vsel_addr; u8 ctrl_addr; u8 tstep_addr; @@ -37,115 +38,159 @@ struct regs_info { static const struct regs_info palmas_regs_info[] = { { .name = "SMPS12", + .sname = "smps1-in", .vsel_addr = PALMAS_SMPS12_VOLTAGE, .ctrl_addr = PALMAS_SMPS12_CTRL, .tstep_addr = PALMAS_SMPS12_TSTEP, }, { .name = "SMPS123", + .sname = "smps1-in", .vsel_addr = PALMAS_SMPS12_VOLTAGE, .ctrl_addr = PALMAS_SMPS12_CTRL, .tstep_addr = PALMAS_SMPS12_TSTEP, }, { .name = "SMPS3", + .sname = "smps3-in", .vsel_addr = PALMAS_SMPS3_VOLTAGE, .ctrl_addr = PALMAS_SMPS3_CTRL, }, { .name = "SMPS45", + .sname = "smps4-in", .vsel_addr = PALMAS_SMPS45_VOLTAGE, .ctrl_addr = PALMAS_SMPS45_CTRL, .tstep_addr = PALMAS_SMPS45_TSTEP, }, { .name = "SMPS457", + .sname = "smps4-in", .vsel_addr = PALMAS_SMPS45_VOLTAGE, .ctrl_addr = PALMAS_SMPS45_CTRL, .tstep_addr = PALMAS_SMPS45_TSTEP, }, { .name = "SMPS6", + .sname = "smps6-in", .vsel_addr = PALMAS_SMPS6_VOLTAGE, .ctrl_addr = PALMAS_SMPS6_CTRL, .tstep_addr = PALMAS_SMPS6_TSTEP, }, { .name = "SMPS7", + .sname = "smps7-in", .vsel_addr = PALMAS_SMPS7_VOLTAGE, .ctrl_addr = PALMAS_SMPS7_CTRL, }, { .name = "SMPS8", + .sname = "smps8-in", .vsel_addr = PALMAS_SMPS8_VOLTAGE, .ctrl_addr = PALMAS_SMPS8_CTRL, .tstep_addr = PALMAS_SMPS8_TSTEP, }, { .name = "SMPS9", + .sname = "smps9-in", .vsel_addr = PALMAS_SMPS9_VOLTAGE, .ctrl_addr = PALMAS_SMPS9_CTRL, }, { .name = "SMPS10", + .sname = "smps10-in", + .ctrl_addr = PALMAS_SMPS10_CTRL, }, { .name = "LDO1", + .sname = "ldo1-in", .vsel_addr = PALMAS_LDO1_VOLTAGE, .ctrl_addr = PALMAS_LDO1_CTRL, }, { .name = "LDO2", + .sname = "ldo2-in", .vsel_addr = PALMAS_LDO2_VOLTAGE, .ctrl_addr = PALMAS_LDO2_CTRL, }, { .name = "LDO3", + .sname = "ldo3-in", .vsel_addr = PALMAS_LDO3_VOLTAGE, .ctrl_addr = PALMAS_LDO3_CTRL, }, { .name = "LDO4", + .sname = "ldo4-in", .vsel_addr = PALMAS_LDO4_VOLTAGE, .ctrl_addr = PALMAS_LDO4_CTRL, }, { .name = "LDO5", + .sname = "ldo5-in", .vsel_addr = PALMAS_LDO5_VOLTAGE, .ctrl_addr = PALMAS_LDO5_CTRL, }, { .name = "LDO6", + .sname = "ldo6-in", .vsel_addr = PALMAS_LDO6_VOLTAGE, .ctrl_addr = PALMAS_LDO6_CTRL, }, { .name = "LDO7", + .sname = "ldo7-in", .vsel_addr = PALMAS_LDO7_VOLTAGE, .ctrl_addr = PALMAS_LDO7_CTRL, }, { .name = "LDO8", + .sname = "ldo8-in", .vsel_addr = PALMAS_LDO8_VOLTAGE, .ctrl_addr = PALMAS_LDO8_CTRL, }, { .name = "LDO9", + .sname = "ldo9-in", .vsel_addr = PALMAS_LDO9_VOLTAGE, .ctrl_addr = PALMAS_LDO9_CTRL, }, { .name = "LDOLN", + .sname = "ldoln-in", .vsel_addr = PALMAS_LDOLN_VOLTAGE, .ctrl_addr = PALMAS_LDOLN_CTRL, }, { .name = "LDOUSB", + .sname = "ldousb-in", .vsel_addr = PALMAS_LDOUSB_VOLTAGE, .ctrl_addr = PALMAS_LDOUSB_CTRL, }, + { + .name = "REGEN1", + .ctrl_addr = PALMAS_REGEN1_CTRL, + }, + { + .name = "REGEN2", + .ctrl_addr = PALMAS_REGEN2_CTRL, + }, + { + .name = "REGEN3", + .ctrl_addr = PALMAS_REGEN3_CTRL, + }, + { + .name = "SYSEN1", + .ctrl_addr = PALMAS_SYSEN1_CTRL, + }, + { + .name = "SYSEN2", + .ctrl_addr = PALMAS_SYSEN2_CTRL, + }, }; +static unsigned int palmas_smps_ramp_delay[4] = {0, 10000, 5000, 2500}; + #define SMPS_CTRL_MODE_OFF 0x00 #define SMPS_CTRL_MODE_ON 0x01 #define SMPS_CTRL_MODE_ECO 0x02 @@ -231,7 +276,10 @@ static int palmas_enable_smps(struct regulator_dev *dev) palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; - reg |= SMPS_CTRL_MODE_ON; + if (pmic->current_reg_mode[id]) + reg |= pmic->current_reg_mode[id]; + else + reg |= SMPS_CTRL_MODE_ON; palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg); @@ -253,16 +301,19 @@ static int palmas_disable_smps(struct regulator_dev *dev) return 0; } - static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode) { struct palmas_pmic *pmic = rdev_get_drvdata(dev); int id = rdev_get_id(dev); unsigned int reg; + bool rail_enable = true; palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; + if (reg == SMPS_CTRL_MODE_OFF) + rail_enable = false; + switch (mode) { case REGULATOR_MODE_NORMAL: reg |= SMPS_CTRL_MODE_ON; @@ -276,8 +327,11 @@ static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode) default: return -EINVAL; } - palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg); + pmic->current_reg_mode[id] = reg & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; + if (rail_enable) + palmas_smps_write(pmic->palmas, + palmas_regs_info[id].ctrl_addr, reg); return 0; } @@ -287,9 +341,7 @@ static unsigned int palmas_get_mode_smps(struct regulator_dev *dev) int id = rdev_get_id(dev); unsigned int reg; - palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); - reg &= PALMAS_SMPS12_CTRL_STATUS_MASK; - reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT; + reg = pmic->current_reg_mode[id] & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; switch (reg) { case SMPS_CTRL_MODE_ON: @@ -356,6 +408,63 @@ static int palmas_map_voltage_smps(struct regulator_dev *rdev, return ret; } +static int palma_smps_set_voltage_smps_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, unsigned int new_selector) +{ + struct palmas_pmic *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int old_uv, new_uv; + unsigned int ramp_delay = pmic->ramp_delay[id]; + + if (!ramp_delay) + return 0; + + old_uv = palmas_list_voltage_smps(rdev, old_selector); + if (old_uv < 0) + return old_uv; + + new_uv = palmas_list_voltage_smps(rdev, new_selector); + if (new_uv < 0) + return new_uv; + + return DIV_ROUND_UP(abs(old_uv - new_uv), ramp_delay); +} + +static int palmas_smps_set_ramp_delay(struct regulator_dev *rdev, + int ramp_delay) +{ + struct palmas_pmic *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + unsigned int reg = 0; + unsigned int addr = palmas_regs_info[id].tstep_addr; + int ret; + + /* SMPS3 and SMPS7 do not have tstep_addr setting */ + switch (id) { + case PALMAS_REG_SMPS3: + case PALMAS_REG_SMPS7: + return 0; + } + + if (ramp_delay <= 0) + reg = 0; + else if (ramp_delay <= 2500) + reg = 3; + else if (ramp_delay <= 5000) + reg = 2; + else + reg = 1; + + ret = palmas_smps_write(pmic->palmas, addr, reg); + if (ret < 0) { + dev_err(pmic->palmas->dev, "TSTEP write failed: %d\n", ret); + return ret; + } + + pmic->ramp_delay[id] = palmas_smps_ramp_delay[reg]; + return ret; +} + static struct regulator_ops palmas_ops_smps = { .is_enabled = palmas_is_enabled_smps, .enable = palmas_enable_smps, @@ -366,6 +475,8 @@ static struct regulator_ops palmas_ops_smps = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .list_voltage = palmas_list_voltage_smps, .map_voltage = palmas_map_voltage_smps, + .set_voltage_time_sel = palma_smps_set_voltage_smps_time_sel, + .set_ramp_delay = palmas_smps_set_ramp_delay, }; static struct regulator_ops palmas_ops_smps10 = { @@ -401,6 +512,12 @@ static struct regulator_ops palmas_ops_ldo = { .map_voltage = regulator_map_voltage_linear, }; +static struct regulator_ops palmas_ops_extreg = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, +}; + /* * setup the hardware based sleep configuration of the SMPS/LDO regulators * from the platform data. This is different to the software based control @@ -422,40 +539,32 @@ static int palmas_smps_init(struct palmas *palmas, int id, switch (id) { case PALMAS_REG_SMPS10: - if (reg_init->mode_sleep) { - reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK; + reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK; + if (reg_init->mode_sleep) reg |= reg_init->mode_sleep << PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT; - } break; default: if (reg_init->warm_reset) reg |= PALMAS_SMPS12_CTRL_WR_S; + else + reg &= ~PALMAS_SMPS12_CTRL_WR_S; if (reg_init->roof_floor) reg |= PALMAS_SMPS12_CTRL_ROOF_FLOOR_EN; + else + reg &= ~PALMAS_SMPS12_CTRL_ROOF_FLOOR_EN; - if (reg_init->mode_sleep) { - reg &= ~PALMAS_SMPS12_CTRL_MODE_SLEEP_MASK; + reg &= ~PALMAS_SMPS12_CTRL_MODE_SLEEP_MASK; + if (reg_init->mode_sleep) reg |= reg_init->mode_sleep << PALMAS_SMPS12_CTRL_MODE_SLEEP_SHIFT; - } } ret = palmas_smps_write(palmas, addr, reg); if (ret) return ret; - if (palmas_regs_info[id].tstep_addr && reg_init->tstep) { - addr = palmas_regs_info[id].tstep_addr; - - reg = reg_init->tstep & PALMAS_SMPS12_TSTEP_TSTEP_MASK; - - ret = palmas_smps_write(palmas, addr, reg); - if (ret) - return ret; - } - if (palmas_regs_info[id].vsel_addr && reg_init->vsel) { addr = palmas_regs_info[id].vsel_addr; @@ -485,9 +594,13 @@ static int palmas_ldo_init(struct palmas *palmas, int id, if (reg_init->warm_reset) reg |= PALMAS_LDO1_CTRL_WR_S; + else + reg &= ~PALMAS_LDO1_CTRL_WR_S; if (reg_init->mode_sleep) reg |= PALMAS_LDO1_CTRL_MODE_SLEEP; + else + reg &= ~PALMAS_LDO1_CTRL_MODE_SLEEP; ret = palmas_ldo_write(palmas, addr, reg); if (ret) @@ -496,6 +609,68 @@ static int palmas_ldo_init(struct palmas *palmas, int id, return 0; } +static int palmas_extreg_init(struct palmas *palmas, int id, + struct palmas_reg_init *reg_init) +{ + unsigned int addr; + int ret; + unsigned int val = 0; + + addr = palmas_regs_info[id].ctrl_addr; + + if (reg_init->mode_sleep) + val = PALMAS_REGEN1_CTRL_MODE_SLEEP; + + ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE, + addr, PALMAS_REGEN1_CTRL_MODE_SLEEP, val); + if (ret < 0) { + dev_err(palmas->dev, "Resource reg 0x%02x update failed %d\n", + addr, ret); + return ret; + } + return 0; +} + +static void palmas_enable_ldo8_track(struct palmas *palmas) +{ + unsigned int reg; + unsigned int addr; + int ret; + + addr = palmas_regs_info[PALMAS_REG_LDO8].ctrl_addr; + + ret = palmas_ldo_read(palmas, addr, ®); + if (ret) { + dev_err(palmas->dev, "Error in reading ldo8 control reg\n"); + return; + } + + reg |= PALMAS_LDO8_CTRL_LDO_TRACKING_EN; + ret = palmas_ldo_write(palmas, addr, reg); + if (ret < 0) { + dev_err(palmas->dev, "Error in enabling tracking mode\n"); + return; + } + /* + * When SMPS45 is set to off and LDO8 tracking is enabled, the LDO8 + * output is defined by the LDO8_VOLTAGE.VSEL register divided by two, + * and can be set from 0.45 to 1.65 V. + */ + addr = palmas_regs_info[PALMAS_REG_LDO8].vsel_addr; + ret = palmas_ldo_read(palmas, addr, ®); + if (ret) { + dev_err(palmas->dev, "Error in reading ldo8 voltage reg\n"); + return; + } + + reg = (reg << 1) & PALMAS_LDO8_VOLTAGE_VSEL_MASK; + ret = palmas_ldo_write(palmas, addr, reg); + if (ret < 0) + dev_err(palmas->dev, "Error in setting ldo8 voltage reg\n"); + + return; +} + static struct of_regulator_match palmas_matches[] = { { .name = "smps12", }, { .name = "smps123", }, @@ -518,6 +693,11 @@ static struct of_regulator_match palmas_matches[] = { { .name = "ldo9", }, { .name = "ldoln", }, { .name = "ldousb", }, + { .name = "regen1", }, + { .name = "regen2", }, + { .name = "regen3", }, + { .name = "sysen1", }, + { .name = "sysen2", }, }; static void palmas_dt_to_pdata(struct device *dev, @@ -553,39 +733,36 @@ static void palmas_dt_to_pdata(struct device *dev, pdata->reg_init[idx] = devm_kzalloc(dev, sizeof(struct palmas_reg_init), GFP_KERNEL); - ret = of_property_read_u32(palmas_matches[idx].of_node, - "ti,warm_reset", &prop); - if (!ret) - pdata->reg_init[idx]->warm_reset = prop; + pdata->reg_init[idx]->warm_reset = + of_property_read_bool(palmas_matches[idx].of_node, + "ti,warm-reset"); - ret = of_property_read_u32(palmas_matches[idx].of_node, - "ti,roof_floor", &prop); - if (!ret) - pdata->reg_init[idx]->roof_floor = prop; + pdata->reg_init[idx]->roof_floor = + of_property_read_bool(palmas_matches[idx].of_node, + "ti,roof-floor"); ret = of_property_read_u32(palmas_matches[idx].of_node, - "ti,mode_sleep", &prop); + "ti,mode-sleep", &prop); if (!ret) pdata->reg_init[idx]->mode_sleep = prop; - ret = of_property_read_u32(palmas_matches[idx].of_node, - "ti,tstep", &prop); - if (!ret) - pdata->reg_init[idx]->tstep = prop; + ret = of_property_read_bool(palmas_matches[idx].of_node, + "ti,smps-range"); + if (ret) + pdata->reg_init[idx]->vsel = + PALMAS_SMPS12_VOLTAGE_RANGE; - ret = of_property_read_u32(palmas_matches[idx].of_node, - "ti,vsel", &prop); - if (!ret) - pdata->reg_init[idx]->vsel = prop; + if (idx == PALMAS_REG_LDO8) + pdata->enable_ldo8_tracking = of_property_read_bool( + palmas_matches[idx].of_node, + "ti,enable-ldo8-tracking"); } - ret = of_property_read_u32(node, "ti,ldo6_vibrator", &prop); - if (!ret) - pdata->ldo6_vibrator = prop; + pdata->ldo6_vibrator = of_property_read_bool(node, "ti,ldo6-vibrator"); } -static int palmas_probe(struct platform_device *pdev) +static int palmas_regulators_probe(struct platform_device *pdev) { struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); struct palmas_pmic_platform_data *pdata = pdev->dev.platform_data; @@ -630,6 +807,7 @@ static int palmas_probe(struct platform_device *pdev) config.driver_data = pmic; for (id = 0; id < PALMAS_REG_LDO1; id++) { + bool ramp_delay_support = false; /* * Miss out regulators which are not available due @@ -640,19 +818,42 @@ static int palmas_probe(struct platform_device *pdev) case PALMAS_REG_SMPS3: if (pmic->smps123) continue; + if (id == PALMAS_REG_SMPS12) + ramp_delay_support = true; break; case PALMAS_REG_SMPS123: if (!pmic->smps123) continue; + ramp_delay_support = true; break; case PALMAS_REG_SMPS45: case PALMAS_REG_SMPS7: if (pmic->smps457) continue; + if (id == PALMAS_REG_SMPS45) + ramp_delay_support = true; break; case PALMAS_REG_SMPS457: if (!pmic->smps457) continue; + ramp_delay_support = true; + break; + } + + if ((id == PALMAS_REG_SMPS6) && (id == PALMAS_REG_SMPS8)) + ramp_delay_support = true; + + if (ramp_delay_support) { + addr = palmas_regs_info[id].tstep_addr; + ret = palmas_smps_read(pmic->palmas, addr, ®); + if (ret < 0) { + dev_err(&pdev->dev, + "reading TSTEP reg failed: %d\n", ret); + goto err_unregister_regulator; + } + pmic->desc[id].ramp_delay = + palmas_smps_ramp_delay[reg & 0x3]; + pmic->ramp_delay[id] = pmic->desc[id].ramp_delay; } /* Initialise sleep/init values from platform data */ @@ -686,7 +887,8 @@ static int palmas_probe(struct platform_device *pdev) /* * Read and store the RANGE bit for later use * This must be done before regulator is probed, - * otherwise we error in probe with unsupportable ranges. + * otherwise we error in probe with unsupportable + * ranges. Read the current smps mode for later use. */ addr = palmas_regs_info[id].vsel_addr; @@ -703,6 +905,14 @@ static int palmas_probe(struct platform_device *pdev) palmas_regs_info[id].vsel_addr); pmic->desc[id].vsel_mask = PALMAS_SMPS12_VOLTAGE_VSEL_MASK; + + /* Read the smps mode for later use. */ + addr = palmas_regs_info[id].ctrl_addr; + ret = palmas_smps_read(pmic->palmas, addr, ®); + if (ret) + goto err_unregister_regulator; + pmic->current_reg_mode[id] = reg & + PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; } pmic->desc[id].type = REGULATOR_VOLTAGE; @@ -713,6 +923,7 @@ static int palmas_probe(struct platform_device *pdev) else config.init_data = NULL; + pmic->desc[id].supply_name = palmas_regs_info[id].sname; config.of_node = palmas_matches[id].of_node; rdev = regulator_register(&pmic->desc[id], &config); @@ -738,27 +949,49 @@ static int palmas_probe(struct platform_device *pdev) /* Register the regulators */ pmic->desc[id].name = palmas_regs_info[id].name; pmic->desc[id].id = id; - pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES; - - pmic->desc[id].ops = &palmas_ops_ldo; - pmic->desc[id].type = REGULATOR_VOLTAGE; pmic->desc[id].owner = THIS_MODULE; - pmic->desc[id].min_uV = 900000; - pmic->desc[id].uV_step = 50000; - pmic->desc[id].linear_min_sel = 1; - pmic->desc[id].vsel_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, + + if (id < PALMAS_REG_REGEN1) { + pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES; + pmic->desc[id].ops = &palmas_ops_ldo; + pmic->desc[id].min_uV = 900000; + pmic->desc[id].uV_step = 50000; + pmic->desc[id].linear_min_sel = 1; + pmic->desc[id].vsel_reg = + PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, palmas_regs_info[id].vsel_addr); - pmic->desc[id].vsel_mask = PALMAS_LDO1_VOLTAGE_VSEL_MASK; - pmic->desc[id].enable_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, + pmic->desc[id].vsel_mask = + PALMAS_LDO1_VOLTAGE_VSEL_MASK; + pmic->desc[id].enable_reg = + PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, + palmas_regs_info[id].ctrl_addr); + pmic->desc[id].enable_mask = + PALMAS_LDO1_CTRL_MODE_ACTIVE; + + /* Check if LDO8 is in tracking mode or not */ + if (pdata && (id == PALMAS_REG_LDO8) && + pdata->enable_ldo8_tracking) { + palmas_enable_ldo8_track(palmas); + pmic->desc[id].min_uV = 450000; + pmic->desc[id].uV_step = 25000; + } + } else { + pmic->desc[id].n_voltages = 1; + pmic->desc[id].ops = &palmas_ops_extreg; + pmic->desc[id].enable_reg = + PALMAS_BASE_TO_REG(PALMAS_RESOURCE_BASE, palmas_regs_info[id].ctrl_addr); - pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE; + pmic->desc[id].enable_mask = + PALMAS_REGEN1_CTRL_MODE_ACTIVE; + } if (pdata) config.init_data = pdata->reg_data[id]; else config.init_data = NULL; + pmic->desc[id].supply_name = palmas_regs_info[id].sname; config.of_node = palmas_matches[id].of_node; rdev = regulator_register(&pmic->desc[id], &config); @@ -777,7 +1010,12 @@ static int palmas_probe(struct platform_device *pdev) if (pdata) { reg_init = pdata->reg_init[id]; if (reg_init) { - ret = palmas_ldo_init(palmas, id, reg_init); + if (id < PALMAS_REG_REGEN1) + ret = palmas_ldo_init(palmas, + id, reg_init); + else + ret = palmas_extreg_init(palmas, + id, reg_init); if (ret) { regulator_unregister(pmic->rdev[id]); goto err_unregister_regulator; @@ -786,6 +1024,7 @@ static int palmas_probe(struct platform_device *pdev) } } + return 0; err_unregister_regulator: @@ -794,7 +1033,7 @@ err_unregister_regulator: return ret; } -static int palmas_remove(struct platform_device *pdev) +static int palmas_regulators_remove(struct platform_device *pdev) { struct palmas_pmic *pmic = platform_get_drvdata(pdev); int id; @@ -806,6 +1045,12 @@ static int palmas_remove(struct platform_device *pdev) static struct of_device_id of_palmas_match_tbl[] = { { .compatible = "ti,palmas-pmic", }, + { .compatible = "ti,twl6035-pmic", }, + { .compatible = "ti,twl6036-pmic", }, + { .compatible = "ti,twl6037-pmic", }, + { .compatible = "ti,tps65913-pmic", }, + { .compatible = "ti,tps65914-pmic", }, + { .compatible = "ti,tps80036-pmic", }, { /* end */ } }; @@ -815,8 +1060,8 @@ static struct platform_driver palmas_driver = { .of_match_table = of_palmas_match_tbl, .owner = THIS_MODULE, }, - .probe = palmas_probe, - .remove = palmas_remove, + .probe = palmas_regulators_probe, + .remove = palmas_regulators_remove, }; static int __init palmas_init(void) diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c index 9e6f786..5885b45 100644 --- a/drivers/regulator/rc5t583-regulator.c +++ b/drivers/regulator/rc5t583-regulator.c @@ -49,10 +49,6 @@ struct rc5t583_regulator_info { struct rc5t583_regulator { struct rc5t583_regulator_info *reg_info; - - /* Devices */ - struct device *dev; - struct rc5t583 *mfd; struct regulator_dev *rdev; }; @@ -155,8 +151,6 @@ static int rc5t583_regulator_probe(struct platform_device *pdev) reg = ®s[id]; ri = &rc5t583_reg_info[id]; reg->reg_info = ri; - reg->mfd = rc5t583; - reg->dev = &pdev->dev; if (ri->deepsleep_id == RC5T583_DS_NONE) goto skip_ext_pwr_config; diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 8a83194..c24448b 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -549,7 +549,7 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) * pdata->num_regulators, GFP_KERNEL); - if (!rdata) { + if (!rmode) { dev_err(iodev->dev, "could not allocate memory for regulator mode\n"); return -ENOMEM; @@ -923,8 +923,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) return 0; err: for (i = 0; i < s5m8767->num_regulators; i++) - if (rdev[i]) - regulator_unregister(rdev[i]); + regulator_unregister(rdev[i]); return ret; } @@ -936,8 +935,7 @@ static int s5m8767_pmic_remove(struct platform_device *pdev) int i; for (i = 0; i < s5m8767->num_regulators; i++) - if (rdev[i]) - regulator_unregister(rdev[i]); + regulator_unregister(rdev[i]); return 0; } diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index acbd63f..612919c 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -278,7 +278,7 @@ static int tps62360_init_dcdc(struct tps62360_chip *tps, __func__, REG_RAMPCTRL, ret); return ret; } - ramp_ctrl = (ramp_ctrl >> 4) & 0x7; + ramp_ctrl = (ramp_ctrl >> 5) & 0x7; /* ramp mV/us = 32/(2^ramp_ctrl) */ tps->desc.ramp_delay = DIV_ROUND_UP(32000, BIT(ramp_ctrl)); diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index 9b9af6d..9d053e2 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -107,12 +107,7 @@ static const unsigned int DCDC_FIXED_1800000_VSEL_table[] = { }; /* Supported voltage values for LDO regulators for tps65020 */ -static const unsigned int TPS65020_LDO1_VSEL_table[] = { - 1000000, 1050000, 1100000, 1300000, - 1800000, 2500000, 3000000, 3300000, -}; - -static const unsigned int TPS65020_LDO2_VSEL_table[] = { +static const unsigned int TPS65020_LDO_VSEL_table[] = { 1000000, 1050000, 1100000, 1300000, 1800000, 2500000, 3000000, 3300000, }; @@ -154,20 +149,15 @@ struct tps_driver_data { static int tps65023_dcdc_get_voltage_sel(struct regulator_dev *dev) { struct tps_pmic *tps = rdev_get_drvdata(dev); - int ret; - int data, dcdc = rdev_get_id(dev); + int dcdc = rdev_get_id(dev); if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) return -EINVAL; - if (dcdc == tps->core_regulator) { - ret = regmap_read(tps->regmap, TPS65023_REG_DEF_CORE, &data); - if (ret != 0) - return ret; - data &= (tps->info[dcdc]->table_len - 1); - return data; - } else + if (dcdc != tps->core_regulator) return 0; + + return regulator_get_voltage_sel_regmap(dev); } static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev, @@ -175,23 +165,11 @@ static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev, { struct tps_pmic *tps = rdev_get_drvdata(dev); int dcdc = rdev_get_id(dev); - int ret; if (dcdc != tps->core_regulator) return -EINVAL; - ret = regmap_write(tps->regmap, TPS65023_REG_DEF_CORE, selector); - if (ret) - goto out; - - /* Tell the chip that we have changed the value in DEFCORE - * and its time to update the core voltage - */ - ret = regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2, - TPS65023_REG_CTRL2_GO, TPS65023_REG_CTRL2_GO); - -out: - return ret; + return regulator_set_voltage_sel_regmap(dev, selector); } /* Operations permitted on VDCDCx */ @@ -202,6 +180,7 @@ static struct regulator_ops tps65023_dcdc_ops = { .get_voltage_sel = tps65023_dcdc_get_voltage_sel, .set_voltage_sel = tps65023_dcdc_set_voltage_sel, .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, }; /* Operations permitted on LDOx */ @@ -212,6 +191,7 @@ static struct regulator_ops tps65023_ldo_ops = { .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, }; static struct regmap_config tps65023_regmap_config = { @@ -285,6 +265,10 @@ static int tps_65023_probe(struct i2c_client *client, default: /* DCDCx */ tps->desc[i].enable_mask = 1 << (TPS65023_NUM_REGULATOR - i); + tps->desc[i].vsel_reg = TPS65023_REG_DEF_CORE; + tps->desc[i].vsel_mask = info->table_len - 1; + tps->desc[i].apply_reg = TPS65023_REG_CON_CTRL2; + tps->desc[i].apply_bit = TPS65023_REG_CTRL2_GO; } config.dev = &client->dev; @@ -347,13 +331,13 @@ static const struct tps_info tps65020_regs[] = { }, { .name = "LDO1", - .table_len = ARRAY_SIZE(TPS65020_LDO1_VSEL_table), - .table = TPS65020_LDO1_VSEL_table, + .table_len = ARRAY_SIZE(TPS65020_LDO_VSEL_table), + .table = TPS65020_LDO_VSEL_table, }, { .name = "LDO2", - .table_len = ARRAY_SIZE(TPS65020_LDO2_VSEL_table), - .table = TPS65020_LDO2_VSEL_table, + .table_len = ARRAY_SIZE(TPS65020_LDO_VSEL_table), + .table = TPS65020_LDO_VSEL_table, }, }; diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index 54aa2da..4117ff5 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -356,6 +356,7 @@ static struct regulator_ops tps6507x_pmic_ops = { .get_voltage_sel = tps6507x_pmic_get_voltage_sel, .set_voltage_sel = tps6507x_pmic_set_voltage_sel, .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, }; #ifdef CONFIG_OF diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c index 843ee0a..1094393 100644 --- a/drivers/regulator/tps6524x-regulator.c +++ b/drivers/regulator/tps6524x-regulator.c @@ -572,6 +572,7 @@ static struct regulator_ops regulator_ops = { .get_voltage_sel = get_voltage_sel, .set_voltage_sel = set_voltage_sel, .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .set_current_limit = set_current_limit, .get_current_limit = get_current_limit, }; @@ -584,8 +585,7 @@ static int pmic_remove(struct spi_device *spi) if (!hw) return 0; for (i = 0; i < N_REGULATORS; i++) { - if (hw->rdev[i]) - regulator_unregister(hw->rdev[i]); + regulator_unregister(hw->rdev[i]); hw->rdev[i] = NULL; } spi_set_drvdata(spi, NULL); diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index e68382d..d8fa37d 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -70,6 +70,7 @@ static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev) static struct regulator_ops tps6586x_regulator_ops = { .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -245,7 +246,7 @@ static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev, reg = TPS6586X_SM1SL; break; default: - dev_warn(&pdev->dev, "Only SM0/SM1 can set slew rate\n"); + dev_err(&pdev->dev, "Only SM0/SM1 can set slew rate\n"); return -EINVAL; } @@ -304,14 +305,12 @@ static struct tps6586x_platform_data *tps6586x_parse_regulator_dt( } err = of_regulator_match(&pdev->dev, regs, tps6586x_matches, num); + of_node_put(regs); 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"); diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index 6ba6931..45c1644 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -748,6 +748,7 @@ static struct regulator_ops tps65910_ops_dcdc = { .set_voltage_sel = tps65910_set_voltage_dcdc_sel, .set_voltage_time_sel = regulator_set_voltage_time_sel, .list_voltage = tps65910_list_voltage_dcdc, + .map_voltage = regulator_map_voltage_ascend, }; static struct regulator_ops tps65910_ops_vdd3 = { @@ -758,6 +759,7 @@ static struct regulator_ops tps65910_ops_vdd3 = { .get_mode = tps65910_get_mode, .get_voltage = tps65910_get_voltage_vdd3, .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, }; static struct regulator_ops tps65910_ops = { @@ -769,6 +771,7 @@ static struct regulator_ops tps65910_ops = { .get_voltage_sel = tps65910_get_voltage_sel, .set_voltage_sel = tps65910_set_voltage_sel, .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, }; static struct regulator_ops tps65911_ops = { @@ -780,6 +783,7 @@ static struct regulator_ops tps65911_ops = { .get_voltage_sel = tps65911_get_voltage_sel, .set_voltage_sel = tps65911_set_voltage_sel, .list_voltage = tps65911_list_voltage, + .map_voltage = regulator_map_voltage_ascend, }; static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, diff --git a/drivers/regulator/tps80031-regulator.c b/drivers/regulator/tps80031-regulator.c index 9019d0e..6511d0b 100644 --- a/drivers/regulator/tps80031-regulator.c +++ b/drivers/regulator/tps80031-regulator.c @@ -238,12 +238,11 @@ static int tps80031_dcdc_get_voltage_sel(struct regulator_dev *rdev) return vsel & SMPS_VSEL_MASK; } -static int tps80031_ldo_set_voltage_sel(struct regulator_dev *rdev, - unsigned sel) +static int tps80031_ldo_list_voltage(struct regulator_dev *rdev, + unsigned int sel) { struct tps80031_regulator *ri = rdev_get_drvdata(rdev); struct device *parent = to_tps80031_dev(rdev); - int ret; /* Check for valid setting for TPS80031 or TPS80032-ES1.0 */ if ((ri->rinfo->desc.id == TPS80031_REGULATOR_LDO2) && @@ -260,28 +259,27 @@ static int tps80031_ldo_set_voltage_sel(struct regulator_dev *rdev, } } - ret = tps80031_write(parent, ri->rinfo->volt_id, - ri->rinfo->volt_reg, sel); - if (ret < 0) - dev_err(ri->dev, "Error in writing reg 0x%02x, e = %d\n", - ri->rinfo->volt_reg, ret); - return ret; + return regulator_list_voltage_linear(rdev, sel); } -static int tps80031_ldo_get_voltage_sel(struct regulator_dev *rdev) +static int tps80031_ldo_map_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) { struct tps80031_regulator *ri = rdev_get_drvdata(rdev); struct device *parent = to_tps80031_dev(rdev); - uint8_t vsel; - int ret; - ret = tps80031_read(parent, ri->rinfo->volt_id, - ri->rinfo->volt_reg, &vsel); - if (ret < 0) { - dev_err(ri->dev, "Error in writing the Voltage register\n"); - return ret; + /* Check for valid setting for TPS80031 or TPS80032-ES1.0 */ + if ((ri->rinfo->desc.id == TPS80031_REGULATOR_LDO2) && + (ri->device_flags & TRACK_MODE_ENABLE)) { + if (((tps80031_get_chip_info(parent) == TPS80031) || + ((tps80031_get_chip_info(parent) == TPS80032) && + (tps80031_get_pmu_version(parent) == 0x0)))) { + return regulator_map_voltage_iterate(rdev, min_uV, + max_uV); + } } - return vsel & rdev->desc->vsel_mask; + + return regulator_map_voltage_linear(rdev, min_uV, max_uV); } static int tps80031_vbus_is_enabled(struct regulator_dev *rdev) @@ -390,9 +388,10 @@ static struct regulator_ops tps80031_dcdc_ops = { }; static struct regulator_ops tps80031_ldo_ops = { - .list_voltage = regulator_list_voltage_linear, - .set_voltage_sel = tps80031_ldo_set_voltage_sel, - .get_voltage_sel = tps80031_ldo_get_voltage_sel, + .list_voltage = tps80031_ldo_list_voltage, + .map_voltage = tps80031_ldo_map_voltage, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, .enable = tps80031_reg_enable, .disable = tps80031_reg_disable, .is_enabled = tps80031_reg_is_enabled, @@ -459,6 +458,7 @@ static struct regulator_ops tps80031_ext_reg_ops = { .uV_step = 100000, \ .linear_min_sel = 1, \ .n_voltages = 25, \ + .vsel_reg = TPS80031_##_id##_CFG_VOLTAGE, \ .vsel_mask = LDO_VSEL_MASK, \ .enable_time = 500, \ }, \ @@ -680,6 +680,7 @@ static int tps80031_regulator_probe(struct platform_device *pdev) struct tps80031_regulator *pmic; struct regulator_dev *rdev; struct regulator_config config = { }; + struct tps80031 *tps80031_mfd = dev_get_drvdata(pdev->dev.parent); int ret; int num; @@ -707,6 +708,8 @@ static int tps80031_regulator_probe(struct platform_device *pdev) config.dev = &pdev->dev; config.init_data = NULL; config.driver_data = ri; + config.regmap = tps80031_mfd->regmap[ri->rinfo->volt_id]; + if (tps_pdata) { config.init_data = tps_pdata->reg_init_data; ri->config_flags = tps_pdata->config_flags; diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index f705d25..fb6e67d 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -441,12 +441,6 @@ static const u16 VSIM_VSEL_table[] = { static const u16 VDAC_VSEL_table[] = { 1200, 1300, 1800, 1800, }; -static const u16 VDD1_VSEL_table[] = { - 800, 1450, -}; -static const u16 VDD2_VSEL_table[] = { - 800, 1450, 1500, -}; static const u16 VIO_VSEL_table[] = { 1800, 1850, }; @@ -615,18 +609,8 @@ static struct regulator_ops twl6030ldo_ops = { /*----------------------------------------------------------------------*/ -/* - * Fixed voltage LDOs don't have a VSEL field to update. - */ -static int twlfixed_list_voltage(struct regulator_dev *rdev, unsigned index) -{ - struct twlreg_info *info = rdev_get_drvdata(rdev); - - return info->min_mV * 1000; -} - static struct regulator_ops twl4030fixed_ops = { - .list_voltage = twlfixed_list_voltage, + .list_voltage = regulator_list_voltage_linear, .enable = twl4030reg_enable, .disable = twl4030reg_disable, @@ -638,7 +622,7 @@ static struct regulator_ops twl4030fixed_ops = { }; static struct regulator_ops twl6030fixed_ops = { - .list_voltage = twlfixed_list_voltage, + .list_voltage = regulator_list_voltage_linear, .enable = twl6030reg_enable, .disable = twl6030reg_disable, @@ -944,19 +928,7 @@ static const struct twlreg_info TWLFIXED_INFO_##label = { \ .ops = &operations, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ - .enable_time = turnon_delay, \ - }, \ - } - -#define TWL6030_FIXED_RESOURCE(label, offset, turnon_delay) \ -static struct twlreg_info TWLRES_INFO_##label = { \ - .base = offset, \ - .desc = { \ - .name = #label, \ - .id = TWL6030_REG_##label, \ - .ops = &twl6030_fixed_resource, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ + .min_uV = mVolts * 1000, \ .enable_time = turnon_delay, \ }, \ } diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 6ff8723..a612c35 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -18,6 +18,7 @@ #include <linux/err.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> #include <linux/gpio.h> #include <linux/slab.h> @@ -28,6 +29,8 @@ struct wm8994_ldo { struct regulator_dev *regulator; struct wm8994 *wm8994; + struct regulator_consumer_supply supply; + struct regulator_init_data init_data; }; #define WM8994_LDO1_MAX_SELECTOR 0x7 @@ -99,6 +102,26 @@ static const struct regulator_desc wm8994_ldo_desc[] = { }, }; +static const struct regulator_consumer_supply wm8994_ldo_consumer[] = { + { .supply = "AVDD1" }, + { .supply = "DCVDD" }, +}; + +static const struct regulator_init_data wm8994_ldo_default[] = { + { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + }, + { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + }, +}; + static int wm8994_ldo_probe(struct platform_device *pdev) { struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent); @@ -117,13 +140,29 @@ static int wm8994_ldo_probe(struct platform_device *pdev) } ldo->wm8994 = wm8994; + ldo->supply = wm8994_ldo_consumer[id]; + ldo->supply.dev_name = dev_name(wm8994->dev); config.dev = wm8994->dev; config.driver_data = ldo; config.regmap = wm8994->regmap; - if (pdata) { - config.init_data = pdata->ldo[id].init_data; + config.init_data = &ldo->init_data; + if (pdata) config.ena_gpio = pdata->ldo[id].enable; + else if (wm8994->dev->of_node) + config.ena_gpio = wm8994->pdata.ldo[id].enable; + + /* Use default constraints if none set up */ + if (!pdata || !pdata->ldo[id].init_data || wm8994->dev->of_node) { + dev_dbg(wm8994->dev, "Using default init data, supply %s %s\n", + ldo->supply.dev_name, ldo->supply.supply); + + ldo->init_data = wm8994_ldo_default[id]; + ldo->init_data.consumer_supplies = &ldo->supply; + if (!config.ena_gpio) + ldo->init_data.constraints.valid_ops_mask = 0; + } else { + ldo->init_data = *pdata->ldo[id].init_data; } ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &config); @@ -162,23 +201,7 @@ static struct platform_driver wm8994_ldo_driver = { }, }; -static int __init wm8994_ldo_init(void) -{ - int ret; - - ret = platform_driver_register(&wm8994_ldo_driver); - if (ret != 0) - pr_err("Failed to register Wm8994 GP LDO driver: %d\n", ret); - - return ret; -} -subsys_initcall(wm8994_ldo_init); - -static void __exit wm8994_ldo_exit(void) -{ - platform_driver_unregister(&wm8994_ldo_driver); -} -module_exit(wm8994_ldo_exit); +module_platform_driver(wm8994_ldo_driver); /* Module information */ MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |