17.12.2019 19:12, Sowjanya Komatineni ÐÐÑÐÑ:
On 12/17/19 7:36 AM, Dmitry Osipenko wrote:Have you actually tried to test that it fails? I think it's a false
17.12.2019 04:29, Sowjanya Komatineni ÐÐÑÐÑ:Current clock driver adds EXTERN clock to lookup with dev_id as
On 12/7/19 11:20 AM, Sowjanya Komatineni wrote:It should be better to use something "resource managed", thus
On 12/7/19 6:58 AM, Dmitry Osipenko wrote:clk_get uses device rather and dev_id will be name of this device and
06.12.2019 05:48, Sowjanya Komatineni ÐÐÑÐÑ:For T30 and later, clk_extern1 is one of the source for clk_out_1_mux.
Current ASoC driver uses extern1 as cdev1 clock from Tegra30 onwardsWhy this is needed given that clk_extern1 is either a child of MCLK or
through device tree.
Actual audio mclk is clk_out_1 and to use PLLA for mclk rate control,
need to clk_out_1_mux parent to extern1 and extern1 parent to
PLLA_OUT0.
Currently Tegra clock driver init sets the parents and enables both
clk_out_1 and extern1 clocks. But these clocks parent and enables
should
be controlled by ASoC driver.
Clock parents can be specified in device tree using assigned-clocks
and assigned-clock-parents.
To enable audio mclk, both clk_out_1 and extern1 clocks need to be
enabled.
This patch configures parents for clk_out_1 and extern1 clocks if
device
tree does not specify clock parents inorder to support old device
tree
and controls mclk using both clk_out_1 and extern1 clocks.
Signed-off-by: Sowjanya Komatineni <skomatineni@xxxxxxxxxx>
---
ÂÂ sound/soc/tegra/tegra_asoc_utils.c | 66
++++++++++++++++++++++++++++++++++++++
ÂÂ sound/soc/tegra/tegra_asoc_utils.h |Â 1 +
ÂÂ 2 files changed, 67 insertions(+)
diff --git a/sound/soc/tegra/tegra_asoc_utils.c
b/sound/soc/tegra/tegra_asoc_utils.c
index 536a578e9512..8e3a3740df7c 100644
--- a/sound/soc/tegra/tegra_asoc_utils.c
+++ b/sound/soc/tegra/tegra_asoc_utils.c
@@ -60,6 +60,7 @@ int tegra_asoc_utils_set_rate(struct
tegra_asoc_utils_data *data, int srate,
ÂÂÂÂÂÂ data->set_mclk = 0;
ÂÂ ÂÂÂÂÂ clk_disable_unprepare(data->clk_cdev1);
+ÂÂÂ clk_disable_unprepare(data->clk_extern1);
ÂÂÂÂÂÂ clk_disable_unprepare(data->clk_pll_a_out0);
ÂÂÂÂÂÂ clk_disable_unprepare(data->clk_pll_a);
ÂÂ @@ -89,6 +90,14 @@ int tegra_asoc_utils_set_rate(struct
tegra_asoc_utils_data *data, int srate,
ÂÂÂÂÂÂÂÂÂÂ return err;
ÂÂÂÂÂÂ }
ÂÂ +ÂÂÂ if (!IS_ERR_OR_NULL(data->clk_extern1)) {
+ÂÂÂÂÂÂÂ err = clk_prepare_enable(data->clk_extern1);
+ÂÂÂÂÂÂÂ if (err) {
+ÂÂÂÂÂÂÂÂÂÂÂ dev_err(data->dev, "Can't enable extern1: %d\n", err);
+ÂÂÂÂÂÂÂÂÂÂÂ return err;
+ÂÂÂÂÂÂÂ }
+ÂÂÂ }
+
ÂÂÂÂÂÂ err = clk_prepare_enable(data->clk_cdev1);
ÂÂÂÂÂÂ if (err) {
ÂÂÂÂÂÂÂÂÂÂ dev_err(data->dev, "Can't enable cdev1: %d\n", err);
@@ -109,6 +118,7 @@ int tegra_asoc_utils_set_ac97_rate(struct
tegra_asoc_utils_data *data)
ÂÂÂÂÂÂ int err;
ÂÂ ÂÂÂÂÂ clk_disable_unprepare(data->clk_cdev1);
+ÂÂÂ clk_disable_unprepare(data->clk_extern1);
ÂÂÂÂÂÂ clk_disable_unprepare(data->clk_pll_a_out0);
ÂÂÂÂÂÂ clk_disable_unprepare(data->clk_pll_a);
ÂÂ @@ -142,6 +152,14 @@ int tegra_asoc_utils_set_ac97_rate(struct
tegra_asoc_utils_data *data)
ÂÂÂÂÂÂÂÂÂÂ return err;
ÂÂÂÂÂÂ }
ÂÂ +ÂÂÂ if (!IS_ERR_OR_NULL(data->clk_extern1)) {
+ÂÂÂÂÂÂÂ err = clk_prepare_enable(data->clk_extern1);
+ÂÂÂÂÂÂÂ if (err) {
+ÂÂÂÂÂÂÂÂÂÂÂ dev_err(data->dev, "Can't enable extern1: %d\n", err);
+ÂÂÂÂÂÂÂÂÂÂÂ return err;
+ÂÂÂÂÂÂÂ }
+ÂÂÂ }
MCLK itself (on T20)? The child clocks are enabled when the parent is
enabled.
clk_extern1 is in CAR and it has its own gate and mux.
As audio mclk related clocks (clk_out_1, clk_out_1_mux, and extern1)
are moved into ASoC driver from clock driver
need to enable extern1 gate as well along with clk_out1 for T30
through T210.
Just FYI, extern1 enable here happens only when data->clk_extern1 is
available which is for T30 onwards.
yeah right, will add check in next version.ÂÂÂÂÂÂ err = clk_prepare_enable(data->clk_cdev1);In a previous patch you added fallback to EXTPERIPH when clk_get(MCLK)
ÂÂÂÂÂÂ if (err) {
ÂÂÂÂÂÂÂÂÂÂ dev_err(data->dev, "Can't enable cdev1: %d\n", err);
@@ -158,6 +176,7 @@
EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_ac97_rate);
ÂÂ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct device *dev)
ÂÂ {
+ÂÂÂ struct clk *clk_out_1_mux;
ÂÂÂÂÂÂ int ret;
ÂÂ ÂÂÂÂÂ data->dev = dev;
@@ -196,6 +215,51 @@ int tegra_asoc_utils_init(struct
tegra_asoc_utils_data *data,
ÂÂÂÂÂÂÂÂÂÂ goto err_put_pll_a_out0;
ÂÂÂÂÂÂ }
fails. This will work perfectly fine for the older kernels which have
all clocks in the same single CaR driver, but this may not work that
great for the newer kernels because PMC driver isn't registered early
during boot and thus it is possible to get a legit -EPROBE_DEFER which
shouldn't be ignored. In other words, you need to add into this
patch a
check for the error code returned by clk_get(MCLK) and fallback
only for
-EINVAL.
+ÂÂÂ /*Note1: clk_get(dev, "clk_out_1_mux") should work here by letting clk
+ÂÂÂÂ * If clock parents are not set in DT, configure here to use
clk_out_1
+ÂÂÂÂ * as mclk and extern1 as parent for Tegra30 and higher.
+ÂÂÂÂ */
+ÂÂÂ if (!of_find_property(dev->of_node, "assigned-clock-parents",
NULL) &&
+ÂÂÂÂÂÂÂ data->soc > TEGRA_ASOC_UTILS_SOC_TEGRA20) {
+ÂÂÂÂÂÂÂ data->clk_extern1 = clk_get_sys("clk_out_1", "extern1");
+ÂÂÂÂÂÂÂ if (IS_ERR(data->clk_extern1)) {
+ÂÂÂÂÂÂÂÂÂÂÂ dev_err(data->dev, "Can't retrieve clk extern1\n");
+ÂÂÂÂÂÂÂÂÂÂÂ ret = PTR_ERR(data->clk_extern1);
+ÂÂÂÂÂÂÂÂÂÂÂ goto err_put_cdev1;
+ÂÂÂÂÂÂÂ }
+
+ÂÂÂÂÂÂÂ ret = clk_set_parent(data->clk_extern1,
data->clk_pll_a_out0);
+ÂÂÂÂÂÂÂ if (ret < 0) {
+ÂÂÂÂÂÂÂÂÂÂÂ dev_err(data->dev,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ "Set parent failed for clk extern1: %d\n",
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ ret);
+ÂÂÂÂÂÂÂÂÂÂÂ goto err_put_cdev1;
+ÂÂÂÂÂÂÂ }
+
+ÂÂÂÂÂÂÂ clk_out_1_mux = clk_get_sys(NULL, "clk_out_1_mux");
core to fall back to the clk_get_sys() by itself. Either way should
be good.
when clk_get fall back to __clk_get_sys() it still will use dev id of
this device rather than actual dev_id that pmc clocks are added to the
lookup. So clk_get_sys() seems to be correct to use as we can specify
exact dev_id and con_id.
devm_clk_get() should be a better choice.
Also, clk_find retrieves clock from lookup only when it finds matchingI'm not sure it's worth the effort to care about con_ids if implicit
clock with both dev_id and con_id as pmc clocks are registered with both
dev_id and con_id.
I see existing clock driver adds both extern and pmc clocks (clk_out) to
lookup with same dev_id of clk_out_1/2/3 and con_id of extern1/2/3 and
with this always extern clock will be retrieved and this is probably
because old DT and audio driver always uses extern1 rather than actual
clk_out_1
But this need to be fixed now as we changed to use clk_out directly
rather than extern (even for other pmc clocks) to match actual hw
design.
Will fix this as well to register pmc clocks using con_id as
clk_out_1/2/3 in pmc driver and extern clocks using con_id of
extern1/2/3 with dev_id being NULL so we can retrieve these clocks by
just using con_id only using clk_get_sys as we switched to use clk_out_1
directly as pmc clock rather than extern from DT and no longer need to
pair pmc clocks to extern clocks.
fallback to clk_get_sys(NULL, "...") does the right thing for the audio
driver.
IIRC, CCF uses variant of matching clocks by names, although I'm not
sure whether that applies to older stable kernels.
[snip]
clk_out_1/2/3 and con_id as extern_1/2/3
With this we can retrieve clock from lookup only with clk_get_sys where
we can pass dev_id as clk_out_1/2/3 and con_id as extern_1/2/3.
We cant use devm_clk_get() or clk_get() for retrieving clocks from
lookup by passing device object from sound driver as dev_id will be diff
and clk_find will return NULL.
assumption.
But with the fix of having dev_id as NULL and use only con_id to add to
lookup, we can use resource managed APIs devm_clk_get.
So was saying will fix this in clock driver as part of removing
clk_out_1/2/3 ids and pmc init from clock driver so we can use
devm_clk_get API in audio driver.