ASoC: tegra-alt: aud mclk clock control via DT

Added support to control the aud mclk parent, rate and scaling factor
from the dt entry which can be optional. With this support, the aud mclk
can be set to all possible aud mclk clock parent, also can set the desired
fixed rate and scale the aud_mclk as a function of Fs.

Bug 200513507

Change-Id: I80d776b7d157c49040d2da8b95b046c21926003b
Signed-off-by: Mohan Kumar <mkumard@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/2111340
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: Jonathan Hunter <jonathanh@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Sameer Pujar <spujar@nvidia.com>
Reviewed-by: Sharad Gupta <sharadg@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Mohan Kumar
2019-05-03 14:03:23 +05:30
committed by Sameer Pujar
parent 7c8718b81e
commit 52f2d67cf4
3 changed files with 38 additions and 23 deletions

View File

@@ -59,17 +59,18 @@ struct tegra_asoc_audio_clock_info {
int set_mclk; int set_mclk;
int lock_count; int lock_count;
int set_baseclock; int set_baseclock;
int set_clk_out_rate;
int num_clk; int num_clk;
unsigned int clk_out_rate; struct clk *clk_mclk_parent;
unsigned int mclk_scale; u32 set_clk_out_rate;
u32 mclk_rate;
u32 mclk_scale;
u32 clk_rates[MAX_NUM_RATES]; u32 clk_rates[MAX_NUM_RATES];
}; };
int tegra_alt_asoc_utils_set_rate(struct tegra_asoc_audio_clock_info *data, int tegra_alt_asoc_utils_set_rate(struct tegra_asoc_audio_clock_info *data,
int srate, int srate,
int mclk, int mclk,
int clk_out_rate); u32 clk_out_rate);
void tegra_alt_asoc_utils_lock_clk_rate( void tegra_alt_asoc_utils_lock_clk_rate(
struct tegra_asoc_audio_clock_info *data, struct tegra_asoc_audio_clock_info *data,
int lock); int lock);

View File

