1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // Device driver for regulators in Hisi IC |
4 | // |
5 | // Copyright (c) 2013 Linaro Ltd. |
6 | // Copyright (c) 2011 HiSilicon Ltd. |
7 | // Copyright (c) 2020-2021 Huawei Technologies Co., Ltd. |
8 | // |
9 | // Guodong Xu <guodong.xu@linaro.org> |
10 | |
11 | #include <linux/delay.h> |
12 | #include <linux/module.h> |
13 | #include <linux/of.h> |
14 | #include <linux/platform_device.h> |
15 | #include <linux/regmap.h> |
16 | #include <linux/regulator/driver.h> |
17 | #include <linux/spmi.h> |
18 | |
19 | struct hi6421_spmi_reg_priv { |
20 | /* Serialize regulator enable logic */ |
21 | struct mutex enable_mutex; |
22 | }; |
23 | |
24 | struct hi6421_spmi_reg_info { |
25 | struct regulator_desc desc; |
26 | u8 eco_mode_mask; |
27 | u32 eco_uA; |
28 | }; |
29 | |
30 | static const unsigned int range_1v5_to_2v0[] = { |
31 | 1500000, 1550000, 1600000, 1650000, |
32 | 1700000, 1725000, 1750000, 1775000, |
33 | 1800000, 1825000, 1850000, 1875000, |
34 | 1900000, 1925000, 1950000, 2000000 |
35 | }; |
36 | |
37 | static const unsigned int range_1v725_to_1v9[] = { |
38 | 1725000, 1750000, 1775000, 1800000, |
39 | 1825000, 1850000, 1875000, 1900000 |
40 | }; |
41 | |
42 | static const unsigned int range_1v75_to_3v3[] = { |
43 | 1750000, 1800000, 1825000, 2800000, |
44 | 2850000, 2950000, 3000000, 3300000 |
45 | }; |
46 | |
47 | static const unsigned int range_1v8_to_3v0[] = { |
48 | 1800000, 1850000, 2400000, 2600000, |
49 | 2700000, 2850000, 2950000, 3000000 |
50 | }; |
51 | |
52 | static const unsigned int range_2v5_to_3v3[] = { |
53 | 2500000, 2600000, 2700000, 2800000, |
54 | 3000000, 3100000, 3200000, 3300000 |
55 | }; |
56 | |
57 | static const unsigned int range_2v6_to_3v3[] = { |
58 | 2600000, 2700000, 2800000, 2900000, |
59 | 3000000, 3100000, 3200000, 3300000 |
60 | }; |
61 | |
62 | /** |
63 | * HI6421V600_LDO() - specify a LDO power line |
64 | * @_id: LDO id name string |
65 | * @vtable: voltage table |
66 | * @ereg: enable register |
67 | * @emask: enable mask |
68 | * @vreg: voltage select register |
69 | * @odelay: off/on delay time in uS |
70 | * @etime: enable time in uS |
71 | * @ecomask: eco mode mask |
72 | * @ecoamp: eco mode load uppler limit in uA |
73 | */ |
74 | #define HI6421V600_LDO(_id, vtable, ereg, emask, vreg, \ |
75 | odelay, etime, ecomask, ecoamp) \ |
76 | [hi6421v600_##_id] = { \ |
77 | .desc = { \ |
78 | .name = #_id, \ |
79 | .of_match = of_match_ptr(#_id), \ |
80 | .regulators_node = of_match_ptr("regulators"), \ |
81 | .ops = &hi6421_spmi_ldo_rops, \ |
82 | .type = REGULATOR_VOLTAGE, \ |
83 | .id = hi6421v600_##_id, \ |
84 | .owner = THIS_MODULE, \ |
85 | .volt_table = vtable, \ |
86 | .n_voltages = ARRAY_SIZE(vtable), \ |
87 | .vsel_mask = ARRAY_SIZE(vtable) - 1, \ |
88 | .vsel_reg = vreg, \ |
89 | .enable_reg = ereg, \ |
90 | .enable_mask = emask, \ |
91 | .enable_time = etime, \ |
92 | .ramp_delay = etime, \ |
93 | .off_on_delay = odelay, \ |
94 | }, \ |
95 | .eco_mode_mask = ecomask, \ |
96 | .eco_uA = ecoamp, \ |
97 | } |
98 | |
99 | static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev) |
100 | { |
101 | struct hi6421_spmi_reg_priv *priv = rdev_get_drvdata(rdev); |
102 | int ret; |
103 | |
104 | /* cannot enable more than one regulator at one time */ |
105 | mutex_lock(&priv->enable_mutex); |
106 | |
107 | ret = regmap_update_bits(map: rdev->regmap, reg: rdev->desc->enable_reg, |
108 | mask: rdev->desc->enable_mask, |
109 | val: rdev->desc->enable_mask); |
110 | |
111 | /* Avoid powering up multiple devices at the same time */ |
112 | usleep_range(min: rdev->desc->off_on_delay, max: rdev->desc->off_on_delay + 60); |
113 | |
114 | mutex_unlock(lock: &priv->enable_mutex); |
115 | |
116 | return ret; |
117 | } |
118 | |
119 | static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev) |
120 | { |
121 | struct hi6421_spmi_reg_info *sreg; |
122 | unsigned int reg_val; |
123 | |
124 | sreg = container_of(rdev->desc, struct hi6421_spmi_reg_info, desc); |
125 | regmap_read(map: rdev->regmap, reg: rdev->desc->enable_reg, val: ®_val); |
126 | |
127 | if (reg_val & sreg->eco_mode_mask) |
128 | return REGULATOR_MODE_IDLE; |
129 | |
130 | return REGULATOR_MODE_NORMAL; |
131 | } |
132 | |
133 | static int hi6421_spmi_regulator_set_mode(struct regulator_dev *rdev, |
134 | unsigned int mode) |
135 | { |
136 | struct hi6421_spmi_reg_info *sreg; |
137 | unsigned int val; |
138 | |
139 | sreg = container_of(rdev->desc, struct hi6421_spmi_reg_info, desc); |
140 | switch (mode) { |
141 | case REGULATOR_MODE_NORMAL: |
142 | val = 0; |
143 | break; |
144 | case REGULATOR_MODE_IDLE: |
145 | if (!sreg->eco_mode_mask) |
146 | return -EINVAL; |
147 | |
148 | val = sreg->eco_mode_mask; |
149 | break; |
150 | default: |
151 | return -EINVAL; |
152 | } |
153 | |
154 | return regmap_update_bits(map: rdev->regmap, reg: rdev->desc->enable_reg, |
155 | mask: sreg->eco_mode_mask, val); |
156 | } |
157 | |
158 | static unsigned int |
159 | hi6421_spmi_regulator_get_optimum_mode(struct regulator_dev *rdev, |
160 | int input_uV, int output_uV, |
161 | int load_uA) |
162 | { |
163 | struct hi6421_spmi_reg_info *sreg; |
164 | |
165 | sreg = container_of(rdev->desc, struct hi6421_spmi_reg_info, desc); |
166 | |
167 | if (!sreg->eco_uA || ((unsigned int)load_uA > sreg->eco_uA)) |
168 | return REGULATOR_MODE_NORMAL; |
169 | |
170 | return REGULATOR_MODE_IDLE; |
171 | } |
172 | |
173 | static const struct regulator_ops hi6421_spmi_ldo_rops = { |
174 | .is_enabled = regulator_is_enabled_regmap, |
175 | .enable = hi6421_spmi_regulator_enable, |
176 | .disable = regulator_disable_regmap, |
177 | .list_voltage = regulator_list_voltage_table, |
178 | .map_voltage = regulator_map_voltage_ascend, |
179 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
180 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
181 | .get_mode = hi6421_spmi_regulator_get_mode, |
182 | .set_mode = hi6421_spmi_regulator_set_mode, |
183 | .get_optimum_mode = hi6421_spmi_regulator_get_optimum_mode, |
184 | }; |
185 | |
186 | /* HI6421v600 regulators with known registers */ |
187 | enum hi6421_spmi_regulator_id { |
188 | hi6421v600_ldo3, |
189 | hi6421v600_ldo4, |
190 | hi6421v600_ldo9, |
191 | hi6421v600_ldo15, |
192 | hi6421v600_ldo16, |
193 | hi6421v600_ldo17, |
194 | hi6421v600_ldo33, |
195 | hi6421v600_ldo34, |
196 | }; |
197 | |
198 | static struct hi6421_spmi_reg_info regulator_info[] = { |
199 | HI6421V600_LDO(ldo3, range_1v5_to_2v0, |
200 | 0x16, 0x01, 0x51, |
201 | 20000, 120, |
202 | 0, 0), |
203 | HI6421V600_LDO(ldo4, range_1v725_to_1v9, |
204 | 0x17, 0x01, 0x52, |
205 | 20000, 120, |
206 | 0x10, 10000), |
207 | HI6421V600_LDO(ldo9, range_1v75_to_3v3, |
208 | 0x1c, 0x01, 0x57, |
209 | 20000, 360, |
210 | 0x10, 10000), |
211 | HI6421V600_LDO(ldo15, range_1v8_to_3v0, |
212 | 0x21, 0x01, 0x5c, |
213 | 20000, 360, |
214 | 0x10, 10000), |
215 | HI6421V600_LDO(ldo16, range_1v8_to_3v0, |
216 | 0x22, 0x01, 0x5d, |
217 | 20000, 360, |
218 | 0x10, 10000), |
219 | HI6421V600_LDO(ldo17, range_2v5_to_3v3, |
220 | 0x23, 0x01, 0x5e, |
221 | 20000, 120, |
222 | 0x10, 10000), |
223 | HI6421V600_LDO(ldo33, range_2v5_to_3v3, |
224 | 0x32, 0x01, 0x6d, |
225 | 20000, 120, |
226 | 0, 0), |
227 | HI6421V600_LDO(ldo34, range_2v6_to_3v3, |
228 | 0x33, 0x01, 0x6e, |
229 | 20000, 120, |
230 | 0, 0), |
231 | }; |
232 | |
233 | static int hi6421_spmi_regulator_probe(struct platform_device *pdev) |
234 | { |
235 | struct device *pmic_dev = pdev->dev.parent; |
236 | struct regulator_config config = { }; |
237 | struct hi6421_spmi_reg_priv *priv; |
238 | struct hi6421_spmi_reg_info *info; |
239 | struct device *dev = &pdev->dev; |
240 | struct regmap *regmap; |
241 | struct regulator_dev *rdev; |
242 | int i; |
243 | |
244 | /* |
245 | * This driver is meant to be called by hi6421-spmi-core, |
246 | * which should first set drvdata. If this doesn't happen, hit |
247 | * a warn on and return. |
248 | */ |
249 | regmap = dev_get_drvdata(dev: pmic_dev); |
250 | if (WARN_ON(!regmap)) |
251 | return -ENODEV; |
252 | |
253 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
254 | if (!priv) |
255 | return -ENOMEM; |
256 | |
257 | mutex_init(&priv->enable_mutex); |
258 | |
259 | for (i = 0; i < ARRAY_SIZE(regulator_info); i++) { |
260 | info = ®ulator_info[i]; |
261 | |
262 | config.dev = pdev->dev.parent; |
263 | config.driver_data = priv; |
264 | config.regmap = regmap; |
265 | |
266 | rdev = devm_regulator_register(dev, regulator_desc: &info->desc, config: &config); |
267 | if (IS_ERR(ptr: rdev)) { |
268 | dev_err(dev, "failed to register %s\n" , |
269 | info->desc.name); |
270 | return PTR_ERR(ptr: rdev); |
271 | } |
272 | } |
273 | |
274 | return 0; |
275 | } |
276 | |
277 | static const struct platform_device_id hi6421_spmi_regulator_table[] = { |
278 | { .name = "hi6421v600-regulator" }, |
279 | {}, |
280 | }; |
281 | MODULE_DEVICE_TABLE(platform, hi6421_spmi_regulator_table); |
282 | |
283 | static struct platform_driver hi6421_spmi_regulator_driver = { |
284 | .id_table = hi6421_spmi_regulator_table, |
285 | .driver = { |
286 | .name = "hi6421v600-regulator" , |
287 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
288 | }, |
289 | .probe = hi6421_spmi_regulator_probe, |
290 | }; |
291 | module_platform_driver(hi6421_spmi_regulator_driver); |
292 | |
293 | MODULE_DESCRIPTION("Hi6421v600 SPMI regulator driver" ); |
294 | MODULE_LICENSE("GPL v2" ); |
295 | |
296 | |