GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / gpu / drm / msm / dp / dp_clk_util.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2012-2015, 2017-2018, The Linux Foundation.
3  * All rights reserved.
4  */
5
6 #include <linux/clk.h>
7 #include <linux/clk/clk-conf.h>
8 #include <linux/err.h>
9 #include <linux/delay.h>
10 #include <linux/of.h>
11
12 #include <drm/drm_print.h>
13
14 #include "dp_clk_util.h"
15
16 void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk)
17 {
18         int i;
19
20         for (i = num_clk - 1; i >= 0; i--) {
21                 if (clk_arry[i].clk)
22                         clk_put(clk_arry[i].clk);
23                 clk_arry[i].clk = NULL;
24         }
25 }
26
27 int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk)
28 {
29         int i, rc = 0;
30
31         for (i = 0; i < num_clk; i++) {
32                 clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name);
33                 rc = PTR_ERR_OR_ZERO(clk_arry[i].clk);
34                 if (rc) {
35                         DEV_ERR("%pS->%s: '%s' get failed. rc=%d\n",
36                                 __builtin_return_address(0), __func__,
37                                 clk_arry[i].clk_name, rc);
38                         goto error;
39                 }
40         }
41
42         return rc;
43
44 error:
45         for (i--; i >= 0; i--) {
46                 if (clk_arry[i].clk)
47                         clk_put(clk_arry[i].clk);
48                 clk_arry[i].clk = NULL;
49         }
50
51         return rc;
52 }
53
54 int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk)
55 {
56         int i, rc = 0;
57
58         for (i = 0; i < num_clk; i++) {
59                 if (clk_arry[i].clk) {
60                         if (clk_arry[i].type != DSS_CLK_AHB) {
61                                 DEV_DBG("%pS->%s: '%s' rate %ld\n",
62                                         __builtin_return_address(0), __func__,
63                                         clk_arry[i].clk_name,
64                                         clk_arry[i].rate);
65                                 rc = clk_set_rate(clk_arry[i].clk,
66                                         clk_arry[i].rate);
67                                 if (rc) {
68                                         DEV_ERR("%pS->%s: %s failed. rc=%d\n",
69                                                 __builtin_return_address(0),
70                                                 __func__,
71                                                 clk_arry[i].clk_name, rc);
72                                         break;
73                                 }
74                         }
75                 } else {
76                         DEV_ERR("%pS->%s: '%s' is not available\n",
77                                 __builtin_return_address(0), __func__,
78                                 clk_arry[i].clk_name);
79                         rc = -EPERM;
80                         break;
81                 }
82         }
83
84         return rc;
85 }
86
87 int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable)
88 {
89         int i, rc = 0;
90
91         if (enable) {
92                 for (i = 0; i < num_clk; i++) {
93                         DEV_DBG("%pS->%s: enable '%s'\n",
94                                 __builtin_return_address(0), __func__,
95                                 clk_arry[i].clk_name);
96                         rc = clk_prepare_enable(clk_arry[i].clk);
97                         if (rc)
98                                 DEV_ERR("%pS->%s: %s en fail. rc=%d\n",
99                                         __builtin_return_address(0),
100                                         __func__,
101                                         clk_arry[i].clk_name, rc);
102
103                         if (rc && i) {
104                                 msm_dss_enable_clk(&clk_arry[i - 1],
105                                         i - 1, false);
106                                 break;
107                         }
108                 }
109         } else {
110                 for (i = num_clk - 1; i >= 0; i--) {
111                         DEV_DBG("%pS->%s: disable '%s'\n",
112                                 __builtin_return_address(0), __func__,
113                                 clk_arry[i].clk_name);
114
115                         clk_disable_unprepare(clk_arry[i].clk);
116                 }
117         }
118
119         return rc;
120 }