1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
// 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 const 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 const 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 },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_refgen_match_table);
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");
|