aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2015-05-21 17:52:49 -0400
committerMark Brown <broonie@kernel.org>2015-05-22 08:27:06 -0400
commit9a127cff91e43af807c96ca4ec7c855d382cc23d (patch)
tree7b9b3fd3f181047788da764b6dfd3fff8540a1a4
parent7cc24b169fa176618c654e50cb27640b75fe68d6 (diff)
ASoC: qcom: support bitclk and osrclk per i2s port
This patch adds support to allow bitclk and osrclk per i2s dai port. on APQ8016 there are 4 i2s ports each one has its own bit clks. Without this patch its not possible to support multiple i2s ports in the lpass driver. Tested-by: Kenneth Westfield <kwestfie@codeaurora.org> Acked-by: Kenneth Westfield <kwestfie@codeaurora.org> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/qcom/lpass-cpu.c60
-rw-r--r--sound/soc/qcom/lpass.h5
2 files changed, 43 insertions, 22 deletions
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index fd181330b3ca..96cb4950b2fd 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -33,7 +33,7 @@ static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
33 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 33 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
34 int ret; 34 int ret;
35 35
36 ret = clk_set_rate(drvdata->mi2s_osr_clk, freq); 36 ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
37 if (ret) 37 if (ret)
38 dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n", 38 dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n",
39 __func__, freq, ret); 39 __func__, freq, ret);
@@ -47,18 +47,18 @@ static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
47 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 47 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
48 int ret; 48 int ret;
49 49
50 ret = clk_prepare_enable(drvdata->mi2s_osr_clk); 50 ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->diver->id]);
51 if (ret) { 51 if (ret) {
52 dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n", 52 dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
53 __func__, ret); 53 __func__, ret);
54 return ret; 54 return ret;
55 } 55 }
56 56
57 ret = clk_prepare_enable(drvdata->mi2s_bit_clk); 57 ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->driver->id]);
58 if (ret) { 58 if (ret) {
59 dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n", 59 dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n",
60 __func__, ret); 60 __func__, ret);
61 clk_disable_unprepare(drvdata->mi2s_osr_clk); 61 clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
62 return ret; 62 return ret;
63 } 63 }
64 64
@@ -70,8 +70,8 @@ static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
70{ 70{
71 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 71 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
72 72
73 clk_disable_unprepare(drvdata->mi2s_bit_clk); 73 clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
74 clk_disable_unprepare(drvdata->mi2s_osr_clk); 74 clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
75} 75}
76 76
77static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream, 77static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
@@ -146,7 +146,8 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
146 return ret; 146 return ret;
147 } 147 }
148 148
149 ret = clk_set_rate(drvdata->mi2s_bit_clk, rate * bitwidth * 2); 149 ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id],
150 rate * bitwidth * 2);
150 if (ret) { 151 if (ret) {
151 dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n", 152 dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n",
152 __func__, rate * bitwidth * 2, ret); 153 __func__, rate * bitwidth * 2, ret);
@@ -354,7 +355,8 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
354 struct lpass_variant *variant; 355 struct lpass_variant *variant;
355 struct device *dev = &pdev->dev; 356 struct device *dev = &pdev->dev;
356 const struct of_device_id *match; 357 const struct of_device_id *match;
357 int ret; 358 char clk_name[16];
359 int ret, i, dai_id;
358 360
359 dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0); 361 dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
360 if (dsp_of_node) { 362 if (dsp_of_node) {
@@ -400,18 +402,36 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
400 if (variant->init) 402 if (variant->init)
401 variant->init(pdev); 403 variant->init(pdev);
402 404
403 drvdata->mi2s_osr_clk = devm_clk_get(&pdev->dev, "mi2s-osr-clk"); 405 for (i = 0; i < variant->num_dai; i++) {
404 if (IS_ERR(drvdata->mi2s_osr_clk)) { 406 dai_id = variant->dai_driver[i].id;
405 dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n", 407 if (variant->num_dai > 1)
406 __func__, PTR_ERR(drvdata->mi2s_osr_clk)); 408 sprintf(clk_name, "mi2s-osr-clk%d", i);
407 return PTR_ERR(drvdata->mi2s_osr_clk); 409 else
408 } 410 sprintf(clk_name, "mi2s-osr-clk");
409 411
410 drvdata->mi2s_bit_clk = devm_clk_get(&pdev->dev, "mi2s-bit-clk"); 412 drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(&pdev->dev,
411 if (IS_ERR(drvdata->mi2s_bit_clk)) { 413 clk_name);
412 dev_err(&pdev->dev, "%s() error getting mi2s-bit-clk: %ld\n", 414 if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {
413 __func__, PTR_ERR(drvdata->mi2s_bit_clk)); 415 dev_err(&pdev->dev,
414 return PTR_ERR(drvdata->mi2s_bit_clk); 416 "%s() error getting mi2s-osr-clk: %ld\n",
417 __func__,
418 PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));
419 return PTR_ERR(drvdata->mi2s_osr_clk[dai_id]);
420 }
421
422 if (variant->num_dai > 1)
423 sprintf(clk_name, "mi2s-bit-clk%d", i);
424 else
425 sprintf(clk_name, "mi2s-bit-clk");
426
427 drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(&pdev->dev,
428 clk_name);
429 if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) {
430 dev_err(&pdev->dev,
431 "%s() error getting mi2s-bit-clk: %ld\n",
432 __func__, PTR_ERR(drvdata->mi2s_bit_clk[i]));
433 return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
434 }
415 } 435 }
416 436
417 drvdata->ahbix_clk = devm_clk_get(&pdev->dev, "ahbix-clk"); 437 drvdata->ahbix_clk = devm_clk_get(&pdev->dev, "ahbix-clk");
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index caaf17fb0015..75e9370cb360 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -22,6 +22,7 @@
22#include <linux/regmap.h> 22#include <linux/regmap.h>
23 23
24#define LPASS_AHBIX_CLOCK_FREQUENCY 131072000 24#define LPASS_AHBIX_CLOCK_FREQUENCY 131072000
25#define LPASS_MAX_MI2S_PORTS (8)
25 26
26/* Both the CPU DAI and platform drivers will access this data */ 27/* Both the CPU DAI and platform drivers will access this data */
27struct lpass_data { 28struct lpass_data {
@@ -30,10 +31,10 @@ struct lpass_data {
30 struct clk *ahbix_clk; 31 struct clk *ahbix_clk;
31 32
32 /* MI2S system clock */ 33 /* MI2S system clock */
33 struct clk *mi2s_osr_clk; 34 struct clk *mi2s_osr_clk[LPASS_MAX_MI2S_PORTS];
34 35
35 /* MI2S bit clock (derived from system clock by a divider */ 36 /* MI2S bit clock (derived from system clock by a divider */
36 struct clk *mi2s_bit_clk; 37 struct clk *mi2s_bit_clk[LPASS_MAX_MI2S_PORTS];
37 38
38 /* low-power audio interface (LPAIF) registers */ 39 /* low-power audio interface (LPAIF) registers */
39 void __iomem *lpaif; 40 void __iomem *lpaif;