summaryrefslogtreecommitdiff
path: root/drivers/regulator
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/Kconfig20
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/bd71815-regulator.c652
-rw-r--r--drivers/regulator/bd71828-regulator.c51
-rw-r--r--drivers/regulator/bd718x7-regulator.c60
-rw-r--r--drivers/regulator/bd9571mwv-regulator.c8
-rw-r--r--drivers/regulator/bd9576-regulator.c11
-rw-r--r--drivers/regulator/core.c59
-rw-r--r--drivers/regulator/da9121-regulator.c80
-rw-r--r--drivers/regulator/da9121-regulator.h13
-rw-r--r--drivers/regulator/fan53555.c136
-rw-r--r--drivers/regulator/helpers.c101
-rw-r--r--drivers/regulator/hi6421v600-regulator.c299
-rw-r--r--drivers/regulator/mt6360-regulator.c4
-rw-r--r--drivers/regulator/of_regulator.c6
-rw-r--r--drivers/regulator/pf8x00-regulator.c1
-rw-r--r--drivers/regulator/qcom-rpmh-regulator.c62
-rw-r--r--drivers/regulator/qcom_spmi-regulator.c36
-rw-r--r--drivers/regulator/rohm-regulator.c23
-rw-r--r--drivers/regulator/s2mpa01.c4
-rw-r--r--drivers/regulator/s2mps11.c22
-rw-r--r--drivers/regulator/scmi-regulator.c46
22 files changed, 1460 insertions, 236 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 77c43134bc9e..9d84d9245490 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -204,6 +204,17 @@ config REGULATOR_BD70528
This driver can also be built as a module. If so, the module
will be called bd70528-regulator.
+config REGULATOR_BD71815
+ tristate "ROHM BD71815 Power Regulator"
+ depends on MFD_ROHM_BD71828
+ help
+ This driver supports voltage regulators on ROHM BD71815 PMIC.
+ This will enable support for the software controllable buck
+ and LDO regulators and a current regulator for LEDs.
+
+ This driver can also be built as a module. If so, the module
+ will be called bd71815-regulator.
+
config REGULATOR_BD71828
tristate "ROHM BD71828 Power Regulator"
depends on MFD_ROHM_BD71828
@@ -422,6 +433,15 @@ config REGULATOR_HI655X
This driver provides support for the voltage regulators of the
Hisilicon Hi655x PMIC device.
+config REGULATOR_HI6421V600
+ tristate "HiSilicon Hi6421v600 PMIC voltage regulator support"
+ depends on MFD_HI6421_SPMI && OF
+ select REGMAP
+ help
+ This driver provides support for the voltage regulators on
+ HiSilicon Hi6421v600 PMU / Codec IC.
+ This is used on Kirin 3670 boards, like HiKey 970.
+
config REGULATOR_ISL9305
tristate "Intersil ISL9305 regulator"
depends on I2C
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 44d2f8bf4b74..580b015296ea 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_ATC260X) += atc260x-regulator.o
obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
obj-$(CONFIG_REGULATOR_BD70528) += bd70528-regulator.o
+obj-$(CONFIG_REGULATOR_BD71815) += bd71815-regulator.o
obj-$(CONFIG_REGULATOR_BD71828) += bd71828-regulator.o
obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o
obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o
@@ -49,6 +50,7 @@ obj-$(CONFIG_REGULATOR_FAN53880) += fan53880.o
obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o
obj-$(CONFIG_REGULATOR_HI6421V530) += hi6421v530-regulator.o
+obj-$(CONFIG_REGULATOR_HI6421V600) += hi6421v600-regulator.o
obj-$(CONFIG_REGULATOR_HI655X) += hi655x-regulator.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
diff --git a/drivers/regulator/bd71815-regulator.c b/drivers/regulator/bd71815-regulator.c
new file mode 100644
index 000000000000..a4e8d5e36b40
--- /dev/null
+++ b/drivers/regulator/bd71815-regulator.c
@@ -0,0 +1,652 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright 2014 Embest Technology Co. Ltd. Inc.
+// bd71815-regulator.c ROHM BD71815 regulator driver
+//
+// Author: Tony Luo <luofc@embedinfo.com>
+//
+// Partially rewritten at 2021 by
+// Matti Vaittinen <matti.vaitinen@fi.rohmeurope.com>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/mfd/rohm-generic.h>
+#include <linux/mfd/rohm-bd71815.h>
+#include <linux/regulator/of_regulator.h>
+
+struct bd71815_regulator {
+ struct regulator_desc desc;
+ const struct rohm_dvs_config *dvs;
+};
+
+struct bd71815_pmic {
+ struct bd71815_regulator descs[BD71815_REGULATOR_CNT];
+ struct regmap *regmap;
+ struct device *dev;
+ struct gpio_descs *gps;
+ struct regulator_dev *rdev[BD71815_REGULATOR_CNT];
+};
+
+static const int bd7181x_wled_currents[] = {
+ 10, 20, 30, 50, 70, 100, 200, 300, 500, 700, 1000, 2000, 3000, 4000,
+ 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 13000, 14000, 15000,
+ 16000, 17000, 18000, 19000, 20000, 21000, 22000, 23000, 24000, 25000,
+};
+
+static const struct rohm_dvs_config buck1_dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+ ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD71815_REG_BUCK1_VOLT_H,
+ .run_mask = BD71815_VOLT_MASK,
+ .run_on_mask = BD71815_BUCK_RUN_ON,
+ .snvs_on_mask = BD71815_BUCK_SNVS_ON,
+ .suspend_reg = BD71815_REG_BUCK1_VOLT_L,
+ .suspend_mask = BD71815_VOLT_MASK,
+ .suspend_on_mask = BD71815_BUCK_SUSP_ON,
+ .lpsr_reg = BD71815_REG_BUCK1_VOLT_L,
+ .lpsr_mask = BD71815_VOLT_MASK,
+ .lpsr_on_mask = BD71815_BUCK_LPSR_ON,
+};
+
+static const struct rohm_dvs_config buck2_dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+ ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD71815_REG_BUCK2_VOLT_H,
+ .run_mask = BD71815_VOLT_MASK,
+ .run_on_mask = BD71815_BUCK_RUN_ON,
+ .snvs_on_mask = BD71815_BUCK_SNVS_ON,
+ .suspend_reg = BD71815_REG_BUCK2_VOLT_L,
+ .suspend_mask = BD71815_VOLT_MASK,
+ .suspend_on_mask = BD71815_BUCK_SUSP_ON,
+ .lpsr_reg = BD71815_REG_BUCK2_VOLT_L,
+ .lpsr_mask = BD71815_VOLT_MASK,
+ .lpsr_on_mask = BD71815_BUCK_LPSR_ON,
+};
+
+static const struct rohm_dvs_config buck3_dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+ ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD71815_REG_BUCK3_VOLT,
+ .run_mask = BD71815_VOLT_MASK,
+ .run_on_mask = BD71815_BUCK_RUN_ON,
+ .snvs_on_mask = BD71815_BUCK_SNVS_ON,
+ .suspend_on_mask = BD71815_BUCK_SUSP_ON,
+ .lpsr_on_mask = BD71815_BUCK_LPSR_ON,
+};
+
+static const struct rohm_dvs_config buck4_dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+ ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD71815_REG_BUCK4_VOLT,
+ .run_mask = BD71815_VOLT_MASK,
+ .run_on_mask = BD71815_BUCK_RUN_ON,
+ .snvs_on_mask = BD71815_BUCK_SNVS_ON,
+ .suspend_on_mask = BD71815_BUCK_SUSP_ON,
+ .lpsr_on_mask = BD71815_BUCK_LPSR_ON,
+};
+
+static const struct rohm_dvs_config ldo1_dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+ ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD71815_REG_LDO_MODE1,
+ .run_mask = BD71815_VOLT_MASK,
+ .run_on_mask = LDO1_RUN_ON,
+ .snvs_on_mask = LDO1_SNVS_ON,
+ .suspend_on_mask = LDO1_SUSP_ON,
+ .lpsr_on_mask = LDO1_LPSR_ON,
+};
+
+static const struct rohm_dvs_config ldo2_dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+ ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD71815_REG_LDO_MODE2,
+ .run_mask = BD71815_VOLT_MASK,
+ .run_on_mask = LDO2_RUN_ON,
+ .snvs_on_mask = LDO2_SNVS_ON,
+ .suspend_on_mask = LDO2_SUSP_ON,
+ .lpsr_on_mask = LDO2_LPSR_ON,
+};
+
+static const struct rohm_dvs_config ldo3_dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+ ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD71815_REG_LDO_MODE2,
+ .run_mask = BD71815_VOLT_MASK,
+ .run_on_mask = LDO3_RUN_ON,
+ .snvs_on_mask = LDO3_SNVS_ON,
+ .suspend_on_mask = LDO3_SUSP_ON,
+ .lpsr_on_mask = LDO3_LPSR_ON,
+};
+
+static const struct rohm_dvs_config ldo4_dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+ ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD71815_REG_LDO_MODE3,
+ .run_mask = BD71815_VOLT_MASK,
+ .run_on_mask = LDO4_RUN_ON,
+ .snvs_on_mask = LDO4_SNVS_ON,
+ .suspend_on_mask = LDO4_SUSP_ON,
+ .lpsr_on_mask = LDO4_LPSR_ON,
+};
+
+static const struct rohm_dvs_config ldo5_dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+ ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD71815_REG_LDO_MODE3,
+ .run_mask = BD71815_VOLT_MASK,
+ .run_on_mask = LDO5_RUN_ON,
+ .snvs_on_mask = LDO5_SNVS_ON,
+ .suspend_on_mask = LDO5_SUSP_ON,
+ .lpsr_on_mask = LDO5_LPSR_ON,
+};
+
+static const struct rohm_dvs_config dvref_dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+ ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+ .run_on_mask = DVREF_RUN_ON,
+ .snvs_on_mask = DVREF_SNVS_ON,
+ .suspend_on_mask = DVREF_SUSP_ON,
+ .lpsr_on_mask = DVREF_LPSR_ON,
+};
+
+static const struct rohm_dvs_config ldolpsr_dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+ ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+ .run_on_mask = DVREF_RUN_ON,
+ .snvs_on_mask = DVREF_SNVS_ON,
+ .suspend_on_mask = DVREF_SUSP_ON,
+ .lpsr_on_mask = DVREF_LPSR_ON,
+};
+
+static const struct rohm_dvs_config buck5_dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+ ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD71815_REG_BUCK5_VOLT,
+ .run_mask = BD71815_VOLT_MASK,
+ .run_on_mask = BD71815_BUCK_RUN_ON,
+ .snvs_on_mask = BD71815_BUCK_SNVS_ON,
+ .suspend_on_mask = BD71815_BUCK_SUSP_ON,
+ .lpsr_on_mask = BD71815_BUCK_LPSR_ON,
+};
+
+static int set_hw_dvs_levels(struct device_node *np,
+ const struct regulator_desc *desc,
+ struct regulator_config *cfg)
+{
+ struct bd71815_regulator *data;
+
+ data = container_of(desc, struct bd71815_regulator, desc);
+ return rohm_regulator_set_dvs_levels(data->dvs, np, desc, cfg->regmap);
+}
+
+/*
+ * Bucks 1 and 2 have two voltage selection registers where selected
+ * voltage can be set. Which of the registers is used can be either controlled
+ * by a control bit in register - or by HW state. If HW state specific voltages
+ * are given - then we assume HW state based control should be used.
+ *
+ * If volatge value is updated to currently selected register - then output
+ * voltage is immediately changed no matter what is set as ramp rate. Thus we
+ * default changing voltage by writing new value to inactive register and
+ * then updating the 'register selection' bit. This naturally only works when
+ * HW state machine is not used to select the voltage.
+ */
+static int buck12_set_hw_dvs_levels(struct device_node *np,
+ const struct regulator_desc *desc,
+ struct regulator_config *cfg)
+{
+ struct bd71815_regulator *data;
+ int ret = 0, val;
+
+ data = container_of(desc, struct bd71815_regulator, desc);
+
+ if (of_find_property(np, "rohm,dvs-run-voltage", NULL) ||
+ of_find_property(np, "rohm,dvs-suspend-voltage", NULL) ||
+ of_find_property(np, "rohm,dvs-lpsr-voltage", NULL) ||
+ of_find_property(np, "rohm,dvs-snvs-voltage", NULL)) {
+ ret = regmap_read(cfg->regmap, desc->vsel_reg, &val);
+ if (ret)
+ return ret;
+
+ if (!(BD71815_BUCK_STBY_DVS & val) &&
+ !(BD71815_BUCK_DVSSEL & val)) {
+ int val2;
+
+ /*
+ * We are currently using voltage from _L.
+ * We'd better copy it to _H and switch to it to
+ * avoid shutting us down if LPSR or SUSPEND is set to
+ * disabled. _L value is at reg _H + 1
+ */
+ ret = regmap_read(cfg->regmap, desc->vsel_reg + 1,
+ &val2);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(cfg->regmap, desc->vsel_reg,
+ BD71815_VOLT_MASK |
+ BD71815_BUCK_DVSSEL,
+ val2 | BD71815_BUCK_DVSSEL);
+ if (ret)
+ return ret;
+ }
+ ret = rohm_regulator_set_dvs_levels(data->dvs, np, desc,
+ cfg->regmap);
+ if (ret)
+ return ret;
+ /*
+ * DVS levels were given => use HW-state machine for voltage
+ * controls. NOTE: AFAIK, This means that if voltage is changed
+ * by SW the ramp-rate is not respected. Should we disable
+ * SW voltage control when the HW state machine is used?
+ */
+ ret = regmap_update_bits(cfg->regmap, desc->vsel_reg,
+ BD71815_BUCK_STBY_DVS,
+ BD71815_BUCK_STBY_DVS);
+ }
+
+ return ret;
+}
+
+/*
+ * BUCK1/2
+ * BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting
+ * 00: 10.00mV/usec 10mV 1uS
+ * 01: 5.00mV/usec 10mV 2uS
+ * 10: 2.50mV/usec 10mV 4uS
+ * 11: 1.25mV/usec 10mV 8uS
+ */
+static const unsigned int bd7181x_ramp_table[] = { 1250, 2500, 5000, 10000 };
+
+static int bd7181x_led_set_current_limit(struct regulator_dev *rdev,
+ int min_uA, int max_uA)
+{
+ int ret;
+ int onstatus;
+
+ onstatus = regulator_is_enabled_regmap(rdev);
+
+ ret = regulator_set_current_limit_regmap(rdev, min_uA, max_uA);
+ if (!ret) {
+ int newstatus;
+
+ newstatus = regulator_is_enabled_regmap(rdev);
+ if (onstatus != newstatus) {
+ /*
+ * HW FIX: spurious led status change detected. Toggle
+ * state as a workaround
+ */
+ if (onstatus)
+ ret = regulator_enable_regmap(rdev);
+ else
+ ret = regulator_disable_regmap(rdev);
+
+ if (ret)
+ dev_err(rdev_get_dev(rdev),
+ "failed to revert the LED state (%d)\n",
+ ret);
+ }
+ }
+
+ return ret;
+}
+
+static int bd7181x_buck12_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct bd71815_pmic *pmic = rdev_get_drvdata(rdev);
+ int rid = rdev_get_id(rdev);
+ int ret, regh, regl, val;
+
+ regh = BD71815_REG_BUCK1_VOLT_H + rid * 0x2;
+ regl = BD71815_REG_BUCK1_VOLT_L + rid * 0x2;
+
+ ret = regmap_read(pmic->regmap, regh, &val);
+ if (ret)
+ return ret;
+
+ /*
+ * If we use HW state machine based voltage reg selection - then we
+ * return BD71815_REG_BUCK1_VOLT_H which is used at RUN.
+ * Else we do return the BD71815_REG_BUCK1_VOLT_H or
+ * BD71815_REG_BUCK1_VOLT_L depending on which is selected to be used
+ * by BD71815_BUCK_DVSSEL bit
+ */
+ if ((!(val & BD71815_BUCK_STBY_DVS)) && (!(val & BD71815_BUCK_DVSSEL)))
+ ret = regmap_read(pmic->regmap, regl, &val);
+
+ if (ret)
+ return ret;
+
+ return val & BD71815_VOLT_MASK;
+}
+
+/*
+ * For Buck 1/2.
+ */
+static int bd7181x_buck12_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int sel)
+{
+ struct bd71815_pmic *pmic = rdev_get_drvdata(rdev);
+ int rid = rdev_get_id(rdev);
+ int ret, val, reg, regh, regl;
+
+ regh = BD71815_REG_BUCK1_VOLT_H + rid*0x2;
+ regl = BD71815_REG_BUCK1_VOLT_L + rid*0x2;
+
+ ret = regmap_read(pmic->regmap, regh, &val);
+ if (ret)
+ return ret;
+
+ /*
+ * If bucks 1 & 2 are controlled by state machine - then the RUN state
+ * voltage is set to BD71815_REG_BUCK1_VOLT_H. Changing SUSPEND/LPSR
+ * voltages at runtime is not supported by this driver.
+ */
+ if (((val & BD71815_BUCK_STBY_DVS))) {
+ return regmap_update_bits(pmic->regmap, regh, BD71815_VOLT_MASK,
+ sel);
+ }
+ /* Update new voltage to the register which is not selected now */
+ if (val & BD71815_BUCK_DVSSEL)
+ reg = regl;
+ else
+ reg = regh;
+
+ ret = regmap_update_bits(pmic->regmap, reg, BD71815_VOLT_MASK, sel);
+ if (ret)
+ return ret;
+
+ /* Select the other DVS register to be used */
+ return regmap_update_bits(pmic->regmap, regh, BD71815_BUCK_DVSSEL, ~val);
+}
+
+static const struct regulator_ops bd7181x_ldo_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static const struct regulator_ops bd7181x_fixed_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+static const struct regulator_ops bd7181x_buck_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .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,
+};
+
+static const struct regulator_ops bd7181x_buck12_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = bd7181x_buck12_set_voltage_sel,
+ .get_voltage_sel = bd7181x_buck12_get_voltage_sel,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
+};
+
+static const struct regulator_ops bd7181x_led_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_current_limit = bd7181x_led_set_current_limit,
+ .get_current_limit = regulator_get_current_limit_regmap,
+};
+
+#define BD71815_FIXED_REG(_name, _id, ereg, emsk, voltage, _dvs) \
+ [(_id)] = { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(#_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = 1, \
+ .ops = &bd7181x_fixed_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = (_id), \
+ .owner = THIS_MODULE, \
+ .min_uV = (voltage), \
+ .enable_reg = (ereg), \
+ .enable_mask = (emsk), \
+ .of_parse_cb = set_hw_dvs_levels, \
+ }, \
+ .dvs = (_dvs), \
+ }
+
+#define BD71815_BUCK_REG(_name, _id, vsel, ereg, min, max, step, _dvs) \
+ [(_id)] = { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(#_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &bd7181x_buck_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = (_id), \
+ .owner = THIS_MODULE, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .vsel_reg = (vsel), \
+ .vsel_mask = BD71815_VOLT_MASK, \
+ .enable_reg = (ereg), \
+ .enable_mask = BD71815_BUCK_RUN_ON, \
+ .of_parse_cb = set_hw_dvs_levels, \
+ }, \
+ .dvs = (_dvs), \
+ }
+
+#define BD71815_BUCK12_REG(_name, _id, vsel, ereg, min, max, step, \
+ _dvs) \
+ [(_id)] = { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(#_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &bd7181x_buck12_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = (_id), \
+ .owner = THIS_MODULE, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .vsel_reg = (vsel), \
+ .vsel_mask = 0x3f, \
+ .enable_reg = (ereg), \
+ .enable_mask = 0x04, \
+ .ramp_reg = (ereg), \
+ .ramp_mask = BD71815_BUCK_RAMPRATE_MASK, \
+ .ramp_delay_table = bd7181x_ramp_table, \
+ .n_ramp_values = ARRAY_SIZE(bd7181x_ramp_table),\
+ .of_parse_cb = buck12_set_hw_dvs_levels, \
+ }, \
+ .dvs = (_dvs), \
+ }
+
+#define BD71815_LED_REG(_name, _id, csel, mask, ereg, emsk, currents) \
+ [(_id)] = { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(#_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_current_limits = ARRAY_SIZE(currents), \
+ .ops = &bd7181x_led_regulator_ops, \
+ .type = REGULATOR_CURRENT, \
+ .id = (_id), \
+ .owner = THIS_MODULE, \
+ .curr_table = currents, \
+ .csel_reg = (csel), \
+ .csel_mask = (mask), \
+ .enable_reg = (ereg), \
+ .enable_mask = (emsk), \
+ }, \
+ }
+
+#define BD71815_LDO_REG(_name, _id, vsel, ereg, emsk, min, max, step, \
+ _dvs) \
+ [(_id)] = { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(#_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &bd7181x_ldo_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = (_id), \
+ .owner = THIS_MODULE, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .vsel_reg = (vsel), \
+ .vsel_mask = BD71815_VOLT_MASK, \
+ .enable_reg = (ereg), \
+ .enable_mask = (emsk), \
+ .of_parse_cb = set_hw_dvs_levels, \
+ }, \
+ .dvs = (_dvs), \
+ }
+
+static struct bd71815_regulator bd71815_regulators[] = {
+ BD71815_BUCK12_REG(buck1, BD71815_BUCK1, BD71815_REG_BUCK1_VOLT_H,
+ BD71815_REG_BUCK1_MODE, 800000, 2000000, 25000,
+ &buck1_dvs),
+ BD71815_BUCK12_REG(buck2, BD71815_BUCK2, BD71815_REG_BUCK2_VOLT_H,
+ BD71815_REG_BUCK2_MODE, 800000, 2000000, 25000,
+ &buck2_dvs),
+ BD71815_BUCK_REG(buck3, BD71815_BUCK3, BD71815_REG_BUCK3_VOLT,
+ BD71815_REG_BUCK3_MODE, 1200000, 2700000, 50000,
+ &buck3_dvs),
+ BD71815_BUCK_REG(buck4, BD71815_BUCK4, BD71815_REG_BUCK4_VOLT,
+ BD71815_REG_BUCK4_MODE, 1100000, 1850000, 25000,
+ &buck4_dvs),
+ BD71815_BUCK_REG(buck5, BD71815_BUCK5, BD71815_REG_BUCK5_VOLT,
+ BD71815_REG_BUCK5_MODE, 1800000, 3300000, 50000,
+ &buck5_dvs),
+ BD71815_LDO_REG(ldo1, BD71815_LDO1, BD71815_REG_LDO1_VOLT,
+ BD71815_REG_LDO_MODE1, LDO1_RUN_ON, 800000, 3300000,
+ 50000, &ldo1_dvs),
+ BD71815_LDO_REG(ldo2, BD71815_LDO2, BD71815_REG_LDO2_VOLT,
+ BD71815_REG_LDO_MODE2, LDO2_RUN_ON, 800000, 3300000,
+ 50000, &ldo2_dvs),
+ /*
+ * Let's default LDO3 to be enabled by SW. We can override ops if DT
+ * says LDO3 should be enabled by HW when DCIN is connected.
+ */
+ BD71815_LDO_REG(ldo3, BD71815_LDO3, BD71815_REG_LDO3_VOLT,
+ BD71815_REG_LDO_MODE2, LDO3_RUN_ON, 800000, 3300000,
+ 50000, &ldo3_dvs),
+ BD71815_LDO_REG(ldo4, BD71815_LDO4, BD71815_REG_LDO4_VOLT,
+ BD71815_REG_LDO_MODE3, LDO4_RUN_ON, 800000, 3300000,
+ 50000, &ldo4_dvs),
+ BD71815_LDO_REG(ldo5, BD71815_LDO5, BD71815_REG_LDO5_VOLT_H,
+ BD71815_REG_LDO_MODE3, LDO5_RUN_ON, 800000, 3300000,
+ 50000, &ldo5_dvs),
+ BD71815_FIXED_REG(ldodvref, BD71815_LDODVREF, BD71815_REG_LDO_MODE4,
+ DVREF_RUN_ON, 3000000, &dvref_dvs),
+ BD71815_FIXED_REG(ldolpsr, BD71815_LDOLPSR, BD71815_REG_LDO_MODE4,
+ LDO_LPSR_RUN_ON, 1800000, &ldolpsr_dvs),
+ BD71815_LED_REG(wled, BD71815_WLED, BD71815_REG_LED_DIMM, LED_DIMM_MASK,
+ BD71815_REG_LED_CTRL, LED_RUN_ON,
+ bd7181x_wled_currents),
+};
+
+static int bd7181x_probe(struct platform_device *pdev)
+{
+ struct bd71815_pmic *pmic;
+ struct regulator_config config = {};
+ int i, ret;
+ struct gpio_desc *ldo4_en;
+
+ pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
+ if (!pmic)
+ return -ENOMEM;
+
+ memcpy(pmic->descs, bd71815_regulators, sizeof(pmic->descs));
+
+ pmic->dev = &pdev->dev;
+ pmic->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!pmic->regmap) {
+ dev_err(pmic->dev, "No parent regmap\n");
+ return -ENODEV;
+ }
+ platform_set_drvdata(pdev, pmic);
+ ldo4_en = devm_gpiod_get_from_of_node(&pdev->dev,
+ pdev->dev.parent->of_node,
+ "rohm,vsel-gpios", 0,
+ GPIOD_ASIS, "ldo4-en");
+
+ if (IS_ERR(ldo4_en)) {
+ ret = PTR_ERR(ldo4_en);
+ if (ret != -ENOENT)
+ return ret;
+ ldo4_en = NULL;
+ }
+
+ /* Disable to go to ship-mode */
+ ret = regmap_update_bits(pmic->regmap, BD71815_REG_PWRCTRL,
+ RESTARTEN, 0);
+ if (ret)
+ return ret;
+
+ config.dev = pdev->dev.parent;
+ config.regmap = pmic->regmap;
+
+ for (i = 0; i < BD71815_REGULATOR_CNT; i++) {
+ struct regulator_desc *desc;
+ struct regulator_dev *rdev;
+
+ desc = &pmic->descs[i].desc;
+ if (i == BD71815_LDO4)
+ config.ena_gpiod = ldo4_en;
+
+ config.driver_data = pmic;
+
+ rdev = devm_regulator_register(&pdev->dev, desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev,
+ "failed to register %s regulator\n",
+ desc->name);
+ return PTR_ERR(rdev);
+ }
+ config.ena_gpiod = NULL;
+ pmic->rdev[i] = rdev;
+ }
+ return 0;
+}
+
+static const struct platform_device_id bd7181x_pmic_id[] = {
+ { "bd71815-pmic", ROHM_CHIP_TYPE_BD71815 },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, bd7181x_pmic_id);
+
+static struct platform_driver bd7181x_regulator = {
+ .driver = {
+ .name = "bd7181x-pmic",
+ .owner = THIS_MODULE,
+ },
+ .probe = bd7181x_probe,
+ .id_table = bd7181x_pmic_id,
+};
+module_platform_driver(bd7181x_regulator);
+
+MODULE_AUTHOR("Tony Luo <luofc@embedinfo.com>");
+MODULE_DESCRIPTION("BD71815 voltage regulator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bd7181x-pmic");
diff --git a/drivers/regulator/bd71828-regulator.c b/drivers/regulator/bd71828-regulator.c
index 6b12e963ed8f..a4f09a5a30ca 100644
--- a/drivers/regulator/bd71828-regulator.c
+++ b/drivers/regulator/bd71828-regulator.c
@@ -90,38 +90,7 @@ static const struct linear_range bd71828_ldo_volts[] = {
REGULATOR_LINEAR_RANGE(3300000, 0x32, 0x3f, 0),
};
-static int bd71828_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
- unsigned int val;
-
- switch (ramp_delay) {
- case 1 ... 2500:
- val = 0;
- break;
- case 2501 ... 5000:
- val = 1;
- break;
- case 5001 ... 10000:
- val = 2;
- break;
- case 10001 ... 20000:
- val = 3;
- break;
- default:
- val = 3;
- dev_err(&rdev->dev,
- "ramp_delay: %d not supported, setting 20mV/uS",
- ramp_delay);
- }
-
- /*
- * On BD71828 the ramp delay level control reg is at offset +2 to
- * enable reg
- */
- return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg + 2,
- BD71828_MASK_RAMP_DELAY,
- val << (ffs(BD71828_MASK_RAMP_DELAY) - 1));
-}
+static const unsigned int bd71828_ramp_delay[] = { 2500, 5000, 10000, 20000 };
static int buck_set_hw_dvs_levels(struct device_node *np,
const struct regulator_desc *desc,
@@ -185,7 +154,7 @@ static const struct regulator_ops bd71828_dvs_buck_ops = {
.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,
- .set_ramp_delay = bd71828_set_ramp_delay,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
};
static const struct regulator_ops bd71828_ldo_ops = {
@@ -219,6 +188,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK1_VOLT,
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
+ .ramp_delay_table = bd71828_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+ .ramp_reg = BD71828_REG_BUCK1_MODE,
+ .ramp_mask = BD71828_MASK_RAMP_DELAY,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
@@ -261,6 +234,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK2_VOLT,
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
+ .ramp_delay_table = bd71828_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+ .ramp_reg = BD71828_REG_BUCK2_MODE,
+ .ramp_mask = BD71828_MASK_RAMP_DELAY,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
@@ -421,6 +398,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK6_VOLT,
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
+ .ramp_delay_table = bd71828_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+ .ramp_reg = BD71828_REG_BUCK6_MODE,
+ .ramp_mask = BD71828_MASK_RAMP_DELAY,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
@@ -458,6 +439,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK7_VOLT,
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
+ .ramp_delay_table = bd71828_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+ .ramp_reg = BD71828_REG_BUCK7_MODE,
+ .ramp_mask = BD71828_MASK_RAMP_DELAY,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c
index 8ff47ea522d6..e61295b30503 100644
--- a/drivers/regulator/bd718x7-regulator.c
+++ b/drivers/regulator/bd718x7-regulator.c
@@ -86,37 +86,7 @@ static const struct regulator_ops BD718XX_HWOPNAME(name) = { \
* 10: 2.50mV/usec 10mV 4uS
* 11: 1.25mV/usec 10mV 8uS
*/
-static int bd718xx_buck1234_set_ramp_delay(struct regulator_dev *rdev,
- int ramp_delay)
-{
- int id = rdev_get_id(rdev);
- unsigned int ramp_value;
-
- dev_dbg(&rdev->dev, "Buck[%d] Set Ramp = %d\n", id + 1,
- ramp_delay);
- switch (ramp_delay) {
- case 1 ... 1250:
- ramp_value = BUCK_RAMPRATE_1P25MV;
- break;
- case 1251 ... 2500:
- ramp_value = BUCK_RAMPRATE_2P50MV;
- break;
- case 2501 ... 5000:
- ramp_value = BUCK_RAMPRATE_5P00MV;
- break;
- case 5001 ... 10000:
- ramp_value = BUCK_RAMPRATE_10P00MV;
- break;
- default:
- ramp_value = BUCK_RAMPRATE_10P00MV;
- dev_err(&rdev->dev,
- "%s: ramp_delay: %d not supported, setting 10000mV//us\n",
- rdev->desc->name, ramp_delay);
- }
-
- return regmap_update_bits(rdev->regmap, BD718XX_REG_BUCK1_CTRL + id,
- BUCK_RAMPRATE_MASK, ramp_value << 6);
-}
+static const unsigned int bd718xx_ramp_delay[] = { 10000, 5000, 2500, 1250 };
/* These functions are used when regulators are under HW state machine control.
* We assume PMIC is in RUN state because SW running and able to query the
@@ -378,7 +348,7 @@ static const struct regulator_ops bd71837_buck34_ops_hwctrl = {
.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,
- .set_ramp_delay = bd718xx_buck1234_set_ramp_delay,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
};
/*
@@ -387,7 +357,7 @@ static const struct regulator_ops bd71837_buck34_ops_hwctrl = {
BD718XX_OPS(bd718xx_dvs_buck_regulator_ops, regulator_list_voltage_linear_range,
NULL, regulator_set_voltage_sel_regmap,
regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
- bd718xx_buck1234_set_ramp_delay);
+ /* bd718xx_buck1234_set_ramp_delay */ regulator_set_ramp_delay_regmap);
/*
* BD71837 BUCK1/2/3/4
@@ -645,6 +615,10 @@ static struct bd718xx_regulator_data bd71847_regulators[] = {
.enable_mask = BD718XX_BUCK_EN,
.enable_time = BD71847_BUCK1_STARTUP_TIME,
.owner = THIS_MODULE,
+ .ramp_delay_table = bd718xx_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
+ .ramp_reg = BD718XX_REG_BUCK1_CTRL,
+ .ramp_mask = BUCK_RAMPRATE_MASK,
.of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
@@ -678,6 +652,10 @@ static struct bd718xx_regulator_data bd71847_regulators[] = {
.enable_reg = BD718XX_REG_BUCK2_CTRL,
.enable_mask = BD718XX_BUCK_EN,
.enable_time = BD71847_BUCK2_STARTUP_TIME,
+ .ramp_delay_table = bd718xx_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
+ .ramp_reg = BD718XX_REG_BUCK2_CTRL,
+ .ramp_mask = BUCK_RAMPRATE_MASK,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
@@ -985,6 +963,10 @@ static struct bd718xx_regulator_data bd71837_regulators[] = {
.enable_reg = BD718XX_REG_BUCK1_CTRL,
.enable_mask = BD718XX_BUCK_EN,
.enable_time = BD71837_BUCK1_STARTUP_TIME,
+ .ramp_delay_table = bd718xx_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
+ .ramp_reg = BD718XX_REG_BUCK1_CTRL,
+ .ramp_mask = BUCK_RAMPRATE_MASK,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
@@ -1019,6 +1001,10 @@ static struct bd718xx_regulator_data bd71837_regulators[] = {
.enable_reg = BD718XX_REG_BUCK2_CTRL,
.enable_mask = BD718XX_BUCK_EN,
.enable_time = BD71837_BUCK2_STARTUP_TIME,
+ .ramp_delay_table = bd718xx_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
+ .ramp_reg = BD718XX_REG_BUCK2_CTRL,
+ .ramp_mask = BUCK_RAMPRATE_MASK,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
@@ -1050,6 +1036,10 @@ static struct bd718xx_regulator_data bd71837_regulators[] = {
.enable_reg = BD71837_REG_BUCK3_CTRL,
.enable_mask = BD718XX_BUCK_EN,
.enable_time = BD71837_BUCK3_STARTUP_TIME,
+ .ramp_delay_table = bd718xx_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
+ .ramp_reg = BD71837_REG_BUCK3_CTRL,
+ .ramp_mask = BUCK_RAMPRATE_MASK,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
@@ -1079,6 +1069,10 @@ static struct bd718xx_regulator_data bd71837_regulators[] = {
.enable_reg = BD71837_REG_BUCK4_CTRL,
.enable_mask = BD718XX_BUCK_EN,
.enable_time = BD71837_BUCK4_STARTUP_TIME,
+ .ramp_delay_table = bd718xx_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
+ .ramp_reg = BD71837_REG_BUCK4_CTRL,
+ .ramp_mask = BUCK_RAMPRATE_MASK,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
diff --git a/drivers/regulator/bd9571mwv-regulator.c b/drivers/regulator/bd9571mwv-regulator.c
index 7b0cd08db446..ba020a45f238 100644
--- a/drivers/regulator/bd9571mwv-regulator.c
+++ b/drivers/regulator/bd9571mwv-regulator.c
@@ -125,7 +125,7 @@ static const struct regulator_ops vid_ops = {
static const struct regulator_desc regulators[] = {
BD9571MWV_REG("VD09", "vd09", VD09, avs_ops, 0, 0x7f,
- 0x80, 600000, 10000, 0x3c),
+ 0x6f, 600000, 10000, 0x3c),
BD9571MWV_REG("VD18", "vd18", VD18, vid_ops, BD9571MWV_VD18_VID, 0xf,
16, 1625000, 25000, 0),
BD9571MWV_REG("VD25", "vd25", VD25, vid_ops, BD9571MWV_VD25_VID, 0xf,
@@ -134,7 +134,7 @@ static const struct regulator_desc regulators[] = {
11, 2800000, 100000, 0),
BD9571MWV_REG("DVFS", "dvfs", DVFS, reg_ops,
BD9571MWV_DVFS_MONIVDAC, 0x7f,
- 0x80, 600000, 10000, 0x3c),
+ 0x6f, 600000, 10000, 0x3c),
};
#ifdef CONFIG_PM_SLEEP
@@ -174,7 +174,7 @@ static ssize_t backup_mode_show(struct device *dev,
{
struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", bdreg->bkup_mode_enabled ? "on" : "off");
+ return sysfs_emit(buf, "%s\n", bdreg->bkup_mode_enabled ? "on" : "off");
}
static ssize_t backup_mode_store(struct device *dev,
@@ -301,7 +301,7 @@ static int bd9571mwv_regulator_probe(struct platform_device *pdev)
&config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register %s regulator\n",
- pdev->name);
+ regulators[i].name);
return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/bd9576-regulator.c b/drivers/regulator/bd9576-regulator.c
index a8b5832a5a1b..204a2da054f5 100644
--- a/drivers/regulator/bd9576-regulator.c
+++ b/drivers/regulator/bd9576-regulator.c
@@ -206,7 +206,7 @@ static int bd957x_probe(struct platform_device *pdev)
{
struct regmap *regmap;
struct regulator_config config = { 0 };
- int i, err;
+ int i;
bool vout_mode, ddr_sel;
const struct bd957x_regulator_data *reg_data = &bd9576_regulators[0];
unsigned int num_reg_data = ARRAY_SIZE(bd9576_regulators);
@@ -279,8 +279,7 @@ static int bd957x_probe(struct platform_device *pdev)
break;
default:
dev_err(&pdev->dev, "Unsupported chip type\n");
- err = -EINVAL;
- goto err;
+ return -EINVAL;
}
config.dev = pdev->dev.parent;
@@ -300,8 +299,7 @@ static int bd957x_probe(struct platform_device *pdev)
dev_err(&pdev->dev,
"failed to register %s regulator\n",
desc->name);
- err = PTR_ERR(rdev);
- goto err;
+ return PTR_ERR(rdev);
}
/*
* Clear the VOUT1 GPIO setting - rest of the regulators do not
@@ -310,8 +308,7 @@ static int bd957x_probe(struct platform_device *pdev)
config.ena_gpiod = NULL;
}
-err:
- return err;
+ return 0;
}
static const struct platform_device_id bd957x_pmic_id[] = {
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 16114aea099a..f192bf19492e 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -538,7 +538,8 @@ static int regulator_mode_constrain(struct regulator_dev *rdev,
/* The modes are bitmasks, the most power hungry modes having
* the lowest values. If the requested mode isn't supported
- * try higher modes. */
+ * try higher modes.
+ */
while (*mode) {
if (rdev->constraints->valid_modes_mask & *mode)
return 0;
@@ -931,7 +932,8 @@ static DEVICE_ATTR(bypass, 0444,
regulator_bypass_show, NULL);
/* Calculate the new optimum regulator operating mode based on the new total
- * consumer load. All locks held by caller */
+ * consumer load. All locks held by caller
+ */
static int drms_uA_update(struct regulator_dev *rdev)
{
struct regulator *sibling;
@@ -1219,7 +1221,8 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
int cmax = constraints->max_uV;
/* it's safe to autoconfigure fixed-voltage supplies
- and the constraints are used by list_voltage. */
+ * and the constraints are used by list_voltage.
+ */
if (count == 1 && !cmin) {
cmin = 1;
cmax = INT_MAX;
@@ -1439,6 +1442,8 @@ static int set_machine_constraints(struct regulator_dev *rdev)
if (rdev->constraints->always_on)
rdev->use_count++;
+ } else if (rdev->desc->off_on_delay) {
+ rdev->last_off = ktime_get();
}
print_constraints(rdev);
@@ -2483,29 +2488,15 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
trace_regulator_enable(rdev_get_name(rdev));
- if (rdev->desc->off_on_delay) {
+ if (rdev->desc->off_on_delay && rdev->last_off) {
/* if needed, keep a distance of off_on_delay from last time
* this regulator was disabled.
*/
- unsigned long start_jiffy = jiffies;
- unsigned long intended, max_delay, remaining;
-
- max_delay = usecs_to_jiffies(rdev->desc->off_on_delay);
- intended = rdev->last_off_jiffy + max_delay;
-
- if (time_before(start_jiffy, intended)) {
- /* calc remaining jiffies to deal with one-time
- * timer wrapping.
- * in case of multiple timer wrapping, either it can be
- * detected by out-of-range remaining, or it cannot be
- * detected and we get a penalty of
- * _regulator_enable_delay().
- */
- remaining = intended - start_jiffy;
- if (remaining <= max_delay)
- _regulator_enable_delay(
- jiffies_to_usecs(remaining));
- }
+ ktime_t end = ktime_add_us(rdev->last_off, rdev->desc->off_on_delay);
+ s64 remaining = ktime_us_delta(end, ktime_get());
+
+ if (remaining > 0)
+ _regulator_enable_delay(remaining);
}
if (rdev->ena_pin) {
@@ -2525,7 +2516,8 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
/* Allow the regulator to ramp; it would be useful to extend
* this for bulk operations so that the regulators can ramp
- * together. */
+ * together.
+ */
trace_regulator_enable_delay(rdev_get_name(rdev));
/* If poll_enabled_time is set, poll upto the delay calculated
@@ -2650,7 +2642,10 @@ static int _regulator_enable(struct regulator *regulator)
goto err_disable_supply;
if (rdev->use_count == 0) {
- /* The regulator may on if it's not switchable or left on */
+ /*
+ * The regulator may already be enabled if it's not switchable
+ * or was left on
+ */
ret = _regulator_is_enabled(rdev);
if (ret == -EINVAL || ret == 0) {
if (!regulator_ops_is_valid(rdev,
@@ -2731,11 +2726,8 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
return ret;
}
- /* cares about last_off_jiffy only if off_on_delay is required by
- * device.
- */
if (rdev->desc->off_on_delay)
- rdev->last_off_jiffy = jiffies;
+ rdev->last_off = ktime_get();
trace_regulator_disable_complete(rdev_get_name(rdev));
@@ -5337,10 +5329,12 @@ regulator_register(const struct regulator_desc *regulator_desc,
ret = set_machine_constraints(rdev);
if (ret == -EPROBE_DEFER) {
/* Regulator might be in bypass mode and so needs its supply
- * to set the constraints */
+ * to set the constraints
+ */
/* FIXME: this currently triggers a chicken-and-egg problem
* when creating -SUPPLY symlink in sysfs to a regulator
- * that is just being created */
+ * that is just being created
+ */
rdev_dbg(rdev, "will resolve supply early: %s\n",
rdev->supply_name);
ret = regulator_resolve_supply(rdev);
@@ -5899,7 +5893,8 @@ static int regulator_late_cleanup(struct device *dev, void *data)
if (have_full_constraints()) {
/* We log since this may kill the system if it goes
- * wrong. */
+ * wrong.
+ */
rdev_info(rdev, "disabling\n");
ret = _regulator_do_disable(rdev);
if (ret != 0)
diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c
index a2ede7d7897e..08cbf688e14d 100644
--- a/drivers/regulator/da9121-regulator.c
+++ b/drivers/regulator/da9121-regulator.c
@@ -40,6 +40,7 @@ struct da9121 {
unsigned int passive_delay;
int chip_irq;
int variant_id;
+ int subvariant_id;
};
/* Define ranges for different variants, enabling translation to/from
@@ -812,7 +813,6 @@ static struct regmap_config da9121_2ch_regmap_config = {
static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip)
{
u32 device_id;
- u8 chip_id = chip->variant_id;
u32 variant_id;
u8 variant_mrc, variant_vrc;
char *type;
@@ -839,22 +839,34 @@ static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip)
variant_vrc = variant_id & DA9121_MASK_OTP_VARIANT_ID_VRC;
- switch (variant_vrc) {
- case DA9121_VARIANT_VRC:
- type = "DA9121/DA9130";
- config_match = (chip_id == DA9121_TYPE_DA9121_DA9130);
+ switch (chip->subvariant_id) {
+ case DA9121_SUBTYPE_DA9121:
+ type = "DA9121";
+ config_match = (variant_vrc == DA9121_VARIANT_VRC);
break;
- case DA9220_VARIANT_VRC:
- type = "DA9220/DA9132";
- config_match = (chip_id == DA9121_TYPE_DA9220_DA9132);
+ case DA9121_SUBTYPE_DA9130:
+ type = "DA9130";
+ config_match = (variant_vrc == DA9130_VARIANT_VRC);
break;
- case DA9122_VARIANT_VRC:
- type = "DA9122/DA9131";
- config_match = (chip_id == DA9121_TYPE_DA9122_DA9131);
+ case DA9121_SUBTYPE_DA9220:
+ type = "DA9220";
+ config_match = (variant_vrc == DA9220_VARIANT_VRC);
break;
- case DA9217_VARIANT_VRC:
+ case DA9121_SUBTYPE_DA9132:
+ type = "DA9132";
+ config_match = (variant_vrc == DA9132_VARIANT_VRC);
+ break;
+ case DA9121_SUBTYPE_DA9122:
+ type = "DA9122";
+ config_match = (variant_vrc == DA9122_VARIANT_VRC);
+ break;
+ case DA9121_SUBTYPE_DA9131:
+ type = "DA9131";
+ config_match = (variant_vrc == DA9131_VARIANT_VRC);
+ break;
+ case DA9121_SUBTYPE_DA9217:
type = "DA9217";
- config_match = (chip_id == DA9121_TYPE_DA9217);
+ config_match = (variant_vrc == DA9217_VARIANT_VRC);
break;
default:
type = "Unknown";
@@ -892,15 +904,27 @@ static int da9121_assign_chip_model(struct i2c_client *i2c,
chip->dev = &i2c->dev;
- switch (chip->variant_id) {
- case DA9121_TYPE_DA9121_DA9130:
- fallthrough;
- case DA9121_TYPE_DA9217:
+ /* Use configured subtype to select the regulator descriptor index and
+ * register map, common to both consumer and automotive grade variants
+ */
+ switch (chip->subvariant_id) {
+ case DA9121_SUBTYPE_DA9121:
+ case DA9121_SUBTYPE_DA9130:
+ chip->variant_id = DA9121_TYPE_DA9121_DA9130;
regmap = &da9121_1ch_regmap_config;
break;
- case DA9121_TYPE_DA9122_DA9131:
- fallthrough;
- case DA9121_TYPE_DA9220_DA9132:
+ case DA9121_SUBTYPE_DA9217:
+ chip->variant_id = DA9121_TYPE_DA9217;
+ regmap = &da9121_1ch_regmap_config;
+ break;
+ case DA9121_SUBTYPE_DA9122:
+ case DA9121_SUBTYPE_DA9131:
+ chip->variant_id = DA9121_TYPE_DA9122_DA9131;
+ regmap = &da9121_2ch_regmap_config;
+ break;
+ case DA9121_SUBTYPE_DA9220:
+ case DA9121_SUBTYPE_DA9132:
+ chip->variant_id = DA9121_TYPE_DA9220_DA9132;
regmap = &da9121_2ch_regmap_config;
break;
}
@@ -975,13 +999,13 @@ regmap_error:
}
static const struct of_device_id da9121_dt_ids[] = {
- { .compatible = "dlg,da9121", .data = (void *) DA9121_TYPE_DA9121_DA9130 },
- { .compatible = "dlg,da9130", .data = (void *) DA9121_TYPE_DA9121_DA9130 },
- { .compatible = "dlg,da9217", .data = (void *) DA9121_TYPE_DA9217 },
- { .compatible = "dlg,da9122", .data = (void *) DA9121_TYPE_DA9122_DA9131 },
- { .compatible = "dlg,da9131", .data = (void *) DA9121_TYPE_DA9122_DA9131 },
- { .compatible = "dlg,da9220", .data = (void *) DA9121_TYPE_DA9220_DA9132 },
- { .compatible = "dlg,da9132", .data = (void *) DA9121_TYPE_DA9220_DA9132 },
+ { .compatible = "dlg,da9121", .data = (void *) DA9121_SUBTYPE_DA9121 },
+ { .compatible = "dlg,da9130", .data = (void *) DA9121_SUBTYPE_DA9130 },
+ { .compatible = "dlg,da9217", .data = (void *) DA9121_SUBTYPE_DA9217 },
+ { .compatible = "dlg,da9122", .data = (void *) DA9121_SUBTYPE_DA9122 },
+ { .compatible = "dlg,da9131", .data = (void *) DA9121_SUBTYPE_DA9131 },
+ { .compatible = "dlg,da9220", .data = (void *) DA9121_SUBTYPE_DA9220 },
+ { .compatible = "dlg,da9132", .data = (void *) DA9121_SUBTYPE_DA9132 },
{ }
};
MODULE_DEVICE_TABLE(of, da9121_dt_ids);
@@ -1011,7 +1035,7 @@ static int da9121_i2c_probe(struct i2c_client *i2c,
}
chip->pdata = i2c->dev.platform_data;
- chip->variant_id = da9121_of_get_id(&i2c->dev);
+ chip->subvariant_id = da9121_of_get_id(&i2c->dev);
ret = da9121_assign_chip_model(i2c, chip);
if (ret < 0)
diff --git a/drivers/regulator/da9121-regulator.h b/drivers/regulator/da9121-regulator.h
index 3c34cb889ca8..357f416e17c1 100644
--- a/drivers/regulator/da9121-regulator.h
+++ b/drivers/regulator/da9121-regulator.h
@@ -29,6 +29,16 @@ enum da9121_variant {
DA9121_TYPE_DA9217
};
+enum da9121_subvariant {
+ DA9121_SUBTYPE_DA9121,
+ DA9121_SUBTYPE_DA9130,
+ DA9121_SUBTYPE_DA9220,
+ DA9121_SUBTYPE_DA9132,
+ DA9121_SUBTYPE_DA9122,
+ DA9121_SUBTYPE_DA9131,
+ DA9121_SUBTYPE_DA9217
+};
+
/* Minimum, maximum and default polling millisecond periods are provided
* here as an example. It is expected that any final implementation will
* include a modification of these settings to match the required
@@ -279,6 +289,9 @@ enum da9121_variant {
#define DA9220_VARIANT_VRC 0x0
#define DA9122_VARIANT_VRC 0x2
#define DA9217_VARIANT_VRC 0x7
+#define DA9130_VARIANT_VRC 0x0
+#define DA9131_VARIANT_VRC 0x1
+#define DA9132_VARIANT_VRC 0x2
/* DA9121_REG_OTP_CUSTOMER_ID */
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
index aa426183b6a1..f3918f03aaf3 100644
--- a/drivers/regulator/fan53555.c
+++ b/drivers/regulator/fan53555.c
@@ -24,6 +24,12 @@
/* Voltage setting */
#define FAN53555_VSEL0 0x00
#define FAN53555_VSEL1 0x01
+
+#define TCS4525_VSEL0 0x11
+#define TCS4525_VSEL1 0x10
+#define TCS4525_TIME 0x13
+#define TCS4525_COMMAND 0x14
+
/* Control register */
#define FAN53555_CONTROL 0x02
/* IC Type */
@@ -49,11 +55,20 @@
#define FAN53555_NVOLTAGES 64 /* Numbers of voltages */
#define FAN53526_NVOLTAGES 128
+#define TCS4525_NVOLTAGES 127 /* Numbers of voltages */
+
+#define TCS_VSEL_NSEL_MASK 0x7f
+#define TCS_VSEL0_MODE (1 << 7)
+#define TCS_VSEL1_MODE (1 << 6)
+
+#define TCS_SLEW_SHIFT 3
+#define TCS_SLEW_MASK (0x3 < 3)
enum fan53555_vendor {
FAN53526_VENDOR_FAIRCHILD = 0,
FAN53555_VENDOR_FAIRCHILD,
FAN53555_VENDOR_SILERGY,
+ FAN53555_VENDOR_TCS,
};
enum {
@@ -106,6 +121,11 @@ struct fan53555_device_info {
unsigned int mode_mask;
/* Sleep voltage cache */
unsigned int sleep_vol_cache;
+ /* Slew rate */
+ unsigned int slew_reg;
+ unsigned int slew_mask;
+ unsigned int slew_shift;
+ unsigned int slew_rate;
};
static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV)
@@ -189,13 +209,37 @@ static const int slew_rates[] = {
500,
};
+static const int tcs_slew_rates[] = {
+ 18700,
+ 9300,
+ 4600,
+ 2300,
+};
+
static int fan53555_set_ramp(struct regulator_dev *rdev, int ramp)
{
struct fan53555_device_info *di = rdev_get_drvdata(rdev);
int regval = -1, i;
+ const int *slew_rate_t;
+ int slew_rate_n;
- for (i = 0; i < ARRAY_SIZE(slew_rates); i++) {
- if (ramp <= slew_rates[i])
+ switch (di->vendor) {
+ case FAN53526_VENDOR_FAIRCHILD:
+ case FAN53555_VENDOR_FAIRCHILD:
+ case FAN53555_VENDOR_SILERGY:
+ slew_rate_t = slew_rates;
+ slew_rate_n = ARRAY_SIZE(slew_rates);
+ break;
+ case FAN53555_VENDOR_TCS:
+ slew_rate_t = tcs_slew_rates;
+ slew_rate_n = ARRAY_SIZE(tcs_slew_rates);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (i = 0; i < slew_rate_n; i++) {
+ if (ramp <= slew_rate_t[i])
regval = i;
else
break;
@@ -206,8 +250,8 @@ static int fan53555_set_ramp(struct regulator_dev *rdev, int ramp)
return -EINVAL;
}
- return regmap_update_bits(rdev->regmap, FAN53555_CONTROL,
- CTL_SLEW_MASK, regval << CTL_SLEW_SHIFT);
+ return regmap_update_bits(rdev->regmap, di->slew_reg,
+ di->slew_mask, regval << di->slew_shift);
}
static const struct regulator_ops fan53555_regulator_ops = {
@@ -292,7 +336,9 @@ static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di)
"Chip ID %d not supported!\n", di->chip_id);
return -EINVAL;
}
-
+ di->slew_reg = FAN53555_CONTROL;
+ di->slew_mask = CTL_SLEW_MASK;
+ di->slew_shift = CTL_SLEW_SHIFT;
di->vsel_count = FAN53555_NVOLTAGES;
return 0;
@@ -312,12 +358,29 @@ static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di)
"Chip ID %d not supported!\n", di->chip_id);
return -EINVAL;
}
-
+ di->slew_reg = FAN53555_CONTROL;
+ di->slew_reg = FAN53555_CONTROL;
+ di->slew_mask = CTL_SLEW_MASK;
+ di->slew_shift = CTL_SLEW_SHIFT;
di->vsel_count = FAN53555_NVOLTAGES;
return 0;
}
+static int fan53555_voltages_setup_tcs(struct fan53555_device_info *di)
+{
+ di->slew_reg = TCS4525_TIME;
+ di->slew_mask = TCS_SLEW_MASK;
+ di->slew_shift = TCS_SLEW_MASK;
+
+ /* Init voltage range and step */
+ di->vsel_min = 600000;
+ di->vsel_step = 6250;
+ di->vsel_count = TCS4525_NVOLTAGES;
+
+ return 0;
+}
+
/* For 00,01,03,05 options:
* VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V.
* For 04 option:
@@ -329,17 +392,41 @@ static int fan53555_device_setup(struct fan53555_device_info *di,
int ret = 0;
/* Setup voltage control register */
- switch (pdata->sleep_vsel_id) {
- case FAN53555_VSEL_ID_0:
- di->sleep_reg = FAN53555_VSEL0;
- di->vol_reg = FAN53555_VSEL1;
+ switch (di->vendor) {
+ case FAN53526_VENDOR_FAIRCHILD:
+ case FAN53555_VENDOR_FAIRCHILD:
+ case FAN53555_VENDOR_SILERGY:
+ switch (pdata->sleep_vsel_id) {
+ case FAN53555_VSEL_ID_0:
+ di->sleep_reg = FAN53555_VSEL0;
+ di->vol_reg = FAN53555_VSEL1;
+ break;
+ case FAN53555_VSEL_ID_1:
+ di->sleep_reg = FAN53555_VSEL1;
+ di->vol_reg = FAN53555_VSEL0;
+ break;
+ default:
+ dev_err(di->dev, "Invalid VSEL ID!\n");
+ return -EINVAL;
+ }
break;
- case FAN53555_VSEL_ID_1:
- di->sleep_reg = FAN53555_VSEL1;
- di->vol_reg = FAN53555_VSEL0;
+ case FAN53555_VENDOR_TCS:
+ switch (pdata->sleep_vsel_id) {
+ case FAN53555_VSEL_ID_0:
+ di->sleep_reg = TCS4525_VSEL0;
+ di->vol_reg = TCS4525_VSEL1;
+ break;
+ case FAN53555_VSEL_ID_1:
+ di->sleep_reg = TCS4525_VSEL1;
+ di->vol_reg = TCS4525_VSEL0;
+ break;
+ default:
+ dev_err(di->dev, "Invalid VSEL ID!\n");
+ return -EINVAL;
+ }
break;
default:
- dev_err(di->dev, "Invalid VSEL ID!\n");
+ dev_err(di->dev, "vendor %d not supported!\n", di->vendor);
return -EINVAL;
}
@@ -362,6 +449,18 @@ static int fan53555_device_setup(struct fan53555_device_info *di,
di->mode_reg = di->vol_reg;
di->mode_mask = VSEL_MODE;
break;
+ case FAN53555_VENDOR_TCS:
+ di->mode_reg = TCS4525_COMMAND;
+
+ switch (pdata->sleep_vsel_id) {
+ case FAN53555_VSEL_ID_0:
+ di->mode_mask = TCS_VSEL1_MODE;
+ break;
+ case FAN53555_VSEL_ID_1:
+ di->mode_mask = TCS_VSEL0_MODE;
+ break;
+ }
+ break;
default:
dev_err(di->dev, "vendor %d not supported!\n", di->vendor);
return -EINVAL;
@@ -378,6 +477,9 @@ static int fan53555_device_setup(struct fan53555_device_info *di,
case FAN53555_VENDOR_SILERGY:
ret = fan53555_voltages_setup_silergy(di);
break;
+ case FAN53555_VENDOR_TCS:
+ ret = fan53555_voltages_setup_tcs(di);
+ break;
default:
dev_err(di->dev, "vendor %d not supported!\n", di->vendor);
return -EINVAL;
@@ -449,6 +551,9 @@ static const struct of_device_id __maybe_unused fan53555_dt_ids[] = {
}, {
.compatible = "silergy,syr828",
.data = (void *)FAN53555_VENDOR_SILERGY,
+ }, {
+ .compatible = "tcs,tcs4525",
+ .data = (void *)FAN53555_VENDOR_TCS
},
{ }
};
@@ -554,6 +659,9 @@ static const struct i2c_device_id fan53555_id[] = {
}, {
.name = "syr828",
.driver_data = FAN53555_VENDOR_SILERGY
+ }, {
+ .name = "tcs4525",
+ .driver_data = FAN53555_VENDOR_TCS
},
{ },
};
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
index f42b394a0c46..0e16e31c968f 100644
--- a/drivers/regulator/helpers.c
+++ b/drivers/regulator/helpers.c
@@ -509,6 +509,33 @@ int regulator_map_voltage_pickable_linear_range(struct regulator_dev *rdev,
EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range);
/**
+ * regulator_desc_list_voltage_linear - List voltages with simple calculation
+ *
+ * @desc: Regulator desc for regulator which volatges are to be listed
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with a simple linear mapping between voltages and
+ * selectors can set min_uV and uV_step in the regulator descriptor
+ * and then use this function prior regulator registration to list
+ * the voltages. This is useful when voltages need to be listed during
+ * device-tree parsing.
+ */
+int regulator_desc_list_voltage_linear(const struct regulator_desc *desc,
+ unsigned int selector)
+{
+ if (selector >= desc->n_voltages)
+ return -EINVAL;
+
+ if (selector < desc->linear_min_sel)
+ return 0;
+
+ selector -= desc->linear_min_sel;
+
+ return desc->min_uV + (desc->uV_step * selector);
+}
+EXPORT_SYMBOL_GPL(regulator_desc_list_voltage_linear);
+
+/**
* regulator_list_voltage_linear - List voltages with simple calculation
*
* @rdev: Regulator device
@@ -521,14 +548,7 @@ EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range);
int regulator_list_voltage_linear(struct regulator_dev *rdev,
unsigned int selector)
{
- if (selector >= rdev->desc->n_voltages)
- return -EINVAL;
- if (selector < rdev->desc->linear_min_sel)
- return 0;
-
- selector -= rdev->desc->linear_min_sel;
-
- return rdev->desc->min_uV + (rdev->desc->uV_step * selector);
+ return regulator_desc_list_voltage_linear(rdev->desc, selector);
}
EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
@@ -881,3 +901,68 @@ bool regulator_is_equal(struct regulator *reg1, struct regulator *reg2)
return reg1->rdev == reg2->rdev;
}
EXPORT_SYMBOL_GPL(regulator_is_equal);
+
+static int find_closest_bigger(unsigned int target, const unsigned int *table,
+ unsigned int num_sel, unsigned int *sel)
+{
+ unsigned int s, tmp, max, maxsel = 0;
+ bool found = false;
+
+ max = table[0];
+
+ for (s = 0; s < num_sel; s++) {
+ if (table[s] > max) {
+ max = table[s];
+ maxsel = s;
+ }
+ if (table[s] >= target) {
+ if (!found || table[s] - target < tmp - target) {
+ tmp = table[s];
+ *sel = s;
+ found = true;
+ if (tmp == target)
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ *sel = maxsel;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * regulator_set_ramp_delay_regmap - set_ramp_delay() helper
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the ramp_reg
+ * and ramp_mask fields in their descriptor and then use this as their
+ * set_ramp_delay operation, saving some code.
+ */
+int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay)
+{
+ int ret;
+ unsigned int sel;
+
+ if (!rdev->desc->n_ramp_values)
+ return -EINVAL;
+
+ ret = find_closest_bigger(ramp_delay, rdev->desc->ramp_delay_table,
+ rdev->desc->n_ramp_values, &sel);
+
+ if (ret) {
+ dev_warn(rdev_get_dev(rdev),
+ "Can't set ramp-delay %u, setting %u\n", ramp_delay,
+ rdev->desc->ramp_delay_table[sel]);
+ }
+
+ sel <<= ffs(rdev->desc->ramp_mask) - 1;
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->ramp_reg,
+ rdev->desc->ramp_mask, sel);
+}
+EXPORT_SYMBOL_GPL(regulator_set_ramp_delay_regmap);
diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c
new file mode 100644
index 000000000000..f6a14e9c3cbf
--- /dev/null
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Device driver for regulators in Hisi IC
+//
+// Copyright (c) 2013 Linaro Ltd.
+// Copyright (c) 2011 Hisilicon.
+// Copyright (c) 2020-2021 Huawei Technologies Co., Ltd
+//
+// Guodong Xu <guodong.xu@linaro.org>
+
+#include <linux/delay.h>
+#include <linux/mfd/hi6421-spmi-pmic.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/spmi.h>
+
+struct hi6421_spmi_reg_info {
+ struct regulator_desc desc;
+ struct hi6421_spmi_pmic *pmic;
+ u8 eco_mode_mask;
+ u32 eco_uA;
+
+ /* Serialize regulator enable logic */
+ struct mutex enable_mutex;
+};
+
+static const unsigned int ldo3_voltages[] = {
+ 1500000, 1550000, 1600000, 1650000,
+ 1700000, 1725000, 1750000, 1775000,
+ 1800000, 1825000, 1850000, 1875000,
+ 1900000, 1925000, 1950000, 2000000
+};
+
+static const unsigned int ldo4_voltages[] = {
+ 1725000, 1750000, 1775000, 1800000,
+ 1825000, 1850000, 1875000, 1900000
+};
+
+static const unsigned int ldo9_voltages[] = {
+ 1750000, 1800000, 1825000, 2800000,
+ 2850000, 2950000, 3000000, 3300000
+};
+
+static const unsigned int ldo15_voltages[] = {
+ 1800000, 1850000, 2400000, 2600000,
+ 2700000, 2850000, 2950000, 3000000
+};
+
+static const unsigned int ldo17_voltages[] = {
+ 2500000, 2600000, 2700000, 2800000,
+ 3000000, 3100000, 3200000, 3300000
+};
+
+static const unsigned int ldo34_voltages[] = {
+ 2600000, 2700000, 2800000, 2900000,
+ 3000000, 3100000, 3200000, 3300000
+};
+
+/**
+ * HI6421V600_LDO() - specify a LDO power line
+ * @_id: LDO id name string
+ * @vtable: voltage table
+ * @ereg: enable register
+ * @emask: enable mask
+ * @vreg: voltage select register
+ * @odelay: off/on delay time in uS
+ * @etime: enable time in uS
+ * @ecomask: eco mode mask
+ * @ecoamp: eco mode load uppler limit in uA
+ */
+#define HI6421V600_LDO(_id, vtable, ereg, emask, vreg, \
+ odelay, etime, ecomask, ecoamp) \
+ [HI6421V600_##_id] = { \
+ .desc = { \
+ .name = #_id, \
+ .of_match = of_match_ptr(#_id), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .ops = &hi6421_spmi_ldo_rops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = HI6421V600_##_id, \
+ .owner = THIS_MODULE, \
+ .volt_table = vtable, \
+ .n_voltages = ARRAY_SIZE(vtable), \
+ .vsel_mask = (1 << (ARRAY_SIZE(vtable) - 1)) - 1, \
+ .vsel_reg = vreg, \
+ .enable_reg = ereg, \
+ .enable_mask = emask, \
+ .enable_time = etime, \
+ .ramp_delay = etime, \
+ .off_on_delay = odelay, \
+ }, \
+ .eco_mode_mask = ecomask, \
+ .eco_uA = ecoamp, \
+ }
+
+static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev)
+{
+ struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev);
+ struct hi6421_spmi_pmic *pmic = sreg->pmic;
+ int ret;
+
+ /* cannot enable more than one regulator at one time */
+ mutex_lock(&sreg->enable_mutex);
+
+ ret = regmap_update_bits(pmic->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask,
+ rdev->desc->enable_mask);
+
+ /* Avoid powering up multiple devices at the same time */
+ usleep_range(rdev->desc->off_on_delay, rdev->desc->off_on_delay + 60);
+
+ mutex_unlock(&sreg->enable_mutex);
+
+ return ret;
+}
+
+static int hi6421_spmi_regulator_disable(struct regulator_dev *rdev)
+{
+ struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev);
+ struct hi6421_spmi_pmic *pmic = sreg->pmic;
+
+ return regmap_update_bits(pmic->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, 0);
+}
+
+static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev)
+{
+ struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev);
+ struct hi6421_spmi_pmic *pmic = sreg->pmic;
+ u32 reg_val;
+
+ regmap_read(pmic->regmap, rdev->desc->enable_reg, &reg_val);
+
+ if (reg_val & sreg->eco_mode_mask)
+ return REGULATOR_MODE_IDLE;
+
+ return REGULATOR_MODE_NORMAL;
+}
+
+static int hi6421_spmi_regulator_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev);
+ struct hi6421_spmi_pmic *pmic = sreg->pmic;
+ u32 val;
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ val = 0;
+ break;
+ case REGULATOR_MODE_IDLE:
+ val = sreg->eco_mode_mask << (ffs(sreg->eco_mode_mask) - 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(pmic->regmap, rdev->desc->enable_reg,
+ sreg->eco_mode_mask, val);
+}
+
+static unsigned int
+hi6421_spmi_regulator_get_optimum_mode(struct regulator_dev *rdev,
+ int input_uV, int output_uV,
+ int load_uA)
+{
+ struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev);
+
+ if (!sreg->eco_uA || ((unsigned int)load_uA > sreg->eco_uA))
+ return REGULATOR_MODE_NORMAL;
+
+ return REGULATOR_MODE_IDLE;
+}
+
+static const struct regulator_ops hi6421_spmi_ldo_rops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = hi6421_spmi_regulator_enable,
+ .disable = hi6421_spmi_regulator_disable,
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_iterate,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_mode = hi6421_spmi_regulator_get_mode,
+ .set_mode = hi6421_spmi_regulator_set_mode,
+ .get_optimum_mode = hi6421_spmi_regulator_get_optimum_mode,
+};
+
+/* HI6421v600 regulators with known registers */
+enum hi6421_spmi_regulator_id {
+ HI6421V600_LDO3,
+ HI6421V600_LDO4,
+ HI6421V600_LDO9,
+ HI6421V600_LDO15,
+ HI6421V600_LDO16,
+ HI6421V600_LDO17,
+ HI6421V600_LDO33,
+ HI6421V600_LDO34,
+};
+
+static struct hi6421_spmi_reg_info regulator_info[] = {
+ HI6421V600_LDO(LDO3, ldo3_voltages,
+ 0x16, 0x01, 0x51,
+ 20000, 120,
+ 0, 0),
+ HI6421V600_LDO(LDO4, ldo4_voltages,
+ 0x17, 0x01, 0x52,
+ 20000, 120,
+ 0x10, 10000),
+ HI6421V600_LDO(LDO9, ldo9_voltages,
+ 0x1c, 0x01, 0x57,
+ 20000, 360,
+ 0x10, 10000),
+ HI6421V600_LDO(LDO15, ldo15_voltages,
+ 0x21, 0x01, 0x5c,
+ 20000, 360,
+ 0x10, 10000),
+ HI6421V600_LDO(LDO16, ldo15_voltages,
+ 0x22, 0x01, 0x5d,
+ 20000, 360,
+ 0x10, 10000),
+ HI6421V600_LDO(LDO17, ldo17_voltages,
+ 0x23, 0x01, 0x5e,
+ 20000, 120,
+ 0x10, 10000),
+ HI6421V600_LDO(LDO33, ldo17_voltages,
+ 0x32, 0x01, 0x6d,
+ 20000, 120,
+ 0, 0),
+ HI6421V600_LDO(LDO34, ldo34_voltages,
+ 0x33, 0x01, 0x6e,
+ 20000, 120,
+ 0, 0),
+};
+
+static int hi6421_spmi_regulator_probe(struct platform_device *pdev)
+{
+ struct device *pmic_dev = pdev->dev.parent;
+ struct regulator_config config = { };
+ struct hi6421_spmi_reg_info *sreg;
+ struct hi6421_spmi_reg_info *info;
+ struct device *dev = &pdev->dev;
+ struct hi6421_spmi_pmic *pmic;
+ struct regulator_dev *rdev;
+ int i;
+
+ /*
+ * This driver is meant to be called by hi6421-spmi-core,
+ * which should first set drvdata. If this doesn't happen, hit
+ * a warn on and return.
+ */
+ pmic = dev_get_drvdata(pmic_dev);
+ if (WARN_ON(!pmic))
+ return -ENODEV;
+
+ sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL);
+ if (!sreg)
+ return -ENOMEM;
+
+ sreg->pmic = pmic;
+ mutex_init(&sreg->enable_mutex);
+
+ for (i = 0; i < ARRAY_SIZE(regulator_info); i++) {
+ info = &regulator_info[i];
+
+ config.dev = pdev->dev.parent;
+ config.driver_data = sreg;
+ config.regmap = pmic->regmap;
+
+ rdev = devm_regulator_register(dev, &info->desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(dev, "failed to register %s\n",
+ info->desc.name);
+ return PTR_ERR(rdev);
+ }
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id hi6421_spmi_regulator_table[] = {
+ { .name = "hi6421v600-regulator" },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, hi6421_spmi_regulator_table);
+
+static struct platform_driver hi6421_spmi_regulator_driver = {
+ .id_table = hi6421_spmi_regulator_table,
+ .driver = {
+ .name = "hi6421v600-regulator",
+ },
+ .probe = hi6421_spmi_regulator_probe,
+};
+module_platform_driver(hi6421_spmi_regulator_driver);
+
+MODULE_DESCRIPTION("Hi6421v600 SPMI regulator driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/regulator/mt6360-regulator.c b/drivers/regulator/mt6360-regulator.c
index 15308ee29c13..4d34be94d166 100644
--- a/drivers/regulator/mt6360-regulator.c
+++ b/drivers/regulator/mt6360-regulator.c
@@ -380,10 +380,8 @@ static int mt6360_regulator_irq_register(struct platform_device *pdev,
const struct mt6360_irq_mapping *irq_desc = tbls + i;
irq = platform_get_irq_byname(pdev, irq_desc->name);
- if (irq < 0) {
- dev_err(&pdev->dev, "Fail to get %s irq\n", irq_desc->name);
+ if (irq < 0)
return irq;
- }
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, irq_desc->handler, 0,
irq_desc->name, rdev);
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 564f928eb1db..49f6c05fee34 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -422,7 +422,11 @@ device_node *regulator_of_get_init_node(struct device *dev,
if (!strcmp(desc->of_match, name)) {
of_node_put(search);
- return of_node_get(child);
+ /*
+ * 'of_node_get(child)' is already performed by the
+ * for_each loop.
+ */
+ return child;
}
}
diff --git a/drivers/regulator/pf8x00-regulator.c b/drivers/regulator/pf8x00-regulator.c
index 9b28bd63208d..5d319fb81288 100644
--- a/drivers/regulator/pf8x00-regulator.c
+++ b/drivers/regulator/pf8x00-regulator.c
@@ -359,6 +359,7 @@ static const struct regulator_ops pf8x00_buck7_ops = {
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.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,
.get_current_limit = regulator_get_current_limit_regmap,
diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c
index 65a108c9121f..22fec370fa61 100644
--- a/drivers/regulator/qcom-rpmh-regulator.c
+++ b/drivers/regulator/qcom-rpmh-regulator.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+// Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -723,6 +723,15 @@ static const struct rpmh_vreg_hw_data pmic5_ftsmps510 = {
.of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
};
+static const struct rpmh_vreg_hw_data pmic5_ftsmps520 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 263, 4000),
+ .n_voltages = 264,
+ .pmic_mode_map = pmic_mode_map_pmic5_smps,
+ .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
static const struct rpmh_vreg_hw_data pmic5_hfsmps515 = {
.regulator_type = VRM,
.ops = &rpmh_regulator_vrm_ops,
@@ -1033,6 +1042,49 @@ static const struct rpmh_vreg_init_data pmx55_vreg_data[] = {
{},
};
+static const struct rpmh_vreg_init_data pm7325_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps520, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps520, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps520, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps520, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps520, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l4-l12-l15"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l7"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l1-l4-l12-l15"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9-l10"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l2-l7"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9-l10"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l6-l9-l10"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l1-l4-l12-l15"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic5_nldo, "vdd-l13"),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14-l16"),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l1-l4-l12-l15"),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo, "vdd-l14-l16"),
+ RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
+ RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
+ RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
+};
+
+static const struct rpmh_vreg_init_data pmr735a_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps520, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_hfsmps510, "vdd-s3"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l2"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l1-l2"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo_lv, "vdd-l4"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-bob"),
+};
+
static int rpmh_regulator_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1127,6 +1179,14 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = {
.compatible = "qcom,pmx55-rpmh-regulators",
.data = pmx55_vreg_data,
},
+ {
+ .compatible = "qcom,pm7325-rpmh-regulators",
+ .data = pm7325_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmr735a-rpmh-regulators",
+ .data = pmr735a_vreg_data,
+ },
{}
};
MODULE_DEVICE_TABLE(of, rpmh_regulator_match_table);
diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c
index e62e1d72d943..95677c51c1fa 100644
--- a/drivers/regulator/qcom_spmi-regulator.c
+++ b/drivers/regulator/qcom_spmi-regulator.c
@@ -5,6 +5,7 @@
#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/devm-helpers.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
@@ -1522,10 +1523,12 @@ static const struct spmi_regulator_mapping supported_regulators[] = {
SPMI_VREG(ULT_LDO, N600_ST, 0, INF, ULT_LDO, ult_ldo, ult_nldo, 10000),
SPMI_VREG(ULT_LDO, N900_ST, 0, INF, ULT_LDO, ult_ldo, ult_nldo, 10000),
SPMI_VREG(ULT_LDO, N1200_ST, 0, INF, ULT_LDO, ult_ldo, ult_nldo, 10000),
+ SPMI_VREG(ULT_LDO, LV_P50, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000),
SPMI_VREG(ULT_LDO, LV_P150, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000),
SPMI_VREG(ULT_LDO, LV_P300, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000),
SPMI_VREG(ULT_LDO, LV_P450, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000),
SPMI_VREG(ULT_LDO, P600, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000),
+ SPMI_VREG(ULT_LDO, P300, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000),
SPMI_VREG(ULT_LDO, P150, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000),
SPMI_VREG(ULT_LDO, P50, 0, INF, ULT_LDO, ult_ldo, ult_pldo, 5000),
};
@@ -1842,7 +1845,10 @@ static int spmi_regulator_of_parse(struct device_node *node,
return ret;
}
- INIT_DELAYED_WORK(&vreg->ocp_work, spmi_regulator_vs_ocp_work);
+ ret = devm_delayed_work_autocancel(dev, &vreg->ocp_work,
+ spmi_regulator_vs_ocp_work);
+ if (ret)
+ return ret;
}
return 0;
@@ -2157,10 +2163,8 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev)
vreg->regmap = regmap;
if (reg->ocp) {
vreg->ocp_irq = platform_get_irq_byname(pdev, reg->ocp);
- if (vreg->ocp_irq < 0) {
- ret = vreg->ocp_irq;
- goto err;
- }
+ if (vreg->ocp_irq < 0)
+ return vreg->ocp_irq;
}
vreg->desc.id = -1;
vreg->desc.owner = THIS_MODULE;
@@ -2203,8 +2207,7 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev)
rdev = devm_regulator_register(dev, &vreg->desc, &config);
if (IS_ERR(rdev)) {
dev_err(dev, "failed to register %s\n", name);
- ret = PTR_ERR(rdev);
- goto err;
+ return PTR_ERR(rdev);
}
INIT_LIST_HEAD(&vreg->node);
@@ -2212,24 +2215,6 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev)
}
return 0;
-
-err:
- list_for_each_entry(vreg, vreg_list, node)
- if (vreg->ocp_irq)
- cancel_delayed_work_sync(&vreg->ocp_work);
- return ret;
-}
-
-static int qcom_spmi_regulator_remove(struct platform_device *pdev)
-{
- struct spmi_regulator *vreg;
- struct list_head *vreg_list = platform_get_drvdata(pdev);
-
- list_for_each_entry(vreg, vreg_list, node)
- if (vreg->ocp_irq)
- cancel_delayed_work_sync(&vreg->ocp_work);
-
- return 0;
}
static struct platform_driver qcom_spmi_regulator_driver = {
@@ -2238,7 +2223,6 @@ static struct platform_driver qcom_spmi_regulator_driver = {
.of_match_table = qcom_spmi_regulator_match,
},
.probe = qcom_spmi_regulator_probe,
- .remove = qcom_spmi_regulator_remove,
};
module_platform_driver(qcom_spmi_regulator_driver);
diff --git a/drivers/regulator/rohm-regulator.c b/drivers/regulator/rohm-regulator.c
index 5c558b153d55..6e0d9c08ec1c 100644
--- a/drivers/regulator/rohm-regulator.c
+++ b/drivers/regulator/rohm-regulator.c
@@ -22,13 +22,26 @@ static int set_dvs_level(const struct regulator_desc *desc,
return ret;
return 0;
}
-
+ /* If voltage is set to 0 => disable */
if (uv == 0) {
if (omask)
return regmap_update_bits(regmap, oreg, omask, 0);
}
+ /* Some setups don't allow setting own voltage but do allow enabling */
+ if (!mask) {
+ if (omask)
+ return regmap_update_bits(regmap, oreg, omask, omask);
+
+ return -EINVAL;
+ }
for (i = 0; i < desc->n_voltages; i++) {
- ret = regulator_desc_list_voltage_linear_range(desc, i);
+ /* NOTE to next hacker - Does not support pickable ranges */
+ if (desc->linear_range_selectors)
+ return -EINVAL;
+ if (desc->n_linear_ranges)
+ ret = regulator_desc_list_voltage_linear_range(desc, i);
+ else
+ ret = regulator_desc_list_voltage_linear(desc, i);
if (ret < 0)
continue;
if (ret == uv) {
@@ -82,6 +95,12 @@ int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
mask = dvs->lpsr_mask;
omask = dvs->lpsr_on_mask;
break;
+ case ROHM_DVS_LEVEL_SNVS:
+ prop = "rohm,dvs-snvs-voltage";
+ reg = dvs->snvs_reg;
+ mask = dvs->snvs_mask;
+ omask = dvs->snvs_on_mask;
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c
index 115f59530852..28b424fe7bea 100644
--- a/drivers/regulator/s2mpa01.c
+++ b/drivers/regulator/s2mpa01.c
@@ -340,7 +340,6 @@ static const struct regulator_desc regulators[] = {
static int s2mpa01_pmic_probe(struct platform_device *pdev)
{
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
struct regulator_config config = { };
struct s2mpa01_info *s2mpa01;
int i;
@@ -356,9 +355,6 @@ static int s2mpa01_pmic_probe(struct platform_device *pdev)
for (i = 0; i < S2MPA01_REGULATOR_MAX; i++) {
struct regulator_dev *rdev;
- if (pdata)
- config.init_data = pdata->regulators[i].initdata;
-
rdev = devm_regulator_register(&pdev->dev,
&regulators[i], &config);
if (IS_ERR(rdev)) {
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index 33cf84bce05a..ebc67e3ddd4f 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -1120,7 +1120,6 @@ static const struct regulator_desc s2mpu02_regulators[] = {
static int s2mps11_pmic_probe(struct platform_device *pdev)
{
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct sec_platform_data *pdata = NULL;
struct of_regulator_match *rdata = NULL;
struct regulator_config config = { };
struct s2mps11_info *s2mps11;
@@ -1171,17 +1170,6 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
if (!s2mps11->ext_control_gpiod)
return -ENOMEM;
- if (!iodev->dev->of_node) {
- if (iodev->pdata) {
- pdata = iodev->pdata;
- goto common_reg;
- } else {
- dev_err(pdev->dev.parent,
- "Platform data or DT node not supplied\n");
- return -ENODEV;
- }
- }
-
rdata = kcalloc(rdev_num, sizeof(*rdata), GFP_KERNEL);
if (!rdata)
return -ENOMEM;
@@ -1193,7 +1181,6 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
if (ret)
goto out;
-common_reg:
platform_set_drvdata(pdev, s2mps11);
config.dev = &pdev->dev;
@@ -1202,13 +1189,8 @@ common_reg:
for (i = 0; i < rdev_num; i++) {
struct regulator_dev *regulator;
- if (pdata) {
- config.init_data = pdata->regulators[i].initdata;
- config.of_node = pdata->regulators[i].reg_node;
- } else {
- config.init_data = rdata[i].init_data;
- config.of_node = rdata[i].of_node;
- }
+ config.init_data = rdata[i].init_data;
+ config.of_node = rdata[i].of_node;
config.ena_gpiod = s2mps11->ext_control_gpiod[i];
/*
* Hand the GPIO descriptor management over to the regulator
diff --git a/drivers/regulator/scmi-regulator.c b/drivers/regulator/scmi-regulator.c
index 0e8b3caa8146..bbadf72b94e8 100644
--- a/drivers/regulator/scmi-regulator.c
+++ b/drivers/regulator/scmi-regulator.c
@@ -2,7 +2,7 @@
//
// System Control and Management Interface (SCMI) based regulator driver
//
-// Copyright (C) 2020 ARM Ltd.
+// Copyright (C) 2020-2021 ARM Ltd.
//
// Implements a regulator driver on top of the SCMI Voltage Protocol.
//
@@ -33,9 +33,12 @@
#include <linux/slab.h>
#include <linux/types.h>
+static const struct scmi_voltage_proto_ops *voltage_ops;
+
struct scmi_regulator {
u32 id;
struct scmi_device *sdev;
+ struct scmi_protocol_handle *ph;
struct regulator_dev *rdev;
struct device_node *of_node;
struct regulator_desc desc;
@@ -50,19 +53,17 @@ struct scmi_regulator_info {
static int scmi_reg_enable(struct regulator_dev *rdev)
{
struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
- const struct scmi_handle *handle = sreg->sdev->handle;
- return handle->voltage_ops->config_set(handle, sreg->id,
- SCMI_VOLTAGE_ARCH_STATE_ON);
+ return voltage_ops->config_set(sreg->ph, sreg->id,
+ SCMI_VOLTAGE_ARCH_STATE_ON);
}
static int scmi_reg_disable(struct regulator_dev *rdev)
{
struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
- const struct scmi_handle *handle = sreg->sdev->handle;
- return handle->voltage_ops->config_set(handle, sreg->id,
- SCMI_VOLTAGE_ARCH_STATE_OFF);
+ return voltage_ops->config_set(sreg->ph, sreg->id,
+ SCMI_VOLTAGE_ARCH_STATE_OFF);
}
static int scmi_reg_is_enabled(struct regulator_dev *rdev)
@@ -70,10 +71,8 @@ static int scmi_reg_is_enabled(struct regulator_dev *rdev)
int ret;
u32 config;
struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
- const struct scmi_handle *handle = sreg->sdev->handle;
- ret = handle->voltage_ops->config_get(handle, sreg->id,
- &config);
+ ret = voltage_ops->config_get(sreg->ph, sreg->id, &config);
if (ret) {
dev_err(&sreg->sdev->dev,
"Error %d reading regulator %s status.\n",
@@ -89,9 +88,8 @@ static int scmi_reg_get_voltage_sel(struct regulator_dev *rdev)
int ret;
s32 volt_uV;
struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
- const struct scmi_handle *handle = sreg->sdev->handle;
- ret = handle->voltage_ops->level_get(handle, sreg->id, &volt_uV);
+ ret = voltage_ops->level_get(sreg->ph, sreg->id, &volt_uV);
if (ret)
return ret;
@@ -103,13 +101,12 @@ static int scmi_reg_set_voltage_sel(struct regulator_dev *rdev,
{
s32 volt_uV;
struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
- const struct scmi_handle *handle = sreg->sdev->handle;
volt_uV = sreg->desc.ops->list_voltage(rdev, selector);
if (volt_uV <= 0)
return -EINVAL;
- return handle->voltage_ops->level_set(handle, sreg->id, 0x0, volt_uV);
+ return voltage_ops->level_set(sreg->ph, sreg->id, 0x0, volt_uV);
}
static const struct regulator_ops scmi_reg_fixed_ops = {
@@ -204,11 +201,10 @@ scmi_config_discrete_regulator_mappings(struct scmi_regulator *sreg,
static int scmi_regulator_common_init(struct scmi_regulator *sreg)
{
int ret;
- const struct scmi_handle *handle = sreg->sdev->handle;
struct device *dev = &sreg->sdev->dev;
const struct scmi_voltage_info *vinfo;
- vinfo = handle->voltage_ops->info_get(handle, sreg->id);
+ vinfo = voltage_ops->info_get(sreg->ph, sreg->id);
if (!vinfo) {
dev_warn(dev, "Failure to get voltage domain %d\n",
sreg->id);
@@ -257,6 +253,7 @@ static int scmi_regulator_common_init(struct scmi_regulator *sreg)
}
static int process_scmi_regulator_of_node(struct scmi_device *sdev,
+ struct scmi_protocol_handle *ph,
struct device_node *np,
struct scmi_regulator_info *rinfo)
{
@@ -284,6 +281,7 @@ static int process_scmi_regulator_of_node(struct scmi_device *sdev,
rinfo->sregv[dom]->id = dom;
rinfo->sregv[dom]->sdev = sdev;
+ rinfo->sregv[dom]->ph = ph;
/* get hold of good nodes */
of_node_get(np);
@@ -302,11 +300,17 @@ static int scmi_regulator_probe(struct scmi_device *sdev)
struct device_node *np, *child;
const struct scmi_handle *handle = sdev->handle;
struct scmi_regulator_info *rinfo;
+ struct scmi_protocol_handle *ph;
- if (!handle || !handle->voltage_ops)
+ if (!handle)
return -ENODEV;
- num_doms = handle->voltage_ops->num_domains_get(handle);
+ voltage_ops = handle->devm_protocol_get(sdev,
+ SCMI_PROTOCOL_VOLTAGE, &ph);
+ if (IS_ERR(voltage_ops))
+ return PTR_ERR(voltage_ops);
+
+ num_doms = voltage_ops->num_domains_get(ph);
if (num_doms <= 0) {
if (!num_doms) {
dev_err(&sdev->dev,
@@ -341,10 +345,12 @@ static int scmi_regulator_probe(struct scmi_device *sdev)
*/
np = of_find_node_by_name(handle->dev->of_node, "regulators");
for_each_child_of_node(np, child) {
- ret = process_scmi_regulator_of_node(sdev, child, rinfo);
+ ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo);
/* abort on any mem issue */
- if (ret == -ENOMEM)
+ if (ret == -ENOMEM) {
+ of_node_put(child);
return ret;
+ }
}
/*