@@ -514,10 +514,11 @@ static int tegra_machine_dai_init(struct snd_soc_pcm_runtime *runtime,
} }
if (machine->soc_data->is_clk_rate_via_dt) if (machine->soc_data->is_clk_rate_via_dt)
clk_out_rate = machine->audio_clock.clk_out_rate; clk_out_rate = machine->audio_clock.set_clk_out_rate;
pr_debug("pll_a_out0 = %d Hz, aud_mclk = %d Hz, codec rate = %d Hz\n", pr_debug("pll_a_out0 = %d Hz, aud_mclk = %d Hz, codec rate = %d Hz\n",
machine->audio_clock.set_mclk, clk_out_rate, clk_rate); machine->audio_clock.set_mclk,
machine->audio_clock.set_clk_out_rate, clk_rate);
/* TODO: should we pass here clk_rate ? */ /* TODO: should we pass here clk_rate ? */
err = tegra_machine_set_params(card, machine, rate, channels, formats); err = tegra_machine_set_params(card, machine, rate, channels, formats);
@@ -1075,6 +1076,16 @@ static int tegra_machine_driver_probe(struct platform_device *pdev)
if (ret) if (ret)
goto err; goto err;
if (of_property_read_u32(np, "nvidia,mclk-rate",
&machine->audio_clock.mclk_rate) < 0)
dev_dbg(&pdev->dev, "Missing property nvidia,mclk-rate\n");
if (of_property_read_u32(np, "mclk-fs",
&machine->audio_clock.mclk_scale) < 0) {
machine->audio_clock.mclk_scale = 256;
dev_dbg(&pdev->dev, "Missing property mclk-fs\n");
}
if (machine->soc_data->is_clk_rate_via_dt) { if (machine->soc_data->is_clk_rate_via_dt) {
if (of_property_read_u32(np, "nvidia,num-clk", if (of_property_read_u32(np, "nvidia,num-clk",
&machine->audio_clock.num_clk) < 0) { &machine->audio_clock.num_clk) < 0) {

View File

@@ -40,7 +40,7 @@
int tegra_alt_asoc_utils_set_rate(struct tegra_asoc_audio_clock_info *data, int tegra_alt_asoc_utils_set_rate(struct tegra_asoc_audio_clock_info *data,
int srate, int srate,
int mclk, int mclk,
int clk_out_rate) u32 clk_out_rate)
{ {
int new_baseclock; int new_baseclock;
int ahub_rate = 0; int ahub_rate = 0;
@@ -67,9 +67,7 @@ int tegra_alt_asoc_utils_set_rate(struct tegra_asoc_audio_clock_info *data,
mclk = mclk >> 1; mclk = mclk >> 1;
ahub_rate = ahub_rate >> 1; ahub_rate = ahub_rate >> 1;
} }
clk_out_rate = srate * data->mclk_scale; clk_out_rate = srate * data->mclk_scale;
data->clk_out_rate = clk_out_rate;
} }
break; break;
case 8000: case 8000:
@@ -93,15 +91,15 @@ int tegra_alt_asoc_utils_set_rate(struct tegra_asoc_audio_clock_info *data,
mclk = mclk >> 1; mclk = mclk >> 1;
ahub_rate = ahub_rate >> 1; ahub_rate = ahub_rate >> 1;
} }
clk_out_rate = srate * data->mclk_scale; clk_out_rate = srate * data->mclk_scale;
data->clk_out_rate = clk_out_rate;
} }
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
clk_out_rate = data->mclk_rate ? data->mclk_rate : clk_out_rate;
clk_change = ((new_baseclock != data->set_baseclock) || clk_change = ((new_baseclock != data->set_baseclock) ||
(mclk != data->set_mclk) || (mclk != data->set_mclk) ||
(clk_out_rate != data->set_clk_out_rate)); (clk_out_rate != data->set_clk_out_rate));
@@ -191,7 +189,6 @@ int tegra_alt_asoc_utils_init(struct tegra_asoc_audio_clock_info *data,
{ {
data->dev = dev; data->dev = dev;
data->card = card; data->card = card;
data->mclk_scale = 256;
if (of_machine_is_compatible("nvidia,tegra210") || if (of_machine_is_compatible("nvidia,tegra210") ||
of_machine_is_compatible("nvidia,tegra210b01")) of_machine_is_compatible("nvidia,tegra210b01"))
@@ -228,6 +225,14 @@ int tegra_alt_asoc_utils_init(struct tegra_asoc_audio_clock_info *data,
return PTR_ERR(data->clk_cdev1); return PTR_ERR(data->clk_cdev1);
} }
/* Control the aud mclk rate and parent for usecases which might
* need fixed rate and needs to be derived from other possible
* parents of aud mclk clk source
*/
data->clk_mclk_parent = devm_clk_get(dev, "mclk_parent");
if (IS_ERR(data->clk_mclk_parent))
dev_dbg(data->dev, "Can't retrieve mclk parent clk\n");
if (data->soc > TEGRA_ASOC_UTILS_SOC_TEGRA210) { if (data->soc > TEGRA_ASOC_UTILS_SOC_TEGRA210) {
data->clk_ahub = devm_clk_get(dev, "ahub"); data->clk_ahub = devm_clk_get(dev, "ahub");
if (IS_ERR(data->clk_ahub)) { if (IS_ERR(data->clk_ahub)) {
@@ -255,21 +260,19 @@ int tegra_alt_asoc_utils_set_extern_parent(
struct tegra_asoc_audio_clock_info *data, const char *parent) struct tegra_asoc_audio_clock_info *data, const char *parent)
{ {
unsigned long rate; unsigned long rate;
int err; int err = 0;
rate = clk_get_rate(data->clk_cdev1); rate = clk_get_rate(data->clk_cdev1);
if (!strcmp(parent, "clk_m")) { if (!IS_ERR(data->clk_mclk_parent))
err = clk_set_parent(data->clk_cdev1, data->clk_mclk_parent);
else if (!strcmp(parent, "clk_m"))
err = clk_set_parent(data->clk_cdev1, data->clk_m); err = clk_set_parent(data->clk_cdev1, data->clk_m);
if (err) { else if (!strcmp(parent, "pll_a_out0"))
dev_err(data->dev, "Can't set clk extern1 parent");
return err;
}
} else if (!strcmp(parent, "pll_a_out0")) {
err = clk_set_parent(data->clk_cdev1, data->clk_pll_a_out0); err = clk_set_parent(data->clk_cdev1, data->clk_pll_a_out0);
if (err) {
dev_err(data->dev, "Can't set clk cdev1/extern1 parent"); if (err) {
return err; dev_err(data->dev, "Can't set aud mclk clock parent");
} return err;
} }
err = clk_set_rate(data->clk_cdev1, rate); err = clk_set_rate(data->clk_cdev1, rate);