blob: c112cdc8c90ae8ecfdfd084ec39bd550023db83b [file] [log] [blame]
Ajay Singh Parmar769215f2017-03-19 22:35:13 -07001/*
2 * Copyright (c) 2012-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
15#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
16
17#include <linux/of_gpio.h>
18
19#include "dp_parser.h"
20
21static void dp_parser_unmap_io_resources(struct dp_parser *parser)
22{
23 struct dp_io *io = &parser->io;
24
Samantha Tran45c3e5c2017-10-19 12:51:09 -070025 msm_dss_iounmap(&io->dp_ahb);
26 msm_dss_iounmap(&io->dp_aux);
27 msm_dss_iounmap(&io->dp_link);
28 msm_dss_iounmap(&io->dp_p0);
Padmanabhan Komandurub6117bd2017-05-11 20:18:40 -070029 msm_dss_iounmap(&io->phy_io);
30 msm_dss_iounmap(&io->ln_tx0_io);
31 msm_dss_iounmap(&io->ln_tx0_io);
32 msm_dss_iounmap(&io->dp_pll_io);
33 msm_dss_iounmap(&io->dp_cc_io);
34 msm_dss_iounmap(&io->usb3_dp_com);
35 msm_dss_iounmap(&io->qfprom_io);
36 msm_dss_iounmap(&io->hdcp_io);
Ajay Singh Parmar769215f2017-03-19 22:35:13 -070037}
38
39static int dp_parser_ctrl_res(struct dp_parser *parser)
40{
41 int rc = 0;
42 u32 index;
43 struct platform_device *pdev = parser->pdev;
44 struct device_node *of_node = parser->pdev->dev.of_node;
45 struct dp_io *io = &parser->io;
46
47 rc = of_property_read_u32(of_node, "cell-index", &index);
48 if (rc) {
49 pr_err("cell-index not specified, rc=%d\n", rc);
50 goto err;
51 }
52
Samantha Tran45c3e5c2017-10-19 12:51:09 -070053 rc = msm_dss_ioremap_byname(pdev, &io->dp_ahb, "dp_ahb");
54 if (rc) {
55 pr_err("unable to remap dp io resources\n");
56 goto err;
57 }
58
59 rc = msm_dss_ioremap_byname(pdev, &io->dp_aux, "dp_aux");
60 if (rc) {
61 pr_err("unable to remap dp io resources\n");
62 goto err;
63 }
64
65 rc = msm_dss_ioremap_byname(pdev, &io->dp_link, "dp_link");
66 if (rc) {
67 pr_err("unable to remap dp io resources\n");
68 goto err;
69 }
70
71 rc = msm_dss_ioremap_byname(pdev, &io->dp_p0, "dp_p0");
Ajay Singh Parmar769215f2017-03-19 22:35:13 -070072 if (rc) {
73 pr_err("unable to remap dp io resources\n");
74 goto err;
75 }
76
77 rc = msm_dss_ioremap_byname(pdev, &io->phy_io, "dp_phy");
78 if (rc) {
79 pr_err("unable to remap dp PHY resources\n");
80 goto err;
81 }
82
83 rc = msm_dss_ioremap_byname(pdev, &io->ln_tx0_io, "dp_ln_tx0");
84 if (rc) {
85 pr_err("unable to remap dp TX0 resources\n");
86 goto err;
87 }
88
89 rc = msm_dss_ioremap_byname(pdev, &io->ln_tx1_io, "dp_ln_tx1");
90 if (rc) {
91 pr_err("unable to remap dp TX1 resources\n");
92 goto err;
93 }
94
95 rc = msm_dss_ioremap_byname(pdev, &io->dp_pll_io, "dp_pll");
96 if (rc) {
97 pr_err("unable to remap DP PLL resources\n");
98 goto err;
99 }
100
Padmanabhan Komandurub6117bd2017-05-11 20:18:40 -0700101 rc = msm_dss_ioremap_byname(pdev, &io->usb3_dp_com, "usb3_dp_com");
102 if (rc) {
103 pr_err("unable to remap USB3 DP com resources\n");
104 goto err;
105 }
106
Ajay Singh Parmar769215f2017-03-19 22:35:13 -0700107 if (msm_dss_ioremap_byname(pdev, &io->dp_cc_io, "dp_mmss_cc")) {
108 pr_err("unable to remap dp MMSS_CC resources\n");
109 goto err;
110 }
111
112 if (msm_dss_ioremap_byname(pdev, &io->qfprom_io, "qfprom_physical"))
113 pr_warn("unable to remap dp qfprom resources\n");
114
115 if (msm_dss_ioremap_byname(pdev, &io->hdcp_io, "hdcp_physical"))
116 pr_warn("unable to remap dp hdcp resources\n");
117
118 return 0;
119err:
120 dp_parser_unmap_io_resources(parser);
121 return rc;
122}
123
Padmanabhan Komanduru20a21db2017-07-10 16:58:59 +0530124static const char *dp_get_phy_aux_config_property(u32 cfg_type)
125{
126 switch (cfg_type) {
127 case PHY_AUX_CFG0:
128 return "qcom,aux-cfg0-settings";
129 case PHY_AUX_CFG1:
130 return "qcom,aux-cfg1-settings";
131 case PHY_AUX_CFG2:
132 return "qcom,aux-cfg2-settings";
133 case PHY_AUX_CFG3:
134 return "qcom,aux-cfg3-settings";
135 case PHY_AUX_CFG4:
136 return "qcom,aux-cfg4-settings";
137 case PHY_AUX_CFG5:
138 return "qcom,aux-cfg5-settings";
139 case PHY_AUX_CFG6:
140 return "qcom,aux-cfg6-settings";
141 case PHY_AUX_CFG7:
142 return "qcom,aux-cfg7-settings";
143 case PHY_AUX_CFG8:
144 return "qcom,aux-cfg8-settings";
145 case PHY_AUX_CFG9:
146 return "qcom,aux-cfg9-settings";
147 default:
148 return "unknown";
149 }
150}
151
152static void dp_parser_phy_aux_cfg_reset(struct dp_parser *parser)
153{
154 int i = 0;
155
156 for (i = 0; i < PHY_AUX_CFG_MAX; i++)
157 parser->aux_cfg[i] = (const struct dp_aux_cfg){ 0 };
158}
159
Ajay Singh Parmar769215f2017-03-19 22:35:13 -0700160static int dp_parser_aux(struct dp_parser *parser)
161{
Ajay Singh Parmar769215f2017-03-19 22:35:13 -0700162 struct device_node *of_node = parser->pdev->dev.of_node;
Padmanabhan Komanduru20a21db2017-07-10 16:58:59 +0530163 int len = 0, i = 0, j = 0, config_count = 0;
Ajay Singh Parmar769215f2017-03-19 22:35:13 -0700164 const char *data;
Padmanabhan Komanduru20a21db2017-07-10 16:58:59 +0530165 int const minimum_config_count = 1;
Ajay Singh Parmar769215f2017-03-19 22:35:13 -0700166
Padmanabhan Komanduru20a21db2017-07-10 16:58:59 +0530167 for (i = 0; i < PHY_AUX_CFG_MAX; i++) {
168 const char *property = dp_get_phy_aux_config_property(i);
169
170 data = of_get_property(of_node, property, &len);
171 if (!data) {
172 pr_err("Unable to read %s\n", property);
173 goto error;
174 }
175
176 config_count = len - 1;
177 if ((config_count < minimum_config_count) ||
178 (config_count > DP_AUX_CFG_MAX_VALUE_CNT)) {
179 pr_err("Invalid config count (%d) configs for %s\n",
180 config_count, property);
181 goto error;
182 }
183
184 parser->aux_cfg[i].offset = data[0];
185 parser->aux_cfg[i].cfg_cnt = config_count;
186 pr_debug("%s offset=0x%x, cfg_cnt=%d\n",
187 property,
188 parser->aux_cfg[i].offset,
189 parser->aux_cfg[i].cfg_cnt);
190 for (j = 1; j < len; j++) {
191 parser->aux_cfg[i].lut[j - 1] = data[j];
192 pr_debug("%s lut[%d]=0x%x\n",
193 property,
194 i,
195 parser->aux_cfg[i].lut[j - 1]);
196 }
Ajay Singh Parmar769215f2017-03-19 22:35:13 -0700197 }
Padmanabhan Komanduru20a21db2017-07-10 16:58:59 +0530198 return 0;
Ajay Singh Parmar769215f2017-03-19 22:35:13 -0700199
Padmanabhan Komanduru20a21db2017-07-10 16:58:59 +0530200error:
201 dp_parser_phy_aux_cfg_reset(parser);
202 return -EINVAL;
Ajay Singh Parmar769215f2017-03-19 22:35:13 -0700203}
204
205static int dp_parser_misc(struct dp_parser *parser)
206{
207 int rc = 0;
208 struct device_node *of_node = parser->pdev->dev.of_node;
209
210 rc = of_property_read_u32(of_node,
211 "qcom,max-pclk-frequency-khz", &parser->max_pclk_khz);
212 if (rc)
213 parser->max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ;
214
215 return 0;
216}
217
218static int dp_parser_pinctrl(struct dp_parser *parser)
219{
220 int rc = 0;
221 struct dp_pinctrl *pinctrl = &parser->pinctrl;
222
223 pinctrl->pin = devm_pinctrl_get(&parser->pdev->dev);
224
225 if (IS_ERR_OR_NULL(pinctrl->pin)) {
226 rc = PTR_ERR(pinctrl->pin);
227 pr_err("failed to get pinctrl, rc=%d\n", rc);
228 goto error;
229 }
230
231 pinctrl->state_active = pinctrl_lookup_state(pinctrl->pin,
232 "mdss_dp_active");
233 if (IS_ERR_OR_NULL(pinctrl->state_active)) {
234 rc = PTR_ERR(pinctrl->state_active);
235 pr_err("failed to get pinctrl active state, rc=%d\n", rc);
236 goto error;
237 }
238
239 pinctrl->state_suspend = pinctrl_lookup_state(pinctrl->pin,
240 "mdss_dp_sleep");
241 if (IS_ERR_OR_NULL(pinctrl->state_suspend)) {
242 rc = PTR_ERR(pinctrl->state_suspend);
243 pr_err("failed to get pinctrl suspend state, rc=%d\n", rc);
244 goto error;
245 }
246error:
247 return rc;
248}
249
250static int dp_parser_gpio(struct dp_parser *parser)
251{
252 int i = 0;
253 struct device *dev = &parser->pdev->dev;
254 struct device_node *of_node = dev->of_node;
255 struct dss_module_power *mp = &parser->mp[DP_CORE_PM];
256 static const char * const dp_gpios[] = {
257 "qcom,aux-en-gpio",
258 "qcom,aux-sel-gpio",
259 "qcom,usbplug-cc-gpio",
260 };
261
262 mp->gpio_config = devm_kzalloc(dev,
263 sizeof(struct dss_gpio) * ARRAY_SIZE(dp_gpios), GFP_KERNEL);
Samantha Tranf4259fd2017-09-28 16:42:12 -0700264 if (!mp->gpio_config)
265 return -ENOMEM;
266
Ajay Singh Parmar769215f2017-03-19 22:35:13 -0700267 mp->num_gpio = ARRAY_SIZE(dp_gpios);
268
269 for (i = 0; i < ARRAY_SIZE(dp_gpios); i++) {
270 mp->gpio_config[i].gpio = of_get_named_gpio(of_node,
271 dp_gpios[i], 0);
272
273 if (!gpio_is_valid(mp->gpio_config[i].gpio)) {
274 pr_err("%s gpio not specified\n", dp_gpios[i]);
275 return -EINVAL;
276 }
277
278 strlcpy(mp->gpio_config[i].gpio_name, dp_gpios[i],
279 sizeof(mp->gpio_config[i].gpio_name));
280
281 mp->gpio_config[i].value = 0;
282 }
283
284 return 0;
285}
286
287static const char *dp_parser_supply_node_name(enum dp_pm_type module)
288{
289 switch (module) {
290 case DP_CORE_PM: return "qcom,core-supply-entries";
291 case DP_CTRL_PM: return "qcom,ctrl-supply-entries";
292 case DP_PHY_PM: return "qcom,phy-supply-entries";
293 default: return "???";
294 }
295}
296
297static int dp_parser_get_vreg(struct dp_parser *parser,
298 enum dp_pm_type module)
299{
300 int i = 0, rc = 0;
301 u32 tmp = 0;
302 const char *pm_supply_name = NULL;
303 struct device_node *supply_node = NULL;
304 struct device_node *of_node = parser->pdev->dev.of_node;
305 struct device_node *supply_root_node = NULL;
306 struct dss_module_power *mp = &parser->mp[module];
307
308 mp->num_vreg = 0;
309 pm_supply_name = dp_parser_supply_node_name(module);
310 supply_root_node = of_get_child_by_name(of_node, pm_supply_name);
311 if (!supply_root_node) {
312 pr_err("no supply entry present: %s\n", pm_supply_name);
313 goto novreg;
314 }
315
316 mp->num_vreg = of_get_available_child_count(supply_root_node);
317
318 if (mp->num_vreg == 0) {
319 pr_debug("no vreg\n");
320 goto novreg;
321 } else {
322 pr_debug("vreg found. count=%d\n", mp->num_vreg);
323 }
324
325 mp->vreg_config = devm_kzalloc(&parser->pdev->dev,
326 sizeof(struct dss_vreg) * mp->num_vreg, GFP_KERNEL);
327 if (!mp->vreg_config) {
328 rc = -ENOMEM;
329 goto error;
330 }
331
332 for_each_child_of_node(supply_root_node, supply_node) {
333 const char *st = NULL;
334 /* vreg-name */
335 rc = of_property_read_string(supply_node,
336 "qcom,supply-name", &st);
337 if (rc) {
338 pr_err("error reading name. rc=%d\n",
339 rc);
340 goto error;
341 }
342 snprintf(mp->vreg_config[i].vreg_name,
343 ARRAY_SIZE((mp->vreg_config[i].vreg_name)), "%s", st);
344 /* vreg-min-voltage */
345 rc = of_property_read_u32(supply_node,
346 "qcom,supply-min-voltage", &tmp);
347 if (rc) {
348 pr_err("error reading min volt. rc=%d\n",
349 rc);
350 goto error;
351 }
352 mp->vreg_config[i].min_voltage = tmp;
353
354 /* vreg-max-voltage */
355 rc = of_property_read_u32(supply_node,
356 "qcom,supply-max-voltage", &tmp);
357 if (rc) {
358 pr_err("error reading max volt. rc=%d\n",
359 rc);
360 goto error;
361 }
362 mp->vreg_config[i].max_voltage = tmp;
363
364 /* enable-load */
365 rc = of_property_read_u32(supply_node,
366 "qcom,supply-enable-load", &tmp);
367 if (rc) {
368 pr_err("error reading enable load. rc=%d\n",
369 rc);
370 goto error;
371 }
372 mp->vreg_config[i].enable_load = tmp;
373
374 /* disable-load */
375 rc = of_property_read_u32(supply_node,
376 "qcom,supply-disable-load", &tmp);
377 if (rc) {
378 pr_err("error reading disable load. rc=%d\n",
379 rc);
380 goto error;
381 }
382 mp->vreg_config[i].disable_load = tmp;
383
384 pr_debug("%s min=%d, max=%d, enable=%d, disable=%d\n",
385 mp->vreg_config[i].vreg_name,
386 mp->vreg_config[i].min_voltage,
387 mp->vreg_config[i].max_voltage,
388 mp->vreg_config[i].enable_load,
389 mp->vreg_config[i].disable_load
390 );
391 ++i;
392 }
393
394 return rc;
395
396error:
397 if (mp->vreg_config) {
398 devm_kfree(&parser->pdev->dev, mp->vreg_config);
399 mp->vreg_config = NULL;
400 }
401novreg:
402 mp->num_vreg = 0;
403
404 return rc;
405}
406
407static void dp_parser_put_vreg_data(struct device *dev,
408 struct dss_module_power *mp)
409{
410 if (!mp) {
411 DEV_ERR("invalid input\n");
412 return;
413 }
414
415 if (mp->vreg_config) {
416 devm_kfree(dev, mp->vreg_config);
417 mp->vreg_config = NULL;
418 }
419 mp->num_vreg = 0;
420}
421
422static int dp_parser_regulator(struct dp_parser *parser)
423{
424 int i, rc = 0;
425 struct platform_device *pdev = parser->pdev;
426
427 /* Parse the regulator information */
428 for (i = DP_CORE_PM; i < DP_MAX_PM; i++) {
429 rc = dp_parser_get_vreg(parser, i);
430 if (rc) {
431 pr_err("get_dt_vreg_data failed for %s. rc=%d\n",
432 dp_parser_pm_name(i), rc);
433 i--;
434 for (; i >= DP_CORE_PM; i--)
435 dp_parser_put_vreg_data(&pdev->dev,
436 &parser->mp[i]);
437 break;
438 }
439 }
440
441 return rc;
442}
443
444static bool dp_parser_check_prefix(const char *clk_prefix, const char *clk_name)
445{
446 return !!strnstr(clk_name, clk_prefix, strlen(clk_name));
447}
448
449static void dp_parser_put_clk_data(struct device *dev,
450 struct dss_module_power *mp)
451{
452 if (!mp) {
453 DEV_ERR("%s: invalid input\n", __func__);
454 return;
455 }
456
457 if (mp->clk_config) {
458 devm_kfree(dev, mp->clk_config);
459 mp->clk_config = NULL;
460 }
461
462 mp->num_clk = 0;
463}
464
Tatenda Chipeperekwa2bc44872017-10-18 18:26:56 -0700465static void dp_parser_put_gpio_data(struct device *dev,
466 struct dss_module_power *mp)
467{
468 if (!mp) {
469 DEV_ERR("%s: invalid input\n", __func__);
470 return;
471 }
472
473 if (mp->gpio_config) {
474 devm_kfree(dev, mp->gpio_config);
475 mp->gpio_config = NULL;
476 }
477
478 mp->num_gpio = 0;
479}
480
Ajay Singh Parmar769215f2017-03-19 22:35:13 -0700481static int dp_parser_init_clk_data(struct dp_parser *parser)
482{
483 int num_clk = 0, i = 0, rc = 0;
484 int core_clk_count = 0, ctrl_clk_count = 0;
485 const char *core_clk = "core";
486 const char *ctrl_clk = "ctrl";
487 const char *clk_name;
488 struct device *dev = &parser->pdev->dev;
489 struct dss_module_power *core_power = &parser->mp[DP_CORE_PM];
490 struct dss_module_power *ctrl_power = &parser->mp[DP_CTRL_PM];
491
492 num_clk = of_property_count_strings(dev->of_node, "clock-names");
493 if (num_clk <= 0) {
494 pr_err("no clocks are defined\n");
495 rc = -EINVAL;
496 goto exit;
497 }
498
499 for (i = 0; i < num_clk; i++) {
500 of_property_read_string_index(dev->of_node,
501 "clock-names", i, &clk_name);
502
503 if (dp_parser_check_prefix(core_clk, clk_name))
504 core_clk_count++;
505
506 if (dp_parser_check_prefix(ctrl_clk, clk_name))
507 ctrl_clk_count++;
508 }
509
510 /* Initialize the CORE power module */
511 if (core_clk_count <= 0) {
512 pr_err("no core clocks are defined\n");
513 rc = -EINVAL;
514 goto exit;
515 }
516
517 core_power->num_clk = core_clk_count;
518 core_power->clk_config = devm_kzalloc(dev,
519 sizeof(struct dss_clk) * core_power->num_clk,
520 GFP_KERNEL);
521 if (!core_power->clk_config) {
522 rc = -EINVAL;
523 goto exit;
524 }
525
526 /* Initialize the CTRL power module */
527 if (ctrl_clk_count <= 0) {
528 pr_err("no ctrl clocks are defined\n");
529 rc = -EINVAL;
530 goto ctrl_clock_error;
531 }
532
533 ctrl_power->num_clk = ctrl_clk_count;
534 ctrl_power->clk_config = devm_kzalloc(dev,
535 sizeof(struct dss_clk) * ctrl_power->num_clk,
536 GFP_KERNEL);
537 if (!ctrl_power->clk_config) {
538 ctrl_power->num_clk = 0;
539 rc = -EINVAL;
540 goto ctrl_clock_error;
541 }
542
543 return rc;
544
545ctrl_clock_error:
546 dp_parser_put_clk_data(dev, core_power);
547exit:
548 return rc;
549}
550
551static int dp_parser_clock(struct dp_parser *parser)
552{
553 int rc = 0, i = 0;
554 int num_clk = 0;
555 int core_clk_index = 0, ctrl_clk_index = 0;
556 int core_clk_count = 0, ctrl_clk_count = 0;
557 const char *clk_name;
558 const char *core_clk = "core";
559 const char *ctrl_clk = "ctrl";
560 struct device *dev = &parser->pdev->dev;
561 struct dss_module_power *core_power = &parser->mp[DP_CORE_PM];
562 struct dss_module_power *ctrl_power = &parser->mp[DP_CTRL_PM];
563
564 core_power = &parser->mp[DP_CORE_PM];
565 ctrl_power = &parser->mp[DP_CTRL_PM];
566
567 rc = dp_parser_init_clk_data(parser);
568 if (rc) {
569 pr_err("failed to initialize power data\n");
570 rc = -EINVAL;
571 goto exit;
572 }
573
574 core_clk_count = core_power->num_clk;
575 ctrl_clk_count = ctrl_power->num_clk;
576
577 num_clk = core_clk_count + ctrl_clk_count;
578
579 for (i = 0; i < num_clk; i++) {
580 of_property_read_string_index(dev->of_node, "clock-names",
581 i, &clk_name);
582
583 if (dp_parser_check_prefix(core_clk, clk_name) &&
584 core_clk_index < core_clk_count) {
585 struct dss_clk *clk =
586 &core_power->clk_config[core_clk_index];
587 strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
588 clk->type = DSS_CLK_AHB;
589 core_clk_index++;
590 } else if (dp_parser_check_prefix(ctrl_clk, clk_name) &&
591 ctrl_clk_index < ctrl_clk_count) {
592 struct dss_clk *clk =
593 &ctrl_power->clk_config[ctrl_clk_index];
594 strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
595 ctrl_clk_index++;
596
597 if (!strcmp(clk_name, "ctrl_link_clk") ||
Tatenda Chipeperekwac44d51b2017-06-16 17:12:00 -0700598 !strcmp(clk_name, "ctrl_pixel_clk"))
Ajay Singh Parmar769215f2017-03-19 22:35:13 -0700599 clk->type = DSS_CLK_PCLK;
600 else
601 clk->type = DSS_CLK_AHB;
602 }
603 }
604
605 pr_debug("clock parsing successful\n");
606
607exit:
608 return rc;
609}
610
611static int dp_parser_parse(struct dp_parser *parser)
612{
613 int rc = 0;
614
615 if (!parser) {
616 pr_err("invalid input\n");
617 rc = -EINVAL;
618 goto err;
619 }
620
621 rc = dp_parser_ctrl_res(parser);
622 if (rc)
623 goto err;
624
625 rc = dp_parser_aux(parser);
626 if (rc)
627 goto err;
628
629 rc = dp_parser_misc(parser);
630 if (rc)
631 goto err;
632
633 rc = dp_parser_clock(parser);
634 if (rc)
635 goto err;
636
637 rc = dp_parser_regulator(parser);
638 if (rc)
639 goto err;
640
641 rc = dp_parser_gpio(parser);
642 if (rc)
643 goto err;
644
645 rc = dp_parser_pinctrl(parser);
646err:
647 return rc;
648}
649
650struct dp_parser *dp_parser_get(struct platform_device *pdev)
651{
652 struct dp_parser *parser;
653
654 parser = devm_kzalloc(&pdev->dev, sizeof(*parser), GFP_KERNEL);
655 if (!parser)
656 return ERR_PTR(-ENOMEM);
657
658 parser->parse = dp_parser_parse;
659 parser->pdev = pdev;
660
661 return parser;
662}
663
664void dp_parser_put(struct dp_parser *parser)
665{
666 int i = 0;
667 struct dss_module_power *power = NULL;
668
669 if (!parser) {
670 pr_err("invalid parser module\n");
671 return;
672 }
673
674 power = parser->mp;
675
676 for (i = 0; i < DP_MAX_PM; i++) {
Tatenda Chipeperekwa2bc44872017-10-18 18:26:56 -0700677 dp_parser_put_clk_data(&parser->pdev->dev, &power[i]);
678 dp_parser_put_vreg_data(&parser->pdev->dev, &power[i]);
679 dp_parser_put_gpio_data(&parser->pdev->dev, &power[i]);
Ajay Singh Parmar769215f2017-03-19 22:35:13 -0700680 }
681
682 devm_kfree(&parser->pdev->dev, parser);
683}