Skip to content

Commit

Permalink
ASoC: qcom: support bitclk and osrclk per i2s port
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Srinivas Kandagatla authored and Mark Brown committed May 22, 2015
1 parent 7cc24b1 commit 9a127cf
Showing 2 changed files with 43 additions and 22 deletions.
60 changes: 40 additions & 20 deletions sound/soc/qcom/lpass-cpu.c
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
int ret;

ret = clk_set_rate(drvdata->mi2s_osr_clk, freq);
ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
if (ret)
dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n",
__func__, freq, ret);
@@ -47,18 +47,18 @@ static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
int ret;

ret = clk_prepare_enable(drvdata->mi2s_osr_clk);
ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->diver->id]);
if (ret) {
dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
__func__, ret);
return ret;
}

ret = clk_prepare_enable(drvdata->mi2s_bit_clk);
ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->driver->id]);
if (ret) {
dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n",
__func__, ret);
clk_disable_unprepare(drvdata->mi2s_osr_clk);
clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
return ret;
}

@@ -70,8 +70,8 @@ static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
{
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);

clk_disable_unprepare(drvdata->mi2s_bit_clk);
clk_disable_unprepare(drvdata->mi2s_osr_clk);
clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
}

static 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,
return ret;
}

ret = clk_set_rate(drvdata->mi2s_bit_clk, rate * bitwidth * 2);
ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id],
rate * bitwidth * 2);
if (ret) {
dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n",
__func__, rate * bitwidth * 2, ret);
@@ -354,7 +355,8 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
struct lpass_variant *variant;
struct device *dev = &pdev->dev;
const struct of_device_id *match;
int ret;
char clk_name[16];
int ret, i, dai_id;

dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
if (dsp_of_node) {
@@ -400,18 +402,36 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
if (variant->init)
variant->init(pdev);

drvdata->mi2s_osr_clk = devm_clk_get(&pdev->dev, "mi2s-osr-clk");
if (IS_ERR(drvdata->mi2s_osr_clk)) {
dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n",
__func__, PTR_ERR(drvdata->mi2s_osr_clk));
return PTR_ERR(drvdata->mi2s_osr_clk);
}

drvdata->mi2s_bit_clk = devm_clk_get(&pdev->dev, "mi2s-bit-clk");
if (IS_ERR(drvdata->mi2s_bit_clk)) {
dev_err(&pdev->dev, "%s() error getting mi2s-bit-clk: %ld\n",
__func__, PTR_ERR(drvdata->mi2s_bit_clk));
return PTR_ERR(drvdata->mi2s_bit_clk);
for (i = 0; i < variant->num_dai; i++) {
dai_id = variant->dai_driver[i].id;
if (variant->num_dai > 1)
sprintf(clk_name, "mi2s-osr-clk%d", i);
else
sprintf(clk_name, "mi2s-osr-clk");

drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(&pdev->dev,
clk_name);
if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {
dev_err(&pdev->dev,
"%s() error getting mi2s-osr-clk: %ld\n",
__func__,
PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));
return PTR_ERR(drvdata->mi2s_osr_clk[dai_id]);
}

if (variant->num_dai > 1)
sprintf(clk_name, "mi2s-bit-clk%d", i);
else
sprintf(clk_name, "mi2s-bit-clk");

drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(&pdev->dev,
clk_name);
if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) {
dev_err(&pdev->dev,
"%s() error getting mi2s-bit-clk: %ld\n",
__func__, PTR_ERR(drvdata->mi2s_bit_clk[i]));
return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
}
}

drvdata->ahbix_clk = devm_clk_get(&pdev->dev, "ahbix-clk");
5 changes: 3 additions & 2 deletions sound/soc/qcom/lpass.h
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
#include <linux/regmap.h>

#define LPASS_AHBIX_CLOCK_FREQUENCY 131072000
#define LPASS_MAX_MI2S_PORTS (8)

/* Both the CPU DAI and platform drivers will access this data */
struct lpass_data {
@@ -30,10 +31,10 @@ struct lpass_data {
struct clk *ahbix_clk;

/* MI2S system clock */
struct clk *mi2s_osr_clk;
struct clk *mi2s_osr_clk[LPASS_MAX_MI2S_PORTS];

/* MI2S bit clock (derived from system clock by a divider */
struct clk *mi2s_bit_clk;
struct clk *mi2s_bit_clk[LPASS_MAX_MI2S_PORTS];

/* low-power audio interface (LPAIF) registers */
void __iomem *lpaif;

0 comments on commit 9a127cf

Please sign in to comment.