Commit 7cbfbe23 authored by Konrad Dybcio's avatar Konrad Dybcio Committed by Mark Brown

regulator: Introduce Qualcomm REFGEN regulator driver

Modern Qualcomm SoCs have a REFGEN (reference voltage generator)
regulator, providing reference voltage to on-chip IP, like PHYs.

Add a driver to support toggling that regulator.
Signed-off-by: default avatarKonrad Dybcio <konrad.dybcio@linaro.org>
Link: https://lore.kernel.org/r/20230628-topic-refgen-v3-2-9fbf0e605d23@linaro.orgSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent d16db38c
...@@ -989,6 +989,17 @@ config REGULATOR_PWM ...@@ -989,6 +989,17 @@ config REGULATOR_PWM
This driver supports PWM controlled voltage regulators. PWM This driver supports PWM controlled voltage regulators. PWM
duty cycle can increase or decrease the voltage. duty cycle can increase or decrease the voltage.
config REGULATOR_QCOM_REFGEN
tristate "Qualcomm REFGEN regulator driver"
depends on HAS_IOMEM
depends on REGMAP
help
This driver supports the MMIO-mapped reference voltage regulator,
used internally by some PHYs on many Qualcomm SoCs.
Say M here if you want to include support for this regulator as
a module. The module will be named "qcom-refgen-regulator".
config REGULATOR_QCOM_RPM config REGULATOR_QCOM_RPM
tristate "Qualcomm RPM regulator driver" tristate "Qualcomm RPM regulator driver"
depends on MFD_QCOM_RPM depends on MFD_QCOM_RPM
......
...@@ -108,6 +108,7 @@ obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o ...@@ -108,6 +108,7 @@ obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_LABIBB) += qcom-labibb-regulator.o obj-$(CONFIG_REGULATOR_QCOM_LABIBB) += qcom-labibb-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_REFGEN) += qcom-refgen-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
......
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2017, 2019-2020, The Linux Foundation. All rights reserved.
// Copyright (c) 2023, Linaro Limited
#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#define REFGEN_REG_BIAS_EN 0x08
#define REFGEN_BIAS_EN_MASK GENMASK(2, 0)
#define REFGEN_BIAS_EN_ENABLE 0x7
#define REFGEN_BIAS_EN_DISABLE 0x6
#define REFGEN_REG_BG_CTRL 0x14
#define REFGEN_BG_CTRL_MASK GENMASK(2, 1)
#define REFGEN_BG_CTRL_ENABLE 0x3
#define REFGEN_BG_CTRL_DISABLE 0x2
#define REFGEN_REG_PWRDWN_CTRL5 0x80
#define REFGEN_PWRDWN_CTRL5_MASK BIT(0)
#define REFGEN_PWRDWN_CTRL5_ENABLE 0x1
static int qcom_sdm845_refgen_enable(struct regulator_dev *rdev)
{
regmap_update_bits(rdev->regmap, REFGEN_REG_BG_CTRL, REFGEN_BG_CTRL_MASK,
FIELD_PREP(REFGEN_BG_CTRL_MASK, REFGEN_BG_CTRL_ENABLE));
regmap_write(rdev->regmap, REFGEN_REG_BIAS_EN,
FIELD_PREP(REFGEN_BIAS_EN_MASK, REFGEN_BIAS_EN_ENABLE));
return 0;
}
static int qcom_sdm845_refgen_disable(struct regulator_dev *rdev)
{
regmap_write(rdev->regmap, REFGEN_REG_BIAS_EN,
FIELD_PREP(REFGEN_BIAS_EN_MASK, REFGEN_BIAS_EN_DISABLE));
regmap_update_bits(rdev->regmap, REFGEN_REG_BG_CTRL, REFGEN_BG_CTRL_MASK,
FIELD_PREP(REFGEN_BG_CTRL_MASK, REFGEN_BG_CTRL_DISABLE));
return 0;
}
static int qcom_sdm845_refgen_is_enabled(struct regulator_dev *rdev)
{
u32 val;
regmap_read(rdev->regmap, REFGEN_REG_BG_CTRL, &val);
if (FIELD_GET(REFGEN_BG_CTRL_MASK, val) != REFGEN_BG_CTRL_ENABLE)
return 0;
regmap_read(rdev->regmap, REFGEN_REG_BIAS_EN, &val);
if (FIELD_GET(REFGEN_BIAS_EN_MASK, val) != REFGEN_BIAS_EN_ENABLE)
return 0;
return 1;
}
static struct regulator_desc sdm845_refgen_desc = {
.enable_time = 5,
.name = "refgen",
.owner = THIS_MODULE,
.type = REGULATOR_VOLTAGE,
.ops = &(const struct regulator_ops) {
.enable = qcom_sdm845_refgen_enable,
.disable = qcom_sdm845_refgen_disable,
.is_enabled = qcom_sdm845_refgen_is_enabled,
},
};
static struct regulator_desc sm8250_refgen_desc = {
.enable_reg = REFGEN_REG_PWRDWN_CTRL5,
.enable_mask = REFGEN_PWRDWN_CTRL5_MASK,
.enable_val = REFGEN_PWRDWN_CTRL5_ENABLE,
.disable_val = 0,
.enable_time = 5,
.name = "refgen",
.owner = THIS_MODULE,
.type = REGULATOR_VOLTAGE,
.ops = &(const struct regulator_ops) {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
},
};
static const struct regmap_config qcom_refgen_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.fast_io = true,
};
static int qcom_refgen_probe(struct platform_device *pdev)
{
struct regulator_init_data *init_data;
struct regulator_config config = {};
const struct regulator_desc *rdesc;
struct device *dev = &pdev->dev;
struct regulator_dev *rdev;
struct regmap *regmap;
void __iomem *base;
rdesc = of_device_get_match_data(dev);
if (!rdesc)
return -ENODATA;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
regmap = devm_regmap_init_mmio(dev, base, &qcom_refgen_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
init_data = of_get_regulator_init_data(dev, dev->of_node, rdesc);
if (!init_data)
return -ENOMEM;
config.dev = dev;
config.init_data = init_data;
config.of_node = dev->of_node;
config.regmap = regmap;
rdev = devm_regulator_register(dev, rdesc, &config);
if (IS_ERR(rdev))
return PTR_ERR(rdev);
return 0;
}
static const struct of_device_id qcom_refgen_match_table[] = {
{ .compatible = "qcom,sdm845-refgen-regulator", .data = &sdm845_refgen_desc },
{ .compatible = "qcom,sm8250-refgen-regulator", .data = &sm8250_refgen_desc },
{ }
};
static struct platform_driver qcom_refgen_driver = {
.probe = qcom_refgen_probe,
.driver = {
.name = "qcom-refgen-regulator",
.of_match_table = qcom_refgen_match_table,
},
};
module_platform_driver(qcom_refgen_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Qualcomm REFGEN regulator driver");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment