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(map: rdev->regmap, reg: rdev->desc->enable_reg, val: ®_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(map: rdev->regmap, reg: rdev->desc->enable_reg, |
145 | mask: info->mode_mask, val: 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(dev: 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(dev: &pdev->dev, |
182 | regulator_desc: &hi6421v530_regulator_info[i].rdesc, |
183 | config: &config); |
184 | if (IS_ERR(ptr: rdev)) { |
185 | dev_err(&pdev->dev, "failed to register regulator %s\n" , |
186 | hi6421v530_regulator_info[i].rdesc.name); |
187 | return PTR_ERR(ptr: 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 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
204 | }, |
205 | .probe = hi6421v530_regulator_probe, |
206 | }; |
207 | module_platform_driver(hi6421v530_regulator_driver); |
208 | |
209 | MODULE_AUTHOR("Wang Xiaoyin <hw.wangxiaoyin@hisilicon.com>" ); |
210 | MODULE_DESCRIPTION("Hi6421v530 regulator driver" ); |
211 | MODULE_LICENSE("GPL v2" ); |
212 | |