blob: 753e7f049ef9750d76588fc752892cf113ea22ba [file] [log] [blame]
Banajit Goswami2d3eebc2017-02-01 12:52:50 -08001/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
Banajit Goswamide8271c2017-01-18 00:28:59 -08002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/err.h>
16#include <linux/module.h>
17#include <linux/of.h>
18#include <linux/clk.h>
19#include <linux/clk-provider.h>
20#include "../../../drivers/clk/qcom/common.h"
21#include <linux/platform_device.h>
22#include <linux/gpio.h>
23#include <linux/of_gpio.h>
Banajit Goswami2d3eebc2017-02-01 12:52:50 -080024#include <dt-bindings/clock/qcom,audio-ext-clk.h>
Banajit Goswamide8271c2017-01-18 00:28:59 -080025#include <sound/q6afe-v2.h>
26
27enum audio_clk_mux {
28 AP_CLK2,
29 LPASS_MCLK,
30 LPASS_MCLK2,
31};
32
33struct pinctrl_info {
34 struct pinctrl *pinctrl;
35 struct pinctrl_state *sleep;
36 struct pinctrl_state *active;
37};
38
39struct audio_ext_ap_clk {
40 bool enabled;
41 int gpio;
42 struct clk_fixed_factor fact;
43};
44
45struct audio_ext_pmi_clk {
46 int gpio;
47 struct clk_fixed_factor fact;
48};
49
50struct audio_ext_ap_clk2 {
51 bool enabled;
52 struct pinctrl_info pnctrl_info;
53 struct clk_fixed_factor fact;
54};
55
56struct audio_ext_lpass_mclk {
57 struct pinctrl_info pnctrl_info;
58 struct clk_fixed_factor fact;
59};
60
61static struct afe_clk_set clk2_config = {
62 Q6AFE_LPASS_CLK_CONFIG_API_VERSION,
63 Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR,
64 Q6AFE_LPASS_IBIT_CLK_11_P2896_MHZ,
65 Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
66 Q6AFE_LPASS_CLK_ROOT_DEFAULT,
67 0,
68};
69
70static struct afe_clk_set lpass_default = {
71 Q6AFE_LPASS_CLK_CONFIG_API_VERSION,
72 Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR,
73 Q6AFE_LPASS_IBIT_CLK_11_P2896_MHZ,
74 Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
75 Q6AFE_LPASS_CLK_ROOT_DEFAULT,
76 0,
77};
78
79static struct afe_clk_set lpass_mclk = {
80 Q6AFE_LPASS_CLK_CONFIG_API_VERSION,
81 Q6AFE_LPASS_CLK_ID_MCLK_1,
82 Q6AFE_LPASS_OSR_CLK_11_P2896_MHZ,
83 Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
84 Q6AFE_LPASS_CLK_ROOT_DEFAULT,
85 0,
86};
87
88static inline struct audio_ext_ap_clk *to_audio_ap_clk(struct clk_hw *hw)
89{
90 return container_of(hw, struct audio_ext_ap_clk, fact.hw);
91}
92
93static int audio_ext_clk_prepare(struct clk_hw *hw)
94{
95 struct audio_ext_ap_clk *audio_clk = to_audio_ap_clk(hw);
96
97 pr_debug("%s: gpio: %d\n", __func__, audio_clk->gpio);
98 if (gpio_is_valid(audio_clk->gpio))
99 return gpio_direction_output(audio_clk->gpio, 1);
100 return 0;
101}
102
103static void audio_ext_clk_unprepare(struct clk_hw *hw)
104{
105 struct audio_ext_ap_clk *audio_clk = to_audio_ap_clk(hw);
106
107 pr_debug("%s: gpio: %d\n", __func__, audio_clk->gpio);
108 if (gpio_is_valid(audio_clk->gpio))
109 gpio_direction_output(audio_clk->gpio, 0);
110}
111
112static inline struct audio_ext_ap_clk2 *to_audio_ap_clk2(struct clk_hw *hw)
113{
114 return container_of(hw, struct audio_ext_ap_clk2, fact.hw);
115}
116
117static int audio_ext_clk2_prepare(struct clk_hw *hw)
118{
119 struct audio_ext_ap_clk2 *audio_clk2 = to_audio_ap_clk2(hw);
120 struct pinctrl_info *pnctrl_info = &audio_clk2->pnctrl_info;
121 int ret;
122
123
124 if (!pnctrl_info->pinctrl || !pnctrl_info->active)
125 return 0;
126
127 ret = pinctrl_select_state(pnctrl_info->pinctrl,
128 pnctrl_info->active);
129 if (ret) {
130 pr_err("%s: active state select failed with %d\n",
131 __func__, ret);
132 return -EIO;
133 }
134
135 clk2_config.enable = 1;
136 ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk2_config);
137 if (ret < 0) {
138 pr_err("%s: failed to set clock, ret = %d\n", __func__, ret);
139 return -EINVAL;
140 }
141
142 return 0;
143}
144
145static void audio_ext_clk2_unprepare(struct clk_hw *hw)
146{
147 struct audio_ext_ap_clk2 *audio_clk2 = to_audio_ap_clk2(hw);
148 struct pinctrl_info *pnctrl_info = &audio_clk2->pnctrl_info;
149 int ret;
150
151 if (!pnctrl_info->pinctrl || !pnctrl_info->sleep)
152 return;
153
154 ret = pinctrl_select_state(pnctrl_info->pinctrl,
155 pnctrl_info->sleep);
156 if (ret)
157 pr_err("%s: sleep state select failed with %d\n",
158 __func__, ret);
159
160 clk2_config.enable = 0;
161 ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk2_config);
162 if (ret < 0)
163 pr_err("%s: failed to reset clock, ret = %d\n", __func__, ret);
164}
165
166static inline struct audio_ext_lpass_mclk *to_audio_lpass_mclk(
167 struct clk_hw *hw)
168{
169 return container_of(hw, struct audio_ext_lpass_mclk, fact.hw);
170}
171
172static int audio_ext_lpass_mclk_prepare(struct clk_hw *hw)
173{
174 struct audio_ext_lpass_mclk *audio_lpass_mclk = to_audio_lpass_mclk(hw);
175 struct pinctrl_info *pnctrl_info = &audio_lpass_mclk->pnctrl_info;
176 int ret;
177
178 if (pnctrl_info->pinctrl) {
179 ret = pinctrl_select_state(pnctrl_info->pinctrl,
180 pnctrl_info->active);
181 if (ret) {
182 pr_err("%s: active state select failed with %d\n",
183 __func__, ret);
184 return -EIO;
185 }
186 }
187
188 lpass_mclk.enable = 1;
189 ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX,
190 &lpass_mclk);
191 if (ret < 0) {
192 pr_err("%s afe_set_digital_codec_core_clock failed\n",
193 __func__);
194 return ret;
195 }
196
197 return 0;
198}
199
200static void audio_ext_lpass_mclk_unprepare(struct clk_hw *hw)
201{
202 struct audio_ext_lpass_mclk *audio_lpass_mclk = to_audio_lpass_mclk(hw);
203 struct pinctrl_info *pnctrl_info = &audio_lpass_mclk->pnctrl_info;
204 int ret;
205
206 if (pnctrl_info->pinctrl) {
207 ret = pinctrl_select_state(pnctrl_info->pinctrl,
208 pnctrl_info->sleep);
209 if (ret) {
210 pr_err("%s: active state select failed with %d\n",
211 __func__, ret);
212 return;
213 }
214 }
215
216 lpass_mclk.enable = 0;
217 ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX,
218 &lpass_mclk);
219 if (ret < 0)
220 pr_err("%s: afe_set_digital_codec_core_clock failed, ret = %d\n",
221 __func__, ret);
222}
223
224static int audio_ext_lpass_mclk2_prepare(struct clk_hw *hw)
225{
226 struct audio_ext_lpass_mclk *audio_lpass_mclk2 =
227 to_audio_lpass_mclk(hw);
228 struct pinctrl_info *pnctrl_info = &audio_lpass_mclk2->pnctrl_info;
229 int ret;
230
231 if (pnctrl_info->pinctrl) {
232 ret = pinctrl_select_state(pnctrl_info->pinctrl,
233 pnctrl_info->active);
234 if (ret) {
235 pr_err("%s: active state select failed with %d\n",
236 __func__, ret);
237 return -EIO;
238 }
239 }
240
241 lpass_default.enable = 1;
242 ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &lpass_default);
243 if (ret < 0) {
244 pr_err("%s: failed to set clock, ret = %d\n", __func__, ret);
245 return -EINVAL;
246 }
247
248 return 0;
249}
250
251static void audio_ext_lpass_mclk2_unprepare(struct clk_hw *hw)
252{
253 struct audio_ext_lpass_mclk *audio_lpass_mclk2 =
254 to_audio_lpass_mclk(hw);
255 struct pinctrl_info *pnctrl_info = &audio_lpass_mclk2->pnctrl_info;
256 int ret;
257
258 if (pnctrl_info->pinctrl) {
259 ret = pinctrl_select_state(pnctrl_info->pinctrl,
260 pnctrl_info->sleep);
261 if (ret)
262 pr_err("%s: sleep state select failed with %d\n",
263 __func__, ret);
264 }
265
266 lpass_default.enable = 0;
267 ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &lpass_default);
268 if (ret < 0)
269 pr_err("%s: failed to reset clock, ret = %d\n", __func__, ret);
270}
271
272static const struct clk_ops audio_ext_ap_clk_ops = {
273 .prepare = audio_ext_clk_prepare,
274 .unprepare = audio_ext_clk_unprepare,
275};
276
277static const struct clk_ops audio_ext_ap_clk2_ops = {
278 .prepare = audio_ext_clk2_prepare,
279 .unprepare = audio_ext_clk2_unprepare,
280};
281
282static const struct clk_ops audio_ext_lpass_mclk_ops = {
283 .prepare = audio_ext_lpass_mclk_prepare,
284 .unprepare = audio_ext_lpass_mclk_unprepare,
285};
286
287static const struct clk_ops audio_ext_lpass_mclk2_ops = {
288 .prepare = audio_ext_lpass_mclk2_prepare,
289 .unprepare = audio_ext_lpass_mclk2_unprepare,
290};
291
292static struct audio_ext_pmi_clk audio_pmi_clk = {
293 .gpio = -EINVAL,
294 .fact = {
295 .mult = 1,
296 .div = 1,
297 .hw.init = &(struct clk_init_data){
298 .name = "audio_ext_pmi_clk",
Yeleswarapu Nagaradhesh3f051562017-01-17 16:05:34 +0530299 .parent_names = (const char *[]){ "div_clk1" },
300 .num_parents = 1,
Banajit Goswamide8271c2017-01-18 00:28:59 -0800301 .ops = &clk_dummy_ops,
302 },
303 },
304};
305
306static struct audio_ext_pmi_clk audio_pmi_lnbb_clk = {
307 .gpio = -EINVAL,
308 .fact = {
309 .mult = 1,
310 .div = 1,
311 .hw.init = &(struct clk_init_data){
312 .name = "audio_ext_pmi_lnbb_clk",
Yeleswarapu Nagaradhesh3f051562017-01-17 16:05:34 +0530313 .parent_names = (const char *[]){ "ln_bb_clk2" },
314 .num_parents = 1,
Banajit Goswamide8271c2017-01-18 00:28:59 -0800315 .ops = &clk_dummy_ops,
316 },
317 },
318};
319
320static struct audio_ext_ap_clk audio_ap_clk = {
321 .gpio = -EINVAL,
322 .fact = {
323 .mult = 1,
324 .div = 1,
325 .hw.init = &(struct clk_init_data){
326 .name = "audio_ap_clk",
327 .ops = &audio_ext_ap_clk_ops,
328 },
329 },
330};
331
332static struct audio_ext_ap_clk2 audio_ap_clk2 = {
333 .enabled = false,
334 .pnctrl_info = {NULL},
335 .fact = {
336 .mult = 1,
337 .div = 1,
338 .hw.init = &(struct clk_init_data){
339 .name = "audio_ap_clk2",
340 .ops = &audio_ext_ap_clk2_ops,
341 },
342 },
343};
344
345static struct audio_ext_lpass_mclk audio_lpass_mclk = {
346 .pnctrl_info = {NULL},
347 .fact = {
348 .mult = 1,
349 .div = 1,
350 .hw.init = &(struct clk_init_data){
351 .name = "audio_lpass_mclk",
352 .ops = &audio_ext_lpass_mclk_ops,
353 },
354 },
355};
356
357static struct audio_ext_lpass_mclk audio_lpass_mclk2 = {
358 .pnctrl_info = {NULL},
359 .fact = {
360 .mult = 1,
361 .div = 1,
362 .hw.init = &(struct clk_init_data){
363 .name = "audio_lpass_mclk2",
364 .ops = &audio_ext_lpass_mclk2_ops,
365 },
366 },
367};
368
369static struct clk_hw *audio_msm_hws[] = {
370 &audio_pmi_clk.fact.hw,
Banajit Goswamide8271c2017-01-18 00:28:59 -0800371 &audio_ap_clk.fact.hw,
372 &audio_ap_clk2.fact.hw,
373 &audio_lpass_mclk.fact.hw,
374 &audio_lpass_mclk2.fact.hw,
375};
376
Yeleswarapu Nagaradhesh3f051562017-01-17 16:05:34 +0530377static struct clk_hw *audio_msm_hws1[] = {
378 &audio_pmi_lnbb_clk.fact.hw,
379};
380
Banajit Goswamide8271c2017-01-18 00:28:59 -0800381static int audio_get_pinctrl(struct platform_device *pdev,
382 enum audio_clk_mux mux)
383{
384 struct pinctrl_info *pnctrl_info;
385 struct pinctrl *pinctrl;
386 int ret;
387
388 switch (mux) {
389 case AP_CLK2:
390 pnctrl_info = &audio_ap_clk2.pnctrl_info;
391 break;
392 case LPASS_MCLK:
393 pnctrl_info = &audio_lpass_mclk.pnctrl_info;
394 break;
395 case LPASS_MCLK2:
396 pnctrl_info = &audio_lpass_mclk2.pnctrl_info;
397 break;
398 default:
399 dev_err(&pdev->dev, "%s Not a valid MUX ID: %d\n",
400 __func__, mux);
401 return -EINVAL;
402 }
403 pnctrl_info = &audio_ap_clk2.pnctrl_info;
404
405 if (pnctrl_info->pinctrl) {
406 dev_dbg(&pdev->dev, "%s: already requested before\n",
407 __func__);
408 return -EINVAL;
409 }
410
411 pinctrl = devm_pinctrl_get(&pdev->dev);
412 if (IS_ERR_OR_NULL(pinctrl)) {
413 dev_dbg(&pdev->dev, "%s: Unable to get pinctrl handle\n",
414 __func__);
415 return -EINVAL;
416 }
417 pnctrl_info->pinctrl = pinctrl;
418 /* get all state handles from Device Tree */
419 pnctrl_info->sleep = pinctrl_lookup_state(pinctrl, "sleep");
420 if (IS_ERR(pnctrl_info->sleep)) {
421 dev_err(&pdev->dev, "%s: could not get sleep pinstate\n",
422 __func__);
423 goto err;
424 }
425 pnctrl_info->active = pinctrl_lookup_state(pinctrl, "active");
426 if (IS_ERR(pnctrl_info->active)) {
427 dev_err(&pdev->dev, "%s: could not get active pinstate\n",
428 __func__);
429 goto err;
430 }
431 /* Reset the TLMM pins to a default state */
432 ret = pinctrl_select_state(pnctrl_info->pinctrl,
433 pnctrl_info->sleep);
434 if (ret) {
435 dev_err(&pdev->dev, "%s: Disable TLMM pins failed with %d\n",
436 __func__, ret);
437 goto err;
438 }
439 return 0;
440
441err:
442 devm_pinctrl_put(pnctrl_info->pinctrl);
443 return -EINVAL;
444}
445
446static int audio_ref_clk_probe(struct platform_device *pdev)
447{
448 int clk_gpio;
449 int ret;
450 u32 mclk_freq;
451 struct clk *audio_clk;
452 struct device *dev = &pdev->dev;
453 int i;
454 struct clk_onecell_data *clk_data;
455
456 ret = of_property_read_u32(pdev->dev.of_node,
457 "qcom,codec-mclk-clk-freq",
458 &mclk_freq);
459 if (!ret) {
460 lpass_mclk.clk_freq_in_hz = mclk_freq;
461
462 ret = audio_get_pinctrl(pdev, LPASS_MCLK);
463 if (ret)
464 dev_err(&pdev->dev, "%s: Parsing pinctrl %s failed\n",
465 __func__, "LPASS_MCLK");
466 ret = audio_get_pinctrl(pdev, LPASS_MCLK2);
467 if (ret)
468 dev_dbg(&pdev->dev, "%s: Parsing pinctrl %s failed\n",
469 __func__, "LPASS_MCLK2");
470 }
471
472 clk_gpio = of_get_named_gpio(pdev->dev.of_node,
473 "qcom,audio-ref-clk-gpio", 0);
474 if (clk_gpio > 0) {
475 ret = gpio_request(clk_gpio, "EXT_CLK");
476 if (ret) {
477 dev_err(&pdev->dev,
478 "Request ext clk gpio failed %d, err:%d\n",
479 clk_gpio, ret);
480 goto err;
481 }
482 if (of_property_read_bool(pdev->dev.of_node,
483 "qcom,node_has_rpm_clock")) {
484 audio_pmi_clk.gpio = clk_gpio;
485 } else
486 audio_ap_clk.gpio = clk_gpio;
487
488 }
489
490 ret = audio_get_pinctrl(pdev, AP_CLK2);
491 if (ret)
492 dev_dbg(&pdev->dev, "%s: Parsing pinctrl failed\n",
493 __func__);
494
495 clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL);
496 if (!clk_data)
497 goto err_gpio;
498
499 clk_data->clk_num = ARRAY_SIZE(audio_msm_hws);
500 clk_data->clks = devm_kzalloc(&pdev->dev,
501 clk_data->clk_num * sizeof(struct clk *),
502 GFP_KERNEL);
503 if (!clk_data->clks)
504 goto err_clk;
505
Yeleswarapu Nagaradhesh3f051562017-01-17 16:05:34 +0530506
507 clk_gpio = of_get_named_gpio(pdev->dev.of_node,
508 "qcom,audio-ref-clk-gpio", 0);
509 if (clk_gpio > 0) {
510 for (i = 0; i < ARRAY_SIZE(audio_msm_hws); i++) {
511 audio_clk = devm_clk_register(dev, audio_msm_hws[i]);
512 if (IS_ERR(audio_clk)) {
513 dev_err(&pdev->dev,
514 "%s: ref clock: %d register failed\n",
515 __func__, i);
516 return PTR_ERR(audio_clk);
517 }
518 clk_data->clks[i] = audio_clk;
Banajit Goswamide8271c2017-01-18 00:28:59 -0800519 }
Yeleswarapu Nagaradhesh3f051562017-01-17 16:05:34 +0530520 } else {
521 for (i = 0; i < ARRAY_SIZE(audio_msm_hws1); i++) {
522 audio_clk = devm_clk_register(dev, audio_msm_hws1[i]);
523 if (IS_ERR(audio_clk)) {
524 dev_err(&pdev->dev,
525 "%s: ref clock: %d register failed\n",
526 __func__, i);
527 return PTR_ERR(audio_clk);
528 }
529 clk_data->clks[i] = audio_clk;
530 }
Banajit Goswamide8271c2017-01-18 00:28:59 -0800531 }
532
533 ret = of_clk_add_provider(pdev->dev.of_node,
534 of_clk_src_onecell_get, clk_data);
535 if (ret) {
536 dev_err(&pdev->dev, "%s: audio ref clock register failed\n",
537 __func__);
538 goto err_gpio;
539 }
540
541 return 0;
542
543err_clk:
544 if (clk_data)
545 devm_kfree(&pdev->dev, clk_data->clks);
546 devm_kfree(&pdev->dev, clk_data);
547err_gpio:
548 gpio_free(clk_gpio);
549
550err:
551 return ret;
552}
553
554static int audio_ref_clk_remove(struct platform_device *pdev)
555{
556 struct pinctrl_info *pnctrl_info = &audio_ap_clk2.pnctrl_info;
557
558 if (audio_pmi_clk.gpio > 0)
559 gpio_free(audio_pmi_clk.gpio);
560 else if (audio_ap_clk.gpio > 0)
561 gpio_free(audio_ap_clk.gpio);
562
563 if (pnctrl_info->pinctrl) {
564 devm_pinctrl_put(pnctrl_info->pinctrl);
565 pnctrl_info->pinctrl = NULL;
566 }
567
568 return 0;
569}
570
571static const struct of_device_id audio_ref_clk_match[] = {
572 {.compatible = "qcom,audio-ref-clk"},
573 {}
574};
575MODULE_DEVICE_TABLE(of, audio_ref_clk_match);
576
577static struct platform_driver audio_ref_clk_driver = {
578 .driver = {
579 .name = "audio-ref-clk",
580 .owner = THIS_MODULE,
581 .of_match_table = audio_ref_clk_match,
582 },
583 .probe = audio_ref_clk_probe,
584 .remove = audio_ref_clk_remove,
585};
586
587static int __init audio_ref_clk_platform_init(void)
588{
589 return platform_driver_register(&audio_ref_clk_driver);
590}
591module_init(audio_ref_clk_platform_init);
592
593static void __exit audio_ref_clk_platform_exit(void)
594{
595 platform_driver_unregister(&audio_ref_clk_driver);
596}
597module_exit(audio_ref_clk_platform_exit);
598
599MODULE_DESCRIPTION("Audio Ref Up Clock module platform driver");
600MODULE_LICENSE("GPL v2");