GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / regulator / qcom-refgen-regulator.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (c) 2017, 2019-2020, The Linux Foundation. All rights reserved.
3 // Copyright (c) 2023, Linaro Limited
4
5 #include <linux/bitfield.h>
6 #include <linux/module.h>
7 #include <linux/of.h>
8 #include <linux/platform_device.h>
9 #include <linux/regmap.h>
10 #include <linux/regulator/driver.h>
11 #include <linux/regulator/machine.h>
12 #include <linux/regulator/of_regulator.h>
13
14 #define REFGEN_REG_BIAS_EN              0x08
15 #define REFGEN_BIAS_EN_MASK             GENMASK(2, 0)
16  #define REFGEN_BIAS_EN_ENABLE          0x7
17  #define REFGEN_BIAS_EN_DISABLE         0x6
18
19 #define REFGEN_REG_BG_CTRL              0x14
20 #define REFGEN_BG_CTRL_MASK             GENMASK(2, 1)
21  #define REFGEN_BG_CTRL_ENABLE          0x3
22  #define REFGEN_BG_CTRL_DISABLE         0x2
23
24 #define REFGEN_REG_PWRDWN_CTRL5         0x80
25 #define REFGEN_PWRDWN_CTRL5_MASK        BIT(0)
26  #define REFGEN_PWRDWN_CTRL5_ENABLE     0x1
27
28 static int qcom_sdm845_refgen_enable(struct regulator_dev *rdev)
29 {
30         regmap_update_bits(rdev->regmap, REFGEN_REG_BG_CTRL, REFGEN_BG_CTRL_MASK,
31                            FIELD_PREP(REFGEN_BG_CTRL_MASK, REFGEN_BG_CTRL_ENABLE));
32
33         regmap_write(rdev->regmap, REFGEN_REG_BIAS_EN,
34                      FIELD_PREP(REFGEN_BIAS_EN_MASK, REFGEN_BIAS_EN_ENABLE));
35
36         return 0;
37 }
38
39 static int qcom_sdm845_refgen_disable(struct regulator_dev *rdev)
40 {
41         regmap_write(rdev->regmap, REFGEN_REG_BIAS_EN,
42                      FIELD_PREP(REFGEN_BIAS_EN_MASK, REFGEN_BIAS_EN_DISABLE));
43
44         regmap_update_bits(rdev->regmap, REFGEN_REG_BG_CTRL, REFGEN_BG_CTRL_MASK,
45                            FIELD_PREP(REFGEN_BG_CTRL_MASK, REFGEN_BG_CTRL_DISABLE));
46
47         return 0;
48 }
49
50 static int qcom_sdm845_refgen_is_enabled(struct regulator_dev *rdev)
51 {
52         u32 val;
53
54         regmap_read(rdev->regmap, REFGEN_REG_BG_CTRL, &val);
55         if (FIELD_GET(REFGEN_BG_CTRL_MASK, val) != REFGEN_BG_CTRL_ENABLE)
56                 return 0;
57
58         regmap_read(rdev->regmap, REFGEN_REG_BIAS_EN, &val);
59         if (FIELD_GET(REFGEN_BIAS_EN_MASK, val) != REFGEN_BIAS_EN_ENABLE)
60                 return 0;
61
62         return 1;
63 }
64
65 static struct regulator_desc sdm845_refgen_desc = {
66         .enable_time = 5,
67         .name = "refgen",
68         .owner = THIS_MODULE,
69         .type = REGULATOR_VOLTAGE,
70         .ops = &(const struct regulator_ops) {
71                 .enable         = qcom_sdm845_refgen_enable,
72                 .disable        = qcom_sdm845_refgen_disable,
73                 .is_enabled     = qcom_sdm845_refgen_is_enabled,
74         },
75 };
76
77 static struct regulator_desc sm8250_refgen_desc = {
78         .enable_reg = REFGEN_REG_PWRDWN_CTRL5,
79         .enable_mask = REFGEN_PWRDWN_CTRL5_MASK,
80         .enable_val = REFGEN_PWRDWN_CTRL5_ENABLE,
81         .disable_val = 0,
82         .enable_time = 5,
83         .name = "refgen",
84         .owner = THIS_MODULE,
85         .type = REGULATOR_VOLTAGE,
86         .ops = &(const struct regulator_ops) {
87                 .enable         = regulator_enable_regmap,
88                 .disable        = regulator_disable_regmap,
89                 .is_enabled     = regulator_is_enabled_regmap,
90         },
91 };
92
93 static const struct regmap_config qcom_refgen_regmap_config = {
94         .reg_bits = 32,
95         .reg_stride = 4,
96         .val_bits = 32,
97         .fast_io = true,
98 };
99
100 static int qcom_refgen_probe(struct platform_device *pdev)
101 {
102         struct regulator_init_data *init_data;
103         struct regulator_config config = {};
104         const struct regulator_desc *rdesc;
105         struct device *dev = &pdev->dev;
106         struct regulator_dev *rdev;
107         struct regmap *regmap;
108         void __iomem *base;
109
110         rdesc = of_device_get_match_data(dev);
111         if (!rdesc)
112                 return -ENODATA;
113
114         base = devm_platform_ioremap_resource(pdev, 0);
115         if (IS_ERR(base))
116                 return PTR_ERR(base);
117
118         regmap = devm_regmap_init_mmio(dev, base, &qcom_refgen_regmap_config);
119         if (IS_ERR(regmap))
120                 return PTR_ERR(regmap);
121
122         init_data = of_get_regulator_init_data(dev, dev->of_node, rdesc);
123         if (!init_data)
124                 return -ENOMEM;
125
126         config.dev = dev;
127         config.init_data = init_data;
128         config.of_node = dev->of_node;
129         config.regmap = regmap;
130
131         rdev = devm_regulator_register(dev, rdesc, &config);
132         if (IS_ERR(rdev))
133                 return PTR_ERR(rdev);
134
135         return 0;
136 }
137
138 static const struct of_device_id qcom_refgen_match_table[] = {
139         { .compatible = "qcom,sdm845-refgen-regulator", .data = &sdm845_refgen_desc },
140         { .compatible = "qcom,sm8250-refgen-regulator", .data = &sm8250_refgen_desc },
141         { }
142 };
143
144 static struct platform_driver qcom_refgen_driver = {
145         .probe = qcom_refgen_probe,
146         .driver = {
147                 .name = "qcom-refgen-regulator",
148                 .of_match_table = qcom_refgen_match_table,
149         },
150 };
151 module_platform_driver(qcom_refgen_driver);
152
153 MODULE_LICENSE("GPL");
154 MODULE_DESCRIPTION("Qualcomm REFGEN regulator driver");