Merge tag 'gpio-v4.19-4' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
[linux-2.6-microblaze.git] / drivers / gpu / drm / msm / disp / dpu1 / dpu_io_util.c
1 /* Copyright (c) 2012-2015, 2017-2018, The Linux Foundation.
2  * 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/clk.h>
15 #include <linux/clk/clk-conf.h>
16 #include <linux/err.h>
17 #include <linux/delay.h>
18
19 #include "dpu_io_util.h"
20
21 void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk)
22 {
23         int i;
24
25         for (i = num_clk - 1; i >= 0; i--) {
26                 if (clk_arry[i].clk)
27                         clk_put(clk_arry[i].clk);
28                 clk_arry[i].clk = NULL;
29         }
30 }
31
32 int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk)
33 {
34         int i, rc = 0;
35
36         for (i = 0; i < num_clk; i++) {
37                 clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name);
38                 rc = PTR_ERR_OR_ZERO(clk_arry[i].clk);
39                 if (rc) {
40                         DEV_ERR("%pS->%s: '%s' get failed. rc=%d\n",
41                                 __builtin_return_address(0), __func__,
42                                 clk_arry[i].clk_name, rc);
43                         goto error;
44                 }
45         }
46
47         return rc;
48
49 error:
50         for (i--; i >= 0; i--) {
51                 if (clk_arry[i].clk)
52                         clk_put(clk_arry[i].clk);
53                 clk_arry[i].clk = NULL;
54         }
55
56         return rc;
57 }
58
59 int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk)
60 {
61         int i, rc = 0;
62
63         for (i = 0; i < num_clk; i++) {
64                 if (clk_arry[i].clk) {
65                         if (clk_arry[i].type != DSS_CLK_AHB) {
66                                 DEV_DBG("%pS->%s: '%s' rate %ld\n",
67                                         __builtin_return_address(0), __func__,
68                                         clk_arry[i].clk_name,
69                                         clk_arry[i].rate);
70                                 rc = clk_set_rate(clk_arry[i].clk,
71                                         clk_arry[i].rate);
72                                 if (rc) {
73                                         DEV_ERR("%pS->%s: %s failed. rc=%d\n",
74                                                 __builtin_return_address(0),
75                                                 __func__,
76                                                 clk_arry[i].clk_name, rc);
77                                         break;
78                                 }
79                         }
80                 } else {
81                         DEV_ERR("%pS->%s: '%s' is not available\n",
82                                 __builtin_return_address(0), __func__,
83                                 clk_arry[i].clk_name);
84                         rc = -EPERM;
85                         break;
86                 }
87         }
88
89         return rc;
90 }
91
92 int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable)
93 {
94         int i, rc = 0;
95
96         if (enable) {
97                 for (i = 0; i < num_clk; i++) {
98                         DEV_DBG("%pS->%s: enable '%s'\n",
99                                 __builtin_return_address(0), __func__,
100                                 clk_arry[i].clk_name);
101                         if (clk_arry[i].clk) {
102                                 rc = clk_prepare_enable(clk_arry[i].clk);
103                                 if (rc)
104                                         DEV_ERR("%pS->%s: %s en fail. rc=%d\n",
105                                                 __builtin_return_address(0),
106                                                 __func__,
107                                                 clk_arry[i].clk_name, rc);
108                         } else {
109                                 DEV_ERR("%pS->%s: '%s' is not available\n",
110                                         __builtin_return_address(0), __func__,
111                                         clk_arry[i].clk_name);
112                                 rc = -EPERM;
113                         }
114
115                         if (rc) {
116                                 msm_dss_enable_clk(&clk_arry[i],
117                                         i, false);
118                                 break;
119                         }
120                 }
121         } else {
122                 for (i = num_clk - 1; i >= 0; i--) {
123                         DEV_DBG("%pS->%s: disable '%s'\n",
124                                 __builtin_return_address(0), __func__,
125                                 clk_arry[i].clk_name);
126
127                         if (clk_arry[i].clk)
128                                 clk_disable_unprepare(clk_arry[i].clk);
129                         else
130                                 DEV_ERR("%pS->%s: '%s' is not available\n",
131                                         __builtin_return_address(0), __func__,
132                                         clk_arry[i].clk_name);
133                 }
134         }
135
136         return rc;
137 }
138
139 int msm_dss_parse_clock(struct platform_device *pdev,
140                         struct dss_module_power *mp)
141 {
142         u32 i, rc = 0;
143         const char *clock_name;
144         int num_clk = 0;
145
146         if (!pdev || !mp)
147                 return -EINVAL;
148
149         mp->num_clk = 0;
150         num_clk = of_property_count_strings(pdev->dev.of_node, "clock-names");
151         if (num_clk <= 0) {
152                 pr_debug("clocks are not defined\n");
153                 return 0;
154         }
155
156         mp->clk_config = devm_kcalloc(&pdev->dev,
157                                       num_clk, sizeof(struct dss_clk),
158                                       GFP_KERNEL);
159         if (!mp->clk_config)
160                 return -ENOMEM;
161
162         for (i = 0; i < num_clk; i++) {
163                 rc = of_property_read_string_index(pdev->dev.of_node,
164                                                    "clock-names", i,
165                                                    &clock_name);
166                 if (rc) {
167                         dev_err(&pdev->dev, "Failed to get clock name for %d\n",
168                                 i);
169                         break;
170                 }
171                 strlcpy(mp->clk_config[i].clk_name, clock_name,
172                         sizeof(mp->clk_config[i].clk_name));
173
174                 mp->clk_config[i].type = DSS_CLK_AHB;
175         }
176
177         rc = msm_dss_get_clk(&pdev->dev, mp->clk_config, num_clk);
178         if (rc) {
179                 dev_err(&pdev->dev, "Failed to get clock refs %d\n", rc);
180                 goto err;
181         }
182
183         rc = of_clk_set_defaults(pdev->dev.of_node, false);
184         if (rc) {
185                 dev_err(&pdev->dev, "Failed to set clock defaults %d\n", rc);
186                 goto err;
187         }
188
189         for (i = 0; i < num_clk; i++) {
190                 u32 rate = clk_get_rate(mp->clk_config[i].clk);
191                 if (!rate)
192                         continue;
193                 mp->clk_config[i].rate = rate;
194                 mp->clk_config[i].type = DSS_CLK_PCLK;
195         }
196
197         mp->num_clk = num_clk;
198         return 0;
199
200 err:
201         msm_dss_put_clk(mp->clk_config, num_clk);
202         return rc;
203 }