diff options
Diffstat (limited to 'drivers/power/regulator')
35 files changed, 610 insertions, 61 deletions
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 102ec7bc5f8..bc061c20d75 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -216,6 +216,14 @@ config DM_REGULATOR_GPIO features for gpio regulators. The driver implements get/set for voltage value. +config DM_REGULATOR_QCOM_RPMH + bool "Enable driver model for Qualcomm RPMh regulator" + depends on DM_REGULATOR && QCOM_RPMH + ---help--- + Enable support for the Qualcomm RPMh regulator. The driver + implements get/set api for a limited set of regulators used + by u-boot. + config SPL_DM_REGULATOR_GPIO bool "Enable Driver Model for GPIO REGULATOR in SPL" depends on DM_REGULATOR_GPIO && SPL_GPIO diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index f79932d8330..56a527612b7 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_$(SPL_)DM_REGULATOR_FAN53555) += fan53555.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_COMMON) += regulator_common.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_FIXED) += fixed.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_GPIO) += gpio-regulator.o +obj-$(CONFIG_DM_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o obj-$(CONFIG_$(SPL_TPL_)REGULATOR_RK8XX) += rk8xx.o obj-$(CONFIG_DM_REGULATOR_S2MPS11) += s2mps11_regulator.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o diff --git a/drivers/power/regulator/act8846.c b/drivers/power/regulator/act8846.c index bdce97365dd..d3e72da0d35 100644 --- a/drivers/power/regulator/act8846.c +++ b/drivers/power/regulator/act8846.c @@ -8,7 +8,6 @@ * zyw <zyw@rock-chips.com> */ -#include <common.h> #include <dm.h> #include <errno.h> #include <power/act8846_pmic.h> diff --git a/drivers/power/regulator/anatop_regulator.c b/drivers/power/regulator/anatop_regulator.c index 096a1565d5a..824a753db16 100644 --- a/drivers/power/regulator/anatop_regulator.c +++ b/drivers/power/regulator/anatop_regulator.c @@ -4,7 +4,6 @@ * Copyright (C) 2021 Linaro */ -#include <common.h> #include <dm.h> #include <errno.h> #include <log.h> diff --git a/drivers/power/regulator/as3722_regulator.c b/drivers/power/regulator/as3722_regulator.c index ec0776b440b..8d60965fe9a 100644 --- a/drivers/power/regulator/as3722_regulator.c +++ b/drivers/power/regulator/as3722_regulator.c @@ -6,7 +6,6 @@ * Placeholder regulator driver for as3722. */ -#include <common.h> #include <dm.h> #include <errno.h> #include <log.h> diff --git a/drivers/power/regulator/axp_regulator.c b/drivers/power/regulator/axp_regulator.c index d27e09538e0..75cdbca30f6 100644 --- a/drivers/power/regulator/axp_regulator.c +++ b/drivers/power/regulator/axp_regulator.c @@ -189,6 +189,33 @@ static const struct axp_regulator_plat axp313_regulators[] = { { } }; +/* + * The "dcdc2" regulator has another range, beyond 1.54V up to 3.4V, in + * steps of 100mV. We cannot model this easily, but also don't need that, + * since it's typically only used for lower voltages anyway, so just ignore it. + */ +static const struct axp_regulator_plat axp717_regulators[] = { + { "dcdc1", 0x80, BIT(0), 0x83, 0x7f, 500, 1540, 10, 70 }, + { "dcdc2", 0x80, BIT(1), 0x84, 0x7f, 500, 1540, 10, 70 }, + { "dcdc3", 0x80, BIT(2), 0x85, 0x7f, 500, 1840, 10, 70 }, + { "dcdc4", 0x80, BIT(3), 0x86, 0x7f, 1000, 3700, 100, NA }, + { "aldo1", 0x90, BIT(0), 0x93, 0x1f, 500, 3500, 100, NA }, + { "aldo2", 0x90, BIT(1), 0x94, 0x1f, 500, 3500, 100, NA }, + { "aldo3", 0x90, BIT(2), 0x95, 0x1f, 500, 3500, 100, NA }, + { "aldo4", 0x90, BIT(3), 0x96, 0x1f, 500, 3500, 100, NA }, + { "bldo1", 0x90, BIT(4), 0x97, 0x1f, 500, 3500, 100, NA }, + { "bldo2", 0x90, BIT(5), 0x98, 0x1f, 500, 3500, 100, NA }, + { "bldo3", 0x90, BIT(6), 0x99, 0x1f, 500, 3500, 100, NA }, + { "bldo4", 0x90, BIT(7), 0x9a, 0x1f, 500, 3500, 100, NA }, + { "cldo1", 0x91, BIT(0), 0x9b, 0x1f, 500, 3500, 100, NA }, + { "cldo2", 0x91, BIT(1), 0x9c, 0x1f, 500, 3500, 100, NA }, + { "cldo3", 0x91, BIT(2), 0x9d, 0x1f, 500, 3500, 100, NA }, + { "cldo4", 0x91, BIT(3), 0x9e, 0x1f, 500, 3500, 100, NA }, + {"cpusldo",0x91, BIT(4), 0x9f, 0x1f, 500, 1400, 50, NA }, + {" boost", 0x19, BIT(4), 0x1e, 0xf0, 4550, 5510, 64, NA }, + { } +}; + static const struct axp_regulator_plat axp803_regulators[] = { { "dcdc1", 0x10, BIT(0), 0x20, 0x1f, 1600, 3400, 100, NA }, { "dcdc2", 0x10, BIT(1), 0x21, 0x7f, 500, 1300, 10, 70 }, @@ -291,6 +318,7 @@ static const struct axp_regulator_plat *const axp_regulators[] = { [AXP221_ID] = axp22x_regulators, [AXP223_ID] = axp22x_regulators, [AXP313_ID] = axp313_regulators, + [AXP717_ID] = axp717_regulators, [AXP803_ID] = axp803_regulators, [AXP806_ID] = axp806_regulators, [AXP809_ID] = axp809_regulators, diff --git a/drivers/power/regulator/bd71837.c b/drivers/power/regulator/bd71837.c index 913ed88d45f..59aec1a7313 100644 --- a/drivers/power/regulator/bd71837.c +++ b/drivers/power/regulator/bd71837.c @@ -5,7 +5,6 @@ * ROHM BD71837 regulator driver */ -#include <common.h> #include <dm.h> #include <log.h> #include <linux/bitops.h> diff --git a/drivers/power/regulator/da9063.c b/drivers/power/regulator/da9063.c index 8df1abcf788..5d566b06a52 100644 --- a/drivers/power/regulator/da9063.c +++ b/drivers/power/regulator/da9063.c @@ -4,7 +4,6 @@ * Martin Fuzzey <martin.fuzzey@flowbird.group> */ -#include <common.h> #include <dm.h> #include <linux/bitops.h> #include <power/da9063_pmic.h> diff --git a/drivers/power/regulator/fan53555.c b/drivers/power/regulator/fan53555.c index fa8d88f2e0d..5cba58f91ca 100644 --- a/drivers/power/regulator/fan53555.c +++ b/drivers/power/regulator/fan53555.c @@ -3,7 +3,6 @@ * (C) 2018 Theobroma Systems Design und Consulting GmbH */ -#include <common.h> #include <bitfield.h> #include <errno.h> #include <dm.h> diff --git a/drivers/power/regulator/fixed.c b/drivers/power/regulator/fixed.c index 590c288d657..98c89bf2aff 100644 --- a/drivers/power/regulator/fixed.c +++ b/drivers/power/regulator/fixed.c @@ -5,7 +5,6 @@ * Przemyslaw Marczak <p.marczak@samsung.com> */ -#include <common.h> #include <clk.h> #include <errno.h> #include <dm.h> diff --git a/drivers/power/regulator/gpio-regulator.c b/drivers/power/regulator/gpio-regulator.c index 74137b7b876..38b22535c3d 100644 --- a/drivers/power/regulator/gpio-regulator.c +++ b/drivers/power/regulator/gpio-regulator.c @@ -4,7 +4,6 @@ * Keerthy <j-keerthy@ti.com> */ -#include <common.h> #include <fdtdec.h> #include <errno.h> #include <dm.h> diff --git a/drivers/power/regulator/lp873x_regulator.c b/drivers/power/regulator/lp873x_regulator.c index c326f8efa47..271a7e45139 100644 --- a/drivers/power/regulator/lp873x_regulator.c +++ b/drivers/power/regulator/lp873x_regulator.c @@ -6,7 +6,6 @@ * Keerthy <j-keerthy@ti.com> */ -#include <common.h> #include <fdtdec.h> #include <errno.h> #include <dm.h> @@ -311,7 +310,6 @@ static int buck_get_enable(struct udevice *dev) bool enable = false; int ret; - ret = lp873x_buck_enable(dev, PMIC_OP_GET, &enable); if (ret) return ret; diff --git a/drivers/power/regulator/lp87565_regulator.c b/drivers/power/regulator/lp87565_regulator.c index 6bbc831d2c8..2212cb5c651 100644 --- a/drivers/power/regulator/lp87565_regulator.c +++ b/drivers/power/regulator/lp87565_regulator.c @@ -6,7 +6,6 @@ * Keerthy <j-keerthy@ti.com> */ -#include <common.h> #include <fdtdec.h> #include <errno.h> #include <dm.h> @@ -168,7 +167,6 @@ static int buck_get_enable(struct udevice *dev) bool enable = false; int ret; - ret = lp87565_buck_enable(dev, PMIC_OP_GET, &enable); if (ret) return ret; diff --git a/drivers/power/regulator/max77686.c b/drivers/power/regulator/max77686.c index 3a208039934..4e0ba12a0ef 100644 --- a/drivers/power/regulator/max77686.c +++ b/drivers/power/regulator/max77686.c @@ -6,7 +6,6 @@ * Przemyslaw Marczak <p.marczak@samsung.com> */ -#include <common.h> #include <fdtdec.h> #include <errno.h> #include <dm.h> diff --git a/drivers/power/regulator/npcm8xx_regulator.c b/drivers/power/regulator/npcm8xx_regulator.c index fcd1058cdf5..30d1b8945cb 100644 --- a/drivers/power/regulator/npcm8xx_regulator.c +++ b/drivers/power/regulator/npcm8xx_regulator.c @@ -3,7 +3,6 @@ * Copyright (c) 2022 Nuvoton Technology Corp. */ -#include <common.h> #include <dm.h> #include <asm/io.h> #include <dm/device_compat.h> diff --git a/drivers/power/regulator/palmas_regulator.c b/drivers/power/regulator/palmas_regulator.c index d615e947340..2286eac93fb 100644 --- a/drivers/power/regulator/palmas_regulator.c +++ b/drivers/power/regulator/palmas_regulator.c @@ -6,7 +6,6 @@ * Keerthy <j-keerthy@ti.com> */ -#include <common.h> #include <fdtdec.h> #include <errno.h> #include <dm.h> diff --git a/drivers/power/regulator/pbias_regulator.c b/drivers/power/regulator/pbias_regulator.c index cf4e2858443..8f599cab689 100644 --- a/drivers/power/regulator/pbias_regulator.c +++ b/drivers/power/regulator/pbias_regulator.c @@ -4,7 +4,6 @@ * Jean-Jacques Hiblot <jjhiblot@ti.com> */ -#include <common.h> #include <errno.h> #include <dm.h> #include <log.h> diff --git a/drivers/power/regulator/pca9450.c b/drivers/power/regulator/pca9450.c index 7ca20d1f7f8..9faf1eab5f9 100644 --- a/drivers/power/regulator/pca9450.c +++ b/drivers/power/regulator/pca9450.c @@ -7,7 +7,6 @@ * ROHM BD71837 regulator driver */ -#include <common.h> #include <dm.h> #include <log.h> #include <linux/bitops.h> diff --git a/drivers/power/regulator/pfuze100.c b/drivers/power/regulator/pfuze100.c index 1d926689b3b..bf3a7019411 100644 --- a/drivers/power/regulator/pfuze100.c +++ b/drivers/power/regulator/pfuze100.c @@ -5,7 +5,6 @@ * Peng Fan <peng.fan@nxp.com> */ -#include <common.h> #include <fdtdec.h> #include <errno.h> #include <dm.h> diff --git a/drivers/power/regulator/pwm_regulator.c b/drivers/power/regulator/pwm_regulator.c index ca59f3ae3e1..ff738faadc5 100644 --- a/drivers/power/regulator/pwm_regulator.c +++ b/drivers/power/regulator/pwm_regulator.c @@ -7,7 +7,6 @@ * Author: Lee Jones <lee.jones@linaro.org> */ -#include <common.h> #include <dm.h> #include <errno.h> #include <log.h> diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c new file mode 100644 index 00000000000..06fd3f31956 --- /dev/null +++ b/drivers/power/regulator/qcom-rpmh-regulator.c @@ -0,0 +1,544 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. +// Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/err.h> +#include <dm/device_compat.h> +#include <dm/device.h> +#include <dm/devres.h> +#include <dm/lists.h> +#include <power/regulator.h> +#include <log.h> + +#include <soc/qcom/cmd-db.h> +#include <soc/qcom/rpmh.h> + +#include <dt-bindings/regulator/qcom,rpmh-regulator.h> + +/** + * enum rpmh_regulator_type - supported RPMh accelerator types + * @VRM: RPMh VRM accelerator which supports voting on enable, voltage, + * and mode of LDO, SMPS, and BOB type PMIC regulators. + * @XOB: RPMh XOB accelerator which supports voting on the enable state + * of PMIC regulators. + */ +enum rpmh_regulator_type { + VRM, + XOB, +}; + +enum rpmh_regulator_mode { + REGULATOR_MODE_RETENTION, + REGULATOR_MODE_LPM, + REGULATOR_MODE_AUTO, + REGULATOR_MODE_HPM, +}; + +#define RPMH_REGULATOR_REG_VRM_VOLTAGE 0x0 +#define RPMH_REGULATOR_REG_ENABLE 0x4 +#define RPMH_REGULATOR_REG_VRM_MODE 0x8 + +#define PMIC4_LDO_MODE_RETENTION 4 +#define PMIC4_LDO_MODE_LPM 5 +#define PMIC4_LDO_MODE_HPM 7 + +#define PMIC4_SMPS_MODE_RETENTION 4 +#define PMIC4_SMPS_MODE_PFM 5 +#define PMIC4_SMPS_MODE_AUTO 6 +#define PMIC4_SMPS_MODE_PWM 7 + +#define PMIC4_BOB_MODE_PASS 0 +#define PMIC4_BOB_MODE_PFM 1 +#define PMIC4_BOB_MODE_AUTO 2 +#define PMIC4_BOB_MODE_PWM 3 + +#define PMIC5_LDO_MODE_RETENTION 3 +#define PMIC5_LDO_MODE_LPM 4 +#define PMIC5_LDO_MODE_HPM 7 + +#define PMIC5_SMPS_MODE_RETENTION 3 +#define PMIC5_SMPS_MODE_PFM 4 +#define PMIC5_SMPS_MODE_AUTO 6 +#define PMIC5_SMPS_MODE_PWM 7 + +#define PMIC5_BOB_MODE_PASS 2 +#define PMIC5_BOB_MODE_PFM 4 +#define PMIC5_BOB_MODE_AUTO 6 +#define PMIC5_BOB_MODE_PWM 7 + + +/** + * struct linear_range - table of selector - value pairs + * + * Define a lookup-table for range of values. Intended to help when looking + * for a register value matching certaing physical measure (like voltage). + * Usable when increment of one in register always results a constant increment + * of the physical measure (like voltage). + * + * @min: Lowest value in range + * @min_sel: Lowest selector for range + * @max_sel: Highest selector for range + * @step: Value step size + */ +struct linear_range { + unsigned int min; + unsigned int min_sel; + unsigned int max_sel; + unsigned int step; +}; + +/* Initialize struct linear_range for regulators */ +#define REGULATOR_LINEAR_RANGE(_min_uV, _min_sel, _max_sel, _step_uV) \ +{ \ + .min = _min_uV, \ + .min_sel = _min_sel, \ + .max_sel = _max_sel, \ + .step = _step_uV, \ +} + +/** + * struct rpmh_vreg_hw_data - RPMh regulator hardware configurations + * @regulator_type: RPMh accelerator type used to manage this + * regulator + * @ops: Pointer to regulator ops callback structure + * @voltage_range: The single range of voltages supported by this + * PMIC regulator type + * @n_voltages: The number of unique voltage set points defined + * by voltage_range + * @hpm_min_load_uA: Minimum load current in microamps that requires + * high power mode (HPM) operation. This is used + * for LDO hardware type regulators only. + * @pmic_mode_map: Array indexed by regulator framework mode + * containing PMIC hardware modes. Must be large + * enough to index all framework modes supported + * by this regulator hardware type. + * @of_map_mode: Maps an RPMH_REGULATOR_MODE_* mode value defined + * in device tree to a regulator framework mode + */ +struct rpmh_vreg_hw_data { + enum rpmh_regulator_type regulator_type; + const struct dm_regulator_ops *ops; + struct linear_range voltage_range; + int n_voltages; + int hpm_min_load_uA; + struct dm_regulator_mode *pmic_mode_map; + int n_modes; + unsigned int (*of_map_mode)(unsigned int mode); +}; + +/** + * struct rpmh_vreg - individual RPMh regulator data structure encapsulating a + * single regulator device + * @dev: Device pointer for the top-level PMIC RPMh + * regulator parent device. This is used as a + * handle in RPMh write requests. + * @addr: Base address of the regulator resource within + * an RPMh accelerator + * @rdesc: Regulator descriptor + * @hw_data: PMIC regulator configuration data for this RPMh + * regulator + * @always_wait_for_ack: Boolean flag indicating if a request must always + * wait for an ACK from RPMh before continuing even + * if it corresponds to a strictly lower power + * state (e.g. enabled --> disabled). + * @enabled: Flag indicating if the regulator is enabled or + * not + * @bypassed: Boolean indicating if the regulator is in + * bypass (pass-through) mode or not. This is + * only used by BOB rpmh-regulator resources. + * @uv: Selector used for get_voltage_sel() and + * set_value() callbacks + * @mode: RPMh VRM regulator current framework mode + */ +struct rpmh_vreg { + struct udevice *dev; + u32 addr; + const struct rpmh_vreg_hw_data *hw_data; + bool always_wait_for_ack; + + int enabled; + bool bypassed; + int uv; + int mode; +}; + +/** + * struct rpmh_vreg_init_data - initialization data for an RPMh regulator + * @name: Name for the regulator which also corresponds + * to the device tree subnode name of the regulator + * @resource_name: RPMh regulator resource name format string. + * This must include exactly one field: '%s' which + * is filled at run-time with the PMIC ID provided + * by device tree property qcom,pmic-id. Example: + * "ldo%s1" for RPMh resource "ldoa1". + * @supply_name: Parent supply regulator name + * @hw_data: Configuration data for this PMIC regulator type + */ +struct rpmh_vreg_init_data { + const char *name; + const char *resource_name; + const char *supply_name; + const struct rpmh_vreg_hw_data *hw_data; +}; + +/** + * rpmh_regulator_send_request() - send the request to RPMh + * @vreg: Pointer to the RPMh regulator + * @cmd: Pointer to the RPMh command to send + * @wait_for_ack: Boolean indicating if execution must wait until the + * request has been acknowledged as complete + * + * Return: 0 on success, errno on failure + */ +static int rpmh_regulator_send_request(struct rpmh_vreg *vreg, + const struct tcs_cmd *cmd, bool wait_for_ack) +{ + int ret; + + if (wait_for_ack || vreg->always_wait_for_ack) + ret = rpmh_write(vreg->dev->parent, RPMH_ACTIVE_ONLY_STATE, cmd, 1); + else + ret = rpmh_write_async(vreg->dev->parent, RPMH_ACTIVE_ONLY_STATE, cmd, 1); + + return ret; +} + +static int _rpmh_regulator_vrm_set_value(struct udevice *rdev, + int uv, bool wait_for_ack) +{ + struct rpmh_vreg *vreg = dev_get_priv(rdev); + struct tcs_cmd cmd = { + .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_VOLTAGE, + }; + int ret; + unsigned int selector; + + selector = (uv - vreg->hw_data->voltage_range.min) / vreg->hw_data->voltage_range.step; + cmd.data = DIV_ROUND_UP(vreg->hw_data->voltage_range.min + + selector * vreg->hw_data->voltage_range.step, 1000); + + ret = rpmh_regulator_send_request(vreg, &cmd, wait_for_ack); + if (!ret) + vreg->uv = cmd.data * 1000; + + return ret; +} + +static int rpmh_regulator_vrm_set_value(struct udevice *rdev, + int uv) +{ + struct rpmh_vreg *vreg = dev_get_priv(rdev); + + debug("%s: set_value %d (current %d)\n", rdev->name, uv, vreg->uv); + + if (vreg->enabled == -EINVAL) { + /* + * Cache the voltage and send it later when the regulator is + * enabled or disabled. + */ + vreg->uv = uv; + return 0; + } + + return _rpmh_regulator_vrm_set_value(rdev, uv, + uv > vreg->uv); +} + +static int rpmh_regulator_vrm_get_value(struct udevice *rdev) +{ + struct rpmh_vreg *vreg = dev_get_priv(rdev); + + debug("%s: get_value %d\n", rdev->name, vreg->uv); + + return vreg->uv; +} + +static int rpmh_regulator_is_enabled(struct udevice *rdev) +{ + struct rpmh_vreg *vreg = dev_get_priv(rdev); + + debug("%s: is_enabled %d\n", rdev->name, vreg->enabled); + + return vreg->enabled > 0; +} + +static int rpmh_regulator_set_enable_state(struct udevice *rdev, + bool enable) +{ + struct rpmh_vreg *vreg = dev_get_priv(rdev); + struct tcs_cmd cmd = { + .addr = vreg->addr + RPMH_REGULATOR_REG_ENABLE, + .data = enable, + }; + int ret; + + debug("%s: set_enable %d (current %d)\n", rdev->name, enable, + vreg->enabled); + + if (vreg->enabled == -EINVAL && + vreg->uv != -ENOTRECOVERABLE) { + ret = _rpmh_regulator_vrm_set_value(rdev, + vreg->uv, true); + if (ret < 0) + return ret; + } + + ret = rpmh_regulator_send_request(vreg, &cmd, enable); + if (!ret) + vreg->enabled = enable; + + return ret; +} + +static int rpmh_regulator_vrm_set_mode_bypass(struct rpmh_vreg *vreg, + unsigned int mode, bool bypassed) +{ + struct tcs_cmd cmd = { + .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_MODE, + }; + struct dm_regulator_mode *pmic_mode; + int i; + + if (mode > REGULATOR_MODE_HPM) + return -EINVAL; + + for (i = 0; i < vreg->hw_data->n_modes; i++) { + pmic_mode = &vreg->hw_data->pmic_mode_map[i]; + if (pmic_mode->id == mode) + break; + } + if (pmic_mode->id != mode) { + printf("Invalid mode %d\n", mode); + return -EINVAL; + } + + if (bypassed) + cmd.data = PMIC4_BOB_MODE_PASS; + else + cmd.data = pmic_mode->id; + + return rpmh_regulator_send_request(vreg, &cmd, true); +} + +static int rpmh_regulator_vrm_set_mode(struct udevice *rdev, + int mode) +{ + struct rpmh_vreg *vreg = dev_get_priv(rdev); + int ret; + + debug("%s: set_mode %d (current %d)\n", rdev->name, mode, vreg->mode); + + if (mode == vreg->mode) + return 0; + + ret = rpmh_regulator_vrm_set_mode_bypass(vreg, mode, vreg->bypassed); + if (!ret) + vreg->mode = mode; + + return ret; +} + +static int rpmh_regulator_vrm_get_mode(struct udevice *rdev) +{ + struct rpmh_vreg *vreg = dev_get_priv(rdev); + + debug("%s: get_mode %d\n", rdev->name, vreg->mode); + + return vreg->mode; +} +static const struct dm_regulator_ops rpmh_regulator_vrm_drms_ops = { + .get_value = rpmh_regulator_vrm_get_value, + .set_value = rpmh_regulator_vrm_set_value, + .set_enable = rpmh_regulator_set_enable_state, + .get_enable = rpmh_regulator_is_enabled, + .set_mode = rpmh_regulator_vrm_set_mode, + .get_mode = rpmh_regulator_vrm_get_mode, +}; + +static struct dm_regulator_mode pmic_mode_map_pmic5_ldo[] = { + { + .id = REGULATOR_MODE_RETENTION, + .register_value = PMIC5_LDO_MODE_RETENTION, + .name = "PMIC5_LDO_MODE_RETENTION" + }, { + .id = REGULATOR_MODE_LPM, + .register_value = PMIC5_LDO_MODE_LPM, + .name = "PMIC5_LDO_MODE_LPM" + }, { + .id = REGULATOR_MODE_HPM, + .register_value = PMIC5_LDO_MODE_HPM, + .name = "PMIC5_LDO_MODE_HPM" + }, +}; + +static const struct rpmh_vreg_hw_data pmic5_pldo = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000), + .n_voltages = 256, + .hpm_min_load_uA = 10000, + .pmic_mode_map = pmic_mode_map_pmic5_ldo, + .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo), +}; + +static const struct rpmh_vreg_hw_data pmic5_pldo_lv = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(1504000, 0, 62, 8000), + .n_voltages = 63, + .hpm_min_load_uA = 10000, + .pmic_mode_map = pmic_mode_map_pmic5_ldo, + .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo), +}; + +#define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \ +{ \ + .name = _name, \ + .resource_name = _resource_name, \ + .hw_data = _hw_data, \ + .supply_name = _supply_name, \ +} + +static const struct rpmh_vreg_init_data pm8150_vreg_data[] = { + RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l16-l17"), + {} +}; + +static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = { + RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l8"), + RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"), + {} +}; + +/* probe an individual regulator */ +static int rpmh_regulator_probe(struct udevice *dev) +{ + const struct rpmh_vreg_init_data *init_data; + struct rpmh_vreg *priv; + struct dm_regulator_uclass_plat *plat_data; + + init_data = (const struct rpmh_vreg_init_data *)dev_get_driver_data(dev); + priv = dev_get_priv(dev); + plat_data = dev_get_uclass_plat(dev); + + priv->dev = dev; + priv->addr = cmd_db_read_addr(dev->name); + if (!priv->addr) { + dev_err(dev, "Failed to read RPMh address for %s\n", dev->name); + return -ENODEV; + } + + priv->hw_data = init_data->hw_data; + priv->enabled = -EINVAL; + priv->uv = -ENOTRECOVERABLE; + if (ofnode_read_u32(dev_ofnode(dev), "regulator-initial-mode", &priv->mode)) + priv->mode = -EINVAL; + + plat_data->mode = priv->hw_data->pmic_mode_map; + plat_data->mode_count = priv->hw_data->n_modes; + + return 0; +} + +/* for non-drm, xob, or bypass regulators add additional driver definitions */ +U_BOOT_DRIVER(rpmh_regulator_drm) = { + .name = "rpmh_regulator_drm", + .id = UCLASS_REGULATOR, + .probe = rpmh_regulator_probe, + .priv_auto = sizeof(struct rpmh_vreg), + .ops = &rpmh_regulator_vrm_drms_ops, +}; + +/* This driver intentionally only supports a subset of the available regulators. + * This function checks to see if a given regulator node in DT matches a regulator + * defined in the driver. + */ +static const struct rpmh_vreg_init_data * +vreg_get_init_data(const struct rpmh_vreg_init_data *init_data, ofnode node) +{ + const struct rpmh_vreg_init_data *data; + + for (data = init_data; data->name; data++) { + if (!strcmp(data->name, ofnode_get_name(node))) + return data; + } + + return NULL; +} + +static int rpmh_regulators_bind(struct udevice *dev) +{ + const struct rpmh_vreg_init_data *init_data, *data; + const char *pmic_id; + char *name; + struct driver *drv; + ofnode node; + int ret; + size_t namelen; + + init_data = (const struct rpmh_vreg_init_data *)dev_get_driver_data(dev); + if (!init_data) { + dev_err(dev, "No RPMh regulator init data\n"); + return -ENODEV; + } + + pmic_id = ofnode_read_string(dev_ofnode(dev), "qcom,pmic-id"); + if (!pmic_id) { + dev_err(dev, "No PMIC ID\n"); + return -ENODEV; + } + + drv = lists_driver_lookup_name("rpmh_regulator_drm"); + + ofnode_for_each_subnode(node, dev_ofnode(dev)) { + data = vreg_get_init_data(init_data, node); + if (!data) + continue; + + /* %s is replaced with pmic_id, so subtract 2, then add 1 for the null terminator */ + namelen = strlen(data->resource_name) + strlen(pmic_id) - 1; + name = devm_kzalloc(dev, namelen, GFP_KERNEL); + ret = snprintf(name, namelen, data->resource_name, pmic_id); + if (ret < 0 || ret >= namelen) { + dev_err(dev, "Failed to create RPMh regulator name\n"); + return -ENOMEM; + } + + ret = device_bind_with_driver_data(dev, drv, name, (ulong)data, + node, NULL); + if (ret < 0) { + dev_err(dev, "Failed to bind RPMh regulator %s: %d\n", name, ret); + return ret; + } + } + + return 0; +} + +static const struct udevice_id rpmh_regulator_ids[] = { + { + .compatible = "qcom,pm8150-rpmh-regulators", + .data = (ulong)pm8150_vreg_data, + }, + { + .compatible = "qcom,pm8150l-rpmh-regulators", + .data = (ulong)pm8150l_vreg_data, + }, + { /* sentinal */ }, +}; + +/* Driver for a 'bank' of regulators. This creates devices for each + * individual regulator + */ +U_BOOT_DRIVER(rpmh_regulators) = { + .name = "rpmh_regulators", + .id = UCLASS_MISC, + .bind = rpmh_regulators_bind, + .of_match = rpmh_regulator_ids, + .ops = &rpmh_regulator_vrm_drms_ops, +}; + +MODULE_DESCRIPTION("Qualcomm RPMh regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index 77d101f262e..88a8525b3c4 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -6,7 +6,6 @@ #define LOG_CATEGORY UCLASS_REGULATOR -#include <common.h> #include <errno.h> #include <dm.h> #include <log.h> @@ -518,7 +517,7 @@ int regulators_enable_boot_on(bool verbose) dev; uclass_next_device(&dev)) { ret = regulator_autoset(dev); - if (ret == -EMEDIUMTYPE) { + if (ret == -EMEDIUMTYPE || ret == -EALREADY) { ret = 0; continue; } diff --git a/drivers/power/regulator/regulator_common.c b/drivers/power/regulator/regulator_common.c index 0116fa01bbf..e3565d32a01 100644 --- a/drivers/power/regulator/regulator_common.c +++ b/drivers/power/regulator/regulator_common.c @@ -4,7 +4,6 @@ * Sven Schwermer <sven.svenschwermer@disruptive-technologies.com> */ -#include <common.h> #include <dm.h> #include <log.h> #include <asm/gpio.h> diff --git a/drivers/power/regulator/rk8xx.c b/drivers/power/regulator/rk8xx.c index 1bd4605d43a..34e61511d88 100644 --- a/drivers/power/regulator/rk8xx.c +++ b/drivers/power/regulator/rk8xx.c @@ -8,7 +8,6 @@ * zyw <zyw@rock-chips.com> */ -#include <common.h> #include <dm.h> #include <errno.h> #include <log.h> @@ -520,7 +519,7 @@ static int _buck_get_enable(struct udevice *pmic, int buck) if (ret < 0) return ret; - return ret & mask ? true : false; + return (ret & mask) ? true : false; } static int _buck_set_suspend_enable(struct udevice *pmic, int buck, bool enable) @@ -585,7 +584,7 @@ static int _buck_get_suspend_enable(struct udevice *pmic, int buck) val = pmic_reg_read(pmic, RK816_REG_DCDC_SLP_EN); if (val < 0) return val; - ret = val & mask ? 1 : 0; + ret = (val & mask) ? 1 : 0; break; case RK806_ID: { @@ -608,7 +607,7 @@ static int _buck_get_suspend_enable(struct udevice *pmic, int buck) val = pmic_reg_read(pmic, REG_SLEEP_SET_OFF1); if (val < 0) return val; - ret = val & mask ? 0 : 1; + ret = (val & mask) ? 0 : 1; break; case RK809_ID: case RK817_ID: @@ -620,7 +619,7 @@ static int _buck_get_suspend_enable(struct udevice *pmic, int buck) val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(0)); if (val < 0) return val; - ret = val & mask ? 1 : 0; + ret = (val & mask) ? 1 : 0; break; default: ret = -EINVAL; @@ -723,7 +722,7 @@ static int _ldo_get_enable(struct udevice *pmic, int ldo) if (ret < 0) return ret; - return ret & mask ? true : false; + return (ret & mask) ? true : false; } static int _nldo_get_enable(struct udevice *pmic, int nldo) @@ -980,7 +979,7 @@ static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo) val = pmic_reg_read(pmic, RK816_REG_LDO_SLP_EN); if (val < 0) return val; - ret = val & mask ? 1 : 0; + ret = (val & mask) ? 1 : 0; break; case RK808_ID: case RK818_ID: @@ -988,7 +987,7 @@ static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo) val = pmic_reg_read(pmic, REG_SLEEP_SET_OFF2); if (val < 0) return val; - ret = val & mask ? 0 : 1; + ret = (val & mask) ? 0 : 1; break; case RK809_ID: case RK817_ID: @@ -997,13 +996,13 @@ static int _ldo_get_suspend_enable(struct udevice *pmic, int ldo) val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(0)); if (val < 0) return val; - ret = val & mask ? 1 : 0; + ret = (val & mask) ? 1 : 0; } else { mask = 1 << ldo; val = pmic_reg_read(pmic, RK817_POWER_SLP_EN(1)); if (val < 0) return val; - ret = val & mask ? 1 : 0; + ret = (val & mask) ? 1 : 0; } break; } @@ -1134,14 +1133,14 @@ static int buck_get_enable(struct udevice *dev) return _buck_get_enable(dev->parent, buck); } -static int _ldo_get_value(struct udevice *dev, const struct rk8xx_reg_info *info) +static int _ldo_get_value(struct udevice *pmic, const struct rk8xx_reg_info *info) { int mask = info->vsel_mask; int ret, val; if (info->vsel_reg == NA) return -ENOSYS; - ret = pmic_reg_read(dev->parent, info->vsel_reg); + ret = pmic_reg_read(pmic, info->vsel_reg); if (ret < 0) return ret; val = ret & mask; @@ -1154,7 +1153,7 @@ static int ldo_get_value(struct udevice *dev) int ldo = dev->driver_data - 1; const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, 0); - return _ldo_get_value(dev, info); + return _ldo_get_value(dev->parent, info); } static int nldo_get_value(struct udevice *dev) @@ -1162,7 +1161,7 @@ static int nldo_get_value(struct udevice *dev) int nldo = dev->driver_data - 1; const struct rk8xx_reg_info *info = get_nldo_reg(dev->parent, nldo, 0); - return _ldo_get_value(dev, info); + return _ldo_get_value(dev->parent, info); } static int pldo_get_value(struct udevice *dev) @@ -1170,10 +1169,10 @@ static int pldo_get_value(struct udevice *dev) int pldo = dev->driver_data - 1; const struct rk8xx_reg_info *info = get_pldo_reg(dev->parent, pldo, 0); - return _ldo_get_value(dev, info); + return _ldo_get_value(dev->parent, info); } -static int _ldo_set_value(struct udevice *dev, const struct rk8xx_reg_info *info, int uvolt) +static int _ldo_set_value(struct udevice *pmic, const struct rk8xx_reg_info *info, int uvolt) { int mask = info->vsel_mask; int val; @@ -1189,7 +1188,7 @@ static int _ldo_set_value(struct udevice *dev, const struct rk8xx_reg_info *info debug("%s: volt=%d, reg=0x%x, mask=0x%x, val=0x%x\n", __func__, uvolt, info->vsel_reg, mask, val); - return pmic_clrsetbits(dev->parent, info->vsel_reg, mask, val); + return pmic_clrsetbits(pmic, info->vsel_reg, mask, val); } static int ldo_set_value(struct udevice *dev, int uvolt) @@ -1197,7 +1196,7 @@ static int ldo_set_value(struct udevice *dev, int uvolt) int ldo = dev->driver_data - 1; const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo, uvolt); - return _ldo_set_value(dev, info, uvolt); + return _ldo_set_value(dev->parent, info, uvolt); } static int nldo_set_value(struct udevice *dev, int uvolt) @@ -1205,7 +1204,7 @@ static int nldo_set_value(struct udevice *dev, int uvolt) int nldo = dev->driver_data - 1; const struct rk8xx_reg_info *info = get_nldo_reg(dev->parent, nldo, uvolt); - return _ldo_set_value(dev, info, uvolt); + return _ldo_set_value(dev->parent, info, uvolt); } static int pldo_set_value(struct udevice *dev, int uvolt) @@ -1213,10 +1212,10 @@ static int pldo_set_value(struct udevice *dev, int uvolt) int pldo = dev->driver_data - 1; const struct rk8xx_reg_info *info = get_pldo_reg(dev->parent, pldo, uvolt); - return _ldo_set_value(dev, info, uvolt); + return _ldo_set_value(dev->parent, info, uvolt); } -static int _ldo_set_suspend_value(struct udevice *dev, const struct rk8xx_reg_info *info, int uvolt) +static int _ldo_set_suspend_value(struct udevice *pmic, const struct rk8xx_reg_info *info, int uvolt) { int mask = info->vsel_mask; int val; @@ -1232,7 +1231,7 @@ static int _ldo_set_suspend_value(struct udevice *dev, const struct rk8xx_reg_in debug("%s: volt=%d, reg=0x%x, mask=0x%x, val=0x%x\n", __func__, uvolt, info->vsel_sleep_reg, mask, val); - return pmic_clrsetbits(dev->parent, info->vsel_sleep_reg, mask, val); + return pmic_clrsetbits(pmic, info->vsel_sleep_reg, mask, val); } static int ldo_set_suspend_value(struct udevice *dev, int uvolt) @@ -1259,7 +1258,7 @@ static int pldo_set_suspend_value(struct udevice *dev, int uvolt) return _ldo_set_suspend_value(dev->parent, info, uvolt); } -static int _ldo_get_suspend_value(struct udevice *dev, const struct rk8xx_reg_info *info) +static int _ldo_get_suspend_value(struct udevice *pmic, const struct rk8xx_reg_info *info) { int mask = info->vsel_mask; int val, ret; @@ -1267,7 +1266,7 @@ static int _ldo_get_suspend_value(struct udevice *dev, const struct rk8xx_reg_in if (info->vsel_sleep_reg == NA) return -ENOSYS; - ret = pmic_reg_read(dev->parent, info->vsel_sleep_reg); + ret = pmic_reg_read(pmic, info->vsel_sleep_reg); if (ret < 0) return ret; @@ -1438,7 +1437,7 @@ static int switch_get_enable(struct udevice *dev) if (ret < 0) return ret; - return ret & mask ? true : false; + return (ret & mask) ? true : false; } static int switch_set_suspend_value(struct udevice *dev, int uvolt) @@ -1493,21 +1492,21 @@ static int switch_get_suspend_enable(struct udevice *dev) val = pmic_reg_read(dev->parent, REG_SLEEP_SET_OFF1); if (val < 0) return val; - ret = val & mask ? 0 : 1; + ret = (val & mask) ? 0 : 1; break; case RK809_ID: mask = 1 << (sw + 6); val = pmic_reg_read(dev->parent, RK817_POWER_SLP_EN(0)); if (val < 0) return val; - ret = val & mask ? 1 : 0; + ret = (val & mask) ? 1 : 0; break; case RK818_ID: mask = 1 << 6; val = pmic_reg_read(dev->parent, REG_SLEEP_SET_OFF1); if (val < 0) return val; - ret = val & mask ? 0 : 1; + ret = (val & mask) ? 0 : 1; break; } diff --git a/drivers/power/regulator/s2mps11_regulator.c b/drivers/power/regulator/s2mps11_regulator.c index 987a1f9d863..96de55065fe 100644 --- a/drivers/power/regulator/s2mps11_regulator.c +++ b/drivers/power/regulator/s2mps11_regulator.c @@ -4,7 +4,6 @@ * Jaehoon Chung <jh80.chung@samsung.com> */ -#include <common.h> #include <fdtdec.h> #include <errno.h> #include <dm.h> diff --git a/drivers/power/regulator/s5m8767.c b/drivers/power/regulator/s5m8767.c index 23575831f38..0dcf0990802 100644 --- a/drivers/power/regulator/s5m8767.c +++ b/drivers/power/regulator/s5m8767.c @@ -3,7 +3,6 @@ * Copyright (C) 2015 Google, Inc */ -#include <common.h> #include <fdtdec.h> #include <errno.h> #include <dm.h> diff --git a/drivers/power/regulator/sandbox.c b/drivers/power/regulator/sandbox.c index 71ef0c5441a..80a68f5a30d 100644 --- a/drivers/power/regulator/sandbox.c +++ b/drivers/power/regulator/sandbox.c @@ -4,7 +4,6 @@ * Przemyslaw Marczak <p.marczak@samsung.com> */ -#include <common.h> #include <fdtdec.h> #include <errno.h> #include <dm.h> diff --git a/drivers/power/regulator/scmi_regulator.c b/drivers/power/regulator/scmi_regulator.c index 9c72c35d039..99f6506f162 100644 --- a/drivers/power/regulator/scmi_regulator.c +++ b/drivers/power/regulator/scmi_regulator.c @@ -5,7 +5,6 @@ #define LOG_CATEGORY UCLASS_REGULATOR -#include <common.h> #include <dm.h> #include <errno.h> #include <scmi_agent.h> diff --git a/drivers/power/regulator/stm32-vrefbuf.c b/drivers/power/regulator/stm32-vrefbuf.c index c37998a4bac..dd8a33f15be 100644 --- a/drivers/power/regulator/stm32-vrefbuf.c +++ b/drivers/power/regulator/stm32-vrefbuf.c @@ -8,7 +8,6 @@ #define LOG_CATEGORY UCLASS_REGULATOR -#include <common.h> #include <clk.h> #include <dm.h> #include <asm/io.h> diff --git a/drivers/power/regulator/stpmic1.c b/drivers/power/regulator/stpmic1.c index 4839d834316..b5ffa1cd589 100644 --- a/drivers/power/regulator/stpmic1.c +++ b/drivers/power/regulator/stpmic1.c @@ -4,7 +4,6 @@ * Author: Christophe Kerello <christophe.kerello@st.com> */ -#include <common.h> #include <dm.h> #include <errno.h> #include <linux/delay.h> diff --git a/drivers/power/regulator/tps62360_regulator.c b/drivers/power/regulator/tps62360_regulator.c index 7014b1982d0..9acc6b90549 100644 --- a/drivers/power/regulator/tps62360_regulator.c +++ b/drivers/power/regulator/tps62360_regulator.c @@ -4,7 +4,6 @@ * Tero Kristo <t-kristo@ti.com> */ -#include <common.h> #include <dm.h> #include <i2c.h> #include <dm/device_compat.h> diff --git a/drivers/power/regulator/tps65090_regulator.c b/drivers/power/regulator/tps65090_regulator.c index fa15e61a10e..2d414de1490 100644 --- a/drivers/power/regulator/tps65090_regulator.c +++ b/drivers/power/regulator/tps65090_regulator.c @@ -3,10 +3,10 @@ * Copyright (c) 2015 Google, Inc */ -#include <common.h> #include <dm.h> #include <errno.h> #include <log.h> +#include <time.h> #include <linux/delay.h> #include <power/pmic.h> #include <power/regulator.h> diff --git a/drivers/power/regulator/tps65219_regulator.c b/drivers/power/regulator/tps65219_regulator.c index f87d07e61fb..b7124fed024 100644 --- a/drivers/power/regulator/tps65219_regulator.c +++ b/drivers/power/regulator/tps65219_regulator.c @@ -5,7 +5,6 @@ * */ -#include <common.h> #include <fdtdec.h> #include <errno.h> #include <dm.h> diff --git a/drivers/power/regulator/tps65910_regulator.c b/drivers/power/regulator/tps65910_regulator.c index a4b9d449274..562fd7db190 100644 --- a/drivers/power/regulator/tps65910_regulator.c +++ b/drivers/power/regulator/tps65910_regulator.c @@ -3,7 +3,6 @@ * Copyright (C) EETS GmbH, 2017, Felix Brack <f.brack@eets.ch> */ -#include <common.h> #include <dm.h> #include <log.h> #include <linux/printk.h> diff --git a/drivers/power/regulator/tps65941_regulator.c b/drivers/power/regulator/tps65941_regulator.c index 5809a53fa21..bc4d153fd84 100644 --- a/drivers/power/regulator/tps65941_regulator.c +++ b/drivers/power/regulator/tps65941_regulator.c @@ -6,7 +6,6 @@ * Keerthy <j-keerthy@ti.com> */ -#include <common.h> #include <fdtdec.h> #include <errno.h> #include <dm.h> |