mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 10:11:26 +03:00
ASoC: tegra-alt: clock cleanup for machine driver
Highlights from current clock handling in machine driver(L4T/Android)
* Tegra210 and Tegra186/194 have different approaches to update clock
rates for pll_a, pll_a_out0, mclk and ahub.
-> Tegra210 uses static method, where base pll_a rate is hardcoded
in the driver.
-> Tegra186/194 use DT driven approach, where sound node passes rates
for above clocks. Two sets of rates are passed, one to support odd
sample rates and one for even.
* Some of the functions from tegra_asoc_utils_alt.c are unused
* clock names are not really generic.
This patch has following updates.
* Unify clock update approach. Use static array for base pll rates.
This also helps to get rid of following sound node DT properties.
"nvidia,num-rates"
"nvidia,clk-rates"
* Remove below unused functions.
tegra_alt_asoc_utils_lock_clk_rate()
tegra_alt_asoc_utils_register_ctls()
tegra_alt_asoc_utils_tristate_dap()
* clk_set_parent() functions are not needed. Instead the relationship
can be set from DT through "assigned-clocks" binding.
* update clock handle names to be more meaningful. However, clock names
that are parsed in devm_clk_get() are not changed because these names
are used in Automotive DT files under "sound_ref" node. Scope of
current patch is limited to L4T/Android drivers and DT files.
Bug 200503387
Bug 200516191
Change-Id: Ideaf150e6e200ffbba4dcbdec4c49f1127ea25db
Signed-off-by: Sameer Pujar <spujar@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/2164482
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Ravindra Lokhande <rlokhande@nvidia.com>
Reviewed-by: Mohan Kumar D <mkumard@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:
@@ -205,7 +205,6 @@ struct tegra_soc_bytes {
|
||||
u32 shift; /* Used as offset for ahub ram related programing */
|
||||
};
|
||||
|
||||
int tegra210_xbar_set_clock(unsigned long rate);
|
||||
void tegra210_xbar_set_cif(struct regmap *regmap, unsigned int reg,
|
||||
struct tegra210_xbar_cif_conf *conf);
|
||||
void tegra210_xbar_write_ahubram(struct regmap *regmap, unsigned int reg_ctrl,
|
||||
|
||||
@@ -34,9 +34,7 @@ struct tegra_machine_soc_data {
|
||||
sfc_dai_link;
|
||||
|
||||
bool is_asrc_available,
|
||||
is_clk_rate_via_dt,
|
||||
write_cdev1_state,
|
||||
write_idle_bias_off_state;
|
||||
write_idle_bias_off_state;
|
||||
|
||||
struct snd_soc_codec_conf *ahub_confs;
|
||||
struct snd_soc_dai_link *ahub_links;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* tegra_alt_asoc_utils.h - Definitions for MCLK and DAP Utility driver
|
||||
*
|
||||
* Author: Stephen Warren <swarren@nvidia.com>
|
||||
* Copyright (c) 2011-2019 NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2011-2019 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -32,7 +32,10 @@ enum tegra_asoc_utils_soc {
|
||||
TEGRA_ASOC_UTILS_SOC_TEGRA194,
|
||||
};
|
||||
|
||||
/* Maintain same order in DT entry */
|
||||
/*
|
||||
* Maintain same order in DT entry
|
||||
* FIXME: (This would be removed going ahead)
|
||||
*/
|
||||
enum tegra_asoc_utils_clkrate {
|
||||
PLLA_x11025_RATE,
|
||||
AUD_MCLK_x11025_RATE,
|
||||
@@ -49,36 +52,30 @@ struct tegra_asoc_audio_clock_info {
|
||||
struct device *dev;
|
||||
struct snd_soc_card *card;
|
||||
enum tegra_asoc_utils_soc soc;
|
||||
struct clk *clk_pll_a;
|
||||
struct clk *clk_pll_a_out0;
|
||||
struct clk *clk_cdev1;
|
||||
struct clk *clk_pll_base;
|
||||
struct clk *clk_pll_out;
|
||||
struct clk *clk_aud_mclk;
|
||||
struct clk *clk_ahub;
|
||||
struct reset_control *clk_cdev1_rst;
|
||||
struct clk *clk_pll_p_out1;
|
||||
int set_mclk;
|
||||
int lock_count;
|
||||
int set_baseclock;
|
||||
int num_clk;
|
||||
struct clk *clk_mclk_parent;
|
||||
u32 set_clk_out_rate;
|
||||
u32 mclk_rate;
|
||||
unsigned int *pll_base_rate;
|
||||
u32 set_pll_base_rate;
|
||||
u32 set_pll_out_rate;
|
||||
u32 set_aud_mclk_rate;
|
||||
u32 mclk_scale;
|
||||
/* fixed MCLK rate from DT */
|
||||
u32 mclk_rate;
|
||||
|
||||
/* FIXME: below would be removed going ahead */
|
||||
u32 clk_rates[MAX_NUM_RATES];
|
||||
u32 num_clk;
|
||||
};
|
||||
|
||||
int tegra_alt_asoc_utils_set_rate(struct tegra_asoc_audio_clock_info *data,
|
||||
int srate,
|
||||
int mclk,
|
||||
u32 clk_out_rate);
|
||||
void tegra_alt_asoc_utils_lock_clk_rate(
|
||||
struct tegra_asoc_audio_clock_info *data,
|
||||
int lock);
|
||||
unsigned int srate, unsigned int mclk,
|
||||
unsigned int clk_out_rate);
|
||||
int tegra_alt_asoc_utils_init(struct tegra_asoc_audio_clock_info *data,
|
||||
struct device *dev, struct snd_soc_card *card);
|
||||
struct device *dev, struct snd_soc_card *card);
|
||||
int tegra_alt_asoc_utils_clk_enable(struct tegra_asoc_audio_clock_info *data);
|
||||
int tegra_alt_asoc_utils_clk_disable(struct tegra_asoc_audio_clock_info *data);
|
||||
int tegra_alt_asoc_utils_register_ctls(struct tegra_asoc_audio_clock_info *data);
|
||||
|
||||
int tegra_alt_asoc_utils_tristate_dap(int id, bool tristate);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -70,9 +70,9 @@ static int tegra_machine_suspend_pre(struct snd_soc_card *);
|
||||
static int tegra_machine_pcm_hw_params(struct snd_pcm_substream *,
|
||||
struct snd_pcm_hw_params *);
|
||||
static int tegra_machine_dai_init(struct snd_soc_pcm_runtime *,
|
||||
int, int, u64, bool);
|
||||
unsigned int, unsigned int, u64, bool);
|
||||
static int tegra_machine_set_params(struct snd_soc_card *,
|
||||
struct tegra_machine *, int, int, u64);
|
||||
struct tegra_machine *, unsigned int, unsigned int, u64);
|
||||
static int tegra_machine_codec_get_rate(struct snd_kcontrol *,
|
||||
struct snd_ctl_elem_value *);
|
||||
static int tegra_machine_codec_put_rate(struct snd_kcontrol *,
|
||||
@@ -94,7 +94,6 @@ static const struct tegra_machine_soc_data soc_data_tegra210 = {
|
||||
#endif
|
||||
.sfc_dai_link = TEGRA210_DAI_LINK_SFC1_RX,
|
||||
|
||||
.is_clk_rate_via_dt = false,
|
||||
.write_idle_bias_off_state = false,
|
||||
|
||||
.ahub_links = tegra210_xbar_dai_links,
|
||||
@@ -115,7 +114,6 @@ static const struct tegra_machine_soc_data soc_data_tegra186 = {
|
||||
#endif
|
||||
.sfc_dai_link = TEGRA186_DAI_LINK_SFC1_RX,
|
||||
|
||||
.is_clk_rate_via_dt = true,
|
||||
.write_idle_bias_off_state = true,
|
||||
|
||||
.ahub_links = tegra186_xbar_dai_links,
|
||||
@@ -293,10 +291,10 @@ static int tegra_machine_codec_put_format(struct snd_kcontrol *kcontrol,
|
||||
}
|
||||
|
||||
static int tegra_machine_set_params(struct snd_soc_card *card,
|
||||
struct tegra_machine *machine,
|
||||
int rate,
|
||||
int channels,
|
||||
u64 formats)
|
||||
struct tegra_machine *machine,
|
||||
unsigned int rate,
|
||||
unsigned int channels,
|
||||
u64 formats)
|
||||
{
|
||||
unsigned int mask = (1 << channels) - 1;
|
||||
int idx = 0, err = 0;
|
||||
@@ -352,72 +350,31 @@ static int tegra_machine_set_params(struct snd_soc_card *card,
|
||||
return 0;
|
||||
}
|
||||
static int tegra_machine_dai_init(struct snd_soc_pcm_runtime *runtime,
|
||||
int rate,
|
||||
int channels,
|
||||
u64 formats,
|
||||
bool is_playback)
|
||||
unsigned int rate, unsigned int channels,
|
||||
u64 formats, bool is_playback)
|
||||
{
|
||||
struct snd_soc_card *card = runtime->card;
|
||||
struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
|
||||
struct snd_soc_pcm_stream *dai_params;
|
||||
unsigned int clk_out_rate = 0, mclk = 0;
|
||||
int err, codec_rate, clk_rate;
|
||||
unsigned int aud_mclk, srate;
|
||||
int err;
|
||||
struct snd_soc_pcm_runtime *rtd;
|
||||
|
||||
codec_rate = tegra_machine_srate_values[machine->rate_via_kcontrol];
|
||||
clk_rate = (machine->rate_via_kcontrol) ? codec_rate : rate;
|
||||
srate = (machine->rate_via_kcontrol) ?
|
||||
tegra_machine_srate_values[machine->rate_via_kcontrol] :
|
||||
rate;
|
||||
|
||||
if (!machine->soc_data->is_clk_rate_via_dt) {
|
||||
/* TODO remove this hardcoding */
|
||||
/* aud_mclk, 256 times the sample rate */
|
||||
clk_out_rate = clk_rate << 8;
|
||||
switch (clk_rate) {
|
||||
case 11025:
|
||||
mclk = 22579200;
|
||||
break;
|
||||
case 22050:
|
||||
case 44100:
|
||||
case 88200:
|
||||
case 176400:
|
||||
mclk = 45158400;
|
||||
break;
|
||||
case 8000:
|
||||
mclk = 24576000;
|
||||
break;
|
||||
case 16000:
|
||||
case 32000:
|
||||
case 48000:
|
||||
case 64000:
|
||||
case 96000:
|
||||
case 192000:
|
||||
default:
|
||||
mclk = 49152000;
|
||||
break;
|
||||
}
|
||||
|
||||
err = tegra210_xbar_set_clock(mclk);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev,
|
||||
"Can't configure xbar clock = %d Hz\n", mclk);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = tegra_alt_asoc_utils_set_rate(&machine->audio_clock, clk_rate,
|
||||
mclk, clk_out_rate);
|
||||
err = tegra_alt_asoc_utils_set_rate(&machine->audio_clock, srate, 0, 0);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "Can't configure clocks\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (machine->soc_data->is_clk_rate_via_dt)
|
||||
clk_out_rate = machine->audio_clock.set_clk_out_rate;
|
||||
aud_mclk = machine->audio_clock.set_aud_mclk_rate;
|
||||
|
||||
pr_debug("pll_a_out0 = %d Hz, aud_mclk = %d Hz, codec rate = %d Hz\n",
|
||||
machine->audio_clock.set_mclk,
|
||||
machine->audio_clock.set_clk_out_rate, clk_rate);
|
||||
pr_debug("pll_a_out0 = %u Hz, aud_mclk = %u Hz, sample rate = %u Hz\n",
|
||||
machine->audio_clock.set_pll_out_rate, aud_mclk, srate);
|
||||
|
||||
/* TODO: should we pass here clk_rate ? */
|
||||
err = tegra_machine_set_params(card, machine, rate, channels, formats);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@@ -427,12 +384,12 @@ static int tegra_machine_dai_init(struct snd_soc_pcm_runtime *runtime,
|
||||
dai_params =
|
||||
(struct snd_soc_pcm_stream *)rtd->dai_link->params;
|
||||
|
||||
dai_params->rate_min = clk_rate;
|
||||
dai_params->rate_min = srate;
|
||||
dai_params->formats = (machine->fmt_via_kcontrol == 2) ?
|
||||
(1ULL << SNDRV_PCM_FORMAT_S32_LE) : formats;
|
||||
|
||||
err = snd_soc_dai_set_sysclk(rtd->codec_dai, RT5659_SCLK_S_MCLK,
|
||||
clk_out_rate, SND_SOC_CLOCK_IN);
|
||||
aud_mclk, SND_SOC_CLOCK_IN);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "codec_dai clock not set\n");
|
||||
return err;
|
||||
@@ -446,22 +403,22 @@ static int tegra_machine_dai_init(struct snd_soc_pcm_runtime *runtime,
|
||||
dai_params =
|
||||
(struct snd_soc_pcm_stream *)rtd->dai_link->params;
|
||||
|
||||
dai_params->rate_min = clk_rate;
|
||||
dai_params->rate_min = srate;
|
||||
dai_params->formats = (machine->fmt_via_kcontrol == 2) ?
|
||||
(1ULL << SNDRV_PCM_FORMAT_S32_LE) : formats;
|
||||
|
||||
switch (dai_params->formats) {
|
||||
case SNDRV_PCM_FMTBIT_S8:
|
||||
bclk_rate = clk_rate * channels * 8;
|
||||
bclk_rate = srate * channels * 8;
|
||||
break;
|
||||
case SNDRV_PCM_FMTBIT_S16_LE:
|
||||
bclk_rate = clk_rate * channels * 16;
|
||||
bclk_rate = srate * channels * 16;
|
||||
break;
|
||||
case SNDRV_PCM_FMTBIT_S24_LE:
|
||||
bclk_rate = clk_rate * channels * 24;
|
||||
bclk_rate = srate * channels * 24;
|
||||
break;
|
||||
case SNDRV_PCM_FMTBIT_S32_LE:
|
||||
bclk_rate = clk_rate * channels * 32;
|
||||
bclk_rate = srate * channels * 32;
|
||||
break;
|
||||
default:
|
||||
dev_err(card->dev, "invalid format %llu\n",
|
||||
@@ -471,29 +428,26 @@ static int tegra_machine_dai_init(struct snd_soc_pcm_runtime *runtime,
|
||||
|
||||
err = snd_soc_dai_set_pll(rtd->codec_dai, 0,
|
||||
RT5659_PLL1_S_BCLK1,
|
||||
bclk_rate, clk_rate * 256);
|
||||
bclk_rate, srate * 256);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "failed to set codec pll\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = snd_soc_dai_set_sysclk(rtd->codec_dai, RT5659_SCLK_S_PLL1,
|
||||
clk_rate * 256, SND_SOC_CLOCK_IN);
|
||||
srate * 256, SND_SOC_CLOCK_IN);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "codec_dai clock not set\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: remove below spdif links if clk_rate is passed
|
||||
* in tegra_machine_set_params
|
||||
*/
|
||||
rtd = snd_soc_get_pcm_runtime(card, "spdif-dit-0");
|
||||
if (rtd) {
|
||||
dai_params =
|
||||
(struct snd_soc_pcm_stream *)rtd->dai_link->params;
|
||||
|
||||
dai_params->rate_min = clk_rate;
|
||||
dai_params->rate_min = srate;
|
||||
}
|
||||
|
||||
rtd = snd_soc_get_pcm_runtime(card, "spdif-dit-1");
|
||||
@@ -501,7 +455,7 @@ static int tegra_machine_dai_init(struct snd_soc_pcm_runtime *runtime,
|
||||
dai_params =
|
||||
(struct snd_soc_pcm_stream *)rtd->dai_link->params;
|
||||
|
||||
dai_params->rate_min = clk_rate;
|
||||
dai_params->rate_min = srate;
|
||||
}
|
||||
|
||||
/* set clk rate for i2s3 dai link*/
|
||||
@@ -510,7 +464,7 @@ static int tegra_machine_dai_init(struct snd_soc_pcm_runtime *runtime,
|
||||
dai_params =
|
||||
(struct snd_soc_pcm_stream *)rtd->dai_link->params;
|
||||
|
||||
dai_params->rate_min = clk_rate;
|
||||
dai_params->rate_min = srate;
|
||||
}
|
||||
|
||||
rtd = snd_soc_get_pcm_runtime(card, "spdif-dit-3");
|
||||
@@ -518,7 +472,7 @@ static int tegra_machine_dai_init(struct snd_soc_pcm_runtime *runtime,
|
||||
dai_params =
|
||||
(struct snd_soc_pcm_stream *)rtd->dai_link->params;
|
||||
|
||||
dai_params->rate_min = clk_rate;
|
||||
dai_params->rate_min = srate;
|
||||
}
|
||||
|
||||
rtd = snd_soc_get_pcm_runtime(card, "spdif-dit-5");
|
||||
@@ -527,7 +481,7 @@ static int tegra_machine_dai_init(struct snd_soc_pcm_runtime *runtime,
|
||||
(struct snd_soc_pcm_stream *)rtd->dai_link->params;
|
||||
|
||||
/* update link_param to update hw_param for DAPM */
|
||||
dai_params->rate_min = clk_rate;
|
||||
dai_params->rate_min = srate;
|
||||
dai_params->channels_min = channels;
|
||||
dai_params->formats = formats;
|
||||
}
|
||||
@@ -539,7 +493,7 @@ static int tegra_machine_dai_init(struct snd_soc_pcm_runtime *runtime,
|
||||
|
||||
if (!strcmp(rtd->codec_dai->name, "tas2552-amplifier")) {
|
||||
err = snd_soc_dai_set_sysclk(rtd->codec_dai,
|
||||
TAS2552_PDM_CLK_IVCLKIN, clk_out_rate,
|
||||
TAS2552_PDM_CLK_IVCLKIN, aud_mclk,
|
||||
SND_SOC_CLOCK_IN);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "codec_dai clock not set\n");
|
||||
@@ -555,7 +509,7 @@ static int tegra_machine_dai_init(struct snd_soc_pcm_runtime *runtime,
|
||||
|
||||
if (!strcmp(rtd->codec_dai->name, "tas2552-amplifier")) {
|
||||
err = snd_soc_dai_set_sysclk(rtd->codec_dai,
|
||||
TAS2552_PDM_CLK_IVCLKIN, clk_out_rate,
|
||||
TAS2552_PDM_CLK_IVCLKIN, aud_mclk,
|
||||
SND_SOC_CLOCK_IN);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "codec_dai clock not set\n");
|
||||
@@ -569,7 +523,7 @@ static int tegra_machine_dai_init(struct snd_soc_pcm_runtime *runtime,
|
||||
dai_params =
|
||||
(struct snd_soc_pcm_stream *)rtd->dai_link->params;
|
||||
|
||||
dai_params->rate_min = clk_rate;
|
||||
dai_params->rate_min = srate;
|
||||
dai_params->channels_min = channels;
|
||||
dai_params->formats = formats;
|
||||
}
|
||||
@@ -888,35 +842,18 @@ static int tegra_machine_driver_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memset(&machine->audio_clock, 0, sizeof(machine->audio_clock));
|
||||
if (of_property_read_u32(np, "nvidia,mclk-rate",
|
||||
&machine->audio_clock.mclk_rate) < 0)
|
||||
&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) < 0) {
|
||||
/* TODO: fix clock in DT and remove usage of default scale */
|
||||
machine->audio_clock.mclk_scale = 256;
|
||||
dev_dbg(&pdev->dev, "Missing property mclk-fs\n");
|
||||
}
|
||||
|
||||
if (machine->soc_data->is_clk_rate_via_dt) {
|
||||
ret = of_property_read_u32(np, "nvidia,num-clk",
|
||||
&machine->audio_clock.num_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Missing property 'nvidia,num-clk'\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_array(np, "nvidia,clk-rates",
|
||||
(u32 *)&machine->audio_clock.clk_rates,
|
||||
machine->audio_clock.num_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Missing property 'nvidia,clk-rates'\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
tegra_machine_dma_set_mask(pdev);
|
||||
|
||||
ret = add_dai_links(pdev);
|
||||
|
||||
@@ -32,22 +32,6 @@
|
||||
|
||||
static struct tegra_xbar *xbar;
|
||||
|
||||
int tegra210_xbar_set_clock(unsigned long rate)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = clk_set_rate(xbar->clk_parent, rate);
|
||||
if (ret)
|
||||
pr_info("Failed to set clock rate of pll_a_out0\n");
|
||||
|
||||
ret = clk_set_rate(xbar->clk, rate);
|
||||
if (ret)
|
||||
pr_info("Failed to set clock rate of ahub\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tegra210_xbar_set_clock);
|
||||
|
||||
void tegra210_xbar_set_cif(struct regmap *regmap, unsigned int reg,
|
||||
struct tegra210_xbar_cif_conf *conf)
|
||||
{
|
||||
|
||||
@@ -26,25 +26,37 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <linux/clk/tegra.h>
|
||||
#include <linux/reset.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pinctrl/pinconf-tegra.h>
|
||||
|
||||
#include "tegra_asoc_utils_alt.h"
|
||||
|
||||
enum rate_type {
|
||||
ODD_RATE,
|
||||
EVEN_RATE,
|
||||
NUM_RATE_TYPE,
|
||||
};
|
||||
|
||||
unsigned int tegra210_pll_base_rate[NUM_RATE_TYPE] = {
|
||||
338688000,
|
||||
368640000,
|
||||
};
|
||||
|
||||
unsigned int tegra186_pll_base_rate[NUM_RATE_TYPE] = {
|
||||
270950400,
|
||||
245760000,
|
||||
};
|
||||
|
||||
unsigned int default_pll_out_rate[NUM_RATE_TYPE] = {
|
||||
45158400,
|
||||
49152000,
|
||||
};
|
||||
|
||||
int tegra_alt_asoc_utils_set_rate(struct tegra_asoc_audio_clock_info *data,
|
||||
int srate,
|
||||
int mclk,
|
||||
u32 clk_out_rate)
|
||||
unsigned int srate, unsigned int pll_out,
|
||||
unsigned int aud_mclk)
|
||||
{
|
||||
int new_baseclock;
|
||||
int ahub_rate = 0;
|
||||
bool clk_change;
|
||||
unsigned int new_pll_base;
|
||||
int err;
|
||||
|
||||
switch (srate) {
|
||||
@@ -53,22 +65,8 @@ int tegra_alt_asoc_utils_set_rate(struct tegra_asoc_audio_clock_info *data,
|
||||
case 44100:
|
||||
case 88200:
|
||||
case 176400:
|
||||
if (data->soc < TEGRA_ASOC_UTILS_SOC_TEGRA186)
|
||||
new_baseclock = 338688000;
|
||||
else {
|
||||
new_baseclock = data->clk_rates[PLLA_x11025_RATE];
|
||||
mclk = data->clk_rates[PLLA_OUT0_x11025_RATE];
|
||||
ahub_rate = data->clk_rates[AHUB_x11025_RATE];
|
||||
|
||||
if (srate <= 11025) {
|
||||
/* half the pll_a_out0 to support lower
|
||||
* sampling rate divider
|
||||
*/
|
||||
mclk = mclk >> 1;
|
||||
ahub_rate = ahub_rate >> 1;
|
||||
}
|
||||
clk_out_rate = srate * data->mclk_scale;
|
||||
}
|
||||
new_pll_base = data->pll_base_rate[ODD_RATE];
|
||||
pll_out = default_pll_out_rate[ODD_RATE];
|
||||
break;
|
||||
case 8000:
|
||||
case 16000:
|
||||
@@ -77,88 +75,67 @@ int tegra_alt_asoc_utils_set_rate(struct tegra_asoc_audio_clock_info *data,
|
||||
case 64000:
|
||||
case 96000:
|
||||
case 192000:
|
||||
if (data->soc < TEGRA_ASOC_UTILS_SOC_TEGRA186)
|
||||
new_baseclock = 368640000;
|
||||
else {
|
||||
new_baseclock = data->clk_rates[PLLA_x8000_RATE];
|
||||
mclk = data->clk_rates[PLLA_OUT0_x8000_RATE];
|
||||
ahub_rate = data->clk_rates[AHUB_x8000_RATE];
|
||||
|
||||
if (srate <= 8000) {
|
||||
/* half the pll_a_out0 to support lower
|
||||
* sampling rate divider
|
||||
*/
|
||||
mclk = mclk >> 1;
|
||||
ahub_rate = ahub_rate >> 1;
|
||||
}
|
||||
clk_out_rate = srate * data->mclk_scale;
|
||||
}
|
||||
new_pll_base = data->pll_base_rate[EVEN_RATE];
|
||||
pll_out = default_pll_out_rate[EVEN_RATE];
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
clk_out_rate = data->mclk_rate ? data->mclk_rate : clk_out_rate;
|
||||
/* reduce pll_out rate to support lower sampling rates */
|
||||
if (srate <= 11025)
|
||||
pll_out = pll_out >> 1;
|
||||
if (data->mclk_scale)
|
||||
aud_mclk = srate * data->mclk_scale;
|
||||
/*
|
||||
* mclk_rate is the fixed clock from DT, this overrides mclk_scale.
|
||||
* TODO: manage MCLK fixed or dynamic rate from a single DT property.
|
||||
*/
|
||||
aud_mclk = data->mclk_rate ? data->mclk_rate : aud_mclk;
|
||||
|
||||
clk_change = ((new_baseclock != data->set_baseclock) ||
|
||||
(mclk != data->set_mclk) ||
|
||||
(clk_out_rate != data->set_clk_out_rate));
|
||||
|
||||
if (!clk_change)
|
||||
return 0;
|
||||
|
||||
/* Don't change rate if already one dai-link is using it */
|
||||
if (data->lock_count)
|
||||
return -EINVAL;
|
||||
|
||||
data->set_baseclock = 0;
|
||||
data->set_mclk = 0;
|
||||
|
||||
err = clk_set_rate(data->clk_pll_a, new_baseclock);
|
||||
if (err) {
|
||||
dev_err(data->dev, "Can't set pll_a rate: %d\n", err);
|
||||
return err;
|
||||
if (data->set_pll_base_rate != new_pll_base) {
|
||||
err = clk_set_rate(data->clk_pll_base, new_pll_base);
|
||||
if (err) {
|
||||
dev_err(data->dev, "Can't set clk_pll_base rate: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
data->set_pll_base_rate = new_pll_base;
|
||||
}
|
||||
|
||||
err = clk_set_rate(data->clk_pll_a_out0, mclk);
|
||||
if (err) {
|
||||
dev_err(data->dev, "Can't set clk_pll_a_out0 rate: %d\n", err);
|
||||
return err;
|
||||
if (data->set_pll_out_rate != pll_out) {
|
||||
err = clk_set_rate(data->clk_pll_out, pll_out);
|
||||
if (err) {
|
||||
dev_err(data->dev, "Can't set clk_pll_out rate: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* TODO: remove below once ahub rate is fixed from DT */
|
||||
err = clk_set_rate(data->clk_ahub, pll_out);
|
||||
if (err) {
|
||||
dev_err(data->dev, "Can't set ahub rate: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
data->set_pll_out_rate = pll_out;
|
||||
}
|
||||
|
||||
if (data->soc > TEGRA_ASOC_UTILS_SOC_TEGRA210) {
|
||||
err = clk_set_rate(data->clk_ahub, ahub_rate);
|
||||
if (data->set_aud_mclk_rate != aud_mclk) {
|
||||
err = clk_set_rate(data->clk_aud_mclk, aud_mclk);
|
||||
if (err) {
|
||||
dev_err(data->dev, "Can't set clk_cdev1 rate: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
data->set_aud_mclk_rate = aud_mclk;
|
||||
}
|
||||
|
||||
err = clk_set_rate(data->clk_cdev1, clk_out_rate);
|
||||
if (err) {
|
||||
dev_err(data->dev, "Can't set clk_cdev1 rate: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
data->set_baseclock = new_baseclock;
|
||||
data->set_mclk = mclk;
|
||||
data->set_clk_out_rate = clk_out_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tegra_alt_asoc_utils_set_rate);
|
||||
|
||||
void tegra_alt_asoc_utils_lock_clk_rate(struct tegra_asoc_audio_clock_info *data,
|
||||
int lock)
|
||||
{
|
||||
if (lock)
|
||||
data->lock_count++;
|
||||
else if (data->lock_count)
|
||||
data->lock_count--;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tegra_alt_asoc_utils_lock_clk_rate);
|
||||
|
||||
int tegra_alt_asoc_utils_clk_enable(struct tegra_asoc_audio_clock_info *data)
|
||||
{
|
||||
int err;
|
||||
@@ -166,7 +143,7 @@ int tegra_alt_asoc_utils_clk_enable(struct tegra_asoc_audio_clock_info *data)
|
||||
if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA186)
|
||||
reset_control_reset(data->clk_cdev1_rst);
|
||||
|
||||
err = clk_prepare_enable(data->clk_cdev1);
|
||||
err = clk_prepare_enable(data->clk_aud_mclk);
|
||||
if (err) {
|
||||
dev_err(data->dev, "Can't enable cdev1: %d\n", err);
|
||||
return err;
|
||||
@@ -178,7 +155,7 @@ EXPORT_SYMBOL_GPL(tegra_alt_asoc_utils_clk_enable);
|
||||
|
||||
int tegra_alt_asoc_utils_clk_disable(struct tegra_asoc_audio_clock_info *data)
|
||||
{
|
||||
clk_disable_unprepare(data->clk_cdev1);
|
||||
clk_disable_unprepare(data->clk_aud_mclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -187,8 +164,6 @@ EXPORT_SYMBOL_GPL(tegra_alt_asoc_utils_clk_disable);
|
||||
int tegra_alt_asoc_utils_init(struct tegra_asoc_audio_clock_info *data,
|
||||
struct device *dev, struct snd_soc_card *card)
|
||||
{
|
||||
int ret;
|
||||
|
||||
data->dev = dev;
|
||||
data->card = card;
|
||||
|
||||
@@ -203,38 +178,28 @@ int tegra_alt_asoc_utils_init(struct tegra_asoc_audio_clock_info *data,
|
||||
/* DT boot, but unknown SoC */
|
||||
return -EINVAL;
|
||||
|
||||
data->clk_pll_a = devm_clk_get(dev, "pll_a");
|
||||
if (IS_ERR(data->clk_pll_a)) {
|
||||
data->clk_pll_base = devm_clk_get(dev, "pll_a");
|
||||
if (IS_ERR(data->clk_pll_base)) {
|
||||
dev_err(data->dev, "Can't retrieve clk pll_a\n");
|
||||
return PTR_ERR(data->clk_pll_a);
|
||||
return PTR_ERR(data->clk_pll_base);
|
||||
}
|
||||
|
||||
data->clk_pll_a_out0 = devm_clk_get(dev, "pll_a_out0");
|
||||
if (IS_ERR(data->clk_pll_a_out0)) {
|
||||
data->clk_pll_out = devm_clk_get(dev, "pll_a_out0");
|
||||
if (IS_ERR(data->clk_pll_out)) {
|
||||
dev_err(data->dev, "Can't retrieve clk pll_a_out0\n");
|
||||
return PTR_ERR(data->clk_pll_a_out0);
|
||||
return PTR_ERR(data->clk_pll_out);
|
||||
}
|
||||
|
||||
data->clk_cdev1 = devm_clk_get(dev, "extern1");
|
||||
if (IS_ERR(data->clk_cdev1)) {
|
||||
data->clk_aud_mclk = devm_clk_get(dev, "extern1");
|
||||
if (IS_ERR(data->clk_aud_mclk)) {
|
||||
dev_err(data->dev, "Can't retrieve clk cdev1\n");
|
||||
return PTR_ERR(data->clk_cdev1);
|
||||
return PTR_ERR(data->clk_aud_mclk);
|
||||
}
|
||||
|
||||
/* 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))
|
||||
data->clk_mclk_parent = data->clk_pll_a_out0;
|
||||
|
||||
if (data->soc > TEGRA_ASOC_UTILS_SOC_TEGRA210) {
|
||||
data->clk_ahub = devm_clk_get(dev, "ahub");
|
||||
if (IS_ERR(data->clk_ahub)) {
|
||||
dev_err(data->dev, "Can't retrieve clk ahub\n");
|
||||
return PTR_ERR(data->clk_ahub);
|
||||
}
|
||||
data->clk_ahub = devm_clk_get(dev, "ahub");
|
||||
if (IS_ERR(data->clk_ahub)) {
|
||||
dev_err(data->dev, "Can't retrieve clk ahub\n");
|
||||
return PTR_ERR(data->clk_ahub);
|
||||
}
|
||||
|
||||
if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA186) {
|
||||
@@ -248,11 +213,10 @@ int tegra_alt_asoc_utils_init(struct tegra_asoc_audio_clock_info *data,
|
||||
reset_control_reset(data->clk_cdev1_rst);
|
||||
}
|
||||
|
||||
ret = clk_set_parent(data->clk_cdev1, data->clk_mclk_parent);
|
||||
if (ret < 0) {
|
||||
dev_err(card->dev, "Failed to set extern clk parent\n");
|
||||
return ret;
|
||||
}
|
||||
if (data->soc < TEGRA_ASOC_UTILS_SOC_TEGRA186)
|
||||
data->pll_base_rate = tegra210_pll_base_rate;
|
||||
else
|
||||
data->pll_base_rate = tegra186_pll_base_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user