diff options
Diffstat (limited to 'drivers')
29 files changed, 971 insertions, 187 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 1bcf601de5bc..ff031a7735a5 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -852,13 +852,14 @@ config MFD_RK808 including interrupts, RTC, LDO & DCDC regulators, and onkey. config MFD_RN5T618 - tristate "Ricoh RN5T5618 PMIC" + tristate "Ricoh RN5T567/618 PMIC" depends on I2C + depends on OF select MFD_CORE select REGMAP_I2C help - Say yes here to add support for the Ricoh RN5T618 PMIC. This - driver provides common support for accessing the device, + Say yes here to add support for the Ricoh RN5T567 or R5T618 PMIC. + This driver provides common support for accessing the device, additional drivers must be enabled in order to use the functionality of the device. diff --git a/drivers/mfd/rn5t618.c b/drivers/mfd/rn5t618.c index 0ad51d792feb..ee94080e1cbb 100644 --- a/drivers/mfd/rn5t618.c +++ b/drivers/mfd/rn5t618.c @@ -2,6 +2,7 @@ * MFD core driver for Ricoh RN5T618 PMIC * * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> + * Copyright (C) 2016 Toradex AG * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -11,10 +12,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <linux/delay.h> #include <linux/i2c.h> #include <linux/mfd/core.h> #include <linux/mfd/rn5t618.h> #include <linux/module.h> +#include <linux/of_device.h> +#include <linux/reboot.h> #include <linux/regmap.h> static const struct mfd_cell rn5t618_cells[] = { @@ -48,28 +52,64 @@ static const struct regmap_config rn5t618_regmap_config = { }; static struct rn5t618 *rn5t618_pm_power_off; +static struct notifier_block rn5t618_restart_handler; -static void rn5t618_power_off(void) +static void rn5t618_trigger_poweroff_sequence(bool repower) { /* disable automatic repower-on */ regmap_update_bits(rn5t618_pm_power_off->regmap, RN5T618_REPCNT, - RN5T618_REPCNT_REPWRON, 0); + RN5T618_REPCNT_REPWRON, + repower ? RN5T618_REPCNT_REPWRON : 0); /* start power-off sequence */ regmap_update_bits(rn5t618_pm_power_off->regmap, RN5T618_SLPCNT, RN5T618_SLPCNT_SWPWROFF, RN5T618_SLPCNT_SWPWROFF); } +static void rn5t618_power_off(void) +{ + rn5t618_trigger_poweroff_sequence(false); +} + +static int rn5t618_restart(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + rn5t618_trigger_poweroff_sequence(true); + + /* + * Re-power factor detection on PMIC side is not instant. 1ms + * proved to be enough time until reset takes effect. + */ + mdelay(1); + + return NOTIFY_DONE; +} + +static const struct of_device_id rn5t618_of_match[] = { + { .compatible = "ricoh,rn5t567", .data = (void *)RN5T567 }, + { .compatible = "ricoh,rn5t618", .data = (void *)RN5T618 }, + { } +}; +MODULE_DEVICE_TABLE(of, rn5t618_of_match); + static int rn5t618_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + const struct of_device_id *of_id; struct rn5t618 *priv; int ret; + of_id = of_match_device(rn5t618_of_match, &i2c->dev); + if (!of_id) { + dev_err(&i2c->dev, "Failed to find matching DT ID\n"); + return -EINVAL; + } + priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; i2c_set_clientdata(i2c, priv); + priv->variant = (long)of_id->data; priv->regmap = devm_regmap_init_i2c(i2c, &rn5t618_regmap_config); if (IS_ERR(priv->regmap)) { @@ -85,9 +125,21 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c, return ret; } - if (!pm_power_off) { - rn5t618_pm_power_off = priv; - pm_power_off = rn5t618_power_off; + rn5t618_pm_power_off = priv; + if (of_device_is_system_power_controller(i2c->dev.of_node)) { + if (!pm_power_off) + pm_power_off = rn5t618_power_off; + else + dev_warn(&i2c->dev, "Poweroff callback already assigned\n"); + } + + rn5t618_restart_handler.notifier_call = rn5t618_restart; + rn5t618_restart_handler.priority = 192; + + ret = register_restart_handler(&rn5t618_restart_handler); + if (ret) { + dev_err(&i2c->dev, "cannot register restart handler, %d\n", ret); + return ret; } return 0; @@ -105,12 +157,6 @@ static int rn5t618_i2c_remove(struct i2c_client *i2c) return 0; } -static const struct of_device_id rn5t618_of_match[] = { - { .compatible = "ricoh,rn5t618" }, - { } -}; -MODULE_DEVICE_TABLE(of, rn5t618_of_match); - static const struct i2c_device_id rn5t618_i2c_id[] = { { } }; @@ -129,5 +175,5 @@ static struct i2c_driver rn5t618_i2c_driver = { module_i2c_driver(rn5t618_i2c_driver); MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>"); -MODULE_DESCRIPTION("Ricoh RN5T618 MFD driver"); +MODULE_DESCRIPTION("Ricoh RN5T567/618 MFD driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 144cbf5b3e5a..6c88e31c01f7 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -498,6 +498,15 @@ config REGULATOR_MT6311 This driver supports the control of different power rails of device through regulator interface. +config REGULATOR_MT6323 + tristate "MediaTek MT6323 PMIC" + depends on MFD_MT6397 + help + Say y here to select this option to enable the power regulator of + MediaTek MT6323 PMIC. + This driver supports the control of different power rails of device + through regulator interface. + config REGULATOR_MT6397 tristate "MediaTek MT6397 PMIC" depends on MFD_MT6397 @@ -543,12 +552,12 @@ config REGULATOR_PCF50633 on PCF50633 config REGULATOR_PFUZE100 - tristate "Freescale PFUZE100/PFUZE200 regulator driver" + tristate "Freescale PFUZE100/200/3000 regulator driver" depends on I2C select REGMAP_I2C help Say y here to support the regulators found on the Freescale - PFUZE100/PFUZE200 PMIC. + PFUZE100/200/3000 PMIC. config REGULATOR_PV88060 tristate "Powerventure Semiconductor PV88060 regulator" @@ -636,10 +645,11 @@ config REGULATOR_RK808 outputs which can be controlled by i2c communication. config REGULATOR_RN5T618 - tristate "Ricoh RN5T618 voltage regulators" + tristate "Ricoh RN5T567/618 voltage regulators" depends on MFD_RN5T618 help - Say y here to support the regulators found on Ricoh RN5T618 PMIC. + Say y here to support the regulators found on Ricoh RN5T567 or + RN5T618 PMIC. config REGULATOR_RT5033 tristate "Richtek RT5033 Regulators" diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 85a1d44a3939..f3da9eea9ab6 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o +obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index a1cd0d4f8257..7652477e6a9d 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -395,12 +395,6 @@ static int act8865_pdata_from_dt(struct device *dev, struct act8865_regulator_data *regulator; struct of_regulator_match *matches; - np = of_get_child_by_name(dev->of_node, "regulators"); - if (!np) { - dev_err(dev, "missing 'regulators' subnode in DT\n"); - return -EINVAL; - } - switch (type) { case ACT8600: matches = act8600_matches; @@ -419,6 +413,12 @@ static int act8865_pdata_from_dt(struct device *dev, return -EINVAL; } + np = of_get_child_by_name(dev->of_node, "regulators"); + if (!np) { + dev_err(dev, "missing 'regulators' subnode in DT\n"); + return -EINVAL; + } + matched = of_regulator_match(dev, np, matches, num_matches); of_node_put(np); if (matched <= 0) diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index 514a5e8fdbab..6d9ac76a772f 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -36,6 +36,8 @@ #define AXP20X_FREQ_DCDC_MASK 0x0f +#define AXP22X_MISC_N_VBUSEN_FUNC BIT(4) + #define AXP_DESC_IO(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ _vmask, _ereg, _emask, _enable_val, _disable_val) \ [_family##_##_id] = { \ @@ -230,6 +232,73 @@ static const struct regulator_desc axp22x_regulators[] = { AXP_DESC_FIXED(AXP22X, RTC_LDO, "rtc_ldo", "ips", 3000), }; +static const struct regulator_desc axp22x_drivevbus_regulator = { + .name = "drivevbus", + .supply_name = "drivevbus", + .of_match = of_match_ptr("drivevbus"), + .regulators_node = of_match_ptr("regulators"), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = AXP20X_VBUS_IPSOUT_MGMT, + .enable_mask = BIT(2), + .ops = &axp20x_ops_sw, +}; + +static const struct regulator_linear_range axp809_dcdc4_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2f, 20000), + REGULATOR_LINEAR_RANGE(1800000, 0x30, 0x38, 100000), +}; + +static const struct regulator_linear_range axp809_dldo1_ranges[] = { + REGULATOR_LINEAR_RANGE(700000, 0x0, 0x1a, 100000), + REGULATOR_LINEAR_RANGE(3400000, 0x1b, 0x1f, 200000), +}; + +static const struct regulator_desc axp809_regulators[] = { + AXP_DESC(AXP809, DCDC1, "dcdc1", "vin1", 1600, 3400, 100, + AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(1)), + AXP_DESC(AXP809, DCDC2, "dcdc2", "vin2", 600, 1540, 20, + AXP22X_DCDC2_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(2)), + AXP_DESC(AXP809, DCDC3, "dcdc3", "vin3", 600, 1860, 20, + AXP22X_DCDC3_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(3)), + AXP_DESC_RANGES(AXP809, DCDC4, "dcdc4", "vin4", axp809_dcdc4_ranges, + 57, AXP22X_DCDC4_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, + BIT(4)), + AXP_DESC(AXP809, DCDC5, "dcdc5", "vin5", 1000, 2550, 50, + AXP22X_DCDC5_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(5)), + /* secondary switchable output of DCDC1 */ + AXP_DESC_SW(AXP809, DC1SW, "dc1sw", NULL, AXP22X_PWR_OUT_CTRL2, + BIT(7)), + /* LDO regulator internally chained to DCDC5 */ + AXP_DESC(AXP809, DC5LDO, "dc5ldo", NULL, 700, 1400, 100, + AXP22X_DC5LDO_V_OUT, 0x7, AXP22X_PWR_OUT_CTRL1, BIT(0)), + AXP_DESC(AXP809, ALDO1, "aldo1", "aldoin", 700, 3300, 100, + AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(6)), + AXP_DESC(AXP809, ALDO2, "aldo2", "aldoin", 700, 3300, 100, + AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(7)), + AXP_DESC(AXP809, ALDO3, "aldo3", "aldoin", 700, 3300, 100, + AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)), + AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", axp809_dldo1_ranges, + 32, AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, + BIT(3)), + AXP_DESC(AXP809, DLDO2, "dldo2", "dldoin", 700, 3300, 100, + AXP22X_DLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(4)), + AXP_DESC(AXP809, ELDO1, "eldo1", "eldoin", 700, 3300, 100, + AXP22X_ELDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(0)), + AXP_DESC(AXP809, ELDO2, "eldo2", "eldoin", 700, 3300, 100, + AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)), + AXP_DESC(AXP809, ELDO3, "eldo3", "eldoin", 700, 3300, 100, + AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)), + AXP_DESC_IO(AXP809, LDO_IO0, "ldo_io0", "ips", 700, 3300, 100, + AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07, + AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), + AXP_DESC_IO(AXP809, LDO_IO1, "ldo_io1", "ips", 700, 3300, 100, + AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07, + AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), + AXP_DESC_FIXED(AXP809, RTC_LDO, "rtc_ldo", "ips", 1800), + AXP_DESC_SW(AXP809, SW, "sw", "swin", AXP22X_PWR_OUT_CTRL2, BIT(6)), +}; + static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) { struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); @@ -245,6 +314,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) break; case AXP221_ID: case AXP223_ID: + case AXP809_ID: min = 1800; max = 4050; def = 3000; @@ -324,6 +394,7 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work case AXP221_ID: case AXP223_ID: + case AXP809_ID: if (id < AXP22X_DCDC1 || id > AXP22X_DCDC5) return -EINVAL; @@ -352,8 +423,9 @@ static int axp20x_regulator_probe(struct platform_device *pdev) }; int ret, i, nregulators; u32 workmode; - const char *axp22x_dc1_name = axp22x_regulators[AXP22X_DCDC1].name; - const char *axp22x_dc5_name = axp22x_regulators[AXP22X_DCDC5].name; + const char *dcdc1_name = axp22x_regulators[AXP22X_DCDC1].name; + const char *dcdc5_name = axp22x_regulators[AXP22X_DCDC5].name; + bool drivevbus = false; switch (axp20x->variant) { case AXP202_ID: @@ -365,6 +437,12 @@ static int axp20x_regulator_probe(struct platform_device *pdev) case AXP223_ID: regulators = axp22x_regulators; nregulators = AXP22X_REG_ID_MAX; + drivevbus = of_property_read_bool(pdev->dev.parent->of_node, + "x-powers,drive-vbus-en"); + break; + case AXP809_ID: + regulators = axp809_regulators; + nregulators = AXP809_REG_ID_MAX; break; default: dev_err(&pdev->dev, "Unsupported AXP variant: %ld\n", @@ -388,22 +466,22 @@ static int axp20x_regulator_probe(struct platform_device *pdev) * part of this loop to see where we save the DT defined * name. */ - if (regulators == axp22x_regulators) { - if (i == AXP22X_DC1SW) { - new_desc = devm_kzalloc(&pdev->dev, - sizeof(*desc), - GFP_KERNEL); - *new_desc = regulators[i]; - new_desc->supply_name = axp22x_dc1_name; - desc = new_desc; - } else if (i == AXP22X_DC5LDO) { - new_desc = devm_kzalloc(&pdev->dev, - sizeof(*desc), - GFP_KERNEL); - *new_desc = regulators[i]; - new_desc->supply_name = axp22x_dc5_name; - desc = new_desc; - } + if ((regulators == axp22x_regulators && i == AXP22X_DC1SW) || + (regulators == axp809_regulators && i == AXP809_DC1SW)) { + new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc), + GFP_KERNEL); + *new_desc = regulators[i]; + new_desc->supply_name = dcdc1_name; + desc = new_desc; + } + + if ((regulators == axp22x_regulators && i == AXP22X_DC5LDO) || + (regulators == axp809_regulators && i == AXP809_DC5LDO)) { + new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc), + GFP_KERNEL); + *new_desc = regulators[i]; + new_desc->supply_name = dcdc5_name; + desc = new_desc; } rdev = devm_regulator_register(&pdev->dev, desc, &config); @@ -426,16 +504,29 @@ static int axp20x_regulator_probe(struct platform_device *pdev) /* * Save AXP22X DCDC1 / DCDC5 regulator names for later. */ - if (regulators == axp22x_regulators) { - /* Can we use rdev->constraints->name instead? */ - if (i == AXP22X_DCDC1) - of_property_read_string(rdev->dev.of_node, - "regulator-name", - &axp22x_dc1_name); - else if (i == AXP22X_DCDC5) - of_property_read_string(rdev->dev.of_node, - "regulator-name", - &axp22x_dc5_name); + if ((regulators == axp22x_regulators && i == AXP22X_DCDC1) || + (regulators == axp809_regulators && i == AXP809_DCDC1)) + of_property_read_string(rdev->dev.of_node, + "regulator-name", + &dcdc1_name); + + if ((regulators == axp22x_regulators && i == AXP22X_DCDC5) || + (regulators == axp809_regulators && i == AXP809_DCDC5)) + of_property_read_string(rdev->dev.of_node, + "regulator-name", + &dcdc5_name); + } + + if (drivevbus) { + /* Change N_VBUSEN sense pin to DRIVEVBUS output pin */ + regmap_update_bits(axp20x->regmap, AXP20X_OVER_TMP, + AXP22X_MISC_N_VBUSEN_FUNC, 0); + rdev = devm_regulator_register(&pdev->dev, + &axp22x_drivevbus_regulator, + &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "Failed to register drivevbus\n"); + return PTR_ERR(rdev); } } diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index ec8184d53f13..db320e8fa865 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2509,33 +2509,6 @@ int regulator_is_enabled(struct regulator *regulator) EXPORT_SYMBOL_GPL(regulator_is_enabled); /** - * regulator_can_change_voltage - check if regulator can change voltage - * @regulator: regulator source - * - * Returns positive if the regulator driver backing the source/client - * can change its voltage, false otherwise. Useful for detecting fixed - * or dummy regulators and disabling voltage change logic in the client - * driver. - */ -int regulator_can_change_voltage(struct regulator *regulator) -{ - struct regulator_dev *rdev = regulator->rdev; - - if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { - if (rdev->desc->n_voltages - rdev->desc->linear_min_sel > 1) - return 1; - - if (rdev->desc->continuous_voltage_range && - rdev->constraints->min_uV && rdev->constraints->max_uV && - rdev->constraints->min_uV != rdev->constraints->max_uV) - return 1; - } - - return 0; -} -EXPORT_SYMBOL_GPL(regulator_can_change_voltage); - -/** * regulator_count_voltages - count regulator_list_voltage() selectors * @regulator: regulator source * diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index 1050cb77561a..9ececfef42d6 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -333,7 +333,7 @@ static const struct regulator_ops da9052_ldo_ops = { static struct da9052_regulator_info da9052_regulator_info[] = { DA9052_DCDC(BUCK1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), DA9052_DCDC(BUCK2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), - DA9052_DCDC(BUCK3, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO), + DA9052_DCDC(BUCK3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO), DA9052_DCDC(BUCK4, 50, 1800, 3600, 5, 6, 0), DA9052_LDO(LDO1, 50, 600, 1800, 5, 6, 0), DA9052_LDO(LDO2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), @@ -350,8 +350,8 @@ static struct da9052_regulator_info da9052_regulator_info[] = { static struct da9052_regulator_info da9053_regulator_info[] = { DA9052_DCDC(BUCK1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), DA9052_DCDC(BUCK2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), - DA9052_DCDC(BUCK3, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO), - DA9052_DCDC(BUCK4, 25, 925, 2500, 6, 6, 0), + DA9052_DCDC(BUCK3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO), + DA9052_DCDC(BUCK4, 25, 950, 2525, 6, 6, 0), DA9052_LDO(LDO1, 50, 600, 1800, 5, 6, 0), DA9052_LDO(LDO2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), DA9052_LDO(LDO3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index 01c0e3709b66..d0496d6b0934 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -21,12 +21,11 @@ #include <linux/err.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/slab.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/of_device.h> #include <linux/regulator/of_regulator.h> #include <linux/regmap.h> @@ -179,6 +178,13 @@ error_i2c: /* * I2C driver interface functions */ + +static const struct of_device_id da9210_dt_ids[] = { + { .compatible = "dlg,da9210", }, + { } +}; +MODULE_DEVICE_TABLE(of, da9210_dt_ids); + static int da9210_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -188,6 +194,16 @@ static int da9210_i2c_probe(struct i2c_client *i2c, struct regulator_dev *rdev = NULL; struct regulator_config config = { }; int error; + const struct of_device_id *match; + + if (i2c->dev.of_node && !pdata) { + match = of_match_device(of_match_ptr(da9210_dt_ids), + &i2c->dev); + if (!match) { + dev_err(&i2c->dev, "Error: No device match found\n"); + return -ENODEV; + } + } chip = devm_kzalloc(&i2c->dev, sizeof(struct da9210), GFP_KERNEL); if (!chip) @@ -264,6 +280,7 @@ MODULE_DEVICE_TABLE(i2c, da9210_i2c_id); static struct i2c_driver da9210_regulator_driver = { .driver = { .name = "da9210", + .of_match_table = of_match_ptr(da9210_dt_ids), }, .probe = da9210_i2c_probe, .id_table = da9210_i2c_id, diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index 236abf473db5..aa47280efd32 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -1,5 +1,6 @@ /* - * da9211-regulator.c - Regulator device driver for DA9211/DA9213/DA9215 + * da9211-regulator.c - Regulator device driver for DA9211/DA9212 + * /DA9213/DA9214/DA9215 * Copyright (C) 2015 Dialog Semiconductor Ltd. * * This library is free software; you can redistribute it and/or @@ -493,7 +494,9 @@ static int da9211_i2c_probe(struct i2c_client *i2c, static const struct i2c_device_id da9211_i2c_id[] = { {"da9211", DA9211}, + {"da9212", DA9212}, {"da9213", DA9213}, + {"da9214", DA9214}, {"da9215", DA9215}, {}, }; @@ -502,8 +505,10 @@ MODULE_DEVICE_TABLE(i2c, da9211_i2c_id); #ifdef CONFIG_OF static const struct of_device_id da9211_dt_ids[] = { { .compatible = "dlg,da9211", .data = &da9211_i2c_id[0] }, - { .compatible = "dlg,da9213", .data = &da9211_i2c_id[1] }, - { .compatible = "dlg,da9215", .data = &da9211_i2c_id[2] }, + { .compatible = "dlg,da9212", .data = &da9211_i2c_id[1] }, + { .compatible = "dlg,da9213", .data = &da9211_i2c_id[2] }, + { .compatible = "dlg,da9214", .data = &da9211_i2c_id[3] }, + { .compatible = "dlg,da9215", .data = &da9211_i2c_id[4] }, {}, }; MODULE_DEVICE_TABLE(of, da9211_dt_ids); @@ -521,5 +526,5 @@ static struct i2c_driver da9211_regulator_driver = { module_i2c_driver(da9211_regulator_driver); MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>"); -MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211/DA9213/DA9215"); +MODULE_DESCRIPTION("DA9211/DA9212/DA9213/DA9214/DA9215 regulator driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/da9211-regulator.h b/drivers/regulator/da9211-regulator.h index d6ad96fc64d3..b841bbf330cc 100644 --- a/drivers/regulator/da9211-regulator.h +++ b/drivers/regulator/da9211-regulator.h @@ -1,5 +1,6 @@ /* - * da9211-regulator.h - Regulator definitions for DA9211/DA9213/DA9215 + * da9211-regulator.h - Regulator definitions for DA9211/DA9212 + * /DA9213/DA9214/DA9215 * Copyright (C) 2015 Dialog Semiconductor Ltd. * * This program is free software; you can redistribute it and/or diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index ff62d69ba0be..988a7472c2ab 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -79,18 +79,8 @@ of_get_fixed_voltage_config(struct device *dev, config->enabled_at_boot = true; config->gpio = of_get_named_gpio(np, "gpio", 0); - /* - * of_get_named_gpio() currently returns ENODEV rather than - * EPROBE_DEFER. This code attempts to be compatible with both - * for now; the ENODEV check can be removed once the API is fixed. - * of_get_named_gpio() doesn't differentiate between a missing - * property (which would be fine here, since the GPIO is optional) - * and some other error. Patches have been posted for both issues. - * Once they are check in, we should replace this with: - * if (config->gpio < 0 && config->gpio != -ENOENT) - */ - if ((config->gpio == -ENODEV) || (config->gpio == -EPROBE_DEFER)) - return ERR_PTR(-EPROBE_DEFER); + if ((config->gpio < 0) && (config->gpio != -ENOENT)) + return ERR_PTR(config->gpio); of_property_read_u32(np, "startup-delay-us", &config->startup_delay); diff --git a/drivers/regulator/lp873x-regulator.c b/drivers/regulator/lp873x-regulator.c index b4ffd113ba21..e504b9148226 100644 --- a/drivers/regulator/lp873x-regulator.c +++ b/drivers/regulator/lp873x-regulator.c @@ -20,7 +20,7 @@ #include <linux/mfd/lp873x.h> #define LP873X_REGULATOR(_name, _id, _of, _ops, _n, _vr, _vm, _er, _em, \ - _delay, _lr, _nlr, _cr) \ + _delay, _lr, _cr) \ [_id] = { \ .desc = { \ .name = _name, \ @@ -37,7 +37,7 @@ .enable_mask = _em, \ .ramp_delay = _delay, \ .linear_ranges = _lr, \ - .n_linear_ranges = _nlr, \ + .n_linear_ranges = ARRAY_SIZE(_lr), \ }, \ .ctrl2_reg = _cr, \ } @@ -175,22 +175,20 @@ static const struct lp873x_regulator regulators[] = { 256, LP873X_REG_BUCK0_VOUT, LP873X_BUCK0_VOUT_BUCK0_VSET, LP873X_REG_BUCK0_CTRL_1, LP873X_BUCK0_CTRL_1_BUCK0_EN, 10000, - buck0_buck1_ranges, 4, LP873X_REG_BUCK0_CTRL_2), + buck0_buck1_ranges, LP873X_REG_BUCK0_CTRL_2), LP873X_REGULATOR("BUCK1", LP873X_BUCK_1, "buck1", lp873x_buck01_ops, 256, LP873X_REG_BUCK1_VOUT, LP873X_BUCK1_VOUT_BUCK1_VSET, LP873X_REG_BUCK1_CTRL_1, LP873X_BUCK1_CTRL_1_BUCK1_EN, 10000, - buck0_buck1_ranges, 4, LP873X_REG_BUCK1_CTRL_2), + buck0_buck1_ranges, LP873X_REG_BUCK1_CTRL_2), LP873X_REGULATOR("LDO0", LP873X_LDO_0, "ldo0", lp873x_ldo01_ops, 26, LP873X_REG_LDO0_VOUT, LP873X_LDO0_VOUT_LDO0_VSET, LP873X_REG_LDO0_CTRL, - LP873X_LDO0_CTRL_LDO0_EN, 0, ldo0_ldo1_ranges, 1, - 0xFF), + LP873X_LDO0_CTRL_LDO0_EN, 0, ldo0_ldo1_ranges, 0xFF), LP873X_REGULATOR("LDO1", LP873X_LDO_1, "ldo1", lp873x_ldo01_ops, 26, LP873X_REG_LDO1_VOUT, LP873X_LDO1_VOUT_LDO1_VSET, LP873X_REG_LDO1_CTRL, - LP873X_LDO1_CTRL_LDO1_EN, 0, ldo0_ldo1_ranges, 1, - 0xFF), + LP873X_LDO1_CTRL_LDO1_EN, 0, ldo0_ldo1_ranges, 0xFF), }; static int lp873x_regulator_probe(struct platform_device *pdev) diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 08d2f13eca00..3958f50c5975 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -271,22 +271,18 @@ static int max8973_set_ramp_delay(struct regulator_dev *rdev, struct max8973_chip *max = rdev_get_drvdata(rdev); unsigned int control; int ret; - int ret_val; /* Set ramp delay */ - if (ramp_delay < 25000) { + if (ramp_delay <= 12000) control = MAX8973_RAMP_12mV_PER_US; - ret_val = 12000; - } else if (ramp_delay < 50000) { + else if (ramp_delay <= 25000) control = MAX8973_RAMP_25mV_PER_US; - ret_val = 25000; - } else if (ramp_delay < 200000) { + else if (ramp_delay <= 50000) control = MAX8973_RAMP_50mV_PER_US; - ret_val = 50000; - } else { + else if (ramp_delay <= 200000) control = MAX8973_RAMP_200mV_PER_US; - ret_val = 200000; - } + else + return -EINVAL; ret = regmap_update_bits(max->regmap, MAX8973_CONTROL1, MAX8973_RAMP_MASK, control); diff --git a/drivers/regulator/mt6323-regulator.c b/drivers/regulator/mt6323-regulator.c new file mode 100644 index 000000000000..b7b9670f0979 --- /dev/null +++ b/drivers/regulator/mt6323-regulator.c @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: Chen Zhong <chen.zhong@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/mfd/mt6397/core.h> +#include <linux/mfd/mt6323/registers.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/mt6323-regulator.h> +#include <linux/regulator/of_regulator.h> + +#define MT6323_LDO_MODE_NORMAL 0 +#define MT6323_LDO_MODE_LP 1 + +/* + * MT6323 regulators' information + * + * @desc: standard fields of regulator description. + * @qi: Mask for query enable signal status of regulators + * @vselon_reg: Register sections for hardware control mode of bucks + * @vselctrl_reg: Register for controlling the buck control mode. + * @vselctrl_mask: Mask for query buck's voltage control mode. + */ +struct mt6323_regulator_info { + struct regulator_desc desc; + u32 qi; + u32 vselon_reg; + u32 vselctrl_reg; + u32 vselctrl_mask; + u32 modeset_reg; + u32 modeset_mask; +}; + +#define MT6323_BUCK(match, vreg, min, max, step, volt_ranges, enreg, \ + vosel, vosel_mask, voselon, vosel_ctrl) \ +[MT6323_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6323_volt_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6323_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = (max - min)/step + 1, \ + .linear_ranges = volt_ranges, \ + .n_linear_ranges = ARRAY_SIZE(volt_ranges), \ + .vsel_reg = vosel, \ + .vsel_mask = vosel_mask, \ + .enable_reg = enreg, \ + .enable_mask = BIT(0), \ + }, \ + .qi = BIT(13), \ + .vselon_reg = voselon, \ + .vselctrl_reg = vosel_ctrl, \ + .vselctrl_mask = BIT(1), \ +} + +#define MT6323_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel, \ + vosel_mask, _modeset_reg, _modeset_mask) \ +[MT6323_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6323_volt_table_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6323_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(ldo_volt_table), \ + .volt_table = ldo_volt_table, \ + .vsel_reg = vosel, \ + .vsel_mask = vosel_mask, \ + .enable_reg = enreg, \ + .enable_mask = BIT(enbit), \ + }, \ + .qi = BIT(15), \ + .modeset_reg = _modeset_reg, \ + .modeset_mask = _modeset_mask, \ +} + +#define MT6323_REG_FIXED(match, vreg, enreg, enbit, volt, \ + _modeset_reg, _modeset_mask) \ +[MT6323_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6323_volt_fixed_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6323_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = 1, \ + .enable_reg = enreg, \ + .enable_mask = BIT(enbit), \ + .min_uV = volt, \ + }, \ + .qi = BIT(15), \ + .modeset_reg = _modeset_reg, \ + .modeset_mask = _modeset_mask, \ +} + +static const struct regulator_linear_range buck_volt_range1[] = { + REGULATOR_LINEAR_RANGE(700000, 0, 0x7f, 6250), +}; + +static const struct regulator_linear_range buck_volt_range2[] = { + REGULATOR_LINEAR_RANGE(1400000, 0, 0x7f, 12500), +}; + +static const struct regulator_linear_range buck_volt_range3[] = { + REGULATOR_LINEAR_RANGE(500000, 0, 0x3f, 50000), +}; + +static const u32 ldo_volt_table1[] = { + 3300000, 3400000, 3500000, 3600000, +}; + +static const u32 ldo_volt_table2[] = { + 1500000, 1800000, 2500000, 2800000, +}; + +static const u32 ldo_volt_table3[] = { + 1800000, 3300000, +}; + +static const u32 ldo_volt_table4[] = { + 3000000, 3300000, +}; + +static const u32 ldo_volt_table5[] = { + 1200000, 1300000, 1500000, 1800000, 2000000, 2800000, 3000000, 3300000, +}; + +static const u32 ldo_volt_table6[] = { + 1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 2000000, +}; + +static const u32 ldo_volt_table7[] = { + 1200000, 1300000, 1500000, 1800000, +}; + +static const u32 ldo_volt_table8[] = { + 1800000, 3000000, +}; + +static const u32 ldo_volt_table9[] = { + 1200000, 1350000, 1500000, 1800000, +}; + +static const u32 ldo_volt_table10[] = { + 1200000, 1300000, 1500000, 1800000, +}; + +static int mt6323_get_status(struct regulator_dev *rdev) +{ + int ret; + u32 regval; + struct mt6323_regulator_info *info = rdev_get_drvdata(rdev); + + ret = regmap_read(rdev->regmap, info->desc.enable_reg, ®val); + if (ret != 0) { + dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret); + return ret; + } + + return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF; +} + +static int mt6323_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + int ret, val = 0; + struct mt6323_regulator_info *info = rdev_get_drvdata(rdev); + + if (!info->modeset_mask) { + dev_err(&rdev->dev, "regulator %s doesn't support set_mode\n", + info->desc.name); + return -EINVAL; + } + + switch (mode) { + case REGULATOR_MODE_STANDBY: + val = MT6323_LDO_MODE_LP; + break; + case REGULATOR_MODE_NORMAL: + val = MT6323_LDO_MODE_NORMAL; + break; + default: + return -EINVAL; + } + + val <<= ffs(info->modeset_mask) - 1; + + ret = regmap_update_bits(rdev->regmap, info->modeset_reg, + info->modeset_mask, val); + + return ret; +} + +static unsigned int mt6323_ldo_get_mode(struct regulator_dev *rdev) +{ + unsigned int val; + unsigned int mode; + int ret; + struct mt6323_regulator_info *info = rdev_get_drvdata(rdev); + + if (!info->modeset_mask) { + dev_err(&rdev->dev, "regulator %s doesn't support get_mode\n", + info->desc.name); + return -EINVAL; + } + + ret = regmap_read(rdev->regmap, info->modeset_reg, &val); + if (ret < 0) + return ret; + + val &= info->modeset_mask; + val >>= ffs(info->modeset_mask) - 1; + + if (val & 0x1) + mode = REGULATOR_MODE_STANDBY; + else + mode = REGULATOR_MODE_NORMAL; + + return mode; +} + +static const struct regulator_ops mt6323_volt_range_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6323_get_status, +}; + +static const struct regulator_ops mt6323_volt_table_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6323_get_status, + .set_mode = mt6323_ldo_set_mode, + .get_mode = mt6323_ldo_get_mode, +}; + +static const struct regulator_ops mt6323_volt_fixed_ops = { + .list_voltage = regulator_list_voltage_linear, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6323_get_status, + .set_mode = mt6323_ldo_set_mode, + .get_mode = mt6323_ldo_get_mode, +}; + +/* The array is indexed by id(MT6323_ID_XXX) */ +static struct mt6323_regulator_info mt6323_regulators[] = { + MT6323_BUCK("buck_vproc", VPROC, 700000, 1493750, 6250, + buck_volt_range1, MT6323_VPROC_CON7, MT6323_VPROC_CON9, 0x7f, + MT6323_VPROC_CON10, MT6323_VPROC_CON5), + MT6323_BUCK("buck_vsys", VSYS, 1400000, 2987500, 12500, + buck_volt_range2, MT6323_VSYS_CON7, MT6323_VSYS_CON9, 0x7f, + MT6323_VSYS_CON10, MT6323_VSYS_CON5), + MT6323_BUCK("buck_vpa", VPA, 500000, 3650000, 50000, + buck_volt_range3, MT6323_VPA_CON7, MT6323_VPA_CON9, + 0x3f, MT6323_VPA_CON10, MT6323_VPA_CON5), + MT6323_REG_FIXED("ldo_vtcxo", VTCXO, MT6323_ANALDO_CON1, 10, 2800000, + MT6323_ANALDO_CON1, 0x2), + MT6323_REG_FIXED("ldo_vcn28", VCN28, MT6323_ANALDO_CON19, 12, 2800000, + MT6323_ANALDO_CON20, 0x2), + MT6323_LDO("ldo_vcn33_bt", VCN33_BT, ldo_volt_table1, + MT6323_ANALDO_CON16, 7, MT6323_ANALDO_CON16, 0xC, + MT6323_ANALDO_CON21, 0x2), + MT6323_LDO("ldo_vcn33_wifi", VCN33_WIFI, ldo_volt_table1, + MT6323_ANALDO_CON17, 12, MT6323_ANALDO_CON16, 0xC, + MT6323_ANALDO_CON21, 0x2), + MT6323_REG_FIXED("ldo_va", VA, MT6323_ANALDO_CON2, 14, 2800000, + MT6323_ANALDO_CON2, 0x2), + MT6323_LDO("ldo_vcama", VCAMA, ldo_volt_table2, + MT6323_ANALDO_CON4, 15, MT6323_ANALDO_CON10, 0x60, -1, 0), + MT6323_REG_FIXED("ldo_vio28", VIO28, MT6323_DIGLDO_CON0, 14, 2800000, + MT6323_DIGLDO_CON0, 0x2), + MT6323_REG_FIXED("ldo_vusb", VUSB, MT6323_DIGLDO_CON2, 14, 3300000, + MT6323_DIGLDO_CON2, 0x2), + MT6323_LDO("ldo_vmc", VMC, ldo_volt_table3, + MT6323_DIGLDO_CON3, 12, MT6323_DIGLDO_CON24, 0x10, + MT6323_DIGLDO_CON3, 0x2), + MT6323_LDO("ldo_vmch", VMCH, ldo_volt_table4, + MT6323_DIGLDO_CON5, 14, MT6323_DIGLDO_CON26, 0x80, + MT6323_DIGLDO_CON5, 0x2), + MT6323_LDO("ldo_vemc3v3", VEMC3V3, ldo_volt_table4, + MT6323_DIGLDO_CON6, 14, MT6323_DIGLDO_CON27, 0x80, + MT6323_DIGLDO_CON6, 0x2), + MT6323_LDO("ldo_vgp1", VGP1, ldo_volt_table5, + MT6323_DIGLDO_CON7, 15, MT6323_DIGLDO_CON28, 0xE0, + MT6323_DIGLDO_CON7, 0x2), + MT6323_LDO("ldo_vgp2", VGP2, ldo_volt_table6, + MT6323_DIGLDO_CON8, 15, MT6323_DIGLDO_CON29, 0xE0, + MT6323_DIGLDO_CON8, 0x2), + MT6323_LDO("ldo_vgp3", VGP3, ldo_volt_table7, + MT6323_DIGLDO_CON9, 15, MT6323_DIGLDO_CON30, 0x60, + MT6323_DIGLDO_CON9, 0x2), + MT6323_REG_FIXED("ldo_vcn18", VCN18, MT6323_DIGLDO_CON11, 14, 1800000, + MT6323_DIGLDO_CON11, 0x2), + MT6323_LDO("ldo_vsim1", VSIM1, ldo_volt_table8, + MT6323_DIGLDO_CON13, 15, MT6323_DIGLDO_CON34, 0x20, + MT6323_DIGLDO_CON13, 0x2), + MT6323_LDO("ldo_vsim2", VSIM2, ldo_volt_table8, + MT6323_DIGLDO_CON14, 15, MT6323_DIGLDO_CON35, 0x20, + MT6323_DIGLDO_CON14, 0x2), + MT6323_REG_FIXED("ldo_vrtc", VRTC, MT6323_DIGLDO_CON15, 8, 2800000, + -1, 0), + MT6323_LDO("ldo_vcamaf", VCAMAF, ldo_volt_table5, + MT6323_DIGLDO_CON31, 15, MT6323_DIGLDO_CON32, 0xE0, + MT6323_DIGLDO_CON31, 0x2), + MT6323_LDO("ldo_vibr", VIBR, ldo_volt_table5, + MT6323_DIGLDO_CON39, 15, MT6323_DIGLDO_CON40, 0xE0, + MT6323_DIGLDO_CON39, 0x2), + MT6323_REG_FIXED("ldo_vrf18", VRF18, MT6323_DIGLDO_CON45, 15, 1825000, + MT6323_DIGLDO_CON45, 0x2), + MT6323_LDO("ldo_vm", VM, ldo_volt_table9, + MT6323_DIGLDO_CON47, 14, MT6323_DIGLDO_CON48, 0x30, + MT6323_DIGLDO_CON47, 0x2), + MT6323_REG_FIXED("ldo_vio18", VIO18, MT6323_DIGLDO_CON49, 14, 1800000, + MT6323_DIGLDO_CON49, 0x2), + MT6323_LDO("ldo_vcamd", VCAMD, ldo_volt_table10, + MT6323_DIGLDO_CON51, 14, MT6323_DIGLDO_CON52, 0x60, + MT6323_DIGLDO_CON51, 0x2), + MT6323_REG_FIXED("ldo_vcamio", VCAMIO, MT6323_DIGLDO_CON53, 14, 1800000, + MT6323_DIGLDO_CON53, 0x2), +}; + +static int mt6323_set_buck_vosel_reg(struct platform_device *pdev) +{ + struct mt6397_chip *mt6323 = dev_get_drvdata(pdev->dev.parent); + int i; + u32 regval; + + for (i = 0; i < MT6323_MAX_REGULATOR; i++) { + if (mt6323_regulators[i].vselctrl_reg) { + if (regmap_read(mt6323->regmap, + mt6323_regulators[i].vselctrl_reg, + ®val) < 0) { + dev_err(&pdev->dev, + "Failed to read buck ctrl\n"); + return -EIO; + } + + if (regval & mt6323_regulators[i].vselctrl_mask) { + mt6323_regulators[i].desc.vsel_reg = + mt6323_regulators[i].vselon_reg; + } + } + } + + return 0; +} + +static int mt6323_regulator_probe(struct platform_device *pdev) +{ + struct mt6397_chip *mt6323 = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = {}; + struct regulator_dev *rdev; + int i; + u32 reg_value; + + /* Query buck controller to select activated voltage register part */ + if (mt6323_set_buck_vosel_reg(pdev)) + return -EIO; + + /* Read PMIC chip revision to update constraints and voltage table */ + if (regmap_read(mt6323->regmap, MT6323_CID, ®_value) < 0) { + dev_err(&pdev->dev, "Failed to read Chip ID\n"); + return -EIO; + } + dev_info(&pdev->dev, "Chip ID = 0x%x\n", reg_value); + + for (i = 0; i < MT6323_MAX_REGULATOR; i++) { + config.dev = &pdev->dev; + config.driver_data = &mt6323_regulators[i]; + config.regmap = mt6323->regmap; + rdev = devm_regulator_register(&pdev->dev, + &mt6323_regulators[i].desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s\n", + mt6323_regulators[i].desc.name); + return PTR_ERR(rdev); + } + } + return 0; +} + +static const struct platform_device_id mt6323_platform_ids[] = { + {"mt6323-regulator", 0}, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(platform, mt6323_platform_ids); + +static struct platform_driver mt6323_regulator_driver = { + .driver = { + .name = "mt6323-regulator", + }, + .probe = mt6323_regulator_probe, + .id_table = mt6323_platform_ids, +}; + +module_platform_driver(mt6323_regulator_driver); + +MODULE_AUTHOR("Chen Zhong <chen.zhong@mediatek.com>"); +MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6323 PMIC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/mt6397-regulator.c b/drivers/regulator/mt6397-regulator.c index 17a5b6c2d6a9..c6c6aa85e4e8 100644 --- a/drivers/regulator/mt6397-regulator.c +++ b/drivers/regulator/mt6397-regulator.c @@ -23,6 +23,9 @@ #include <linux/regulator/mt6397-regulator.h> #include <linux/regulator/of_regulator.h> +#define MT6397_BUCK_MODE_AUTO 0 +#define MT6397_BUCK_MODE_FORCE_PWM 1 + /* * MT6397 regulators' information * @@ -38,10 +41,14 @@ struct mt6397_regulator_info { u32 vselon_reg; u32 vselctrl_reg; u32 vselctrl_mask; + u32 modeset_reg; + u32 modeset_mask; + u32 modeset_shift; }; #define MT6397_BUCK(match, vreg, min, max, step, volt_ranges, enreg, \ - vosel, vosel_mask, voselon, vosel_ctrl) \ + vosel, vosel_mask, voselon, vosel_ctrl, _modeset_reg, \ + _modeset_shift) \ [MT6397_ID_##vreg] = { \ .desc = { \ .name = #vreg, \ @@ -62,6 +69,9 @@ struct mt6397_regulator_info { .vselon_reg = voselon, \ .vselctrl_reg = vosel_ctrl, \ .vselctrl_mask = BIT(1), \ + .modeset_reg = _modeset_reg, \ + .modeset_mask = BIT(_modeset_shift), \ + .modeset_shift = _modeset_shift \ } #define MT6397_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel, \ @@ -145,6 +155,63 @@ static const u32 ldo_volt_table7[] = { 1300000, 1500000, 1800000, 2000000, 2500000, 2800000, 3000000, 3300000, }; +static int mt6397_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct mt6397_regulator_info *info = rdev_get_drvdata(rdev); + int ret, val; + + switch (mode) { + case REGULATOR_MODE_FAST: + val = MT6397_BUCK_MODE_FORCE_PWM; + break; + case REGULATOR_MODE_NORMAL: + val = MT6397_BUCK_MODE_AUTO; + break; + default: + ret = -EINVAL; + goto err_mode; + } + + dev_dbg(&rdev->dev, "mt6397 buck set_mode %#x, %#x, %#x, %#x\n", + info->modeset_reg, info->modeset_mask, + info->modeset_shift, val); + + val <<= info->modeset_shift; + ret = regmap_update_bits(rdev->regmap, info->modeset_reg, + info->modeset_mask, val); +err_mode: + if (ret != 0) { + dev_err(&rdev->dev, + "Failed to set mt6397 buck mode: %d\n", ret); + return ret; + } + + return 0; +} + +static unsigned int mt6397_regulator_get_mode(struct regulator_dev *rdev) +{ + struct mt6397_regulator_info *info = rdev_get_drvdata(rdev); + int ret, regval; + + ret = regmap_read(rdev->regmap, info->modeset_reg, ®val); + if (ret != 0) { + dev_err(&rdev->dev, + "Failed to get mt6397 buck mode: %d\n", ret); + return ret; + } + + switch ((regval & info->modeset_mask) >> info->modeset_shift) { + case MT6397_BUCK_MODE_AUTO: + return REGULATOR_MODE_NORMAL; + case MT6397_BUCK_MODE_FORCE_PWM: + return REGULATOR_MODE_FAST; + default: + return -EINVAL; + } +} + static int mt6397_get_status(struct regulator_dev *rdev) { int ret; @@ -160,7 +227,7 @@ static int mt6397_get_status(struct regulator_dev *rdev) return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF; } -static struct regulator_ops mt6397_volt_range_ops = { +static const struct regulator_ops mt6397_volt_range_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, .set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -170,9 +237,11 @@ static struct regulator_ops mt6397_volt_range_ops = { .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, .get_status = mt6397_get_status, + .set_mode = mt6397_regulator_set_mode, + .get_mode = mt6397_regulator_get_mode, }; -static struct regulator_ops mt6397_volt_table_ops = { +static const struct regulator_ops mt6397_volt_table_ops = { .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_iterate, .set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -184,7 +253,7 @@ static struct regulator_ops mt6397_volt_table_ops = { .get_status = mt6397_get_status, }; -static struct regulator_ops mt6397_volt_fixed_ops = { +static const struct regulator_ops mt6397_volt_fixed_ops = { .list_voltage = regulator_list_voltage_linear, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -196,28 +265,30 @@ static struct regulator_ops mt6397_volt_fixed_ops = { static struct mt6397_regulator_info mt6397_regulators[] = { MT6397_BUCK("buck_vpca15", VPCA15, 700000, 1493750, 6250, buck_volt_range1, MT6397_VCA15_CON7, MT6397_VCA15_CON9, 0x7f, - MT6397_VCA15_CON10, MT6397_VCA15_CON5), + MT6397_VCA15_CON10, MT6397_VCA15_CON5, MT6397_VCA15_CON2, 11), MT6397_BUCK("buck_vpca7", VPCA7, 700000, 1493750, 6250, buck_volt_range1, MT6397_VPCA7_CON7, MT6397_VPCA7_CON9, 0x7f, - MT6397_VPCA7_CON10, MT6397_VPCA7_CON5), + MT6397_VPCA7_CON10, MT6397_VPCA7_CON5, MT6397_VPCA7_CON2, 8), MT6397_BUCK("buck_vsramca15", VSRAMCA15, 700000, 1493750, 6250, buck_volt_range1, MT6397_VSRMCA15_CON7, MT6397_VSRMCA15_CON9, - 0x7f, MT6397_VSRMCA15_CON10, MT6397_VSRMCA15_CON5), + 0x7f, MT6397_VSRMCA15_CON10, MT6397_VSRMCA15_CON5, + MT6397_VSRMCA15_CON2, 8), MT6397_BUCK("buck_vsramca7", VSRAMCA7, 700000, 1493750, 6250, buck_volt_range1, MT6397_VSRMCA7_CON7, MT6397_VSRMCA7_CON9, - 0x7f, MT6397_VSRMCA7_CON10, MT6397_VSRMCA7_CON5), + 0x7f, MT6397_VSRMCA7_CON10, MT6397_VSRMCA7_CON5, + MT6397_VSRMCA7_CON2, 8), MT6397_BUCK("buck_vcore", VCORE, 700000, 1493750, 6250, buck_volt_range1, MT6397_VCORE_CON7, MT6397_VCORE_CON9, 0x7f, - MT6397_VCORE_CON10, MT6397_VCORE_CON5), + MT6397_VCORE_CON10, MT6397_VCORE_CON5, MT6397_VCORE_CON2, 8), MT6397_BUCK("buck_vgpu", VGPU, 700000, 1493750, 6250, buck_volt_range1, MT6397_VGPU_CON7, MT6397_VGPU_CON9, 0x7f, - MT6397_VGPU_CON10, MT6397_VGPU_CON5), + MT6397_VGPU_CON10, MT6397_VGPU_CON5, MT6397_VGPU_CON2, 8), MT6397_BUCK("buck_vdrm", VDRM, 800000, 1593750, 6250, buck_volt_range2, MT6397_VDRM_CON7, MT6397_VDRM_CON9, 0x7f, - MT6397_VDRM_CON10, MT6397_VDRM_CON5), + MT6397_VDRM_CON10, MT6397_VDRM_CON5, MT6397_VDRM_CON2, 8), MT6397_BUCK("buck_vio18", VIO18, 1500000, 2120000, 20000, buck_volt_range3, MT6397_VIO18_CON7, MT6397_VIO18_CON9, 0x1f, - MT6397_VIO18_CON10, MT6397_VIO18_CON5), + MT6397_VIO18_CON10, MT6397_VIO18_CON5, MT6397_VIO18_CON2, 8), MT6397_REG_FIXED("ldo_vtcxo", VTCXO, MT6397_ANALDO_CON0, 10, 2800000), MT6397_REG_FIXED("ldo_va28", VA28, MT6397_ANALDO_CON1, 14, 2800000), MT6397_LDO("ldo_vcama", VCAMA, ldo_volt_table1, diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index cd828dbf9d52..4f613ec99500 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -163,6 +163,9 @@ static void of_get_regulation_constraints(struct device_node *np, "regulator-suspend-microvolt", &pval)) suspend_state->uV = pval; + if (i == PM_SUSPEND_MEM) + constraints->initial_state = PM_SUSPEND_MEM; + of_node_put(suspend_np); suspend_state = NULL; suspend_np = NULL; diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 2a44e5dd9c2a..cb18b5c4f2db 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -70,6 +70,7 @@ struct pfuze_chip { struct device *dev; struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR]; struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR]; + struct pfuze_regulator *pfuze_regulators; }; static const int pfuze100_swbst[] = { @@ -334,8 +335,6 @@ static struct pfuze_regulator pfuze3000_regulators[] = { PFUZE100_VGEN_REG(PFUZE3000, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), }; -static struct pfuze_regulator *pfuze_regulators; - #ifdef CONFIG_OF /* PFUZE100 */ static struct of_regulator_match pfuze100_matches[] = { @@ -563,21 +562,21 @@ static int pfuze100_regulator_probe(struct i2c_client *client, /* use the right regulators after identify the right device */ switch (pfuze_chip->chip_id) { case PFUZE3000: - pfuze_regulators = pfuze3000_regulators; + pfuze_chip->pfuze_regulators = pfuze3000_regulators; regulator_num = ARRAY_SIZE(pfuze3000_regulators); sw_check_start = PFUZE3000_SW2; sw_check_end = PFUZE3000_SW2; sw_hi = 1 << 3; break; case PFUZE200: - pfuze_regulators = pfuze200_regulators; + pfuze_chip->pfuze_regulators = pfuze200_regulators; regulator_num = ARRAY_SIZE(pfuze200_regulators); sw_check_start = PFUZE200_SW2; sw_check_end = PFUZE200_SW3B; break; case PFUZE100: default: - pfuze_regulators = pfuze100_regulators; + pfuze_chip->pfuze_regulators = pfuze100_regulators; regulator_num = ARRAY_SIZE(pfuze100_regulators); sw_check_start = PFUZE100_SW2; sw_check_end = PFUZE100_SW4; @@ -587,7 +586,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client, (pfuze_chip->chip_id == PFUZE100) ? "100" : ((pfuze_chip->chip_id == PFUZE200) ? "200" : "3000")); - memcpy(pfuze_chip->regulator_descs, pfuze_regulators, + memcpy(pfuze_chip->regulator_descs, pfuze_chip->pfuze_regulators, sizeof(pfuze_chip->regulator_descs)); ret = pfuze_parse_regulators_dt(pfuze_chip); @@ -631,7 +630,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client, devm_regulator_register(&client->dev, desc, &config); if (IS_ERR(pfuze_chip->regulators[i])) { dev_err(&client->dev, "register regulator%s failed\n", - pfuze_regulators[i].desc.name); + pfuze_chip->pfuze_regulators[i].desc.name); return PTR_ERR(pfuze_chip->regulators[i]); } } @@ -650,5 +649,5 @@ static struct i2c_driver pfuze_driver = { module_i2c_driver(pfuze_driver); MODULE_AUTHOR("Robin Gong <b38343@freescale.com>"); -MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/PFUZE200 PMIC"); +MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/200/3000 PMIC"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/pv88060-regulator.c b/drivers/regulator/pv88060-regulator.c index c448b727f5f8..6c4afc73ecac 100644 --- a/drivers/regulator/pv88060-regulator.c +++ b/drivers/regulator/pv88060-regulator.c @@ -14,7 +14,6 @@ */ #include <linux/err.h> -#include <linux/gpio.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/init.h> @@ -25,8 +24,6 @@ #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/regulator/of_regulator.h> -#include <linux/proc_fs.h> -#include <linux/uaccess.h> #include "pv88060-regulator.h" #define PV88060_MAX_REGULATORS 14 diff --git a/drivers/regulator/pv88080-regulator.c b/drivers/regulator/pv88080-regulator.c index d7107566c429..81950bdb1cc4 100644 --- a/drivers/regulator/pv88080-regulator.c +++ b/drivers/regulator/pv88080-regulator.c @@ -14,7 +14,6 @@ */ #include <linux/err.h> -#include <linux/gpio.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/init.h> @@ -25,8 +24,6 @@ #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/regulator/of_regulator.h> -#include <linux/proc_fs.h> -#include <linux/uaccess.h> #include "pv88080-regulator.h" #define PV88080_MAX_REGULATORS 3 diff --git a/drivers/regulator/pv88090-regulator.c b/drivers/regulator/pv88090-regulator.c index 0057c6740d6f..421641175352 100644 --- a/drivers/regulator/pv88090-regulator.c +++ b/drivers/regulator/pv88090-regulator.c @@ -14,7 +14,6 @@ */ #include <linux/err.h> -#include <linux/gpio.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/init.h> @@ -25,8 +24,6 @@ #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/regulator/of_regulator.h> -#include <linux/proc_fs.h> -#include <linux/uaccess.h> #include "pv88090-regulator.h" #define PV88090_MAX_REGULATORS 5 diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index fafa3488e960..666bc3bb52ef 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -20,6 +20,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/pwm.h> +#include <linux/gpio/consumer.h> struct pwm_regulator_data { /* Shared */ @@ -38,6 +39,9 @@ struct pwm_regulator_data { /* Continuous voltage */ int volt_uV; + + /* Enable GPIO */ + struct gpio_desc *enb_gpio; }; struct pwm_voltages { @@ -94,6 +98,9 @@ static int pwm_regulator_enable(struct regulator_dev *dev) { struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); + if (drvdata->enb_gpio) + gpiod_set_value_cansleep(drvdata->enb_gpio, 1); + return pwm_enable(drvdata->pwm); } @@ -103,6 +110,9 @@ static int pwm_regulator_disable(struct regulator_dev *dev) pwm_disable(drvdata->pwm); + if (drvdata->enb_gpio) + gpiod_set_value_cansleep(drvdata->enb_gpio, 0); + return 0; } @@ -110,6 +120,9 @@ static int pwm_regulator_is_enabled(struct regulator_dev *dev) { struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev); + if (drvdata->enb_gpio && !gpiod_get_value_cansleep(drvdata->enb_gpio)) + return false; + return pwm_is_enabled(drvdata->pwm); } @@ -132,6 +145,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, unsigned int duty_pulse; u64 req_period; u32 rem; + int old_uV = pwm_regulator_get_voltage(rdev); int ret; pwm_get_args(drvdata->pwm, &pargs); @@ -159,15 +173,14 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, return ret; } - ret = pwm_enable(drvdata->pwm); - if (ret) { - dev_err(&rdev->dev, "Failed to enable PWM: %d\n", ret); - return ret; - } drvdata->volt_uV = min_uV; - /* Delay required by PWM regulator to settle to the new voltage */ - usleep_range(ramp_delay, ramp_delay + 1000); + if ((ramp_delay == 0) || !pwm_regulator_is_enabled(rdev)) + return 0; + + /* Ramp delay is in uV/uS. Adjust to uS and delay */ + ramp_delay = DIV_ROUND_UP(abs(min_uV - old_uV), ramp_delay); + usleep_range(ramp_delay, ramp_delay + DIV_ROUND_UP(ramp_delay, 10)); return 0; } @@ -253,6 +266,7 @@ static int pwm_regulator_probe(struct platform_device *pdev) struct regulator_dev *regulator; struct regulator_config config = { }; struct device_node *np = pdev->dev.of_node; + enum gpiod_flags gpio_flags; int ret; if (!np) { @@ -290,6 +304,18 @@ static int pwm_regulator_probe(struct platform_device *pdev) return ret; } + if (init_data->constraints.boot_on || init_data->constraints.always_on) + gpio_flags = GPIOD_OUT_HIGH; + else + gpio_flags = GPIOD_OUT_LOW; + drvdata->enb_gpio = devm_gpiod_get_optional(&pdev->dev, "enable", + gpio_flags); + if (IS_ERR(drvdata->enb_gpio)) { + ret = PTR_ERR(drvdata->enb_gpio); + dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n", ret); + return ret; + } + /* * FIXME: pwm_apply_args() should be removed when switching to the * atomic PWM API. diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index 6c7fe4778793..5022fa8d10c6 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -211,7 +211,7 @@ static const struct regulator_desc pma8084_switch = { static const struct regulator_desc pm8x41_hfsmps = { .linear_ranges = (struct regulator_linear_range[]) { REGULATOR_LINEAR_RANGE( 375000, 0, 95, 12500), - REGULATOR_LINEAR_RANGE(1550000, 96, 158, 25000), + REGULATOR_LINEAR_RANGE(1575000, 96, 158, 25000), }, .n_linear_ranges = 2, .n_voltages = 159, diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 84cce21e98cd..16c5f84e06a7 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -1085,6 +1085,8 @@ static struct regulator_ops spmi_vs_ops = { .set_pull_down = spmi_regulator_common_set_pull_down, .set_soft_start = spmi_regulator_common_set_soft_start, .set_over_current_protection = spmi_regulator_vs_ocp, + .set_mode = spmi_regulator_common_set_mode, + .get_mode = spmi_regulator_common_get_mode, }; static struct regulator_ops spmi_boost_ops = { @@ -1496,6 +1498,7 @@ static const struct spmi_regulator_data pm8941_regulators[] = { { "s1", 0x1400, "vdd_s1", }, { "s2", 0x1700, "vdd_s2", }, { "s3", 0x1a00, "vdd_s3", }, + { "s4", 0xa000, }, { "l1", 0x4000, "vdd_l1_l3", }, { "l2", 0x4100, "vdd_l2_lvs_1_2_3", }, { "l3", 0x4200, "vdd_l1_l3", }, @@ -1523,8 +1526,8 @@ static const struct spmi_regulator_data pm8941_regulators[] = { { "lvs1", 0x8000, "vdd_l2_lvs_1_2_3", }, { "lvs2", 0x8100, "vdd_l2_lvs_1_2_3", }, { "lvs3", 0x8200, "vdd_l2_lvs_1_2_3", }, - { "mvs1", 0x8300, "vin_5vs", }, - { "mvs2", 0x8400, "vin_5vs", }, + { "5vs1", 0x8300, "vin_5vs", "ocp-5vs1", }, + { "5vs2", 0x8400, "vin_5vs", "ocp-5vs2", }, { } }; diff --git a/drivers/regulator/rn5t618-regulator.c b/drivers/regulator/rn5t618-regulator.c index b85ceb8ff911..9c930eb68cda 100644 --- a/drivers/regulator/rn5t618-regulator.c +++ b/drivers/regulator/rn5t618-regulator.c @@ -46,6 +46,23 @@ static struct regulator_ops rn5t618_reg_ops = { .vsel_mask = (vmask), \ } +static struct regulator_desc rn5t567_regulators[] = { + /* DCDC */ + REG(DCDC1, DC1CTL, BIT(0), DC1DAC, 0xff, 600000, 3500000, 12500), + REG(DCDC2, DC2CTL, BIT(0), DC2DAC, 0xff, 600000, 3500000, 12500), + REG(DCDC3, DC3CTL, BIT(0), DC3DAC, 0xff, 600000, 3500000, 12500), + REG(DCDC4, DC4CTL, BIT(0), DC4DAC, 0xff, 600000, 3500000, 12500), + /* LDO */ + REG(LDO1, LDOEN1, BIT(0), LDO1DAC, 0x7f, 900000, 3500000, 25000), + REG(LDO2, LDOEN1, BIT(1), LDO2DAC, 0x7f, 900000, 3500000, 25000), + REG(LDO3, LDOEN1, BIT(2), LDO3DAC, 0x7f, 600000, 3500000, 25000), + REG(LDO4, LDOEN1, BIT(3), LDO4DAC, 0x7f, 900000, 3500000, 25000), + REG(LDO5, LDOEN1, BIT(4), LDO5DAC, 0x7f, 900000, 3500000, 25000), + /* LDO RTC */ + REG(LDORTC1, LDOEN2, BIT(4), LDORTCDAC, 0x7f, 1200000, 3500000, 25000), + REG(LDORTC2, LDOEN2, BIT(5), LDORTC2DAC, 0x7f, 900000, 3500000, 25000), +}; + static struct regulator_desc rn5t618_regulators[] = { /* DCDC */ REG(DCDC1, DC1CTL, BIT(0), DC1DAC, 0xff, 600000, 3500000, 12500), @@ -67,18 +84,33 @@ static int rn5t618_regulator_probe(struct platform_device *pdev) struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; struct regulator_dev *rdev; + struct regulator_desc *regulators; int i; + switch (rn5t618->variant) { + case RN5T567: + regulators = rn5t567_regulators; + break; + case RN5T618: + regulators = rn5t618_regulators; + break; + default: + return -EINVAL; + } + + config.dev = pdev->dev.parent; + config.regmap = rn5t618->regmap; + for (i = 0; i < RN5T618_REG_NUM; i++) { - config.dev = pdev->dev.parent; - config.regmap = rn5t618->regmap; + if (!regulators[i].name) + continue; rdev = devm_regulator_register(&pdev->dev, - &rn5t618_regulators[i], + ®ulators[i], &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register %s regulator\n", - rn5t618_regulators[i].name); + regulators[i].name); return PTR_ERR(rdev); } } diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 02fb6b4ea820..d838e77dd947 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -750,7 +750,7 @@ static const struct regulator_linear_range s2mps15_ldo_voltage_ranges3[] = { /* voltage range for s2mps15 LDO 7, 8, 9 and 10 */ static const struct regulator_linear_range s2mps15_ldo_voltage_ranges4[] = { - REGULATOR_LINEAR_RANGE(700000, 0xc, 0x18, 25000), + REGULATOR_LINEAR_RANGE(700000, 0x10, 0x20, 25000), }; /* voltage range for s2mps15 LDO 1 */ @@ -760,12 +760,12 @@ static const struct regulator_linear_range s2mps15_ldo_voltage_ranges5[] = { /* voltage range for s2mps15 BUCK 1, 2, 3, 4, 5, 6 and 7 */ static const struct regulator_linear_range s2mps15_buck_voltage_ranges1[] = { - REGULATOR_LINEAR_RANGE(500000, 0x20, 0xb0, 6250), + REGULATOR_LINEAR_RANGE(500000, 0x20, 0xc0, 6250), }; /* voltage range for s2mps15 BUCK 8, 9 and 10 */ static const struct regulator_linear_range s2mps15_buck_voltage_ranges2[] = { - REGULATOR_LINEAR_RANGE(1000000, 0x20, 0xc0, 12500), + REGULATOR_LINEAR_RANGE(1000000, 0x20, 0x78, 12500), }; static const struct regulator_desc s2mps15_regulators[] = { diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index adbe4fc5cf07..2d12b9af3540 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -28,7 +28,7 @@ #include <linux/mfd/tps65217.h> #define TPS65217_REGULATOR(_name, _id, _of_match, _ops, _n, _vr, _vm, _em, \ - _t, _lr, _nlr) \ + _t, _lr, _nlr, _sr, _sm) \ { \ .name = _name, \ .id = _id, \ @@ -45,6 +45,8 @@ .volt_table = _t, \ .linear_ranges = _lr, \ .n_linear_ranges = _nlr, \ + .bypass_reg = _sr, \ + .bypass_mask = _sm, \ } \ static const unsigned int LDO1_VSEL_table[] = { @@ -118,6 +120,35 @@ static int tps65217_pmic_set_voltage_sel(struct regulator_dev *dev, return ret; } +static int tps65217_pmic_set_suspend_enable(struct regulator_dev *dev) +{ + struct tps65217 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) + return -EINVAL; + + return tps65217_clear_bits(tps, dev->desc->bypass_reg, + dev->desc->bypass_mask, + TPS65217_PROTECT_L1); +} + +static int tps65217_pmic_set_suspend_disable(struct regulator_dev *dev) +{ + struct tps65217 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) + return -EINVAL; + + if (!tps->strobes[rid]) + return -EINVAL; + + return tps65217_set_bits(tps, dev->desc->bypass_reg, + dev->desc->bypass_mask, + tps->strobes[rid], TPS65217_PROTECT_L1); +} + /* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */ static struct regulator_ops tps65217_pmic_ops = { .is_enabled = regulator_is_enabled_regmap, @@ -127,6 +158,8 @@ static struct regulator_ops tps65217_pmic_ops = { .set_voltage_sel = tps65217_pmic_set_voltage_sel, .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, + .set_suspend_enable = tps65217_pmic_set_suspend_enable, + .set_suspend_disable = tps65217_pmic_set_suspend_disable, }; /* Operations permitted on LDO1 */ @@ -138,41 +171,50 @@ static struct regulator_ops tps65217_pmic_ldo1_ops = { .set_voltage_sel = tps65217_pmic_set_voltage_sel, .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, + .set_suspend_enable = tps65217_pmic_set_suspend_enable, + .set_suspend_disable = tps65217_pmic_set_suspend_disable, }; static const struct regulator_desc regulators[] = { TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, "dcdc1", tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC1_EN, - NULL, tps65217_uv1_ranges, 2), + NULL, tps65217_uv1_ranges, 2, TPS65217_REG_SEQ1, + TPS65217_SEQ1_DC1_SEQ_MASK), TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, "dcdc2", tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC2_EN, NULL, tps65217_uv1_ranges, - ARRAY_SIZE(tps65217_uv1_ranges)), + ARRAY_SIZE(tps65217_uv1_ranges), TPS65217_REG_SEQ1, + TPS65217_SEQ1_DC2_SEQ_MASK), TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, "dcdc3", tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC3_EN, - NULL, tps65217_uv1_ranges, 1), + NULL, tps65217_uv1_ranges, 1, TPS65217_REG_SEQ2, + TPS65217_SEQ2_DC3_SEQ_MASK), TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, "ldo1", tps65217_pmic_ldo1_ops, 16, TPS65217_REG_DEFLDO1, TPS65217_DEFLDO1_LDO1_MASK, TPS65217_ENABLE_LDO1_EN, - LDO1_VSEL_table, NULL, 0), + LDO1_VSEL_table, NULL, 0, TPS65217_REG_SEQ2, + TPS65217_SEQ2_LDO1_SEQ_MASK), TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, "ldo2", tps65217_pmic_ops, 64, TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK, TPS65217_ENABLE_LDO2_EN, NULL, tps65217_uv1_ranges, - ARRAY_SIZE(tps65217_uv1_ranges)), + ARRAY_SIZE(tps65217_uv1_ranges), TPS65217_REG_SEQ3, + TPS65217_SEQ3_LDO2_SEQ_MASK), TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, "ldo3", tps65217_pmic_ops, 32, TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK, TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN, NULL, tps65217_uv2_ranges, - ARRAY_SIZE(tps65217_uv2_ranges)), + ARRAY_SIZE(tps65217_uv2_ranges), TPS65217_REG_SEQ3, + TPS65217_SEQ3_LDO3_SEQ_MASK), TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, "ldo4", tps65217_pmic_ops, 32, TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK, TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN, NULL, tps65217_uv2_ranges, - ARRAY_SIZE(tps65217_uv2_ranges)), + ARRAY_SIZE(tps65217_uv2_ranges), TPS65217_REG_SEQ4, + TPS65217_SEQ4_LDO4_SEQ_MASK), }; static int tps65217_regulator_probe(struct platform_device *pdev) @@ -181,13 +223,18 @@ static int tps65217_regulator_probe(struct platform_device *pdev) struct tps65217_board *pdata = dev_get_platdata(tps->dev); struct regulator_dev *rdev; struct regulator_config config = { }; - int i; + int i, ret; + unsigned int val; if (tps65217_chip_id(tps) != TPS65217) { dev_err(&pdev->dev, "Invalid tps chip version\n"); return -ENODEV; } + /* Allocate memory for strobes */ + tps->strobes = devm_kzalloc(&pdev->dev, sizeof(u8) * + TPS65217_NUM_REGULATOR, GFP_KERNEL); + platform_set_drvdata(pdev, tps); for (i = 0; i < TPS65217_NUM_REGULATOR; i++) { @@ -205,6 +252,10 @@ static int tps65217_regulator_probe(struct platform_device *pdev) pdev->name); return PTR_ERR(rdev); } + + /* Store default strobe info */ + ret = tps65217_reg_read(tps, regulators[i].bypass_reg, &val); + tps->strobes[i] = val & regulators[i].bypass_mask; } return 0; diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c index a5e5634eeb9e..d1e631d64a20 100644 --- a/drivers/regulator/tps65218-regulator.c +++ b/drivers/regulator/tps65218-regulator.c @@ -31,7 +31,7 @@ enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, DCDC5, DCDC6, LDO1, LS3 }; #define TPS65218_REGULATOR(_name, _id, _type, _ops, _n, _vr, _vm, _er, _em, \ - _cr, _cm, _lr, _nlr, _delay, _fuv) \ + _cr, _cm, _lr, _nlr, _delay, _fuv, _sr, _sm) \ { \ .name = _name, \ .id = _id, \ @@ -49,7 +49,9 @@ enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, .linear_ranges = _lr, \ .n_linear_ranges = _nlr, \ .ramp_delay = _delay, \ - .fixed_uV = _fuv \ + .fixed_uV = _fuv, \ + .bypass_reg = _sr, \ + .bypass_mask = _sm, \ } \ #define TPS65218_INFO(_id, _nm, _min, _max) \ @@ -157,6 +159,40 @@ static int tps65218_pmic_disable(struct regulator_dev *dev) dev->desc->enable_mask, TPS65218_PROTECT_L1); } +static int tps65218_pmic_set_suspend_enable(struct regulator_dev *dev) +{ + struct tps65218 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1) + return -EINVAL; + + return tps65218_clear_bits(tps, dev->desc->bypass_reg, + dev->desc->bypass_mask, + TPS65218_PROTECT_L1); +} + +static int tps65218_pmic_set_suspend_disable(struct regulator_dev *dev) +{ + struct tps65218 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1) + return -EINVAL; + + if (!tps->info[rid]->strobe) { + if (rid == TPS65218_DCDC_3) + tps->info[rid]->strobe = 3; + else + return -EINVAL; + } + + return tps65218_set_bits(tps, dev->desc->bypass_reg, + dev->desc->bypass_mask, + tps->info[rid]->strobe, + TPS65218_PROTECT_L1); +} + /* Operations permitted on DCDC1, DCDC2 */ static struct regulator_ops tps65218_dcdc12_ops = { .is_enabled = regulator_is_enabled_regmap, @@ -167,6 +203,8 @@ static struct regulator_ops tps65218_dcdc12_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_enable = tps65218_pmic_set_suspend_enable, + .set_suspend_disable = tps65218_pmic_set_suspend_disable, }; /* Operations permitted on DCDC3, DCDC4 and LDO1 */ @@ -178,6 +216,8 @@ static struct regulator_ops tps65218_ldo1_dcdc34_ops = { .set_voltage_sel = tps65218_pmic_set_voltage_sel, .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, + .set_suspend_enable = tps65218_pmic_set_suspend_enable, + .set_suspend_disable = tps65218_pmic_set_suspend_disable, }; static const int ls3_currents[] = { 100, 200, 500, 1000 }; @@ -247,6 +287,8 @@ static struct regulator_ops tps65218_dcdc56_pmic_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = tps65218_pmic_enable, .disable = tps65218_pmic_disable, + .set_suspend_enable = tps65218_pmic_set_suspend_enable, + .set_suspend_disable = tps65218_pmic_set_suspend_disable, }; static const struct regulator_desc regulators[] = { @@ -254,42 +296,47 @@ static const struct regulator_desc regulators[] = { tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC1, TPS65218_CONTROL_DCDC1_MASK, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC1_EN, 0, 0, dcdc1_dcdc2_ranges, - 2, 4000, 0), + 2, 4000, 0, TPS65218_REG_SEQ3, + TPS65218_SEQ3_DC1_SEQ_MASK), TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, REGULATOR_VOLTAGE, tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC2, TPS65218_CONTROL_DCDC2_MASK, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC2_EN, 0, 0, dcdc1_dcdc2_ranges, - 2, 4000, 0), + 2, 4000, 0, TPS65218_REG_SEQ3, + TPS65218_SEQ3_DC2_SEQ_MASK), TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 64, TPS65218_REG_CONTROL_DCDC3, TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC3_EN, 0, 0, ldo1_dcdc3_ranges, 2, - 0, 0), + 0, 0, TPS65218_REG_SEQ4, TPS65218_SEQ4_DC3_SEQ_MASK), TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 53, TPS65218_REG_CONTROL_DCDC4, TPS65218_CONTROL_DCDC4_MASK, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC4_EN, 0, 0, dcdc4_ranges, 2, - 0, 0), + 0, 0, TPS65218_REG_SEQ4, TPS65218_SEQ4_DC4_SEQ_MASK), TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, REGULATOR_VOLTAGE, tps65218_dcdc56_pmic_ops, 1, -1, -1, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC5_EN, 0, 0, - NULL, 0, 0, 1000000), + NULL, 0, 0, 1000000, TPS65218_REG_SEQ5, + TPS65218_SEQ5_DC5_SEQ_MASK), TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, REGULATOR_VOLTAGE, tps65218_dcdc56_pmic_ops, 1, -1, -1, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, 0, 0, - NULL, 0, 0, 1800000), + NULL, 0, 0, 1800000, TPS65218_REG_SEQ5, + TPS65218_SEQ5_DC6_SEQ_MASK), TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 64, TPS65218_REG_CONTROL_LDO1, TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2, TPS65218_ENABLE2_LDO1_EN, 0, 0, ldo1_dcdc3_ranges, - 2, 0, 0), + 2, 0, 0, TPS65218_REG_SEQ6, + TPS65218_SEQ6_LDO1_SEQ_MASK), TPS65218_REGULATOR("LS3", TPS65218_LS_3, REGULATOR_CURRENT, tps65218_ls3_ops, 0, 0, 0, TPS65218_REG_ENABLE2, TPS65218_ENABLE2_LS3_EN, TPS65218_REG_CONFIG2, - TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0), + TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0, 0, 0), }; static int tps65218_regulator_probe(struct platform_device *pdev) @@ -300,7 +347,8 @@ static int tps65218_regulator_probe(struct platform_device *pdev) struct regulator_dev *rdev; const struct of_device_id *match; struct regulator_config config = { }; - int id; + int id, ret; + unsigned int val; match = of_match_device(tps65218_of_match, &pdev->dev); if (!match) @@ -327,6 +375,12 @@ static int tps65218_regulator_probe(struct platform_device *pdev) return PTR_ERR(rdev); } + ret = tps65218_reg_read(tps, regulators[id].bypass_reg, &val); + if (ret) + return ret; + + tps->info[id]->strobe = val & regulators[id].bypass_mask; + return 0; } diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index faeb5ee92c9e..210681d6b743 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -905,7 +905,7 @@ static struct regulator_ops twlsmps_ops = { twl4030reg_map_mode) #define TWL6030_FIXED_LDO(label, offset, mVolts, turnon_delay) \ TWL_FIXED_LDO(label, offset, mVolts, 0x0, turnon_delay, \ - 0x0, TWL6030, twl6030fixed_ops, 0x0) + 0x0, TWL6030, twl6030fixed_ops, NULL) #define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \ static const struct twlreg_info TWL4030_INFO_##label = { \ |