Merge tag 'pm-5.11-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
[linux-2.6-microblaze.git] / drivers / regulator / hi6421v530-regulator.c
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Device driver for regulators in Hi6421V530 IC
4 //
5 // Copyright (c) <2017> HiSilicon Technologies Co., Ltd.
6 //              http://www.hisilicon.com
7 // Copyright (c) <2017> Linaro Ltd.
8 //              https://www.linaro.org
9 //
10 // Author: Wang Xiaoyin <hw.wangxiaoyin@hisilicon.com>
11 //         Guodong Xu <guodong.xu@linaro.org>
12
13 #include <linux/mfd/hi6421-pmic.h>
14 #include <linux/module.h>
15 #include <linux/of.h>
16 #include <linux/platform_device.h>
17 #include <linux/regmap.h>
18 #include <linux/regulator/driver.h>
19
20 /*
21  * struct hi6421v530_regulator_info - hi6421v530 regulator information
22  * @desc: regulator description
23  * @mode_mask: ECO mode bitmask of LDOs; for BUCKs, this masks sleep
24  * @eco_microamp: eco mode load upper limit (in uA), valid for LDOs only
25  */
26 struct hi6421v530_regulator_info {
27         struct regulator_desc rdesc;
28         u8 mode_mask;
29         u32 eco_microamp;
30 };
31
32 /* HI6421v530 regulators */
33 enum hi6421v530_regulator_id {
34         HI6421V530_LDO3,
35         HI6421V530_LDO9,
36         HI6421V530_LDO11,
37         HI6421V530_LDO15,
38         HI6421V530_LDO16,
39 };
40
41 static const unsigned int ldo_3_voltages[] = {
42         1800000, 1825000, 1850000, 1875000,
43         1900000, 1925000, 1950000, 1975000,
44         2000000, 2025000, 2050000, 2075000,
45         2100000, 2125000, 2150000, 2200000,
46 };
47
48 static const unsigned int ldo_9_11_voltages[] = {
49         1750000, 1800000, 1825000, 2800000,
50         2850000, 2950000, 3000000, 3300000,
51 };
52
53 static const unsigned int ldo_15_16_voltages[] = {
54         1750000, 1800000, 2400000, 2600000,
55         2700000, 2850000, 2950000, 3000000,
56 };
57
58 static const struct regulator_ops hi6421v530_ldo_ops;
59
60 #define HI6421V530_LDO_ENABLE_TIME (350)
61
62 /*
63  * _id - LDO id name string
64  * v_table - voltage table
65  * vreg - voltage select register
66  * vmask - voltage select mask
67  * ereg - enable register
68  * emask - enable mask
69  * odelay - off/on delay time in uS
70  * ecomask - eco mode mask
71  * ecoamp - eco mode load uppler limit in uA
72  */
73 #define HI6421V530_LDO(_ID, v_table, vreg, vmask, ereg, emask,          \
74                    odelay, ecomask, ecoamp) {                           \
75         .rdesc = {                                                      \
76                 .name            = #_ID,                                \
77                 .of_match        = of_match_ptr(#_ID),                  \
78                 .regulators_node = of_match_ptr("regulators"),          \
79                 .ops             = &hi6421v530_ldo_ops,                 \
80                 .type            = REGULATOR_VOLTAGE,                   \
81                 .id              = HI6421V530_##_ID,                    \
82                 .owner           = THIS_MODULE,                         \
83                 .n_voltages      = ARRAY_SIZE(v_table),                 \
84                 .volt_table      = v_table,                             \
85                 .vsel_reg        = HI6421_REG_TO_BUS_ADDR(vreg),        \
86                 .vsel_mask       = vmask,                               \
87                 .enable_reg      = HI6421_REG_TO_BUS_ADDR(ereg),        \
88                 .enable_mask     = emask,                               \
89                 .enable_time     = HI6421V530_LDO_ENABLE_TIME,          \
90                 .off_on_delay    = odelay,                              \
91         },                                                              \
92         .mode_mask      = ecomask,                                      \
93         .eco_microamp   = ecoamp,                                       \
94 }
95
96 /* HI6421V530 regulator information */
97
98 static struct hi6421v530_regulator_info hi6421v530_regulator_info[] = {
99         HI6421V530_LDO(LDO3, ldo_3_voltages, 0x061, 0xf, 0x060, 0x2,
100                    20000, 0x6, 8000),
101         HI6421V530_LDO(LDO9, ldo_9_11_voltages, 0x06b, 0x7, 0x06a, 0x2,
102                    40000, 0x6, 8000),
103         HI6421V530_LDO(LDO11, ldo_9_11_voltages, 0x06f, 0x7, 0x06e, 0x2,
104                    40000, 0x6, 8000),
105         HI6421V530_LDO(LDO15, ldo_15_16_voltages, 0x077, 0x7, 0x076, 0x2,
106                    40000, 0x6, 8000),
107         HI6421V530_LDO(LDO16, ldo_15_16_voltages, 0x079, 0x7, 0x078, 0x2,
108                    40000, 0x6, 8000),
109 };
110
111 static unsigned int hi6421v530_regulator_ldo_get_mode(
112                                         struct regulator_dev *rdev)
113 {
114         struct hi6421v530_regulator_info *info;
115         unsigned int reg_val;
116
117         info = rdev_get_drvdata(rdev);
118         regmap_read(rdev->regmap, rdev->desc->enable_reg, &reg_val);
119
120         if (reg_val & (info->mode_mask))
121                 return REGULATOR_MODE_IDLE;
122
123         return REGULATOR_MODE_NORMAL;
124 }
125
126 static int hi6421v530_regulator_ldo_set_mode(struct regulator_dev *rdev,
127                                                 unsigned int mode)
128 {
129         struct hi6421v530_regulator_info *info;
130         unsigned int new_mode;
131
132         info = rdev_get_drvdata(rdev);
133         switch (mode) {
134         case REGULATOR_MODE_NORMAL:
135                 new_mode = 0;
136                 break;
137         case REGULATOR_MODE_IDLE:
138                 new_mode = info->mode_mask;
139                 break;
140         default:
141                 return -EINVAL;
142         }
143
144         regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
145                            info->mode_mask, new_mode);
146
147         return 0;
148 }
149
150
151 static const struct regulator_ops hi6421v530_ldo_ops = {
152         .is_enabled = regulator_is_enabled_regmap,
153         .enable = regulator_enable_regmap,
154         .disable = regulator_disable_regmap,
155         .list_voltage = regulator_list_voltage_table,
156         .map_voltage = regulator_map_voltage_ascend,
157         .get_voltage_sel = regulator_get_voltage_sel_regmap,
158         .set_voltage_sel = regulator_set_voltage_sel_regmap,
159         .get_mode = hi6421v530_regulator_ldo_get_mode,
160         .set_mode = hi6421v530_regulator_ldo_set_mode,
161 };
162
163 static int hi6421v530_regulator_probe(struct platform_device *pdev)
164 {
165         struct hi6421_pmic *pmic;
166         struct regulator_dev *rdev;
167         struct regulator_config config = { };
168         unsigned int i;
169
170         pmic = dev_get_drvdata(pdev->dev.parent);
171         if (!pmic) {
172                 dev_err(&pdev->dev, "no pmic in the regulator parent node\n");
173                 return -ENODEV;
174         }
175
176         for (i = 0; i < ARRAY_SIZE(hi6421v530_regulator_info); i++) {
177                 config.dev = pdev->dev.parent;
178                 config.regmap = pmic->regmap;
179                 config.driver_data = &hi6421v530_regulator_info[i];
180
181                 rdev = devm_regulator_register(&pdev->dev,
182                                 &hi6421v530_regulator_info[i].rdesc,
183                                 &config);
184                 if (IS_ERR(rdev)) {
185                         dev_err(&pdev->dev, "failed to register regulator %s\n",
186                                 hi6421v530_regulator_info[i].rdesc.name);
187                         return PTR_ERR(rdev);
188                 }
189         }
190         return 0;
191 }
192
193 static const struct platform_device_id hi6421v530_regulator_table[] = {
194         { .name = "hi6421v530-regulator" },
195         {},
196 };
197 MODULE_DEVICE_TABLE(platform, hi6421v530_regulator_table);
198
199 static struct platform_driver hi6421v530_regulator_driver = {
200         .id_table = hi6421v530_regulator_table,
201         .driver = {
202                 .name   = "hi6421v530-regulator",
203         },
204         .probe  = hi6421v530_regulator_probe,
205 };
206 module_platform_driver(hi6421v530_regulator_driver);
207
208 MODULE_AUTHOR("Wang Xiaoyin <hw.wangxiaoyin@hisilicon.com>");
209 MODULE_DESCRIPTION("Hi6421v530 regulator driver");
210 MODULE_LICENSE("GPL v2");