blob: 9c7ebf78a00e872ecd345a49a91b97e4a76a4f6d [file] [log] [blame]
Banajit Goswamide8271c2017-01-18 00:28:59 -08001/*
2 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/of_irq.h>
17#include <linux/of_device.h>
18#include <linux/slab.h>
19#include <linux/mfd/msm-cdc-supply.h>
20#include <linux/regulator/consumer.h>
21
22#define CODEC_DT_MAX_PROP_SIZE 40
23
24static int msm_cdc_dt_parse_vreg_info(struct device *dev,
25 struct cdc_regulator *cdc_vreg,
26 const char *name, bool is_ond)
27{
28 char prop_name[CODEC_DT_MAX_PROP_SIZE];
29 struct device_node *regulator_node = NULL;
30 const __be32 *prop;
31 int len, rc;
32 u32 prop_val;
33
34 /* Parse supply name */
35 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply", name);
36
37 regulator_node = of_parse_phandle(dev->of_node, prop_name, 0);
38 if (!regulator_node) {
39 dev_err(dev, "%s: Looking up %s property in node %s failed",
40 __func__, prop_name, dev->of_node->full_name);
41 rc = -EINVAL;
42 goto done;
43 }
44 cdc_vreg->name = name;
45 cdc_vreg->ondemand = is_ond;
46
47 /* Parse supply - voltage */
48 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "qcom,%s-voltage", name);
49 prop = of_get_property(dev->of_node, prop_name, &len);
50 if (!prop || (len != (2 * sizeof(__be32)))) {
51 dev_err(dev, "%s: %s %s property\n", __func__,
52 prop ? "invalid format" : "no", prop_name);
53 rc = -EINVAL;
54 goto done;
55 } else {
56 cdc_vreg->min_uV = be32_to_cpup(&prop[0]);
57 cdc_vreg->max_uV = be32_to_cpup(&prop[1]);
58 }
59
60 /* Parse supply - current */
61 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "qcom,%s-current", name);
62 rc = of_property_read_u32(dev->of_node, prop_name, &prop_val);
63 if (rc) {
64 dev_err(dev, "%s: Looking up %s property in node %s failed",
65 __func__, prop_name, dev->of_node->full_name);
66 goto done;
67 }
68 cdc_vreg->optimum_uA = prop_val;
69
70 dev_info(dev, "%s: %s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n",
71 __func__, cdc_vreg->name, cdc_vreg->min_uV, cdc_vreg->max_uV,
72 cdc_vreg->optimum_uA, cdc_vreg->ondemand);
73
74done:
75 return rc;
76}
77
78static int msm_cdc_parse_supplies(struct device *dev,
79 struct cdc_regulator *cdc_reg,
80 const char *sup_list, int sup_cnt,
81 bool is_ond)
82{
83 int idx, rc = 0;
84 const char *name = NULL;
85
86 for (idx = 0; idx < sup_cnt; idx++) {
87 rc = of_property_read_string_index(dev->of_node, sup_list, idx,
88 &name);
89 if (rc) {
90 dev_err(dev, "%s: read string %s[%d] error (%d)\n",
91 __func__, sup_list, idx, rc);
92 goto done;
93 }
94
95 dev_dbg(dev, "%s: Found cdc supply %s as part of %s\n",
96 __func__, name, sup_list);
97
98 rc = msm_cdc_dt_parse_vreg_info(dev, &cdc_reg[idx], name,
99 is_ond);
100 if (rc) {
101 dev_err(dev, "%s: parse %s vreg info failed (%d)\n",
102 __func__, name, rc);
103 goto done;
104 }
105 }
106
107done:
108 return rc;
109}
110
111static int msm_cdc_check_supply_param(struct device *dev,
112 struct cdc_regulator *cdc_vreg,
113 int num_supplies)
114{
115 if (!dev) {
116 pr_err("%s: device is NULL\n", __func__);
117 return -ENODEV;
118 }
119
120 if (!cdc_vreg || (num_supplies <= 0)) {
121 dev_err(dev, "%s: supply check failed: vreg: %pK, num_supplies: %d\n",
122 __func__, cdc_vreg, num_supplies);
123 return -EINVAL;
124 }
125
126 return 0;
127}
128
129/*
130 * msm_cdc_disable_static_supplies:
131 * Disable codec static supplies
132 *
133 * @dev: pointer to codec device
134 * @supplies: pointer to regulator bulk data
135 * @cdc_vreg: pointer to platform regulator data
136 * @num_supplies: number of supplies
137 *
138 * Return error code if supply disable is failed
139 */
140int msm_cdc_disable_static_supplies(struct device *dev,
141 struct regulator_bulk_data *supplies,
142 struct cdc_regulator *cdc_vreg,
143 int num_supplies)
144{
145 int rc, i;
146
147 if ((!dev) || (!supplies) || (!cdc_vreg)) {
148 pr_err("%s: either dev or supplies or cdc_vreg is NULL\n",
149 __func__);
150 return -EINVAL;
151 }
152 /* input parameter validation */
153 rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies);
154 if (rc)
155 return rc;
156
157 for (i = 0; i < num_supplies; i++) {
158 if (cdc_vreg[i].ondemand)
159 continue;
160
161 rc = regulator_disable(supplies[i].consumer);
162 if (rc)
163 dev_err(dev, "%s: failed to disable supply %s, err:%d\n",
164 __func__, supplies[i].supply, rc);
165 else
166 dev_dbg(dev, "%s: disabled regulator %s\n",
167 __func__, supplies[i].supply);
168 }
169
170 return rc;
171}
172EXPORT_SYMBOL(msm_cdc_disable_static_supplies);
173
174/*
175 * msm_cdc_release_supplies:
176 * Release codec power supplies
177 *
178 * @dev: pointer to codec device
179 * @supplies: pointer to regulator bulk data
180 * @cdc_vreg: pointer to platform regulator data
181 * @num_supplies: number of supplies
182 *
183 * Return error code if supply disable is failed
184 */
185int msm_cdc_release_supplies(struct device *dev,
186 struct regulator_bulk_data *supplies,
187 struct cdc_regulator *cdc_vreg,
188 int num_supplies)
189{
190 int rc = 0;
191 int i;
192
193 if ((!dev) || (!supplies) || (!cdc_vreg)) {
194 pr_err("%s: either dev or supplies or cdc_vreg is NULL\n",
195 __func__);
196 return -EINVAL;
197 }
198 /* input parameter validation */
199 rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies);
200 if (rc)
201 return rc;
202
203 msm_cdc_disable_static_supplies(dev, supplies, cdc_vreg,
204 num_supplies);
205 for (i = 0; i < num_supplies; i++) {
206 if (regulator_count_voltages(supplies[i].consumer) < 0)
207 continue;
208
209 regulator_set_voltage(supplies[i].consumer, 0,
210 cdc_vreg[i].max_uV);
211 regulator_set_load(supplies[i].consumer, 0);
212 devm_regulator_put(supplies[i].consumer);
213 supplies[i].consumer = NULL;
214 }
215 devm_kfree(dev, supplies);
216
217 return rc;
218}
219EXPORT_SYMBOL(msm_cdc_release_supplies);
220
221/*
222 * msm_cdc_enable_static_supplies:
223 * Enable codec static supplies
224 *
225 * @dev: pointer to codec device
226 * @supplies: pointer to regulator bulk data
227 * @cdc_vreg: pointer to platform regulator data
228 * @num_supplies: number of supplies
229 *
230 * Return error code if supply enable is failed
231 */
232int msm_cdc_enable_static_supplies(struct device *dev,
233 struct regulator_bulk_data *supplies,
234 struct cdc_regulator *cdc_vreg,
235 int num_supplies)
236{
237 int rc, i;
238
239 if ((!dev) || (!supplies) || (!cdc_vreg)) {
240 pr_err("%s: either dev or supplies or cdc_vreg is NULL\n",
241 __func__);
242 return -EINVAL;
243 }
244 /* input parameter validation */
245 rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies);
246 if (rc)
247 return rc;
248
249 for (i = 0; i < num_supplies; i++) {
250 if (cdc_vreg[i].ondemand)
251 continue;
252
253 rc = regulator_enable(supplies[i].consumer);
254 if (rc) {
255 dev_err(dev, "%s: failed to enable supply %s, rc: %d\n",
256 __func__, supplies[i].supply, rc);
257 break;
258 }
259 }
260
261 while (rc && i--)
262 if (!cdc_vreg[i].ondemand)
263 regulator_disable(supplies[i].consumer);
264
265 return rc;
266}
267EXPORT_SYMBOL(msm_cdc_enable_static_supplies);
268
269/*
270 * msm_cdc_init_supplies:
271 * Initialize codec static supplies with regulator get
272 *
273 * @dev: pointer to codec device
274 * @supplies: pointer to regulator bulk data
275 * @cdc_vreg: pointer to platform regulator data
276 * @num_supplies: number of supplies
277 *
278 * Return error code if supply init is failed
279 */
280int msm_cdc_init_supplies(struct device *dev,
281 struct regulator_bulk_data **supplies,
282 struct cdc_regulator *cdc_vreg,
283 int num_supplies)
284{
285 struct regulator_bulk_data *vsup;
286 int rc;
287 int i;
288
289 if (!dev || !cdc_vreg) {
290 pr_err("%s: device pointer or dce_vreg is NULL\n",
291 __func__);
292 return -EINVAL;
293 }
294 /* input parameter validation */
295 rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies);
296 if (rc)
297 return rc;
298
299 vsup = devm_kcalloc(dev, num_supplies,
300 sizeof(struct regulator_bulk_data),
301 GFP_KERNEL);
302 if (!vsup)
303 return -ENOMEM;
304
305 for (i = 0; i < num_supplies; i++) {
306 if (!cdc_vreg[i].name) {
307 dev_err(dev, "%s: supply name not defined\n",
308 __func__);
309 rc = -EINVAL;
310 goto err_supply;
311 }
312 vsup[i].supply = cdc_vreg[i].name;
313 }
314
315 rc = devm_regulator_bulk_get(dev, num_supplies, vsup);
316 if (rc) {
317 dev_err(dev, "%s: failed to get supplies (%d)\n",
318 __func__, rc);
319 goto err_supply;
320 }
321
322 /* Set voltage and current on regulators */
323 for (i = 0; i < num_supplies; i++) {
324 if (regulator_count_voltages(vsup[i].consumer) < 0)
325 continue;
326
327 rc = regulator_set_voltage(vsup[i].consumer,
328 cdc_vreg[i].min_uV,
329 cdc_vreg[i].max_uV);
330 if (rc) {
331 dev_err(dev, "%s: set regulator voltage failed for %s, err:%d\n",
332 __func__, vsup[i].supply, rc);
333 goto err_set_supply;
334 }
335 rc = regulator_set_load(vsup[i].consumer,
336 cdc_vreg[i].optimum_uA);
337 if (rc < 0) {
338 dev_err(dev, "%s: set regulator optimum mode failed for %s, err:%d\n",
339 __func__, vsup[i].supply, rc);
340 goto err_set_supply;
341 }
342 }
343
344 *supplies = vsup;
345
346 return 0;
347
348err_set_supply:
349 for (i = 0; i < num_supplies; i++)
350 devm_regulator_put(vsup[i].consumer);
351err_supply:
352 devm_kfree(dev, vsup);
353 return rc;
354}
355EXPORT_SYMBOL(msm_cdc_init_supplies);
356
357/*
358 * msm_cdc_get_power_supplies:
359 * Get codec power supplies from device tree.
360 * Allocate memory to hold regulator data for
361 * all power supplies.
362 *
363 * @dev: pointer to codec device
364 * @cdc_vreg: pointer to codec regulator
365 * @total_num_supplies: total number of supplies read from DT
366 *
367 * Return error code if supply disable is failed
368 */
369int msm_cdc_get_power_supplies(struct device *dev,
370 struct cdc_regulator **cdc_vreg,
371 int *total_num_supplies)
372{
373 const char *static_prop_name = "qcom,cdc-static-supplies";
374 const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
375 const char *cp_prop_name = "qcom,cdc-cp-supplies";
376 int static_sup_cnt = 0;
377 int ond_sup_cnt = 0;
378 int cp_sup_cnt = 0;
379 int num_supplies = 0;
380 struct cdc_regulator *cdc_reg;
381 int rc;
382
383 if (!dev) {
384 pr_err("%s: device pointer is NULL\n", __func__);
385 return -EINVAL;
386 }
387 static_sup_cnt = of_property_count_strings(dev->of_node,
388 static_prop_name);
Xiaoyu Ye1a2d8bd92017-01-31 18:54:15 -0800389 if (static_sup_cnt < 0) {
Banajit Goswamide8271c2017-01-18 00:28:59 -0800390 dev_err(dev, "%s: Failed to get static supplies(%d)\n",
391 __func__, static_sup_cnt);
392 rc = static_sup_cnt;
393 goto err_supply_cnt;
394 }
395 ond_sup_cnt = of_property_count_strings(dev->of_node, ond_prop_name);
Xiaoyu Ye1a2d8bd92017-01-31 18:54:15 -0800396 if (ond_sup_cnt < 0)
Banajit Goswamide8271c2017-01-18 00:28:59 -0800397 ond_sup_cnt = 0;
398
399 cp_sup_cnt = of_property_count_strings(dev->of_node,
400 cp_prop_name);
Xiaoyu Ye1a2d8bd92017-01-31 18:54:15 -0800401 if (cp_sup_cnt < 0)
Banajit Goswamide8271c2017-01-18 00:28:59 -0800402 cp_sup_cnt = 0;
403
404 num_supplies = static_sup_cnt + ond_sup_cnt + cp_sup_cnt;
405 if (num_supplies <= 0) {
406 dev_err(dev, "%s: supply count is 0 or negative\n", __func__);
407 rc = -EINVAL;
408 goto err_supply_cnt;
409 }
410
411 cdc_reg = devm_kcalloc(dev, num_supplies,
412 sizeof(struct cdc_regulator),
413 GFP_KERNEL);
414 if (!cdc_reg) {
415 rc = -ENOMEM;
416 goto err_mem_alloc;
417 }
418
419 rc = msm_cdc_parse_supplies(dev, cdc_reg, static_prop_name,
420 static_sup_cnt, false);
421 if (rc) {
422 dev_err(dev, "%s: failed to parse static supplies(%d)\n",
423 __func__, rc);
424 goto err_sup;
425 }
426
427 rc = msm_cdc_parse_supplies(dev, &cdc_reg[static_sup_cnt],
428 ond_prop_name, ond_sup_cnt,
429 true);
430 if (rc) {
431 dev_err(dev, "%s: failed to parse demand supplies(%d)\n",
432 __func__, rc);
433 goto err_sup;
434 }
435
436 rc = msm_cdc_parse_supplies(dev,
437 &cdc_reg[static_sup_cnt + ond_sup_cnt],
438 cp_prop_name, cp_sup_cnt, true);
439 if (rc) {
440 dev_err(dev, "%s: failed to parse cp supplies(%d)\n",
441 __func__, rc);
442 goto err_sup;
443 }
444
445 *cdc_vreg = cdc_reg;
446 *total_num_supplies = num_supplies;
447
448 return 0;
449
450err_sup:
451 devm_kfree(dev, cdc_reg);
452err_supply_cnt:
453err_mem_alloc:
454 return rc;
455}
456EXPORT_SYMBOL(msm_cdc_get_power_supplies);