blob: fc3cb386f42c91abfcec61a04e5ede3b47cbb1dd [file] [log] [blame]
Meng Wang43bbb872018-12-10 12:32:05 +08001// SPDX-License-Identifier: GPL-2.0-only
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +05302/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303 */
4
5#include <linux/kernel.h>
6#include <linux/init.h>
7#include <linux/err.h>
8#include <linux/module.h>
9#include <linux/of.h>
10#include <linux/clk.h>
11#include <linux/clk-provider.h>
12#include "../../../drivers/clk/qcom/common.h"
Meng Wang15c825d2018-09-06 10:49:18 +080013#include <linux/pinctrl/consumer.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053014#include <linux/platform_device.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053015#include <dt-bindings/clock/qcom,audio-ext-clk.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053016#include <dsp/q6afe-v2.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053017#include "audio-ext-clk-up.h"
18
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -080019enum {
20 AUDIO_EXT_CLK_PMI,
21 AUDIO_EXT_CLK_LNBB2,
22 AUDIO_EXT_CLK_LPASS,
Laxminath Kasamd712cc72018-07-17 23:43:21 +053023 AUDIO_EXT_CLK_LPASS2,
24 AUDIO_EXT_CLK_LPASS3,
Aditya Bavanari7259ca62018-07-30 12:03:03 +053025 AUDIO_EXT_CLK_LPASS4,
26 AUDIO_EXT_CLK_LPASS5,
27 AUDIO_EXT_CLK_LPASS6,
28 AUDIO_EXT_CLK_LPASS7,
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +053029 AUDIO_EXT_CLK_LPASS_CORE_HW_VOTE,
Sudheer Papothia1351b92019-03-07 18:52:08 +053030 AUDIO_EXT_CLK_LPASS8,
Sudheer Papothiba445bf2019-04-16 05:05:55 +053031 AUDIO_EXT_CLK_LPASS_AUDIO_HW_VOTE,
Laxminath Kasamd712cc72018-07-17 23:43:21 +053032 AUDIO_EXT_CLK_LPASS_MAX,
Rohit kumar68725bb2018-11-23 16:52:58 +053033 AUDIO_EXT_CLK_EXTERNAL_PLL = AUDIO_EXT_CLK_LPASS_MAX,
34 AUDIO_EXT_CLK_MAX,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053035};
36
37struct pinctrl_info {
38 struct pinctrl *pinctrl;
39 struct pinctrl_state *sleep;
40 struct pinctrl_state *active;
41 char __iomem *base;
42};
43
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -080044struct audio_ext_clk {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053045 struct pinctrl_info pnctrl_info;
46 struct clk_fixed_factor fact;
47};
48
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -080049struct audio_ext_clk_priv {
50 struct device *dev;
51 int clk_src;
52 struct afe_clk_set clk_cfg;
53 struct audio_ext_clk audio_clk;
Surendar Karka0a915f82018-07-09 20:30:03 +053054 const char *clk_name;
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +053055 uint32_t lpass_core_hwvote_client_handle;
Sudheer Papothiba445bf2019-04-16 05:05:55 +053056 uint32_t lpass_audio_hwvote_client_handle;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053057};
58
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -080059static inline struct audio_ext_clk_priv *to_audio_clk(struct clk_hw *hw)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053060{
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -080061 return container_of(hw, struct audio_ext_clk_priv, audio_clk.fact.hw);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053062}
63
64static int audio_ext_clk_prepare(struct clk_hw *hw)
65{
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -080066 struct audio_ext_clk_priv *clk_priv = to_audio_clk(hw);
67 struct pinctrl_info *pnctrl_info = &clk_priv->audio_clk.pnctrl_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053068 int ret;
69
Laxminath Kasamd712cc72018-07-17 23:43:21 +053070 if ((clk_priv->clk_src >= AUDIO_EXT_CLK_LPASS) &&
71 (clk_priv->clk_src < AUDIO_EXT_CLK_LPASS_MAX)) {
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -080072 clk_priv->clk_cfg.enable = 1;
Aditya Bavanarif500a1d2019-09-16 18:27:51 -070073 trace_printk("%s: vote for %d clock\n",
74 __func__, clk_priv->clk_src);
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -080075 ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk_priv->clk_cfg);
76 if (ret < 0) {
Ramprasad Katkam14efed62019-03-07 13:16:50 +053077 pr_err_ratelimited("%s afe_set_digital_codec_core_clock failed\n",
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -080078 __func__);
79 return ret;
80 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053081 }
82
83 if (pnctrl_info->pinctrl) {
84 ret = pinctrl_select_state(pnctrl_info->pinctrl,
85 pnctrl_info->active);
86 if (ret) {
87 pr_err("%s: active state select failed with %d\n",
88 __func__, ret);
89 return -EIO;
90 }
91 }
92
93 if (pnctrl_info->base)
94 iowrite32(1, pnctrl_info->base);
95 return 0;
96}
97
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -080098static void audio_ext_clk_unprepare(struct clk_hw *hw)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053099{
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800100 struct audio_ext_clk_priv *clk_priv = to_audio_clk(hw);
101 struct pinctrl_info *pnctrl_info = &clk_priv->audio_clk.pnctrl_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530102 int ret;
103
104 if (pnctrl_info->pinctrl) {
105 ret = pinctrl_select_state(pnctrl_info->pinctrl,
106 pnctrl_info->sleep);
107 if (ret) {
108 pr_err("%s: active state select failed with %d\n",
109 __func__, ret);
110 return;
111 }
112 }
113
Laxminath Kasamd712cc72018-07-17 23:43:21 +0530114 if ((clk_priv->clk_src >= AUDIO_EXT_CLK_LPASS) &&
115 (clk_priv->clk_src < AUDIO_EXT_CLK_LPASS_MAX)) {
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800116 clk_priv->clk_cfg.enable = 0;
Aditya Bavanarif500a1d2019-09-16 18:27:51 -0700117 trace_printk("%s: unvote for %d clock\n",
118 __func__, clk_priv->clk_src);
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800119 ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk_priv->clk_cfg);
120 if (ret < 0)
Ramprasad Katkam14efed62019-03-07 13:16:50 +0530121 pr_err_ratelimited("%s: afe_set_lpass_clk_cfg failed, ret = %d\n",
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800122 __func__, ret);
123 }
124
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530125 if (pnctrl_info->base)
126 iowrite32(0, pnctrl_info->base);
127}
128
Surendar Karka0a915f82018-07-09 20:30:03 +0530129static u8 audio_ext_clk_get_parent(struct clk_hw *hw)
130{
131 struct audio_ext_clk_priv *clk_priv = to_audio_clk(hw);
132 int num_parents = clk_hw_get_num_parents(hw);
133 const char * const *parent_names = hw->init->parent_names;
134 u8 i = 0, ret = hw->init->num_parents + 1;
135
136 if ((clk_priv->clk_src == AUDIO_EXT_CLK_PMI) && clk_priv->clk_name) {
137 for (i = 0; i < num_parents; i++) {
138 if (!strcmp(parent_names[i], clk_priv->clk_name))
139 ret = i;
140 }
141 pr_debug("%s: parent index = %u\n", __func__, ret);
142 return ret;
143 } else
144 return 0;
145}
146
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530147static int lpass_hw_vote_prepare(struct clk_hw *hw)
Mangesh Kunchamwar912a96a2018-11-13 16:04:53 +0530148{
149 struct audio_ext_clk_priv *clk_priv = to_audio_clk(hw);
150 int ret;
151
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530152 if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_CORE_HW_VOTE) {
Aditya Bavanarif500a1d2019-09-16 18:27:51 -0700153 trace_printk("%s: vote for %d clock\n",
154 __func__, clk_priv->clk_src);
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530155 ret = afe_vote_lpass_core_hw(AFE_LPASS_CORE_HW_MACRO_BLOCK,
156 "LPASS_HW_MACRO",
157 &clk_priv->lpass_core_hwvote_client_handle);
158 if (ret < 0) {
159 pr_err("%s lpass core hw vote failed %d\n",
160 __func__, ret);
161 return ret;
Mangesh Kunchamwar912a96a2018-11-13 16:04:53 +0530162 }
163 }
164
Sudheer Papothiba445bf2019-04-16 05:05:55 +0530165 if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_AUDIO_HW_VOTE) {
Aditya Bavanarif500a1d2019-09-16 18:27:51 -0700166 trace_printk("%s: vote for %d clock\n",
167 __func__, clk_priv->clk_src);
Sudheer Papothiba445bf2019-04-16 05:05:55 +0530168 ret = afe_vote_lpass_core_hw(AFE_LPASS_CORE_HW_DCODEC_BLOCK,
169 "LPASS_HW_DCODEC",
170 &clk_priv->lpass_audio_hwvote_client_handle);
171 if (ret < 0) {
172 pr_err("%s lpass audio hw vote failed %d\n",
173 __func__, ret);
174 return ret;
175 }
176 }
177
Mangesh Kunchamwar912a96a2018-11-13 16:04:53 +0530178 return 0;
179}
180
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530181static void lpass_hw_vote_unprepare(struct clk_hw *hw)
Mangesh Kunchamwar912a96a2018-11-13 16:04:53 +0530182{
183 struct audio_ext_clk_priv *clk_priv = to_audio_clk(hw);
184 int ret = 0;
185
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530186 if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_CORE_HW_VOTE) {
Aditya Bavanarif500a1d2019-09-16 18:27:51 -0700187 trace_printk("%s: unvote for %d clock\n",
188 __func__, clk_priv->clk_src);
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530189 ret = afe_unvote_lpass_core_hw(
190 AFE_LPASS_CORE_HW_MACRO_BLOCK,
191 clk_priv->lpass_core_hwvote_client_handle);
192 if (ret < 0) {
193 pr_err("%s lpass core hw vote failed %d\n",
194 __func__, ret);
Mangesh Kunchamwar912a96a2018-11-13 16:04:53 +0530195 }
196 }
Sudheer Papothiba445bf2019-04-16 05:05:55 +0530197
198 if (clk_priv->clk_src == AUDIO_EXT_CLK_LPASS_AUDIO_HW_VOTE) {
Aditya Bavanarif500a1d2019-09-16 18:27:51 -0700199 trace_printk("%s: unvote for %d clock\n",
200 __func__, clk_priv->clk_src);
Sudheer Papothiba445bf2019-04-16 05:05:55 +0530201 ret = afe_unvote_lpass_core_hw(
202 AFE_LPASS_CORE_HW_DCODEC_BLOCK,
203 clk_priv->lpass_audio_hwvote_client_handle);
204 if (ret < 0) {
205 pr_err("%s lpass audio hw unvote failed %d\n",
206 __func__, ret);
207 }
208 }
Mangesh Kunchamwar912a96a2018-11-13 16:04:53 +0530209}
210
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800211static const struct clk_ops audio_ext_clk_ops = {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530212 .prepare = audio_ext_clk_prepare,
213 .unprepare = audio_ext_clk_unprepare,
Surendar Karka0a915f82018-07-09 20:30:03 +0530214 .get_parent = audio_ext_clk_get_parent,
215};
216
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530217static const struct clk_ops lpass_hw_vote_ops = {
218 .prepare = lpass_hw_vote_prepare,
219 .unprepare = lpass_hw_vote_unprepare,
Mangesh Kunchamwar912a96a2018-11-13 16:04:53 +0530220};
221
Surendar Karka0a915f82018-07-09 20:30:03 +0530222static const char * const audio_ext_pmi_div_clk[] = {
223 "qpnp_clkdiv_1",
224 "pms405_div_clk1",
225 "pm6150_div_clk1",
Aditya Bavanari94eb98b2019-01-25 21:55:05 +0530226 "pm6125_div_clk1",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530227};
228
Sudheer Papothi9b51e3e2018-07-21 05:20:10 +0530229static int audio_ext_clk_dummy_prepare(struct clk_hw *hw)
230{
231 return 0;
232}
233
234static void audio_ext_clk_dummy_unprepare(struct clk_hw *hw)
235{
236
237}
238
239static const struct clk_ops audio_ext_clk_dummy_ops = {
240 .prepare = audio_ext_clk_dummy_prepare,
241 .unprepare = audio_ext_clk_dummy_unprepare,
242};
243
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800244static struct audio_ext_clk audio_clk_array[] = {
245 {
246 .pnctrl_info = {NULL},
247 .fact = {
248 .mult = 1,
249 .div = 1,
250 .hw.init = &(struct clk_init_data){
251 .name = "audio_ext_pmi_clk",
Surendar Karka0a915f82018-07-09 20:30:03 +0530252 .parent_names = audio_ext_pmi_div_clk,
253 .num_parents =
254 ARRAY_SIZE(audio_ext_pmi_div_clk),
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800255 .ops = &audio_ext_clk_ops,
256 },
257 },
258 },
259 {
260 .pnctrl_info = {NULL},
261 .fact = {
262 .mult = 1,
263 .div = 1,
264 .hw.init = &(struct clk_init_data){
265 .name = "audio_ext_pmi_lnbb_clk",
266 .parent_names = (const char *[])
267 { "ln_bb_clk2" },
268 .num_parents = 1,
Sudheer Papothi9b51e3e2018-07-21 05:20:10 +0530269 .ops = &audio_ext_clk_dummy_ops,
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800270 },
271 },
272 },
273 {
274 .pnctrl_info = {NULL},
275 .fact = {
276 .mult = 1,
277 .div = 1,
278 .hw.init = &(struct clk_init_data){
279 .name = "audio_lpass_mclk",
280 .ops = &audio_ext_clk_ops,
281 },
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530282 },
283 },
Laxminath Kasamd712cc72018-07-17 23:43:21 +0530284 {
285 .pnctrl_info = {NULL},
286 .fact = {
287 .mult = 1,
288 .div = 1,
289 .hw.init = &(struct clk_init_data){
290 .name = "audio_lpass_mclk2",
291 .ops = &audio_ext_clk_ops,
292 },
293 },
294 },
295 {
296 .pnctrl_info = {NULL},
297 .fact = {
298 .mult = 1,
299 .div = 1,
300 .hw.init = &(struct clk_init_data){
301 .name = "audio_lpass_mclk3",
302 .ops = &audio_ext_clk_ops,
303 },
304 },
305 },
Aditya Bavanari7259ca62018-07-30 12:03:03 +0530306 {
307 .pnctrl_info = {NULL},
308 .fact = {
309 .mult = 1,
310 .div = 1,
311 .hw.init = &(struct clk_init_data){
312 .name = "audio_lpass_mclk4",
313 .ops = &audio_ext_clk_ops,
314 },
315 },
316 },
317 {
318 .pnctrl_info = {NULL},
319 .fact = {
320 .mult = 1,
321 .div = 1,
322 .hw.init = &(struct clk_init_data){
323 .name = "audio_lpass_mclk5",
324 .ops = &audio_ext_clk_ops,
325 },
326 },
327 },
328 {
329 .pnctrl_info = {NULL},
330 .fact = {
331 .mult = 1,
332 .div = 1,
333 .hw.init = &(struct clk_init_data){
334 .name = "audio_lpass_mclk6",
335 .ops = &audio_ext_clk_ops,
336 },
337 },
338 },
339 {
340 .pnctrl_info = {NULL},
341 .fact = {
342 .mult = 1,
343 .div = 1,
344 .hw.init = &(struct clk_init_data){
345 .name = "audio_lpass_mclk7",
346 .ops = &audio_ext_clk_ops,
347 },
348 },
349 },
Mangesh Kunchamwar912a96a2018-11-13 16:04:53 +0530350 {
351 .pnctrl_info = {NULL},
352 .fact = {
353 .hw.init = &(struct clk_init_data){
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530354 .name = "lpass_hw_vote_clk",
355 .ops = &lpass_hw_vote_ops,
Mangesh Kunchamwar912a96a2018-11-13 16:04:53 +0530356 },
357 },
358 },
Rohit kumar68725bb2018-11-23 16:52:58 +0530359 {
360 .pnctrl_info = {NULL},
361 .fact = {
362 .mult = 1,
363 .div = 1,
364 .hw.init = &(struct clk_init_data){
Sudheer Papothia1351b92019-03-07 18:52:08 +0530365 .name = "audio_lpass_mclk8",
366 .ops = &audio_ext_clk_ops,
367 },
368 },
369 },
370 {
371 .pnctrl_info = {NULL},
372 .fact = {
Sudheer Papothiba445bf2019-04-16 05:05:55 +0530373 .hw.init = &(struct clk_init_data){
374 .name = "lpass_audio_hw_vote_clk",
375 .ops = &lpass_hw_vote_ops,
376 },
377 },
378 },
379 {
380 .pnctrl_info = {NULL},
381 .fact = {
Sudheer Papothia1351b92019-03-07 18:52:08 +0530382 .mult = 1,
383 .div = 1,
384 .hw.init = &(struct clk_init_data){
Rohit kumar68725bb2018-11-23 16:52:58 +0530385 .name = "audio_external_pll_clk",
386 .ops = &audio_ext_clk_ops,
387 },
388 },
389 },
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530390};
391
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800392static int audio_get_pinctrl(struct platform_device *pdev)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530393{
394 struct device *dev = &pdev->dev;
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800395 struct audio_ext_clk_priv *clk_priv = platform_get_drvdata(pdev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530396 struct pinctrl_info *pnctrl_info;
397 struct pinctrl *pinctrl;
398 int ret;
399 u32 reg;
400
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800401 pnctrl_info = &clk_priv->audio_clk.pnctrl_info;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530402 if (pnctrl_info->pinctrl) {
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800403 dev_err(dev, "%s: already requested before\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530404 __func__);
405 return -EINVAL;
406 }
407
408 pinctrl = devm_pinctrl_get(dev);
409 if (IS_ERR_OR_NULL(pinctrl)) {
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800410 dev_err(dev, "%s: Unable to get pinctrl handle\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530411 __func__);
412 return -EINVAL;
413 }
414 pnctrl_info->pinctrl = pinctrl;
415 /* get all state handles from Device Tree */
416 pnctrl_info->sleep = pinctrl_lookup_state(pinctrl, "sleep");
417 if (IS_ERR(pnctrl_info->sleep)) {
418 dev_err(dev, "%s: could not get sleep pinstate\n",
419 __func__);
420 goto err;
421 }
422 pnctrl_info->active = pinctrl_lookup_state(pinctrl, "active");
423 if (IS_ERR(pnctrl_info->active)) {
424 dev_err(dev, "%s: could not get active pinstate\n",
425 __func__);
426 goto err;
427 }
428 /* Reset the TLMM pins to a default state */
429 ret = pinctrl_select_state(pnctrl_info->pinctrl,
430 pnctrl_info->sleep);
431 if (ret) {
432 dev_err(dev, "%s: Disable TLMM pins failed with %d\n",
433 __func__, ret);
434 goto err;
435 }
436
437 ret = of_property_read_u32(dev->of_node, "qcom,mclk-clk-reg", &reg);
438 if (ret < 0) {
439 dev_dbg(dev, "%s: miss mclk reg\n", __func__);
440 } else {
441 pnctrl_info->base = ioremap(reg, sizeof(u32));
442 if (pnctrl_info->base == NULL) {
443 dev_err(dev, "%s ioremap failed\n", __func__);
444 goto err;
445 }
446 }
447
448 return 0;
449
450err:
451 devm_pinctrl_put(pnctrl_info->pinctrl);
452 return -EINVAL;
453}
454
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800455static int audio_put_pinctrl(struct platform_device *pdev)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530456{
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800457 struct audio_ext_clk_priv *clk_priv = platform_get_drvdata(pdev);
458 struct pinctrl_info *pnctrl_info = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530459
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800460 pnctrl_info = &clk_priv->audio_clk.pnctrl_info;
461 if (pnctrl_info && pnctrl_info->pinctrl) {
462 devm_pinctrl_put(pnctrl_info->pinctrl);
463 pnctrl_info->pinctrl = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530464 }
465
466 return 0;
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800467}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530468
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800469static int audio_get_clk_data(struct platform_device *pdev)
470{
471 int ret;
472 struct clk *audio_clk;
473 struct clk_hw *clkhw;
474 struct clk_onecell_data *clk_data;
475 struct audio_ext_clk_priv *clk_priv = platform_get_drvdata(pdev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530476
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800477 clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL);
478 if (!clk_data)
479 return -ENOMEM;
480
481 clk_data->clk_num = 1;
482 clk_data->clks = devm_kzalloc(&pdev->dev,
483 sizeof(struct clk *),
484 GFP_KERNEL);
485 if (!clk_data->clks)
486 return -ENOMEM;
487
488 clkhw = &clk_priv->audio_clk.fact.hw;
489 audio_clk = devm_clk_register(&pdev->dev, clkhw);
490 if (IS_ERR(audio_clk)) {
491 dev_err(&pdev->dev,
492 "%s: clock register failed for clk_src = %d\\n",
493 __func__, clk_priv->clk_src);
494 ret = PTR_ERR(audio_clk);
495 return ret;
496 }
497 clk_data->clks[0] = audio_clk;
498
499 ret = of_clk_add_provider(pdev->dev.of_node,
500 of_clk_src_onecell_get, clk_data);
501 if (ret)
502 dev_err(&pdev->dev, "%s: clock add failed for clk_src = %d\n",
503 __func__, clk_priv->clk_src);
504
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530505 return ret;
506}
507
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800508static int audio_ref_clk_probe(struct platform_device *pdev)
509{
510 int ret;
511 struct audio_ext_clk_priv *clk_priv;
Laxminath Kasam43c1a132018-06-15 13:18:07 +0530512 u32 clk_freq = 0, clk_id = 0, clk_src = 0, use_pinctrl = 0;
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800513
514 clk_priv = devm_kzalloc(&pdev->dev, sizeof(*clk_priv), GFP_KERNEL);
515 if (!clk_priv)
516 return -ENOMEM;
517
518 ret = of_property_read_u32(pdev->dev.of_node,
519 "qcom,codec-ext-clk-src",
520 &clk_src);
521 if (ret) {
522 dev_err(&pdev->dev, "%s: could not get clk source, ret = %d\n",
523 __func__, ret);
524 return ret;
525 }
526
527 if (clk_src >= AUDIO_EXT_CLK_MAX) {
528 dev_err(&pdev->dev, "%s: Invalid clk source = %d\n",
529 __func__, clk_src);
530 return -EINVAL;
531 }
Surendar Karka0a915f82018-07-09 20:30:03 +0530532 clk_priv->clk_name = NULL;
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800533 clk_priv->clk_src = clk_src;
534 memcpy(&clk_priv->audio_clk, &audio_clk_array[clk_src],
535 sizeof(struct audio_ext_clk));
536
537 /* Init lpass clk default values */
538 clk_priv->clk_cfg.clk_set_minor_version =
539 Q6AFE_LPASS_CLK_CONFIG_API_VERSION;
540 clk_priv->clk_cfg.clk_id = Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR;
541 clk_priv->clk_cfg.clk_freq_in_hz = Q6AFE_LPASS_OSR_CLK_9_P600_MHZ;
542 clk_priv->clk_cfg.clk_attri = Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO;
543
544 ret = of_property_read_u32(pdev->dev.of_node,
545 "qcom,codec-lpass-ext-clk-freq",
546 &clk_freq);
547 if (!ret)
548 clk_priv->clk_cfg.clk_freq_in_hz = clk_freq;
549
550 ret = of_property_read_u32(pdev->dev.of_node,
551 "qcom,codec-lpass-clk-id",
552 &clk_id);
553 if (!ret)
554 clk_priv->clk_cfg.clk_id = clk_id;
555
556 dev_dbg(&pdev->dev, "%s: ext-clk freq: %d, lpass clk_id: %d, clk_src: %d\n",
557 __func__, clk_priv->clk_cfg.clk_freq_in_hz,
558 clk_priv->clk_cfg.clk_id, clk_priv->clk_src);
559 platform_set_drvdata(pdev, clk_priv);
560
Surendar Karka0a915f82018-07-09 20:30:03 +0530561 ret = of_property_read_string(pdev->dev.of_node, "pmic-clock-names",
562 &clk_priv->clk_name);
563 if (ret)
564 dev_dbg(&pdev->dev, "%s: could not find pmic clock names\n",
565 __func__);
Laxminath Kasam43c1a132018-06-15 13:18:07 +0530566 /*
567 * property qcom,use-pinctrl to be defined in DTSI to val 1
568 * for clock nodes using pinctrl
569 */
570 of_property_read_u32(pdev->dev.of_node, "qcom,use-pinctrl",
571 &use_pinctrl);
572 dev_dbg(&pdev->dev, "%s: use-pinctrl : %d\n",
573 __func__, use_pinctrl);
574
575 if (use_pinctrl) {
576 ret = audio_get_pinctrl(pdev);
577 if (ret) {
578 dev_err(&pdev->dev, "%s: Parsing PMI pinctrl failed\n",
579 __func__);
580 return ret;
581 }
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800582 }
583
584 ret = audio_get_clk_data(pdev);
585 if (ret) {
586 dev_err(&pdev->dev, "%s: clk_init is failed\n",
587 __func__);
588 audio_put_pinctrl(pdev);
589 return ret;
590 }
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800591 return 0;
592}
593
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530594static int audio_ref_clk_remove(struct platform_device *pdev)
595{
Vidyakumar Athotaecc4eda2017-12-13 16:24:10 -0800596 audio_put_pinctrl(pdev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530597
598 return 0;
599}
600
601static const struct of_device_id audio_ref_clk_match[] = {
602 {.compatible = "qcom,audio-ref-clk"},
603 {}
604};
605MODULE_DEVICE_TABLE(of, audio_ref_clk_match);
606
607static struct platform_driver audio_ref_clk_driver = {
608 .driver = {
609 .name = "audio-ref-clk",
610 .owner = THIS_MODULE,
611 .of_match_table = audio_ref_clk_match,
Xiaojun Sang53cd13a2018-06-29 15:14:37 +0800612 .suppress_bind_attrs = true,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530613 },
614 .probe = audio_ref_clk_probe,
615 .remove = audio_ref_clk_remove,
616};
617
618int audio_ref_clk_platform_init(void)
619{
620 return platform_driver_register(&audio_ref_clk_driver);
621}
622
623void audio_ref_clk_platform_exit(void)
624{
625 platform_driver_unregister(&audio_ref_clk_driver);
626}
627
628MODULE_DESCRIPTION("Audio Ref Up Clock module platform driver");
629MODULE_LICENSE("GPL v2");