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 
msm_dss_put_clk(struct dss_clk * clk_arry,int num_clk)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 
msm_dss_get_clk(struct device * dev,struct dss_clk * clk_arry,int num_clk)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 
msm_dss_clk_set_rate(struct dss_clk * clk_arry,int num_clk)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 
msm_dss_enable_clk(struct dss_clk * clk_arry,int num_clk,int enable)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 
msm_dss_parse_clock(struct platform_device * pdev,struct dss_module_power * mp)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 }
204